====== 4. MQTT, SSE ====== ===== Cíle cvičení ===== * Seznámení s MQTT, SSE protokoly ===== Důležité odkazy ===== * [[https://pypi.org/project/paho-mqtt/|Paho MQTT]] * [[https://pypi.org/project/Flask-MQTT/| Flask-MQTT]] ===== Návod ke cvičení ===== ==== MQTT ==== MQTT (Message Queuing Telemetry Transport) představuje síťový protokol navržený speciálně pro potřeby Internetu Věcí (IoT). Tento protokol umožňuje efektivní výměnu zpráv mezi zařízeními v IoT prostředí, a to i přes nestabilní nebo pomalé síťové spojení. Jeho hlavní silou je jednoduchost a nízké nároky na systémové zdroje, což z něj činí ideální volbu pro zařízení s omezeným výpočetním výkonem a pamětí. MQTT funguje na principu publish/subscribe, což je model, kde zařízení (klienti) mohou "publikovat" (publish) zprávy na dané téma a zároveň mohou "předplatit" (subscribe) zprávy z daného téma od ostatních zařízení. Tento model umožňuje, aby komunikace byla tzv. Decoupled, což znamená, že publisher a subscriber nemusí být přímo spojeni ani si být vědomi vzájemné existence. Základní charakteristiky MQTT: * Unordered List ItemMQTT minimalizuje datový provoz a nároky na systémové zdroje, což ho činí vhodným pro zařízení s omezeným výpočetním výkonem a pro sítě s omezenou šířkou pásma, jako jsou mobilní sítě. * Díky modelu publish/subscribe může být komunikace mezi zařízeními snadno škálovatelná a flexibilní, bez nutnosti pevných spojení mezi zařízeními * Ačkoli MQTT samotný poskytuje základní mechanismy pro identifikaci a ověřování, je často kombinován s SSL/TLS protokoly pro zajištění šifrované komunikace mezi klientem a brokerem, což zvyšuje bezpečnost přenášených dat. === Broker === MQTT Broker je centrální uzel v MQTT síti, který přijímá všechny zprávy od klientů, filtruje tyto zprávy, rozhoduje, kdo je jejich příjemce, a poté zprávy distribuuje příslušným klientům. Broker je zásadní pro model publish/subscribe, protože umožňuje Decoupled komunikaci mezi klienty. Broker může být hostován na jakémkoliv serveru s dostatečnou konektivitou a je odpovědný za zpracování autentizace klientů a zajištění bezpečnosti komunikace. Je buď možné využít veřejně dostupný (např. [[https://www.hivemq.com/public-mqtt-broker/|HiveMQ]], vytvořit si vlastní instanci v cloudu (např. [[https://devcenter.heroku.com/articles/cloudmqtt|Heroku]], [[https://cloud.google.com/iot/docs/how-tos/mqtt-bridge|Google]]) nebo si vytvořit vlastní, klidně na svém počítači. Patrně nejznámějším volně dostupným MQTT brokerem je [[https://mosquitto.org/|Mosquitto]]. Pro naše účely využijeme volně přístupný broker na adrese [[https://mqtt.eclipseprojects.io/]]. === Klienti === Klient MQTT je jakékoliv zařízení (od mikrokontrolérů až po plnohodnotné servery), které publikuje zprávy a/nebo se přihlašuje k odběru témat prostřednictvím brokera. Klienti vytvářejí dvě hlavní akce v MQTT: publikují ("publish") zprávy, které odesílají na broker, a předplácejí ("subscribe") témata, pro která chtějí přijímat zprávy od brokera. === Témata (Topics) === Témata jsou způsob, jakým MQTT řídí filtraci a distribuci zpráv. Když klient publikuje zprávu, přiřadí ji k určitému tématu, což je v podstatě cesta nebo identifikátor, který určuje obsah nebo kontext zprávy. Klienti poté mohou předplácet specifická témata u brokera a dostávat zprávy, které jsou publikovány pod těmito tématy. Struktura témat umožňuje velmi flexibilní a dynamické řízení toku informací. === Zprávy (Messages) === Zprávy jsou informace nebo data posílaná mezi klienty prostřednictvím brokera. Každá zpráva je spojena s určitým tématem a může obsahovat libovolná data, od jednoduchých textových řetězců až po složitá binární data. Velikost a obsah zpráv mohou být různé, ale je doporučeno držet zprávy co nejmenší pro zachování efektivity síťové komunikace. === QoS (Quality of Service) úrovně === MQTT definuje tři úrovně QoS pro doručování zpráv, které umožňují klientům určit, jakou garanci doručení si přejí pro své zprávy: * **QoS 0 (At most once)**: Zpráva je odeslána maximálně jednou a broker nevyžaduje potvrzení od příjemce. Je to nejrychlejší, ale nejméně spolehlivá úroveň. * **QoS 1 (At least once)**: Zajišťuje, že zpráva bude doručena alespoň jednou. Příjemce musí potvrdit přijetí, což může vést k duplikaci zpráv. * **QoS 2 (Exactly once)**: Zajišťuje, že zpráva bude doručena přesně jednou. Toto je nejspolehlivější, ale zároveň nejpomalejší úroveň doručení zpráv, protože vyžaduje několik kroků pro potvrzení. ==== MQTT v Pythonu ==== Pro vytvoření odběratele zpráv na PC (server) použijeme knihovnu [[https://pypi.org/project/paho-mqtt/|paho-mqtt]]. pip install paho-mqtt === MQTT subscriber === Následující kód přečte dvě zprávy ze všech zpráv (topic ''#'' reprezentuje všechny zprávy), které v okamžiku připojení brokerem procházejí. import paho.mqtt.subscribe as subscribe topics = ['#'] m = subscribe.simple(topics, hostname="mqtt.eclipseprojects.io", retained=False, msg_count=2) for a in m: print(a.topic) print(a.payload) Pochopitelně nepotřebujeme přijímat všechny zprávy, ale pouze zprávy, které přijímat chceme. Následující kód se přihlásí k odběru topicu ''nsi/test'' a může přijímat zprávy, které do něj někdo pošle. Použijeme také asychronní zpracování dat pomocí callback funkce ''print_msg()'', která se zavolá v okamžiku, kdy se v topicu objeví zpráva: import paho.mqtt.subscribe as subscribe def print_msg(client, userdata, message): print("%s : %s" % (message.topic, message.payload)) subscribe.callback(print_msg, "nsi/test", hostname="mqtt.eclipseprojects.io") === MQTT publisher === Aby se v topicu objevila zpráva, je třeba ji tam publikovat. import paho.mqtt.publish as publish publish.single("nsi/test", "nazdar!", hostname="mqtt.eclipseprojects.io") ==== MQTT ve Flasku ==== import queue import json # import paho.mqtt.subscribe as subscribe from flask import Flask, Response, render_template from flask_mqtt import Mqtt q = queue.Queue() output = dict() app = Flask(__name__) app.config['MQTT_BROKER_URL'] = 'mqtt.eclipseprojects.io' app.config['MQTT_BROKER_PORT'] = 1883 mqtt = Mqtt(app) @mqtt.on_connect() def handle_connect(client, userdata, flags, rc): mqtt.subscribe('nsi/#') @mqtt.on_message() def handle_mqtt_message(client, userdata, message): data = dict( topic=message.topic, payload=message.payload.decode() ) print('topic:{}, payload: {}'.format(message.topic, message.payload.decode())) if __name__ == "__main__": app.run(host='0.0.0.0', port=5000, debug=True, use_reloader=True)