I don’t know the answer but i can confirm that all fan speed works for me (however I can’t turn off the fan by the knob)
What do you see in the ESPHome log?
I don’t know the answer but i can confirm that all fan speed works for me (however I can’t turn off the fan by the knob)
What do you see in the ESPHome log?
I’ve also replaced the whole board with a wemos D1 mini with the wiring diagram Nierit posted above, plus I have also added a standard rotary encoder in place of the 4 pos switch, which fits nicely on top. It turns the speed up and down and acts as a on/off toggle button.
Also I managed to read the speed of the fan, although I have no clue about how many steps the encoder does per revolution, the reading of the fan-tacho seems a tad high.
I have measured the speed of the fan using my phone in slowmo mode and have adjusted the multiplier in the pulse counter so it would read correct rounds per minute of the fan.
Additionally there was a problem with the configuration where the PWM wouldn’t switch off, I’ve managed to fix this by adding zero_means_zero = true
to the config of the pwm output pin.
I’ve spent a few hours with the yaml today so I figured it’s best to share
Here’s a wiring diagram made by @Montaneste which he graciously allowed me to share:
and here’s my yaml config:
esphome:
name: "fornuftig"
esp8266:
board: d1_mini
# Enable logging
logger:
# Enable Home Assistant API
api:
ota:
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Fornuftig-AP"
password: ""
captive_portal:
output:
- platform: esp8266_pwm
pin: D1
frequency: 150 Hz
id: pwm_output
min_power: 0.5
max_power: 0.5
zero_means_zero: true
fan:
- platform: speed
output: pwm_output
name: "Fornuftig Air Purifier"
id: "fornuftig_fan"
restore_mode: RESTORE_DEFAULT_OFF
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: |-
id(set_fan_freq).publish_state(id(fornuftig_fan).speed);
on_turn_off:
- output.esp8266_pwm.set_frequency:
id: pwm_output
frequency: !lambda 'return int(0);'
- logger.log: "Fan Turned Off!"
sensor:
- platform: rotary_encoder
name: "Rotary Encoder"
pin_a:
number: D5
inverted: false
mode:
input: true
pullup: true
pin_b:
number: D6
inverted: false
mode:
input: true
pullup: true
on_clockwise:
- logger.log: "Turned Clockwise"
- lambda: |-
if(!id(fornuftig_fan).state && id(fan_speed) == 20) {
auto call = id(fornuftig_fan).turn_on();
call.perform();
} else if(id(fan_speed) < 100) {
auto call = id(fornuftig_fan).turn_on();
call.set_speed(id(fan_speed)+2);
call.perform();
}
on_anticlockwise:
- logger.log: "Turned Anticlockwise"
- lambda: |-
if (id(fan_speed) > 20) {
auto call = id(fornuftig_fan).turn_on();
call.set_speed(id(fan_speed)-2);
call.perform();
} else if (id(fan_speed) <= 20) {
auto call = id(fornuftig_fan).turn_off();
call.perform();
}
- platform: pulse_counter
pin:
number: D2
mode: INPUT_PULLUP
unit_of_measurement: 'RPM'
id: fan_tach
name: Fornuftig Fanspeed
filters:
- multiply: 0.06
- 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 > 5) { // limit low frequency
return 60;
} else if(x <= 5) {
return 0;
} else {
return x;
}
} else {
return 0;
}
on_value:
then:
- output.esp8266_pwm.set_frequency:
id: pwm_output
frequency: !lambda 'return int(x);'
- logger.log: "on_value called"
- 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();
}
binary_sensor:
- platform: gpio
pin:
number: D7
mode:
input: true
pullup: true
name: "Toggle Fan"
on_press:
then:
- fan.toggle: "fornuftig_fan"
- logger.log: "Clicked"
globals:
- id: fan_speed
type: int
restore_value: yes
initial_value: '0'
Hi, i’ve done all steps but i´m only getting 1 speed (slowest) and the rotary switch doesn’t work too…
Any help?
Thks
Hi,
For the fellas using the PWM version: (actually it’s not PWM, since the fan speed reacts on frequency of the input signal).
Both scripts above seems a bit strange. First one doesn’t switch the fan completely off, the second script does switch the fan off, but somehow the knob turns doesn’t really work well here.
Also the RPM sensor seems a bit weird. I used another factor for this, though based on guessing
If there’s someone around with a tachometer, please
I combined both scripts, everything seems to work well for me now. I changed the initial power on RPM to use the value it was set on in HA (instead of speed_1, 33%).
Also changed the minimum freqnuency to 36 Hz, at this point my fan starts turning. Might be safer to put it a bit higher if needed.
Always room for enhancements, credits to the other posters!
Regards,
Patrick
captive_portal:
output:
- platform: esp8266_pwm
pin: D1
frequency: 150 Hz
id: pwm_output
min_power: 0.5
max_power: 0.5
zero_means_zero: true
fan:
- platform: speed
output: pwm_output
name: "Fornuftig Air Purifier"
id: "fornuftig_fan"
restore_mode: RESTORE_DEFAULT_OFF
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: |-
id(set_fan_freq).publish_state(id(fornuftig_fan).speed);
on_turn_off:
- output.esp8266_pwm.set_frequency:
id: pwm_output
frequency: !lambda 'return int(0);'
- logger.log: "Fan Turned Off!"
sensor:
- platform: pulse_counter
pin:
number: D2
mode: INPUT_PULLUP
unit_of_measurement: 'RPM'
accuracy_decimals: 0
id: fan_tach
name: Fornuftig Fanspeed
filters:
- multiply: 0.1
- 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 < 36 && x > 3) { // limit low frequency
return 36;
} 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);'
- logger.log: "on_value called"
- 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();
}
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);'
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: '33'
- id: speed_2
type: int
restore_value: yes
initial_value: '66'
- id: speed_3
type: int
restore_value: yes
initial_value: '100'
What kind of rotary encoder did you use?
Yes I’ve mentioned that the tach-speed is a bit off
I have also mentioned that I changed the 4 pos-switch which was wrongly named an encoder to a true rotatry encoder with totally different wiring. I removed the original ikea-pcb completely as it’s not necessary in any way with my implementation.
oh and I have also added some decoupling capacitors to the the encoder pins on my wemos D1 to make sure there’s no false inputs. The internal pull-ups are a bit too weak without decoupling, and i’d also recommend use external pull-ups for the encoder, although I got away without them and just use decoupling caps.
Hi,
I understand now That’s the reason of the different code in the yaml file for the “knob”.
Got it working without the capacitors or pullups now, with the original knob.
Only thing left is the RPM, not really important (totally not) but would like to see a “correct-ish” value
Keep up the good work!
Patrick
regarding rpm, yeah me too
by the way, I’ve scoped the original pcb and found that at minimum rpm setting there is a brief turn on period that outputs 200hz which then lowers down to 100hz, and if there’s no rpm sensed on the tach-pin it turns off completely.
Ok so I went ahead, set the fanspeed to 20% (60hz) and filmed the fan in slowmotion, it turned out one revolution took 0.25s resulting 240rpm. The raw-reading of the pulse counter returns 4000, so the resulting scaling factor should be 0.06.
Please fee free to repeat my experiment and report back in case you find an error
Heheh that’s a way of doing it
Dear all! As I mentioned in my previous post, I was thinking about to test a custom PCB for this project mainly to avoid messy wires under the housing.
My PCBs have finally arrived and they are working great so far! The main idea was to make a longer board (ca. 130mm) and place the Wemos D1 mini at the end. I also added a 1A fuse for safety purposes as the original board had one. You can see I installed the D1 mini upside-down as I didn’t want to push the metal shield too close to the top of the case. I think the board fits just well inside. It cost me around 8$ for 5 pcs (including shipping, but without components like esp8266, voltage divider, rotary encoder, fuse, soldering iron, pins etc) that seems reasonable as I have multiple air purifiers at home.
Any feedback is appreciated. Later I’m going to upload more pictures. If anyone interested I can share the PCB design with the community (Gerber file or I think there is an option to share the whole project with EasyEda. First, I need to figure out how to do it)
Link to open source project:
Simple Smart Control Panel for IKEA Förnuftig Air Purifiers - EasyEDA open source hardware lab (oshwlab.com)
This is great. Any recommendation on where to order the PCB from and you ordered the parts you have used?
cheers
btw. i can see there is an order option from the EasyEDA editor; however, that seems not to work…?
just add this sensor to esphome config
- platform: total_daily_energy
name: "Total Daily Energy"
power_id: power_usage
it needs the time component eg.
time:
- platform: homeassistant
id: homeassistant_time
Hi! just fried my pcb… Is your mod possible without decoupling caps or anything extra? Just your wemos and converter connected straight to förnuftig? And maby add the rotary encoder after. Just to see if it works?
/Carl
Hi. are you using decoupling caps? Or is your PCB only connecting the wemos, rotary encoder, and converter to the förnuftig without the decoupling caps?
/Carl
When I designed the PCB the cheapest manufacturer was JLCPCB so I ordered from them. I’m quite satisfied with the result, the PCB material looks of a high quality. You don’t need EasyEDA, just upload the so called ‘Gerber’ file to any manufacturers website you like
Unfortunately you can’t order it assembled as i didn’t add all of the components to the PCB. So you can order only the plain PCB and you should buy and solder the items on it. (Please note that it has a pretty large ground plane thus soldering GNDs need extra patience )
No, i didn’t use decoupling caps
nice work!
Could you provide a list of items needed (e.g. the fuse, d1mini, etc)?
Thanks