Napisz do mnie

Wyślij prywatną wiadomość

MQTT - STRUKTURA TEMATÓW WIADOMOŚCI

opublikowano: 10 lut 2019 wyświetleń: 762 komentarzy: 0

#dariahomesystem #IoT #home automation #automatyka domowa #MQTT #Node-RED #JSON #middleware

Jak ugryźć temat... tematów wiadomości w MQTT?

Dokument został zmodyfikowany 20.11.2019. Naniesione zmiany w systemie wynikające z jego rozwoju.

W jednym z wcześniejszych wpisów dotyczącym połączenia Hapcana z Node-REDem wspomniałem o problemie z utrzymaniem porządku i czytelności przepływów. Poniższy rysunek poglądowy dla przypomnienia:

Skomplikowane połączenia w Node-RED

Wszystko jest tutaj ładnie pomieszane i będzie to bardzo trudne w utrzymaniu. Dlatego też, postanowiłem, po pierwsze podzielić cały system oparty o Node-RED na osobne przepływy, spełniające określone zadania. Sprawa prosta i oczywista. Node-RED umożliwia tworzenie połączeń pomiędzy przepływami i tak można z jednej karty wywołać funkcje znajdujące się na innej karcie. Ma to jednak jeden minus — wszystkim zajmuje się Node-RED.

Postanowiłem zatem uniezależnić się od jednego tylko procesu i całą komunikację pomiędzy urządzenia, serwisami, usługami przepuszczam przez zewnętrzny proces serwera MQTT.

STRUKTURA TEMATÓW MQTT

Protokół nie wymusza żadnej konkretnej struktury, zatem mamy pełną dowolność. Niestety szybko okazuje się, że zaczniemy wyszukiwać w internetach fraz: jaka struktura mqtt. Każdy ma swoją wersję, swój pomysł. Czy w temacie umieszczać informację, który parametr w systemie się zmienia? Czy może nazwę albo adres urządzenia? A może jego typ… albo położenie w domu, a co jeśli usługa nie ma położenia, bo jest tylko usługą :).

Głowiłem się na tym tematem dosyć długo. Od wyboru sposobu tworzenia tematów zależy też, czy będziesz mógł skorzystać np. z aplikacji na Androida, w którym mógłbyś oglądać i sterować swoim systemem. Ich możliwości są nieco ograniczone i wymuszają one poniekąd pewne informacje zawarte w temacie.

Po wielu próbach opracowałem, nie powiem, że do końca oraz, że jest to jedyny, najlepszy i w ogóle… sposób zapisu tematów. (aktualizacja listopad 2019 — zmieniłem jednak nieco strukturę tematów przestawiając kolejność jednej sekcji).

ŹRÓDŁO / DOMENA / TYP-MODUŁ / LOKALIZACJA-USŁUGA / NAZWA / RODZAJ WIADOMOŚCI

Wygląda groźnie, w praktyce mi jest łatwiej zapamiętać takie tematy i pisać je z głowy. Kilka założeń odnośnie tematów i wiadomości:

  • wszystkie tematy mają tę samą strukturę — co za tym idzie, głębokość
  • wiadomości w formacie JSON
  • tematy nie przekazują informacji o statusie ani instrukcji sterujących

Dlaczego JSON? Bo można go w dowolnej chwili rozszerzyć o dodatkowe dane i nie posypie się cały istniejący już kod. Z podobnego względu tematy nie zawierają informacji nt. statusu ani instrukcji sterujących. Niektóre statusy czy instrukcje mają więcej niż 1 parametr. W temacie trzeba by to realizować poprzez jego zmienną długość lub wysyłać kilka osobnych instrukcji sterujących — a niestety niektóre urządzenia potrzebują kompletu instrukcji aby zachowywały się poprawnie.

PRZYKŁADOWE TEMATY

  • home/env/light/room1/walllight/status
  • home/env/light/room1/walllight/control
  • home/env/button/kitchen/leftwindow/status
  • home/env/blind/room2/window2/control
  • home/sys/service/eventgenerator/sun/status
  • home/sys/scene/room1/night/control
  • home/sys/service/notification/center/control

DOKŁADNIEJSZY OPIS

Źródło wskazuje na fragment systemu, który bezpośrednio związany jest z wiadomością. Wszystko co jest generowane w domu i jest z nim związane ma tutaj wartość home. Inne wartości wskazują na zewnętrzne jednostki organizacyjne, jakimi np jest samochód, działka (ROD) czy smartfon.

