Apple HomeKit mit ESP32 - Teil 2
Hallo und Willkommen zum zweiten Teil der Blog Reihe im Bereich HomeKit!

Wie im ersten Blogbeitrag bereits angekündigt, gehe ich heute zuerst auf einige weiterführende theoretische Grundlagen ein. Anschließend werde ich einen Temperatur- und Luftfeuchtigkeitssensor umsetzten.

Accessories

Grundsätzlich wird im HAP zwischen Bridges und Accessories unterschieden, wobei eine Bridge bis zu 150 Accessories zusammenfassen kann und diese mit einer Verbindung in das HomeKit bringt. Als Beispiel kann man hierbei eine beliebige Zigbee Bridge nennen, welche alle Zigbee Produkte in das HomeKit Netzwerk überträgt, indem man nur die Bridge zum HomeKit hinzufügt.
Jedes HomeKit Accessory wird durch das HomeKit Datenmodell definiert, welches aus Accessories, Services und Charakteristiken besteht. Außerdem definiert das HAP, wie der für die erstmalige Verbindung benötigte, aus 8 Zahlen bestehende Setup Code generiert werden muss. Dies muss entweder bei jeder erstmaligen Einrichtung, unabhängig von einzigartigen Gerätedaten, auf dem Gerät passieren, oder für jedes Gerät zufällig bei der Produktion, wobei bei dieser Option der Code nach dem Secure Remote Password Protocol gespeichert werden muss. In beiden Fällen muss der Zufallsgenerator für die Codes kryptographisch sicher sein. Des Weiteren sind eine Reihe an sehr einfachen Code-Kombinationen verboten.

Die folgende Abbildung stellt beispielsweise den Information Service dar, welcher für jedes HomeKit Accessory und jede Bridge notwendigerweise definiert werden muss. Services stellen im HomeKit Accessory Protocol das Kontext liefernde Element eines Accessory dar und enthalten, abhängig davon um was für ein Accessory es sich handelt, dementsprechende notwendige und optionale Charakteristiken.

Abbildung 2: Ein Auszug aus dem HomeKit Accessory Protocol für den Information Service. (Apple, HomeKit Accessory Protocol Specification. Non-Commercial Version, Release R2, 2019)

Auszug aus dem HomeKit Accessory Protocol für den Information Service. (Apple, HomeKit Accessory Protocol Specification. Non-Commercial Version, Release R2, 2019)

In der Tabelle ist zu sehen, dass der Information Service zum Beispiel notwendigerweise unter anderem als Charakteristiken die Firmware Version, den Geräte Namen und die Seriennummer enthalten muss. Ein etwas komplexeres Beispiel für das HomeKit Datenmodell wäre zum Beispiel ein Ventilator mit Glühlampe und Luftbefeuchter. Dieses Gerät stellt ein Accessory dar, welches aus drei Services, dem Fan Service, dem Light Bulb Service und dem Air Purifier Service besteht. Diese drei Services verfügen dann alle nochmal über eigene notwendige und optionale Charakteristiken. In der Standard HomeKit App würde dieses Gerät nun als ein einziges Gerät angezeigt werden und das Einstellen der entsprechenden Services erlaubt. Alternativ könnte man die drei Services auch auf drei einzelne Accessories aufteilen, welche durch eine Bridge gemeinsam in HomeKit gebracht werden. Hierbei wäre es dann möglich, die einzelnen Geräte vollkommen individuell zu betrachten, also auch in unterschiedlichen Räumen in der Home App zu platzieren.

Wie ebenfalls in Abbildung 2 zu erkennen, verfügt jeder HAP Service über eine UUID, gleiches gilt ebenfalls für jede HAP Charakteristik. Eine UUID ist dabei ein 128-bit großer „Universally Unique IDentifier”, wie er in RFC 4122 definiert wurde. Bei einer UUID handelt es sich um eine weltweit einmalige Kennung, welche aufgrund ihrer 128-bit Größe und der daraus resultierenden Anzahl an möglichen Kennungen, auch ohne ein zentrales Verteilungsgremium, sondern durch die im RFC 4122 mögliche Generation auf Basis eines Zeitstempels einmalig ist. UUIDs bieten also eine Möglichkeit, sowohl Services, als auch Charakteristiken eindeutig zu identifizieren. Dies ist besonders für die Kommunikation über BluetoothLE wichtig, da hierfür „Bluetooth Generic Attribute”, kurz GATT, verwendet werden, welche auf UUIDs als eindeutige Kennungen angewiesen sind.

