Lab #5: Komunikácia pomocou prokolu MQTT

organizácia tém, štruktúra správ, zmena konfigurácie zariadenia a jeho ovládanie na diaľku pomocou protokolu MQTT

Video pre cvičenie

Motivácia

Komunikačný protokol MQTT patrí medzi najčastejšie a najobľúbenejšie protokoly používané v oblasti IoT. Aj preto je hlavným komunikačným protokolom v architekúre projektu Smart Department, kde sa používa na komunikáciu medzi všetkými vrstami architektúry. Všetky správy, ktoré sa pomocou protokolu MQTT posielajú, sú vo formáte JSON.

Smart Department: Architektúra

Na tomto cvičení zabezpečíme odosielanie nameraných údajov zo senzoru, ako aj príjem správ na zmenu konfigurácie zariadenia a vzdialenú správu.

Ciele

  1. naučiť sa ovládať chytré zariadenie pomocou protokolu MQTT

  2. naučiť sa prijímať správy cez MQTT protokol

  3. porozumieť významu príznaku retain pri odosielaní MQTT správ

  4. naučiť sa zabezpečiť OTA aktualizáciu zmenou konfigurácie zariadenia

Postup

Inštalácia knižnice umqtt.simple

V aktuálnom firmvéri jazyka MicroPython pre mikrokontroléry z rodiny RP2 sa nenachádza modul pre prácu s protokolom MQTT. V tomto kroku ju pridáme nainštalovaním balíka umqtt.simple.

Task

Nainštalujte na chytré zariadenie knižnicu umqtt.simple.

Knižnica umqtt.simple je minimalistický klient protokolu MQTT zo štandardnej knižnice jazyka MicroPython (micropython-lib). Je navrhnutá pre zariadenia s obmedzenými zdrojmi, takže je malá a podporuje len to najpodstatnejšie:

  • pripojenie k brokeru
  • podpora šifrovanej komunikácie pomocou TLS,
  • publikovanie správ s úrovňou kvality služby QoS 0 alebo 1 (QoS 2 nepodporuje),
  • prihlásenie na odber tém a spracovanie prijatých správ,
  • nastavenie poslednej vôle (z angl. last will).

Knižnica je blokujúca a spojenie s brokerom sama neudržiava. Pri dlhšom spojení je preto potrebné posielať brokeru správu PING a po výpadku sa pripojiť znova. Automatické opätovné pripojenie rieši nadstavba umqtt.robust.

Používateľské nastavenia pre MQTT

Chytré zariadenie bude komunikovať pomocou protokolu MQTT. To, ku ktorému brokeru sa pripojí, aké prihlasovacie údaje použije a či bude komunikácia šifrovaná, však závisí od toho, kde bude zariadenie nasadené – iný broker použijete na cvičení, iný doma a iný bude mať zákazník. Tieto údaje preto nemôžu byť súčasťou statickej konfigurácie v module constants.py, ale musí ich byť možné zmeniť bez zásahu do kódu.

V tomto kroku rozšírime triedu Settings o novú skupinu nastavení pre pripojenie k MQTT brokeru.

Task

Rozšírte používateľské nastavenia o pripojenie k MQTT brokeru.

Nastavenia pripojenia budú v novej triede MQTT a v triede Settings budú dostupné v členskej premennej mqtt. Trieda MQTT bude vyzerať nasledovne:

class MQTT(BaseModel):
    broker: str = Field(default=None, type=str, optional=True)
    port: int = 1883
    username: str = Field(default=None, type=str, optional=True)
    password: str = Field(default=None, type=str, optional=True)
    tls: bool = False
    topic_prefix: str = 'thsensor'

Význam jednotlivých premenných je nasledovný:

  • broker – adresa MQTT brokera,
  • port – port, na ktorom broker počúva; štandardne 1883, pri šifrovanej komunikácii 8883,
  • username a password – prihlasovacie údaje k brokeru,
  • tls – príznak šifrovanej komunikácie (ak ho zapnete, nezabudnite zmeniť aj port),
  • topic_prefix – začiatok tém, do ktorých bude zariadenie publikovať.

Task

Navrhnite a implementujte vhodné validátory pre overenie hodnôt v nastaveniach pripojenia k MQTT brokeru.

