Een beschrijving van een domotica project dat draait op een Raspberry Pi 3, is geschreven in Kotlin, op afstand bediend kan worden met een iPhone, communiceert met onder andere klikaanklikuit via een RFXCOM en wordt gebouwd en gedeployed in een CI/CD straat die draait in Docker op een Synology NAS. O ja, sinds kort wordt ook de slimme meter uitgelezen en op een LCD display getoond, in prometheus opgeslagen en met grafana getoond.
Ik maak al lang gebruik van klikaanklikuit, radiografische afstandsbediening op 433 Mhz, om apparaten, vooral lampen, aan en uit te zetten (of te dimmen). Het bestaat uit zenders en ontvangers. Zenders sturen commando's naar de ontvangers die reageren als het commando voor hen bestemd is. Of een commando bestemd is voor een ontvanger wordt bepaald door het adres dat meegegeven wordt in het commando, elke ontvanger luistert naar één of meerdere adressen. Commando's zijn bijvoorbeeld: aan, aan op 50%, of uit.
In 2011 ben ik verhuisd naar een nieuw huis dat 's avonds erg donker is bij de voordeur waardoor het sleutelgat erg moeilijk te vinden is. Om in het donker beter zicht te hebben heb ik daar verlichting gemaakt die aan en uit gaat via een bewegingssensor van klikaanklikuit. Dus als je in het donker aan komt lopen gaat de verlichting aan, het sleutelgat is makkelijk te vinden en na enige tijd gaat de verlichting weer uit. De bewegingssensor is de zender, die detecteert beweging, en stuurt een 'aan' commando naar de ontvanger, die de verlichting aan zet. Na enige (instelbare) tijd stuurt de beweginssensor ook het 'uit' commando. Het 'uit' commando wordt altijd verstuurd na de ingestelde tijd, ook als er in die tijd nog beweging is geweest.
Voordeur in het donker
Voordeur met licht
'Enige tijd' is maximaal instelbaar op vier minuten. Dat is lang genoeg om je sleutel te zoeken en binnen te komen, maar te kort als je de auto aan het uitladen bent of met iemand bij de voordeur aan het praten. De verlichting gaat dan uit en het duurt even voordat de zender weer een 'aan' commando stuurt als gevolg van beweging. Om een langere tijdsduur tussen 'aan' en 'uit' te kunnen instellen heb ik een Raspberry Pi 3 met RFXCOM tussen de zender en ontvanger gezet en software geschreven die het volgende doet:
Nu blijft de verlichting aan totdat er 30 minuten lang geen beweging is gedetecteerd, in plaats van altijd uit na vier minuten.
In de loop der tijd is er steeds meer toegevoegd en tegenwoordig kan ik ook:
Klikaanklikuit is te koop in diverse bouwmarkten en elektronica winkels.
De Raspberry Pi 3 is een goedkope singleboardcomputer gebaseerd op een ARM-processor. Hij heeft een hdmi aansluiting, netwerk aansluiting, 4 USB-aansluitingen, wifi en bluetooth.
De RFXCOM is een 433 Mhz zender/ontvanger die via USB aangesloten wordt op een computer. Hij kan klikaanklikuit commando's versturen en ontvangen en ook signalen sturen/ontvangen van veel andere zenders/ontvangers die werken op 433 Mhz, bijvoorbeeld weerstations.
RFXCOM hardware
Omdat de Raspberry Pi SD-kaart gevoelig is voor corruptie van het bestandssysteem bij onverwacht uitschakelen heb ik besloten om de Raspberry Pi 3 te draaien zonder SD-kaart. Hij start op en draait vanaf het netwerk. Hiervoor is wel een vaste netwerk kabel nodig, dit kan niet via wifi. Opstarten en draaien gaat met behulp van een Synology NAS die een tftp server en nfs server draait. De tftp server zorgt dat de Raspberry Pi bij het starten informatie krijgt waardoor hij kan opstarten en weet waar hij na het opstarten mee verder moet gaan (bootcode). De nfs server bevat het file systeem voor de Raspberry Pi (wat anders op de SD-kaart zou staan).
Een ander voordeel van deze setup is dat de backup van de Raspberry Pi installatie makkelijk via de NAS geregeld kan worden.
De software is geschreven in Kotlin, omdat ik daar meer ervaring mee wilde opdoen, en ontworpen met behulp van DDD (Domain Driven Design), ook om daarmee meer ervaring op te doen (hoe deel je een applicatie op in domeinen en hoe geef je die weer in de source code).
Het hoofddomein werkt met messages. Een message is een map van key/values waarbij een key de betekenis van een value aangeeft.
Het hoofddomein is een message processor: een message gaat de processor in en er komen nul of meer messages uit als resultaat. De messages die er uit komen kunnen weer naar de input gaan of naar andere (output) domeinen, afhankelijk van het type van de uitgaande message.
Messages worden verwerkt met regels. Bij elke message worden de regels gezocht die van toepassing zijn (aan de hand van de keys/values in de message) op die message en elke regel produceert nul of meer uitgaande messages afhankelijk van de inkomende message.
Een regel kan ook state bewaren, bijvoorbeeld of de verlichting aan staat en hoe laat die weer uitgezet moet worden. Die state kan later door dezelfde regel of andere regels gebruikt worden.
Klikaanklikuit commando's komen van de RFXCOM driver in de RFXCOM input die er messages van maakt die de message processor kan verwerken. In de message staat onder andere het commando en het adres aan wie het commando is gestuurd. Voor verschillende commando's en adressen kunnem verschillende regels ingesteld worden.
Een 1 minute-timer die elke minuut een message stuurt met daarin het huidige tijdstip. Regels die afhankelijk zijn van een tijdstip kunnen hierop reageren (bijvoorbeeld het uitzetten van de verlichting bij de voordeur na 30 minuten inactiviteit).
In 2020 werd mijn gas- en elektriciteitsmeter vervangen door een slimme meter. Die heeft een uitgang waarop hij gegevens publiceert over de meterstanden en het verbruik. De P1 lezer zet de slimme meter gegevens om in een message die de message processor kan verwerken.
Slimme meter en raspberry pi 3 met LCD display in de meterkast.
Ik wilde kunnen zien of er wel of niet iemand thuis is. Daarvoor dient de MAC-scanner. Die scant alle MAC-adressen op het netwerk en weet dan welke apparaten er zijn aangesloten. Als één of meer adressen van een mobiele telefoon is dan is er waarschijnlijk iemand thuis.
De MAC-scanner zet de aanwezige MAC-adressen in een message die de message processor kan verwerken. De message processor zelf zet die weer om in messages die aangeven of een mac-adres is toegevoegd of verwijderd.
Een HTTP-endpoint dat JSON-data omzet naar messages die de message processor kan verwerken. Op een iPhone zijn scripts gemaakt in de Opdrachten app die JSON naar het endpoint kunnen sturen. Door in de JSON de juiste keys/values te plaatsen kan een RFXCOM commando worden gestuurd.
Het HTTP-endpoint kan ook op andere manieren aangestuurd worden, bijvoorbeeld door een Angular app.
De RFXCOM-output maakt van uitgaande messages, die bestemd zijn voor de RFXCOM, een RFXCOM-commando dat naar de RFXCOM-driver gaat. Hiermee kan bijvoorbeeld verlichting aan/uit gezet worden.
Ik wilde de slimme meter gegevens graag real-time kunnen zien. Bij Ali Express kun je goedkoop een LCD display voor de Raspberry Pi kopen. De message processor zet de slimme meter message om naar meerdere display messages (voor de verschillende gegevens) en de LCD display output zet die op het LCD display.
Nu staan alleen de slimme meter gegevens nog op het LCD display, maar in de toekomst moeten daar ook statussen van klikaanklikuit bij komen te staan (verlichting die aan staat, deuren die open staan, en dergelijke) en degenen die thuis zijn (waarvan de telefoon thuis is).
Een HTTP-endpoint dat wordt gebruikt door prometheus. Hierop worden gegevens gepubliceerd die opgeslagen worden in prometheus. De gegevens in prometheus worden door grafana getoond in grafieken.
De applicatie bestaat uit verschillende libraries en een hoofdprogramma die in aparte projecten in git zijn opgeslagen. Elk project, ook het hoofdprogramma, wordt gebouwd met gradle en heeft als resultaat artifact een jar-file. De jar-file van het hoofdprogramma wordt gedeployed naar de Raspberry Pi 3 en daar gestart.
De buildstraat bestaat uit:
Git draait op de Synology NAS, Jenkins en Nexus draaien in een docker container op de Synology NAS.
Zodra nieuwe sources naar git worden gepushed wordt het bijbehorende project in Jenkins gebouwd doordat in git een hook is gemaakt die het Jenkins project triggert. Als het Jenkins project succesvol bouwt wordt het resultaat artifact opgeslagen in Nexus zodat het later door andere projecten gebruikt kan worden.
Als het hoofdprogramma door Jenkins is gebouwd wordt het resultaat artifact, samen met een start script en een installatie script, naar de Raspberry Pi 3 gedeployed, geïnstalleerd en gestart. Een eventueel al draaiend hoofdprogramma wordt eerst gestopt.
De opdrachten app op de iPhone kan POST requests sturen naar een https-endpoint. Door in de body van de request de juiste codes te zetten kunnen onder andere klikaanklikuit codes verstuurd worden.
In de toekomst wil ik nog: