Sonoff Ifan04 - ESPHome working code

I just did this with this GitHub - rh1rich/esphome-ifan04: Sonoff IFAN04 with ESPHome

Works perfectly.

Someone more qualified can answer why pin 3 is reused. I just found out how to disable the check.

@deschmit - The link that @Wheemer mentioned above does not reuse pin 3.

You know what they say if itā€™s not broken donā€™t fix it.

As for me, it was driving the people in my house nuts that the remote wouldnā€™t properly respond all the time. Nobody else in this thread seems to confirm this behavior or say they donā€™t use the remote enough for it to matter. To me that is broken. @ssieb told me that the old code defines the UART twice which may be the problem there. The code that rh1rich did does this as well but the remote works 99% of the time with 1 press which is better than barely ever. I made an issue on rh1richā€™s repo for it. Also, the ability shown above to reuse two buttons on the remote pretty easily, lets the little people in my house scared of the dark, turn the lights on downstairs from their room instead of waking others up to do that.

The only downfall to this code I see is the dev made this code and then disappeared. They Donā€™t seem to look at their GitHub issues or may be away on a long vacation UART conflict Ā· Issue #1 Ā· rh1rich/esphome-ifan04 Ā· GitHub So if you find anything wrong you are probably still on your own just like the other methods above to find a way to fix it.

Itā€™s been running pretty much fine all this time so far. I wouldnā€™t use anything else personally, specifically for the remote responsiveness. I had a few glitches where the remote randomly decided to pick one of the other speeds instead of the one you pressed. Not sure if this is a flaw in the code or the RF remote sending or not receiving the right bit to translate to the right action.

Hope this helps in your decision.

Nothing stops you from forking the project and place your version here and proclaim victory :slight_smile:
That is the beauty of opensource after all !

I personally do not use this code so my remote works!
I use:

external_components:
  - source: github://ssieb/custom_components
    components: [ ifan04 ]

Sure there is a version of that code here already !

The remote in my scenario is used as the primary switch for the room light so itā€™s noticeable if it doesnā€™t work 100% of the time. The controller is directly powered with the hotline no hardwired switch in between. The switch on the wall for the room wonā€™t turn the power to the controller off like most setups, so wondering if maybe people turning off the power to the unit all the time helps with also not seeing remote problems.

What does your full ESPHome YAML look like?

@NonaSuomy Would you mind helping guide me on getting a IFAN04-L flashed with esphome and adopted into my local Home Assistant installation? Iā€™m trying to replace a failed Insteon Fanlinc at our second home, which I am only physically at for the next few days. I donā€™t really care about remotes and/or particular flavors of esphome projects to use, as I just need to be able to automate fan speeds to match the other fans in the house. I soldered pins onto the board and have it physically connected to my Mac which has esphome on it. I am just a n00b at how to proceed from here and cannot find any examples of working yaml that I can use to get it going.

I recently went through this with my ifan04-L. I also donā€™t care about remotes at all.

GitHub - rh1rich/esphome-ifan04: Sonoff IFAN04 with ESPHome I just used the yaml there and went through the standard esphome install device install. Worked really well.

Have you installed with esphome before? Is your device already flashed to esphome or tasmota?

@haydon thank you for the response. Sounds like I want to do exactly what you did, including using that particular version from GitHub. I have esphome locally on my Mac, as well as on the Home Assistant box. I was trying to do the initial flash locally from the Mac and then figured Iā€™d adopt it on HA. Iā€™ve only done this process once before with a Bluetooth Proxy device, but it was so cookie cutter that I didnā€™t really learn about this process of doing a standard esphome device install. And, it was ethernet connected so I didnā€™t really have to deal with secrets like the wifi credentials, etc. Iā€™ve been trying to RTFM on esphomeā€™s web site but havenā€™t found a clear set of steps. If you have anything you can point me at, thatā€™d be awesome.

Yah this is quite different for sure. I did a bunch of sonoff s31 wall plugs first - that taught me the kinda weird approach esphome takes.
I also setup the esphome docker container on my nas (that has home assistant).

