Pull to refresh

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

Reading time 4 min
Views 69K
Эта статья показывает ещё один способ взаимодействия микроконтроллера из семейства 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"	<light>
Switch	Kitchen_light2	"Кухня. Свет 2"	<light>

Не забываем добавить их в sitemap в любое удобное место. Перезапускаем openHAB:
sudo service openhab restart

Можно начинать экспериментировать! Подключаемся с любого устройства к серверу MQTT и подписываемся на топик /myhome/#. При каждом изменении статуса любого Item мы будем получать сообщение, в топике которого будет указано имя Item, а в тексте сообщения — его новый статус. Нам этого достаточно, перейдём к программированию микроконтроллера.

Код должен выглядеть примерно так
#include <SPI.h>           // Ethernet shield
#include <Ethernet.h>      // Ethernet shield
#include <PubSubClient.h>  // MQTT 

#define light1_pin 25
#define light2_pin 27

byte mac[]    = { 0x01, 0x23, 0x45, 0x67, 0x89, 0x12 };
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)) {
    if (!client.connected()) {
      if (client.connect("myhome-kitchen")) client.subscribe("/myhome/in/#");
    } 
    if (client.connected()) { 
      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();
  }
}


Недостающую библиотеку можно скачать здесь: https://github.com/knolleary/pubsubclient

Вот и всё. Прокомментирую только последний кусочек кода. Если управление освещением происходит напрямую через микроконтроллер, то необходимо передать новое состояние в openHAB. Это можно сделать непосредственно сразу после изменения состояния, либо раз в минуту передавать состояние всех контролируемых нагрузок.

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

Articles