Mijn pad naar het IoT (24): Dingen besturen van veraf met de ESP32 Pico Kit
11 april 2018
op
op
In het vorige deel hebben we met de ESP32 Pico Kit, een RGB-LED en een lichtgevoelige weerstand een klein apparaat gebouwd, dat periodiek helderheidswaarden meet en de resultaten naar het cloudplatform AllThingsTalk stuurt. Daar worden de sensorwaarden weergegeven op een webpagina die aan het apparaat (device) is toegewezen. De gebruiker kan die pagina zelf configureren en natuurlijk van overal op de wereld oproepen. En u herinnert zich vast nog wel, dat we gekeken hebben naar het wegvallen van de verbinding en het automatisch opnieuw inloggen in een WLAN en opnieuw verbinden met de AllThingsTalk-MQTT-broker.
In deel 18 hebben we een AllThingsMaker-device met de naam „MyJourneyIoT_Sensor“ aangesloten, met een asset die was gekoppeld met een sensor „temperature“. Later hebben we er nog een asset voor de sensor „light“ aan toegevoegd. Om het besturen vanuit de cloud te testen, heb ik aan hetzelfde device nog een asset „lamp“ toegevoegd, maar daarbij heb ik in plaats van „Sensor“ nu „Actuator“ aangeklikt. Voor het type heb ik „Number“ gekozen om numerieke waarden te kunnen verzenden (zie screenshot):
In het asset-overzicht staan nu drie items onder elkaar:
Als we op de drie punten rechts klikken opent er een menu en met de menukeuze „Send Command“ komen we in dan in een venster, waarin we de payload van het te verzenden MQTT-bericht rechtstreeks kunnen bewerken en verzenden. U herinnert zich misschien nog wel van de sensoren dat numerieke waarden in JSON-formaat werden weergegeven. Dat is nu ook het geval. Een commando om de waarde 15 naar de actuator te sturen is bijvoorbeeld:
Maar er is ook een comfortabeler manier om actuatoren te besturen. Via de keuze „Pinboards“ in het hoofdmenu kunnen we een eigen, op de toepassing toegesneden besturingsvenster maken. Dat doen we door een nieuw Pinboard aan te maken en dan op het potlood rechtsboven te klikken om het te bewerken. In de ontwerpweergave kunnen we dan met het schakelvlakje „New pin“ nieuwe besturingselementen aanmaken, die we kunnen toewijzen aan sensoren, maar ook aan actuatoren. In het screenshot is te zien hoe ik dat heb gedaan voor mijn actuator „lamp“:
In het volgende venster heb ik ingesteld dat de lamp moet worden bediend met een Slider (schuifregelaar). Het complete Pinboard ziet er dan als volgt uit:
Als we nu de schuifregelaar verschuiven, wordt een commando met een nieuwe waarde verzonden via MQTT.
Om te beginnen heb ik mijn functie ConnectToATT() uitgebreid met het volgende codefragment, dat ik natuurlijk heb gepikt uit de sketch van een eerdere aflevering en vervolgens heb aangepast:
In deze functie maakt de ESP32 als MQTT-client niet meer alleen verbinding met de broker, maar hij abonneert zich ook op de berichten uit de cloud voor het aansturen van de lamp. In de eerste regels ziet u, hoe het topic moet worden samengesteld.
In de hoofdlus van het programma moeten we nu natuurlijk regelmatig checken, of er berichten zijn ontvangen. Deze berichten krijgt de ESP32 als MQTT-client (en TCP-client) van de MQTT-broker (die werkt als TCP-server) via de openstaande MQTT/TCP-verbinding.
In eerste instantie had ik niet voor de juiste aanpak gekozen. Met
liet ik het programma regelmatig kijken, of er een MQTT-bericht was binnengekomen; in dat geval wordt de variabele PayloadCountReceivedMessage groter dan 0 en komt de nuttige lading van het bericht in het array attMQTTClient.Payloadbuffer te staan. (Zo heb ik dat geïmplementeerd in mijn MQTTClient-library.) Maar het bleek al snel dat die .Get-functie erg belemmerend werkte. Deze functie van de MQTTClient-library maakte namelijk gebruik van de .Receive-functie van de TCPClient-library. En bij die laatste was een time-out van 1 seconde ingesteld, als er geen tekens zouden binnenkomen. Dat was praktisch om bijvoorbeeld te wachten op een antwoord van een webserver. In zo’n geval weten we zeker, dat er tekens aankomen. Maar als we alleen maar willen checken, of iets te halen is, moeten we anders te werk gaan.
Daarom heb ik de TCPClient-library uitgebreid met een functie .ReceiveIfAvailable(…), die gebruik maakt van de functie .Available() van de Arduino-ESP32-WifiClient-library. Die geeft als retourwaarde hoeveel tekens er via TCP/IP zijn binnengekomen. Als er niets gekomen is, wordt .ReceiveIfAvailable heel snel beëindigd. Nu moest ik alleen nog mijn MQTT-library aanpassen, zodat de .Get-functie gebruik zou maken van deze nieuwe functie. Eerlijk gezegd is ook dit pollen nog niet erg efficiënt, maar ik heb uit gebrek aan tijd de verdere optimalisatie uitgesteld tot een latere aflevering van deze serie.
Dat zag er veelbelovend uit: de eigenlijke waarde van de slider kon ik vinden tussen de tekens „:“ en „}“. In de download onderaan deze pagina vindt u de complete sketch met een kleine demo: Met de schuifregelaar kunt u de blauw-waarde van de dimmende RGB-LED op afstand bedienen. Natuurlijk bevat het download-archief ook de veranderde bibliotheken, die zoals altijd in de map „libraries“ van de Arduino-IDE moeten worden geplaatst.
Ik heb geconstateerd, dat er bijna altijd MQTT-commando’s binnenkomen, als ik de slider beweeg; maar 100 % betrouwbaar is het geheel nog niet. In een werkelijke besturing in de praktijk zouden we dus absoluut ook nog een terugmelding moeten inbouwen, om te zien of de lamp ook werkelijk op de gewenste helderheid is ingesteld.
Commando’s versturen met AllThingsTalk
Maar met dit cloudplatform kunnen we ook vanaf een webpagina commando’s naar een apparaat sturen, alweer via MQTT. Zo kunnen we LED’s, motoren en allerlei andere actuatoren besturen.In deel 18 hebben we een AllThingsMaker-device met de naam „MyJourneyIoT_Sensor“ aangesloten, met een asset die was gekoppeld met een sensor „temperature“. Later hebben we er nog een asset voor de sensor „light“ aan toegevoegd. Om het besturen vanuit de cloud te testen, heb ik aan hetzelfde device nog een asset „lamp“ toegevoegd, maar daarbij heb ik in plaats van „Sensor“ nu „Actuator“ aangeklikt. Voor het type heb ik „Number“ gekozen om numerieke waarden te kunnen verzenden (zie screenshot):
In het asset-overzicht staan nu drie items onder elkaar:
Als we op de drie punten rechts klikken opent er een menu en met de menukeuze „Send Command“ komen we in dan in een venster, waarin we de payload van het te verzenden MQTT-bericht rechtstreeks kunnen bewerken en verzenden. U herinnert zich misschien nog wel van de sensoren dat numerieke waarden in JSON-formaat werden weergegeven. Dat is nu ook het geval. Een commando om de waarde 15 naar de actuator te sturen is bijvoorbeeld:
{
"value": 15
}
"value": 15
}
Maar er is ook een comfortabeler manier om actuatoren te besturen. Via de keuze „Pinboards“ in het hoofdmenu kunnen we een eigen, op de toepassing toegesneden besturingsvenster maken. Dat doen we door een nieuw Pinboard aan te maken en dan op het potlood rechtsboven te klikken om het te bewerken. In de ontwerpweergave kunnen we dan met het schakelvlakje „New pin“ nieuwe besturingselementen aanmaken, die we kunnen toewijzen aan sensoren, maar ook aan actuatoren. In het screenshot is te zien hoe ik dat heb gedaan voor mijn actuator „lamp“:
In het volgende venster heb ik ingesteld dat de lamp moet worden bediend met een Slider (schuifregelaar). Het complete Pinboard ziet er dan als volgt uit:
Als we nu de schuifregelaar verschuiven, wordt een commando met een nieuwe waarde verzonden via MQTT.
Wachten op het MQTT-bericht?
Nu moest ik mijn ESP32 nog zover zien te krijgen, dat hij ging luisteren naar binnenkomende berichten. Ik heb de sketch uit de vorige aflevering gebruikt als basis. U kunt die hier downloaden en vergelijken met nieuwe sketch die onderaan deze pagina te downloaden is.Om te beginnen heb ik mijn functie ConnectToATT() uitgebreid met het volgende codefragment, dat ik natuurlijk heb gepikt uit de sketch van een eerdere aflevering en vervolgens heb aangepast:
String ActuatorName = "lamp";
String ATT_ActuatorTopic = "device/" + strDeviceID + "/asset/" + ActuatorName + "/command";
int MQTT_Subscribe_Result = attMQTTClient.Subscribe(ATT_ActuatorTopic); // Attempt to subscribe to topic
if (MQTT_Subscribe_Result == 1) // successful
{
BreadboardRGBLED.SwitchRGBLED(LED_GREEN);
NodeState = NODESTATE_OK;
Serial.println("MQTT subscribed.");
}
else
{
BreadboardRGBLED.SwitchRGBLED(LED_RED);
BreadboardRGBLED.setRGB(255, 0, 0); // set the default color to red for dimming
NodeState = NODESTATE_NOMQTTSUBSCRIPTION;
Serial.println("MQTT not subscribed.");
}
String ATT_ActuatorTopic = "device/" + strDeviceID + "/asset/" + ActuatorName + "/command";
int MQTT_Subscribe_Result = attMQTTClient.Subscribe(ATT_ActuatorTopic); // Attempt to subscribe to topic
if (MQTT_Subscribe_Result == 1) // successful
{
BreadboardRGBLED.SwitchRGBLED(LED_GREEN);
NodeState = NODESTATE_OK;
Serial.println("MQTT subscribed.");
}
else
{
BreadboardRGBLED.SwitchRGBLED(LED_RED);
BreadboardRGBLED.setRGB(255, 0, 0); // set the default color to red for dimming
NodeState = NODESTATE_NOMQTTSUBSCRIPTION;
Serial.println("MQTT not subscribed.");
}
In deze functie maakt de ESP32 als MQTT-client niet meer alleen verbinding met de broker, maar hij abonneert zich ook op de berichten uit de cloud voor het aansturen van de lamp. In de eerste regels ziet u, hoe het topic moet worden samengesteld.
In de hoofdlus van het programma moeten we nu natuurlijk regelmatig checken, of er berichten zijn ontvangen. Deze berichten krijgt de ESP32 als MQTT-client (en TCP-client) van de MQTT-broker (die werkt als TCP-server) via de openstaande MQTT/TCP-verbinding.
In eerste instantie had ik niet voor de juiste aanpak gekozen. Met
byte PayloadCountReceivedMessage = attMQTTClient.Get(attMQTTClient.PayloadBuffer);
liet ik het programma regelmatig kijken, of er een MQTT-bericht was binnengekomen; in dat geval wordt de variabele PayloadCountReceivedMessage groter dan 0 en komt de nuttige lading van het bericht in het array attMQTTClient.Payloadbuffer te staan. (Zo heb ik dat geïmplementeerd in mijn MQTTClient-library.) Maar het bleek al snel dat die .Get-functie erg belemmerend werkte. Deze functie van de MQTTClient-library maakte namelijk gebruik van de .Receive-functie van de TCPClient-library. En bij die laatste was een time-out van 1 seconde ingesteld, als er geen tekens zouden binnenkomen. Dat was praktisch om bijvoorbeeld te wachten op een antwoord van een webserver. In zo’n geval weten we zeker, dat er tekens aankomen. Maar als we alleen maar willen checken, of iets te halen is, moeten we anders te werk gaan.
Daarom heb ik de TCPClient-library uitgebreid met een functie .ReceiveIfAvailable(…), die gebruik maakt van de functie .Available() van de Arduino-ESP32-WifiClient-library. Die geeft als retourwaarde hoeveel tekens er via TCP/IP zijn binnengekomen. Als er niets gekomen is, wordt .ReceiveIfAvailable heel snel beëindigd. Nu moest ik alleen nog mijn MQTT-library aanpassen, zodat de .Get-functie gebruik zou maken van deze nieuwe functie. Eerlijk gezegd is ook dit pollen nog niet erg efficiënt, maar ik heb uit gebrek aan tijd de verdere optimalisatie uitgesteld tot een latere aflevering van deze serie.
De ESP32 ontvangt commando’s
Nu kon de ESP32 MQTT-berichten ontvangen. Om te beginnen liet ik alleen maar via de seriële poort weergeven, welke nuttige lading er bij de ESP32 aankwam, als ik de slider op het Pinboard verschoof. Er kwamen telkens tekenreeksen binnen, zoals bijvoorbeeld de volgende:{"at":"2018-04-09 …… ","value":46}
Dat zag er veelbelovend uit: de eigenlijke waarde van de slider kon ik vinden tussen de tekens „:“ en „}“. In de download onderaan deze pagina vindt u de complete sketch met een kleine demo: Met de schuifregelaar kunt u de blauw-waarde van de dimmende RGB-LED op afstand bedienen. Natuurlijk bevat het download-archief ook de veranderde bibliotheken, die zoals altijd in de map „libraries“ van de Arduino-IDE moeten worden geplaatst.
Ik heb geconstateerd, dat er bijna altijd MQTT-commando’s binnenkomen, als ik de slider beweeg; maar 100 % betrouwbaar is het geheel nog niet. In een werkelijke besturing in de praktijk zouden we dus absoluut ook nog een terugmelding moeten inbouwen, om te zien of de lamp ook werkelijk op de gewenste helderheid is ingesteld.
Read full article
Hide full article
Discussie (0 opmerking(en))