Apple HomeKit mit ESP32 - Teil 1 - AZ-Delivery

Hallo und Willkommen zu meinem ersten Blogbeitrag bei AZ-Delivery!

Im heutigen Blog, dem ersten Teil einer neuen Blog Serie, geht es um das Thema der Hausautomatisierung mit Apple HomeKit. HomeKit ist hierbei ein Smarthome Framework für iOS-Geräte, welches den Benutzern in einer einzigen App Zugriff auf alle Smarthomegeräte in ihrem Zuhause bietet. HomeKit umfasst hierbei den gesamten Entwicklungsprozess. Ein wichtiger Grundsatz hierbei ist, dass die entsprechenden Smarthomegeräte, wie zum Beispiel Glühlampen, Thermostate oder Kameras, direkt über Bluetooth oder WLAN mit dem zu steuernden Applegerät kommunizieren können.

HomeKit umfasst hierfür zwei Frameworks. Das HomeKit Framework zur Entwicklung von eigenen HomeKit Applikationen auf iOS und das HomeKit Accessory Protokoll für die Entwicklung von entsprechendem Smarthome Zubehör (siehe folgende Abbildung).

HomeKit Framework

Das HomeKit Accessory Protokoll, kurz HAP, wurde hierbei als Open Source Projekt veröffentlicht. Die Implementation des HomeKit Accessory Protokoll findet hierbei auf einem ESP32, einem kleinen und kostengünstigen Mikrocontroller der Firma Espressif,  statt. Als Bibliothek zur Implementation des HAP Standards kommt die speziell für den ESP32 und die Arduino IDE entwickelte HomeSpan Bibliothek zum Einsatz. Dies ermöglicht mit wenigen und günstigen Bauteilen, sowie einem vertretbaren Aufwand, verschiedene HomeKit Accessories umzusetzen.

Im Folgenden werde Ich Ihnen zuerst einige Grundlagen des HomeKit Accessory Protokolls näher bringen und anschließend die Umsetzung einer HomeKit fähigen, dimmbaren LED vorstellen.

HomeKit Accessory Protokoll

Wie bereits angekündigt konzentriere ich mich in diesem Blog Beitrag auf das HomeKit Accessory Protokoll, da das HomeKit Framework der Anwendungsentwicklung zur Bedienung der eigenen Smarthomegeräte dient. Im Folgenden erläutere ich einige theoretische Grundlagen zu dem HAP, konkretere Informationen zu einem HomeKit Accessory und dem Aspekt der Sicherheit in HomeKit werden im zweiten Part dieser Blog Reihe folgen.

Das HomeKit Accessory Protokoll definiert hierbei die Anforderungen an das entsprechend zu entwickelnde Gerät und die Anbindung an das HomeKit Framework. Berücksichtigt wird hierbei das HomeKit Accessory Development Kit, welches Aufgaben wie die Verschlüsselung für den Entwickler übernimmt, so dass dieser sich auf die Anwendungslogik konzentrieren kann.

Das HAP startet hierbei mit der Definition der geforderten Netzwerktransportebene, welche Bluetooth Low Energy und IP basierte Protokolle, vor allem WLAN, umfassen. Für IP basierte Accessories, welche auch die im Rahmen dieses Blogs entwickelte dimmbare LED betrifft, gelten einige Anforderungen. Die wichtigsten sind hierbei der gleichzeitige Support von IPv4 und IPv6 Verbindungen, die Implementation von Bonjour, vor allem in Bezug auf Multicast DNS Dienste und das Zulassen von acht zeitgleichen TCP Verbindungen auf einen HAP Accessory Server. Zusätzlich müssen HAP Server die Generierung und Serialisierung von JavaScript Object Notation, kurz JSON, im Rahmen des RFC 7159 beherrschen und JSON im UTF-8 Format codieren und decodieren. Zudem werden im HAP diverse Sicherheitsanforderungen definiert, auf welche ich im nächsten Blogbeitrag noch genauer eingehe. Weiterhin wird im HAP auf die verschiedenen Rollen eingegangen. Hierbei ist der HAP Client, also in der Regel ein iPhone oder iPad, immer der Controller, welcher Anfragen an den HAP Accessory Server, also das Smarthome Gerät, sendet und entsprechende Statusrückmeldungen erhält. Außerdem muss der Client Nachrichten vom HAP Server registrieren und verarbeiten, also zum Beispiel eine Aktualisierung eines Farbwertes registrieren und verarbeiten. Des Weiteren muss der HAP Server HTTP kompatibel, nach RFC 7230 und RFC 7231, sein und auf HTTP Anfragen mit entsprechenden HTTP Antworten und entsprechenden HTTP Status Codes antworten können.

