Mosquitto – MQTT message broker

Mosquitto – MQTT message broker

Co je Mosquitto? Je to MQTT message broker. To znamená, že umožňuje komunikaci mezi hromadou zařízení pomocí MQTT protokolu. Zařízení může být v jednom ze dvou režimů. To první je Publisher, to druhe Subscriber. Publisher data generuje a sype do nějaké fronty, Subscriber (odběratel) je pak načítá. Odběratelů může být neomezeně, stejně tak Publisherů (vydavatelů?).

Celé se to dá krásně využít k tomu, že všechny IoT čidla postavené na Arduinu generují data a jednotně je sypo do MQTT. Z MQTT se to pak jednotně načítá, ať už napřímo přes Loxone, nebo třeba do NodeRED, kde se nastaví co se s datama má dít a až pak se data pošlu dál.

Díky tomu se do čidel nemusí dávat žádná složitá logika na publikování dat, posílání jích do Loxone atd. Ale jen se to nasype do MQTT brokera a další logika se postaví až o stupeň dál.

Instalace Mosquitto serveru.

Já jsem využil toho, že mi doma běží server na pracovní věci, a tak jsem si udělal novou virtualizovanou instanci Ubuntu ;-). Ale jinak se dá mosquitto rozběhat i na Windows, Raspberry, Turrisu a dalších.

2016-12-04_12-54-58

Instalace byla v mém pomocí apt-get. Kromě balíku mosquitto sem bral i mosquitto-clients, které přidají příkazy na simulaci subscribera/publishera, takže lze otestovat, že vše běží jak má. Po nainstalování jsem pak pro účely ladění zapl komplet logování, které v ostrém provozu později vypnu.

sudo apt-get install mosquitto mosquitto-clients
sudo /etc/init.d/mosquitto stop
sudo nano /etc/mosquitto/mosquitto.conf
sudo /etc/init.d/mosquitto start

Do konfigurační soubor mosquitta jsem přidal:

2016-12-04_13-14-27

log_type error
log_type warning
log_type notice
log_type information
connection_messages true
log_timestamp true

A nahodil jsem zpět mosquitto. Pro otestování, že vše funuje jak má, jsou právě ty mosquitto-clients.

2016-12-04_16-06-53

Pro otestování subscribera je příkaz mosquitto_sub. Parametr -d zapíná debug zprávy, -t nastavuje název kanálu, nad kterým subscriber poslouchá.

mosquitto_sub -d -t hello/world

2016-12-04_13-09-54

Když máme posluchače, je potřeba vygenerovat nějakou zprávu. To se dělá pomocí publishera mosquitto_pub. Parametry opět stejné, akorat místo naslouchání na -t se do kanálu -t data pošlou, -m pak definuje zprávu na poslání.

mosquitto_pub -d -t hello/world -m "test"

2016-12-04_13-10-02

Jakmile vygenerujete publisherem zprávu, na subscriberovi se zobrazí

Client mosqsub/7136-home-serve received PUBLISH (d0, q0, r0, m0, 'hello/world', ... (4 bytes))
test

To znamená, že nám MQTT broker funguje jak má. Pokud by něco zlobilo, logy jsou dostupně v souboru  /var/log/mosquitto/mosquitto.log

Komunikace s Mosquitto serverem z Arduina

A teď ta druhá část, poslání/naslouchání MQTT s Arduina. Zkusíme poslat zprávu, kterou necháme zobrazit pomocí již nahozeného subscribera v konzoli a pak přijímat zprávy a při přijmutí bliknout diodou.

2016-12-04_13-54-39

Krok první, nainstalujeme si nějakou předpřipravenou MQTT knihovnu do Arduina. V menu VMICRO -> Visual Micro Explorer -> Manage Libraries.

2016-12-04_13-55-55

Zkusil jsem PubSubClient, tvrdí že je lightweight a takové mám rád ;-).

2016-12-04_13-56-32

Jako další krok vložíme knihovnu do projektu. Pokud člověk ví co dělá, stačí obyčejný #include<PubSubClient.h>, pokud ne, může si to vybrat takto z wizarda. Napoprvé je to fajn, že není potřeba lovit, jak se soubor přesně jmenuje.

2016-12-04_13-58-20

Zkusíme zkompilovat a zdá se, že je vše ok. Tak pojďme poslat nějaká data. Výhoda Arduina je, že celý ekosystém už je opravdu pěkně rozrostlý a na všechno existují připravené knihovny.

Na druhou stranu nevýhoda Arduina je, že celý ekosystém dělají lidé, co jsou zřejme opravdu borci na elektrotechniku, ale dost slabí na programování. Takže ačkoli je Arduino postavené nad c++,  jeho knihovny, ukázky a vše ostatní vypadá jako programy psané v čistém C kódu kdysi v minulém století.

Naštěstí to není až takový problém a všechno jde postupně zabalit do vlastních objektů a udělat si nad tím čistý kód.

Inicializace Wifi, Debugu, Mqtt a Diody

