Apple HomeKit mit ESP32 - Teil 2
¡Hola y bienvenido a la segunda parte de la serie de blogs del HomeKit!

Como ya mencioné en la primera parte del blog, en esta ocasión me enfocaré primero en algunos fundamentos más teóricos. Luego implementaré un sensor de temperatura y humedad.

Accesorios

Básicamente, el HAP distingue entre puentes y accesorios, por lo que un puente puede combinar hasta 150 accesorios y llevarlos a HomeKit con una sola conexión. Como ejemplo, puede nombrar cualquier puente Zigbee que transfiere todos los productos ZigBee a la red de Homekit añadiendo solo el puente al HomeKit.
Cada accesorio de HomeKit está definido por el modelo de datos de HomeKit, que consiste en accesorios, servicios y características. Además, el HAP define cómo generar el código de configuración de 8 dígitos necesario para la conexión inicial. Esto se debe realizar en el dispositivo en cada configuración inicial, independientemente de los datos únicos del dispositivo, o bien de forma aleatoria para cada dispositivo en la producción, en cuyo caso el código se debe almacenar de acuerdo con el protocolo de clave remota segura. En ambos casos, el generador de números aleatorios para los códigos debe ser criptográficamente seguro. Además, se prohíbe una serie de combinaciones de código muy simples.

Por ejemplo, la siguiente figura muestra el servicio de información que se debe definir para cada accesorio y puente de HomeKit. En el protocolo de accesorios de Homekit, los servicios representan el elemento contextualizador de un accesorio y, dependiendo de qué tipo de accesorio sea, contienen las correspondientes características necesarias y opcionales.

Figura 2: Un extracto del Protocolo de Accesorios HomeKit para el Servicio de Información. (Apple, especificación de protocolo de accesorios para el hogar. Versión no comercial, versión R2, 2019)

Extracto del protocolo de accesorios de Homekit para el servicio de información. (Apple, Especificación del protocolo de accesorios del HomeKit. Versión no comercial, versión R2, 2019)

La tabla presenta que el servicio de información, por ejemplo, debe contener necesariamente la versión del firmware, el nombre del dispositivo y el número de serie como características. Un ejemplo más complejo del modelo de datos de HomeKit sería un ventilador con una bombilla y un humidificador. Este dispositivo representa un accesorio que consiste en tres servicios, el servicio del ventilador, el servicio de bombilla y el servicio de purificador de aire. Estos tres servicios tienen sus propias características necesarias y opcionales. En la app estándar de HomeKit, este dispositivo se mostraría ahora como un único dispositivo y se permitiría la configuración de los servicios correspondientes. Como alternativa, los tres servicios también se podrían dividir en tres accesorios individuales que se incorporan juntos en HomeKit a través de un puente. En este caso, sería posible ver los dispositivos de forma completamente individual, es decir, colocarlos en diferentes habitaciones en la aplicación Home.

Como también se puede ver en la Figura 2, cada servicio HAP tiene un UUID, y lo mismo se aplica a cada característica HAP. Un UUID es un "Universally Unique Identifier" de 128 bits, tal y como se define en el RFC 4122. Un UUID es un identificador único universal que, debido a su tamaño de 128 bits y el número resultante de posibles identificadores, es único incluso sin un comité de distribución central, sino a través de la generación posible en el RFC 4122 sobre la base de una marca de tiempo. Por lo tanto, los UUIDs ofrecen la posibilidad de identificar de forma única tanto los servicios como las características. Esto es especialmente importante para la comunicación a través de BluetoothLE, ya que para ello se utilizan los "Atributos Genéricos de Bluetooth", GATT por sus siglas en inglés, que se basan en UUIDs como identificadores únicos.

Seguridad

El tema de la seguridad desempeña un papel cada vez más importante en el área "Smarthome", ya que cada vez hay más aparatos domésticos que se integran a esta área y, por lo tanto, también son vulnerables a sufrir ataques. Esto se aplica tanto a los ataques de Internet, en el caso de que estos estén en la red, como directamente a los ataques desde la red local. Por un lado, esto es especialmente relevante para los temas relacionados con la seguridad del hogar, como las cerraduras de las puertas o los sistemas de alarma, y por otro lado, para todos los ámbitos relacionados con la privacidad, como los micrófonos y las cámaras en particular.

