In de afleveringen tot nu toe heb ik verschillende open-source-bibliotheken gebruikt om twee MQTT-clients te programmeren: één voor de PC en één voor Android-smartphones. Vanuit een mobieltje kunnen we nu waar dan ook ter wereld besturingscommando’s verzenden, die via een openbare MQTT-broker naar een MQTT-client op de PC en daarna via USB worden doorgegeven naar een controllerkaart. Dat is al heel mooi, maar we hebben wel een draaiende PC nodig als relaisstation. En we hebben ons ook nog niet beziggehouden met de omgekeerde richting. Een klassieke IoT-toepassing is immers het verzenden van meetwaarden van een controllerkaart op het internet naar de gebruiker toe.

In de volgende delen moeten we dus een MQTT-client op een controllerkaart zien te maken, die berichten kan publiceren (publish) en zich kan abonneren (subscribe). U weet ongetwijfeld nog dat MQTT gebaseerd is op TCP /IP. Naast een netwerkaansluiting of WLAN-module op de kaart hebben we dus ook een goed geteste TCP /IP-library nodig. Er zijn bijvoorbeeld Arduino-kaarten met Ethernet-shield verkrijgbaar; en er is een MQTT-bibliotheek voor de Arduino-IDE, die al bijna als standaard-implementatie geldt. We hebben het hier over PubSubClient/.cpp/.h van Nick O‘Leary (http://pubsubclient.knolleary.net/index.html); de sourcecode is te downloaden bij GitHub.

We zouden een Uno met een Ethernet-shield kunnen kopen, alle benodigde bibliotheken in de Arduino-IDE integreren en proberen, één van de meegeleverde voorbeelden aan de praat te krijgen. Maar ik ga hier toch een andere kant op om MQTT beter te begrijpen. Dan krijgen we ook de gelegenheid om eigen MQTT-bibliotheken te programmeren, voor elke controllerkaart die we willen. Voor het gemak heb ik eerst maar eens gekeken, welke functies nodig zijn voor het publiceren van MQTT-berichten. Zo’n minimale bibliotheek zou immers al genoeg zijn om vanuit een sensorknooppunt meetwaarden over te dragen naar de cloud.

Als we de sourcecode van PubSubClient bestuderen, wordt al gauw duidelijk wat we nodig hebben:
  • Om te beginnen moet een functie in de TCP-library worden aangeroepen om ons programma als TCP-client te laten verbinden met een TCP-server (die kan bijvoorbeeld TCPClient_Connect heten). Als parameter krijgt die het IP-adres van onze openbare MQTT-server.
  • Daarna moet er een MQTT-connect-aanvraag naar de MQTT/TCP-server worden gestuurd en moeten we een bevestiging ontvangen. Dat kan in een functie die bijvoorbeeld MQTTClient_Connect heet. Daarbij wordt gebruik gemaakt van een functie TCPClient_Send die gewoon bytes via TCP kan verzenden en een antwoord van de server in de vorm van bytes kan ontvangen.
  • De functie MQTTClient_Publish zendt nuttige data (payload) naar de MQTT-server om ze op een bepaald topic te publiceren. Ook die functie maakt gebruik van TCPClient_Send om de bytes over te dragen. In het simpelste geval (Quality of Service = 0) komt er geen antwoord van de server terug.
  • Twee hulpfuncties (in de PubSubClient-library heten ze …_Write en …_WriteString) vergemakkelijken het samenvoegen van de bytes, die met TCP naar de server gestuurd moeten worden; de eerste keer voor de connect-aanvraag en de tweede keer voor het publish-bericht.
Zowel in de connect-aanvraag als in het publish-bericht zijn er verschillende optionele gedeelten. In de connect-aanvraag moeten we minimaal de client-ID mee geven en in het publish-bericht het topic en natuurlijk de nuttige data (die trouwens ook 0 bytes lang kan zijn). In de afbeelding is te zien, hoe de beide datavelden moeten worden gecodeerd. Zoals u ziet, is het samenvoegen van de bytes werkelijk niet zo moeilijk. Het is goed te zien dat dit een heel lichtgewicht protocol is. Toch heb ik nog een verdere vereenvoudiging doorgevoerd: beide berichten mogen hier maximaal 128 bytes lang zijn. Als het topic korter is dan 48 bytes en de nuttige lading minder dan 64 bytes blijft, dan past het in elk geval. En nog een vereenvoudiging: We kunnen na het verbinden met de MQTT-server maar een paar minuten lang berichten publiceren (we komen in één van de volgende delen nog terug op de Keep Alive Time). De volledige specificatie, bijvoorbeeld voor langere berichten, is te vinden onder http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html.

Ik heb met deze informatie een minimale bibliotheek geschreven op basis van de PubSubClient-library; voorlopig eerst maar eens voor de PC in C#, omdat we daar al een goede TCP -bibliotheek tot onze beschikking hebben en omdat het gemakkelijk is om de data weer te geven. Bij wijze van test heb ik nog een klein MQTT-client voor de PC geprogrammeerd die alleen maar berichten kan publiceren, maar niet meer die grote , NET -MQTT-bibliotheek M2Mqtt uit deel 4 nodig heeft. De sourcecode en de werkende toepassing kunt u downloaden onderaan deze pagina. We kunnen het geheel bijvoorbeeld testen met mijn grote MQTT-test-client uit deel 5. Voer daar in het tekstveld „Topic to subscribe“ gewoon een kort topic-keyword in, bijvoorbeeld: „min“. Als we op de button „Subscribe“ drukken, wordt het keyword zoals altijd aangevuld tot het topic „/ElektorIoTJourney/min/test“. Nu kunt u de minimale client gaan testen. Na het starten van het programma zie u meteen, welke bytes in de connect-aanvraag naar de openbare MQTT-server werden gestuurd (net als tot nu toe gebruiken we test.mosquitto.org). De client-ID is bijvoorbeeld „elektorIoT“. De server moet hebben geantwoord met de bytes „32 2 0 0“. U kunt het topic-keyword „min“ en tekst invoeren in de tekstvelden en het bericht publiceren met de button „Publish“.

Er is nog veel te doen; in het volgende deel gaan we verder. Intussen krijgen sommige lezers vast zin om hun eigen minimale client te schrijven voor het platform van hun voorkeur. We horen daar graag over. Gebruik de onderstaande commentaarfunctie!