IKEA FÖRNUFTIG in Home-Assistant

I found the issue in my setup - I accidentally pushed two wires together on installation.

I’m not sure if this damaged the d1 mini or what, but if I enable my D4 pin it will only turn on the LED.

I switched the ports and it’s fine now :slight_smile:

I know way too little about ESPHome to be useful in this case, sorry! I suggest trying the ESPHome Discord.

Good to hear you were able to solve the issue.

I removed the LED as I needed all the ports available on an ESP8266 and the LED was connected to one of them. So at one setting (I don’t remember which one) the LED was always on.

Sorry, I can’t help with further investigations as my FÖRNUFTIG is kinda “productive” and I don’t have another one to toy around with.

@tht well my works now, so everything is fine :slight_smile:
I would just recommend to not use D4 as it won’t work (if I haven’t just fried some connection - is a bit since I soldered the last time :D)

Hey Habbie, thanks anyway. I figured it out. Using last_reset is actually problematic as it is already deprecated anyway.

So here’s how you get the Energy Consumption from the Förnuftig into your Energy Dashboard:

Add these two additional sensors:

sensor:
  - platform: template
    name: '$friendly_name - Power consumption'
    id: power_consumption
    device_class: power
    state_class: measurement
    unit_of_measurement: 'W'
    accuracy_decimals: 1
    update_interval: 0s
  - platform: integration
    name: "$friendly_name - Consumed Energy"
    sensor: power_consumption
    time_unit: 'h'
    device_class: energy
    state_class: total_increasing
    unit_of_measurement: 'Wh'
    restore: false
    integration_method: left

And expand the fanout internal template with the consumption values, as @tht showed before (my pins are different than yours):

  - platform: template
    id: fan_out_internal
    type: float
    write_action:
      if:
        condition:
          lambda: 'return state < 0.1;'
        then:
          - output.turn_off: gpio_d5
          - output.turn_off: gpio_d7
          - output.turn_off: gpio_d6
          - sensor.template.publish:
              id: power_consumption
              state: 0.1

        else:
          - if:
              condition:
                lambda: 'return state < 0.4;'
              then:
                - output.turn_on:  gpio_d5
                - output.turn_off: gpio_d7
                - output.turn_off: gpio_d6
                - sensor.template.publish:
                    id: power_consumption
                    state: 1.5
              else:
                - if:
                    condition:
                      lambda: 'return state < 0.7;'
                    then:
                      - output.turn_off: gpio_d5
                      - output.turn_on:  gpio_d7
                      - output.turn_off: gpio_d6
                      - sensor.template.publish:
                          id: power_consumption
                          state: 6.5
                    else:
                      - output.turn_off: gpio_d5
                      - output.turn_off: gpio_d7
                      - output.turn_on:  gpio_d6
                      - sensor.template.publish:
                          id: power_consumption
                          state: 15

Only limitation is, that the statistics will only be calculated and pushed to HA if you set a fan speed. So if you want to push it like once a minute you need an interval timer, like I used in the config for the Vindriktning. It’s just a bit complex for my liking, so I stick with an automation which just sends a fan speed setting depending on the Vindriktning sensor reading. :slight_smile:

On the idea of driving the fan directly I have just found an article:
https://blog.sarine.nl/2021/07/22/making-stupid-smart.html

If anyone is experienced with the PWM modul of ESPhome, could help me piece out a config for that. It should allow us gradually control the fan curve.

Have a look here

Graphs comparing PM1006 (in the unmodified IKEA setup including the automatic fan management) to an SDS011 (set to 1 minute intervals with the ESPHome driver) - in every picture, the PM1006 is purple (usually the bottom line). These results are not as terrible as I’ve seen other people report!

1 Like

So far I have managed to send any preset frequency to the fan, and its spins on various speed based on that, but I cannot figure out how to modify this on the the fly, lets say with a slide in HA

esphome:
  name: $devicename
  platform: ESP8266
  board: d1_mini

substitutions:
  devicename: esp82-fornuftig1
  friendly_name: FORNÜFTIG

# Insert your SSID and Your PWD after inital setup
wifi:
  networks:
    - ssid: "myssid"
      password: "mypass"
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Airfilteresp Fallback Hotspot"
    password: "pass"


# Enable logging
logger:
  logs:
      # Make adc input less verbose
      adc: INFO

# Enable Home Assistant API
api:
  password: xxxxxxxxxxx

# Enable OTA upgrade
ota:
  safe_mode: True
  password: "e5a460b498b3a7a1471b4cc7a443e45d"

