AEG/Electrolux hob2hood

Based on the code for this project (Arduino-Hob2Hood/Hob2Hood.ino at dd49e276af1daf824b515881fa42f53bf2a14624 · tuxedo0801/Arduino-Hob2Hood · GitHub), I made my own code for ESPHOME. I am not experienced in this matter yet and ask for advice. How can I better implement work with RAW codes? Is it possible not to list them, but to transfer them as LONG?

# IR commands from AEG/Electrolux hob2hood device https://github.com/tuxedo0801/Arduino-Hob2Hood/blob/dd49e276af1daf824b515881fa42f53bf2a14624/Hob2Hood.ino

#const long IRCMD_VENT_1 = 0xE3C01BE2; // Hob2hood On (level 1) raw code = {1538, 1342,  794, 1340,  2290, 1340,  790, 1346,  788, 652,  788, 1346,  794, 2040,  790}
#const long IRCMD_VENT_2 = 0xD051C301; // Hob2hood level 2      raw code = {1542, 1340,  790, 2738,  816, 2014,  3788, 2026,  2292}
#const long IRCMD_VENT_3 = 0xC22FFFD7; // Hob2hood level 3      raw code = {790, 2042,  3036, 2730,  2290, 644,  790, 2042,  2286}
#const long IRCMD_VENT_4 = 0xB9121B29; // Hob2hood level 4      raw code = {1540, 2036,  1540, 650,  1540, 2034,  1542, 1340,  790, 2042,  794, 646,  1540}
#const long IRCMD_VENT_OFF = 0x55303A3;// Hob2hood off          raw code = {790, 1344,  786, 1350,  2290, 1340,  794, 1344,  1536, 2040,  794, 1344,  792, 650,  788}

#const long IRCMD_LIGHT_ON = 0xE208293C;// Light on (Hood on)    raw code = {786, 1348,  790, 652,  1538, 648,  790, 1344,  784, 656,  1540, 2734,  790, 652,  790, 650,  1538}
#const long IRCMD_LIGHT_OFF = 0x24ACF947;// Light off (Automatic after 2min) raw code = {762, 1424,  770, 674,  764, 676,  760, 2172,  760, 680,  766, 1420,  766, 1420,  760, 682,  760}

esphome:
 name: new8266
 friendly_name: new8266


esp8266:
 board: esp01_1m


# Enable logging
logger:
 #level: VERBOSE
 #tx_buffer_size: 1024 # Log large Pronto Codes


# Enable Home Assistant API
api:
 encryption:
   key: "J9y7B9VfI+wy4qp6B5I2fj1YJVwilFeMAVMwmP2A1es="


ota:
 - platform: esphome
   password: "4307b9782280616940a7ff1a2e91b43f"


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


 # Enable fallback hotspot (captive portal) in case wifi connection fails
 ap:
   ssid: "New8266 Fallback Hotspot"
   password: "lpwy6tTR7qQD"
captive_portal:


# Sync time with Home Assistant.
time:
 - platform: homeassistant
   id: homeassistant_time


# Signal WiFi
sensor:
 - platform: wifi_signal
   name: "WiFi"
   update_interval: 30s


 - platform: uptime
   name: "Uptime"


# WiFi IP
text_sensor:
 - platform: wifi_info
   ip_address:
     name: "IP"    


# WiFi LED Status (internal: True — не публикует в HA)
light:
 - platform: status_led
   name: "Switch state"
   pin: GPIO2
   internal: True


# IRDA
remote_receiver:
 pin:
   number: GPIO05
   inverted: True
   mode: INPUT_PULLUP
 #dump: raw
 buffer_size: 1kb
 idle: 25ms



