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

Материал из Wiren Board
(Отметить эту версию для перевода)
м (массовое удаление контролов по маске)
(не показаны 84 промежуточные версии 3 участников)
Строка 2: Строка 2:
<translate>
<translate>
<!--T:1-->
<!--T:1-->
'''MQTT''' - очередь сообщений, использующаяся в Wiren Board. Большая часть встроенных функций контроллера (АЦП, реле, транзисторный выход, watchdog) и внешних совместимых устройств транслируются туда в виде сообщений и реагируют на управляющие сообщения оттуда. [[Wiren Board 4:Веб-интерфейс | Веб-интерфейс]] работает также через систему сообщений MQTT - нажатие кнопки в интерфейсе вызывает отправку сообщения сообщения в MQTT-брокер, изменение показания датчика, поступившее в систему сообщений, тут же транслируется в веб-интерфейс.
'''MQTT''' - очередь сообщений, использующаяся в [[Программное обеспечение Wiren Board|программном обеспечении Wiren Board]]. [http://en.wikipedia.org/wiki/MQTT Базовая информация по MQTT на Википедии].


<!--T:2-->
Драйверы, отвечающие за аппаратные возможности контроллера (цифровые входы, АЦП, транзисторный выходы, ...) и функции внешних подключённых устройств (например, подключённых по RS-485 модулей реле) записывают их состояние в очередь MQTT в виде специальных сообщений. Веб-интерфейс читает эти сообщения и на их основе отображает состояние устройств.
Базовая информация по MQTT - [http://en.wikipedia.org/wiki/MQTT статья] на википедии. Используемый демон - брокер сообщений [http://mosquitto.org/ Mosquitto].


Если же происходит нажатие кнопки в веб-интерфейсе, уже веб-интерфейс отправляет сообщение в очередь MQTT, драйвер устройства его получает и отдаёт команду устройству.


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


<!--T:4-->
== Принцип работы очереди сообщений ==
Архитектура ПО Wiren Board:
[[File:MQTT.png | thumb | 600px | Через очередь сообщений MQTT работают драйверы внутренних функций, внешних устройств, веб-интерфейс, система правил]]
Система сообщений MQTT построена по следующему принципу:
*есть иерархическая система "топиков" (как на обычных форумах в интернете)
*в эти топики клиенты (в случае Wiren Board это драйверы устройств и веб-интерфейс) могут писать сообщения и читать оттуда
*чтобы следить за изменениями нужного топика (например, температуры на датчике), клиент может на него "подписаться" - тогда он получит все сообщения в данном топике.
Полное описание системы топиков и подписок [http://mosquitto.org/man/mqtt-7.html http://mosquitto.org/man/mqtt-7.html].


<!--T:5-->
=== Отображение устройств в структуре сообщений === <!--T:24-->
[[Special:MyLanguage/File:MQTT.png | thumb | 600px]]


<!--T:6-->
<!--T:25-->
Специальные "драйверы" (отдельный для каждой функции контроллера и внешнего устройства) транслируют данные с устройства в очередь в виде сообщений специального формата. Сообщения из этой очереди получает веб-интерфейс и движок правил. Они же могут добавлять туда новые сообщения - например, "включить реле" после получения нажатия в интерфейсе или выполнения нужных условий в каком-нибудь правиле.
Логика организации топиков, соответствующих разным устройствам и их параметрам, в Wiren Board следует определённым правилам - так называемым соглашениям ([https://github.com/contactless/homeui/blob/master/conventions.md Wiren Board MQTT Conventions]).
 
 
== Принцип работы системы сообщений == <!--T:7-->


<!--T:8-->
Полный список MQTT-топиков можно увидеть на странице ''Settings'' веб-интерфейса в разделе ''MQTT Channels'' (появилось в последних версиях [[Обновление прошивки|прошивки]]).
MQTT построена по следующему принципу: есть иерархическая система "топиков" (прямо как на обычных форумах), куда клиенты могут писать сообщения, и откуда могут читать. Чтобы было удобно следить за изменениями нужного топика (например, температуры), на него можно "подписаться".


=== Пример сообщения === <!--T:9-->
=== Клиенты очереди сообщений ===
*драйверы внутренних аппаратных функций
*драйверы внешних подключённых устройств
*веб-интерфейс
*движок правил
*(если есть) собственные программы пользователя


<!--T:10-->
=== Структура сообщения о состоянии устройства ===
Вот пример сообщения от драйвера датчика 1-Wire (драйвер регулярно опрашивает датчик и отправляет в виде сообщений значения с него):
Вот пример сообщения от драйвера температурного датчика 1-Wire из примера выше:
<pre>
<pre>
/devices/wb-w1/controls/28-000004a7d3f9 24.687000
/devices/wb-w1/controls/28-0115a48fcfff 23.25
</pre>
</pre>
Часть до пробела - название топика, после - само сообщение.
Часть до пробела - название топика, после - само сообщение.
Здесь:
* ''/devices'' - коренной топик для всех "устройств" - как встроенных модулей Wiren Board (реле, АЦП, ...), так и подключённых внешних,
* ''/wb-w1'' - подтопик, который наполняется драйвером 1-Wire,
* ''/controls'' - подтопик, который есть у всех устройств - именно в него записываются все их параметры, которые меняются ("включено-выключено", значение датчика, ...),
* ''/28-000004a7d3f9'' - непосредственно сам "контрол" - топик, куда записывается значение с датчика. Его название совпадает с адресом 1-Wire датчика (аппаратно закладывается в каждый датчик на заводе),
* ''24.687000'' - значение температуры. Это и есть содержание сообщения, отправленного драйвером 1-Wire в топик.


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


=== Пример подписки === <!--T:11-->
=== Пример подписки === <!--T:11-->
Строка 47: Строка 68:


<!--T:13-->
<!--T:13-->
Подписаться на сообщения можно и из консоли Linux при помощи утилиты '''mosquitto_sub''':
Подписаться на сообщения можно и из консоли Linux при помощи утилиты '''mosquitto_sub''' (полное описание работы с очередью из командной строки смотрите ниже):
<pre>
<syntaxhighlight lang="bash">
root@wirenboard:~# mosquitto_sub -t '/devices/wb-w1/controls/28-000004a7d3f9' -v  
root@wirenboard:~# mosquitto_sub -t '/devices/wb-w1/controls/28-0115a48fcfff' -v //получить сообщения из топика устройства 1-Wire с идентификатором 28-0115a48fcfff
/devices/wb-w1/controls/28-000004a7d3f9 20.312000
/devices/wb-w1/controls/28-0115a48fcfff 22.75 //в этой строке и ниже - вывод утилиты, полученные сообщения
/devices/wb-w1/controls/28-000004a7d3f9 20.312000
/devices/wb-w1/controls/28-0115a48fcfff 22.75
/devices/wb-w1/controls/28-000004a7d3f9 20.375000
/devices/wb-w1/controls/28-0115a48fcfff 22.75
</pre>
</syntaxhighlight>
(описание утилиты смотрите [http://mosquitto.org/man/mosquitto_sub-1.html]).


<!--T:14-->
=== Структура сообщения - команды на изменение состояния === <!--T:16-->
Подписаться можно не только на один топик, но и на группу по wildcard:
<pre>
root@wirenboard:~# mosquitto_sub -t '/devices/wb-w1/#' -v
/devices/wb-w1/meta/name 1-wire Thermometers
/devices/wb-w1/controls/28-000004a7d3f9 23.312000
/devices/wb-w1/controls/28-000004a7d3f9/meta/type temperature
/devices/wb-w1/controls/28-000004a7d3f9 23.312000
/devices/wb-w1/controls/28-000004a7d3f9 23.312000
</pre>
, где ''#'' - означает любое количество топиков. Соответственно, вывелись не только значения с "контрола" устройства, но и топики с метаданными - название драйвера устройства и тип "контрола" - ''temperature''.
 
<!--T:15-->
Полное описание системы топиков и подписок: [http://mosquitto.org/man/mqtt-7.html].
 
 
=== Пример сообщения от веб-интерфейса === <!--T:16-->


<!--T:17-->
<!--T:17-->
Подпишемся на сообщения о состоянии встроенного реле Wiren Board:
Подпишемся на сообщения о состоянии первого реле подключённого по RS-485 релейного модуля WB-MRM2:
<pre>
<syntaxhighlight lang="bash">
root@wirenboard:~# mosquitto_sub -t '/devices/wb-gpio/controls/Relay_1/#' -v
root@wirenboard:~# mosquitto_sub -t "/devices/wb-mrm2_130/controls/Relay 1/#" -v
/devices/wb-gpio/controls/Relay_1/meta/type switch
/devices/wb-mrm2_130/controls/Relay 1/meta/type switch
/devices/wb-gpio/controls/Relay_1/on 0
/devices/wb-mrm2_130/controls/Relay 1/meta/order 1
/devices/wb-gpio/controls/Relay_1 0
/devices/wb-mrm2_130/controls/Relay 1 0
</pre>
</syntaxhighlight>
Тут стоит отметить, что MQTT сохраняет часть сообщений (а именно с флагом retained) вечно, поэтому после подписки вы получите даже те сообщения, которые были отправлен раньше, чем вы подписались.
Тут стоит отметить, что MQTT сохраняет часть сообщений (а именно те, которые при отправке были помечены флагом ''retained'') вечно, поэтому после подписки вы получите даже те сообщения, которые были отправлены раньше, чем вы подписались.


<!--T:18-->
<!--T:18-->
Реле управляется драйвером ''wb-gpio'' (этот драйвер также управляет транзисторными выходами и всем, что в электрическом смысле управляется GPIO). У него есть соответствующий топик-"контрол" ''Relay_1''. У него самого есть значение - ''0'' (реле выключено), и есть два подтопика. Один из них - служебный: в ''/meta/type'' записан тип "контрола". Здесь он ''switch'' - выключатель. Второй подтопик ''/on'' - интереснее: в него клиенты пишут то состояние, в которое они хотят установить реле. Заметим, что оно может не совпадать с тем состоянием, в котором реле находится, так как драйвер реле ведёт себя следующим образом: при получении сообщения в топик ''/devices/wb-gpio/controls/Relay_1/on'' он физически устанавливает его на реле, а лишь затем записывает новое значение реле в топик ''/devices/wb-gpio/controls/Relay_1''.
Релейный модуль управляется драйвером [[Драйвер wb-mqtt-serial]]. У него есть соответствующий топик-"канал"("контрол") ''Relay 1''. У него самого есть значение - ''0'' (реле выключено), и есть два подтопика. Один из них - служебный: в ''/meta/type'' записан тип "контрола". Здесь он ''switch'' - выключатель. Второй подтопик ''/on'' - интереснее: в него клиенты пишут то состояние, в которое они хотят установить реле. Заметим, что оно может не совпадать некоторое время (затрачиваемое на процесс переключения) с тем состоянием, в котором реле находится. Драйвер при этом ведёт себя следующим образом: при получении сообщения в топик ''/devices/wb-mrm2_130/controls/Relay 1/on'' он физически включает реле на релейном модуле, а лишь затем записывает новое состояние реле в топик ''/devices/wb-mrm2_130/controls/Relay''.


<!--T:19-->
<!--T:19-->
Например, если мы сейчас нажмем на реле в веб-интерфейсе (переключим его состояние), то получим новые сообщения:
Например, если мы сейчас нажмём на кнопку реле в веб-интерфейсе (переключим его состояние), то получим новые сообщения:
<pre>
<pre>
/devices/wb-gpio/controls/Relay_1/on 1
/devices/wb-mrm2_130/controls/Relay 1/on 1
/devices/wb-gpio/controls/Relay_1 1
/devices/wb-mrm2_130/controls/Relay 1 1
</pre>
</pre>
- веб-интерфейс сначала "даёт указание" включить реле, потом драйвер его включает и ставит актуальное состояние в "контрол".
- веб-интерфейс сначала "даёт указание" включить реле, потом драйвер его включает и записывает актуальное состояние в "канал"("контрол").


==Работа с очередью сообщений==
Программа (демон), отвечающая за рассылку сообщений от одних клиентов другим, называется брокером сообщений. В Wiren Board используется брокер сообщений [http://mosquitto.org/ Mosquitto]. Фактически, все драйверы и веб-интерфейс передают свои сообщения именно демону-брокеру Mosquitto.
===Работа из командной строки===


=== Управление устройствами из командной строки === <!--T:20-->
==== Управление устройствами из командной строки ==== <!--T:20-->


<!--T:21-->
Для управления устройством (изменения значения канала), необходимо отправить сообщение в топик "/devices/<device-id>/controls/<control-id>/on" (обратите внимание на /on в конце).
Как следует из написанного выше, для управления устройством (изменения значения канала), необходимо отправить сообщение в топик "/devices/<device-id>/controls/<control-id>/on" (обратите внимание на /on в конце).
Это делается с помощью консольной команды '''mosquitto_pub'''. Пример:
Это легко сделать с помощью консольной команды mosquitto_pub . Пример:
<syntaxhighlight lang="bash">
root@wirenboard:~# mosquitto_pub -t "/devices/wb-mrm2_130/controls/Relay 1/on" -m "1"
</syntaxhighlight>
команда отправляет сообщение "1" (логическую единицу, "включить") в топик, соответствующий подключённому по RS-485 релейном модуле WM-MRM2 с адресом 130.


<!--T:22-->
==== Слежение за состоянием устройства / подписка на топик ==== <!--T:11-->
<pre>
mosquitto_pub -t "/devices/wb-gpio/controls/Relay_1/on" -m "1"
</pre>


<!--T:23-->
<!--T:12-->
команда включает реле 1 (канал "Relay_1" устройства "wb-gpio").
Клиенты, которые хотят следить за значением температуры, "подписываются" на этот топик, и им приходят все новые сообщения - меняющиеся значения температуры. Один из таких клиентов - веб-интерфейс.


<!--T:13-->
Подписаться на сообщения можно и из консоли Linux при помощи утилиты '''mosquitto_sub''' (полное описание утилиты смотрите на [http://mosquitto.org/man/mosquitto_sub-1.html http://mosquitto.org/man/mosquitto_sub-1.html]):
<syntaxhighlight lang="bash">
root@wirenboard:~# mosquitto_sub -t '/devices/wb-w1/controls/28-0115a48fcfff' -v //получить сообщения из топика устройства 1-Wire с идентификатором 28-0115a48fcfff
/devices/wb-w1/controls/28-0115a48fcfff 22.75 //в этой строке и ниже - вывод утилиты, полученные сообщения
/devices/wb-w1/controls/28-0115a48fcfff 22.75
/devices/wb-w1/controls/28-0115a48fcfff 22.75
</syntaxhighlight>
===Метасимволы===


Подписаться можно не только на один топик, но и на группу топиков по метасиволу. В MQTT применяется два метасимвола: '''#''' и '''+'''. Метасимвол ''#''  означает любое количество уровней вложенных топиков. Выполним команду
<syntaxhighlight lang="bash">
root@wirenboard:~# mosquitto_sub -t '/devices/wb-w1/#' -v
/devices/wb-w1/meta/name 1-wire Thermometers
/devices/wb-w1/controls/28-0115a48fcfff 22.812
/devices/wb-w1/controls/28-0115a48fcfff/meta/type temperature
/devices/wb-w1/controls/28-0115a48fcfff 22.75
</syntaxhighlight>
В результате мы получили не только значения с "контрола" устройства, но и топики с метаданными - название драйвера устройства и тип "контрола" - ''temperature''.
Существует так же метасимвол ''+'', который обозначает один уровень, а не произвольное количество,как ''#'':
<syntaxhighlight lang="bash">
mosquitto_sub -v -t "/config/widgets/+/name"
</syntaxhighlight>
В этом случае мы получим имена всех виджетов.




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


 
==== Очистка очереди сообщений ==== <!--T:26-->
=== Отображение устройств в системе сообщений === <!--T:24-->
 
<!--T:25-->
Логика топиков, соответствующих разным устройствам и их параметрам, основывается на так называемых Conventions. Список актуальных типов здесь: [https://github.com/contactless/homeui/blob/contactless/conventions.md]
 
 
== Очистка сообщений MQTT == <!--T:26-->


<!--T:27-->
<!--T:27-->
Ненужные retained-сообщения могут остаться в системе MQTT после удаления неиспользуемых драйверов или отключения каких-либо устройств.
Ненужные retained-сообщения могут остаться в системе MQTT после удаления неиспользуемых драйверов или отключения каких-либо устройств.
Это приводит к тому, что несуществующие больше устройства могут отображаться в разделе Devices веб-интерфейса.
Это приводит к тому, что несуществующие больше устройства могут отображаться в разделе ''Devices'' веб-интерфейса.


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


Для удаления топиков "по маске", можно циклично вызывать runShellCommand из правил. Таким образом, задача сводится к задаче работы со строками в js.
<syntaxhighlight lang="bash">
var deviceName = ['name1',.., 'nameN'];
var controlName = 'Temperature';


for (var i = 0; i<deviceName.length; i++) {
  runShellCommand ('mqtt-delete-retained /devices/'+ deviceName[i]  + '/controls/controlName/#');
}
</syntaxhighlight>


=== Работа с очередью из внешних программ === <!--T:34-->


== Использование данных внешними программами == <!--T:34-->
<!--T:35-->
Если вы разрабатываете собственное ПО для Wiren Board, взаимодействовать с его аппаратными ресурсами лучше всего через очередь сообщений - ваша программа передаёт сообщение в очередь, драйвер управляет устройством, и вашей программе не нужно напрямую взаимодействовать с устройством на низком уровне.


<!--T:35-->
Для того, чтобы отправлять сообщения 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]
</translate>


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


== Система правил == <!--T:36-->
=== Настройка MQTT моста (bridge) ===
[[File:CloudMQTT.png | thumb | 400px | Настройки брокера Cloud MQTT]]
MQTT мост (bridge) - это функция MQTT-брокера, позволяющая пересылать все или часть сообщений на другой MQTT-брокер, и получать сообщения с другого брокера обратно. На контроллере эта функция настраивается в конфигурационных файлах ''mosquitto''. Самый простой вариант конфигурации приведён ниже.


<!--T:37-->
'''Задача:''' настроить пересылку всех сообщений MQTT на популярный бесплатный облачный MQTT брокер http://cloudmqtt.com/ и обратно.
Вы можете написать свои правила на языке Javascript. Подробнее смотрите [https://github.com/contactless/wb-rules]
 
</translate>
'''Решение:'''
# Зарегистрируйтесь на http://cloudmqtt.com/
# Зайдите в свой аккаунт на http://cloudmqtt.com/ и посмотрите настройки: сервер, порт, логин, пароль.
# Зайдите на контроллер и добавьте в конец файла ''/etc/mosquitto/mosquitto.conf'' следующие строки:
#: <syntaxhighlight lang="bash">
connection cloudmqtt
address m21.cloudmqtt.com:10858
remote_username fs_user_kp
remote_password 5dn_pass_pm
clientid pavel_test
try_private false
start_type automatic
topic # both
</syntaxhighlight>
#: (последняя строка говорит, что нужно пересылать все сообщения (метасимвол '''#''', смотрите описание выше) в обе ('''both''') стороны (с брокера контроллера на облачный брокер и обратно)
#: Более подробное описание всех опций смотрите на https://mosquitto.org/man/mosquitto-conf-5.html.
# Перезапустите mosquitto, выполнив в консоли
#: <syntaxhighlight lang="bash">
service mosquitto restart
</syntaxhighlight>

Версия 20:32, 3 декабря 2018

MQTT - очередь сообщений, использующаяся в программном обеспечении Wiren Board. Базовая информация по MQTT на Википедии.

Драйверы, отвечающие за аппаратные возможности контроллера (цифровые входы, АЦП, транзисторный выходы, ...) и функции внешних подключённых устройств (например, подключённых по RS-485 модулей реле) записывают их состояние в очередь MQTT в виде специальных сообщений. Веб-интерфейс читает эти сообщения и на их основе отображает состояние устройств.

Если же происходит нажатие кнопки в веб-интерфейсе, уже веб-интерфейс отправляет сообщение в очередь MQTT, драйвер устройства его получает и отдаёт команду устройству.

Примеры работы через очередь MQTT

Получение значения от датчика температуры и вывод его в веб-интерфейс

Показания датчика и его уникальный идентификатор на странице Devices веб-интерфейса

Предположим, что к Wiren Board подключён датчик температуры по шине 1-Wire. Проследим, как данные с него через очередь сообщений попадают в веб-интерфейс:

  1. Драйвер, отвечающий за данную аппаратную функцию (wb-homa-w1) опрашивает подключённые к контролеру датчики 1-Wire.
  2. При получении значения драйвер размещает в очереди сообщение следующего вида:
    /devices/wb-w1/controls/28-0115a48fcfff 23.25
    Оно значит, что на устройстве 1-Wire с идентификатором 28-0115a48fcfff получено значение 23.25°C.
  3. Веб-интерфейс, который получает все сообщения из очереди (он подписан на все сообщения), получает это сообщение и выводит значение датчика на страницу.

Нажатие кнопки в веб-интерфейсе и переключение реле на внешнем модуле

Веб-интерфейс после нажатия кнопки включения Реле 1 на подключённом по RS-485 релейном модуле WB-MRM2

Предположим, что к контроллеру по шине RS-485 подключён релейный модуль WB-MRM2. Пользователь в веб-интерфейсе нажимает кнопку включения реле. Проследим, как команда из веб-интерфейса попадает на внешний модуль:

  1. После нажатия кнопки веб-интерфейс размещает в очереди сообщение следующего вида:
    /devices/wb-mrm2_130/controls/Relay 1/on 1
    Оно значит, что устройство WB-MRM2 с адресом 130 должно перевести Реле 1 в состояние логической единицы - "включено".
  2. Драйвер wb-mqtt-serial, отвечающий за данную аппаратную функцию, получает это сообщение (он подписан на все сообщения, относящиеся к подключённым по RS-485 устройствам) и посылает по шине RS-485 релейному модулю команду на включение первого реле.
  3. Релейный модуль WB-MRM2 получает команду от контроллера, переключает реле и посылает обратно уведомление ("Реле 1 включено").
  4. Драйвер wb-mqtt-serial получает это уведомление по RS-485 и публикует в очереди сообщение:
    /devices/wb-mrm2_130/controls/Relay 1 1
    Оно значит, что первое реле на устройстве WB-MRM2 с адресом 130 находится (уже переведено) в состоянии логической единицы ("включено").

Принцип работы очереди сообщений

Через очередь сообщений MQTT работают драйверы внутренних функций, внешних устройств, веб-интерфейс, система правил

Система сообщений MQTT построена по следующему принципу:

  • есть иерархическая система "топиков" (как на обычных форумах в интернете)
  • в эти топики клиенты (в случае Wiren Board это драйверы устройств и веб-интерфейс) могут писать сообщения и читать оттуда
  • чтобы следить за изменениями нужного топика (например, температуры на датчике), клиент может на него "подписаться" - тогда он получит все сообщения в данном топике.

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

Отображение устройств в структуре сообщений

Логика организации топиков, соответствующих разным устройствам и их параметрам, в Wiren Board следует определённым правилам - так называемым соглашениям (Wiren Board MQTT Conventions).

Полный список MQTT-топиков можно увидеть на странице Settings веб-интерфейса в разделе MQTT Channels (появилось в последних версиях прошивки).

Клиенты очереди сообщений

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

Структура сообщения о состоянии устройства

Вот пример сообщения от драйвера температурного датчика 1-Wire из примера выше:

/devices/wb-w1/controls/28-0115a48fcfff 23.25

Часть до пробела - название топика, после - само сообщение.

Название топика состоит из вложенных друг в друга "подтопиков":

  • /devices - коренной топик для всех "устройств" - как встроенных функций Wiren Board (цифровые, АЦП, ...), так и подключённых внешних (например, модулей реле)
  • /wb-w1 - подтопик, который наполняется драйвером 1-Wire
  • /controls - подтопик, который есть у всех устройств - именно в него записываются все их параметры, которые меняются ("включено-выключено", значение датчика, ...)
  • /28-0115a48fcfff - непосредственно сам "канал" ("контрол)" - топик, куда записывается значение с датчика. Его название совпадает с адресом 1-Wire датчика на шине.

Содержание сообщения:

  • 23.25 - значение температуры

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

Пример подписки

Клиенты, которые хотят следить за значением температуры, "подписываются" на этот топик, и им приходят все новые сообщения - меняющиеся значения температуры. Один из таких клиентов - веб-интерфейс.

Подписаться на сообщения можно и из консоли Linux при помощи утилиты mosquitto_sub (полное описание работы с очередью из командной строки смотрите ниже):

root@wirenboard:~# mosquitto_sub -t '/devices/wb-w1/controls/28-0115a48fcfff' -v //получить сообщения из топика устройства 1-Wire с идентификатором 28-0115a48fcfff
/devices/wb-w1/controls/28-0115a48fcfff 22.75 //в этой строке и ниже - вывод утилиты, полученные сообщения
/devices/wb-w1/controls/28-0115a48fcfff 22.75
/devices/wb-w1/controls/28-0115a48fcfff 22.75

Структура сообщения - команды на изменение состояния

Подпишемся на сообщения о состоянии первого реле подключённого по RS-485 релейного модуля WB-MRM2:

root@wirenboard:~# mosquitto_sub -t "/devices/wb-mrm2_130/controls/Relay 1/#" -v
/devices/wb-mrm2_130/controls/Relay 1/meta/type switch
/devices/wb-mrm2_130/controls/Relay 1/meta/order 1
/devices/wb-mrm2_130/controls/Relay 1 0

Тут стоит отметить, что MQTT сохраняет часть сообщений (а именно те, которые при отправке были помечены флагом retained) вечно, поэтому после подписки вы получите даже те сообщения, которые были отправлены раньше, чем вы подписались.

Релейный модуль управляется драйвером Драйвер wb-mqtt-serial. У него есть соответствующий топик-"канал"("контрол") Relay 1. У него самого есть значение - 0 (реле выключено), и есть два подтопика. Один из них - служебный: в /meta/type записан тип "контрола". Здесь он switch - выключатель. Второй подтопик /on - интереснее: в него клиенты пишут то состояние, в которое они хотят установить реле. Заметим, что оно может не совпадать некоторое время (затрачиваемое на процесс переключения) с тем состоянием, в котором реле находится. Драйвер при этом ведёт себя следующим образом: при получении сообщения в топик /devices/wb-mrm2_130/controls/Relay 1/on он физически включает реле на релейном модуле, а лишь затем записывает новое состояние реле в топик /devices/wb-mrm2_130/controls/Relay.

Например, если мы сейчас нажмём на кнопку реле в веб-интерфейсе (переключим его состояние), то получим новые сообщения:

/devices/wb-mrm2_130/controls/Relay 1/on 1
/devices/wb-mrm2_130/controls/Relay 1 1

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

Работа с очередью сообщений

Программа (демон), отвечающая за рассылку сообщений от одних клиентов другим, называется брокером сообщений. В Wiren Board используется брокер сообщений Mosquitto. Фактически, все драйверы и веб-интерфейс передают свои сообщения именно демону-брокеру Mosquitto.

Работа из командной строки

Управление устройствами из командной строки

Для управления устройством (изменения значения канала), необходимо отправить сообщение в топик "/devices/<device-id>/controls/<control-id>/on" (обратите внимание на /on в конце). Это делается с помощью консольной команды mosquitto_pub. Пример:

root@wirenboard:~# mosquitto_pub -t "/devices/wb-mrm2_130/controls/Relay 1/on" -m "1"

команда отправляет сообщение "1" (логическую единицу, "включить") в топик, соответствующий подключённому по RS-485 релейном модуле WM-MRM2 с адресом 130.

Слежение за состоянием устройства / подписка на топик

Клиенты, которые хотят следить за значением температуры, "подписываются" на этот топик, и им приходят все новые сообщения - меняющиеся значения температуры. Один из таких клиентов - веб-интерфейс.

Подписаться на сообщения можно и из консоли Linux при помощи утилиты mosquitto_sub (полное описание утилиты смотрите на http://mosquitto.org/man/mosquitto_sub-1.html):

root@wirenboard:~# mosquitto_sub -t '/devices/wb-w1/controls/28-0115a48fcfff' -v //получить сообщения из топика устройства 1-Wire с идентификатором 28-0115a48fcfff
/devices/wb-w1/controls/28-0115a48fcfff 22.75 //в этой строке и ниже - вывод утилиты, полученные сообщения
/devices/wb-w1/controls/28-0115a48fcfff 22.75
/devices/wb-w1/controls/28-0115a48fcfff 22.75

Метасимволы

Подписаться можно не только на один топик, но и на группу топиков по метасиволу. В MQTT применяется два метасимвола: # и +. Метасимвол # означает любое количество уровней вложенных топиков. Выполним команду

root@wirenboard:~# mosquitto_sub -t '/devices/wb-w1/#' -v
/devices/wb-w1/meta/name 1-wire Thermometers
/devices/wb-w1/controls/28-0115a48fcfff 22.812
/devices/wb-w1/controls/28-0115a48fcfff/meta/type temperature
/devices/wb-w1/controls/28-0115a48fcfff 22.75

В результате мы получили не только значения с "контрола" устройства, но и топики с метаданными - название драйвера устройства и тип "контрола" - temperature. Существует так же метасимвол +, который обозначает один уровень, а не произвольное количество,как #:

mosquitto_sub -v -t "/config/widgets/+/name"

В этом случае мы получим имена всех виджетов.


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

Очистка очереди сообщений

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

Для удаления топиков можно воспользоваться командой mqtt-delete-retained. Пример использования:

root@wirenboard:~# mqtt-delete-retained '/devices/noolite_tx_1234/#'

- удалит все топики, начинающиеся на '/devices/noolite_tx_1234/'

Для удаления топиков "по маске", можно циклично вызывать runShellCommand из правил. Таким образом, задача сводится к задаче работы со строками в js.

var deviceName = ['name1',.., 'nameN'];
var controlName = 'Temperature';

for (var i = 0; i<deviceName.length; i++) {
  runShellCommand ('mqtt-delete-retained /devices/'+ deviceName[i]  + '/controls/controlName/#'); 
}

Работа с очередью из внешних программ

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

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

Просмотр MQTT-каналов в web-интерфейсе

MQTT-названия устройств, их элементов управления и последние значения можно найти в разделе Settings web-интерфейса:

Информация об MQTT-названиях устройств

Настройка MQTT моста (bridge)

Настройки брокера Cloud MQTT

MQTT мост (bridge) - это функция MQTT-брокера, позволяющая пересылать все или часть сообщений на другой MQTT-брокер, и получать сообщения с другого брокера обратно. На контроллере эта функция настраивается в конфигурационных файлах mosquitto. Самый простой вариант конфигурации приведён ниже.

Задача: настроить пересылку всех сообщений MQTT на популярный бесплатный облачный MQTT брокер http://cloudmqtt.com/ и обратно.

Решение:

  1. Зарегистрируйтесь на http://cloudmqtt.com/
  2. Зайдите в свой аккаунт на http://cloudmqtt.com/ и посмотрите настройки: сервер, порт, логин, пароль.
  3. Зайдите на контроллер и добавьте в конец файла /etc/mosquitto/mosquitto.conf следующие строки:
    connection cloudmqtt
    address m21.cloudmqtt.com:10858
    remote_username fs_user_kp
    remote_password 5dn_pass_pm
    clientid pavel_test
    try_private false
    start_type automatic
    topic # both
    
    (последняя строка говорит, что нужно пересылать все сообщения (метасимвол #, смотрите описание выше) в обе (both) стороны (с брокера контроллера на облачный брокер и обратно)
    Более подробное описание всех опций смотрите на https://mosquitto.org/man/mosquitto-conf-5.html.
  4. Перезапустите mosquitto, выполнив в консоли
    service mosquitto restart