Der nächste große Punkt im HAP Standard ist das Datenmodell. Dieses definiert, wie Accessories selbst, welche auch als Profile bezeichnet werden und das Gerät generell beschreiben, strukturiert sein müssen. Hierzu bestehen Accessories aus Service Objekten und Charakteristiken, auf welche ich ebenfalls im nächsten Teil dieser Blog Serie noch näher eingehen werde. Dies betrifft auch die Anforderungen an den Setup Prozess, welche im nächsten Blogbeitrag genauer behandelt werden.

Weitere wichtige Anforderungen, an HomeKit Accessory Protokoll entsprechende Geräte, sind im Falle eines WLAN Gerätes die Notwendigkeit, sich im selben Netzwerk wie der HomeKit Client zu befinden, im Falle einer möglichen Kommunikation sowohl über WLAN, als auch über BluetoothLE, auf beiden Kommunikationswegen dieselben Informationen zur Verfügung zu stellen und keine Firmware Herabstufungen zu erlauben.

Hardwareaufbau

Bauteile und Pinouts

Für die Umsetzung wird benötigt:

Anzahl Bauteil Anmerkung
1 ESP-32 Dev Kit C V4 Als Alternative können auch andere Versionen des ESP32 genutzt werden.
1 KY-009 RGB LED SMD Modul Sensor Da wir die LEDs nicht als RGB LED nutzen möchten, geht natürlich auch jede einfache LED mit entsprechendem Vorwiderstand.
1 Jumper Wire Kabel 3 x 40 STK. je 20 cm M2M/ F2M / F2F Raspberry Pi Bre Es werden 4 female / female Jumper Wire benötigt. Falls nicht vorhanden empfiehlt sich das angegebene Set.


Nachfolgend das Pin Layout des oben angegeben ESP32:

ESP32 Pinout

Nachfolgend das Pin Layout des oben angegebenen SMD Moduls:

RGB SMD

- Ground
+ Grün
+ Rot
+ Blau

Verdrahtung

Fritzing Schaltplan

Für den Schaltungsaufbau müssen folgende Pins miteinander verbunden werden:

  1. Der GND Pin des RGB LED Moduls muss mit einem beliebigen GND Pin des Mikrocontrollers verbunden werden.
  2. Der R Pin des RGB LED Moduls muss mit einem GPIO Pin des Mikrocontrollers verbunden werden.
  3. Der G Pin des RGB LED Moduls muss mit einem GPIO Pin des Mikrocontrollers verbunden werden.
  4. Der B Pin des RGB LED Moduls muss mit einem GPIO Pin des Mikrocontrollers verbunden werden.

Verdrahtung Alternativ

Fritzing Schaltplan alternativ

Bei einer LED, welche nicht bereits mit Vorwiderstand auf einer Platine verlötet ist, muss auf die korrekte Verdrahtung geachtet werden. Hierzu müssen die Anode, welche der längere Draht sein sollte, an den gewünschten GPIO Pin angeschlossen werden und die Kathode an den Ground. Zu beachten ist die Notwendigkeit eines passenden Vorwiderstandes. Dieser sollte in der Regel passend zu der verwendeten LED nach  berechnet werden. Als Alternative eignen sich für LEDs in der Regel Vorwiderstände im Bereich 150 Ohm bis 220 Ohm. Zu bedenken ist hierbei allerdings, dass ein zu geringer Vorwiderstand zu einem unzulässig hohen Strom und somit zur Zerstörung der LED führen kann.