binary_sensor:
 - platform: gpio
   name: "Hood Button Level 1"
   pin:
     number: GPIO1
     inverted: True
     mode:
       INPUT_PULLUP
   filters:
     - delayed_on: 10ms
   id: H2H_Button_FanSpeed1
   on_press:
     then:
       - if:
           condition:
             - switch.is_off: relay1
           then:
             - switch.turn_on: relay1
           else:
             - switch.turn_off: relay1


 - platform: gpio
   name: "Hood Button Level 2"
   pin:
     number: GPIO4
     inverted: True
     mode:
       INPUT_PULLUP
   filters:
     - delayed_on: 10ms
   id: H2H_Button_FanSpeed2
   on_press:
     then:
       - if:
           condition:
             - switch.is_off: relay2
           then:
             - switch.turn_on: relay2
           else:
             - switch.turn_off: relay2


 - platform: gpio
   name: "Hood Button Level 3"
   pin:
     number: GPIO0
     inverted: True
     mode:
       INPUT_PULLUP
   filters:
     - delayed_on: 10ms
   id: H2H_Button_FanSpeed3
   on_press:
     then:
       - if:
           condition:
             - switch.is_off: relay3
           then:
             - switch.turn_on: relay3 
           else:
             - switch.turn_off: relay3


 - platform: gpio
   name: "Hood Button Light on/off"
   pin:
     number: GPIO3
     inverted: True
     mode: INPUT_PULLUP
   filters:
     - delayed_on: 10ms
   id: H2H_Button_Light
   on_press:
     then:
       - if:
           condition:
             - switch.is_off: relay4
           then:
             - switch.turn_on: relay4
           else:
             - switch.turn_off: relay4



 - platform: remote_receiver
 # const long IRCMD_VENT_1 = 0xE3C01BE2 
 # Hob2hood On (level 1) raw code = {1538, 1342,  794, 1340,  2290, 1340,  790, 1346,  788, 652,  788, 1346,  794, 2040,  790}
   name: "Hob send: Level 1"
   raw:
     code:
       - 1538 
       - -1342  
       - 794 
       - -1340  
       - 2290 
       - -1340  
       - 790 
       - -1346 
       - 788 
       - -652  
       - 788 
       - -1346  
       - 794 
       - -2040  
       - 790


   filters:
     - delayed_off: 200ms
   on_press:
     - switch.turn_on: relay1
     - switch.turn_on: relay4

 - platform: remote_receiver
 # const long IRCMD_VENT_2 = 0xD051C301 
 # Hob2hood level 2      raw code = {1542, 1340,  790, 2738,  816, 2014,  3788, 2026,  2292}
   name: "Hob send: Level 2"
   raw:
     code:
       - 1542 
       - -1340  
       - 790 
       - -2738  
       - 816 
       - -2014  
       - 3788 
       - -2026  
       - 2292


   filters:
     - delayed_off: 200ms
   on_press:
     - switch.turn_on: relay2
     - switch.turn_on: relay4

 - platform: remote_receiver
 # const long IRCMD_VENT_3 = 0xC22FFFD7 
 # Hob2hood level 3      raw code = {790, 2042,  3036, 2730,  2290, 644,  790, 2042,  2286}
   name: "Hob send: Level 3"
   raw:
     code:
       - 790 
       - -2042  
       - 3036 
       - -2730  
       - 2290 
       - -644  
       - 790 
       - -2042  
       - 2286


   filters:
     - delayed_off: 200ms
   on_press:
     - switch.turn_on: relay3
     - switch.turn_on: relay4

 - platform: remote_receiver
 # const long IRCMD_VENT_4 = 0xB9121B29 
 # Hob2hood level 4      raw code = {1540, 2036,  1540, 650,  1540, 2034,  1542, 1340,  790, 2042,  794, 646,  1540}
   name: "Hob send: Level 4"
   raw:
     code:
       - 1540 
       - -2036  
       - 1540 
       - -650  
       - 1540 
       - -2034  
       - 1542 
       - -1340  
       - 790 
       - -2042  
       - 794 
       - -646  
       - 1540

   filters:
     - delayed_off: 200ms
   on_press:
     - switch.turn_on: relay3
     - switch.turn_on: relay4

 - platform: remote_receiver
 # const long IRCMD_LIGHT_ON = 0xE208293C 
 # Light on (Hood on)    raw code = {786, 1348,  790, 652,  1538, 648,  790, 1344,  784, 656,  1540, 2734,  790, 652,  790, 650,  1538}
   name: "Hob send: Light on"
   raw:
     code:
       - 786 
       - -1348
       - 790
       - -652  
       - 1538 
       - -648  
       - 790 
       - -1344  
       - 784 
       - -656 
       - 1540 
       - -2734 
       - 790 
       - -652 
       - 790 
       - -650 
       - 1538

   filters:
     - delayed_off: 200ms
   on_press:
     - switch.turn_on: relay4     

 - platform: remote_receiver 
 # const long IRCMD_LIGHT_OFF = 0x24ACF947
 # Light off (Automatic after 2min) raw code = {762, 1424,  770, 674,  764, 676,  760, 2172,  760, 680,  766, 1420,  766, 1420,  760, 682,  760}
   name: "Hob send: Light off"
   raw:
     code:
       - 762 
       - -1424 
       - 770  
       - -674 
       - 764 
       - -676 
       - 760  
       - -2172 
       - 760 
       - -680 
       - 766 
       - -1420 
       - 766 
       - -1420 
       - 760 
       - -682 
       - 760 
       
   filters:
     - delayed_off: 200ms
   on_press:
     - switch.turn_off: relay4 
     - switch.turn_off: relay1 
     - switch.turn_off: relay2 
     - switch.turn_off: relay3        

 - platform: remote_receiver
 #const long IRCMD_VENT_OFF = 0x55303A3 
 # Hob2hood off          raw code = {790, 1344,  786, 1350,  2290, 1340,  794, 1344,  1536, 2040,  794, 1344,  792, 650,  788}
   name: "Hob send: hood off"
   raw:
     code:
       - 790
       - -1344 
       - 786
       - -1350 
       - 2290 
       - -1340 
       - 794
       - -1344 
       - 1536
       - -2040
       - 794
       - -1344  
       - 792
       - -650 
       - 788 
       
   filters:
     - delayed_off: 200ms
   on_press:
     - switch.turn_off: relay1          
     - switch.turn_off: relay2     
     - switch.turn_off: relay3    
     - switch.turn_off: relay4    


