Apple HomeKit mit ESP32 - Teil 2
Hello and welcome to the second part of the blog series in the field HomeKit!

As in the first Blog Already announced, I first enter some further theoretical basics today. Then I will implement a temperature and humidity sensor.

ACCESSORIES

Basically, the HAP is distinguished between Bridges and Accessories, which can summarize a bridge up to 150 accessories and brings them with a connection to the homekit. As an example, one can call any ZigBee Bridge, which transfers all ZigBee products into the HomeKit network by adding only the bridge to the homekit.
Each homeKit Accessory is defined by the homeKit data model consisting of accessories, services and characteristics. In addition, the HAP defines how the required for the first connection must be generated from 8 numbers setup code. This must happen either for each first institution, regardless of unique device data, on the device, or randomly for each device in production, whereby the code must be stored after the Secure Remote Password Protocol in this option. In both cases, the random generator for the codes must be cryptographically safe. Furthermore, a series of very simple code combinations are prohibited.

For example, the following figure represents the information service, which must necessarily be defined for each HomeKit Accessory and every Bridge. Services in HomeKit Accessory Protocol are the context of the context of an accessory and contain, depending on what a accessory it acts, corresponding necessary and optional characteristics.

Figure 2: An excerpt from the HomeKit Accessory Protocol for Information Service. (Apple, HomeKit Accessory Protocol Specification. Non-Commercial Version, Release R2, 2019)

Excerpt from the HomeKit Accessory Protocol for Information Service. (Apple, HomeKit Accessory Protocol Specification. Non-Commercial Version, Release R2, 2019)

The table shows that the information service, for example, necessarily, among other things, as characteristics the firmware version, the devices name and the serial number must contain. A slightly more complex example of the HomeKit data model would be, for example, a fan with light bulb and humidifier. This device represents an accessory consisting of three services, the Fan Service, the Light Bulb Service and the Air Purifier Service. These three services then all have their own necessary and optional characteristics. In the standard HomeKit App, this device would now be displayed as a single device and the setting of the corresponding services allowed. Alternatively, one could also divide the three services to three individual accessories, which are brought together by a Bridge in Homekit. Here it would be possible to consider the individual devices completely individually, so placing in different rooms in the home app.

As can also be seen in Figure 2, each HAP service has a UUID, the same applies to every HAP characteristic. A UUID is a 128-bit "Universal Unique Identifier", as he in RFC 4122 has been defined. A UUID is a globally unique identifier, which is due to its 128-bit size and the resulting number of possible identifiers, even without a central distribution panel, but by the generation possible in the RFC 4122 based on a timestamp. So UUIDs offer a way to uniquely identify both services, as well as characteristics. This is especially important for communication via Bluetoothle, as "Bluetooth Generic Attributes", short GATT, which depends on UUIDs as unique identifiers.

Safety

The topic of security plays an increasingly growing role in the SmartHome area, as more and more household appliances are integrated into the SmartHome and thus also prone to attacks. This applies both to attacks from the Internet, in the event that these are networked, or directly for attacks from the local network. This is relevant on the one hand above all for the security of the house related topics, such as door locks or alarm systems relevant and, on the other hand, for all areas concerning privacy, such as microphones and cameras.

For this reason, homeKit devices communicate exclusively through end-to-end encryption, which is ensured by Apple as part of the HomeKit Accessory Development Kit. The initial connection, the so-called "pair setup" is realized here via an asymmetric encryption method. This is explicitly a unique process for setting up the device. For the safe replacement of the keys, the Stanford Secure Remote Password Protocol is used. Instead of the obsolete SHA-1 hash function, the SHA-512 hash function based on SHA-2 is used. The generator is here by the 3072-bit group in RFC 5054 Are defined. In addition to the asymmetric encryption method, the user must also enter an 8-digit number combination on its iOS device, which is mapped on the homekeeping accessory. After initialization, a so-called "pair verify" is carried out for each subsequent session, ie communication. Here, a synchronous encryption is carried out with a newly generated for each session. The corresponding key is generated according to the Ephemeral Diffie Hellman method and thus can not be decrypted by prior communication with this even if the key is stolen. One speaks of forward secrecy. In order to prevent theft of the key as possible, all of the device certified by Apple for HomeKit, all the key necessary for encryption must be specifically secured for encryption, so even the public keys necessary for the pair setup and all related processes. Apple recommends the use of a hardware level secure chip for this purpose, but also allows software-side backup of the processes.

As mentioned above, cameras with microphones are a particularly critical aspect for privacy in the SmartHome. For this reason, the function "HomeKit Secure Video" was introduced. Cameras must encrypt their data with at least 128-bit AES, better 256-bit AES for a corresponding home-to-end encryption for all home-to-end encryption, which applies to all homekit devices. This encryption encrypts all images and anonymized for 7 days in the iCloud. In addition, all the analyzes of the image materials, ie, for example, the detection of humans, animals or packages, locally on a homekit hub, ie an iPad, Apple TV or Homepod and not in the cloud take place.

Finally, however, it has to be said that despite some security by encryption, also SmartHome devices from the HomeKit Framework also a certain risk for security gaps mountains, which should be aware of which user should be aware of and to make appropriate measures to protect against such security gaps. For example, homekit devices without HomeKit hub could also be locally operated in a certain range of functions. Further possibilities would be the operation of the devices in a VLAN separated from the main network, ie a virtual LAN, or cameras, for example, avoid extremely critical image cutouts, for example in the living area.