Sicherheit

Das Thema Sicherheit spielt im Smarthome-Bereich eine zunehmend wachsende Rolle, da immer mehr Haushaltsgeräte in das Smarthome integriert werden und somit auch anfällig für Angriffe sind. Dies gilt sowohl für Angriffe aus dem Internet, für den Fall, dass diese vernetzt sind, oder auch direkt für Angriffe aus dem lokalen Netz. Dies ist auf der einen Seite vor allem für die Sicherheit des Hauses betreffende Themen, wie zum Beispiel Türschlösser oder Alarmanlagen relevant und andererseits für alle die Privatsphäre betreffenden Bereiche, wie vor allem Mikrofone und Kameras.

Aus diesem Grund kommunizieren HomeKit-Geräte ausschließlich über Ende-zu-Ende-Verschlüsselung, welche von Apple im Rahmen des HomeKit Accessory Development Kit gewährleistet wird. Die initiale Verbindung, der sogenannte „Pair Setup” wird hierbei über ein asymmetrisches Verschlüsselungsverfahren realisiert. Hierbei handelt es sich explizit um einen einmaligen Prozess zum Einrichten des Gerätes. Für den sicheren Austausch der Schlüssel wird das Stanford Secure Remote Password Protocol verwendet. Anstatt der veralteten SHA-1 Hash-Funktion wird die SHA-512 Hash-Funktion, welche auf SHA-2 basiert, verwendet. Der Generator wird hierbei durch die 3072-bit Gruppe im RFC 5054 definiert. Zusätzlich zu dem asymmetrischen Verschlüsselungsverfahren muss der Nutzer auf seinem iOS-Gerät außerdem eine 8-stellige Zahlenkombination eingeben, welche auf dem HomeKit-Zubehör entsprechend abgebildet wird. Nach erstmaliger Initialisierung wird für jede nachfolgende Session, also Kommunikation, ein sogenanntes „Pair Verify“ durchgeführt. Hierbei wird dann eine synchrone Verschlüsselung mit einem für jede Session neu generierten Schlüssel durchgeführt. Der entsprechende Schlüssel wird nach dem Ephemeral-Diffie-Hellman-Verfahren generiert und somit kann, selbst wenn der Schlüssel gestohlen wird, keine vorherige Kommunikation mit diesem entschlüsselt werden. Man spricht von vorwärts gerichteter Geheimhaltung. Um einen Diebstahl des Schlüssels möglichst zu verhindern, müssen in einem von Apple für HomeKit zertifizierten Gerät alle für die Verschlüsselung notwendigen Schlüssel, also sogar der zum Pair Setup nötige öffentliche Schlüssel und alle damit zusammenhängenden Prozesse, speziell gesichert werden. Apple empfiehlt hierfür den Einsatz eines Sicherheitschips auf Hardwareebene, ermöglicht inzwischen aber ebenfalls softwareseitige Sicherung der Prozesse.

Wie eingangs erwähnt, sind Kameras mit Mikrofonen ein besonders kritischer Aspekt für die Privatsphäre im Smarthome. Aus diesem Grund wurde die Funktion „HomeKit Secure Video” eingeführt. Kameras müssen für eine entsprechende HomeKit-Secure-Video-Zertifizierung zusätzlich zu der gleichen Ende-zu-Ende-Verschlüsselung, welche für alle HomeKit-Geräte gilt, ihre Daten mit mindestens 128-bit AES, besser 256-bit AES, verschlüsseln. Mit dieser Verschlüsselung wird sämtliches Bildmaterial verschlüsselt und anonymisiert für 7 Tage in der iCloud vorgehalten. Außerdem finden sämtliche Analysen der Bildmaterialien, also zum Beispiel die Erkennung von Menschen, Tieren oder Paketen, lokal auf einem HomeKit Hub, also einem iPad, Apple TV oder HomePod und nicht in der Cloud statt.

Abschließend muss aber gesagt werden, dass trotz einer gewissen Sicherheit durch Verschlüsselung, auch Smarthome-Geräte aus dem HomeKit Framework ein gewisses Risiko für Sicherheitslücken bergen, über welches sich Nutzer bewusst sein sollten und für sich angemessene Maßnahmen zum Schutz vor solchen Sicherheitslücken treffen müssen. Beispielsweise ließen sich HomeKit-Geräte ohne HomeKit Hub in einem gewissen Funktionsumfang auch lokal betreiben. Weitere Möglichkeiten wären der Betrieb der Geräte in einem vom Hauptnetz getrennten VLAN, also einem virtuellen LAN, oder bei Kameras zum Beispiel das Vermeiden extrem kritischer Bildausschnitte, zum Beispiel im Wohnbereich.

Hardwareaufbau

Bauteile und Pinouts

Für die Umsetzung wird benötigt:

Anzahl Bauteil Anmerkung
1 ESP-32 Dev Kit C V4 – AZ-Delivery Als Alternative können auch andere Versionen des ESP32 genutzt werden.
1 DHT22 Temperatur- und Luftfeuchtigkeitssensor – AZ-Delivery Als Alternative kann auch die bereits mit Pull-Up-Wiederstand bestückte Platine genutzt werden
1 Widerstände Resistor Kit 525 Stück Widerstand Sortiment, 0 Ohm -1M Ohm – AZ-Delivery Eine Auswahl an verschiedenen Wiederständen, benötigt wird ein 10k Ohm Wiederstand.
1 Jumper Wire Kabel 3 x 40 STK. je 20 cm M2M/ F2M / F2F Raspberry Pi Bre – AZ-Delivery 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:

Pinout

Nachfolgend das Pin Layout des oben angegebenen DHT22:

DHT22

  • Vin – das ist der Power Pin. Zur Verwendung mit einem ESP32 müssen hier 3,3 V angelegt werden.
  • DATA – Datenleitung. Dieser Pin benötigt einen 10K Pull-Up-Widerstand zu Vin
  • NULL - funktionslos
  • GND - Ground

Verdrahtung

 

Schaltplan

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

  1. Der Vin Pin des DHT22 muss mit dem 3,3V Pin des Mikrocontrollers verbunden werden.
  2. Der GND Pin des DHT22 muss mit einem beliebigen GND Pin des Mikrocontrollers verbunden werden
  3. Der Data Pin des DHT22 muss mit einem GPIO Pin des Mikrocontrollers verbunden werden. Außerdem muss ein Pull-Up-Wiederstand zu Vin eingefügt werden.

Softwareaufbau

Als Bibliotheken kommen in diesem Projekt die bereits genannte „HomeSpan“-Bibliothek zur Integration des HomeKit Accessory Protocols zum Einsatz und die „Adafruit_DHTxx“-Bibliothek zum Auslesen des verwendeten Temperatursensors. Beide Bibliotheken können hierbei über den Bibliotheken-Manager in der Arduino IDE installiert werden.

Die HomeSpan-Bibliothek übernimmt die Implementierung des HomeKit Accessory Protocol 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 Kommandozeilen-Interface mit einem hohen Maß an Debug-Informationen und Fehlermeldungen.