Por esta motivo, los dispositivos HomeKit se comunican exclusivamente a través de un cifrado de extremo a extremo, que está garantizado por Apple como parte del Kit de desarrollo de accesorios de HomeKit. La conexión inicial, la denominada "Pair Setup" se implementa mediante un procedimiento de cifrado asimétrico. Esto es explícitamente un proceso único para configurar el dispositivo. Para el intercambio seguro de claves se utiliza el "Stanford Secure Remote Password Protocol". En lugar de la obsoleta función hash SHA-1, se utiliza la función SHA-512 que se basa en SHA-2. El generador aquí está definido por el grupo de 3072 bits en el RFC 5054. Además del método de cifrado asimétrico, el usuario debe ingresar una combinación numérica de 8 dígitos en su dispositivo iOS, que se mapea en consecuencia en el accesorio HomeKit. Después de la inicialización, se realiza el denominado "Pair Verify" para cada sesión posterior, es decir, la comunicación. A continuación, se lleva a cabo un cifrado síncrono con una nueva clave generada para cada sesión. La clave correspondiente se genera según el método de Ephemeral-Diffie-Hellman y, por lo tanto, aunque la clave sea robada, no se podrá descifrar ninguna comunicación previa con ella. Esto se denomina "forward secrecy". Para evitar al máximo el robo de la clave, todas las claves necesarias para el cifrado, es decir, incluso la clave pública necesaria para la configuración del par y todos los procesos relacionados, deben estar especialmente aseguradas en un dispositivo certificado por Apple para HomeKit. Apple recomienda el uso de un chip de seguridad a nivel de hardware para este propósito, pero mientras tanto también permite la seguridad de los procesos por software.

Como se mencionó anteriormente, las cámaras con micrófonos son un aspecto especialmente crítico para la privacidad en el Smarthome. Por este motivo, se introdujo la función "HomeKit Secure Video". Las cámaras deben cifrar sus datos con al menos AES de 128 bits,mejor AES de 256 bits, para obtener la correspondiente certificación de vídeo seguro de HomeKit, además del mismo cifrado de extremo a extremo que se aplica a todos los dispositivos de HomeKit. Con este cifrado, todas las grabaciones se encriptan y se anonimizan durante 7 días en iCloud. Además, todos los análisis del material de imagen, por ejemplo, el reconocimiento de personas, animales o paquetes, tienen lugar localmente en un HomeKit Hub, es decir, un iPad, Apple TV o HomePod y no en iCloud.

Sin embargo, se debe mencionar que a pesar de un cierto nivel de seguridad a través del cifrado, los dispositivos SmartHome del marco HomeKit también conllevan un cierto riesgo de vulnerabilidades de seguridad, que los usuarios debe tener en cuenta y tomar las medidas adecuadas para protegerse. Por ejemplo, los dispositivos HomeKit sin un HomeKit Hub también podrían funcionar localmente hasta cierto rango de funciones. Otras posibilidades serían operar los dispositivos en una VLAN separada de la red principal, es decir, una LAN virtual, o, en el caso de las cámaras, evitar secciones de imagen extremadamente críticas, por ejemplo, en la sala de estar.

Estructura del hardware

Componentes y Pinouts

Para la aplicación se requiere:

número Componente anotación
1 ESP-32 Dev Kit C V4 - AZ-Delivery Alternativamente, también se pueden utilizar otras versiones del ESP32.
1 Sensor de temperatura y humedad DHT22 - AZ-Delivery Alternativamente, también se puede utilizar la placa ya equipada con resistencia de pull-up.
1 Kit de Resistencias 525 piezas de resistencia, 0 Ohm -1M Ohm - AZ-Delivery Una selección de diferentes resistencias, se requiere una resistencia de 10k Ohm.
1 Cable puente 3 x 40 pcs. 20 cm M2M / F2M / F2F Raspberry Pi - AZ-Delivery Se necesitan 4 cables de puente hembra / hembra. Si no está disponible, se recomienda el conjunto especificado.


A continuación, se presenta la disposición de los pines del ESP32 mencionado anteriormente:

Pinout

La siguiente es la disposición de los pines del DHT22 mencionado anteriormente:

DHT22

  • Vin - Este es el pin de alimentación. Para utilizarlo con un ESP32, se debe aplicar aquí 3.3 V.
  • DATA - Línea de datos. Este pin requiere una resistencia de pull-up de 10K a Vin.
  • NULL - Sin función.
  • GND - Tierra.

Cableado


diagrama de circuito

Los siguientes pines se deben conectar entre sí para la construcción del circuito:

  1. El pin Vin del DHT22 se debe conectar al pin de 3.3V del microcontrolador.
  2. El pin GND del DHT22 se debe conectar a cualquier pin GND del microcontrolador.
  3. El pin de datos del DHT22 se debe conectar a un pin GPIO del microcontrolador. Además, se debe insertar una resistencia de pull-up al Vin.