Softwareaufbau

Als Bibliothek kommt in diesem Projekt die bereits benannte „HomeSpan“ Bibliothek zur Integration des HomeKit Accessory Protokolls zum Einsatz. Außerdem wird zum dimmen der LED eine PWM-Integration benötigt. Diese kann entweder beliebig selbst implementiert werden, oder alternativ kann die in HomeSpan verwendete Funktionalität für die Ansteuerung von LEDs mittels PWM genutzt werden. In diesem Beispiel werde ich letzteres präsentieren, um die Umsetzung möglichst übersichtlich und einfach zu gestalten. Die HomeSpan Bibliothek kann hierbei über den Bibliotheken Manager in der Arduino IDE installiert werden.

Die HomeSpan Bibliothek übernimmt die Implementierung des HomeKit Accessory Protokoll in der Open Source Variante R2. Hierbei ist vor allem das HomeKit Daten Modell, also alle von Apple vorgesehenen Accessories inklusive ihrer Services und Charakteristiken interessant. Einzig Sound- und Videogeräte können aufgrund ihrer erhöhten Hardwareanforderungen nicht erstellt werden. HomeSpan ermöglicht eine komplette Programmierung des HomeKit-Zubehörs in der Arduino IDE und bietet ebenfalls ein Kommandozeileninterface mit einem hohen Maß an Debug-Informationen und Fehlermeldungen.

Zur ordentlichen Strukturierung ist das Programm in drei Teile aufgeteilt. Der erste Teil „dimmable_LED“ entspricht der main Funktion und kümmert sich um die Definition der HomeKit Accessories und erstellt Objekte, welche den HAP Server der definierten Geräte repräsentieren. Der zweite Teil des Programms „DEV_Identify.h“ ist eine Funktion zur übersichtlicheren und schnelleren Erstellung von HomeKit Accessories. Dieser Funktion übergibt man die Daten des “Accessory Information Service” als String, so dass die Funktion anschließend aus diesen ein HomeKit Accessory erstellt, indem sie die entsprechen HAP Funktionen aufruft. Außerdem wird der im HAP geforderte sichtbare Initialisierungsprozess durch eine blinkende LED umgesetzt, die in diesem Projekt allerdings keine Hardwareseitige Repräsentation findet. Sie können diese Funktion allerdings ohne Probleme durch den Anschluss einer LED im Bereich „DEV_Identify.h“ definierten Output Pin für die Blinks umsetzten. In meinem Beispiel habe ich diesen auf GPIO 4 gesetzt. Bei der Verwendung des oben genannten LED Moduls könnte für die Hardwareumsetzung zum Beispiel eine der drei einzeln ansteuerbaren LEDs dienen. Im dritten Programmteil „DEV_Sensors.h“ werden alle anderen benötigten oder optionalen Services des Accessory definiert und außerdem die Routine zum Auslesen der Sensordaten, oder im Falle von Aktoren, die Routine zum Ausführen des Aktors erstellt.

In diesem konkreten Fall wurde eine dimmbare LED integriert. Die verwendete LED wird mit Hilfe der PWM-Funktionalität des ESP32 gedimmt. Als erste erhält die LED den Accessory Information Service, welcher für jedes HomeKit Zubehör notwendig ist. Dieser Service enthält als Charakteristiken die Firmware Version, eine Identifizierungsroutine, einen Hersteller, die Modellbezeichnung, einen Namen und die Seriennummer. Anschließend wurden im Bereich „DEV_LED.h“ die LED  mit ihren entsprechenden Services implementiert.

Bei einer dimmbaren LED gibt es den Power Service zur Beschreibung, ob die LED eingeschaltet oder ausgeschaltet ist und einen Level Service, welcher die eingestellte Helligkeit der LED beschreibt. Für den Level Service wird ein Startwert festgelegt, welche angenommen wird, wenn die LED eingeschaltet wird, ohne dass die Helligkeit fest definiert wird. Außerdem wird für die LED ein Arbeitsbereich festgelegt, in welchem die Helligkeit vom Nutzer in der entsprechenden HomeKit App eingestellt werden kann.