Esphome part is pretty easy - upload the header files and yaml to your docker continaerā€™s config directory, modify it for for your home - wifi etc. then manually download the image - itā€™ll compile it so youā€™ll know if it fails before you flash it.

then follow any flashing guide for the ifan04. Iā€™d strongly suggest spending the $10 on a sonoff s31 first and flashing that - itā€™s easier to test and you donā€™t need to install it in the fan to test (donā€™t put it back together - just remove the wires and plug it into an extnsion cord - so you can pull the cord out of mains power safely). Make sure you understand the process. (You could put it on your washer to sense when itā€™s done washing). Also take a dump of the memory before you flash so you have a working backupā€¦

As long as youā€™re on the same network you should be good, if youā€™ve set the name, encryption key, wifi SSID and password, you can always do an Over the air update to corect small config issues.

Just read my directions further up in the thread on how to manually backup and flash it. Itā€™s pretty basic as long as you have a regulator on your USB board which is stated above and shows pictures of what a regulator looks like.

@haydon @NonaSuomy thank you both for the assistance here. Worked like a charm!

2 Likes

Thanks again for the help on this! The device has been working great ā€“ flashed, fully installed in the fan, and integrated into Home Assistant. The feature set of the device works as expected, and was a great replacement for the failed Insteon FanLinc device.

There is one thing left to do, and I am unclear on how to do it. When I built and flashed the firmware, I did it from my personal Mac using a local install of esphome, with the device physically connected through the flasher to my Mac via USB-C. And, since the yaml file included Wi-Fi credentials, the device of course connected to the Wi-Fi network once it powered on. I was then able to adopt the device into Home Assistant and configured the ESPHome integration there for the device. But the device is not registered inside the ESPHome addon of Home Assistant, and so I canā€™t, for example, rebuild the firmware or update it. I feel like I should ā€œadoptā€ it into the ESPHome instance inside of my Home Assistant machine, so I can flash it again in the future, etc. And I am unclear on how to do thisā€¦

1 Like

The ESPHome device needs to be on the same network CIDR as the ESPhome plugin. This is because it uses broadcast to notify devices that itā€™s around.

So if your wifi is on a different network than your home assistant you will need to forward the broadcast packets. Then ESPHome interface will show it as a new device detected on the network.

Hey everyone. Looking to jump into getting ESPHome on my iFan04-L this weekend.

Looks like I have similar experience to @duerrd561 with doing Bluetooth proxies and a couple other simple things. Never flashed a device this way before, but Iā€™ve picked up a few things that it seemed like I would need. Let me know if this all looks right:



From what I understand,I just need to run cables to that adapter from that group of 4 contacts on the iFan04 PCB? Does it need to be connected to the wall/fan at all or can I just disconnect it and it gets power from the USB adapter for flashing?

I havenā€™t installed ESPHome to a device with a yaml config like this before but I think I can figure that part out when I get to it.

The last question is around functionality. From what Iā€™ve read it seems like everything from the original remote should just continue to work, and the only config changes that Iā€™ll really need to make is just network info and device name. Is that right?

I donā€™t think youā€™ll need the header pins (2nd pic). I used some wires from your first pic and chopped off the end one end and used the socket end to connect to the usb2ttl. Then Soldered to the fan04 temporarily (itā€™s super fiddily).

The ifan04 has pads so you either have to use a pin clamp (or similar setup) or just solder on as i mentioned.

Donā€™t forget to set hte voltage of the USB 2 TTL adapter correctly.

My Home Assistant and ESPHome device are on the exact same Wi-Fi network subnet, and Home Assistant totally sees the device and has it all setup. It just isnā€™t showing up (i.e. to be ā€œadoptedā€) in the ESPHome addon running on Home Assistant. Make sense?

Yup makes senseā€¦
Looks like others have experienced this problem before tooā€¦ Esphome devices not showing up on dashboard but are working - #7 by zoogara

Unfortunately I donā€™t have this setup - so will let others weigh in.

1 Like

Thanks! That was what I was looking for, and the thread you sent me to essentially has a solve/workaround which is to manually create the yaml file from my Macā€™s esphome directory into the config/esphome/ directory on HA. This makes total sense, and Iā€™m sure it would get me where I wanted.

