In de vorige delen hebben we met de ESP32 Pico-kit en een paar onderdelen een IoT-apparaat gebouwd dat sensorwaarden naar de cloud stuurt en ook vanuit de cloud te besturen is. Als cloud-platform hebben we de maker-versie van AllThingsTalk gebruikt. Na een eenvoudige registratie staan daar meerdere webpagina's, die de gebruiker zelf kan configureren ter beschikking. Daar kunnen we sensorwaarden weergeven in diagrammen, maar ook kleine besturingsvensters bouwen.

Amazon Web Services

Maar natuurlijk zijn er nog veel meer cloud-platforms. Veel van de IoT-oplossingen die bijvoorbeeld op beurzen zoals Embedded World te zien zijn, werken met Amazon Web Services (AWS). Dit platform is erg krachtig, robuust en veilig en is daarom al tot een soort „industriestandaard“ geworden. Bekende diensten zoals bijvoorbeeld Dropbox werken hiermee. Speciaal voor het Internet of Things heeft Amazon „AWS IoT Core“ ontwikkeld. Bedrijven en privé-gebruikers kunnen daar in theorie miljoenen sensorkaarten registreren en de gegevens verzamelen in een databank, big-data-analyses uitvoeren, bedrijfsprocessen als regels invoeren in het systeem en nog veel meer. Er wordt afgerekend op verbindingsduur in miljoen minuten en per miljoen berichten. Wie dat eens, net als ik, een keer wil uitproberen, kan voor 12 maanden een gratis budget van 500.000 berichten krijgen.

Eerst even dit: aan de slag gaan met AWS en het programmeren van een sensorkaart is geen kleinigheid, daar komt behoorlijk wat bij kijken. Het begint al bij het aanmaken van een AWS-account. We moeten ons niet alleen registreren met email-adres en wachtwoord, we moeten ook een postadres, een creditcardnummer voor het afrekenen en een telefoonnummer opgeven. En dat laatste wordt zelfs geverifieerd: u wordt opgebeld door een robot en dan moet u op de telefoon een viercijferige code invoeren, die op het scherm van de PC wordt weergegeven. In het telefoonnummerveld moeten we het telefoonnummer trouwens volledig invullen (met landnummer en zonder spaties), anders komt er geen telefoontje.

Daarna kunt u het best het tutorial First steps with AWS IoT volgen (een Nederlandse versie is er helaas niet). Het kost wat moeite om vertrouwd te raken met de „AWS-taal“. En dat wordt er niet beter op, als Engelse begrippen soms wel en soms niet worden vertaald (en in het Duitse tutorial staan screenshots met Engelse menukeuzes). Hier twee tips: met Registry wordt de enorme AWS-databank bedoeld, waarin we onze apparaten invullen. Een Device (apparaat) en een Thing (object) zijn bij benadering hetzelfde (om precies te zijn: een Thing is een virtueel apparaat, dat in de cloud een echt apparaat vertegenwoordigt).

Veiligheid voor alles

Er is veel knowhow gestoken in het thema veiligheid. Alle boards, smartphones en computers in de hele wereld communiceren met AWS namelijk altijd versleuteld, en wel via het protocol Transport Layer Security (TLS), dat gebaseerd is TCP/IP. Ik citeer hier kort uit de Duitse Wikipedia, want daar wordt de werking heel goed samengevat:

De client bouwt een verbinding op met de server. De server authentiseert zich tegenover de client met een certificaat. De client controleert of het een echt X.509-certificaat is en of de servernaam overeenkomt met het certificaat. Optioneel kan de client zich ook authentiseren tegenover de server met een eigen certificaat. Dan stuurt ofwel de client een met de openbare sleutel van de server versleuteld geheim toevalsgetal naar de server, of beide partijen berekenen met behulp van een Diffie-Hellman-sleuteluitwisseling een gezamenlijk geheim getal. Uit dit geheime getal wordt dan een cryptografische sleutel afgeleid. Deze sleutel wordt vervolgens gebruikt om alle berichten op de verbinding met een symmetrisch versleutelingsmechanisme te versleutelen en voor de bescherming van de integriteit en authenticiteit berichten door middel van een bericht-authenticatiecode.

Voor het communiceren van een board met AWS via met TLS -beschermd TCP /IP hebben we drie cryptische tekenreeksen nodig; die we later in de firmware zullen moeten inbouwen:
  1. Certificate (certificaat)
  2. Private Key (privésleutel)
  3. Root Certificate
Voor TLS -communicatie is nog een vierde tekenreeks nodig, de Public Key, maar die hoeft de kaart niet te kennen. Het certificaat en de Private Key worden door AWS individueel gegenereerd als we een apparaat registreren op de manier die in het tutorial is beschreven. Daarbij ontstaan twee bestanden met tekenreeksen, die we moeten downloaden. Ze zijn met een editor zoals Notepad++ te openen. Maar dan zijn we nog niet klaar. Er moeten ook nog Policies (richtlijnen) worden vastgelegd voor het apparaat. In feite zijn dat regels, die aangeven wat het apparaat in de cloud mag doen. Hier komt MQTT weer in het spel. Net als bij AllThingsTalk zal ons apparaat namelijk later als MQTT-client verbinding maken met een MQTT-broker van AWS. Om meetgegevens naar de cloud te zenden, moeten we zoals altijd de MQTT-commando’s CONNECT en PUBLISH gebruiken. We moeten het apparaat dus toestaan, om verbinding te maken met de broker en berichten te publiceren op een bepaald topic. Het is het beste om hier het tutorial stap voor stap te volgen. Dat stelt voor om in het veld van het toegestane topic bijvoorbeeld
arn:aws:iot:us-east-1:123456789012:topic/my/topic/here