Der Quellcode ist kommentiert als GitHub Repo zum Runterladen und ausprobieren vorhanden.

Im Folgenden ist er nochmal als Quelltext dargestellt:

Dimmable_LED.ino:

 /*********************************************************************************
  * MIT License
  *  
  * Copyright (c) 2020 Gregg E. Berman
  *  
  * https://github.com/HomeSpan/HomeSpan
  *  
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  * copies of the Software, and to permit persons to whom the Software is
  * furnished to do so, subject to the following conditions:
  *  
  * The above copyright notice and this permission notice shall be included in all
  * copies or substantial portions of the Software.
  *  
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  *  
  ********************************************************************************/
 
 #include "HomeSpan.h"
 #include "DEV_LED.h"    
 #include "DEV_Identify.h"      
 
 void setup() {
   
   Serial.begin(115200);
 
   homeSpan.begin(Category::Lighting,"HomeSpan LED");  
                                                         
   // Create an Dimmable LED attached to pin 16
   new SpanAccessory();                                                          
     new DEV_Identify("Dimmable LED","AZ-Delivery","123-ABC","LED","0.9",0);
     new Service::HAPProtocolInformation();
       new Characteristic::Version("1.1.0");
     new DEV_DimmableLED(16);                                                      
     
 } // end of setup()
 
 //////////////////////////////////////
 
 void loop(){
   
   homeSpan.poll();
   
 } // end of loop()

DEV_Identify.h:

 
 //////////////////////////////////
 //   DEVICE-SPECIFIC SERVICES   //
 //////////////////////////////////
 
 struct DEV_Identify : Service::AccessoryInformation {
 
   int nBlinks;                    // number of times to blink built-in LED in identify routine
   SpanCharacteristic *identify;   // reference to the Identify Characteristic
   
   DEV_Identify(const char *name, const char *manu, const char *sn, const char *model, const char *version, int nBlinks) : Service::AccessoryInformation(){
     
     new Characteristic::Name(name);                   // create all the required Characteristics with values set based on above arguments
     new Characteristic::Manufacturer(manu);
     new Characteristic::SerialNumber(sn);    
     new Characteristic::Model(model);
     new Characteristic::FirmwareRevision(version);
     identify=new Characteristic::Identify();          // store a reference to the Identify Characteristic for use below
 
     this->nBlinks=nBlinks;                            // store the number of times to blink the LED
 
     pinMode(homeSpan.getStatusPin(),OUTPUT);          // make sure LED is set for output
  }
 
   boolean update(){
       
     for(int i=0;i<nBlinks;i++){
       digitalWrite(homeSpan.getStatusPin(),LOW);
       delay(250);
       digitalWrite(homeSpan.getStatusPin(),HIGH);
       delay(250);
    }
 
     return(true);                               // return true
     
  } // update
   
 };

DEV_LED.h:

 
 ////////////////////////////////////
 //   DEVICE-SPECIFIC LED SERVICES //
 ////////////////////////////////////
 
 // library of various PWM functions
 #include "extras/PwmPin.h"                          
 
 ////////////////////////////////////
 
 // Dimmable LED
 struct DEV_DimmableLED : Service::LightBulb {      
 
   // reference to Led Pin
   LedPin *ledPin;                                  
   // reference to the On Characteristic
   SpanCharacteristic *power;                        
   // reference to the Brightness Characteristic
   SpanCharacteristic *level;                        
 
   // constructor() method  
   DEV_DimmableLED(int pin) : Service::LightBulb(){      
 
     power=new Characteristic::On();    
 
     // Brightness Characteristic with an initial value of 50%                
     level=new Characteristic::Brightness(50);      
     // sets the range of the Brightness to be from a min of 5%, to a max of 100%, in steps of 1%
     level->setRange(5,100,1);                      
 
     // configures a PWM LED for output to the specified pin
     this->ledPin=new LedPin(pin);                  
 
     // initialization message
     Serial.print("Configuring Dimmable LED: Pin=");
     Serial.print(ledPin->getPin());
     Serial.print("\n");
     
  } // end constructor
   
   // update() method
   boolean update(){
                                   
     // displays information about what is updated
     LOG1("Updating Dimmable LED on pin=");      
     LOG1(ledPin->getPin());
     LOG1(": Current Power=");
     LOG1(power->getVal()?"true":"false");
     LOG1(" Current Brightness=");
     LOG1(level->getVal());
 
     if(power->updated()){
       LOG1(" New Power=");
       LOG1(power->getNewVal()?"true":"false");
    }
 
     if(level->updated()){
       LOG1(" New Brightness=");
       LOG1(level->getNewVal());
    }
 
     LOG1("\n");
 
     // updates the actual PWM Pin
     ledPin->set(power->getNewVal()*level->getNewVal());    
   
     return(true);
   
  } // update
 };
 
 ////////////////////////////////////

