Перейти к содержанию

Навигация

MQTT: различия между версиями

359 байт добавлено ,  3 года назад
м
Обновил оформление статьи — теперь выглядит лучше
м (Обновил оформление статьи — теперь выглядит лучше)
Строка 10: Строка 10:
К [[Wiren Board]] подключён датчик температуры по шине [[1-Wire]]. Проследим, как данные с него через MQTT попадают в веб-интерфейс:
К [[Wiren Board]] подключён датчик температуры по шине [[1-Wire]]. Проследим, как данные с него через MQTT попадают в веб-интерфейс:
#Драйвер, отвечающий за данную аппаратную функцию ([https://github.com/contactless/wb-homa-drivers/tree/master/wb-homa-w1 wb-homa-w1]) опрашивает подключённые к контролеру датчики 1-Wire.
#Драйвер, отвечающий за данную аппаратную функцию ([https://github.com/contactless/wb-homa-drivers/tree/master/wb-homa-w1 wb-homa-w1]) опрашивает подключённые к контролеру датчики 1-Wire.
#При получении значения драйвер публикует по MQTT сообщение вида: <pre>/devices/wb-w1/controls/28-0115a48fcfff 23.25</pre>Оно значит, что на устройстве 1-Wire с идентификатором ''28-0115a48fcfff'' получено значение 23.25 °C.
#При получении значения драйвер публикует по MQTT сообщение вида: <pre>/devices/wb-w1/controls/28-0115a48fcfff 23.25</pre>Оно значит, что от устройства 1-Wire с идентификатором ''28-0115a48fcfff'' получено значение 23.25 °C.
#Веб-интерфейс, который подписан на все сообщения из MQTT, получает это сообщение и выводит значение датчика на страницу.
#Веб-интерфейс, который подписан на все сообщения из MQTT, получает это сообщение и выводит значение датчика на страницу.
===Нажатие кнопки в веб-интерфейсе и переключение реле на внешнем модуле===
===Нажатие кнопки в веб-интерфейсе и переключение реле на внешнем модуле===
[[File:Web-devices-serial.png|400px|thumb|Веб-интерфейс после нажатия кнопки включения Реле 1 на подключённом по RS-485 релейном модуле [[WB-MRM2]]]]
[[File:Web-devices-serial.png|400px|thumb|Веб-интерфейс после нажатия кнопки включения Реле 1 на подключённом по RS-485 релейном модуле [[WB-MRM2]]]]
К контроллеру по шине [[RS-485]] подключён релейный модуль [[WB-MRM2]]. Пользователь в веб-интерфейсе нажимает кнопку включения реле. Проследим, как команда из веб-интерфейса попадает на внешний модуль:
К контроллеру по шине [[RS-485]] подключён релейный модуль [[WB-MRM2]]. Пользователь в веб-интерфейсе нажимает кнопку включения реле. Проследим, как команда из веб-интерфейса попадает на внешний модуль:
#После нажатия кнопки веб-интерфейс публикует по MQTT сообщение вида: <pre>/devices/wb-mrm2_130/controls/Relay 1/on 1</pre>Оно значит, что устройство WB-MRM2 с адресом ''130'' должно перевести ''Реле 1'' в состояние логической единицы - «включено».
#После нажатия кнопки веб-интерфейс публикует по MQTT сообщение вида: <pre>/devices/wb-mrm2_130/controls/Relay 1/on 1</pre>Оно значит, что устройство WB-MRM2 с адресом ''130'' должно перевести ''Реле 1'' в состояние логической единицы «включено».
#[[Драйвер wb-mqtt-serial]], отвечающий за данную аппаратную функцию, получает это сообщение (он ''подписан'' на все сообщения, относящиеся к подключённым по RS-485 устройствам) и посылает по шине RS-485 релейному модулю команду на включение первого реле.
#[[Драйвер wb-mqtt-serial]], отвечающий за данную аппаратную функцию, получает это сообщение (он ''подписан'' на все сообщения, относящиеся к подключённым по RS-485 устройствам) и посылает по шине RS-485 релейному модулю команду на включение первого реле.
#Релейный модуль WB-MRM2 получает команду от контроллера, переключает реле и посылает обратно уведомление «Реле 1 включено».
#Релейный модуль WB-MRM2 получает команду от контроллера, переключает реле и посылает обратно уведомление «Реле 1 включено».
Строка 42: Строка 42:


=== Структура сообщения о состоянии устройства ===  
=== Структура сообщения о состоянии устройства ===  
Вот пример сообщения от драйвера температурного датчика 1-Wire из примера выше:
Вот сообщение от драйвера температурного датчика 1-Wire из примера выше:
<pre>
<pre>
/devices/wb-w1/controls/28-0115a48fcfff 23.25
/devices/wb-w1/controls/28-0115a48fcfff 23.25
Строка 49: Строка 49:


Название топика состоит из вложенных друг в друга «подтопиков»:
Название топика состоит из вложенных друг в друга «подтопиков»:
* ''/devices'' — коренной топик для всех «устройств» — как встроенных функций Wiren Board (цифровые, АЦП, ...), так и подключённых внешних (например, модулей реле).
* <code>/devices</code> — коренной топик для всех «устройств» — как встроенных функций Wiren Board (цифровые, АЦП, ...), так и подключённых внешних (например, модулей реле).
* ''/wb-w1'' — подтопик, который наполняется драйвером 1-Wire.
* <code>/wb-w1</code> — подтопик, который наполняется драйвером 1-Wire.
* ''/controls'' — подтопик, который есть у всех устройств — именно в него записываются все их параметры, которые меняются («включено-выключено», значение датчика, ...).
* <code>/controls</code> — подтопик, который есть у всех устройств — именно в него записываются все их параметры, которые меняются («включено-выключено», значение датчика, ...).
* ''/28-0115a48fcfff'' — непосредственно сам «канал» («контрол») — топик, куда записывается значение с датчика. Его название совпадает с адресом 1-Wire датчика на шине.
* <code>/28-0115a48fcfff</code> — непосредственно сам «канал» («контрол») — топик, куда записывается значение с датчика. Его название совпадает с адресом 1-Wire датчика на шине.
Содержание сообщения:
Содержание сообщения:
* ''23.25'' — значение температуры
* <code>23.25</code> — значение температуры


Если вы хотите самостоятельно написать драйвер устройства, и хотите, что оно отображалось на вкладке Devices и его можно было использовать в правилах, вам необходимо придерживаться такой же структуры топиков.
Если вы хотите самостоятельно написать драйвер устройства, и хотите, что оно отображалось на вкладке '''Devices''' и его можно было использовать в правилах, вам необходимо придерживаться такой же структуры топиков.


=== Структура сообщения об ошибке опроса устройства ===  
=== Структура сообщения об ошибке опроса устройства ===  
Строка 76: Строка 76:
Клиенты, которые хотят следить за значением температуры, «подписываются» на этот топик, и им приходят все новые сообщения — меняющиеся значения температуры. Один из таких клиентов — веб-интерфейс.
Клиенты, которые хотят следить за значением температуры, «подписываются» на этот топик, и им приходят все новые сообщения — меняющиеся значения температуры. Один из таких клиентов — веб-интерфейс.


Подписаться на сообщения можно и из консоли Linux при помощи утилиты '''mosquitto_sub''' (полное описание работы с MQTT из командной строки смотрите ниже):
Подписаться на сообщения можно и из консоли Linux при помощи утилиты <code>mosquitto_sub</code>:
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
root@wirenboard:~# mosquitto_sub -t '/devices/wb-w1/controls/28-0115a48fcfff' -v //получить сообщения из топика устройства 1-Wire с идентификатором 28-0115a48fcfff
root@wirenboard:~# mosquitto_sub -t '/devices/wb-w1/controls/28-0115a48fcfff' -v //получить сообщения из топика устройства 1-Wire с идентификатором 28-0115a48fcfff
Строка 83: Строка 83:
/devices/wb-w1/controls/28-0115a48fcfff 22.75
/devices/wb-w1/controls/28-0115a48fcfff 22.75
</syntaxhighlight>
</syntaxhighlight>
Полное описание работы с MQTT из командной строки смотрите ниже.


=== Структура сообщения — команды на изменение состояния ===  
=== Структура сообщения — команды на изменение состояния ===  
Строка 139: Строка 141:
</syntaxhighlight>
</syntaxhighlight>
В результате мы получили не только значения с «контрола» устройства, но и топики с метаданными — название драйвера устройства и тип «контрола» - ''temperature''.
В результате мы получили не только значения с «контрола» устройства, но и топики с метаданными — название драйвера устройства и тип «контрола» - ''temperature''.
Существует так же метасимвол ''+'', который обозначает один уровень, а не произвольное количество,как ''#'':
Существует так же метасимвол '''+''', который обозначает один уровень, а не произвольное количество,как '''#''':
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
mosquitto_sub -v -t "/config/widgets/+/name"  
mosquitto_sub -v -t "/config/widgets/+/name"  
Строка 146: Строка 148:




Полное описание системы топиков и подписок [http://mosquitto.org/man/mqtt-7.html http://mosquitto.org/man/mqtt-7.html].
[http://mosquitto.org/man/mqtt-7.html Полное описание системы топиков и подписок].


==== Очистка очереди сообщений ====
==== Очистка очереди сообщений ====
Строка 153: Строка 155:
Это приводит к тому, что несуществующие больше устройства могут отображаться в разделе ''Devices'' веб-интерфейса.
Это приводит к тому, что несуществующие больше устройства могут отображаться в разделе ''Devices'' веб-интерфейса.


Для удаления топиков можно воспользоваться командой ''mqtt-delete-retained''. Пример использования:
Для удаления топиков можно воспользоваться командой <code>mqtt-delete-retained</code>.  
 
Например, удалим все топики, начинающиеся на <code>/devices/noolite_tx_1234/</code>
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
root@wirenboard:~# mqtt-delete-retained '/devices/noolite_tx_1234/#'  
root@wirenboard:~# mqtt-delete-retained '/devices/noolite_tx_1234/#'  
</syntaxhighlight>
</syntaxhighlight>
удалит все топики, начинающиеся на '/devices/noolite_tx_1234/'


Для удаления топиков «по маске», можно циклично вызывать runShellCommand из правил. Таким образом, задача сводится к задаче работы со строками в js.
Для удаления топиков «по маске», можно циклично вызывать <code>runShellCommand</code> из правил. Таким образом, задача сводится к задаче работы со строками в js.
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
var deviceName = ['name1',.., 'nameN'];
var deviceName = ['name1',.., 'nameN'];
Строка 171: Строка 174:
=== Работа с MQTT из внешних программ ===
=== Работа с MQTT из внешних программ ===


Если вы разрабатываете собственное ПО для Wiren Board, взаимодействовать с его аппаратными ресурсами лучше всего через протокол MQTT — ваша программа передаёт сообщение по MQTT, драйвер управляет устройством, и вашей программе не нужно напрямую взаимодействовать с устройством на низком уровне.
Если вы разрабатываете собственное ПО для Wiren Board, взаимодействовать с его аппаратными ресурсами лучше всего через протокол MQTT — ваша программа передаёт сообщение по MQTT, драйвер управляет устройством и вашей программе не нужно напрямую взаимодействовать с устройством на низком уровне.


Для того, чтобы отправлять сообщения MQTT, для многих языков программирования есть библиотеки. Примеры:
Для того, чтобы отправлять сообщения MQTT, для многих языков программирования есть библиотеки:
* Python - [https://github.com/contactless/mqtt-tools]
* Python - [https://github.com/contactless/mqtt-tools]
* C - [http://mosquitto.org/man/libmosquitto-3.html]
* C - [http://mosquitto.org/man/libmosquitto-3.html]
Строка 179: Строка 182:


=== Просмотр MQTT-каналов в web-интерфейсе ===
=== Просмотр MQTT-каналов в web-интерфейсе ===
MQTT-названия устройств, их элементов управления и последние значения можно найти в разделе Settings web-интерфейса:
MQTT-названия устройств, их элементов управления и последние значения можно найти в разделе '''Settings''' web-интерфейса:
[[Файл:Wb_settings.png|900px|thumb|center|Информация об MQTT-названиях устройств]]
[[Файл:Wb_settings.png|900px|thumb|center|Информация об MQTT-названиях устройств]]


Строка 204: Строка 207:
#: (последняя строка говорит, что нужно пересылать все сообщения (метасимвол '''#''', смотрите описание выше) в обе ('''both''') стороны (с брокера контроллера на облачный брокер и обратно)
#: (последняя строка говорит, что нужно пересылать все сообщения (метасимвол '''#''', смотрите описание выше) в обе ('''both''') стороны (с брокера контроллера на облачный брокер и обратно)
#: Более подробное описание всех опций смотрите на https://mosquitto.org/man/mosquitto-conf-5.html.
#: Более подробное описание всех опций смотрите на https://mosquitto.org/man/mosquitto-conf-5.html.
# Перезапустите mosquitto, выполнив в консоли
# Перезапустите <code>mosquitto</code>, выполнив в консоли:
#: <syntaxhighlight lang="bash">
#: <syntaxhighlight lang="bash">
service mosquitto restart
service mosquitto restart
Строка 213: Строка 216:
Список облачных брокеров, в том числе бесплатных: [https://github.com/mqtt/mqtt.github.io/wiki/public_brokers https://github.com/mqtt/mqtt.github.io/wiki/public_brokers]
Список облачных брокеров, в том числе бесплатных: [https://github.com/mqtt/mqtt.github.io/wiki/public_brokers https://github.com/mqtt/mqtt.github.io/wiki/public_brokers]


'''Задача:''' настроить пересылку топика MQTT на другой контроллер.
Есть два контроллера в одной сети^
# ''DestinationController'' с адресом <code>10.0.0.40</code>, на этот контроллер получать топик.
# ''SourceController'' с адресом <code>10.0.0.70</code>, с этого контроллера будем забирать топик.


'''Задача:''' настроить пересылку топика MQTT на другой контроллер.
На  ''SourceController'' есть <code>/client/temp1</code>, но его нужно видеть на ''DestinationController'' в <code>/devices/temp1</code>.
Есть два контроллера в одной сети, адреса:
;10.0.0.40
:На этот контроллер «забираем» топик. Обозначаем его как «40».
;10.0.0.70
:С этого контроллера, он источник. Назовем его «70».


На  '''70''' есть <code>/client/temp1</code>
Решается двумя способами, можно с ''SourceController'' публиковать на ''DestinationController'' или с ''DestinationController'' подписаться на топик ''SourceController'' и забирать изменения. От выбора стратегии зависит на каком контроллере будем проводить настройки.
Его нужно видеть на '''40''' в <code>/devices/temp1</code>


Решается двумя способами, можно с '''70''' публиковать на '''40''' или с '''40''' подписаться на топик '''70''' и забирать изменения. От выбора стратегии зависит на каком контроллере будем проводить настройки.
Мы будем настраивать ''DestinationController''.
Будем настраивать '''40'''.


'''Решение:'''
'''Решение:''' На контроллере ''DestinationController'' добавьте в конфиг:
На контроллере «40» добавляем в конфиг:
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
mcedit /etc/mosquitto/conf.d/bridge.conf
mcedit /etc/mosquitto/conf.d/bridge.conf
</syntaxhighlight>
</syntaxhighlight>
Следующее
Строки:
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
connection wb_40
connection wb_40
Строка 242: Строка 241:


topic /temp1/# in 2 /devices /client
topic /temp1/# in 2 /devices /client
</syntaxhighlight>
</syntaxhighlight>


Перезапускаем на нем же mosquitto:
Перезапустите <code>mosquitto</code> на ''DestinationController'':
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
systemctl restart mosquitto; systemctl status mosquitto
systemctl restart mosquitto; systemctl status mosquitto
</syntaxhighlight>
</syntaxhighlight>
'''ВАЖНО''' перед перезапуском желательно [[watchdog |остановить watchdog]]. В случае ошибки в конфигах брокер не запустится и watchdog вызовет перезапуск контроллера.
'''ВАЖНО:''' перед перезапуском желательно [[watchdog |остановить watchdog]]. В случае ошибки в конфигурационных файлах брокер не запустится и watchdog вызовет перезапуск контроллера.


Подробней о строчке:
Рассмотрим подробнее строчку <code>topic /temp1/# in 2 /devices /client</code>
 
<syntaxhighlight lang="bash">
topic /temp1/# in 2 /devices /client
</syntaxhighlight>
где:
где:
;/temp1/# это топик от «корня»
* <code>/temp1/#</code> это топик от «корня». На брокере-источнике /client/'''temp1'''.
:На брокере-источнике /client/'''temp1'''
* <code>in</code> — только забираем, изменения на контроллере не передадутся на сервер.
;in — только забираем, изменения на контроллере не передадутся на сервер
* <code>/devices</code> «корень» '''куда''' располагаем локально. На контроллере ''DestinationController'' это <code>/devices</code> и полный путь будет выгляджеть как '''/devices'''/temp1.
;/devices — »корень« '''куда''' располагаем локально
* <code>/client</code> — «корень» откуда забираем на удаленном. На контроллере ''SourceController'' это <code>/client</code> и полный путь будет выгляджеть как '''/client'''/temp1.
: На контроллере '''40''' это '''/devices''' и полный путь будет выгляджеть как '''/devices'''/temp1
;/client — «корень» откуда забираем на удаленном
: На контроллере '''70''' это '''/client''' и полный путь будет выгляджеть как '''/client'''/temp1


'''Проверка:'''
'''Проверка:'''
Дожидаемся статуса бриджа «1» в топике <code>/client/wb_40/bridge_status</code> на контроллере '''70'''.
Дожидаемся статуса бриджа «1» в топике <code>/client/wb_40/bridge_status</code> на контроллере ''SourceController''.
На нем же публикуем:
На нем же публикуем:
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
Строка 275: Строка 266:
</syntaxhighlight>
</syntaxhighlight>


подписавшись на контроллере '''40''' на целевой топик можно видеть:
Подписавшись на контроллере ''DestinationController'' на целевой топик можно видеть:
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
mosquitto_sub -v -t /devices/temp1/#  
mosquitto_sub -v -t /devices/temp1/#