# Switches
switch:
 - platform: gpio
   name: "Relay_FanSpeed1"
   pin: GPIO14
   inverted: False
   id: relay1
   on_turn_on:
     - switch.turn_off: relay2
     - switch.turn_off: relay3


 - platform: gpio
   name: "Relay_FanSpeed2"
   pin: GPIO12
   inverted: False
   id: relay2
   on_turn_on:
     - switch.turn_off: relay1
     - switch.turn_off: relay3


 - platform: gpio
   name: "Relay_FanSpeed3"
   pin: GPIO13
   inverted: False
   id: relay3
   on_turn_on:
     - switch.turn_off: relay1
     - switch.turn_off: relay2


 - platform: gpio
   name: "Relay_Light"
   pin: GPIO15
   inverted: False
   id: relay4
   on_turn_on:
     - switch.turn_on: relay4
   on_turn_off:
     - switch.turn_off: relay4  

2 Likes

+1 from my side. Still a thing i could not integrate in ESPHome.
Right now i am using a small tasmota device and openHAB.
Check out my tasmota config here.:

Hi, today I mange to make it work with ESPhome.
I have used raw codes and tolerance. (It has been impossible with NEC or other IR protocol)
My hood has only 3 speeds, so the speed 3 and 4, manages the relay 3.

Here is the code, I used a bit chatgpt, but it works fine, and also I have populated virtual buttons on home assistant.

Hope can help someone.






