Egy okosotthon projektnek az alapja, hogy a különböző részegységek egymással tudjanak kommunikálni valahogy. Erre több platform is az MQTT nevű protokollt használja, amit röviden bemutatni próbálok most.
Busz - már itt is
Ha valakinek van némi jártassága Java-ban, netán találkozott már JMS-sel, annak ez szinte primitívnek fog tűnni. Sima publish/subscribe elven működő üzenetküldő szolgáltatással van dolgunk.
Az MQTT-t - a wikipedia szerint - 1999-ben kezdték fejleszteni olyan céllal, hogy beágyazott rendszerek tudjanak egymással infót cserélni. Message Queuing Telemetry Transport, azaz telemetrikus adatokat lehet üzengetni - legalábbis a tervezők eredeti szándéka szerint, de szerencsére nem csak versenyautókban fellépő g-erők közlekedhetnek ezen a buszon.
A rendszernek van egy központi egysége, amit brókernek hívnak. Ő tulajdonképpen csak biztosít egy végtelen hosszú papírlapot, ahova bárki bármit felírhat - kis túlzással. Hozzá csatlakoznak a kliensek, akik vagy üzennek, vagy üzeneteket várnak, vagy mindkettőt egyszerre. Minden üzenet egy bizonyos topic-ra érkezik (lefordítva elég furán hangzik hogy "téma") de ezeket nem kell előre, központilag előkészíteni. Ennek megvan az előnye és a hátránya is: könnyű új publisher-t csatlakoztatni, ugyanakkor nem egyszerű megtalálni egy új topikot, mivel ezeknek nem lehet központilag lekérdezni a listáját. Ha elírsz valamit, akkor lehet keresgélni sokáig...
Hogy áttérjek a lényegre: konkrét implementációnak én a mosquitto nevűt találtam. Legtöbb helyen ezt ajánlják a Home Assistant-hoz, ráadásul még nyílt forrású is. Telepíteni elég egyszerű:
sudo apt install mosquitto -y
Nem sok mindent kell rajta állítgatni, esetleg jelszóval, hitelesítéssel lehet játszadozni, ennyi. Nekem külön RasPi-n fut, de nyilván elfér a HA mellett is. Úgy szokott működni minden erre csatlakozó eszköz, hogy a különböző infókat különböző topikokba rakják fel, illetve ha vár valamire egy kliens, akkor feliratkozik bizonyos topikokra, majd amint azokon üzenet érkezik, akkor teszi amit kell.
Példa
Küldő | Topic | Üzenet |
sonoff_d1 | tele/sonoff_d1/STATE |
{"Time":"2018-12-01T10:25:27", |
hass | stat/sonoff_d1/POWER2 | OFF |
sonoff_d1 | stat/sonoff_d1/RESULT | {"POWER2":"OFF"} |
- sor: egy "sonoff_d1" nevű eszköz kirak egy státusz üzenetet. Akit érdekel, az feliratkozik a "tele/sonoff_d1/STATE" nevű topikra és feldolgozza az üzenetet. Jelen esetben az üzenet egy JSON kód, de nincs semmi előírás, bármi lehet itt. Túl nagy adatot nem érdemes küldeni, általában 1000 karakterben szokták maximálni az üzi hosszát, de sok beágyazott rendszernek már ez is túl hosszú (egy Arduino-nak 2 kB a teljes RAM kapacitása, ami mind nem is érhető el menet közben)
- sor: egy "hass" nevű eszköz (ami jelen esetben a HA központi egysége) küldött egy üzenetet a "stat/sonoff_d1/POWER2" nevű topikra. Amint látható is, itt nem JSON az üzenet, hanem csak "OFF". A konkrét példa azt mutatja, ahogy a központ kikapcsol egy relét.
- sor: "sonoff_d1" visszajelez a "stat/sonoff_d1/RESULT" topikon, hogy sikerült a művelet, JSON-ul szólva "{"POWER2":"OFF"}" - kikapcsolta a kettes relét.
A példa bemutatja, hogy hogy is kommunikálhatnak ezen keresztül a rendszerek. Minden eszköz "belekiált" valamit az éterbe, más eszközök meg hallgatózhatnak ilyen kiáltásokra. Kérdés-válasz jellegű kommunikációhoz 2 topik kell, státusz jellegű üzeneteket viszont bármikor lehet közreadni. A topikok akkor jönnek létre, amikor valaki üzen rájuk, vagy valaki elkezd hallgatni egyre.
Parancssor
A mosquitto-val jön pár parancssori alkalmazás is:
- mosquitto_pub: publish, azaz ezzel lehet publikálni üzit. Ha lokális a mosquitto szerver, akkor csak -t topic -m message paraméterek kellenek és már el is küldtük a "topic"-ra a "message" üzenetet.
- mosquitto_sub: subscribe, vagyis ezzel lehet feliratkozni topikra. Lokálisan ő csak egy topik nevét várja -t után
Retain
Amikor küldünk egy üzenetet, akkor meg lehet adni, hogy az "postán maradó" legyen-e: ha igent mondunk, akkor ez az üzenet ottmarad a topikon, amíg nem jön újabb. Ez azért érdekes, mert ha valaki azután iratkozik fel miután az üzi már megérkezett a topikra, akkor ez a paraméter dönti el, hogy a friss feliratkozó megkapja-e az üzinket, vagy csak a következőt. (Ja igen, azt nem mondtam még, hogy a korábbi üziket nem lehet hivatalos módszerrel elérni, csak mindig a legfrissebbet.)
Will
Ami nekem érdekes volt, hogy megoldható az is, hogy tudni lehessen, egy kliens csatlakozva van-e. Ezt úgy lehet elérni, hogy amikor kliensként csatlakozunk, akkor pár paraméterrel lehet olyat mondani, hogy mennyi legyen a timeout és ha ennyi időn belül nem küldünk semmit a szerver felé, akkor melyik topic-ra milyen üzenet kerüljön ki magától. Python-ul ez a következőképp hangzik:
import paho.mqtt.client as mqtt
MQTT_HOST = 'your_mqtt_server_address'
client = mqtt.Client()
client.will_set('myclient/status', 'offline', 0, True)
client.connect(MQTT_HOST, 1883, 60)
client.loop_start()
client.publish('myclient/status', 'online', 0, True)
#do what you want
client.loop_stop()
client.disconnect()
Itt 60 mp a timeout, és a myclient/status topikra offline üzenet megy ki (retian módban) ha ezen az időkorláton belül nem szólunk semmit. Nyilván a csatlakozás után rögtön szólunk is az említett topikra, hogy online lett a kliensünk. (Ha normál módon, disconnet() metódussal ér véget az együttműködés, akkor is kimegy az offline, amit beállítottunk.)