Zur ordentlichen Strukturierung ist das Programm in drei Teile aufgeteilt. Der erste Teil „HomeSpan-DHT22-Temperatur-Sensor“ entspricht der main-Funktion. Sie kümmert sich um die Definition der HomeKit Accessories und erstellt Objekte, welche den HAP Server der definierten Geräte repräsentieren. Außerdem wird im Gegensatz zum ersten Blogbeitrag das HomeKit Accessory als Bridge definiert, so dass im Rahmen dieser mehrere Geräte über eine einzige Verbindung gekoppelt werden können. 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 und diese erstellt anschließend aus diesen ein HomeKit Accessory, indem sie die entsprechen HAP Funktionen aufruft. Außerdem wird der im HAP geforderte sichtbare Initialisierungsprozess durch eine blinkende LED umgesetzt, diese findet in diesem Projekt allerdings keine hardwareseitige Repräsentation. Im dritten Programmteil „DEV_Sensors.h“ werden alle anderen benötigten oder optionalen Services des Accessories 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 der DHT22 als ein Sensor eingebunden. Dieser Sensor enthält entsprechend einen Temperatursensor und einen Sensor zur Bestimmung der Luftfeuchtigkeit. Als Erstes erhalten beide den Accessory Information Service, welcher für jedes HomeKit-Zubehör notwendig ist. Dieser Service enthält als Charakteristiken die Firmware-Version, eine Identifizierungs-Routine, einen Hersteller, die Modellbezeichnung, einen Namen und die Seriennummer. Anschließend wurden im Bereich „DEV_Sensors.h“ die Sensoren mit ihren entsprechenden Services implementiert. Für den Temperatursensor wurde Beispielsweise der Temperaturarbeitsbereich von den 0 bis 100 Grad Celsius, welche als Standard in HomeKit hinterlegt sind, auf -50 bis 100 Grad Celsius, also den dem Datenblatt zu entnehmenden Bereich des Temperatursensors, geändert. Außerdem wurde die Charakteristik der aktuellen Temperatur deklariert. Alle 10 Sekunden wird der Temperaturwert definiert und somit an HomeKit übermittelt. Hierbei beschränken wir uns auf ein beliebiges Zeitintervall, um das Heimnetzwerk nicht unnötig zu überlasten.
Gleiches wird ebenfalls für den Luftfeuchtigkeitssensor umgesetzt.

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

HomeSpan-DHT22-Temperatur-Sensor.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.
  *  
  ********************************************************************************/
 
 ////////////////////////////////////////////////////////////
 //                                                       //
 //   HomeSpan: A HomeKit implementation for the ESP32   //
 //   ------------------------------------------------   //
 //                                                       //
 ////////////////////////////////////////////////////////////
 
 #include "HomeSpan.h"
 #include "DEV_Identify.h"      
 #include "DEV_Sensors.h"
 
 void setup() {
   
   Serial.begin(115200);
   homeSpan.begin(Category::Bridges,"AZDelivery Temp Sensor Bridge");
 
   new SpanAccessory();  
     new DEV_Identify("AZDelivery HomeKit","SmartHomeFactory","123-ABC","HS Bridge","0.9",3);
     new Service::HAPProtocolInformation();
       new Characteristic::Version("1.1.0");
       
   new SpanAccessory();                                                          
     new DEV_Identify("DHT22 Temp Sensor","SmartHomeFactory","123-ABC","Sensor","0.9",0);
     // Create a Temperature Sensor (see DEV_Sensors.h for definition)
     new DEV_TempSensor();
         
 
   new SpanAccessory();
     new DEV_Identify("DHT22 Humidity Sensor","SmartHomeFactory","123-ABC","Sensor","0.9",0);
     // Create a Humidity Sensor (see DEV_Sensors.h for definition)
     new DEV_HumSensor();
     
 } // 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_Sensors.h

 /////////////////////////////////
 //   DEVICE-SPECIFIC SERVICES //
 ////////////////////////////////
 #include "DHT.h"
 
 #define DHTPIN 17
 #define DHTTYPE DHT22
 
 // reference to the Sensor Objects
 DHT dht(DHTPIN, DHTTYPE);
 
 // A standalone Temperature sensor
 struct DEV_TempSensor : Service::TemperatureSensor {    
 
   // reference to the Current Temperature Characteristic
   SpanCharacteristic *temp;                                      
 
   // constructor() method
   DEV_TempSensor() : Service::TemperatureSensor() {      
 
     // start dhttemp Object
     dht.begin();                                    
 
     // instantiate the Current Temperature Characteristic
     temp = new Characteristic::CurrentTemperature(-10.0);    
     // expand the range from the HAP default of 0-100 to -50 to 100 to allow for negative temperatures
     temp->setRange(-50, 100);                                
 
     // initialization message
     Serial.print("Configuring Temperature Sensor");          
     Serial.print("\n");
 
  } // end constructor
 
   void loop() {
 
     // the temperature refreshes every 10 seconds by the elapsed time
     if (temp->timeVal() > 10000) {
       // read temperature from sensor dht22
       float temperature = dht.readTemperature();        
       // set the new temperature; this generates an Event Notification and also resets the elapsed time
       temp->setVal(temperature);                            
 
       LOG1("Temperature Update: ");
       LOG1(temperature);
       LOG1(" ; ");
    }
  } // loop
 };
 
 ////////////////////////////////////
 
 // A standalone Humidity sensor
 struct DEV_HumSensor : Service::HumiditySensor {    
 
   // reference to the Current Humidity Characteristic
   SpanCharacteristic *hum;                                  
 
   // constructor() method
   DEV_HumSensor() : Service::HumiditySensor() {      
 
     // start dhthum Object
     dht.begin();                                  
 
     // instantiate the Current Temperature Characteristic
     hum = new Characteristic::CurrentRelativeHumidity(50);
     // expand the range to 30%-100%
     hum->setRange(30, 100);                                
 
     // initialization message
     Serial.print("Configuring Humidity Sensor");          
     Serial.print("\n");
 
  } // end constructor
 
   void loop() {
 
     // the humidity refreshes every 10 seconds by the elapsed time
     if (hum->timeVal() > 10000) {
       // read humidity from sensor dht22
       float humidity = dht.readHumidity();  
       // set the new humidity; this generates an Event Notification and also resets the elapsed time        
       hum->setVal(humidity);                            
 
       LOG1("Humidity Update: ");
       LOG1(humidity);
       LOG1(" ; ");
    }
  } // loop
 };
 
 //////////////////////////////////

