zbx-sadman / zabbuino

Zabbix agent for Arduino
92 stars 15 forks source link

Zabbuino <-> MQTT <-> other software #6

Closed Promnovatsia closed 4 years ago

Promnovatsia commented 7 years ago

Есть ли возможность прикрутить PubSubClient в Zabbuino? Чтобы была возможность отправлять сообщения с контроллеров и управлять ими из внешней программы, например, NodeRED. И оставить на Zabbix задачу запуска и отслеживания MQTT событий.

Или придется решать через другой вариант - прикрутить MQTT только к Zabbix, а контроллерами управлять через Zabbuino?

zbx-sadman commented 7 years ago

Насколько я понял, MQTT-клиент шлет данные на сервер сам (к сожалению с данной технологией и терминологией не знаком).

Если это так, то все подключенные датчики должны иметь заранее определенную привязку к определенным пинам, инициализированы и переключены в необходимый режим. А это полная противоположность концепции Zabbuino, В ней параметры датчика определяются в запросе, что дает гибкость в работе и возможность переключения режимы замеров на ходу (менять разрешение оцифровки, точность замера и пр), из интерфейса Zabbix. Однако, при этом Zabbuino не может ничего послать сама, так как до запроса фактически не знает, какие датчики висят у нее, к примеру, на I2C.

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

Promnovatsia commented 7 years ago

PIR sensor обнаружил движение. Нужно проверить на сервере текущий план освещения (день-ночь-охрана) и при необходимости послать комманду на контроллер света. Т.е. это не обязательно одно устройство как посылает так и получает. При этом надо записать момент срабатывания в Zabbix.

В этой ситуации не хватает только одного - как узнать когда сработал датчик?

В терминах MQTT возможное решение выглядит так:

PubSubClient client(servername, 1883, callback, ethClient);

void callback(char* topic, byte* payload, unsigned int length) {
    payload[length] = '\0';
    String strTopic = String(topic);
    String strPayload = String((char*)payload);
    if (strTopic=="ard/in/light"){
        if(strPayload=="on")
           digitalWrite(LIGHT,HIGH);
        else 
           digitalWrite(LIGHT,LOW);
    }
}

setup() {
    Ethernet.begin(mac, ip);
    client.subscribe("ard/in/#");//любая тема с префиксом ard/in
}

loop(){
    if (!client.connected()) {
        client.loop();         
    }
    client.publish("ard/out/pir",digitalRead(PIR));//тут необходимо реализовать задержку, чтобы не слать каждый цикл, но для простоты оставим так
}

MQTT дает возможность слать сообщения с темами. Желающий принять сообщение подписывается на тему. Коммуникацию поддерживает брокер MQTT. В контроллере при приеме любого сообщения библиотека PubSubClient вызывает callback функцию.

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

Нас интересует только отправка сообщения о статусе нужного пина. Но как сделать это через Zabbuino?

client.publish("ard/out/pir",digitalRead(PIR));

Если я правильно понимаю текущую концепцию, то Zabbix должен сам опрашивать контроллер для получения показаний через заданный интервал. И после передать данные управляющему ПО, которое примет решение и опять через Zabbix пошлет управляющее действие.

zbx-sadman commented 7 years ago

Понимаете вы правильно. Zabbuino работает подобно агенту Zabbix в пассивном режиме. И управляющее ПО для него - сам Zabbix, который на основании значения метрики, полученного в результате запроса, принимает какое-то решение и реализует его через Trigger+Action. Иного алгоритма работы в концепцию не закладывалось.

Что касается примера с PIR-ом. Да, его срабатывание отследить можно, но опять же - через запрос (конкретнее - через обнаружение изменения количества срабатываний по прерыванию на соотв. пине), сам по себе Zabbuino никого оповещать не будет. Момент срабатывания определяется с точностью до интервала опроса в связанном элементе данных.

MQTT функционал похож на активный режим работы Zabbix агента, но, к сожалению, на целевом MCU (ATmega328) ресурсов на его реализацию, при данном уровне разработки, не хватает.

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

