Найти в Дзене
K12 :: О ESP32 и не только

Термостат на ESP32 с удаленным управлением. Часть 7. Автоматический контроль диапазонов температуры

Добрый день, уважаемые читатели! Данная статья продолжает цикл статей, посвященных самодельному устройству на базе ESP32 DevKitC WROOM-32x и фреймворка Espressif IoT Development Framework. В прошлых статьях я рассказывал, как и из чего собрать устройство, а так же как создать самый простой вариант прошивки - устройство телеметрии. Для тех, кто пропустил начальные статьи серии, приведу ссылки на них, дабы вы смогли с ними ознакомиться: На текущий момент данная прошивка "умеет" считывать данные с подключенных сенсоров и отправлять их на различные сервера - MQTT брокер, Open Monitoring или (и) Thing Speak. В данном варианте устройство можно с успехом использовать как устройство телеметрии для дачи, гаража или, скажем, курятника. С помощью него можно периодически проверять температуру в доме и температуру "на выходе" из котла, дабы быть уверенным, что котел не погас и система не разморожена. Но, согласитесь, не очень удобно всё время "вручную" контролировать заданные параметры температур
Оглавление

Добрый день, уважаемые читатели! Данная статья продолжает цикл статей, посвященных самодельному устройству на базе ESP32 DevKitC WROOM-32x и фреймворка Espressif IoT Development Framework. В прошлых статьях я рассказывал, как и из чего собрать устройство, а так же как создать самый простой вариант прошивки - устройство телеметрии.

Для тех, кто пропустил начальные статьи серии, приведу ссылки на них, дабы вы смогли с ними ознакомиться:

На текущий момент данная прошивка "умеет" считывать данные с подключенных сенсоров и отправлять их на различные сервера - MQTT брокер, Open Monitoring или (и) Thing Speak. В данном варианте устройство можно с успехом использовать как устройство телеметрии для дачи, гаража или, скажем, курятника. С помощью него можно периодически проверять температуру в доме и температуру "на выходе" из котла, дабы быть уверенным, что котел не погас и система не разморожена.

Но, согласитесь, не очень удобно всё время "вручную" контролировать заданные параметры температуры. У нас таки умный дом или что?

Гораздо удобнее было бы, если бы могли задать какие-то пороговые значения, и при выходе температуры за пределы заданных диапазонов устройство могло само уведомить вас о возникших проблемах, например посредством Telegram. Это позволит оперативно обнаружить неполадки без необходимости постоянного рутинного "ручного" мониторинга.

Пример уведомлений в выходе параметра из диапазона
Пример уведомлений в выходе параметра из диапазона

Вот этим мы и займемся в данной статье. А заодно я познакомлю вас с одной из своих библиотек - Range Monitor.

На самом деле, контроль температуры с уведомлениями в Telegram уже присутствует прошивке и до написания этой статьи. Просто я хочу объяснить, как работают некоторые "составные части" прошивки до того, как мы начнем двигаться далее.

Немного про гистерезис

Сама по себе логика контроля диапазонов (не только температуры, а и любых других физических параметров - влажности, напряжения, уровня воды и т.д. и т.п.) кажется очень-очень простой - задал границы диапазонов и всё. Это может быть только нижний предел диапазона (ниже которого опускаться нельзя); или только верхний предел (выше которого подниматься не рекомендуется); или же оба сразу. Далее просто сравниваем измеренное значение с заданным с помощью операторов < и > и всё. Как только измеряемая величина вышла за пределы - отправляем уведомление. Все? Да нет, не совсем...

Температура в доме - вещь непостоянная. Я бы даже сказал "ветренная". Да и не только температура - и влажность, и напряжение и т.д. и т.п. Да и не только в доме - где угодно. За пару секунд температура может "пересечь" заданную вами границу несколько раз "туда" и "обратно". Совсем не как у Толкиена. Сенсоры, с помощью которых эта самая температура измеряется, так же вещь несовершенная, и дают некую погрешность. Всё это приводит к тому, что при приближении контролируемой температуры к заданной границе могут происходить множественные срабатывания алгоритма контроля, что обязательно приведет к парочке десятков уведомлений, то есть спаму со стороны умного дома. Что нам отнюдь не нужно.

Например мы задали "погоду в доме" не ниже 20 °С. При достижении этой отметки отправляем уведомление - "похолодало, примите меры". Но при следующем измерении сенсор выдал уже 20.01 °С. И устройство вновь шлет уведомление - "потеплело, расслабьтесь". А через еще пару секунд - 19,99 °С. И цикл начинается по новой....