Aby měl návod trochu spád, spojím všechny tyto věci dohromady. Jak už jsem psal, kód pro Arduino je bohužel takový c-like spaghetti bastl. Ačkoli využívá objektový zápis, tak instance objektů existují kdesi globálně a jen se používají. To je supr pro nováčky, co netuší která bije, ale pro pokročilé vyvíjení je to imho škoda, protože to maskuje hromadu věcí a cokoli globálního je prostě blbě.

#include &lt;ESP8266WiFi.h&gt;
#include &lt;WiFiClient.h&gt;
#include &lt;PubSubClient.h&gt;
const char* ssid = "wifi";
const char* password = "password";
const char* mqtt_server = "192.168.0.102";
WiFiClient espClient;
PubSubClient mqttClient(espClient);
void setupDebug()
{
Serial.begin(9600);
Serial.println("WeMos MQTT test");
Serial.println("");
}
void setupWifi()
{
// Connect to your WiFi network
WiFi.begin(ssid, password);
Serial.print("Connecting");
// Wait for successful connection
while ( WiFi.status() != WL_CONNECTED )
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to: ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
Serial.println("");
}
void setupMqtt()
{
mqttClient.setServer(mqtt_server, 1883);
mqttClient.setCallback(MQTT_callback);
}
void setupDiode()
{
pinMode(LED_BUILTIN, OUTPUT);     // Initialize the LED_BUILTIN pin as an output 
}
void Blink(int nDelayOn, int nDelayOff)
{
digitalWrite(LED_BUILTIN, HIGH);  // Turn the LED off by making the voltage HIGH
delay(nDelayOn);                      // Wait for two seconds (to demonstrate the active low LED)
digitalWrite(LED_BUILTIN, LOW);   // Turn the LED on (Note that LOW is the voltage level  
delay(nDelayOff);                      // Wait for two seconds (to demonstrate the active low LED)
}
void setup() 
{ 
setupDebug(); 
setupWifi(); 
setupMqtt(); 
setupDiode(); 
}

Takhle nějak vypadá inicializace pro WeMos D1.

  • hromada “println” posílá po seriovém portu zpět do IDE stavy a zprávy
  • setupDebug inicializuje seriovou linku právě pro tyto přenosy.
  • setupWifi připojí wifi adaptér k zadané síti a vypíše kam se připojila.
  • setupMqtt nastaví parametry připojení pro MQTT clienta
  • setupDiode jakýmsi způsobem propojuje PIN LED_BUILTIN na OUTPUT diodu, toto zatím beru jako fakt a moc to nechápu
  • Blink slouží k bliknutí diody
  • A setup spustí všechny výše uvedené nastavení.

Spoustu nastavení, ale jinak nic objevného. Toto nastavení použijeme jak pro zapisování dat do MQTT, tak pro čtení.

Komunikace s MQTT brokerem

Po tom, co máme vše inicializováno, zbývá se jen připojit k MQTT brokerovi a posílat a přijímat data. Připojení se provede pomocí

if ( mqttClient.connected() == false )
mqttClient.connect("ESP8266Client");

kdy řetězec “ESP8266Client” je pro mne velkou záhadou, ale mám to z examplu. Moc nerozumím tomu, proč je to jako string “ESP8266Client” místo objektu WiFi nebo espClient, ale je to jen další z divných věcí v Arduinu, která má zřejmě sloužit dobru, ale imho jen škodí.

Odeslání dat se provádí pomocí metody publish, která má jako první parametr název kanálu, jako druhý parametr data k odeslání.

mqttClient.publish("hello/world", "hello world");

Příjem dat se provádí pomocí zaregistrování callbacku metodou setCallback a pak přihlášení ke konkrétnímu kanálu metodou subscribe. Tady by mi přišlo logičtější mít co kanál možnost jiný callback, ale opět asi zjednodušení.

void MQTT_callback(char* topic, byte* payload, unsigned int length) {}
mqttClient.setCallback(MQTT_callback);
mqttClient.subscribe("hello/world/2");
&amp;amp;nbsp;

Celý kód pak vypadá třeba takto. V MQTT_callback se zobrazí obdržená data a blikneme diodou. V metodě reconnect se provádí testování platného připojení a jeho případně znovupřipojení, v metodě loop pak dokola testujeme platnost připojení, voláme interní loop MQTT clienta (kvůli přijmu dat) a každé 2sec posíláme zprávy do MQTT brokera “Hello world” spolu s pořadovým číslem zprávy.