Domena ma obecnie dwie wartości i pozwala sprecyzować o jaki świat chodzi :)

  • env — environment, czyli podsystem związany z fizycznymi urządzeniami, jak światła, rolety, czujniki
  • sys  — system, czyli podsystem związany z wszelkimi wirtualnymi usługami, scenami, serwisami, danymi

Typ-moduł dotyczyć może fizycznego typu urządzenia: light, switch, button, robot, screen, lub też w przypadku domeny sys: data, scene, service, website. Pozwala np. grupować wszystkie informacje o światłach pochodzące z mieszkania i zasubskrybować je pod jednym tematem.

Lokalizacja/usługa przybliża z czym mamy do czynienia. W przypadku domeny env są to zazwyczaj nazwy pomieszczeń, czyli room1, room2, kitchen, wc, bathroom, hall, interior. W przypadku domeny systemowej np. user, backup, storage, notification ale też room1, room2 itp. — co oznacza, że np dana usługa działa w obrębie konkretnego pomieszczenia. W dużej mierze nazwa usługi zależy od tego, jakiego modułu dotyczy.

Nazwa to sprawa oczywista, coś co pozwala mi zidentyfikować czy chodzi o lampę na suficie czy na ścianie, usługę taką czy inną, dane użytkownika A czy B.

Rodzaj wiadomości określa przeznaczenie wiadomości:

  • status — oznacza, że wiadomość zawiera informacje o statusie urządzenia bądź usługi, czyli wiadomość informacyjna
  • control — oznacza wiadomość sterującą danym urządzeniem lub usługą
  • control_raw — oznacza bezpośrednią kontrolę nad urządzeniem, gdyż parametry wiadomości typu control mogą być modyfikowane przez tzw. middleware, czyli kod wstrzykiwany pomiędzy zlecenie a wykonanie danego polecenia — umożliwia to np. staerowanie mocą świateł zależnie od godziny i niezależnie od tego w jaki sposób użytkownik zlecił włączenie światła.

Trzymając się takiego podziału wiem czego konkretnie dotyczy wiadomość, czy jest to urządzenie czy usługa, gdzie się ono znajduje, czy jest to wiadomość sterująca czy status.

Bardzo istotne jest aby na tym poziomie dokumentować sobie strukturę tematów. Ja robię to w OneNote w tabeli, której fragment prezentuję poniżej.

Source

Domain

Device type/module

Location/subject

name

messageType

opis

home

env

button

room2

wallbutton7

status

Włacznik światła 7(walllight) w pokoju 2

 

 

 

 

wallbutton8

status

Włącznik światła 8(ceiling) w pokoju 2

 

 

blind

room1

doorblind

control|status

Roleta od balkonu w pokoju 1

 

 

 

 

windowblind

control|status

Roleta okna w pokoju 1

 

 

irreceiver

room1

receiver

status

Odbiornik podczerwieni w pokoju 1

 

 

light

hall

ceiling

control|control_raw|status

Światło w przedpokoju

 

 

 

room1

brickwallledstrip

control|control_raw|status

Taśma led w pokoju 1 na ścianie z cegieł

 

 

 

 

ceiling

control|control_raw|status

Światło hue w pokoju 1

 

 

 

 

ceilingshelf

control|control_raw|status

Światło pólka pod sufitem w pokoju 1

Dla czytelności każda nazwa jest sortowana alfabetycznie i pomijane są początkowe frazy jeśli są takie same jak te powyżej — powstaje zatem takie drzewko tematów.

Każda zmiana w nazewnictwie w Node-red jest od razu aktualizowana w dokumentacji, bo w pewnym momencie zajrzenie do niej staje się o wiele łatwiejsze niż szukanie tego w nodach Node-reda.

Sytuacje dyskusyjne

Kwestia organizacji niektórych tematów nie jest taka oczywista, trzeba po prostu popatrzyć, jak będzie dla nas wygodniej. Przykładowo informacja o zajściu słońca. Jest ona generowana przez fragment kodu w Node-RED, który pozwala emitować wszelkie zdarzenia związane ze słońcem, sunrise, sunset, night (wschód, zachód, noc) itp.

Temat mógłby zatem wyglądać tak:

  • home/sys/service/suneventsgenerator/sunset/status

Zawiera on informację o tym, że jest to jakieś zdarzenie systemowe, że wygenerowała ją usługa suneventsgenerator. Można zasubksrybować się pod ten konkretny temat i wykonać jakąś operację po zachodzie słońca — np. włączyć światła na zewnątrz. Ale teraz, żeby je o świcie wyłączyć należałoby zasubskrybować się do analogicznego zdarzenia na wschód słońca:

  • home/sys/service/suneventsgenerator/sunrise/status

Inne rozwiązanie, to nasłuchiwanie wszystkich tematów związanych z generatorem słonecznym, czyli :

  • home/sys/service/suneventsgenerator/+/status

Wtedy trzeba jednak po odebraniu powiadomienia sprawdzić jaki jest 4 człon tematu, aby wiedzieć jakie to zdarzenie nastąpiło. W tym jak i w powyższych rozwiązaniach sam temat mówi nam już w zasadzie wszystko co chcemy wiedzieć, wiadomość sama w sobie jest zbędna.

Zgodnie jednak z założeniami, że temat nie niesie informacji, zamiast generatora słonecznego (suneventsgenerator) mam usługę eventgenerator. Generator może być oparty o różne aspekty, słońce, czas, być może kalendarz imienin. Tematy generowane u mnie wyglądają zatem tak:

  • home/sys/service/eventgenerator/sun/status
  • home/sys/service/eventgenerator/time/status

W samym temacie nie mam jasnej informacji co się stało — tę informację niesie treść wiadomości. Wiem tylko, że nastąpiło jakieś zdarzenie związane ze słońcem lub z czasem. A sama wiadomość, to zgodnie z założeniami JSON:

{
  "event": "sunset"
}

To oczywiście pociąga za sobą konieczność przetwarzania wiadomości aby sprawdzić jakie to zdarzenie przyszło i tym zajmuje się klocek w Node-RED.

 

KOMUNIKACJA I ABSTRAKCJA

Przy nieco większych systemach problematyczne staje się pamiętanie jaki adres Hapcan ma dane urządzenie, jakie instrukcje trzeba do niego wysłać oraz jak odczytać z niego dane. Dlatego też wszelkie urządzenia Hapcan, oraz inne typu Philips Hue, mam zmapowane na odpowiednie tematy MQTT i tylko przez MQTT mogę się z nimi komunikować. Oczywiście jest to założenie, bo w praktyce nie ma tutaj żadnych ograniczeń.

W Node-RED mam osobne karty (przepływy), na których wszystkie urządzenia generują odpowiednie tematy rodzaju status, oraz odpowiednio zaadresowane tematy control pozwalają sterować urządzeniami. W tym momencie wiedza o tym, że światło w kuchni to jest moduł Hapcan nr (4,2), przekaźnik 5 przestaje być istotna przy programowaniu systemu. Jest ona zapisana tylko w jednym miejscu gdzie następuje mapowanie Hapcan-MQTT.

Jeśli zatem pragnę sterować światłem na suficie w kuchni to tworzę z głowy odpowiedni temat (ewentualnie upewniam się co do nazwy lampy w mojej dokumentacji):

  • home/env/light/kitchen/ceiling/control

i mam pewność, że dotrze to do odpowiedniego przekaźnika w Hapcanie. Takie podejście ma ogromną zaletę. W przypadku awarii, lub zmiany w infrastrukturze Hapcana i np. podłączeniu zamiast przekaźnika żarówki Philips Hue (zigbee) nie muszę modyfikować całego istniejącego już kodu, przepływów itp. Wystarczy zmienić tylko mapowanie w jednym miejscu systemu.

Cała kontrola nad urządzeniami przechodzi zatem zawsze przez jeden punkt. Daje to możliwość wpływu na wiadomości sterujące niezależnie od tego, kto je wysłał. Przykładowo w godzinach wieczornych światła są delikatnie ściemniane i niezależnie od tego czy będą włączone pilotem, przyciskiem, głosem czy poprzez czujnik ruchu, każde z tych poleceń przejdzie przez kawałek kodu (middleware), który zmieni bądź też doda parametr brightness odpowiadający za jasność świecenia danej lampy.

Również w sytuacji gdy chcemy jakiś element systemu odłączyć, wiadomo że wystarczy przerwać jedną nitkę w mapowaniu a nie przeszukiwać cały system w poszukiwaniu użycia bloczka sterującego odpowiednim przekaźnikiem.

Szerzej o tym, w następnej części.


CZYTAJ DALEJ POZOSTAŁE CZĘŚCI TEGO ARTYKUŁU


ZOBACZ RÓWNIEŻ POLECANE WPISY


Comments (0)


Allowed tags: <b><i><br>


PODOBAŁO SIĘ?

PODOBAŁO SIĘ?


0 like voting
is closed
thanks
for your vote

PODZIEL SIĘ

PODZIEL SIĘ