Estructura del software

Las librerías que se utilizan en este proyecto son la ya mencionada "HomeSpan" para integrar el protocolo de accesorios del HomeKit y la librería "Adafruit_DHTxx" para la lectura del sensor de temperatura utilizado. Ambas librerías se pueden instalar a través del gestor de librería en el Arduino IDE.

La librería HomeSpan implementa el protocolo de accesorios de HomeKit en la versión de código abierto R2. En este sentido, resulta de especial interés el modelo de datos de HomeKit, es decir, todos los accesorios proporcionados por Apple, incluyendo sus servicios y características. Sólo no se pueden crear dispositivos de sonido y vídeo debido a sus mayores requisitos de hardware. HomeSpan permite la programación completa de los accesorios de HomeKit en el Arduino IDE y también ofrece una interfaz de línea de comandos con un alto nivel de información de depuración y mensajes de error.

Para una estructuración clara, el programa se divide en tres partes. La primera parte "HomeSpan-DHT22-Sensor Temperatura" corresponde a la función principal. Se encarga de definir de los accesorios de HomeKit y crea objetos que representan el servidor HAP de los dispositivos definidos. Además, a diferencia de la primera publicación del  blog, el accesorio HomeKit se define como un puente, por lo que se pueden emparejar varios dispositivos a través de una única conexión en el ámbito de este. La segunda parte del programa "DEV_Identify.h" es una función para la creación más clara y rápida de los accesorios de HomeKit. A esta función se le pasan los datos de "Accessory Information Service" como una cadena y luego crea un Accesorio HomeKit a partir de esto llamando a las funciones HAP correspondientes. Además, el proceso de inicialización visible requerido en el HAP se implementa mediante un LED intermitente, pero esto no se representa en el hardware de este proyecto. En la tercera parte del programa "DEV_Sensors.h", se definen todos los demás servicios necesarios u opcionales del accesorio y, además, se crea la rutina de lectura de los datos del sensor o, en el caso de los actuadores, la rutina de ejecución del mismo.

En este caso concreto, el DHT22 se integró como un sensor. Este sensor contiene un sensor de temperatura y un sensor para determinar la humedad. En primer lugar, ambos reciben el "Accessory Information Service" necesario para cada accesorio de HomeKit. Este servicio contiene la versión del firmware, una rutina de identificación, un fabricante, la designación del modelo, un nombre y el número de serie como características. Posteriormente, en el área "DEV_Sensors.h" se implementaron los sensores con sus correspondientes servicios. Para el sensor de temperatura, por ejemplo, se cambió el rango de funcionamiento de la temperatura de 0 a 100 grados Celsius, que se almacenan como estándar en Homekit, se cambió a -50 a 100 grados Celsius, es decir, el rango del sensor de temperatura que se puede tomar de la hoja de datos. Además, se declaró la característica de la temperatura actual. Cada 10 segundos se define el valor de temperatura y, por lo tanto, se transmite a HomeKit. Aquí nos limitamos a cualquier intervalo de tiempo para no sobrecargar innecesariamente la red doméstica.
Lo mismo ocurre con el sensor de humedad.

El código fuente se comenta como un repositorio de Github para descargar y probar.

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
 };
 
 //////////////////////////////////

Configuración

Iniciar consola

Este es el modo de configuración de nuestro sensor de temperatura HomeKit, al que se puede acceder a través de la consola serie en el Arduino IDE. Debe tener en cuenta que se debe ajustar la velocidad de transmisión correcta. La WLAN se puede configurar escribiendo "W".

Consola wifi

Aquí, la WLAN ya está configurada y el sensor HomeKit se ha conectado a la red local. Ahora se puede añadir a su hogar HomeKit en su dispositivo iOS con el código de configuración estándar "466-37-726".

Esto se ve así en la aplicación estándar de Homekit, por ejemplo:

Homekit

¡Espero que se divierta mucho construyéndolo!

Esp-32Proyectos para principiantes

1 comentario

Michael

Michael

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

Deja un comentario

Todos los comentarios son moderados antes de ser publicados

Artículos de blog

  1. Ahora instalamos el esp32 a través de la administración.
  2. Lüftersteuerung Raspberry Pi
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1
  4. ESP32 - das Multitalent
  5. Transporte Aéreo - programación de ESP mediante redes locales inalámbricas