Konfiguration

Dies ist der Konfigurationsmodus unserer HomeKit LED, welche über die serielle Konsole in der Arduino IDE erreicht werden kann. Zu beachten ist die Einstellung der korrekten Baud Rate.

Konfiguration

Durch eintippen eines „W“ kann das WLAN konfiguriert werden:

KonfigurationHier ist das WLAN nun konfiguriert und der HomeKit Sensor hat sich mit dem lokalen Netzwerk, in diesem Fall dem Hotspot meines iPhones, verbunden. Nun kann dieser an Ihrem iOS-Gerät mit dem Standardsetup Code „466-37-726“ zu ihrem Home hinzugefügt werden.

Dies sieht dann zum Beispiel so in der Home App aus:

Beispiel App

Im nächsten Beitrag dieser Blogreihe werde ich die theoretischen Grundlagen zum HomeKit Accessory Protokoll noch etwas vertiefen und Ihnen die oben genannten Themen zu den Accessories und dem Thema Sicherheit näher bringen. Außerdem werde ich Ihnen das Konzept einer Bridge in HomeKit etwas näher bringen. Umgesetzt wird dann ein Temperatur- und Luftfeuchtigkeitssensor.

Ich hoffe Sie haben viel Spaß beim Nachbauen!

Hier geht's weiter: Teil 2

Esp-32Projekte für anfängerSmart home

10 commenti

rougex

rougex

Sehr informativer und ausführlicher Beitrag. Eine kleine Kritik hätte ich aber trotzdem – das Wort “hierbei” wurde für meinen Geschmack etwas zu oft genutzt. Trotzdem gelungen!

Christoph

Christoph

Hallo, ich habe den Code so verwendet und auch bereits die Homespan Beispielversion. Hat ca. 5 mal geklappt, alles 1a verbunden etc. Danach seit mittlerweile 3 Tagen, ist es mir nicht mehr möglich eine Verbindung mit Homekit herzustellen. Wenn ich den Code so ausführe, bleibt er immer bei “Starting HAP Server on port 80 supporting 14 simultaneous HomeKit Controller Connections…” Stehen, das war die ersten male nicht so. Bitte um Hilfe.
MfG

Carsten Witt

Carsten Witt

So, für die Nachwelt … ;-)
Kurz: Es funktioniert problemlos wenn man sich nicht selber ein Bein stellt.
Lang: Ich betreibe zur Home Automatisierung einen RPI4 und nutze dort dies USB3 Schnittstelle für eine SSD und einem “JeeLink” zur Steuerung von Geräten. Da ich nun mehr USB Geräte benötigt hatte (Z-Wave, ..) habe ich einen einfachen USB Hub dort angeschlossen um mehr Ports zur Verfügung zu haben, funktionierte für die Automatisierung soweit auch perfekt. Leider erwies sich der HUB als so “billig” das sein Kabel als Antenne funktioniert hat und somit die daneben stehende FRITZBox auf 2.4GHz komplett gestört hat, ist mir nicht aufgefallen da alle anderen WLAN Geräte auf dem 5GHz Band funktionierten.
Kurzum, HUB entsorgt und gg. etwas besseres mit geschirmter Anschlussleitung getauscht und schon waren meine Probleme verschwunden.
Stichworte: Raspberrypi USB3 2.4GHz Probleme FRITZBox ESP32 HomeSpan