One thing that I realize is probably a blocker on this specific device is the fact that I had to download a git clone of that rh1rich/esphome-ifan04 project and then I used the yaml from it to build this deviceā€™s firmware. And since that yaml file includes references to dependencies also in that git clone, I wouldnā€™t be able to get the exact same setup by just creating the yaml file on HA under config/esphome/ ā€“ Iā€™d need the dependencies as well.

I think something like this is what is needed:

packages:
  ifan04.esphome: github://rh1rich/esphome-ifan04/ifan04-test.yaml@main

However I donā€™t think the ifan04-test.yaml file is designed to work for this inheritance use case. Someone would probably need to port it to a new file that could then be imported as a package. Am I thinking about this correctly?

substitutions:
  device_name: office-fan
  device_displayname: Office Fan

esphome:
  name: $device_name
  friendly_name: $device_displayname
  includes:
    - ifan_remote.h

esp8266:
  board: esp8285
  framework:
    version: latest
  early_pin_init: true
  restore_from_flash: true

preferences:
  flash_write_interval: 5min

# Enable logging
# To use logging via uart (UART0 TX, GPIO01) you have to remove
# uart_bus and the IFanRemote custom text_sensor.
logger:
  baud_rate: 0
#  level: VERBOSE

# Enable Home Assistant API
api:
  encryption:
    key: "NOPE"

ota:
  password: "NOPE"

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

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Office-Fan Fallback Hotspot"
    password: "NOPE"

captive_portal:

web_server:
  port: 80

# GPIO00 ... Button
# GPIO01 ... UART0 TX
# GPIO03 ... UART0 RX (RF remote control)
# GPIO04 ... I2C SDA (TP11 D_RX on PCB backside)
# GPIO05 ... I2C SCL (TP10 D_TX on PCB backside)
# GPIO09 ... Light Relay (D7)
# GPIO10 ... Buzzer
# GPIO12 ... Fan Relay 2 (D11, 3uF cap on IFAN04-H)
# GPIO13 ... LED
# GPIO14 ... Fan Relay 1 (D5, 2.5uF cap on IFAN04-H)
# GPIO15 ... Fan Relay 3 (D13, no cap)

status_led:
  pin:
    number: GPIO13
    inverted: true

i2c:
  sda: GPIO04
  scl: GPIO05
  frequency: 200kHz

# UART configuration for the RF remote control
# Logging via uart must be disabled to use this.
uart:
  rx_pin: GPIO03
  baud_rate: 9600
  id: uart_bus

output:
  - platform: gpio
    id: light_relay
    pin:
      number: GPIO09
      inverted: true
  - platform: gpio
    id: buzzer
    pin:
      number: GPIO10
      inverted: true
  - platform: gpio
    id: fan_relay_1
    pin: GPIO14
  - platform: gpio
    id: fan_relay_2
    pin: GPIO12
  - platform: gpio
    id: fan_relay_3
    pin: GPIO15
  - platform: template
    id: fan_relays
    type: float
    write_action:
      - if: # Fan off
          condition:
            lambda: return (state < 0.3);
          then:
            - if:
                condition:
                  lambda: return id(buzzer_enabled).state;
                then:
                  - output.turn_on: buzzer
                  - delay: 300ms
                  - output.turn_off: buzzer
            - output.turn_off: fan_relay_1
            - output.turn_off: fan_relay_2
            - output.turn_off: fan_relay_3
      - if: # Fan low speed
          condition:
            lambda: return ((state >= 0.3) && (state < 0.6));
          then:
            - if:
                condition:
                  lambda: return id(buzzer_enabled).state;
                then:
                  - output.turn_on: buzzer
                  - delay: 50ms
                  - output.turn_off: buzzer
            - output.turn_off: fan_relay_3
            - output.turn_on: fan_relay_1
            - output.turn_on: fan_relay_2
            - delay: 5s
            - output.turn_off: fan_relay_2
      - if: # Fan mid speed
          condition:
            lambda: return ((state >= 0.6) && (state < 0.9));
          then:
            - if:
                condition:
                  lambda: return id(buzzer_enabled).state;
                then:
                  - output.turn_on: buzzer
                  - delay: 50ms
                  - output.turn_off: buzzer
                  - delay: 100ms
                  - output.turn_on: buzzer
                  - delay: 50ms
                  - output.turn_off: buzzer
            - output.turn_off: fan_relay_3
            - output.turn_on: fan_relay_1
            - output.turn_on: fan_relay_2
      - if: # Fan high speed
          condition:
            lambda: return (state >= 0.9);
          then:
            - if:
                condition:
                  lambda: return id(buzzer_enabled).state;
                then:
                  - output.turn_on: buzzer
                  - delay: 50ms
                  - output.turn_off: buzzer
                  - delay: 100ms
                  - output.turn_on: buzzer
                  - delay: 50ms
                  - output.turn_off: buzzer
                  - delay: 100ms
                  - output.turn_on: buzzer
                  - delay: 50ms
                  - output.turn_off: buzzer
            - output.turn_off: fan_relay_2
            - output.turn_off: fan_relay_3
            - output.turn_on: fan_relay_1
            - delay: 5s
            - output.turn_on: fan_relay_3
            - output.turn_off: fan_relay_1