Поэтому вводим ещё один параметр - так называемый гистерезис.

Источник: Яндекс Картинки
Источник: Яндекс Картинки

Гистерезис позволяет несколько "сместить" границу в зависимости от того, в каком состоянии находится контролирующая система. Например устройство будет отправлять уведомление при снижении температуры до заданной границы 20°С, а вот при возвращении в заданный диапазон уведомление будет отправлено только при 21°С или даже 23°С. То есть гистерезис по сути позволяет организовать небольшую зону "нечувствительности" в зависимости от состояния. Можно организовать гистерезис:

  • при выходе из диапазона - например отправлять уведомление о снижении температуры при 19°С, а при увеличении температуры - при 20°С
  • при возвращении в диапазон - например отправлять уведомление о снижении температуры при 20°С, а при увеличении температуры - при 21°С
  • симметрично - например отправлять уведомление о снижении температуры при 19,5°С, а при увеличении температуры - при 20,5°С (ну или не симметрично, никто не запрещает, но потребуется еще одна переменная)

Закат солнца вручную

Давайте таки уже будем писать наш г... хм, код. Как я уже писал выше, логика контроля диапазонов не представляет собой особых премудростей.

Для начала создадим новый тип - перечисление для хранения текущего состояния системы мониторинга, например так:

-4

Затем, само собой, создаем переменные для хранения этого самого состояния, для границ диапазонов и гистерезиса:

-5

Ну и осталось написать несложную функцию:

-6

Как я и говорил - ничего сложного. Здесь я применил готовую функцию отправки уведомлений в телегу из своих библиотек. Вы тоже можете её легко использовать, раз уж пишете код с использованием этих библиотек.

Ну и в основном цикле прикладной задачи, в которой происходит чтение данных с сенсоров (она у меня так и называется - sensors), добавим вызов этой функции с передачей ей в качестве аргумента текущего значения температуры. Проверять температуру имеет смысл только тогда, когда сам сенсор находится в нормальном состоянии и выдает корректные данные:

-7

Если вам нужен контроль диапазона температуры ещё по одному датчику - повторяем шаги описанные выше. Ровно столько раз, сколько вам требуется, с разными переменными и значениями.

Здесь вам самим придется придумать, как изменять границы диапазонов "извне" устройства. Ну а я использую немного другой способ, об чем будет рассказано ниже.

Используем класс reRangeMonitor

Спустя какое-то время приходит понимание, что уведомления-то они то хорошо, да маловато будет. Например уведомление может и не прийти из-за отсутствия интернета. Хотелось бы зафиксировать время "перехода" значения из одного состояния в другое. А если уж мы фиксируем состояние и время, то хотелось бы публиковать все это добро на MQTT-брокере для отображения всего этого в программе управления.

Кроме того, я очень (нет, таки очень-очень-очень-очень) не люблю повторять один и тот же код. Потому что любые мало-мальские изменения в нем придется повторить много раз в дальнейшем. Поэтому почти всегда код, который потенциально может быть использован в нескольких проектах, я выношу в отдельную библиотечку. В данном случае это напрашивалось само собой, тем более что классы очень удобно использовать многократно внутри одного проекта, и не нужно будет писать несколько отдельных функций.

Итак, представляю вам небольшую "классную" библиотечку:

GitHub - kotyara12/reRangeMonitor: Контроль значений (температуры, влажности, напряжения и т.д.) в заданных пределах

Какие функции она предоставляет:

  • Хранение текущего состояния (как я описывал выше)
  • Хранение меток времени последнего пересечения заданных границ и возвращения в нормальный диапазон
  • Хранение текущего значения (только для публикации на MQTT-брокере в виде JSON-пакета)
  • Генерацию JSON-пакета со всеми зафиксированными минимумами и максимумами, а также временными отметками для публикации на MQTT-брокере.
  • Хранение динамически созданного MQTT-топика (в моих проектах топики могут изменяться в зависимости от того, к какому брокеру - основному или резервному, подключено в данным момент устройство)
  • Отправка уведомлений осуществляется за счет подключенной callback функции, поэтому вы можете придумать свой способ уведомлений, например на email или в viber, например.

Как этим пользоваться

Конструктор класса выглядит следующим образом:

-8

Здесь мы сразу же задаем:

  • начальные границы диапазона и гистерезис (их можно будет потом изменить через MQTT-брокер)
  • имя для сохранения внутренних данных в NVS-хранилище
  • функцию обратного вызова для отправки уведомлений при изменении состояния
  • функцию обратного вызова для публикации данных на брокере