in te vullen. In plaats van „my/topic/here“ moet u dan het topic „$aws/things/<DEVICENAME>/shadow/update“ gebruiken. Al met al moet in het veld worden ingevoerd:
 
arn:aws:iot:<REGION>:<ACCOUNTID>:topic/$aws/things/<DEVICENAME>/shadow/update

Het Account-ID vindt u, als u in het AWS IoT management Console rechtsboven klikt op de gebruikersnaam en kiest voor „My account“. Via deze webpagina regelt u alles, wat met uw eigen AWS-account te maken heeft. Nadat ik alle stappen van het tutorial had doorlopen, zag het Management Console er bij mij uit zoals in dit screenshot.



U ziet dat ik mijn eerste AWS-device „MyJourneyIoTDevice“ heb genoemd. Verder ziet u dat de bediening in het Duits werkte (mijn excuses aan de internationale lezers dat ik geen Engelse screenshots kan tonen). En ten derde ziet u, dat ik was vergeten om Region van „Ohio“ te veranderen in „EU (Frankfurt)“. Daardoor staat bij mij onder <REGION> = „us-east-2“.

ESP32 leert TLS

Oeffff, dat was alvast de helft van het werk. Nu moest ik mijn kaart nog leren om met AWS te communiceren. Ik heb veel moeten googelen en uitproberen, voordat ik mijn TCP/IP-library zó kon ombouwen, dat hij in plaats van „normaal“ TCP/IP kon werken met het veilige TLS via TCP/IP. Misschien, herinnert u zich nog, dat mijn TCP-library vooral een wrapper is rondom de functies van de Arduino-klasse WiFiClient, die de ontwikkelaar van Espressif voor de ESP32 heeft geïmplementeerd. En dat niet alleen: er is ook een klasse WiFiClientSecure, die bedoeld is voor TLS-beschermde TCP/IP-bewerkingen. Om snel klaar te zijn, heb ik gewoon mijn TCP/IP-library gedupliceerd, en aan de bestands- en klassenamen het achtervoegsel „Secure“ toegevoegd. De eigenlijke veranderingen in de code van de nieuwe TCPClientSecure zijn, in vergelijking met de TCPClient-library, minimaal (zie screenshot).



In de constructor van het object krijgt de compiler de genoemde drie tekenreeksen voor de TLS-communicatie aangereikt. Die kunnen we hardgecodeerd opslaan in het programma, waarbij steeds pakketten van 64 tekens van elkaar worden gescheiden met een \n. Het root-certificaat kan ik u hier trouwens gerust laten zien, dat is sowieso altijd hetzelfde. Voor de beide andere tekenreeksen heb ik een eigen bestand met de naam AWS_Certificate.h gemaakt, dat met een include-statement in TCPClientSecure.cpp wordt ingebouwd. U vindt een template voor dit bestand in de download, maar daar moet u natuurlijk nog wel uw certificaat en uw sleutel invullen.

Omdat de MQTT-library een object van het type TCPClient verwacht, maar ik nu het type TCPClientSecure nodig heb, heb ik ook de MQTT-library nog verdubbeld en hier eveneens overal „Secure“ aan de bestands- en klassenamen toegevoegd. Er zijn nu een TCP/IP- en een MQTT-library voor de normale en voor de TLS-communicatie.

Schaduw- update

Ik heb de hardware en het hoofdprogramma uit deel 23 als basis voor een kleine demo gebruikt. Download de code en vergelijk die met de nieuwe sketch, die u onderaan deze pagina kunt downloaden. Als parameters hebben we natuurlijk weer de SSID en het wachtwoord van onze router nodig. Er is ook een Device ID (net als bij AllThingsTalk), in mijn geval heet het „MyJourneyIoTDevice“. Een Device Token is er nu niet meer, omdat de authenticatie door de certificaten wordt geregeld. Maar wel is het adres van de MQTT-broker bij AWS individueel. Daarom heb ik de configuratie-webpagina zó aangepast, dat in het vijfde tekstveld het broker-adres kan worden ingevoerd. U vindt het serveradres van uw broker door in het Management Console op het device te klikken en dan in het device-menu op „Interact“ te drukken. Het serveradres vindt u helemaal bovenaan. In het volgende grijze veld ziet u het topic om meetwaarden naar een schaduw-device te zenden. Bij mij is dat
 
$aws/things/MyJourneyIoTDevice/shadow/update

(Zie screenshot).



Wat is een schaduw-object nu weer? Dat is niets anders dan een weergave van de toestanden van een IoT-node (sensor of actuator), in de vorm van een JSON-document. Ook voor het overzenden van meetwaarden naar AllThingsTalk hebben we de JSON-notatie gebruikt. Bij AWS ziet een geldig JSON-document er bijvoorbeeld zó uit:
{
  "desired": {
    "temp": "32"
  }
}

Dit document heb ik op de device-webpagina onder de menukeuze „Schatten“ ingevoerd in de JSON-editor (zie screenshot) om vast te leggen, welke waarden mijn sensorkaart kan verzenden.



Voor de eerste pogingen heb ik me ertoe beperkt om periodiek een van 10 naar 40 omhoog tellende „temperatuurwaarde“ naar AWS over te dragen (zie het commentaar in de sketch). Als beloning voor al mijn inspanningen kon ik me na elke keer dat er een MQTT-bericht was verzonden verheugen op een refresh van de schaduw-weergave (met een nieuwe temperatuurwaarde). Overigens heb ik bij urenlang gebruik geen enkele verbreking van de verbinding gezien.

In het volgende deel gaan we weer verder!