Перейти к публикации
iT4iT.CLUB

Kitsum

Пользователи
  • Публикации

    360
  • Зарегистрирован

  • Посещение

  • Дней в лидерах

    184

Все публикации пользователя Kitsum

  1. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Что Вы имеете в виду под фигурирует, связь между двумя контроллерами по Serial? Если да, то оба контроллера подключаются друг к другу через порты RX и TX с общей землей (GND). RX подключается к TX не зависимо от того с какой стороны смотреть. Также необходимо помнить об согласовании уровней сигналов. В программе работаете с контроллерами через Serial, различия будут лишь в том, что в ESP буфер с данными формируется автоматически, а в ATmega данные получаете по одному байту и буфер нужной длинны необходимо формировать самому. Дело в том, что предоставленный пример написан под ESP 8266/32 и для них в объекте Serial есть метод printf, а вот под ATmega данного метода нет, но есть одноименная функция, приводящая к аналогичному результату. Так что для ATmega строки такого вида Serial.printf ("f1: %f\r\nf2: %f\r\n", f1, f2); приведите к такому printf ("f1: %f\r\nf2: %f\r\n", f1, f2); и все должно заработать. Вообще все строки с Serial можно удалить, я добавил их для вывода отладочной информации дабы можно было отследить как выглядит число, записанное в float при разборе на массив из 4-х byte элементов и дальнейший обратный процесс с записью значение в другую переменную. PS: прошу прощение за задержку с ответами.
  2. Kitsum

    Метеостанция на ESP8266 от it4it.club

    @post125 попробуйте такой вариант разбора float на массив byte float f1 = -3.14; float f2 = 0; byte b1[sizeof(float)]; void setup() { Serial.begin(115200); Serial.println(); *(float*)b1 = f1; Serial.printf("f1: %f\r\nf2: %f\r\n", f1, f2); Serial.printf("0x%02X\r\n0x%02X\r\n0x%02X\r\n0x%02X\r\n", b1[0], b1[1], b1[2], b1[3]); f2 = *(float*)b1; Serial.printf("f1: %f\r\nf2: %f\r\n", f1, f2); } void loop() { } Передавайте этот массив и собирайте его в обратном порядке на стороне ESP.
  3. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Доброе время суток. @post125 В первую очередь нужно понять, что I2C и NRF это две разные транспортные линии, не рассматривайте их как единую среду передачи данных от беспроводных устройств к ESP, так ничего не выйдет. Со стороны ProMini необходимо организовать систему получения данных по беспроводному каналу их обработку и хранение в оперативной памяти. Допустим Вы получаете данные с 5-и беспроводных устройств, значит ProMini должна держать в памяти 5 разных значений с этими данными, пусть это будет float или, что угодно. Далее ESP, по мере надобности, запрашивает у ProMini данные по конкретному устройству, одному из 5-и. В ответ ProMini передает заранее преобразованное значение float с одного из датчиков в массив из 4-х byte или char и по очереди передает все элементы массива ESP. Далее проводите обратную операцию и получаете значение float. Главное помнить простую вещь, что float имеет размер в 4 byte, обращайтесь к каждому из них как к элементу массива и передавайте значение по одному byte. Таким образом получается, что ProMini является агрегатором данных со всех беспроводных устройств, работающих через NRF и передающих мастеру данные в виде массива из 4-х byte для каждого float.
  4. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Доброе время суток. Ограничения есть только в web интерфейсе проекта, в файле index.htm Для проверки SSID применяется следующее регулярное выражение, соответствующее латинским буквам от A до Z без учета регистра, всем цифрам и дополнительным символам "_. -". Общая длинна от 3 до 30 символов включительно. function checkSSID(ssid) { return ssid.match(/^[a-z0-9_. -]{3,30}$/i); } Для пароля все еще проще, это от 5 до 63 любых символов function checkPassw(passw) { return passw.match(/^.{5,63}$/); } Это говорит о том, что Вы проходите проверку на стороне web интерфейса ESP8266. Следовательно, причина кроется на стороне микроконтроллера. В первую очередь будет вызван один из методов web сервера, отвечающий за обработку пользовательских запросов. Файл webserver.h По сути тут будет проведена проверка на авторизацию пользователя и передача новых параметров вашему объекту конфигурации через вызов его метода config::write(String apiSave) Файл config.h Метод перебирает все доступные ему параметры, находящиеся в оперативной памяти и перезаписывает значения для тех из них чьи имена упоминались в списке, переданном web интерфейсом. Далее записывает данные в конфигурационный файл находящийся во Flash памяти. Могу предположить, что причина кроется в обработке некоторых символов библиотекой ArduinoJson в методе config::write(String apiSave), что приводит в отказу от записи конфигурации. json.success() Попробуйте в файле webserver.h добавить код ответа 500 для подобного события в метод http::api_settings(), приведите его к следующему виду void http::api_settings() { this->sendServerHeaders(); this->sendHeader("Cache-Control", "no-store, no-cache"); if (!this->security()) this->send(403); else if (this->authorized()) { if (this->hasArg(F("save"))) { if(!conf.write(this->arg(F("save")))) this->send(500); else this->send(200, headerJson, conf.showSecureConfig()); } else this->send(200, headerJson, conf.showSecureConfig()); } else this->send(401); } В теории, если ошибка происходит на уровне json формата, то она должна появиться с сообщением 500 Internal Server Error Если причина действительно в этом и Вам удастся выловить символ, то дайте мне знать какой он.
  5. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Как мне кажется, эта библиотека не подойдет, но проверить конечно же стоит. Я бы копал в сторону стандартной библиотеки Wire.h как для AVR контроллеров (Atmega ...) так и для ESP, ищите их в вашей Arduino IDE. Также надо учитывать, что для этих контроллеров библиотеки разные. Например, ESP может работать только в качестве Master устройства, что в принципе и требуется, а вот AVR контроллеры могут работать в Master/Slave режиме. Это можно подсмотреть в заголовочных файлах (.h) их библиотек. Также для начала будут очень полезны эти материалы: https://www.arduino.cc/en/Reference/Wire https://www.arduino.cc/en/Tutorial/MasterReader https://www.arduino.cc/en/Tutorial/MasterWriter https://forum.arduino.cc/index.php?topic=336543.msg2321656#msg2321656 (стоит ознакомиться с возможными проблемами, прочтите всю тему) Также помните о подтягивающих резисторах на SDA и SCL т.к они не отражены на схемах. Они понадобятся если Вы соединяете два контроллера между собой, но если на шине установлен какой ни-ть Китайский датчик, то очень велика вероятность, что резисторы уже есть. И еще один важный момент, это согласование уровней сигнала т.к ESP работает от 3.3V, а для ATmega стандартом является 5V, но они могут поддерживать и 3.3V. В любом случае, Вы должны гарантировать, что рассогласования уровней сигнала не будет. Лично мне нравится вариант, когда оба контроллера имеют питание 3.3V, так можно питать Slave от Master и не ставить плату согласования, но это зависит от конкретных задач, этот вариант не всегда приемлем. После того, как Вы научитесь передавать данные между контроллерами, копайте в сторону файла sensors.h в проекте. Вам нужен метод add, а точнее разобраться в параметрах, передаваемых ему. Один из параметров указывает какую функцию нужно вызвать чтобы получить данные от датчика, вот в этой функции и стоит описывать код запроса данных от Slave и дальнейший их разбор. Описание для интерфейса knob_t *sensor_knob_cfg = new knob_t(0, 100, "1", "Что показывает", "Ед. измер."); Функция сбора данных float getSensorData() { float value = 0; /* Тут описываем работу с Slave по i2c, результат записываем в value */ return value; } Добавление датчика sensors.add(sensor_knob_cfg, device::out, "sensor_uid", getSensorData); Это очень грубый пример одного из вариантов. В проекте много примеров реализации и есть некоторое количество комментариев, не стесняйтесь изучать содержимое файлов проекта, таких как sensors.h. Очень велика вероятность, что после изучения их содержимого у Вас появится свое видение как это должно быть реализовано, и это очень хорошо.
  6. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Доброе время суток. @Дмитрий Давайте попробуем, но я заранее предупреждаю, что Вам придется самостоятельно проводить все испытания. Я лишь постараюсь помочь с рекомендациями относительно данного проекта. И так. На сколько я понял, общая идея заключается в подсчете импульсов чашечного анемометра. Самый верный путь, это регистрировать импульсы по прерыванию т.к это не тратит драгоценное время ЦП. Далее, опираясь на частоту импульсов вычислять расстояние, которое прошел анемометр как будто это колесо автомобиля, а уже из этих данных выводить скорость. Стоит учитывать, что при расчете частоты нужно брать время между предыдущим и текущим расчетом скорости ветра, а не фиксированный интервал т.к есть и другие задачи время выполнения которых может меняться, а микроконтроллер выполняет код в реальном времени без распараллеливания задач. В первую очередь необходимо определиться, какой порт микроконтроллера будем задействовать. Я возьму за основу порт GPIO14. Он уже был задействован в проекте, поэтому в основном файле необходимо закомментировать вызов функции, которая его занимает. //gpio_14(); // Расхождение расчетной абсолютной влажности между показаниями с двух датчиков, например, BME280 Теперь порт свободен и можно преступать к коду анемометра. Мне не известно какие датчики Вы еще используете поэтому всё дальнейшее описание я буду делать так, как будто у меня только один этот датчик, так будет более понятно. Выберите пользовательский файл в котором будите работать, это любой .h файл начинающийся с префикса users_ или создайте новый файл со своим уникальным именем, например users_wspeed.h. Выбранный Вами файл должен быть подключен через оператор include в основном файле программы, другие пользовательские файлы должны быть закомментированы. Для себя я выбрал вариант с новым файлом users_wspeed.h //#include "users_auto.h"; // Пользовательская конфигурация датчиков, именно тут описывается с какими датчиками работать //#include "users_bme280_x2.h"; // Пример для двух датчиков BME280 (несовместим с users_auto.h) //#include "users_multiple_ds18b20.h"; #include "users_wspeed.h"; Весь код в этом файле должен быть заключен в конструкцию такого вида #ifndef USERS_H #define USERS_H /* Весь код описанный ниже располагается тут */ #endif Это указания для компилятора, на тот случай если в коде окажутся подключены два пользовательских файла. Теперь добавим описание для плагина Knob который отобразит наш сенсор в web интерфейсе. Установим приделы шкалы от 0 до 40 метров в секунду с шагом в одну десятую и соответствующим описанием. /* Параметры индикаторов web интерфейса для плагина Knob Мин Макс Шаг Заголовок Ед. измер. |---------------------|----|------|------|--------------|---------| */ knob_t *S = new knob_t(0, 40, ".1", "Скорость в.", "м/c"); Теперь объявим все необходимые константы. Обязательно укажите значения, подходящие для Вашего датчика. Учтите количество импульсов на один полный оборот, радиус анемометра и коэффициент для калибровки датчика. По сути этот коэффициент равен расхождению в скорости (м/c) между показаниями Вашего датчика и какого ни-ть эталонного, например другого анемометра. Можно собрать анемометр, покататься с ним на машине и сравнить показания, только помним о переводе км/ч в м/c. Я надеюсь, что зависимость линейная и все будет в порядке. /* Параметры конфигурации для расчета скорости ветра */ #define windSpeed_Pin 14 // GPIO микроконтроллера к которому подключен чашечный анемометр #define windSpeed_Pulses 1 // Количество импульсов на один оборот чашечного анемометра #define windSpeed_Correction 0 // Коэффициент поправки. Разница в скорости м/с между измеренным и фактическим значением полученная при калибровки #define windSpeed_Radius 100 // Радиус чашечного анемометра от центра до середины чашечки в милиметрах Объявим переменные для хранения показаний частоты и расчетной скорости. uint32_t windSpeed_Hz = 0; // Тут будет зафиксирована частота за ПЛАВАЮЩИЙ интервал времени float windSpeed = 0; // Тут будет зафиксирована скорость ветра Далее опишем функцию, которая будет вызываться по прерыванию и изменять показания частоты /* Функция, регистрирующая импульсы с чашечного анемометра */ void pulseDetected() { ++windSpeed_Hz; } Переходим к основной функции, отвечающей за расчет скорости ветра. Обязательно все за мной перепроверяйте т.к я мог ошибиться в расчетах или что-то сделать не так. На время расчетов мы выключаем регистрацию новых импульсов. За время мы возьмем интервал между предыдущим вызовом этой функции и текущим. Рассчитаем длину окружности и общий пройденный путь. Полученный результат запишем в одну из объявленных ранее глобальных переменных. /* Функция, производящая расчет скорости ветра */ void pulseCounter() { detachInterrupt(windSpeed_Pin); // Отключаем регистрацию импульсов на время расчета /* Расчет скорости ветра */ if (windSpeed_Hz) { float time = cron.lastRun("Wind Speed Calculation") / 1000; // Время прошедшее с последнего расчета скорости ветра в секундах float circumference = 3.14 * 2 * windSpeed_Radius; // Длинна окружности анемометра в милиметрах float distance = (windSpeed_Hz / windSpeed_Pulses) * circumference; // Пройденое растояние в милиметрах float speed = distance / time / 1000; // Скорость в метрах в секунду (грязная) windSpeed = speed + windSpeed_Correction; // Скорость ветра с учетом коректировки } else windSpeed = 0; /* Сброс частоты */ windSpeed_Hz = 0; attachInterrupt(windSpeed_Pin, pulseDetected, FALLING); // Возобновляем регистрацию импульсов } Опишем функцию возвращающую расчетный результат скорости. /* Функция, возвращающая последнее расчетное значение скорости ветра */ float getWindSpeed() { return windSpeed; } Ну и осталось самое главное, это функция описывающая наши сенсоры. void sensors_config() { pinMode(windSpeed_Pin, INPUT_PULLUP); // Конфигурируем порт микроконтроллера как вход с активным встроенным подтягивающим резистором attachInterrupt(windSpeed_Pin, pulseDetected, FALLING); // Регистрация импульсов с чашечного анемометра по прерыванию на землю cron.add(cron::time_10s, pulseCounter, "Wind Speed Calculation"); // Задача в планировщике для расчета скорости ветра sensors.add(S, device::out, "windSpeed", getWindSpeed); // Добавляем сенсор скорости ветра в web интерфейс } Как мы видим, тут происходит инициализация порта микроконтроллера на вход с подтяжкой к питанию. Объявление прерывания. А также добавление задачи по расчету скорости в планировщик и добавление нашего сенсора. Еще раз напоминаю, что я не могу гарантировать работоспособность данного решения, у меня нет возможности это проверить. Внимательно все просмотрите, я постарался везде указать комментарии. Помните, что импульсы считаются по прерыванию на землю, Вы должны гарантировать, что схема датчика будет их генерировать. На всякий случай прикрепляю готовый файл. users_wspeed.zip
  7. Ничем не отличается. Разницы нет, это просто уникальные идентификаторы для подсетей.
  8. Вроде бы и ничего сложного тут нет, но то параметр забудешь, то еще какая ни-ть мелочь, а по справке бегать как всегда нет особого желания. В общем оставляю лично для себя. find /catalog -type d -exec chmod 755 {} \; find /catalog -type f -exec chmod 644 {} \;
  9. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Доброе время суток. Электронных компонентов для проверки у меня нет, но я постараюсь помочь, опираясь на код библиотеки. Все фактические проверки Вам придется произвести самостоятельно. Я буду использовать эту библиотеку https://github.com/bogde/HX711, Вы можете использовать любую другую, просто действуйте по аналогии. В первую очередь необходимо определиться с используемыми портами микроконтроллера. Предлагаю задействовать 12 и 13 порты, но т.к они уже были использованы ранее, то в основном файле проекта необходимо закомментировать вызов функции gpio_12_13(). Я выбрал эти порты для примера, возможно Вы задействуете какие ни-ть другие. /* Инициализация GPIO для управления внешней нагрузкой */ //gpio_12_13(); // Простое превышение температуры или влажности (выставляется в WEB интерфейсе) Теперь мы уверенны, что порты не заняты и можем переходить к реализации весов. Я предположу, что для описания сенсоров Вы используете один из пользовательских файлов имена которых начинаются с users_. В начале файла подключаем выбранную библиотеку. #include "HX711.h" Объявляем объект с помощью которого будем работать с весами. При объявлении мы передаем в качестве параметров номера задействованных портов. HX711 scale(12, 13); Создадим описание для системы визуализации (плагин Knob). knob_t *W = new knob_t(-100, 10000, "1", "Вес", "Гр"); Мне не известно какой датчик Вы будите использовать, поэтому значения я выбрал на свое усмотрение. Минимальный вес равен -100 грамм, максимальный 10000 грамм, шаг шкалы 1, описание сенсора "Вес", ну и "Гр" в качестве единиц измерения. Минимальный вес в -100 грамм взят не случайно, так Вам будет проще найти калибровочный коэффициент. Теперь модифицируем функцию sensors_config() и объявим новый сенсор. /* Добавление датчиков в систему */ void sensors_config() { /* Тут описан код других датчиков */ scale.set_scale(3); // калибровочный коэффициент scale.tare(); // тарирование sensors.add(W, device::in, "in_weight", [&](){ return scale.get_units() * 0.035274; // перевод в граммы }); } В теории, этого должно быть достаточно. Обратите внимание на калибровочный коэффициент, я указал значение 3, у Вас это будет свое значение уникальное для Вашего датчика. scale.set_scale(3); Также обратите внимание, что при запуске микроконтроллера происходит тарирование весов. scale.tare(); Отпишитесь о результатах.
  10. Kitsum

    esp8266 и парсинг погоды с OpenWeatherMap

    Доброе время суток. @Же ка Ваша проблема скорее всего связана с ошибочным значением в переменной appid. Возможно опечатка или Вы не прошли до конца процесс получения ключа. Проверьте все еще раз. Таблицу с кодами ответов можно посмотреть тут https://ru.wikipedia.org/wiki/Список_кодов_состояния_HTTP#401 А вот тестовый пример для проверки API. https://samples.openweathermap.org/data/2.5/weather?lat=35&lon=139&appid=b6907d289e10d714a6e88b30761fae22
  11. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Убедитесь в работоспособности проекта без строки корректировки. Проверьте датчик стандартным скетчем, идущим в примере с библиотекой. Укажите в качестве температуры и влажности какие-нибудь значения, можно статичные. Посмотрите на результат длительной работы.
  12. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Доброе время суток. Большинство самостоятельно добавляет необходимый функционал. Как мне кажется, на текущий момент в проекте очень много проблем, думаю, что следующую версию имеет смысл делать для контроллера ESP32. А для всего остального всегда можно получить ответ на форуме. Но, возможно, я ошибаюсь... Это связано с тем, что на одном графике отображается информация с нескольких сенсоров, это сопровождается некоторым описанием для каждого из них. На все это требуется место для визуализации, и только свободная часть используется для вывода данных с сенсоров. В итоге, на маленьком разрешении рассмотреть что-либо практически невозможно. Но если хочется её вернуть, то в файле index.htm найдите следующий фрагмент css кода. @media screen and (max-width:610px) { #graph { display: none; } div.copyright { position: unset; } } И удалите из него строку #graph { display: none; } Не забудьте запаковать файл обратно в .gz формат Это зависит от самого датчика. В проекте данные проходят только через медианный фильтр, класс medianFilter_t в файле tools.h. По сути, это просто накопительный буфер для сглаживания случайных пиков. Больше информации можно посмотреть тут https://ru.wikipedia.org/wiki/Медианный_фильтр В ранних версиях используемой библиотеки это не было реализовано. Интересно посмотреть, как это повлияет на показания. В файле users_auto.h есть пример кода для работы с датчиком #if SENSOR_CCS811 sensors.add(C, device::out, 0x5A, "out_co2", [&](){ ccs811.begin(); ccs811.start(CCS811_MODE_1SEC); }, [&](){ uint16_t eco2, etvoc, errstat, raw; ccs811.read(&eco2, &etvoc, &errstat, &raw); return eco2; }, true); #endif Замените его на этот #if SENSOR_CCS811 sensors.add(C, device::out, 0x5A, "out_co2", [&](){ ccs811.begin(); ccs811.start(CCS811_MODE_1SEC); }, [&](){ uint16_t eco2, etvoc, errstat, raw; ccs811.set_envdata(sensors.get("out_temperature"), sensors.get("out_humidity")); ccs811.read(&eco2, &etvoc, &errstat, &raw); return eco2; }, true); #endif Разница всего в одной строке ccs811.set_envdata(sensors.get("out_temperature"), sensors.get("out_humidity")); Где out_temperature и out_humidity, это имена объявленных Вами сенсоров температуры и влажности.
  13. Kitsum

    esp8266 и парсинг погоды с OpenWeatherMap

    @В К Найдите строку postingInterval = find ? 600L * 1000L : 60L * 1000L; и замените ее на postingInterval = find ? 3600L * 1000L : 60L * 1000L;
  14. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Вы можете воспользоваться решением указанным несколько постов ранее, только внесите одно изменение. Замените запрос температуры по индексному номеру датчика sensors.add(T, device::in, "ds18b20_s0", [&](){ return ds18b20.getTempCByIndex(0); }); на запрос по уникальному серийному номеру sensors.add(T, device::in, "ds18b20_s0", [&](){ return ds18b20.getTempC({ 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0 }); }); После этих изменений датчику c идентификатором ds18b20_s0 будет соответствовать DS18B20 с адресом 0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0
  15. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Попробуйте провести эксперимент используя только один из двух датчиков по очереди чтобы попытаться исключить неисправность датчиков. Или временно замените датчики на другие. Убедитесь, что сама линия имеет надежные контактные соединения с контроллером и датчиками. Проверьте исправность подтягивающего резистора на шине 1 wire. Попробуйте подключать датчики без использования паразитного питания если конечно последнее используется. Воспользуйтесь одним из стандартных примеров библиотеки DallasTemperature для 10-15 минутного теста.
  16. Kitsum

    Метеостанция на ESP8266 от it4it.club

    Доброе время суток. Да конечно, но проверить работоспособность Вам придется самостоятельно. В первую очередь Вам понадобятся следующие библиотеки: OneWire https://github.com/PaulStoffregen/OneWire DallasTemperature https://github.com/milesburton/Arduino-Temperature-Control-Library Скачиваем и добавляем их в Arduino IDE. Первая необходима для реализации обмена данными через шину 1 wire, а вторая представляет из себя всю необходимую реализацию для работы с датчиками серии DS18. Теперь необходимо определиться с тем, какой порт мы задействуем под шину 1 wire, это важно т.к в проекте уже задействовано много портов, а ESP8266 очень в них ограничена. Из свободных и безопасных остался только GPIO16 (D0 на платах NodeMCU) но с ним могут быть проблемы, в любом случае это стоит проверить. Если вдруг не получится, то придется задействовать один из портов, используемых для управления нагрузкой, например, GPIO14 (D5 на платах NodeNCU). Ранее мы использовали его для управления нагрузкой по разности показаний между двумя датчиками BME280. ВАЖНО: если с GPIO16 не получится и придется использовать GPIO14, то в основном файле программы закомментируйте вызов функции инициализации данного порта // gpio_14(); Все необходимое для работы с DS18B20 будем описывать в файле users_bme280_x2.h т.к по всей видимости именно им Вы и пользуетесь в работе с двумя датчиками BME280. Подключаем дополнительные библиотеки. #include <OneWire.h> #include <DallasTemperature.h> Следом можно объявить все необходимые объекты для работы с шиной и датчиками. Я сразу укажу варианты для разных портов. DallasTemperature ds18b20(new OneWire(16)); // GPIO16 (D0) // DallasTemperature ds18b20(new OneWire(14)); // GPIO14 (D5) Теперь доработаем функцию sensors_config так, чтобы в ней появились следующие дополнительные строки void sensors_config() { /* тут описан код других датчиков */ ds18b20.begin(); cron.add(cron::time_5s, [&](){ ds18b20.requestTemperatures(); }, true); sensors.add(T, device::in, "ds18b20_s0", [&](){ return ds18b20.getTempCByIndex(0); }); sensors.add(T, device::in, "ds18b20_s1", [&](){ return ds18b20.getTempCByIndex(1); }); } Пару слов о том, что мы добавили в эту функцию. Инициализация шины 1 wire ds18b20.begin(); Добавляем в планировщик новое задание которое будет отвечать за рассылку телеграммы по шине с целью запроса температуры у всех имеющихся датчиков. Последний параметр (true) заставит задачу отработать сразу при добавлении в планировщик. cron.add(cron::time_5s, [&](){ ds18b20.requestTemperatures(); }, true); Далее описываем каким способом собирать данные с датчиков sensors.add(T, device::in, "ds18b20_s0", [&](){ return ds18b20.getTempCByIndex(0); }); sensors.add(T, device::in, "ds18b20_s1", [&](){ return ds18b20.getTempCByIndex(1); }); В данном представлении датчики объявлены как внутренние - device::in (можете объявить их как внешние device::out), и имеют идентификаторы в системе ds18b20_sX, где X это индекс датчика найденного библиотекой DallasTemperature. Эта информация будет полезна если появится необходимость вывода данных с этих датчиков на общий график. В теории все должно заработать. Отпишитесь пожалуйста о своих результатах.
  17. Kitsum

    Метеостанция на ESP8266 от it4it.club

    @Сергій Артеменко доброе время суток. Это возможно. Один из вариантов, это добавить в планировщик задач новое задание, которое будет, например, раз в час перезаписывать определенный файл во Flash памяти и сохранять туда данные по всем точкам графика. Сами данные хранить в формате JSON. При старте микроконтроллера читать этот файл, разбирать JSON и заполнять массив в оперативной памяти. В принципе это не сложная задача, практически все необходимое уже реализовано в коде. Из минусов можно отметить следующее: При перезагрузке точки на графике могут сдвинуться на время равное тому интервалу времени пока контроллер был выключен. Чем дольше не было питания, тем больше будет рассогласование. Это связано с тем, что контроллер не хранит отметки времени для точек на графике, отсчет идет от последней сохраненной точки с известными интервалами времени опираясь на время устройства с которого просматривается график. Это сделано для того, чтобы отказаться от учета реального времени на микроконтроллере. Любая Flash память имеет ограничение на количество циклов перезаписи, ESP8266 не исключение и число циклов составляет примерно 100000. Если перезаписывать Flash раз в час, то срок жизни будет составлять примерно чуть более 11 лет.
  18. Просмотреть файл [esp8266] Библиотека smartBlink, реализует умное управление штатным светодиодом, что позволяет добавить индикацию состояния вашей программы или микроконтроллера. Основная задача библиотеки, это добавление индикации состояния Вашей программы или микроконтроллера. Отображение состояния производится посредством светодиода. Что самое важное, работа библиотеки через прерывание, это позволяет ей поддерживать индикацию даже в то время, когда выполняется длительный код основной программы. Например, Вы можете использовать её для отображения в каком режиме сейчас работает WiFi микроконтроллера, STA или AP и т.д. Или ход выполнения какой-либо операции, например, передача данных на внешний сервер. Подключение библиотеки #include <smartBlink.h> Чтобы инициализировать управление светодиодом необходимо создать объект, через который мы буем задавать режимы работы индикации. smartBlink::smartBlink(byte gpio, bool on = LOW); Объекту необходимо передать два параметра, первый это номер порта, на котором находится светодиод, а второй это уровень логического сигнала, который заставит светодиод работать. Сигнал может быть низким (LOW) или высоким (HIGH), это зависит от схемотехники подключения светодиода. Например, штатный светодиод модуля ESP12, использующий GPIO2 (порт 2) можно объявить следующим образом. #define led2_pin 2 #define led2_on_signal LOW smartBlink led2(led2_pin, led2_on_signal); Теперь можно в основной программе использовать метод устанавливающий какой режим индикации использовать. smartBlink::setMode(mode_t mode); Например, зададим режим светодиода led2 в котором светодиод будет давать одну короткую вспышку раз в секунду. led2.setMode(smartBlink::mode_flash1); Режимов работы может быть несколько. led2.setMode(smartBlink::mode_off); led2.setMode(smartBlink::mode_flash1); led2.setMode(smartBlink::mode_flash2); led2.setMode(smartBlink::mode_flash3); led2.setMode(smartBlink::mode_flash4); led2.setMode(smartBlink::mode_burn); led2.setMode(smartBlink::mode_inhalf); Чтобы вернуть предыдущий режим индикации для ранее объявленного светодиода led2 используйте следующий метод led2.previous(); Благодаря работе библиотеки через прерывания по таймеру, индикация будет работать даже в тех случаях, когда выполняется долгий код. С библиотекой идут несколько примеров. Автор Kitsum Добавлен 10.12.2018 Категория Библиотеки  
  19. Версия 1.0

    7 скачиваний

    Основная задача библиотеки, это добавление индикации состояния Вашей программы или микроконтроллера. Отображение состояния производится посредством светодиода. Что самое важное, работа библиотеки через прерывание, это позволяет ей поддерживать индикацию даже в то время, когда выполняется длительный код основной программы. Например, Вы можете использовать её для отображения в каком режиме сейчас работает WiFi микроконтроллера, STA или AP и т.д. Или ход выполнения какой-либо операции, например, передача данных на внешний сервер. Подключение библиотеки #include <smartBlink.h> Чтобы инициализировать управление светодиодом необходимо создать объект, через который мы буем задавать режимы работы индикации. smartBlink::smartBlink(byte gpio, bool on = LOW); Объекту необходимо передать два параметра, первый это номер порта, на котором находится светодиод, а второй это уровень логического сигнала, который заставит светодиод работать. Сигнал может быть низким (LOW) или высоким (HIGH), это зависит от схемотехники подключения светодиода. Например, штатный светодиод модуля ESP12, использующий GPIO2 (порт 2) можно объявить следующим образом. #define led2_pin 2 #define led2_on_signal LOW smartBlink led2(led2_pin, led2_on_signal); Теперь можно в основной программе использовать метод устанавливающий какой режим индикации использовать. smartBlink::setMode(mode_t mode); Например, зададим режим светодиода led2 в котором светодиод будет давать одну короткую вспышку раз в секунду. led2.setMode(smartBlink::mode_flash1); Режимов работы может быть несколько. led2.setMode(smartBlink::mode_off); led2.setMode(smartBlink::mode_flash1); led2.setMode(smartBlink::mode_flash2); led2.setMode(smartBlink::mode_flash3); led2.setMode(smartBlink::mode_flash4); led2.setMode(smartBlink::mode_burn); led2.setMode(smartBlink::mode_inhalf); Чтобы вернуть предыдущий режим индикации для ранее объявленного светодиода led2 используйте следующий метод led2.previous(); Благодаря работе библиотеки через прерывания по таймеру, индикация будет работать даже в тех случаях, когда выполняется долгий код. С библиотекой идут несколько примеров.
  20. Просмотреть файл [esp8266] Библиотека Cron, реализует планировщик задач для периодического выполнения пользовательских функций. Основная задача библиотеки, это вызов пользовательских функций через установленный интервал времени. Библиотека работает по схожему принципу с широко известной программой Cron распространяемой в составе UNIX систем. От этой утилиты библиотека и унаследовала название. Библиотека работает исходя из принципов однопоточного выполнения кода в микроконтроллере. Когда обработчик библиотеки получает процессорное время, он проверяет список всех пользовательских задач в поиске задач, которые необходимо выполнить, основываясь на установленном интервале времени для каждой задачи. Данная библиотека предоставляет следующий функционал Позволяет добавлять большое количество пользовательских заданий в виде функций. Количество задач ограничено только их сложностью и свободной памятью микроконтроллера. Предоставляет возможность холодного старта задачи. Дает возможность вызова задачи при старте микроконтроллера с последующим выполнением задачи через установленный интервал времени. Поиск задачи по лексическому идентификатору. Получение время последнего вызова задачи. Обнуление интервала вызова задачи или установку нового интервала в мс. Останавливать задачу на неопределенный срок. Проверять активность задачи. Подключение библиотеки #include <cron.h> Пример добавление задачи, которая вызывает функцию blink_f каждую секунду cron.add(1000, blink_f); Добавление этой же задачи в режиме холодного старта cron.add(1000, blink_f, true); Добавление задачи и присвоение ей человек понятного идентификатора cron.add(1000, blink_f, "Blink"); Добавление задачи с холодным стартом и присвоением ей человек понятного идентификатора cron.add(1000, blink_f, "Blink", true); В качестве временного интервала вызова задачи необходимо указывать количество миллисекунд. Но можно воспользоваться готовыми константами. Фундаментальные константы cron::second cron::minute cron::hour cron::day Самые распространенные значения cron::time_1s cron::time_5s cron::time_10s cron::time_15s cron::time_30s cron::time_1m cron::time_5m cron::time_10m cron::time_15m cron::time_30m cron::time_1h cron::time_5h cron::time_10h cron::time_12h cron::time_1d С константами можно производить арифметические операции чтобы получить необходимые временные интервалы. cron.update("Blink", cron::time_1s); cron.update("Blink", cron::time_1s * 12); cron.update("Blink", cron::time_30s + 500); и т.д В функции loop должна находится команда вызова обработчика. void loop() { cron.handleEvents(); } Поиск задачи по установленному ранее идентификатору cron.find("Blink"); В ответ возвращается объект типа cronEvent который содержит все данные задачи или 0 если задача не была найдена. Можно использовать в качестве простой проверки. if (cron.find("Blink")) { /* … */ } Следующий метод позволяет получить время последнего вызова задачи uint32_t time = cron.lastRun("Blink"); В качестве параметра можно передать идентификатор с типом cronEvent полученный с помощью метода поиска задачи. Перезапуск таймера задачи производится следующим образом cron.update("Blink"); А так можно установить новый интервал вызова задачи cron.update("Blink", cron::time_10m); Остановка выполнения задачи cron.stop("Blink"); Проверка активности задачи bool active = cron.isActive("Blink"); С библиотекой идут несколько примеров. Автор Kitsum Добавлен 09.12.2018 Категория Библиотеки  
  21. Версия 1.0

    12 скачиваний

    Основная задача библиотеки, это вызов пользовательских функций через установленный интервал времени. Библиотека работает по схожему принципу с широко известной программой Cron распространяемой в составе UNIX систем. От этой утилиты библиотека и унаследовала название. Библиотека работает исходя из принципов однопоточного выполнения кода в микроконтроллере. Когда обработчик библиотеки получает процессорное время, он проверяет список всех пользовательских задач в поиске задач, которые необходимо выполнить, основываясь на установленном интервале времени для каждой задачи. Данная библиотека предоставляет следующий функционал Позволяет добавлять большое количество пользовательских заданий в виде функций. Количество задач ограничено только их сложностью и свободной памятью микроконтроллера. Предоставляет возможность холодного старта задачи. Дает возможность вызова задачи при старте микроконтроллера с последующим выполнением задачи через установленный интервал времени. Поиск задачи по лексическому идентификатору. Получение время последнего вызова задачи. Обнуление интервала вызова задачи или установку нового интервала в мс. Останавливать задачу на неопределенный срок. Проверять активность задачи. Подключение библиотеки #include <cron.h> Пример добавление задачи, которая вызывает функцию blink_f каждую секунду cron.add(1000, blink_f); Добавление этой же задачи в режиме холодного старта cron.add(1000, blink_f, true); Добавление задачи и присвоение ей человек понятного идентификатора cron.add(1000, blink_f, "Blink"); Добавление задачи с холодным стартом и присвоением ей человек понятного идентификатора cron.add(1000, blink_f, "Blink", true); В качестве временного интервала вызова задачи необходимо указывать количество миллисекунд. Но можно воспользоваться готовыми константами. Фундаментальные константы cron::second cron::minute cron::hour cron::day Самые распространенные значения cron::time_1s cron::time_5s cron::time_10s cron::time_15s cron::time_30s cron::time_1m cron::time_5m cron::time_10m cron::time_15m cron::time_30m cron::time_1h cron::time_5h cron::time_10h cron::time_12h cron::time_1d С константами можно производить арифметические операции чтобы получить необходимые временные интервалы. cron.update("Blink", cron::time_1s); cron.update("Blink", cron::time_1s * 12); cron.update("Blink", cron::time_30s + 500); и т.д В функции loop должна находится команда вызова обработчика. void loop() { cron.handleEvents(); } Поиск задачи по установленному ранее идентификатору cron.find("Blink"); В ответ возвращается объект типа cronEvent который содержит все данные задачи или 0 если задача не была найдена. Можно использовать в качестве простой проверки. if (cron.find("Blink")) { /* … */ } Следующий метод позволяет получить время последнего вызова задачи uint32_t time = cron.lastRun("Blink"); В качестве параметра можно передать идентификатор с типом cronEvent полученный с помощью метода поиска задачи. Перезапуск таймера задачи производится следующим образом cron.update("Blink"); А так можно установить новый интервал вызова задачи cron.update("Blink", cron::time_10m); Остановка выполнения задачи cron.stop("Blink"); Проверка активности задачи bool active = cron.isActive("Blink"); С библиотекой идут несколько примеров.
  22. Kitsum

    Метеостанция на ESP8266 от it4it.club

    @pvspec доброе время суток. В файле index.htm найдите строку function checkSSID(ssid) { return ssid.match(/^[a-z0-9_. -]{3,30}$/i); } замените её на function checkSSID(ssid) { return ssid.match(/^[a-z0-9_. -]{2,30}$/i); }
  23. Просмотреть файл [esp8266] Библиотека CMD, реализует настройку микроконтроллера и управление вашей программой через терминал. Основная задача библиотеки, это прием пользовательских команд через UART интерфейс, их обработка и выполнение пользовательского кода, связанного с той или иной командой. Данная библиотека позволяет реализовать: Управление микроконтроллером Любую настройку, будь то WiFi, другие библиотеки или часть Вашей программы Вызывать Ваши задачи (функции) из терминала по команде и передавать им требуемые параметры Использовать контроллер в качестве шлюза между датчиками и программами на PC Внимание: любая команда, передаваемая в терминал обязана заканчиваться символом перевода строки "\n". Подключение библиотеки #include <cmd.h> Инициализация объекта, к которому мы будем обращаться для добавления команд. В качестве параметра объекту необходимо передать указатель на объект Serial или любой другой схожий по типу интерфейс. cmd command(&Serial); В функции Setup описываем какие команды требуется обрабатывать. Например, по команде "test" вызывать пользовательскую функцию с именем "myFunctionName". Имя пользовательской функции может быть абсолютно любым. void Setup() { Serial.begin(115200); command.add("test", myFunctionName); } Пользовательская функция будет вызываться каждый раз, когда по интерфейсу Serial поступит команда "test". Если команда будет передана с параметрами, то эти параметры будут переданы в качестве аргументов пользовательской функции. В функции loop должна находится команда вызова обработчика. void loop() { command.handleEvents(); } Пользовательская функция обязана соответствовать ряду требований: Не возвращать никакого результата (быть объявленной с типом void) Принимать в качестве первого аргумента переменную с типом byte в которой будет храниться число равное количеству переданных параметров Принимать в качестве второго параметра переменную с типом char** в которой будет храниться указатель на массив со всеми указателями (char*) на переданные параметры void myFunctionName(byte argc, char** argv) { /* ... */ } Функция всегда должна иметь такой вид, даже если не подразумевается, что ей будут передаваться какие-либо параметры. Чтобы перебрать все переданные параметры и вывести их в консоль, можно воспользоваться следующим примером void myFunctionName(byte argc, char** argv) { if (0 < argc) { for (uint8_t i = 0; i < argc; i++) { Serial.printf("%i. %s\n", i, argv[i]); } } } Пример вызова пользовательской функции без параметров и с ними # test No parameter was passed # test p1 p2 p3 p4 p5 0. p1 1. p2 2. p3 3. p4 4. p5 Помните, что параметры представлены в виде указателей и работать с ними нужно как с обычными переменными не получится т.к указатель содержит не значение переменной (переданный параметр), а указатель на ту область памяти микроконтроллера в которой это значение находится. Чтобы сравнить два значения, например, параметр под индексом 0 (идет первым в списке) с каким-либо значением в программе, воспользуйтесь функцией strcmp, которая возвращает целочисленное значение, указывающее на лексическое расхождение строк. Если строки равны, то возвращаемое значение равно 0. if (!strcmp(argv[0], "wifi")) { Serial.println(F("Первый аргумент WiFi")); } else { Serial.println(F("Первый аргумент НЕ WiFi!!!")); } Для копирования значения указателя в другую переменную с типом char можно воспользоваться функцией strcpy char myVar[20]; strcpy(myVar, argv[0]); if (myVar == "123456") { Serial.prinln(F("ok")); } Также можно обернуть указатель объектом String и получить весь функционал этого объекта, который будет содержать значение параметра String param1(argv[0]); // String param1 = argv[0]; Serial.printf("argv[0] length: %i\n", param1.length()); Serial.printf("argv[0] is integer?: %s\n", param1.toInt() ? "YES" : "NO"); if (param1 == "qwerty") { Serial.println(F("Hello QWERTY!")); } С библиотекой идут несколько примеров, в том числе и пример конфигурации WiFi в режиме STA. Автор Kitsum Добавлен 05.12.2018 Категория Библиотеки  
  24. Версия 1.0

    10 скачиваний

    Основная задача библиотеки, это прием пользовательских команд через UART интерфейс, их обработка и выполнение пользовательского кода, связанного с той или иной командой. Данная библиотека позволяет реализовать: Управление микроконтроллером Любую настройку, будь то WiFi, другие библиотеки или часть Вашей программы Вызывать Ваши задачи (функции) из терминала по команде и передавать им требуемые параметры Использовать контроллер в качестве шлюза между датчиками и программами на PC Внимание: любая команда, передаваемая в терминал обязана заканчиваться символом перевода строки "\n". Подключение библиотеки #include <cmd.h> Инициализация объекта, к которому мы будем обращаться для добавления команд. В качестве параметра объекту необходимо передать указатель на объект Serial или любой другой схожий по типу интерфейс. cmd command(&Serial); В функции Setup описываем какие команды требуется обрабатывать. Например, по команде "test" вызывать пользовательскую функцию с именем "myFunctionName". Имя пользовательской функции может быть абсолютно любым. void Setup() { Serial.begin(115200); command.add("test", myFunctionName); } Пользовательская функция будет вызываться каждый раз, когда по интерфейсу Serial поступит команда "test". Если команда будет передана с параметрами, то эти параметры будут переданы в качестве аргументов пользовательской функции. В функции loop должна находится команда вызова обработчика. void loop() { command.handleEvents(); } Пользовательская функция обязана соответствовать ряду требований: Не возвращать никакого результата (быть объявленной с типом void) Принимать в качестве первого аргумента переменную с типом byte в которой будет храниться число равное количеству переданных параметров Принимать в качестве второго параметра переменную с типом char** в которой будет храниться указатель на массив со всеми указателями (char*) на переданные параметры void myFunctionName(byte argc, char** argv) { /* ... */ } Функция всегда должна иметь такой вид, даже если не подразумевается, что ей будут передаваться какие-либо параметры. Чтобы перебрать все переданные параметры и вывести их в консоль, можно воспользоваться следующим примером void myFunctionName(byte argc, char** argv) { if (0 < argc) { for (uint8_t i = 0; i < argc; i++) { Serial.printf("%i. %s\n", i, argv[i]); } } } Пример вызова пользовательской функции без параметров и с ними # test No parameter was passed # test p1 p2 p3 p4 p5 0. p1 1. p2 2. p3 3. p4 4. p5 Помните, что параметры представлены в виде указателей и работать с ними нужно как с обычными переменными не получится т.к указатель содержит не значение переменной (переданный параметр), а указатель на ту область памяти микроконтроллера в которой это значение находится. Чтобы сравнить два значения, например, параметр под индексом 0 (идет первым в списке) с каким-либо значением в программе, воспользуйтесь функцией strcmp, которая возвращает целочисленное значение, указывающее на лексическое расхождение строк. Если строки равны, то возвращаемое значение равно 0. if (!strcmp(argv[0], "wifi")) { Serial.println(F("Первый аргумент WiFi")); } else { Serial.println(F("Первый аргумент НЕ WiFi!!!")); } Для копирования значения указателя в другую переменную с типом char можно воспользоваться функцией strcpy char myVar[20]; strcpy(myVar, argv[0]); if (myVar == "123456") { Serial.prinln(F("ok")); } Также можно обернуть указатель объектом String и получить весь функционал этого объекта, который будет содержать значение параметра String param1(argv[0]); // String param1 = argv[0]; Serial.printf("argv[0] length: %i\n", param1.length()); Serial.printf("argv[0] is integer?: %s\n", param1.toInt() ? "YES" : "NO"); if (param1 == "qwerty") { Serial.println(F("Hello QWERTY!")); } С библиотекой идут несколько примеров, в том числе и пример конфигурации WiFi в режиме STA.
  25. Kitsum

    Счетчик воды esp8266

    Все доброго времени суток. Набросал тестовую программу для учета расхода воды при использовании счетчиков с импульсным выходом. На данный момент программа очень простая и основная её задача - это отловить все подводные камни при учете показаний. Если наше маленькое сообщество поможет это сделать, то выпустим полноценный вариант с собственным web сервером для наблюдения за текущими показаниями, графиками, отправкой данных на внешние сервера и разными дополнительными настройками. В общем приведем это все к реализации похожей на ту, что используется в метеостанции в соседней теме. Помощь нужна по одной простой причине, у меня дома не подключены счетчики с импульсным выходом. Естественно, что в будущем это будет исправлено, но на данный момент инструмент накрутки импульсов отсутствует. А если у кого-то уже имеются подключенный счетчик, энтузиазм и свободное время, то это может пойти на общее благо. В тестовой программе реализован необходимый минимум для учета показаний: Учет показаний по двум канал (горячая, холодная) с счетчиков, обладающих импульсным выходом, работающим по принципу сухого контакта. Подключение (переподключение) к домашней точке доступа Передача показаний счетчиков на удаленный MQTT сервер Корректировка показаний счетчиков через публикацию сообщений в специализированных топиках на MQTT сервера Корректировка количества импульсов на единицу значения счетчика через специализированный топик на MQTT сервере Хранение показаний в энергонезависимой памяти на случай пропажи питающего напряжения Теперь немного по программе. Для снятия показаний используются прерывания по спаду логического сигнала на каждом из каналов. Это означает, что сухой контакт (импульсный выход) счетчика воды будет коммутировать землю и порт микроконтроллера, последний, в свою очередь, будет настроен как вход с внутренней подтяжкой к питанию. Это позволит использовать очень длинные провода от счетчика до микроконтроллера, что довольно полезно для тех, кто хочет снять показания с счетчика воды установленного в колодце частного дома (на улице) или в любых схожих ситуациях. Программа контроллера не использует спящий режим или другие энергосберегающие приемы, что подразумевает питание от внешнего источника, например, блока питания от старого телефона. Но можно взять у наших братьев с востока контроллер с DC-DC преобразователем и картриджем для литиевого аккумулятора 18650. Вообще резервирование питания не обязательно, я просто перестраховываюсь на случай отключения электроэнергии в то время, когда будет иметь место фактический расход воды. В первую очередь для реализации Вам понадобится дополнительная библиотека PubSubClient использующаяся для связи с MQTT сервером. Она доступна в каталоге библиотек среды разработки Arduino IDE. Что касаемо настроек, то в первой версии оставим их в самом коде. Сетевые настройки /* Настройки подключения */ String ssid = "AP_Name"; // Имя домашней точки доступа String pass = "AP_Pass"; // Пароль к домашней точки доступа String server = "mqtt.it4it.club"; // Адрес MQTT сервера String device = "waterCounter"; // Обязательно уникальное имя для каждого MQTT клиента Если вы пользуетесь собственным MQTT сервером, то имя устройства можно не менять, в противном случае укажите иное имя или оставьте его пустым и в таком случае будет использован WiFi идентификатор устройства, содержащий два последний байта MAC адреса устройства. Настройки используемых портов /* Порты для подключения импульсного выхода с счетчиков */ byte HPort = 12; byte CPort = 14; Таблица соответствия портов ESP, плат WeMos и NodeMCU указана в комментариях в самом коде. Также имеется переменная отвечающая за то, какое количество импульсов необходимо поймать микроконтроллеру для учета одной единицы расхода воды. /* Устанавливаем какое количество импульсов требуется для сохранения данных и отправки их на сервер. 1 импульс = 0,01 куб.м (10 литров), 100 импульсов = 1 куб.м (1000 литров) оптимальное значение. */ uint16_t ppuv = 10; Обычно на счетчиках указано какое количество литров расхода соответствует одному импульсу и в большинстве случаев это 10 литров на 1 импульс. По умолчанию в программе используется значение в 10 импульсов, что равняется 100 литрам расхода воды. Это означает, что за 1 куб.м. расхода контроллер 10 раз передаст показания на сервер. Это также означает, что переданные значения будут содержать не только целое количество израсходованных кубов, но и десятую нового куба. (00000.1), по сути точность показаний при ppuv равным 10 будет 0.1 куба. Подправьте это значение под Ваш счетчик. Программа сохраняет показания в энергонезависимую память одновременно с передачей показаний на внешний сервер, важно это помнить т.к если использовать малое значение ppuv, например 1, то Flash память микроконтроллера будет очень часто перезаписываться, что приведет к быстрому выходу её из строя. В большинстве модулей ESP используется Flash память с минимальным количеством циклов перезаписи равным 100000. Это не мало, но вопрос в том, как расходовать. При ppuv равном 10 и средним расходом воды 10 куб.м. по каждому из каналов в месяц, микросхема выработает первые свои 100000 циклов через 4 года. В принципе мы легко повысим срок службы Flash памяти в следующих версиях, но на данный момент имеем эти показания. Если я где-то ошибся в математике при расчетах, то прошу меня ссаными тряпками не бить. Передача показаний на удаленный MQTT сервер Данные передаются в топик начинающийся с имени устройства указанного в конфигурации или WiFi идентификатора если имя не используется. Далее идут субтопики с именами hot и cold для обозначения горячей и холодной воды соответственно. Данные публикуются в виде целых чисел, и на самом деле может не быть целым числом т.к зависит от переменной ppuv. Просто имейте это в виду и отбрасывайте десятичную и т.п часть в голове. В будущей версии все это будет учтено. waterCounter/hot waterCounter/cold Корректировка показаний При подключении микроконтроллера к сети происходит подписка на топик MQTT сервера через который можно производить изменение текущих показаний и не только. waterCounter/settings/# По сути подписка оформляется на все субтопики родителем которых является субтопик settings. Это означает, что чтобы изменить показания горячей, холодной воды или значения ppuv можно опубликовать нужное значение в следующих топиках: waterCounter/settings/hot waterCounter/settings/cold waterCounter/settings/ppuv Значения должны быть целым числом и учитывать конфигурацию ppuv, а значит иметь дополнительные значения для чисел после запятой. То есть при значении счетчика в 555 кубов и ppuv равным 10 для стандартного счетчика, публикуемое значение для настроек должно быть 5550. Тестируйте, высказывайте предложения, делитесь идеями и наработками. Скачать исходник можно тут
×
×
  • Создать...