Статья

Отправка данных из Home Assistant на сервис narodmon.ru

Вступление

Прочитав статью Обмен данными между NarodMon.ru и Умным домом, я вспомнил, что когда-то тоже активно участвовал в проекте и отправлял данные на этот сервис, почти с самого его основания. Сначала с помощью устройства, заказанного у одного из участников проекта, потом с помощью ESP8266 и прошивки WiFi-IoT, а потом я это дело забросил. В основном из-за неудобств в его обслуживании, необходимости подачи питания, нагрева датчиков от ESP8266 (и безуспешных попыток их термоизоляции), периодических проблем с отвалом wifi и так далее.

Все эти проблемы отпали после того, как я вынес на улицу один из zigbee датчиков xiaomi, датчик проработал в течение года, исправно показывая температуру и влажность за бортом. Единственный минус - из home assistant этими данными нельзя было делиться с сообществом народного мониторинга. 

После статьи Дмитрия, я решил найти способ восполнить этот пробел, тем более что готовых решений в интернете нет. Надеюсь, мой труд не пропадет даром и многие, у кого в home assistant есть данные, которыми они готовы поделиться, воспользуются этим.

Поиск решения

Сервис narodmon поддерживает прием показаний несколькими способами: TCP/UDP, HTTP GET/POST, а также MQTT. 

TCP/UDP является предпочтительным вариантом, по мнению авторов сервиса, но для пользователя home assistant это означает необходимость написания кастомных скриптов.

HTTP рекомендуется использовать только в случае, если доступ в Интернет осуществляется через прокси-сервер, т.к. возможны проблемы с кеширующими прокси и выше риск перехвата / подмены данных, а также увеличивается время обработки данных в "часы пик" из-за большого числа посетителей сайта и мобильных клиентов. В home assistant можно реализовать с помощью RESTful command интеграции, но все же хочется придерживаться рекомендаций сервиса и не использовать HTTP.

MQTT - надеялся, что получится легко и просто, но оказалось что home assistant может работать только с одним MQTT брокером и для реализации задачи необходимо костылить связку из двух MQTT брокеров, не захотел с этим связываться.

Реализация

В результате, единственным вариантом для меня остался вариант TCP/UDP. В описании API narodmon есть несколько примеров скриптов для передачи показаний по TCP/UDP и один из них - на python. Соответственно, первым делом хотел использовать встроенную в home assistant интеграцию python scripts, но к сожалению, оказалось что возможности там урезанные - нет поддержки импорта библиотек, а без этого никак. Гугление привело меня к AppDaemon, на тот момент - абсолютно непонятная для меня вещь (всегда удивлялся, когда в чате обсуждалось его удобство и возможность сделать все, что угодно). Взяв пример от narodmon, документацию appdaemon и статьи Что это такое AppDaemon? и AppDaemon. Часть 2 за несколько самоизоляционных вечеров сделал то, что хотел.

Настройка

Для тех кто захочет воспользоваться моим скриптом, первым делом необходимо установить AppDaemon. Самый простой способ для пользователей hassio - установка аддона AppDaemon 4 из состава Home Assistant Community Add-ons, для пользователей чистого home assistant могу лишь предложить ссылку на статью Установка AppDaemon.

В AppDaemon описание всех пользовательских скриптов и их параметров выполняется в файле apps.yaml, либо, для удобства можно создать отдельный файл с расширением yaml и поместить его вместе с файлом скрипта в папку внутри конфигурационного каталога, AppDaemon сам все найдет и запустит. Кстати, AppDaemon отслеживает изменения файлов и как только вы измените любой существующий или появится новый файл скрипта *.py и его конфигурация правильно описана в *.yaml, скрипт автоматически запустится / перезапустится. Это очень удобно в процессе отладки.

Итак, создаем файл с конфигурацией / вставляем ее в дефолтный apps.yaml:

#apps\ad_narodmon_sender\config.yaml narodmon_sender: module: narodmon_sender class: narodmon_sender narodmon_device_mac: AABBCCDDEEFF narodmon_device_name: Aqara_WSDCGQ11LM hass_coordinates_entity: zone.home hass_sensor_entities: sensor.outside_temperature,sensor.outside_humidity,sensor.outside_pressure

Опишу параметры. Первые два обязательны и нужны для того, чтобы скрипт в принципе запустился:

module: - имя файла скрипта (путь к файлу и расширение.py здесь не указывается).

class: - название класса, должно совпадать с названием класса в скрипте.

Дальше мои "пользовательские" параметры, которые передаются в переменные внутри скрипта:

narodmon_device_mac: MAC-адрес, идентифицирующий ваше устройство на narodmon.ru, 12-18 символов A-Z и 0-9 без разделителей или разделенных '-' или ':' (обязательный параметр).

narodmon_device_name: Имя вашего устройства, оно будет видно тем, кто захочет посмотреть ваше устройство на сайте (не обязательный параметр).

hass_coordinates_entity: зона home assistant для получения координат, нужно для автоматического размещения устройства на карте (не обязательный параметр).

hass_sensor_entities: список сенсоров из home assistant, данные которых будем передавать, разделенный запятыми, без пробелов (обязательный параметр).

Теперь сам скрипт. В нем никаких изменений делать не надо. Но если найдутся специалисты в python, буду рад услышать комментарии, для меня это первый опыт с питоном.

Если кратко, алгоритм следующий:

  1. Получаем исходные данные из параметров, указанных в конфигурации.
  2. Из списка entity отфильтровываем только домен сенсоров и проверяем, существуют ли таковой в home assistant.
  3. Получаем имена и тип сенсоров из атрибутов home assistant (friendly name и device_class).
  4. На основе типов сенсоров формируем идентификаторы сенсоров (чтобы narodmon автоматически определял тип).
  5. Если сенсоров одного типа несколько, нумеруем их по порядку.
  6. Если атрибут device_class отсутствует, идентификатор будет просто SENSOR1, SENSOR2 и т.д. В таком случае, на narodmon в настройках датчика вручную необходимо будет задать его тип. Либо просто добавьте device_class в разделе кастомизации home assistant.
  7. Каждые 5 минут формируем данные для отправки (отфильтровывая недоступные в данный момент сенсоры) и отправляем их на сервер narodmon.ru, записывая в лог все, что отправляем.

Весь скрипт усыпан моими комментариями, думаю будет полезно новичкам.

import appdaemon.plugins.hass.hassapi as hass import socket import datetime import collections class narodmon_sender(hass.Hass): #метод запускаемый однократно при старте программы def initialize(self): # объявляем переменные: # список сенсоров для отправки self.sensors = [] # словарь имен для сенсоров (берем из friendly_name) self.sensors_name = {} # словарь типов сенсоров (берем из device_class, если есть) self.sensors_type = {} # форматированные данные для отправки self.device_data = None # словарь замены типов для автоопределения типа сенсора на narodmon.ru, # исходные данные берутся из параметра device_class сенсора, при отсутстви датчики будут именованы как SENSOR#, тип нужно вручную определить на сайте. replace = { 'temperature': 'TEMP', 'humidity': 'RH', 'pressure': 'PRESS', 'battery': 'BATCHARGE', 'power': 'W', 'illuminance': 'LIGHT', 'signal_strength': 'RSSI', None: 'SENSOR' } # проверяем, есть ли переменная с MAC-адресом в параметрах скрипта if 'narodmon_device_mac' in self.args: if self.args['narodmon_device_mac'] != None: # начинаем формировать данные для отправки self.device_data = '#' self.args['narodmon_device_mac'] # проверяем наличие названия устройства в параметрах скрипта, добавляем к MAC-адресу, если есть if 'narodmon_device_name' in self.args: if self.args['narodmon_device_name'] != None: self.device_data = '#' self.args['narodmon_device_name'] # проверяем наличие зоны в параметрах скрипта для определения координат if 'hass_coordinates_entity' in self.args: if self.entity_exists(self.args['hass_coordinates_entity']): lat = self.get_state(self.args['hass_coordinates_entity'], 'latitude') lng = self.get_state(self.args['hass_coordinates_entity'], 'longitude') if lat != None and lng != None: self.device_data = '\n#LAT#' str(lat) '\n#LNG#' str(lng) else: exit('Please, define narodmon_device_mac value in /config/appdaemon/apps/narodmon_sender/config.yaml') else: exit('Please, specify narodmon_device_mac variable in /config/appdaemon/apps/narodmon_sender/config.yaml') # проверка наличия перечня сенсоров в парамерах скрипта if 'hass_sensor_entities' in self.args: for entity in self.split_device_list(self.args['hass_sensor_entities']): # проверка существования объекта в home assistant if self.entity_exists(entity): domain, sensor_id = self.split_entity(entity) # отфильтровываем все кроме сенсоров if domain == 'sensor': # заполняем список сенсоров для отправки self.sensors.append(sensor_id) # заполняем словари имен и типов self.sensors_name[sensor_id] = self.get_state(entity, 'friendly_name') self.sensors_type[sensor_id] = self.get_state(entity, 'device_class') # на основе словаря типов переименовываем и нумеруем по порядку повторяющиеся for sensor_id in self.sensors_type: if self.sensors_type[sensor_id] in replace: self.sensors_type[sensor_id] = replace[self.sensors_type[sensor_id]] count = collections.Counter(self.sensors_type.values()) for type in count: if count[type] > 1: num = count[type] sel = 1 for sensor_id in self.sensors_type: if self.sensors_type[sensor_id] == type: self.sensors_type[sensor_id] = type str(range(num 1)[sel]) sel = sel 1 else: exit('Please, specify hass_sensor_entities variable in /config/appdaemon/apps/narodmon_sender/config.yaml') # вызвываем метод отправки данных каждые 5 минут, начиная с текушего времени self.run_every(self.send_data, datetime.datetime.now() datetime.timedelta(seconds=2), 300) # метод для отправки данных def send_data(self, kwargs): sensors_data = '\n' # проверяем, есть ли сформированные данные об устройстве if self.device_data != None: for sensor_id in self.sensors: # отбрасываем недоступные датчики if self.get_state('sensor.' sensor_id) != 'unavailable': # формируем строку с данными всех рабочих сенсоров sensors_data = '#' self.sensors_type[sensor_id] '#' self.get_state('sensor.' sensor_id) '#' self.sensors_name[sensor_id] '\n' # собираем пакет данных для отправки: информация об устройстве данные сенсоров символ окончания пакета данных data = self.device_data sensors_data '##' # вывод в лог информации которая будет отправлена self.log('Data for send to narodmon.ru:\n' str(data)) # создаем сокет для подключения к narodmon.ru sock = socket.socket() try: # пробуем подключиться sock.connect(('narodmon.ru', 8213)) # пишем в сокет значения датчиков sock.send(data.encode('utf-8')) # читаем ответ сервера reply = str(sock.recv(1024)) sock.close() self.log('Server reply: ' reply.strip("bn\'\\")) except socket.error as err: self.error('Got error when connecting to narodmon.ru: ' str(err)) else: exit('No device data for send to narodmon.ru')