remote_receiver:
  pin:
    number: GPIO11
    inverted: true
    mode:
      input: true
      pullup: true
  dump: raw
  tolerance:
    type: percentage
    value: 30%

  on_raw:
    then:
      - lambda: |-
          if (x.size() < 5) return;
          // Patrons per encendre la llum
          std::vector<int> target_light = {759, -1380, 789, -653, 1512};
          int tolerance = 100;
          bool light_match = true;
          for (size_t i = 0; i < target_light.size(); i++) {
            if (abs(x[i] - target_light[i]) > tolerance) {
              light_match = false;
              break;
            }
          }

          if (light_match) {
            ESP_LOGI("remote", "🔆 Comanda d'encendre/apagar llum detectada!");
            id(light_on).execute();  // Activar/apagar llum
          }

          
          // Patró per apagar la llum
          std::vector<int> target_light_off = {792, -1349, 797, -646, 769, -676, 762, -2072, 796, -649, 764};
          //int tolerance = 100;  // Tolerància per les petites variacions
          
          bool light_off_match = true;
          for (size_t i = 0; i < target_light_off.size(); i++) {
            if (abs(x[i] - target_light_off[i]) > tolerance) {
              light_off_match = false;
              break;
            }
          }
          
          if (light_off_match) {
            ESP_LOGI("remote", "🔆 Comanda d'apagar llum detectada!");
            id(light_off).execute();  // Executar la funció per apagar la llum
          }
          


          // Patrons per la velocitat 1 del ventilador
          std::vector<int> target_fan_speed1 = {1511, -1377, 762, -1378, 2259, -1373, 764, -1377, 792};
          bool fan_speed1_match = true;
          for (size_t i = 0; i < target_fan_speed1.size(); i++) {
            if (abs(x[i] - target_fan_speed1[i]) > tolerance) {
              fan_speed1_match = false;
              break;
            }
          }

          if (fan_speed1_match) {
            ESP_LOGI("remote", "🌀 Comanda de velocitat 1 del ventilador detectada!");
            id(fan_speed1).execute();  // Executar script per activar la velocitat 1
          }

          // Patrons per la velocitat 2 del ventilador
          std::vector<int> target_fan_speed2 = {1512, -1376, 817, -2715, 736, -2101, 3761, -2064, 2287};
          bool fan_speed2_match = true;
          for (size_t i = 0; i < target_fan_speed2.size(); i++) {
            if (abs(x[i] - target_fan_speed2[i]) > tolerance) {
              fan_speed2_match = false;
              break;
            }
          }

          if (fan_speed2_match) {
            ESP_LOGI("remote", "🌀 Comanda de velocitat 1 del ventilador detectada!");
            id(fan_speed2).execute();  // Executar script per activar la velocitat 2
          }
          
          // Patrons per la velocitat 3 del ventilador
          std::vector<int> target_fan_speed3 = {817, -2017, 3039, -2739, 2293, -646, 760, -2076, 2287};
          bool fan_speed3_match = true;
          for (size_t i = 0; i < target_fan_speed3.size(); i++) {
            if (abs(x[i] - target_fan_speed3[i]) > tolerance) {
              fan_speed3_match = false;
              break;
            }
          }

          if (fan_speed3_match) {
            ESP_LOGI("remote", "🌀 Comanda de velocitat 3 del ventilador detectada!");
            id(fan_speed3).execute();  // Executar script per activar la velocitat 3
          }

          
          // Patrons per la velocitat 4 del ventilador
          std::vector<int> target_fan_speed4 = {1513, -2073, 1512, -677, 1510, -2075, 1535, -1349, 764, -2073, 765, -680, 1515};
          bool fan_speed4_match = true;
          for (size_t i = 0; i < target_fan_speed4.size(); i++) {
            if (abs(x[i] - target_fan_speed4[i]) > tolerance) {
              fan_speed4_match = false;
              break;
            }
          }

          if (fan_speed4_match) {
            ESP_LOGI("remote", "🌀 Comanda de velocitat 4 del ventilador detectada!");
            id(fan_speed3).execute();  // Executar script per activar la velocitat 4
          }

          // Patrons per aturar el ventilador
          std::vector<int> target_fan_off = {760, -1379, 763, -1376, 2259, -1376, 793, -1347, 1513};
          bool fan_off_match = true;
          for (size_t i = 0; i < target_fan_off.size(); i++) {
            if (abs(x[i] - target_fan_off[i]) > tolerance) {
              fan_off_match = false;
              break;
            }
          }

          if (fan_off_match) {
            ESP_LOGI("remote", "🛑 Comanda per aturar el ventilador detectada!");
            id(fan_off).execute();  // Executar script per apagar els ventiladors
          }










switch:
  - platform: gpio
    pin: GPIO2
    id: rel_vent1
    internal: true
    inverted: true
  - platform: gpio
    pin: GPIO3
    id: rel_vent2
    internal: true
    inverted: true
  - platform: gpio
    pin: GPIO4
    id: rel_vent3
    internal: true
    inverted: true




