Integrar Ikea VINDRIKTNING en HA

Integrar Ikea VINDRIKTNING 2.0 en HA

Hoy vamos a integrar Ikea VINDRIKTNING 2.0 en HA, una versión mejorada con más funciones de este magnífico hack!

Ikea VINDRIKTNING 2.0

Ha pasado muy poco tiempo desde que te enseñé cómo había «hackeado» este dispositivo. Siendo sincero, no hice nada diferente a lo que puedas consultar en los últimos años. Y la verdad es que me quedé varios días revisando mi cajón de placas y sensores, pensando en cómo podía incorporar algunas de las funciones o componentes más modernos a este proyecto tan popular.

De esta forma es como he llegado a esta guía para integrar Ikea VINDRIKTNING 2.0 en HA, un dispositivo con las siguientes características:

  • Integración del dispositivo en Home Assistant con en ESPHome.
  • Expone como sensores la concentración de partículas PM2.5, la temperatura y la humedad.
  • Control pleno del LED RGB, que puedes usar como quieras.
  • Detecta presencia y movimiento en la estancia.
  • Puedes utilizarlo como Bluetooth Proxy con Bermuda para la detección de presencia personalizada por habitaciones.
  • El dispositivo utiliza la carcasa original del dispositivo.

Requisitos previos

Para integrar Ikea VINDRIKTNING en HA previamente necesitas:

  • Un Ikea VINDRIKTNING.
  • Una placa ESP32-S3 Matrix. Se trata de una variante de placa ESP32 que nos va a permitir incorporar algunas funciones más a nuestro dispositivo. Además, gracias a su forma y tamaño encaja como un guante en la carcasa!
  • Un sensor AHT10, para incorporar la información de temperatura y humedad a nuestro dispositivo.
  • Un sensor LD2410C, para detectar presencia y movimiento en la estancia.
  • Un cable USB-C para alimentar la placa de DATOS (con un cable de carga no vas a poder instalar el software).
  • Haber instalado ESPHome en Home Assistant.
ESP32-S3 Matrix
GENERICO

ESP32-S3 Matrix

5,0

Placa microcontroladora con matriz de LED para proyectos DIY. Conectividad WiFi y Bluetooth, funcionamiento local e integración con Home Assistant vía ESPHome. Ideal para crear sensores personalizados.Placa microcontroladora con matriz de LED para proyectos DIY. Conectividad WiFi ...

Sensor AHT10
GENERICO

Sensor AHT10

4,0

Sensor de temperatura y humedad ideal para proyectos DIY. Funciona en local vía WiFi y se integra fácilmente en Home Assistant mediante ESPHome. Perfecto para entusiastas de Arduino y ESP.Sensor de temperatura y humedad ideal para proyectos DIY. Funciona en local vía ...

*Algún precio puede haber cambiado desde la ultima revision

Conexión de los componentes

Lo primero que vamos a hacer para integrar Ikea VINDRIKTNING en HA es abrir la carcasa del sensor. Para ello tienes que quitar los 4 tornillos que hay en las esquinas y hecho esto ya podrás retirar (con cuidado) la cubierta frontal. Desconecta los conectores de la placa tirando suavemente de ellos para trabajar más cómodamente.

Fíjate en la placa que trae el dispositivo, por la parte opuesta al puerto USB-C, y observarás una serie de pines expuestos. En estos pines vamos a soldar tres cables que irán a nuestra placa ESP.

  • El cable de alimentación (rojo) irá al pin identificado con +5V
  • El cable de tierra (negro) irá al pin identificado con GND
  • El cable de datos (verde) irá al pin identificado con REST

Lo siguiente es observar el ‘pinout’ (o distribución de pines) de la placa. En mi caso voy a utilizar una placa ESP32-S3 Matrix y este es su ‘pinout’.

El esquema de conexiones que vamos a seguir es el siguiente:

  • El cable de alimentación (en mi caso, el rojo) irá al pin 5V
  • El cable de tierra (en mi caso, el negro) irá al pin GND
  • El cable de datos (en mi caso, el verde) irá al pin GP7

El sensor AHT10 seguirá este esquema de conexiones:

  • El pin ‘VIN’ irá al pin 3V3 de la placa.
  • El pin ‘GND’ irá al pin al pin GND de la placa.
  • El pin ‘SCL’ irá al GP6 de la placa.
  • El pin ‘SDA’ irá al pin GP5 de la placa.

Por último, el sensor LD2410C se conectará a la placa con el siguiente esquema de conexiones:

  • VCC irá conectado al pin de alimentación 5v de la placa.
  • GND irá conectado al pin GND (‘ground’ o tierra) de la placa.
  • RX irá conectado al GP4 de la placa.
  • TX irá conectado al pin GP3 de la placa.
  • No realizaremos ninguna conexión al pin OUT.

