Как подружить OpenHAB и Arduino. Способ #3: MQTT

Эта статья показывает ещё один способ взаимодействия микроконтроллера из семейства Arduino с универсальной платформой для объединения всей домашней «умной» техники в единую систему управления openHAB. На Хабре уже представлены статьи про взаимодействия с помощью Serial и HTTP. Для своего нового проекта я выбрал MQTT, т.к. два предыдущих способа я уже пробовал и хотелось попробовать что-то ещё.Приступим…MQTT — протокол для обмена сообщениями между устройствами. Предполагается наличие одного сервера MQTT (так называемый MQTT-broker) и подключённых к нему клиентских устройств. Сообщения состоят из заголовка (topic) и текста сообщения. Подключение к серверу даёт нам две основные возможности: отправлять сообщения и подписываться на интересующие нас топики. При этом работает древовидная структура топиков. Это проще показать на примере. Для датчиков, передающих данные из спальни, можно использовать такие заголовки:

/myhome/bedroom/temperature /myhome/bedroom/humidity /myhome/bedroom/luminosity Аналогично для кухни: /myhome/kitchen/temperature Теперь, подписавшись на любой из этих топиков, мы будем получать сообщения о состоянии каждого конкретного датчика. Но протокол также позволяет подписываться на всю ветку сразу. Чтобы получать в одной подписке данные со всех датчиков спальни, можно подписаться на топик /myhome/bedroom/# Такая структура удобна для понимания человеком, но дальнейшее использование MQTT показало, что значительно проще использовать всего две ветки: одну для обновления статуса элементов и другую — для отправки команд. Но об этом чуть позже.В своём проекте я использовал Raspberry Pi model B+ с установленной Raspbian в качестве платформы для openHAB и Arduino MEGA 2560 с установленным на ней Ethernet Shield w5100. Также экспериментировал с Arduino Yun — всё тоже самое, только используем YunClient вместо EthernetClient.

Оставим за скобками процесс установки openHAB, т.к. этому посвящено множество статей. Перейдём сразу к установке MQTT. Здесь всё просто, открываем консоль и устанавливаем:

sudo apt-get install mosquitto Перезагружаемся и проверяем работоспособность (у меня при первой установке mosquitto никак не хотел запускаться при старте системы): sudo shutdown -r now После перезагрузки: sudo service mosquitto status В ответ должны получить: [ ok ] mosquitto is running. Теперь необходимо установить binding для openHAB. Для этого выполняем: sudo apt-get install openhab-addon-binding-mqtt Или просто копируем файл org.openhab.binding.mqtt-1.6.2.jar (актуальная на сегодня версия) в папку /usr/share/openhab/addons/Перейдём к настройке openHAB:

sudo nano /etc/openhab/configurations/openhab.cfg Здесь добавляем следующие строки: mqtt: mybroker.url=tcp://localhost:1883 mqtt-eventbus: broker=mybroker mqtt-eventbus: commandPublishTopic=/myhome/in/${item} mqtt-eventbus: stateSubscribeTopic=/myhome/out/${item} Ещё нам потребуются два Item, отвечающих за включение/выключение света на кухне: Switch Kitchen_light1 «Кухня. Свет 1» Switch Kitchen_light2 «Кухня. Свет 2» Не забываем добавить их в sitemap в любое удобное место. Перезапускаем openHAB: sudo service openhab restart Можно начинать экспериментировать! Подключаемся с любого устройства к серверу MQTT и подписываемся на топик /myhome/#. При каждом изменении статуса любого Item мы будем получать сообщение, в топике которого будет указано имя Item, а в тексте сообщения — его новый статус. Нам этого достаточно, перейдём к программированию микроконтроллера.Код должен выглядеть примерно так #include // Ethernet shield #include // Ethernet shield #include // MQTT

#define light1_pin 25 #define light2_pin 27

byte mac[] = { 0×01, 0×23, 0×45, 0×67, 0×89, 0×12 }; byte server[] = { 192, 168, 1, 11 }; byte ip[] = { 192, 168, 1, 12 };

EthernetClient ethClient; PubSubClient client (server, 1883, callback, ethClient); unsigned long lastMqtt = 0;

void callback (char* topic, byte* payload, unsigned int length) { payload[length] = '\0'; Serial.print (topic); Serial.print (» »); String strTopic = String (topic); String strPayload = String ((char*)payload); Serial.println (strPayload);

if (strTopic == »/myhome/in/Kitchen_light1») { if (strPayload == «OFF») digitalWrite (light1_pin, LOW); else if (strPayload == «ON») digitalWrite (light1_pin, HIGH); } else if (strTopic == »/myhome/in/Kitchen_light2») { if (strPayload == «OFF») digitalWrite (light2_pin, LOW); else if (strPayload == «ON») digitalWrite (light2_pin, HIGH); } }

void setup () { Serial.begin (57600); Serial.println («start»);

pinMode (light1_pin, OUTPUT); digitalWrite (light1_pin, LOW); pinMode (light2_pin, OUTPUT); digitalWrite (light2_pin, LOW);

Ethernet.begin (mac, ip); if (client.connect («myhome-kitchen»)) { client.publish (»/myhome/out/Kitchen_light1», «OFF»); client.publish (»/myhome/out/Kitchen_light2», «OFF»); client.subscribe (»/myhome/in/#»); } }

void loop () { if (lastMqtt > millis ()) lastMqtt = 0; client.loop ();

// здесь какой-то другой код по уравлению светом, например, с кнопок или ещё как if (millis () > (lastMqtt + 60000)) { boolean mqtt_connect; if (! client.connected ()) mqtt_connect = client.connect («myhome-kitchen»); if (mqtt_connect) { if (digitalRead (light1_pin)) client.publish (»/myhome/out/Kitchen_light1», «ON»); else client.publish (»/myhome/out/Kitchen_light1», «OFF»); if (digitalRead (light2_pin)) client.publish (»/myhome/out/Kitchen_light2», «ON»); else client.publish (»/myhome/out/Kitchen_light2», «OFF»); } lastMqtt = millis (); } } Вот и всё. Прокомментирую только последний кусочек кода. Если управление освещением происходит напрямую через микроконтроллер, то необходимо передать новое состояние в openHAB. Это можно сделать непосредственно сразу после изменения состояния, либо раз в минуту передавать состояние всех контролируемых нагрузок.

В завершении хочу дать ссылку на потрясающую статью, которая очень мне помогла во всём этом разобраться: «Uber Home Automation w/ Arduino & Pi»

© Habrahabr.ru