Konfiguration

Startkonsole

Dies ist der Konfigurationsmodus unseres HomeKit-Temperatursensors, welcher über die serielle Konsole in der Arduino IDE erreicht werden kann. Zu beachten ist die Einstellung der korrekten Baud Rate. Durch eintippen eines „W“ kann das WLAN konfiguriert werden.

WiFi Konsole

Hier ist das WLAN nun konfiguriert und der HomeKit-Sensor hat sich mit dem lokalen Netzwerk verbunden. Nun kann dieser an Ihrem IOS Gerät mit dem Standardsetup-Code „466-37-726“ zu ihrem HomeKit zu Hause hinzugefügt werden.

Dies sieht dann zum Beispiel so in der Standard HomeKit App aus:

HomeKit

Ich hoffe Sie haben viel Spaß beim Nachbauen!

Esp-32Progetti per principianti

4 Kommentare

Hendrik

Hendrik

Moin, ich habe auch das Problem, dass in der Übersicht ein knapp 20% geringerer Wert für die Luftfeuchtigkeit angezeigt wird. Wenn ich den Wert direkt anzeigen lasse, wird der korrekte Wert angezeigt.

Thomas Hecker

Thomas Hecker

Hallo Leon,
ich habe da noch eine Nachfrage.
Mein Versuch den Sensor nun unabhängig von einem USB Anschluß zu betreiben scheitert. Weder die Versorgung über 3,3V noch 5V führt zum Erfolg. Die LED des ESP32 leuchtet zwar aber vermutlich kann er sich nicht ins WLAN einloggen. Auf den Serial Monitor kann ich nicht zugreifen es sei denn ich schließe wieder das USB Kabel an. Hast Du da, gerne auch jemand der das Problem bereits gelöst hat, einen Rat?
Viele Grüße
Thomas

Thomas Hecker

Thomas Hecker

Vielen Dank für das schöne Projekt!
Ich bin noch sehr am Anfang mit der Arduino-ESP Bastelei, hatte aber bei der praktischen Umsetzung keine Probleme. Die Theorie dahinter ist noch in mehr oder weniger dichtem Nebel.
Die Anzeige der Bridge in Home weist bei der Feuchtigkeit einen niedrigeren Wert (18%) aus als ich ihn gezeigt bekomme wenn ich mir die einzelnen Komponenten der Bridge anzeigen lasse. Feuchtigkeit 40%.
Lässt sich das im Programmcode anpassen? Umrechnung anders?
Viele Grüße
Thomas

Michael

Michael

Hallo, sehr schön Dein Prjekt. Schöner wäre es wenn due einen “GY-BME280” Sensor genommen hättest. Sind genauer.

Einen Kommentar hinterlassen

Alle Kommentare werden vor der Veröffentlichung moderiert

Post di blog consigliati

  1. Installa ESP32 ora dal gestore del consiglio di amministrazione
  2. Lüftersteuerung Raspberry Pi
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1
  4. ESP32 - das Multitalent
  5. OTA - Over the Air - Programmazione ESP tramite WLAN