button:
  - platform: template
    name: "Ventilador OFF"
    icon: mdi:fan-off
    on_press:
      then:
        - script.execute: fan_off

  - platform: template
    name: "Ventilador Velocitat 1"
    icon: mdi:fan-speed-1
    on_press:
      then:
        - script.execute: fan_speed1

  - platform: template
    name: "Ventilador Velocitat 2"
    icon: mdi:fan-speed-2
    on_press:
      then:
        - script.execute: fan_speed2

  - platform: template
    name: "Ventilador Velocitat 3"
    icon: mdi:fan-speed-3
    on_press:
      then:
        - script.execute: fan_speed3



script:
  - id: fan_off
    mode: restart
    then:
      - switch.turn_off: rel_vent1
      - switch.turn_off: rel_vent2
      - switch.turn_off: rel_vent3

  - id: fan_speed1
    mode: restart
    then:
      - if:
          condition:
            switch.is_off: rel_vent1  # Comprovem si el relé de velocitat 1 està apagat
          then:
            - switch.turn_off: rel_vent2
            - switch.turn_off: rel_vent3
            - switch.turn_on: rel_vent1  # Si està apagat, l'engeguem

      
  - id: fan_speed2
    mode: restart
    then:
      - if:
          condition:
            switch.is_off: rel_vent2  # Comprovem si el relé de velocitat 2 està apagat
          then:
            - switch.turn_off: rel_vent1
            - switch.turn_off: rel_vent3
            - switch.turn_on: rel_vent2  # Si està apagat, l'engeguem

      
  - id: fan_speed3
    mode: restart
    then:
      - if:
          condition:
            switch.is_off: rel_vent3  # Comprovem si el relé de velocitat 3 està apagat
          then:
            - switch.turn_off: rel_vent1
            - switch.turn_off: rel_vent2
            - switch.turn_on: rel_vent3  # Si està apagat, l'engeguem

     


  # Script per encendre la llum
  - id: light_on
    mode: restart
    then:
      - light.turn_on: light_hood  # Aquesta línia engega la llum

  # Script per apagar la llum
  - id: light_off
    mode: restart
    then:
      - light.turn_off: light_hood  # Aquesta línia apaga la llum


light:
  - platform: binary
    name: "Llum Campana"
    id: light_hood
    output: light_output

output:
  - platform: gpio
    id: light_output
    pin: GPIO6
    inverted: true

2 Likes

Can you share also your hardware? wich remote_reciver and 4relay board did you used? I will replicate your configuration. Thanks a lot!

Hi, as a receiver I’m using this module based on TSOP38238:

and the relay module is the generic one with 4 relays (one for the light and three for the speeds) if you hod has 4 speeds, you’ll need an extra relay.
https://es.aliexpress.com/item/1005006280813881.html?spm=a2g0o.productlist.main.10.5d24Wp7pWp7pY0

Thanks a lot! I’m waiting for the delivery man now. :wink:

I doubt it. Genuine TSOP costs more than the whole module in AE.

Another Homeassitant controllable Hob2Hood Yaml for ESPHome

Ported that to ESPHome, thanks to @ibernat where i found some different raw codes for testing. I will replace the ESP12F in the YTF-IR-Bridge with a compatible ESP32 Module soon, because its lightweight, the IR Blaster is powerful (7 LEDs)

Thats my yaml
substitutions:
  device_name: ESP32-C3-SuperMini-IR-Blaster
  manufacturer: N/A
  model: ESP32-C3-SuperMini
  name: esp32-c3-supermini-ir-blaster
  encryption_key: "xxx"
  ota_encryption_key: "yyy"
  ap_fallback_pw: "zzz"
  wait_time: "50ms"
  ir_times: "3"

esphome:
  name: ${name}
  friendly_name: ${device_name}
  comment: Used to send IR Signals with ${model}

esp32:
  board: esp32-c3-devkitm-1
  framework:
    type: arduino

logger:

api:
  encryption:
    key: ${encryption_key}

ota:
  - platform: esphome
    password: ${ota_encryption_key}

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

  ap:
    ssid: ${name}
    password: ${ap_fallback_pw}

captive_portal:

bluetooth_proxy:
  active: true

