О чем эта статья
Продолжаем цикл статей о ShIoTiny — визуально программируемом контроллере на базе чипа ESP8266.
В этот статье рассказано о часах реального времени в контроллере ShIoTiny, синхронизации времени и использовании узлов работы с часами.
Сайт проекта ShIoTiny
Предыдущие статьи серии.
ShIoTiny: малая автоматизация, интернет вещей или «за полгода до отпуска»
ShIoTiny: узлы, связи и события или особенности рисования программ
ShIoTiny: вентиляция влажного помещения (проект-пример)
ShIoTiny и окружающий мир: подключение датчиков к бинарным входам, дребезг контактов и другие вопросы
ShIoTiny и окружающий мир: аналоговые датчики или АЦП для самых маленьких
Бинарные прошивки, схема контроллера и документация
Вступление
Сегодня мы поговорим о времени. Не о времени, в том смысле, в котором о нем веками спорят философы и конца-края этому спору не видно. А о том времени, которое мы видим на часах и согласно которому идем на работу, в школу или спешим на свидание.
Вся штука в том, что энергонезависимые часы реального времени в чипе ESP8266 и контроллере ShIoTiny — отсутствуют. Эта родовая травма контроллера ShIoTiny — целиком и полностью моя вина. Но, что сделано — то сделано.
Как только прошивка увидела свет, возмущенная моим отношением к реальному времени общественность начала тыкать меня носом в этот недостаток.
Так как ошибки надо исправлять, и, на этот раз хотя бы не кровью, то я пошел навстречу все возрастающему числу пользователей моей прошивки и сделал то что смог. А именно — я добавил в прошивку контроллера ShIoTiny узлы, позволяющие более-менее удобно с этим работать с реальным временем.
О часах ShIoTiny
Как уже было сказано, «часов с батарейкой» в ShIoTiny нет. Но в то же время, отсчет секунд, начиная с 1 января 1970 года реализован.
Это то самое время, которое называется UNIX-time, хранится в переменных типа time_t языков С/C++ и которое в 32-битных системах должно закончится 19 января 2038 года.
Но, не бойтесь. Я думаю, что к 2038 году все успеют сделать тип time_t 64-битным и на ближайшие примерно 292 миллиарда лет проблема будет решена. Ну а там еще что-нибудь придумаем.
Заметим, что время в формате time_t называется иногда (и у меня в статье тоже) — timestamp или, по-русски временная метка.
Но вернемся к нашему контроллеру. Итак, часы в нем есть, но эти часы сбрасываются в 0 после отключения питания. Отсюда следует тривиальный вывод, что главной проблемой отсчета времени в контроллере ShIoTiny является необходимость синхронизации часов контролера при включении питания. Остальное — чисто технические проблемы
Синхронизация времени
Давным давно устоявшийся способ синхронизации времени в интернете — это NTP-сервера. И первой идеей было сделать узел, который синхронизирует время с заданным NTP-сервером.
Но, немного подышав свежим воздухом и покумекав своей тыковкой я понял, что этот подход идеологически неверный.
Ведь не факт, что пользователь захочет вытащить контролер с прошивкой ShIoTiny в интернет. И время для синхронизации может присылаться не только с NTP-сервера но и по UDP-multicast или при известном качестве связи — по MQTT.
Поэтому было принято судьбоносное решение — разделить узлы получения времени с NTP-сервера и установки системного времени.
Всего для синхронизации времени было разработано два узла: узел получения времени с NTP-сервера NTP Time
и узел установки системных часов Set Time
Узел получения времени с NTP-сервера в качестве параметров получает имя или IP-адрес NTP-сервера и, через запятую, период запроса времени с NTP-сервера в минутах. По умолчанию время запрашивается с NTP-сервера каждые 60 минут или 1 час. На выходе этот узел выставляет 0 до тех пор, пока время не синхронизировано или временную метку — результат последней синхронизации с сервером.
Узел установки системных часов получает на вход временную метку и и устанавливает системные часы в соответствии с этой меткой.
Простейшая схема синхронизации системных часов с NTP-сервером приведена на рисунке.
Период синхронизации не задан и по умолчанию равен 60 минут. На рисунке показана временная метка.
Отмечу, что более одного узла получения времени с NTP-сервера и более одного узла установки системного времени на схеме-программе быть не может.
Если вам нужна экзотическая схема синхронизации — то можно использовать UDP-multicast или MQTT. Схемы при этом полностью аналогичны.
Для синхронизации по UDP-multicast, примерно такая, как на рисунке.
А для синхронизации по MQTT (не советую, конечно, но на крайний случай) — такая.
Надеюсь, теперь все понятно с синхронизацией времени системных часов контролера ShIoTIny. Перейдем к узлам получения и обработки времени.
Который час?
Вопрос простой, но ответить на него, порой, не просто. Ведь время в каждой точке Земли — разное. Наша необъятная Родина включает от Калининграда до Камчатки аж 11 часовых поясов.
NTP-сервер, в зависимости от настроек, может возвращать временную метку, привязанную к различным часовым поясам. Как правило, эта временная метка привязана к UTC — всемирному времени.
Но обычно нам нужно местное время того региона где работает наш контроллер. Как тут быть?
А очень просто — для получения временной метки системных часов контролера ShIoTIny был разработан узел Get Time, в котором можно задать часовой пояс в виде смещения времени от -12 часов до +12 часов относительно системных часов контроллера.
Предположим, мы получаем время с сервера pool.ntp.org и синхронизируем системные часы, как в нашем примере ранее. Этот сервер возвращает всемирное время. Нам нужно местное, например Томское, как у меня. Я знаю, что Томск находится в часовом поясе UTC+7. Значит, зададим в узле получение времени смещение +7 или просто 7. Как на рисунке ниже.
А если бы мы жили в Канадской провинции Альберта — то смещение было бы -7 часов. Главное запомните — часовой пояс задается в узле получения времени в часах. И задается он в виде смещения относительно времени системных часов. На выходе узла получения времени выставляется временная метка. Узлов получения времени на схеме может быть несколько.
Сверим часы
Машине очень удобно работать с временем в формате временных меток time_t. Ведь это просто целое число, которое показывает число секунд относительно начальной точки — 1 января 1970 года. В этом формате можно легко находить расстояние между двумя временными точками, отсчитывать периоды и так далее. Это всего лишь сложение и вычитание целых чисел.
Но человек — не машина. Ему гораздо удобнее привычное представление времени в виде года, месяца, числа, часов, минут и секунд. Так уж мы, люди, устроены.
Поэтому были введены узлы перевода временной метки в привычные человеку единицы изменения времени и наоборот — синтеза временной метки из понятных человеку единиц изменения времени. Называются эти узлы, соответственно, Split Time и Synth Time.
Как все это работает — понятно из рисунка ниже.
Отмечу, что узлы Split Time и Synth Time месяцы (month) и дни недели (wday) отсчитывают с нуля. Для месяцев: 0-январь, 11-декабрь. Для дней недели 0-воскресенье, 6-суббота.
Остальные выходы: день месяца (day), year (год), hour (час), min (минута), sec (секунда) — отсчитываются в привычном виде. Часы, минуты, секунды — от 0 до 59. День месяца — в зависимости от месяца от первого числа до 30го или 31го и, для февраля, до 28 или 29го.
Ну а год — он и есть год. 2019й сейчас.
Надеюсь, все понятно.
Пример системы
Чтобы не быть голословным, приведу пример использования часов. Разумеется, упрощенный.
Предположим, у нас есть влажное помещение, которое мы хотим принудительно вентилировать. Но не всегда, а только когда влажность больше заданного уровня и только ночью. Ночью — чтобы не мешать людям днем шумом вентиляторов. Ну такие вот мы эстеты и заботимся о людях.
Попробуем это реализовать.
Все кусочки схемы нам знакомы. Время синхронизируется с сервера NTP. Пока оно не синхронизировано — узел NTP Time возвращает 0 и реле включения вентилятора — отключено. За это отвечает верхний по схеме элемент И.
Как только время синхронизировалось, включение-отключение вентилятора определяется текущим временем и уровнем влажности. Как только уровень влажности превысит 70% и время будет от 23:00 до 06:00 — вентилятор включится и не мешая никому проветрит помещение.
Разумеется, константы времени и влажности в реальном проекте лучше заменить на параметры, сохраняемые во FLASH и устанавливаемые, например по MQTT. Да и текущее состояние системы — уровень влажности, текущее, время, состояние вентилятора — тоже не повредит опубликовать в сети, чтобы контролировать систему со смартфона. Но это уже я оставляю простор для вашей фантазии.
Заключение
Вот мы и познакомили поближе наш контроллер с реальным временем.
Хочу выразить благодарность всем, кто присылал мне письма с конструктивной критикой и советами по модернизации программного обеспечения. Спасибо, ребята!
Как обычно — конструктивная критика приветствуется. Кроме этого приветствуются замечания и предложения.
Отправлять всю критику, замечания, предложения можно как обычно в комментарии или на почту: shiotiny@yandex.ru.