Но замысел ваш понятен, возможно что-то будет реализовано. Во всяком случае - сейчас обкатывается возможности вызова пользовательских функций в состоянии idle (коллбэков, если угодно), в которых можно будет более чаще получать данные с датчиков, т.е. приблизится к практически мгновенному обнаружению изменения состояния. Однако это всё сдерживается недостатком хардварных ресурсов. Переход на более "емкие" MCU тоже возможен, но пока необходимости в этом не возникало, в частности еще и потому, что основной целью было построение микроагентов (в формате "спичечного коробка") на базе уже готовых компонентов (Arduino Mini Pro, Arduino Nano), что и было достигнуто. Т.е. поставленные задачи были в целом решены.

Promnovatsia commented 7 years ago

Zabbuino отлично работает как исполнитель задачи, передданной из Zabbix. Это как опрос датчика, так и изменение состояния входов\выходов контроллера. Инициатор всегда Zabbix, исполнитель всегда контроллер.

В то время как моя задача включает в себя скорее создание сети из нескольких контроллеров с выгрузкой основной логики на сторону сервера. Датчики из опрашиваемых превращаются в транслирующие. Контроллер полностью контролирует свои входы\выходы и предоставляет интерфейс взаимодействия через подписание на темы MQTT. Сервер же занимается логикой типа "если-тогда" для разгрузки памяти контроллеров и создания возможности ее изменения без перепрошивки.

Это переворачивает концепцию. Полная внешняя управляемость Zabbuino превращается в интерфейс MQTT, скрывающий прописанную физическую реализацию.

zbx-sadman commented 7 years ago

Да, я это понял.

Основная проблема в том, что при передачи роли инициатора MCU, нужно чтобы он знал, какие и как к нему подключены сенсоры и актуаторы, в каком режиме им полагается работать. Т.е. настройки должны быть определены на этапе прошивки или корректироваться удаленно. Первый способ крайне неудобен, второй требует оверхеда для реализации интерфейса конфигурирования. На первоначальном этапе Zabbuino "запихивалась" в ATMega168 и, естественно, ни о каких доп.интерфейсах не было даже мысли. Поэтому был выбран промежуточный вариант - "конфигурирование при запросе". Он работал неплохо, поэтому остался в качестве базового механизма.

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

Что касается вашего проекта, то я так понимаю, что основная задача у вас решена - MQTT сеть работает, но не хватает взаимодействия с Zabbix. Т.е. вы хотели бы события, возникающие на клиентах, отражать в системе мониторинга. Я мог бы посоветовать присмотреться вам к протоколу Zabbix Sender, который позволяет отразить timestamp события, хост, от имени которого исходят данные, и отсылать значения не с клиентов, а с брокера. Думаю, что это будет наиболее легкое решение в данном случае. Однако, прямо сейчас, я не представляю себе в деталях механизм автоматизированного создания элементов данных, которые будут ожидать поступления значений метрик...

foremannn commented 7 years ago

Добрый день! При использовании датчиков температуры 18B20 не корректно выводятся отрицательные температуры. При опросе датчика zabbix_get получаю цифры -103278.6424, -103278.9324, -103278.1824 и т.п. (реальна температура около нуля).

Можно это как-то исправить?

zbx-sadman commented 7 years ago

Странная история. Я специально сейчас в src\ow_sensors.cpp подсунул tRaw = 0xFC90; (-55 по даташиту) перед началом вычислений. Result: -55.0. С 0xFF5E тоже всё нормально. Т.е. математически верно вычисляется.

Исправить можно, если найти на каком этапе корежится tRaw. Попробуйте перед if (tRaw & 0x8000) сделать Serial,println(tRaw) (и после каждой операции с этой переменной - тоже можно), активировать отладку (_FEATURE_DEBUG_TO_SERIALLOW) и в IDE Serial Monitor посмотреть, что вываливается при опросе.

Ну и я, как свободный хвост с DS18B20 найду, суну его в холодильник. Насколько быстро - не могу сказать.

foremannn commented 7 years ago

Спасибо, попробую.

foremannn commented 7 years ago

Сделал Serial,println(tRaw) перед if (tRaw & 0x8000) в ow_sensors.cpp, на этапе компиляции получаю println was not declared in this scope

zbx-sadman commented 7 years ago

Да, это моя ошибка - допустил описку в совете. Вместо запятой, естественно, должна стоять точка: Serial.println(tRaw) - Arduino IDE вам не намекнула на это?

И давайте сделаем так: по своему вопросу вы откроете отдельный issue, потому что этот относится к другому вопросу и засорять его оффтопиком не стоит.

foremannn commented 7 years ago

Извините, создал новый issue https://github.com/zbx-sadman/Zabbuino/issues/7