Hardware structure

Components and pinouts

For the implementation is required:

number Component annotation
1 ESP-32 DEV KIT C V4 - AZ-Delivery Alternatively, other versions of the ESP32 can be used.
1 DHT22 Temperature and Humidity Sensor - AZ-Delivery Alternatively, the board already filled with pull-up resource can be used
1 Resistors Resistor Kit 525 Piece Resistance Assortment, 0 Ohm -1m Ohm - AZ-Delivery A selection of different residues requires a 10k ohm resistance.
1 Jumper wire cable 3 x 40 pcs. 20 cm M2m / F2M / F2F Raspberry Pi Bre - AZ-Delivery 4 female / female jumper wire are needed. If not available, the specified set recommends.


Below the PIN layout of the above mentioned ESP32:

Pinout

Below the PIN layout of the above-mentioned DHT22:

DHT22

  • VIN - this is the power pin. For use with an ESP32, 3.3 V must be applied here.
  • Data - data line. This pin requires a 10k pull-up resistance to VIN
  • NULL - Functionless
  • GND - Ground

Wiring


circuit diagram

The following pins must be connected to each other for the circuit structure:

  1. The Vin pin of the DHT22 must be connected to the 3.3V pin of the microcontroller.
  2. The GND pin of the DHT22 must be connected to any GND pin of the microcontroller
  3. The DATA pin of the DHT22 must be connected to a GPIO pin of the microcontroller. In addition, a pull-up resistance to VIN must be inserted.

Software structure

As libraries in this project, the already mentioned "homeSpan" library for integrating the HomeKit Accessory Protocols for use and the "adafruit_dxx" library for reading the temperature sensor used. Both libraries can be installed via the library manager in the Arduino IDE.

The HomeSpan library assumes the implementation of the HomeKit Accessory Protocol in the open source variant R2. Above all, the HomeKit Data Model, so all accessories provided by Apple, is interesting, including your services and characteristics, interesting. Only sound and video devices can not be created due to their increased hardware requirements. Homespan allows a complete programming of the homeKit accessories in the Arduino IDE and also offers a command line interface with a high degree of debug information and error messages.

For ordinary structuring, the program is divided into three parts. The first part "HomeSpan DHT22 Temperature Sensor" corresponds to the MAIN function. It takes care of the definition of homeKit accessories and creates objects that represent the HAP server of the defined devices. In addition, in contrast to the first blog post, the HomeKit Accessory is defined as a bridge, so that in the context of these multiple devices can be coupled over a single connection. The second part of the program "DEV_Identify.h" is a function for the clearer and faster creation of HomeKit Accessories. This feature is given to the data of the "Accessory Information Service" as a string and then creates a homekit accessory from this by calling the corresponding HAP functions. In addition, the visible initialization process required in the HAP is implemented by a flashing LED, but this project does not find any hardware representation in this project. In the third program part "DEV_Sensors.h", all other required or optional services of the accessories are defined and also the routine for reading the sensor data, or in the case of actuators, which creates routine for executing the actuator.

In this concrete case, the DHT22 was integrated as a sensor. This sensor contains accordingly a temperature sensor and a sensor for determining the humidity. First, both receive the Accessory Information Service, which is necessary for each homekit accessory. This service contains as characteristics the firmware version, an identification routine, a manufacturer, the model name, a name and the serial number. Subsequently, the sensors with their corresponding services were implemented in the "dev_sensors.h" area. For the temperature sensor, for example, the temperature work area from the 0 to 100 degrees Celsius, which are stored as standard in HomeKit, was changed to -50 to 100 degrees Celsius, ie the area of ​​the temperature sensor to be removed to the data sheet. In addition, the characteristic of the current temperature was declared. Every 10 seconds the temperature value is defined and thus transmitted to homekit. Here we limit ourselves to any time interval to not unnecessarily overload the home network.
The same is also implemented for the humidity sensor.

The source code is commented as GitHub Repo To download and try it.

HomeSpan DHT22 Temperature-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 *nameconst char *manuconst char *snconst char *modelconst char *versionint 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(DHTPINDHTTYPE);
 
 // 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(-50100);                                
 
     // 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(30100);                                
 
     // 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
 };
 
 //////////////////////////////////

Configuration

Start console

This is the configuration mode of our homeKit temperature sensor, which can be achieved via the serial console in the Arduino IDE. Note is the setting of the correct baud rate. By typing a "W", the WLAN can be configured.

WiFi console

Here, the WLAN is now configured and the HomeKit sensor has joined the local network. Now this can be added to your homekit at home on your iOS device with the default setup code "466-37-726".

This then looks like this in the standard HomeKit app:

Homekit

I hope you have a lot of fun reading!

Esp-32Projects for beginners

5 comments

Renhold

Renhold

Wenn die Range 0..100% konfiguriert ist, stimmt die Anzeige.
hum→setRange(0, 100);

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.

Leave a comment

All comments are moderated before being published

Recommended blog posts

  1. Install ESP32 now from the board manager
  2. Lüftersteuerung Raspberry Pi
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1
  4. ESP32 - das Multitalent
  5. OTA - Over the Air - ESP programming via WLAN