Did you pair the remote before or after adding ESPHome to the device?
Maybe I will try to flash it back to the factory firmware and try to pair it from there…
./esptool --chip esp8266 -p /dev/ttyUSB1 write_flash 0x0 ifan04lfwbackup001-1.bin
Did you pair the remote before or after adding ESPHome to the device?
Maybe I will try to flash it back to the factory firmware and try to pair it from there…
./esptool --chip esp8266 -p /dev/ttyUSB1 write_flash 0x0 ifan04lfwbackup001-1.bin
Yay I got it!
[04:07:36][D][uart_debug:158]: <<< "\xAAU\x01\x04\x00\x01\x04\n"
[04:07:36][D][light:035]: 'Master Bedroom Fan Light' Setting:
[04:07:36][D][light:046]: State: ON
[04:07:36][D][IFAN04:101]: light trigger
[04:07:37][D][uart_debug:158]: <<< "\xAAU\x01\x04\x00\x01\x04\n"
[04:07:37][D][light:035]: 'Master Bedroom Fan Light' Setting:
[04:07:37][D][light:046]: State: OFF
[04:07:37][D][IFAN04:101]: light trigger
You have to have VAC connected or the 433MHz receiver won’t listen.
You have to hit the button on the remote while the fan controller first starts from being plugged into VAC. (Battery thing didn’t work)
I paired it with the stock firmware reflashed to the device (yay my backup worked).
After flashing ESPHome back it also kept the pair (So the pair is kept on the 433MHz receiver. Nothing to do with the ESP).
I will try to pair the 3rd controller from ESPHome now that I know what I’m doing.
Both bottom buttons on the remote are the same for some reason would have been nice to have two different extra buttons to use for something fun.
Left bottom:
|04:28:28|[D]|[ifan04:077]|unknown command type 1 param 2|
|04:28:28|[D]|[uart_debug:158]|<<< "\xAAU\x01\x01\x00\x01\x02\x05"|
Right bottom:
|04:28:30|[D]|[ifan04:077]|unknown command type 1 param 2|
|04:28:30|[D]|[uart_debug:158]|<<< "\xAAU\x01\x01\x00\x01\x02\x05"|
Edit: Tried from ESPHome and it worked as well.
Not sure if it’s just my fan but I seem to have to enable multiple capacitors in the fan to make the medium/high speed work properly. My low speed was basically the same as my medium speed. If you have this same issue you may need to enable multiple relays in the controller code.
You can make the changes at your own risk by editing this file after forking the github then editing the file below then change hfuller/cpyarger/ssieb in your yaml include to your own github name.
ssieb made the RF433 code.
cpyarger modified that.
hfuller fixed the annoying beep on boot.
nonasuomy (mine was forked from the hfuller code) Note: Capacitor changes.
void IFan::set_med() {
digitalWrite(relay_1, HIGH);
digitalWrite(relay_2, HIGH);
digitalWrite(relay_3, LOW);
beep(2);
}
void IFan::set_high() {
digitalWrite(relay_1, HIGH);
digitalWrite(relay_2, LOW);
digitalWrite(relay_3, HIGH);
beep(3);
}
No changes really.
substitutions:
name: ifan-bedroom-001
friendly_name: Master Bedroom
external_components:
- source: github://nonasuomy/custom_components@master
refresh: 0s
esphome:
name: ${name}
comment: Sonoff iFan04-L
# This will allow for (future) project identification,
# configuration and updates.
project:
name: cpyarger.sonoff-ifan04-l
version: "1.0"
esp8266:
board: esp01_1m
# Disable logging on serial as it is used by the remote
logger:
baud_rate: 0
# Enable Home Assistant API
api:
services:
- service: fan_cycle
then:
- fan.cycle_speed: the_fan
encryption:
key: !secret encryption_key001
ota:
password: !secret ota_pass001
uart:
tx_pin: GPIO01
rx_pin: GPIO03
baud_rate: 9600
#debug:
dashboard_import:
package_import_url: github://cpyarger/esphome-templates/sonoff-ifan04-l.yaml@main
captive_portal:
binary_sensor:
- platform: gpio
id: button_light
pin: GPIO0
on_press:
then:
- light.toggle: fan_light
output:
- platform: esp8266_pwm
id: led_pin
pin: GPIO13
inverted: true
light:
- platform: ifan
id: fan_light
name: "${friendly_name} Light"
- platform: monochromatic
id: led1
output: led_pin
default_transition_length: 0s
restore_mode: always off
button:
- platform: template
name: ${friendly_name} Cycle Fan
on_press:
then:
- fan.cycle_speed: the_fan
fan:
- platform: ifan
id: the_fan
name: "${friendly_name} Fan"
remote_enable: false
buzzer_enable: false
ifan04:
on_fan:
- lambda: |-
auto call = speed ? id (the_fan).turn_on() : id (the_fan).turn_off();
call.set_speed(speed);
call.perform();
on_light:
- light.toggle: fan_light
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
use_address: !secret use_address001
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Ifan04-001 Fallback Hotspot"
password: !secret fallbackhotspot001
web_server:
This is a nice button row for this fan controller instead of a bogus slider/toggle:
Documentation settings:
hacs → frontend → + Explore & Download Repositories → Fan Percent Button Row → Download
Add Card → Manual (at the bottom) → Card Configuration (Make sure to remove type: ‘’ default entry) then paste:
type: entities
title: Bedroom Fans
show_header_toggle: false
entities:
- entity: light.master_bedroom_light
- entity: fan.master_bedroom_fan
type: custom:fan-percent-button-row
name: Master Bedroom
reverseButtons: true
customTheme: true
isOnLowColor: rgb(255, 0, 0)
isOnMedColor: '#888888'
isOnHiColor: '#222222'
buttonInactiveColor: '#aaaaaa'
isOffColor: purple
Thanks to everyone here I now have my ifan04 working through esphome. An added step I have is to use an openhasp display/switch to control the fan. For anyone else that needs it,I mimic the buttons in the fan percent row card
Here is the code:
plate jsonl
{"page":1,"id":10,"obj":"btn","x":5,"y":30,"w":55,"h":55,"toggle":true,"text":"\uE210 Off","text_font":24,"mode":"break","align":1}
{"page":1,"id":11,"obj":"btn","x":65,"y":30,"w":55,"h":55,"toggle":true,"text":"\uE210 Low","text_font":24,"mode":"break","align":1}
{"page":1,"id":12,"obj":"btn","x":125,"y":30,"w":55,"h":55,"toggle":true,"text":"\uE210 Med","text_font":24,"mode":"break","align":1}
{"page":1,"id":13,"obj":"btn","x":185,"y":30,"w":55,"h":55,"toggle":true,"text":"\uE210 High","text_font":24,"mode":"break","align":1}
configuration yaml
- obj: "p1b10"
properties:
"val": '{{ 1 if states("fan.bedroom_fan") == "on" else 0 }}'
"text": '{{ "\uE210 On" if is_state("fan.bedroom_fan", "on") else "\uE210 Off" | e }}'
event:
"down":
- service: homeassistant.toggle
entity_id: "fan.bedroom_fan"
- service: fan.set_percentage
entity_id: "fan.bedroom_fan"
data:
percentage: 0
- obj: "p1b11"
properties:
"val": '{{1 if states("fan.bedroom_fan") == "on" and is_state_attr("fan.bedroom_fan", "percentage", 33) else 0 }}'
"text": '{{ "\uE210 Low" if is_state("fan.bedroom_fan", "on") else "\uE210 Low" | e }}'
event:
"down":
- service: fan.set_percentage
entity_id: "fan.bedroom_fan"
data:
percentage: 33
- service: homeassistant.turn_on
entity_id: "fan.bedroom_fan"
- obj: "p1b12"
properties:
"val": '{{1 if states("fan.bedroom_fan") == "on" and is_state_attr("fan.bedroom_fan", "percentage", 66) else 0 }}'
"text": '{{ "\uE210 Med" if is_state("fan.bedroom_fan", "on") else "\uE210 Med" | e }}'
event:
"down":
- service: fan.set_percentage
entity_id: "fan.bedroom_fan"
data:
percentage: 66
- obj: "p1b13"
properties:
"val": '{{1 if states("fan.bedroom_fan") == "on" and is_state_attr("fan.bedroom_fan", "percentage", 100) else 0 }}'
"text": '{{ "\uE210 High" if is_state("fan.bedroom_fan", "on") else "\uE210 High" | e }}'
event:
"down":
- service: fan.set_percentage
entity_id: "fan.bedroom_fan"
data:
percentage: 100
- service: homeassistant.turn_on
entity_id: "fan.bedroom_fan"
I feel like the LOW MID HIGH logic is wrong.
EDIT: I should read more before posting, NonaSumony posted the same 2 months ago lol.
The code above puts Low as relay 1, Mid as Relay 2, and High as Relay 3. But if you do that Mid is almost the same speed as low is.
I looked up the Tasmota code for the same device, and it has Low as Relay 1, Mid as Relay 1 AND 2, and High as Relay 1 AND 3. Doing that change on my local repo has made a big difference.
Pull request for this change here:
On another note, anyone know a good way to put the fan in high only for a second when starting up give it a boost? Like if the fan goes from is off and its then set to Mid, the Fan actually goes from OFF->HIGH (2 seconds) → MID. So it spins up faster.
cpyarger is MIA, the pr will probably sit there for a while. Essentially the 04-L model was supposed to fix the slow speed issue. We shouldn’t need to do this alas these modules are not the greatest. They should nix the capacitor switching to remove the hum and just properly integrate with just the relays to replace the pull chain switching but most users probably wouldn’t want to take that on. As usually there are multiple coils in the motor that they switch to for speed changes. We’re basically just cutting all that out and only operating with the fast coil with voltage drops which were never meant to run at slower speeds.
I’m not sure how this will go down but you could try some simple Arduino modifications with a delay(ms); also note use at your own risk not sure how much it will like to ramp fast to slow like that. I can understand going slow to fast for longevity reasons.
Try this though:
void IFan::set_med() {
// Ramp up to high speed.
digitalWrite(relay_1, HIGH);
digitalWrite(relay_2, LOW);
digitalWrite(relay_3, HIGH);
beep(3);
delay(10000); // Delay 10 seconds.
// Ramp down to medium speed.
digitalWrite(relay_1, HIGH);
digitalWrite(relay_2, HIGH);
digitalWrite(relay_3, LOW);
beep(2);
}
(Try at your own risk) I found two spots you may be able to solder a small lead to. Maybe add some hot glue to your wires as well to not rip the pads off the board. You can use them for I2C or extra pins for fun. I don’t believe they are connected to anything besides these test points on the back of the board. Sonoff told me they are not connected to anything but these test points.
iFan04 ESP8285 Pinout
GPIO00 - Button
GPIO01 - TX (labelled wrong as RX) Also connected to the RF Remote IC
GPIO02 - N/C
GPIO03 - RX (labelled wrong as TX) Also connected to the RF Remote IC
Note: I think these test points are also on the older models as well. Not sure if connected to the same pins though.
GPIO04 - TP11 D_RX (SDA)
GPIO05 - TP10 D_TX (SCL)
GPIO06 - N/C
GPIO07 - N/C
GPIO08 - N/C
GPIO09 - Relay Light
GPIO10 - Buzzer
GPIO11 - N/C
GPIO12 - Relay 2 Fan Medium
GPIO13 - LED
GPIO14 - Relay 1 Fan Low
GPIO15 - Relay 3 Fan High
GPIO16 - N/C
iFan04 OB38R08 Microcontroller Pinout
Note: Do not use these SDA/SCL header pins at the top of the board as they are not connected to the ESP and are connected to the OB38R08 IC. (3v3/GND should be ok to use up there for your sensor modules)
PIN9(SDA)
PIN10(SCL)
iFan04 backside of PCB
SDA/SCL circled in red.
Few Ideas
Example ESPHome YAML for BME280
# Define the I2C device for iFan04 to the Test Points on the back of the board.
# GPIO04 - TP11 D_RX (SDA)
# GPIO05 - TP10 D_TX (SCL)
i2c:
id: i2c_component
sda: 4
scl: 5
scan: true
sensor:
- platform: bme280
temperature:
name: "BME280 Temperature"
oversampling: 16x
pressure:
name: "BME280 Pressure"
humidity:
name: "BME280 Humidity"
address: 0x77
update_interval: 60s
Note: Caution high voltage! Do not setup like this! For quick testing purposes only!
Log
[01:32:17][C][i2c.arduino:039]: SDA Pin: GPIO4
[01:32:17][C][i2c.arduino:040]: SCL Pin: GPIO5
[01:32:17][C][i2c.arduino:041]: Frequency: 50000 Hz
[01:32:17][C][i2c.arduino:044]: Recovery: bus successfully recovered
[01:32:17][I][i2c.arduino:054]: Results from i2c bus scan:
[01:32:17][I][i2c.arduino:060]: Found i2c device at address 0x77
[01:32:17][C][bme280.sensor:174]: BME280:
[01:32:17][C][bme280.sensor:175]: Address: 0x77
[01:32:17][C][bme280.sensor:187]: IIR Filter: OFF
[01:32:17][C][bme280.sensor:188]: Update Interval: 60.0s
[01:32:17][C][bme280.sensor:190]: Temperature 'BME280 Temperature'
[01:32:17][C][bme280.sensor:190]: Device Class: 'temperature'
[01:32:17][C][bme280.sensor:190]: State Class: 'measurement'
[01:32:17][C][bme280.sensor:190]: Unit of Measurement: '°C'
[01:32:17][C][bme280.sensor:190]: Accuracy Decimals: 1
[01:32:17][C][bme280.sensor:191]: Oversampling: 16x
[01:32:17][C][bme280.sensor:192]: Pressure 'BME280 Pressure'
[01:32:17][C][bme280.sensor:192]: Device Class: 'pressure'
[01:32:17][C][bme280.sensor:192]: State Class: 'measurement'
[01:32:17][C][bme280.sensor:192]: Unit of Measurement: 'hPa'
[01:32:17][C][bme280.sensor:192]: Accuracy Decimals: 1
[01:32:17][C][bme280.sensor:193]: Oversampling: 16x
[01:32:17][C][bme280.sensor:194]: Humidity 'BME280 Humidity'
[01:32:17][C][bme280.sensor:194]: Device Class: 'humidity'
[01:32:17][C][bme280.sensor:194]: State Class: 'measurement'
[01:32:17][C][bme280.sensor:194]: Unit of Measurement: '%'
[01:32:17][C][bme280.sensor:194]: Accuracy Decimals: 1
[01:32:17][C][bme280.sensor:195]: Oversampling: 16x
[01:32:17][C][IFAN:032]: IFan 'Master Bedroom Fan'
[01:32:35][D][api.connection:917]: Home Assistant 2022.11.1 (IP): Connected successfully
[01:32:36][D][sensor:126]: 'BME280 Temperature': Sending state 23.73000 °C with 1 decimals of accuracy
[01:32:36][D][sensor:126]: 'BME280 Pressure': Sending state 978.19110 hPa with 1 decimals of accuracy
[01:32:36][D][sensor:126]: 'BME280 Humidity': Sending state 52.13184 % with 1 decimals of accuracy
Nice it worked
You can’t use delay like that. Everything will stop working and you’ll likely trigger the WDT to reboot the device.
Have you tested that?
You would know better than I with ESPHome. I believe Arduino core wise delay(); triggers esp8266 yield(); behind the scenes which keeps it from hanging and allow it to do tasks like keeping WiFi up.
Otherwise, maybe do something like this instead:
You are blocking the loop()
function which means that no other components can do anything.
I assume you’re referring to this:
Remember that there is a lot of code that needs to run on the chip besides the sketch when WiFi is connected. WiFi and TCP/IP libraries get a chance to handle any pending events each time the
loop()
function completes, OR whendelay
is called. If you have a loop somewhere in your sketch that takes a lot of time (>50ms) without callingdelay
, you might consider adding a call todelay
function to keep the WiFi stack running smoothly.
The part you’re missing is the “besides the sketch”. All of esphome is in “the sketch”. So you are blocking all of esphome’s functions. No sensor updates, no binary sensor triggers, no communication with HA, etc.
Not missing any part as to why I said you would know better about the ESPHome parts.
I fully understand what you mean as to why I also offered the BlinkWithoutDelay URL above.
Here is a modified example of how that may work:
// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0; // Will store last time relay ramp was updated
// Constants won't change:
const long interval = 10000; // 10 second interval at which to trigger the relay ramp (milliseconds)
bool rampmed = false;
void IFan::set_med() {
// Ramp up to high speed.
digitalWrite(relay_1, HIGH);
digitalWrite(relay_2, LOW);
digitalWrite(relay_3, HIGH);
beep(3);
rampmed = true;
}
void loop() {
//... other code ...
if (rampmed) {
// Check to see if it's time to ramp down the relays; that is, if the difference
// between the current time and the last time you ramped the relays is bigger than
// the interval at which you want to ramp the relays.
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// Save the last time you ramped the relays.
previousMillis = currentMillis;
// Ramp down to medium speed.
digitalWrite(relay_1, HIGH);
digitalWrite(relay_2, HIGH);
digitalWrite(relay_3, LOW);
beep(2);
rampmed = false;
}
}
}
…Guess that wouldn’t totally work as the loop wouldn’t call it again without hitting the button again haha. I’ll leave that one for him to further invest time into. Would probably have to add a boolean tracker that will just run in the loop and then rest itself after it runs.
Edit: Fixed the code for fun (not tested) play at your own risk @DelusionalAI .
Edit: Confirmed with @ssieb in discord which they replied with: “Yes, that’s a good way to do it.”
I2C wiring modification:
Note: The pin attached to the ground plane sinks a lot of heat and is pretty hard to solder to.
If anyone has trouble fitting this plastic case in the fan mounting bracket:
You can dremel/sand about half a mill off each bottom side of the Isosceles Trapezium and it may fit as the case is wider at the bottom than the top looking from the short end:
Worked for me your results may vary…
I2C 16 I/O Expander for fan light basic wall switch
I2C Backplane for Environment Sensor and 16 I/O Expander
YAML
i2c:
id: i2c_component
sda: 14
scl: 16
scan: true
# pcf8574 I2C 16 I/O Expander
pcf8574:
- id: 'pcf8574_hub'
address: 0x20
pcf8575: true
switch:
- platform: restart
name: "T-PoE Restart"
- platform: gpio
name: "PCF8574 Pin #1"
pin:
pcf8574: pcf8574_hub
# Use pin number 1
number: 1
# One of INPUT or OUTPUT
mode:
output: true
inverted: false
- platform: gpio
name: "PCF8574 Pin #2"
pin:
pcf8574: pcf8574_hub
# Use pin number 2
number: 2
# One of INPUT or OUTPUT
mode:
output: true
inverted: false
binary_sensor:
- platform: gpio
name: "Input_0"
pin:
pcf8574: pcf8574_hub
number: 0
mode: INPUT
inverted: False
Log
[05:56:18][C][i2c.arduino:039]: SDA Pin: GPIO14
[05:56:18][C][i2c.arduino:040]: SCL Pin: GPIO16
[05:56:18][C][i2c.arduino:041]: Frequency: 50000 Hz
[05:56:18][C][i2c.arduino:044]: Recovery: bus successfully recovered
[05:56:18][I][i2c.arduino:054]: Results from i2c bus scan:
[05:56:18][I][i2c.arduino:060]: Found i2c device at address 0x20
[05:56:18][C][pcf8574:021]: PCF8574:
[05:56:18][C][pcf8574:022]: Address: 0x20
[05:56:18][C][pcf8574:023]: Is PCF8575: YES
[05:56:18][C][switch.gpio:050]: GPIO Switch 'PCF8574 Pin #1'
[05:56:18][C][switch.gpio:051]: Pin: 1 via PCF8574
[05:56:18][C][switch.gpio:073]: Restore Mode: Restore (Defaults to OFF)
[05:56:18][C][switch.gpio:050]: GPIO Switch 'PCF8574 Pin #2'
[05:56:18][C][switch.gpio:051]: Pin: 2 via PCF8574
[05:56:18][C][switch.gpio:073]: Restore Mode: Restore (Defaults to OFF)
[05:56:18][C][gpio.binary_sensor:015]: GPIO Binary Sensor 'Input_0'
[05:56:18][C][gpio.binary_sensor:016]: Pin: 0 via PCF8574
[05:56:26][D][binary_sensor:036]: 'Input_0': Sending state ON
[05:56:27][D][binary_sensor:036]: 'Input_0': Sending state OFF
Two methods of operation thanks to Kraxman
YAML
binary_sensor:
# Physical button on the iFan04-L for testing not related to the PCF8575.
- platform: gpio
id: button_light
pin: GPIO0
on_press:
then:
- light.toggle: fan_light
# PCF8575 enabled basic light switch.
- platform: gpio
name: "Input_0"
pin:
pcf8574: pcf8574_hub
number: 0
mode: INPUT
inverted: true
# Method 1: If the light is on turn it off, if the light is off turn it on, if another source changes the light
# and the physical is in opposite state ignore and leave the current state.
on_press:
then:
- light.turn_on: fan_light
on_release:
then:
- light.turn_off: fan_light
# Method 2: 3-Way Light Switch Emulation.
#on_press:
# then:
# - light.toggle: fan_light
#on_release:
# then:
# - light.toggle: fan_light
# Method 2.1: Same as 2 just a different process.
# on_state:
# then:
# - light.toggle: fan_light
Hi All looks like some great work has gone on in here since I first had a go at this
Time for a new fan for me so time to add another Sonoff - I’ve got a Hunter fan that came with the usual RF remote add on kit that you see in the US but inside the wiring loom of the fan I found there was 1 additional capacitor & i’m wondering if I can remove it and then just use the 3 found inside the ifan for speed control.
I have seen inisde the older pullcord types that have 2 or 3 but this new fan has no cords for lights or fan speed just the reverse switch and 1 cap is using the RF remote for all controls.
I should be ok to just cut it out and join the wiring ?
Thanks
All the fans I have been in have a capacitor in them like that. Usually you add the sonoff controller in addition to what is there. What I would do is find where the controller is in that fan and remove it and connect the Sonoff to the same wires where it was. As they usually all operate on the same principle wires Motor/Light/Neutral.
NonaSuomy - I used your experience and finally got mine working! So thank you, and the other contributors, for all of your work! Has anyone considered or tried getting Alexa/Google Home integration to control the speed of the fan(s)? Currently with Alexa turning on the fan works but only on the maximum speed. It would be great to be able to say Low/Med/High. Clearly it’s already coded based on the lovelace card Low/Med/High buttons, how do you translate that to a voice command. This is all new to me and I’m not quite sure how to work on it and/or where to start. Is it in the YAML or part of the github code?
This is assuming you already have Alexa setup in HA. Install the Alexa app on your mobile device and do something like this:
Step 1.)
Step 2.)
Step 3.)
Step 4.) Click create routine…
Step 5.)
Step 6.) Click add action…
Step 7.)
Step 8.)
Step 9.)
Step 10.)
Step 11.)
Received my iFan04 tonight. No matter what I’ve tried, I cannot get it to flash any code whatsoever.
Anyone have any documented, reliable suggestions for flashing this board?
It helps when you power the board with 110VAC.
Also helps when you depress the button while applying the power.
It finally flashed.
I had the same problem you did Fred. I think it’s post #57 where NonaSuomy documented he had issues with flashing and it only worked with 110v.
As a side note, sonoff 1ch relays work fine with 3.3v applied, sonoff 4ch relays need 110v.