Zamyslite sa nad tým, ktoré hodnoty môže používateľ zadať nesprávne a čo by to spôsobilo pri pripájaní k brokeru alebo pri publikovaní správ. Môžete sa inšpirovať napríklad týmito validátormi:

  • check_port() – overí, či je číslo portu v rozsahu 1 až 65535,
  • check_host() – overí, či je adresa brokera platný doménový názov alebo IP adresa (napr. nesmie obsahovať medzery, schému ako mqtt:// ani číslo portu),
  • check_topic_prefix() – overí, či prefix tém neobsahuje zástupné znaky + a # a nezačína ani nekončí znakom /.

Ak hodnota nie je platná, validátor vyvolá výnimku ValueError s vhodnou správou.

Task

Nastavte a uložte nastavenia pre pripojenie k MQTT brokeru, ktorý budeme používať na cvičeniach.

Broker má tieto parametre:

  • adresa: mother.fei.tuke.sk
  • port: 8883
  • používateľské meno: student
  • heslo: dgRk9cQ8sU4fCO
  • šifrovaná komunikácia: áno

Nastavenia zmeňte v servisnom termináli pomocou príkazu settings a uložte ich. Ak ste postupovali správne, výpis nastavení bude vyzerať takto:

> settings get mqtt
broker: "mother.fei.tuke.sk"
port: 8883
username: "student"
password: "dgRk9cQ8sU4fCO"
tls: true
topic_prefix: "thsensor"

Overte aj to, že nastavenia zostanú zachované po reštarte zariadenia.

Príkaz mqtt

V tomto kroku vytvoríme príkaz mqtt, pomocou ktorého bude možné pracovať s MQTT brokerom priamo zo servisného terminálu. Technik si tak bude môcť ručne overiť, či sú nastavenia pripojenia správne. Jednotlivé činnosti príkazu implementujeme ako operácie príkazu, aby ich neskôr mohli použiť aj stavy zariadenia.

Task

V module commands/mqtt.py vytvorte triedu MQTT, ktorá bude reprezentovať príkaz mqtt.

O tejto triede bude platiť:

  • bude potomkom triedy BaseCommand,
  • názov príkazu bude "mqtt",
  • opis príkazu bude "Manage MQTT client.",
  • prvým parametrom príkazu bude názov podpríkazu (connect, disconnect alebo pub) a ďalšie parametre dostane vybraný podpríkaz,
  • ak príkaz nedostane žiadny parameter alebo dostane neznámy podpríkaz, vypíše správu "Error: Wrong usage.",
  • klienta pre pripojenie k MQTT brokeru bude uchovávať v členskej premennej kontextu mqtt, aby s ním mohli pracovať aj ďalšie príkazy a stavy; túto premennú vytvorte v konštruktore kontextu s hodnotou None.

Príkaz zaregistrujte rovnako ako ostatné príkazy.

Task

Vytvorte podpríkazy connect a disconnect na pripojenie k MQTT brokeru a odpojenie od neho.

Pripojenie a odpojenie implementujte ako operácie príkazu .connect() a .disconnect().

Operácia .connect() vytvorí klienta triedy MQTTClient z knižnice umqtt.simple, pripojí sa ním k brokeru a uloží ho do členskej premennej kontextu mqtt. Pri vytváraní klienta použite:

  • identifikátor zariadenia device_id ako identifikátor klienta,
  • adresu brokera, port a prihlasovacie údaje z nastavení mqtt,
  • konštantu MQTT_KEEPALIVE ako interval udržiavania spojenia,
  • šifrovanie podľa nastavenia tls.

Operácia .disconnect() sa od brokera odpojí a premennú mqtt v kontexte nastaví na hodnotu None.

Podpríkazy vypíšu:

  • "Connecting to <broker>..." na začiatku pripájania a "Connected." po úspešnom pripojení,
  • "Disconnected." po odpojení,
  • "Error: Not connected.", ak sa podpríkaz connect volá bez pripojenia do WiFi siete alebo podpríkaz disconnect bez pripojenia k brokeru,
  • "Error: <text výnimky>", ak sa pripojenie nepodarí.

Pri pripájaní môžu vzniknúť dva typy výnimiek. Ak je broker nedostupný alebo má nesprávnu adresu, vznikne výnimka OSError. Ak broker pripojenie odmietne (napr. pre nesprávne meno alebo heslo), vznikne výnimka MQTTException s návratovým kódom brokera (napr. kód 5 znamená, že klient nie je autorizovaný).

Príklad použitia podpríkazov môže vyzerať nasledovne:

> mqtt connect
Error: Not connected.
> net connect iot-lab Secret.Password
...
> mqtt connect
Connecting to mother.fei.tuke.sk...
Connected.
> mqtt disconnect
Disconnected.
> mqtt disconnect
Error: Not connected.

Task

Vytvorte podpríkaz pub na odosielanie správ, ktorého činnosť implementujete ako operáciu príkazu .pub().

Pripojenie k a odpojenie od MQTT brokera

Pripojenie k MQTT brokeru bude úzko súvisieť so stavom ConnectNetwork. Najprv sa zariadenie pripojí do WiFi siete a hneď potom sa pripojí k MQTT brokeru.

Podobne to bude platiť aj pre stav DisconnectNetwork, ktorého súčasťou sa stane odpojenie od MQTT brokera.

Task

Rozšírte funkcionalitu stavu ConnectNetwork o pripojenie k MQTT brokeru.

Task

Rozšírte funkcionalitu stavu DisconnectNetwork o odpojenie od MQTT brokera.

Aby bolo možné komunikovať pomocou protokolu MQTT s okolím, je potrebné pripojiť chytré zariadenie k MQTT broker-u. To zabezpečíme v tomto kroku.

Pre experimentovanie môžete použiť nasledovnú konfiguráciu, pomocou ktorej sa pripojíte na hlavný MQTT broker v architekúre Smart Department:

  • server = "147.232.205.176"
  • port = 8883
  • user = "student"
  • password = "dgRk9cQ8sU4fCO"
  • ssl = true

Nastavenie uvedených vlastností zabezpečte v stave Configuration samostatným rozhraním a overte ich v stave Commissioning. Ak sa zariadeniu nepodarí pripojiť k MQTT brokeru, vráťte sa späť do stavu Configuration.

Samotné pripojenie k MQTT brokeru pred odoslaním nameraných dát, prebehne v stave Connect Network. Odpojenie od MQTT brokera zasa v stave Sleep. V prípade akéhokoľvek problému zariadenie prejde do stavu Error. Pri odpájaní nezabudnite, že najprv sa treba odpojiť od MQTT brokera a až potom sa môžete odpojiť od WiFi.

Publikovanie stavu zariadenia a posledná vôľa

Rovno po pripojení zariadenia k MQTT brokeru je potrebné vykonať dve veci:

  1. nastaviť tzv. poslednú vôľu, a
  2. vypublikovať, resp. aktualizovať stav zariadenia

Posledná vôľa ako aj stav zariadenia by mali mať nastavený retain príznak, aby sa o stave zariadenia dozvedel ktokoľvek, kto sa pripojí neskôr, ako daná správa vznikla.

Stav zariadenia ako aj posledná vôľa, sa budú posielať do rovnakej témy a síce: <department>/<room>/<type>/<id>/status.

V oboch prípadoch je dôležité, aby JSON dokument obsahoval jeden kľúč s názvom status a hodnotou online alebo offline vzhľadom na stav zariadenia:

{
  "status": "offline"
}

Keď sa zariadenie pripojí, môžete do stavu zariadenia publikovať aj ďalšie informácie, ako napr.:

  • IP adresa zariadenia
  • čas a dátum zapnutia
  • vlastnosti zariadenia
  • číslo firmvéru MicroPython-u
  • číslo verzie vášho softvéru
  • informácie o mikrokontroléri
  • a pod.

Publikovanie nameraných dát

Správanie chytrého senzora rozšírime o nový stav s názvom PublishData, v ktorom dôjde k odoslaniu nameraných dát. Po úspešnom odoslaní nameraných dát prejde zariadenie do stavu Sleep.

Diagram stavov: konceptuálny diagram stavov chytrého senzora

Pre odosielanie správ môžete využiť triedu Payload v balíku models. Táto trieda má dve premenné:

  • dt - čas odoslania reprezentovaný ako reťazec formátovaný podľa štandardu ISO 8601
  • metrics - zoznam metrík, resp. zoznam meraní

Zariadenie bude svoje merania publikovať do témy <department>/<room>/<type>/<id>/data. Údaje budú publikované ako JSON dokument, ktorý bude vyzerať napr. takto:

{
  "dt": "2024-10-29T20:09:35Z",
  "metrics": [
    {
      "dt": "2024-10-29T20:00:00Z",
      "name": "temperature",
      "value": 23.4,
      "units": "metric"
    },
    {
      "dt": "2024-10-29T20:00:00Z",
      "name": "humidity",
      "value": 70,
      "units": "%"
    }
  ]
}

Merania reprezentujte ako inštanciu triedy Payload, ktorá sa nachádza v module models.payload.

Pred odchodom z cvičenia…

Ďalšie úlohy

Ďalšie zdroje

  1. MicroPython Lib: umqtt.simple - zdrojové kódy, ukážkové príklady a dokumentácia

  2. MicroPython Chapters: Inštalácia balíkov

  3. MicroPython Chapters: Práca s protokolom MQTT