output:
  - platform: esp8266_pwm
    pin: D1
    frequency: 50 Hz
    id: pwm_output


fan:
 - platform: speed
   output: pwm_output
   id: fan_internal
   name: "$friendly_name Fan"

I’m pretty sure its something with

- output.esp8266_pwm.set_frequency:

here ESP8266 Software PWM Output — ESPHome but I’m too novice for this.

Has the fan entity in HA not got a speed slider ?

I think your PWM frequency needs to be higher, maybe 1000Hz, this is a constant.

The Speed Fan does the speed adjustment

Hey everyone.

Are you not supposed to cut the unused leg of the encoder?
I cut all 5 legs on that side and connected the required 4 to the ESP8266.
However, I’m having issues with the manual control. WIFI control works great!

Encoder Position 1 results in speed 1, D1: L, D5: H, D6: L, D7: L. It should be off.
Encoder Position 2 results in speed 2, D1: L, D5: L, D6: H, D7: L. It should be speed 1.
Encoder Position 3 results in speed 2, D1: L, D5: L, D6: H, D7: L. Correct
Encoder Position 4 results in speed 3, D1: L, D5: L, D6: L, D7: H. Correct

Positions 1 and 2 aren’t behaving as intended.

Thanks for your help,
Dan

Great project!
I just wanted to add this for posterity since it stumped me for a while: I used a MP2315 step down converter (using it to step down to 3.3V) and a Wemos D1 Mini, and I couldn’t flash the D1 Mini after soldering all the wires. I just got this error:
A fatal error occurred: Failed to connect to Espressif device: Timed out waiting for packet header
I was able to flash the firmware when i plugged in the 24V power supply of the fan. Don’t know why this happens but it does! So try plugging in the power supply if you are experiencing problems with the initial flashing.

Did anyone of you use a 5V <-> 3.3V level shifter, as Wemos use 3.3V GPIO and Förnuftig is at 5V.
I don’t want to fry my Wemo and was wondering about that.

1 Like

Somewhat of a stupid question but how did you wire up the fan following the guide in Making the stupid dumb. Vindriktning and Förnuftig - Qball's Weblog? Having never wired up a PWM fan before I really don’t want to let out the magic smoke and it’s really hard to see from the pictures in that guide.

Hi, how do you set up automation to set the speed of the fan? Thanks

lul


:arrow_down: Rotary switch (optional)

esphome:

output:
  - platform: esp8266_pwm
    pin: D1
    frequency: 150 Hz
    id: pwm_output
    min_power: 0.5
    max_power: 0.5
    
fan:
  - platform: speed
    output: pwm_output
    name: "Fornuftig Air Purifier"
    id: "fornuftig_fan"
    on_speed_set:
      lambda: |-
        if(id(fornuftig_fan).speed != id(fan_speed) && id(fornuftig_fan).state){
          id(fan_speed) = id(fornuftig_fan).speed;
          id(set_fan_freq).publish_state(id(fornuftig_fan).speed);
        }
    on_turn_on:
      lambda: |-
        if(id(fornuftig_fan).speed > 15){
          id(set_fan_freq).publish_state(id(fornuftig_fan).speed);
        }else{
          id(set_fan_freq).publish_state(id(speed_1));
        }
    on_turn_off:
      - output.esp8266_pwm.set_frequency:
          id: pwm_output
          frequency: !lambda 'return int(0);'
    
binary_sensor:
  - platform: template
    id: 'knob_0'
    filters:
      - delayed_on_off: 300ms
    lambda: |-
      if (!id(knob_1).state && !id(knob_2).state && !id(knob_3).state) {
        return true;
      } else {
        return false;
      }
    on_press: 
      lambda: |-
        if(!id(speed_0)){
          auto call = id(fornuftig_fan).turn_off();
          call.perform();
        }else{
          auto call = id(fornuftig_fan).turn_on();
          call.set_speed(id(speed_0));
          call.perform();
        }

  - platform: gpio
    id: 'knob_1'
    pin:
      number: D7
      mode: INPUT_PULLUP
      inverted: true
    filters:
      - delayed_on_off: 100ms
    on_press: 
      then:
        - fan.turn_on:
            id: fornuftig_fan
            speed: !lambda 'return id(speed_1);'
    
    
  - platform: gpio
    id: 'knob_2'
    pin:
      number: D6
      mode: INPUT_PULLUP
      inverted: true
    filters:
      - delayed_on_off: 100ms
    on_press: 
      then:
        - fan.turn_on:
            id: fornuftig_fan
            speed: !lambda 'return id(speed_2);'
  
  
  - platform: gpio
    id: 'knob_3'
    pin:
      number: D5
      mode: INPUT_PULLUP
      inverted: true
    filters:
      - delayed_on_off: 100ms
    on_press:
      then:
        - fan.turn_on:
            id: fornuftig_fan
            speed: !lambda 'return id(speed_3);'
    
    
      
      
