IKEA FÖRNUFTIG in Home-Assistant

Regarding your idea to add more steps:
I haven’t looked into this at all but I don’t see why it should not be possible. Scaling the return signal from the fan is one way to do it. Check out the pulse counter for reading the pulse from the PCB and PWM Output for generating a new signal. Not sure if the PWM output is able to go to a frequency that low.

Another idea would be to replace the PCB completely and drive the motor directly.
It may even be possible to keep it all the same and switch between setting 1 and 2 a few times every second. As this accelerates/decelerates the motor all the time it may wear out quite fast. So… not recommended.

I’m happy with the settings the original PCB offers. I use home-assistant to only let it run when there is no-one in the room so the noise is not an issue. Please give us an update if you dig deeper and find a way to add additional steps.

I’m actually still stuck on getting the board working as you have, I flashed my Esp8266 but as soon as I started it with the wires attached I only get a solid light and no response on the serial port.

I tried two chips, so I can rule out a chip failure - so I guess I connected something wrong :thinking:

I only used the connections to the board and cut the knob’s connections from the board. I haven’t soldered them to the Esp8266 since I won’t use the knob anyway.


Regarding my idea: I actually would like to have HA run a PID controller, so I can set it to something like 0 as a target and it will adjust the fan speed as necessary.

This would of course require more than just 3 steps, as setting 2 feels already too noisy and 1 is too little to keep my office “clean”, after venting some outside air through the windows.

Can you do me a favour and record the duty cycles and the frequency of the PWM to the motor on each step? :slight_smile:

And if I go ahead with the replacement I might just add a differential pressure sensor to see how much resistance the filter creates.

Not sure if this is maybe how the motor signal is used originally, as the duty cycle will request a known good RPM. And if the fan cannot reach it, it will set the filter lamp to on.

Can someone test this theory by taping the outlet up to like 90% and run the fan on high?

If the filter lamp turns on after a while we could test which frequency the chip expect the fan to do at least.

@Habbie hey, can you assist a bit here? I would like to have the energy consumption send to HA with the timestamp of the last measurement in the last_reset field, to avoid having to store the value persistent… or count in memory and have the first valid synced time after boot send out to HA as last_reset and then start doing the accounting in memory…

Is there a chance to do this in ESPHome?

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.

1 Like

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?