light:
  - platform: binary
    name: 'Light'
    id: light_comp
    output: light_relay

fan:
  - platform: speed
    name: 'Fan'
    id: fan_comp
    output: fan_relays
    speed_count: 3

switch:
  - platform: template
    name: 'Buzzer enabled'
    id: buzzer_enabled
    entity_category: config
    optimistic: True
    restore_mode: RESTORE_DEFAULT_OFF

sensor:
  - platform: wifi_signal
    name: 'WiFi signal'
  - platform: uptime
    name: 'Uptime'
    unit_of_measurement: s

binary_sensor:
  - platform: gpio
    name: "Button"
    pin:
      number: GPIO00
      inverted: true

text_sensor:
  - platform: version
    name: 'ESPHome Version'

# Commands from the RF remote control are sent via
#  UART0 RX (= GPIO03)
# These commands are translated into hex strings
#  by the IFanRemote custom text_sensor (ifan_remote.h).
# The first 2 bytes (AA55) and the checksum byte
#  at the end, are removed.
#
# 1 (Light on/off)  = (AA55) 0104000104 (0A)
# 2 (Mute/buzzer)   = (AA55) 0106000101 (09)
# 3 (High speed)    = (AA55) 0104000103 (09)
# 4 (Medium speed)  = (AA55) 0104000102 (08)
# 5 (Fan off)       = (AA55) 0104000100 (06)
# 6 (Low speed)     = (AA55) 0104000101 (07)
# 7 (RF clearing)   = (AA55) 0101000102 (05)
# 8 (Wi-Fi pairing) = (AA55) 0101000102 (05)

  - platform: custom
    lambda: |-
      auto ifan_remote_sensor = new IFanRemote(id(uart_bus));
      App.register_component(ifan_remote_sensor);
      return {ifan_remote_sensor};
    text_sensors:
      name: 'RC command'
      on_value:
        then:
          - if: # Light on/off
              condition:
                lambda: return x == "0104000104";
              then:
                - light.toggle: light_comp
          - if: # Buzzer on/off
              condition:
                lambda: return x == "0106000101";
              then:
                - switch.toggle: buzzer_enabled
                - output.turn_on: buzzer
                - delay: 10ms
                - output.turn_off: buzzer
          - if: # Fan off
              condition:
                lambda: return x == "0104000100";
              then:
                - fan.turn_off: fan_comp
          - if: # Fan low speed
              condition:
                lambda: return x == "0104000101";
              then:
                - fan.turn_on:
                    id: fan_comp
                    speed: 1
          - if: # Fan mid speed
              condition:
                lambda: return x == "0104000102";
              then:
                - fan.turn_on:
                    id: fan_comp
                    speed: 2
          - if: # Fan high speed
              condition:
                lambda: return x == "0104000103";
              then:
                - fan.turn_on:
                    id: fan_comp
                    speed: 3

This is what iā€™m using for my yaml config. I also SSHed into esphome and uploaded the ifan_remote.h file to the config directory that also stores the yaml .