Por tanto, el esquema completo de conexiones será el siguiente:

Adaptaciones de la carcasa

Como te decía en la introducción, al integrar Ikea VINDRIKTNING 2.0 en HA no vas a necesitar ninguna carcasa o accesorio adicional, ni fabricar ninguna pieza con tu impresora 3D. No obstante, si vamos a realizar dos pequeños ajustes.

El primero de ellos es «anular» los LED que el dispositivo trae por defecto, ya que los que vamos a utilizar son los de la matriz LED que trae nuestra placa. No obstante, lo vamos a hacer de una forma muy sencilla, sin alterar la placa que viene de serie con el dispositivo. Lo único que necesitas es pegar un poco de cinta aislante opaca.

Lo siguiente que vamos a hacer es crear una pequeña endidura en la parte central para interponer nuestra placa entre la carcasa y la placa original de Ikea. Puedes usar un cutter, el soldador o cualquier herramienta que te parezca adecuada. Ten paciencia y cuidado, pero no te preocupes por el acabado ya que no se apreciará desde el exterior.

Configuración de ESPHome

Antes de volver a montar el dispositivo, vamos a flashear la placa y comprobar que todo funciona:

  1. Conecta la placa a tu ordenador a través del puerto USB-C.
  2. En Home Assistant, accede al complemento de ESPHome desde el menú lateral y pulsa en “New device”. Pulsa en “Continue” y dale un nombre (por ejemplo, “Ikea Vindriktning»).
  3. Pulsa en “Next” y a continuación selecciona la opción “ESP32-S3” como tipo de dispositivo. Verás que en el fondo se ha creado un nuevo dispositivo.
  4. Pulsa en “Skip” y haz clic en el enlace “Edit” del bloque correspondiente al dispositivo que acabas de crear. Copia el código que aparece y consérvalo, ya que vas a necesitar alguna parte del mismo.
  5. Copia el siguiente código y úsalo para reemplazar el código anterior en ESPHome.
esphome:
  name: ikea-vindriktning-v2
  friendly_name: Ikea Vindriktning v2
  on_boot: 
    then:
      - light.turn_on:
          id: led_matrix
          brightness: 60%
          effect: "Arcoiris"
      - delay: 5s        
      - light.turn_off: led_matrix

esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: esp-idf

# Enable logging
logger:
  
# Enable Home Assistant API
api:
  encryption:
    key: "be915ZxV7sjksd093290ndsXKyQtkEDNaJPI5pKº122"

ota:
  - platform: esphome
    password: "38484nndc752weqb460f4a0"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Ikea-Vindriktning-V2"
    password: "gdxFAoV8mLip"

captive_portal:

# Activación del BT Proxy para utilizar Bermuda#

esp32_ble_tracker:
  scan_parameters:
    interval: 320ms
    window: 300ms
    active: true

bluetooth_proxy:
  active: true

################################################

light:
  - platform: esp32_rmt_led_strip
    rgb_order: RGB
    pin: GPIO14
    num_leds: 64
    chipset: ws2812
    name: "LED"
    id: led_matrix
    color_correct: [30%, 30%, 30%]
    icon: mdi:led-strip-variant
    effects:
      - addressable_rainbow:
          name: "Arcoiris"
      - pulse:
          name: "Fade"
      - addressable_lambda:
          name: "Fuego"
          update_interval: 50ms
          lambda: |-
            static uint8_t heat[8][8];
            static int cooling = 60;  // Reduce el enfriamiento para mantener más brillo
            static int sparking = 130; // Aumenta las chispas para más dinamismo
            
            // Desplazamiento del calor hacia arriba
            for (int x = 0; x < 8; x++) {
              for (int y = 7; y > 0; y--) {
                heat[x][y] = (heat[x][y - 1] * 2 + heat[x][y]) / 3; 
              }
            }

            // Generar nuevas chispas en la parte inferior
            for (int x = 0; x < 8; x++) {
              if (random_uint32() % 255 < sparking) {
                heat[x][0] = 255;
              }
            }

            // Aplicar color a la matriz
            for (int x = 0; x < 8; x++) {
              for (int y = 0; y < 8; y++) {
                uint8_t color = heat[x][y] - (random_uint32() % cooling);
                if (color < 0) color = 0;

                Color col;
                if (color > 180) {
                  col = Color(255, color - 50, 0); // Rojo intenso con un poco de naranja
                } else if (color > 120) {
                  col = Color(255, color - 80, 0); // Rojo-naranja
                } else if (color > 60) {
                  col = Color(200, color - 40, 0); // Naranja oscuro
                } else {
                  col = Color(120, 20, 0); // Rojo apagado
                }
                it[8 * y + x] = col;
              }
            }
      - addressable_lambda:
          name: "Lluvia"
          update_interval: 100ms
          lambda: |-
            static uint8_t rain[8][8] = {0}; // Matriz para el estado de la lluvia

            // Desplazar gotas hacia abajo con efecto de goteo disperso
            for (int x = 0; x < 8; x++) {
              for (int y = 7; y > 0; y--) {
                // Probabilidad de que la gota desaparezca antes de llegar al final
                if (random_uint32() % 8 < 2) { 
                  rain[x][y] = 0;  
                } else {
                  rain[x][y] = rain[x][y - 1]; // Mueve la gota una posición abajo
                }
              }

              // Control estricto para menos gotas encendidas al mismo tiempo
              if (random_uint32() % 18 == 0) { // Reduce la frecuencia de aparición
                rain[x][0] = 200 + (random_uint32() % 55); // Azul claro con variación de brillo
              } else {
                rain[x][0] = 0;
              }
            }

            // Renderizar la lluvia con tonos de azul claro y más fondo negro
            for (int x = 0; x < 8; x++) {
              for (int y = 0; y < 8; y++) {
                uint8_t intensity = rain[x][y];  // Brillo de la gota
                Color col;

                // Mayor contraste con más LEDs apagados
                if (intensity > 220) {
                  col = Color(120, 200, 255); // Azul celeste brillante
                } else if (intensity > 160) {
                  col = Color(90, 180, 240); // Azul cielo
                } else if (intensity > 100) {
                  col = Color(70, 150, 220); // Azul medio
                } else if (intensity > 50) {
                  col = Color(50, 120, 200); // Azul tenue
                } else {
                  col = Color(0, 0, 0); // Negro total (fondo)
                }
                
                it[8 * y + x] = col;
              }
            }