Последние три параметра можно не указывать при создании экземпляра, а "привязать" их позже, во время создания прикладной задачи.

Перво-наперво объявим статическую переменную, в которой будет храниться указатель на экземпляр класса reRangeMonitor. Здесь я как раз не стал указывать функции обратного вызова, так как переменная объявлена в заголовочном файле h, а все callback-и описаны в cpp. Их я подключу позже.

В данном случае тексты сообщений и некоторые константы вынесены в макросы #define. Это не обязательно, но лично мне так гораздо удобнее. Вы можете поступать по другому и вставлять их прямо в код, как в примере выше
В данном случае тексты сообщений и некоторые константы вынесены в макросы #define. Это не обязательно, но лично мне так гораздо удобнее. Вы можете поступать по другому и вставлять их прямо в код, как в примере выше

Далее, напишем как раз эти самые функции обратного вызова:

Callback для отправки уведомлений. Выглядит непонятно, а на самом деле это все просто константы из #define выше
Callback для отправки уведомлений. Выглядит непонятно, а на самом деле это все просто константы из #define выше
Callback для публикации строки на MQTT-брокере
Callback для публикации строки на MQTT-брокере

Инициализация мониторинга выглядит следующим образом:

-12

Здесь:

  • восстанавливается последнее состояние объекта из NVS-раздела
  • подключаются callback-и
  • регистрируются параметры (границы диапазонов и гистерезис) на MQTT-клиенте. Придуманная мной система управления параметрами выполнит всю необходимую работу, в том числе подписку на MQTT-брокере и хранение данных в NVS-разделе. Об этом я постараюсь рассказать как-нибудь позже, напомните мне, если я забуду.

Ну и осталось немного изменить код проверки внутри основного цикла прикладной задачи:

-13

Можно пробовать... Уведомления приходить уже будут (если вы правильно настроили токены telegram бота(ов) в project_config.h.

Но вот на MQTT брокере пока ничего не появится. Это потому, что мы не сгенерировали топик(и) для публикации. Для этого придется создать обработчики системных событий подключения и отключения MQTT-клиента к брокеру:

Обработчик события RE_MQTT_EVENT
Обработчик события RE_MQTT_EVENT
Топики могут быть разными в зависимости от того, основной или резервный сервер используется
Топики могут быть разными в зависимости от того, основной или резервный сервер используется
Регистрируем обработчики
Регистрируем обработчики

Про циклы событий и как с ними работать, я уже писал ранее:

Теперь при изменении состояния класс сам опубликует всю доступную ему информацию на брокере (ну и уведомление отправит, само собой). До выхода из границ никакой информации на брокере не появится. Если вы хотите принудительно публиковать данные с заданным интервалом, то можно добавить такую строчку в основной цикл задачи:

-17

Ах да... Если вы желаете сохранять состояние и после перезапуска устройства, то нужно вызывать функцию nvsStore(...); перед перезапуском устройства.

-18

Можно делать это при изменении состояния или регулярно. Но не стоит делать это слишком часто, чтобы слишком быстро не заполнять NVS раздел и не изнашивать flash-память. Важно соблюдать баланс. Но сохранение состояния не является обязательной функцией, можно этим и пренебречь.

А что на MQTT-брокере?

На MQTT брокере должны быть вот такие топики (если вы все сделали правильно):

-19

Данные из них уже можно извлечь и отобразить в каком-нибудь MQTT Dashboard.

Настройки границ, как им и полагается, расположены в разделе config / confirm:

-20

Как я уже писал в предыдущих статьях цикла, здесь общее правило таково:

  • с телефона мы отправляем новые значения в топик device/config/bla-bla-bla, а в ответ мы должны получить то же самое значение в device/confirm/bla-bla-bla. Это позволяет гарантировать, то наши настройки успешно получены устройством и обработаны.

______________________________

На этом пока все, в следующей статье цикла я расскажу, как заменить сенсоры в прошивке на что-нибудь другое. Например DHT22 заменить на более современный AHT20, а BME280 на более точный SHT31. Ну а потом подключим к проекту библиотеку управления реле и сделаем полноценный термостат.

Если у вас есть какие-либо вопросы по другим компонентам прошивки или библиотекам - задавайте, подумаем и над другими статьями. До следующих встреч на сайте и на dzen-канале!

_______________

На этом пока всё, до встречи на сайте и на dzen-канале!

👍 Понравилась статья? Поддержите канал лайком или комментарием! Каналы на Дзене "живут" только за счет ваших лайков.

📌Подпишитесь на канал и вы всегда будете в курсе новых статей.

🔶 Полный архив статей вы найдете здесь