Файлы также можно скачать с github, там я готовлю его для включения в репозиторий HACS.

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

Жду ваших комментариев, замечаний, предложений!


Отличное продолжение моей статьи. Приятно было что упомянул. Лайк!

Если оформить в 

HACS

, будет законченное, правильное решение.

Без appdaemon было бы круто. Я чёт всё смотрю на него и очкую подходить к нему)) По сути и нет потребности. Поэтому ставить аддон только из-за одного скрипта не хочется.

Модуль для ха было бы круто получить.


Расскажите, как у вас расположен датчик сяоми чтоб он передавал достоверную инфу? Вы в какой полосе живёте, насколько суровые у вас зимы?

Датчик по возможности нужно размещать в тени, в проветриваемом месте. У меня он находится под козырьком балкона. В идеале разместить его в специальный небольшой корпус, по типу метеорологической будки (другое название Stevenson screen) , я планирую распечатать такую модель: https://www.thingiverse.com/thing:4120452">https://www.thingiverse.com/th... 

Живу в Приморском крае, зимы у нас до -20 в среднем. Но эти датчики (xiaomi/aqara) и в более суровые минуса работают, помню в чате люди отписывались о работе в -40



Распечатал и собрал корпус для датчика, как и ожидалось разница в солнечный день довольно существенна, по температуре пиковая разность около 4 градусов, по влажности около 10%.


Температура:


https://sprut.ai/static/media/cache/00/19/15/5/3914944/59151/1000x_image.png?1590545435" alt="1000x_image.png?1590545435" />

Влажность:


https://sprut.ai/static/media/cache/00/19/15/5/3914944/59150/1000x_image.png?1590545407" alt="1000x_image.png?1590545407" />

Синий - график открытого датчика, красный - датчик внутри защитного корпуса:


https://sprut.ai/static/media/cache/00/19/15/5/3915120/59152/1000x_image.jpg?1590547169" alt="1000x_image.jpg?1590547169" />

Спасибо! Всё работает. Прокинул свою метеостанцию: WeMos D1 mini pro+BME280+BH1750 --> HA --> narodmon.ru. Месяц мучался, пытался через MQTT сделать. По вашему методу все быстро, просто и никаких бубнов...

У меня скрипт, к сожалению, не работает.

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

Как еще можно отдебажить запуск скрипта?

HASS.io 0.104.3