uart:
  - id: pm1006_uart
    rx_pin: GPIO7
    baud_rate: 9600

  - id: ld2410_uart
    tx_pin: GPIO4
    rx_pin: GPIO3
    baud_rate: 256000
    parity: NONE
    stop_bits: 1

i2c:
  - id: bus_a
    scl: GPIO6
    sda: GPIO5
    scan: True

sensor:
  - platform: pm1006
    uart_id: pm1006_uart
    pm_2_5:
      name: "Partículas de 2.5µm"
      id: particulate_matter_2_5

  - platform: aht10
    variant: AHT20
    i2c_id: bus_a
    temperature:
      name: "Temperatura"
    humidity:
      name: "Humedad"
    update_interval: 120s

  - platform: ld2410
    light:
      name: light
    moving_distance:
      name : Moving Distance
    still_distance:
      name: Still Distance
    moving_energy:
      name: Move Energy
    still_energy:
      name: Still Energy
    detection_distance:
      name: Detection Distance
    g0:
      move_energy:
        name: g0 move energy
      still_energy:
        name: g0 still energy
    g1:
      move_energy:
        name: g1 move energy
      still_energy:
        name: g1 still energy
    g2:
      move_energy:
        name: g2 move energy
      still_energy:
        name: g2 still energy
    g3:
      move_energy:
        name: g3 move energy
      still_energy:
        name: g3 still energy
    g4:
      move_energy:
        name: g4 move energy
      still_energy:
        name: g4 still energy
    g5:
      move_energy:
        name: g5 move energy
      still_energy:
        name: g5 still energy
    g6:
      move_energy:
        name: g6 move energy
      still_energy:
        name: g6 still energy
    g7:
      move_energy:
        name: g7 move energy
      still_energy:
        name: g7 still energy
    g8:
      move_energy:
        name: g8 move energy
      still_energy:
        name: g8 still energy


text_sensor:
  - platform: template
    name: "Calidad del aire (PM2.5)"
    icon: mdi:air-filter
    update_interval: 60s
    lambda: |-
      if (id(particulate_matter_2_5).state <= 12.0) {
        return {"Excelente"};
      } else if (id(particulate_matter_2_5).state > 12.0 && id(particulate_matter_2_5).state <= 35.0) {
        return {"Buena"};
      } else if (id(particulate_matter_2_5).state > 35.0 && id(particulate_matter_2_5).state <= 55.0) {
        return {"Moderada"};
      } else if (id(particulate_matter_2_5).state > 55.0 && id(particulate_matter_2_5).state <= 150.0) {
        return {"Insana"};
      } else if (id(particulate_matter_2_5).state > 150.0 && id(particulate_matter_2_5).state <= 250.0) {
        return {"Dañina"};
      } else if (id(particulate_matter_2_5).state > 250.0 && id(particulate_matter_2_5).state <= 350.0) {
        return {"Muy dañina"};
      } else {
        return {"Peligrosa"};
      }

ld2410:
  uart_id: ld2410_uart