Danke fürs TUT!, bin gespannt ob es weitere Blogs dazu geben wird (von Teil zwei abgesehen) ;-)

Andreas Wolter

Andreas Wolter

@Nils: Die ESP32 Dev Kits müssen mit der Boot-Taste in den Downloadmodus gebracht werden. Wenn die Arduino IDE das Kompilieren beendet hat, versucht das esptool die Verbindung herzustellen. Dann muss man die Taste drücken, bis die Verbindung hergestellt ist.

Es gibt einen Hardware Hack, damit man das nicht ständig machen muss. Benötigt wird ein ein 10µF Kondensator. Der wird GND an GND und + an EN des ESP angeschlossen. Dann fällt das Tastedrücken weg.

Grüße,
Andreas Wolter

Nils

Nils

Super Blog, die LED läßt sich ohne Probleme mit dem IPhone steuern. Die einzige Hürde war den ESP dazu zu bringen den Sketch zu laden. Ich verwende das ESP32 Dev KitC V2 hier aus dem Shop, und bekomme den Download nur hin wenn ich die BOOT Taste drücke und wieder loslasse, sobald die Arduino IDE bestätigt, dass die Verbindung aufgebaut ist. Sollte doch eigentlich automatisch passieren bei diem Modul. Scheint ein Fehler zu sein. Weiß Jemand, wie man das fixen kann?

Leon

Leon

Hallo,
ich konnte das Problem leider bisher weder bei mir noch bei Kollegen beobachten.
Tritt das nur bei der Verbindung mit dem Wlan Router oder auch im persönlichen Hotspot auf?

Ansonsten kann dir in der GitHub Community (https://github.com/HomeSpan/HomeSpan) eventuell jemand weiterhelfen, da auch der Ersteller der Bibliothek sehr aktiv ist.

Mit freundlichen Grüßen

Mike

Mike

Hallo,
ich habe dasselbe Problem wie @Carsten mit dem WLAN:
E (1758) wifi:AP has neither DSSS parameter nor HT Information, drop it
E (1798) wifi:AP has neither DSSS parameter nor HT Information, drop it

Könnt ihr dabei helfen ?

Leon Ehring

Leon Ehring

Hallo Elias,
nein im Normalfall kannst du das ganz normal zu deinem Heimnetzwerk hinzufügen. Dann kannst du das als normales HomeKit Zubehör nutzen.
Die Verbindung mit dem Hotspot des IPhone ist eher ein minimal Beispiel, womit man externe Fehlerquellen ausschließen kann.

Mit freundlichen Grüßen

Carsten

Carsten

Hallo,
Danke erstmal für den Blog Eintrag, musste ich gleich mal ausprobieren :-)
Leider bekomme ich keine Verbindung zu meiner FritzBox (MAC Adressen Filter ist ausgeschaltet) und ich sehe auch keinen Verbindungsaufbauversuch im Log des Routers.
Im Seriellen Monitor habe ich die Credentials eingegeben und der ESP versucht “etwas”, allerdings kommt nur:
E (187432) wifi:AP has neither DSSS parameter nor HT Information, drop it
E (187495) wifi:AP has neither DSSS parameter nor HT Information, drop it
Trying to connect to XXXX. Waiting 2 second(s) for response…
….. wiederholt sich immer wieder
Hat dazu jemand vielleicht eine Idee?
Besten Dank und Grüße!

Elias

Elias

Hallo Leon,
Danke für den Beitrag! Das Thema kannte ich noch nicht und es ist super über diesen Blog darauf zu stoßen direkt mit einer kleinen Implementierung!

Funktioniert das HomeKit Netz nur in den persönlichen Hotspots der Geräte oder kann man die smarten Geräte auch im WLAN der Wohnung anmelden und dann mit einem Apple Geräte welches im gleichen WLAN ist Steuern?

Grüße
Weiter so!

Lascia un commento

Tutti i commenti vengono moderati prima della pubblicazione