sensor:
  - platform: template
    id: set_fan_freq
    filters:
      - multiply: 3
      - lambda: |-
          if (id(fornuftig_fan).state){
            if(x > 300){ // limit max frequency
              return 300;
              
            }else if(x < 60 && x > 3){ // limit low frequency
              return 60;
              
            } else if(x <= 3){
              return 0;
              
            } else {
              return x;
              
            }
          }else{
            return 0;
          }
    on_value:
      then:
        - output.esp8266_pwm.set_frequency:
            id: pwm_output
            frequency: !lambda 'return int(x);'
        - lambda: |- 
            // send current status to homeassistant
            if(x){
              auto call = id(fornuftig_fan).turn_on();
              call.set_speed(int(x)/3);
              call.perform();
            }else{
              auto call = id(fornuftig_fan).turn_off();
              call.perform();
            }



    
  - platform: homeassistant
    id: ha_fornuftig_speed_0
    entity_id: input_number.fornuftig_speed_0
    on_value:
      - globals.set:
          id: speed_0
          value: !lambda 'return int(x);'
          
          
  - platform: homeassistant
    id: ha_fornuftig_speed_1
    entity_id: input_number.fornuftig_speed_1
    on_value:
      - globals.set:
          id: speed_1
          value: !lambda 'return int(x);'
         
         
  - platform: homeassistant
    id: ha_fornuftig_speed_2
    entity_id: input_number.fornuftig_speed_2
    on_value:
      - globals.set:
          id: speed_2
          value: !lambda 'return int(x);'
        
        
  - platform: homeassistant
    id: ha_fornuftig_speed_3
    entity_id: input_number.fornuftig_speed_3
    on_value:
      - globals.set:
          id: speed_3
          value: !lambda 'return int(x);'
        
        
        
globals:
  - id: fan_speed
    type: int
    restore_value: yes
    initial_value: '0'

  - id: speed_0
    type: int
    restore_value: yes
    initial_value: '0'
    
  - id: speed_1
    type: int
    restore_value: yes
    initial_value: '55'
    
  - id: speed_2
    type: int
    restore_value: yes
    initial_value: '65'
    
  - id: speed_3
    type: int
    restore_value: yes
    initial_value: '100'
    

homeassistant:

input_number:
  fornuftig_speed_0:
    name: 'Fornuftig Speed 0'
    min: 0
    max: 100
    step: 1
    mode: slider
    unit_of_measurement: '%'
    icon: mdi:air-filter
  fornuftig_speed_1:
    name: 'Fornuftig Speed 1'
    min: 0
    max: 100
    step: 1
    mode: slider
    unit_of_measurement: '%'
    icon: mdi:air-filter
  fornuftig_speed_2:
    name: 'Fornuftig Speed 2'
    min: 0
    max: 100
    step: 1
    mode: slider
    unit_of_measurement: '%'
    icon: mdi:air-filter
  fornuftig_speed_3:
    name: 'Fornuftig Speed 3'
    min: 0
    max: 100
    step: 1
    mode: slider
    unit_of_measurement: '%'
    icon: mdi:air-filter
3 Likes

Thanks for the instructions, mine is modified now as well :slight_smile:

I used thick silicone double-sided tape and it’s holding firmly. I put 3.3V regulator because that’s what I had lying around.

I tried to replace D0 with D8, but that didn’t work for some reason.
Also, if compiling with A0 as sensor, it must be soldered as well, otherwise WiFi won’t work properly and ESP will boot loop.

Why is it necessary to cut the rotary switch legs if the original board is only used to hold it in place? Or does it interfere with the ESP and provide unreliable readings?

The rotary switch does short one of the outputs to ground, depending on the setting. The original board scans all the inputs (from highest setting to off) and controls the motor accordingly. So if you don0t cut the logs, the switch will fight the ESP when setting the speed. Disconnecting the legs gives full control to the ESP.

Ah sorry, it was a reply to the PWM method which doesn’t power on the original board anymore. I measured the legs and at least for the PWM method it should work without cutting them anymore.