binary_sensor:
  - platform: ld2410
    has_target:
      name: Presence
    has_moving_target:
      name: Moving Target
    has_still_target:
      name: Still Target
    out_pin_presence_status:
      name: out pin presence status

switch:
  - platform: ld2410
    engineering_mode:
      name: "engineering mode"
    bluetooth:
      name: "control bluetooth"

number:
  - platform: ld2410
    timeout:
      name: timeout
    light_threshold:
      name: light threshold
    max_move_distance_gate:
      name: max move distance gate
    max_still_distance_gate:
      name: max still distance gate
    g0:
      move_threshold:
        name: g0 move threshold
      still_threshold:
        name: g0 still threshold
    g1:
      move_threshold:
        name: g1 move threshold
      still_threshold:
        name: g1 still threshold
    g2:
      move_threshold:
        name: g2 move threshold
      still_threshold:
        name: g2 still threshold
    g3:
      move_threshold:
        name: g3 move threshold
      still_threshold:
        name: g3 still threshold
    g4:
      move_threshold:
        name: g4 move threshold
      still_threshold:
        name: g4 still threshold
    g5:
      move_threshold:
        name: g5 move threshold
      still_threshold:
        name: g5 still threshold
    g6:
      move_threshold:
        name: g6 move threshold
      still_threshold:
        name: g6 still threshold
    g7:
      move_threshold:
        name: g7 move threshold
      still_threshold:
        name: g7 still threshold
    g8:
      move_threshold:
        name: g8 move threshold
      still_threshold:
        name: g8 still threshold

button:
  - platform: ld2410
    factory_reset:
      name: "factory reset"
    restart:
      name: "restart"
    query_params:
      name: query params

select:
  - platform: ld2410
    distance_resolution:
      name: "distance resolution"
    baud_rate:
      name: "baud rate"
    light_function:
      name: light function
    out_pin_level:
      name: out pin level
  1. En este código no se han incluido las credenciales para que el dispositivo se conecte a tu WiFi y tu instancia de Home Assistant y tienes que incluirlas manualmente. En concreto me refiero a las siguientes líneas del código que has copiado en el paso 4.
# Enable Home Assistant API
api:
  encryption:
    key: "bg6hash6sjdjsdjk02hh0qnQeYVwm123vdfKE8BP5"

ota:
  - platform: esphome
    password: "asddasda27aab65a48484502b332f"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Assist Fallback Hotspot"
    password: "ZsasdasdHGP2234"
  1. Cuando hayas terminado de editar el código pulsa en “Save” e “Install”. Selecciona la opción “Manual download” y espera a que el código se compile.
  2. Cuando termine, selecciona la opción “Modern format” para descargar el fichero ‘.bin’ correspondiente.
  3. Ahora ve a la página de ESPHome y pulsa en “Connect”. En la ventana emergente selecciona tu placa y pulsa en “Conectar”.
  4. Ahora pulsa en “Install” y selecciona el fichero ‘.bin’ obtenido en el paso 7. De nuevo, pulsa en “Install”.
  5. Vuelve a Home Assistant y ve a Configuración > Dispositivos y servicios. Lo normal es que tu dispositivo haya sido descubierto y aparezca en la parte superior, esperando únicamente a que pulses el botón de “Configurar”. De lo contrario pulsa en el botón de “Añadir integración”, busca “ESPHome” e introduce la IP de tu placa en el campo ‘Host’. Como siempre, te recomiendo que asignes una IP fija en tu router para evitar fallos en el futuro si esta cambia.

Montaje y puesta a punto

Ya casi lo tenemos, para terminar de integrar Ikea VINDRIKTNING 2.0 en HA haz lo siguiente:

  1. El primer paso es volver a atornillar la placa original en su sitio (sólo los dos tornillos de la parte inferior). La parte inferior debe quedar ajustada para que puedas seguir usando el puerto USB-C de alimentación, pero no te preocupes de la parte superior ya que hay espacio de sobra.
  2. Te sugiero que sigas la siguiente distribución de los componentes. Lejos de ser fruto de la casualidad, he pasado un rato pensando la mejor forma de acomodarlos. Una gotita de silicona puede ser útil para fijar el sensor de presencia.
  1. Ahora, con cuidado de que no se deshaga ninguna conexión, conecta los cables del resto de componentes (el sensor de partículas PM2.5 y el motor) a la placa. Hecho esto, aloja todos los cables en el hueco superior y atornilla la carcasa.
  2. Observa que he definido una serie de efectos visuales que puedes utilizar en tus automatizaciones. Por ejemplo, para que reproduzca el efecto «fuego» cuando la temperatura es muy alta, o el efecto «lluvia» cuando aumenta la humedad.
  3. Por cierto, una vez que hayas colocado el dispositivo en su lugar definitivo, no olvides calibrar el sensor de presencia.