remote_transmitter:
  pin: GPIO10
  carrier_duty_percent: 50%

button:
  - platform: restart
    name: "Restart"

  # Licht AN (L1)
  - platform: template
    id: hood_light_on
    internal: true
    on_press:
      - remote_transmitter.transmit_raw:
          code: [720, -1468, 722, -724, 1392, -748, 722, -1470, 718, -726, 1416, -2968, 696, -748, 696, -748, 1388]
          repeat:
            times: ${ir_times}
            wait_time: ${wait_time}

  # Licht AUS (L0)
  - platform: template
    id: hood_light_off
    internal: true
    on_press:
      - remote_transmitter.transmit_raw:
          code: [684, -1488, 658, -778, 684, -758, 686, -2278, 660, -788, 628, -1532, 688, -1504, 686, -786, 658]
          repeat:
            times: ${ir_times}
            wait_time: ${wait_time}

  # FAN 1 (F1)
  - platform: template
    id: hood_fan_1
    internal: true
    on_press:
      - remote_transmitter.transmit_raw:
          code: [1416, -1494, 722, -1570, 1974, -1510, 722, -1468, 726, -718, 724, -1468, 724, -2216, 696]
          repeat:
            times: ${ir_times}
            wait_time: ${wait_time}

  # FAN 2 (F2)
  - platform: template
    id: hood_fan_2
    internal: true
    on_press:
      - remote_transmitter.transmit_raw:
          code: [1444, -1470, 724, -2936, 726, -2240, 3502, -2198, 2142]
          repeat:
            times: ${ir_times}
            wait_time: ${wait_time}

  # FAN 3 (F3)
  - platform: template
    id: hood_fan_3
    internal: true
    on_press:
      - remote_transmitter.transmit_raw:
          code: [696, -2240, 2784, -2968, 2116, -750, 724, -2216, 2114]
          repeat:
            times: ${ir_times}
            wait_time: ${wait_time}

  # FAN 4 (F4)
  - platform: template
    id: hood_fan_4
    internal: true
    on_press:
      - remote_transmitter.transmit_raw:
          code: [1416, -2244, 1418, -722, 1418, -2216, 1418, -1470, 724, -2216, 722, -722, 1392]
          repeat:
            times: ${ir_times}
            wait_time: ${wait_time}

  # FAN OFF (F0)
  - platform: template
    id: hood_fan_off
    internal: true
    on_press:
      - remote_transmitter.transmit_raw:
          code: [720, -1468, 722, -1470, 2114, -1472, 722, -1470, 1416, -2218, 724, -1470, 724, -720, 698]
          repeat:
            times: ${ir_times}
            wait_time: ${wait_time}

output:
  - platform: template
    type: binary
    id: hood_light_switch
    write_action:
      - if:
          condition:
            light.is_on: hob2hood_light
          then:
            - button.press: hood_light_on
          else:
            - button.press: hood_light_off

light:
  - platform: binary
    id: hob2hood_light
    name: "Licht Dunstabzugshaube"
    icon: mdi:wall-sconce-flat
    output: hood_light_switch

fan:
  - platform: template
    name: "Lüfter Dunstabzugshaube"
    id: hob2hood_fan
    speed_count: 4
    on_turn_off:
      - button.press: hood_fan_off
      - lambda: |-
          // Immer beim Ausschalten auf Stufe 1 zurücksetzen
          auto call = id(hob2hood_fan).turn_off();
          call.set_speed(1);  // Speed 1 (25%)
          call.perform();
    on_turn_on:
      - button.press: hood_fan_1
      - lambda: |-
          // Immer beim Einschalten auf Stufe 1
          auto call = id(hob2hood_fan).turn_on();
          call.set_speed(1);  // Speed 1 (25%)
          call.perform();
    on_speed_set:
        - lambda: |-
            if (id(hob2hood_fan).state) {  // nur wenn Fan an ist!
              int speed = round(x);
              if (speed <= 1) {
                id(hood_fan_1).press();
              } else if (speed == 2) {
                id(hood_fan_2).press();
              } else if (speed == 3) {
                id(hood_fan_3).press();
              } else if (speed >= 4) {
                id(hood_fan_4).press();
              }
            }