void MQTT_callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for ( int i = 0; i &amp;lt; length; i++ )
{
Serial.print((char)payload[i]);
}
Serial.println();
Blink(100, 100);
}
void MQTT_reconnect() 
{
// Loop until we're reconnected
while ( !mqttClient.connected() )
{
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if ( mqttClient.connect("ESP8266Client") )
{
Serial.println("connected");
// Once connected, publish an announcement...
mqttClient.publish("hello/world", "hello world");
// ... and resubscribe
mqttClient.subscribe("hello/world/2");
}
else
{
Serial.print("failed, rc=");
Serial.print(mqttClient.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void loop()
{
if ( !mqttClient.connected() )
MQTT_reconnect();
mqttClient.loop();
static long lastTime = 0;
static int lastValue = 0;
if ( millis() - lastTime &amp;amp;gt; 2000 )
{
char msg[50];
snprintf(msg, 75, "hello world #%ld", lastValue++);
Serial.print("Publish message: ");
Serial.println(msg);
mqttClient.publish("hello/world", msg);
lastTime = millis();
}
}

Na celém kódu není nic složitého a díky předpřipravenému MQTT clientu a hotovým ukázkám jde kód narychlo polepit dohromady.

Co je nevýhoda, tak kód je prostě ošklivý a nepřehledý. Na vlastní finální řešení to bude chtít obalit vše svými objekty, ideálně napsat i nějaké mock objekty kvůli testování a celkově nad tím udělat robustnější testování, aby člověk neprogramoval stylem zkompilovat-nahrát-zkusit-znovu. Takhle se programovalo v dobách Atari, ale ne dneska.

A to je vše, máme funční Arduino MQTT publisher i subscriber. Příště až bude čas, tak zkusím rozchodit onen Node-Red. A až dorazí věci z Aliny, tak na Wemos napom čidla a zkusim posílat nějaká smysluplnější data.

Ostatní linky

forumlink
Link na diskuzní fórum o Arduino vývoji

Pomohl Vám náš blog? Chcete nás podpořit? I málo udělá radost 😉

6 thoughts on “Mosquitto – MQTT message broker

  1. Mne na celom esp8266 pride blba jedna zasadna vec – spotreba. Na baterky to nevydrzi ani prd, takze k tomu clovek musi tahat utp-cko na napajanie. No a ked uz tam taham utp-cko, naco si to komplikovat s ssid a heslom a wifi a neviemeste cim?

    1. Ta spotreba by mela byt prave velmi dobra. Navic wemos podporuje deep-sleep, kdy se zarizeni totalne uspi a jen jednou za cas se necha probudit, sejmout data a zase usnout.

      V aktivnim modu 70mA
      V hlubokym spanku 2mA
      Pri Wifi udajne az 170mA, ale je to narazovka

      https://forum.wemos.cc/topic/211/power-consumption-of-wemos-d1-mini-in-deep-sleep

      Ono je to spis dobre k tomu, kdyz nekde neni Ethernet, ale je tam obyc zasuvka. Pak se tim daji dotlacit data i bez infrastruktury. A nebo to pak pouzit venku a dat k tomu ten mrnavej solarni panel

  2. “Na druhou stranu nevýhoda Arduina je, že celý ekosystém dělají lidé, co jsou zřejme opravdu borci na elektrotechniku, ale dost slabí na programování. Takže ačkoli je Arduino postavené nad c++, jeho knihovny, ukázky a vše ostatní vypadá jako programy psané v čistém C kódu kdysi v minulém století.”

    Zkuste se zamyslet nad tím co píšete, možná není kód skvěle objektový a krásný, ale je, a to současní programátoři opomíjejí, rychlý. A to je to nejdůležitější při programování HW. A buďte rád že nemáte k dispozici jen 256B RAM a 4kB EEPROM, to byste asi nic nenapsal.
    To jen tak na okraj, jinak bych článek hodnotil **** z pěti 🙂

    1. Vidite, zamyslel jsem se a i po tech dvou letech na tom stale trvam. Ti co to pisou jsou HW borci ale SW prumerni vvojari.

      Ono totiz nejde jen o to napsat kod, co ma co nejmensi velikost, nebo nejrychlejsi exekuci. Ale hlavne napsat kod, ve kterem se vyznaji i dalsi lide a budou ho dale udrzovat. Jenze, to proste arduino nema. Nejde o objekty, jde o srozumitelne pojmenovavani, spravne navrzene struktury, komentare, …. zkratka citelnost kodu.

      V cecku se da psat efektivne a rychle a zaroven tvorit vizualne krasny kod, se kterym je radost pracovat a i ostatni ho pak chapu. Bohuzel se ale v cecku da napsat i takova prasarna, ktere rozumi jen sam autor, vypada to desne slozite a sofistikovane a pritom to neni nic jineho nez prasarna.

      Nevim, jake mate zkusenosti s vyvojem vy, ale ja se vyvojem zivim uz docela dlouho a mam za sebou opravdu dost projektu. A to jak samostatnych, tak tymovych. A to, co vidim v arduino kodech je proste prasarna, kterou bych u svych kolegu/zamestnancu proste netrpel. V kodu je potreba se vyznat i po 10ti letech i kdyz clovek opusti firmu, nebo se vratite k nejakemu historickemu projektu. A to umoznuje prave ta kultura kodu.

      A to nemluvim o nejake dokumentaci, unit testech,… O tom si arduino muze take nechat zdat.

Leave a Reply

Your email address will not be published. Required fields are marked *