Спасибо! Тоже все заработало.   ESP-01m + BME280 + BH1750 --> HA --> narodmon.ru

Момент был только с отправкой данных. 

Почти сутки бился, не понимал почему народмон не получает данные, ошибок никаких не было в логах.

В моем случае скрипт подхватил датчики только после перезагрузки ESP-01m, причем по питанию.

Где посмотреть MAC адрес устройства zigbee?



Можно абсолютно любой MAC адрес указать, какой вам нравится, не обязательно реальный. Это нужно только для идентификации вашего устройства на сайте, его уникальность не обязательна

Кто настроил отправку с датчика zigbee?

С 28.10 стало выдавать ошибку. Не нравится синтаксис... Помогите разобраться.


Немного разобрался, после обновления HA, из скриптов пропали "+". Исправил, но все равно не работает, и ошибок в логе нет...


Попробуйте заново скачать скрипт. У меня при обновлениях никаких изменений в скриптах не происходит. У меня сейчас последняя версия HA и AppDaemon, все работает как и прежде, без всяких доработок.

Алексей, приветствую! Спасибо за ответ. Немножечко разобрался, в вашем скрипте ошибок нет, он работает. Проблема возникла в другом. Я, на основе вашего скрипта сделал другой, для выгрузки данных в сеть APRS - "Отправка данных из Home Assistant на сервис APRS"

. В папке apps создал папку aprs_sender, закинул туда файлики скрипта (https://sprut.ai/client/paste/Pxu6mDVy">https://sprut.ai/client/paste/... ,https://sprut.ai/client/paste/fZe3nKNw">https://sprut.ai/client/paste/... ). В общем, параллельно работало 2 скрипта, ваш (narodmon_sender) и мой (aprs_sender). До 28.10 все было нормально, после очередного обновления супервизора ваш скрипт перестал работать. Я заново скачал ваш скрипт из гита, опять ерунда, не работает. Но, как только отключаю свой скрипт, ваш работает отлично. Сделал вывод, что по какой-то причине, после обновления, 2 скрипта вместе работать не могут. При этом в логах ошибок нет. Получается, что скрипты как бы работают, но открывать соккет и отправлять данные может только один (тот который пошустрее?). Можете помочь и развести "всех кроликов по углам"? Возможно заставить отправлять данные 2 скрипта? 

Вроде разобрался, надо сокет правильно закрывать:


sock.shutdown(socket.SHUT_RDWR)


sock.close()

Ерунда, не работает.... Что этому питону ещё надо? О_о

Подскажите, в чем может быть проблема - 

после конфигурирования приложения и запуска апдемона, данные на народмон начинают уходить в лучшем случае через несколько часов. никакой информации ни логах нет, ни во входящих логах на народмон. 

я подумал может быть после запуска происходит отправка данных и могла  произойти отправка с меньшим интервалом при моем конфигурировании и попадание в бан, я подождал 15 минут запустил, все равно отправка не происходит в логах пусто, на народмон тоже. оставляю все, через несколько часов 3-5  приходит сообщение от народмон, что пошли данные от меня.

все конфигурации несколько раз перелопатил, логи в апдемоне на уровне debug, тоже ничего внятного не показывают.

Укажите правильную временную зону в файле конфигурации appdaemon.yaml

То что нужно. Спасибо. Теперь как часы.


Даже мысли почему то небыло в ту сторону, думал аддон берет время HA

Подскажите, как правильно это сделать? Чего-то не получается
                    # отфильтровываем все кроме сенсоров
if domain == 'sensor':

Сложно ли добавить обработку не только сенсоров но и бинарных сенсоров? 

Я в питоне не очень, боюсь  для меня непосильная задача на данный момент.

Не сложно, добавлю

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


Код доступен на github

Большое спасибо. Всё работает. Тоже боялся сперва AppDaemon, но на офиц. его сайте установка понятно расписана.

Спасибо, все работает!

Извините за может быть глупый вопрос, а где указываются данные учётной записи для народмон? Он же должен под какой то учётной записью публиковать датчики?
Скопировал скрипт с гитхаба, подставил свои данные. Выдает ошибку -
File "/config/apps/narodmon_sender.py", line 83, in initialize
self.sensors_name[entity] = self.get_state(entity, 'friendly_name')
~~~~~~~~~~~~~~~~~^^^^^^^^
TypeError: 'set' object does not support item assignment

В чем может быть дело?
Вопрос снимается, исходный текст был отформатирован с ошибками. Все работает нормально.

Вернуться назад

Устройства


Espressif Systems

ESP8266

(1 отзыв)

Вернуться назад