Sonoff IFan02 (Tasmota) MQTT Fan

Hi, I dont know if anyone is familiar with the Ifan 02 by Sonoff but I’m trying to get it to work with HASS using the MQTT Fan implementation.

A brief background on the IFan02. It’s a replacement fan controller that enables you to control the fan speed and also toggle the led lights in the fan.

My reason for implementing this in HASS is so that I can control remotely from my mobile phone and in the near future, use Alexa to control the fan.

My current implementation. I created two separate entities: one for the led light control and one for the fan. The LED light control implementation is really straightforward and it works as expected but the fan control is a bit imperfect in my opinion. This is the config.yaml code for the fan:

fan:

  • platform: mqtt
    name: “Bedroom Fan”
    command_topic: “cmnd/ceilingfan_firzan/fanspeed”
    speed_command_topic: “cmnd/ceilingfan_firzan/fanspeed”
    speed_state_topic: “stat/ceilingfan_firzan/RESULT”
    qos: 0
    payload_off: “OFF”
    payload_low_speed: “LOW”
    payload_medium_speed: “MED”
    payload_high_speed: “HIGH”
    speed_value_template: ‘{{value_json.FanSpeed}}’
    speeds:
    • off
    • low
    • medium
    • high

The issue I’m facing is that the fan is at either of the 3 speeds (basically in an ON state), the state of the fan entity is always OFF. This means that even if the fan is on, the state of the fan entity in HASS is off BUT the speed of the entity is correct (matches the state MQTT of the fan - LOW, MEDIUM, HIGH). So, what I would like help with is a fix, either to my code implementation in the config.yaml (due to my error) or a change in the code on HASS’ side. I’m not sure how to contribute solving the issue but I can try out solutions offered!

1 Like

Hi,

There’s a example of how to configure it on tasmota page, here: https://github.com/arendst/Sonoff-Tasmota/wiki/Home-Assistant (last example).

It seems that there is a tricky part because the fan reports its speed and assume that if its >=1 then the fan is on but for HA speed and on/off are two different things so you have to use a template which do this “translation”.

I ended up modifying the info from that page a little and I think it works better for me.

Here is my code:

- platform: mqtt  
    name: "Master Bedroom Fan"
    command_topic: "cmnd/sonoff_MBR_fan/FanSpeed"
    speed_command_topic: "cmnd/sonoff_MBR_fan/FanSpeed"    
    state_topic: "stat/sonoff_MBR_fan/RESULT"
    speed_state_topic: "stat/sonoff_MBR_fan/RESULT"
    state_value_template: "{% if value_json.FanSpeed == 0 -%}0{%- elif value_json.FanSpeed > 0 -%}4{%- endif %}" 
    speed_value_template: "{{ value_json.FanSpeed }}"
    availability_topic: tele/sonoff_MBR_fan/LWT
    payload_off: "0"
    payload_on: "4"
    payload_low_speed: "1"
    payload_medium_speed: "2"
    payload_high_speed: "3"
    payload_available: Online
    payload_not_available: Offline
    speeds:
      - low
      - medium
      - high

I think there was something weird about the indication of the fan speed when you turned the light off & on. My change above fixed it for me.

I also used a custom_ui for the display of the fan controls from this thread:

I had to tweak that code a little bit (with a little help) to get it just right but this is what I ended up with in the end:

ex

all the speeds display correctly as you click on the buttons.

The changes I made to the code is referenced in the thread.

@finity

Thanks for posting this. I was an early purchaser, against my better judgement since I prefer to be a late adopter b/c less headache. The custom component is very nice. Just got it working. This is my first exposure to custom-ui so everything seemed a little foreign/.

I am getting an error from HA b/c of my current value template. Are you still seeing this error in HA?

Error parsing value: 'dict object' has no attribute 'FanSpeed' (value: {"POWER1":"ON"}, template: {% if value_json.FanSpeed == 0 -%}0{%- elif value_json.FanSpeed > 0 -%}4{%- endif %})

Also Are you suffering the same issue as me and others with the light on after restore power? I came up with a rules based approach that works fundamentally, but I think it will problematic on mqtt drops. Its in one of the github issues

Yeah, I get that same error but to be honest I forgot all about it until you mentioned it because it hasn’t had any effect on operation.

I’ve been messing around with the template for a bit today trying to get rid of the error and I’ve been moderately successful. the problem is that I can get rid of the error but then my buttons don’t update for the speed display properly. It always shows “off” but I haven’t been able to figure out why yet. Here’s what I’ve tried so far:

state_value_template: >
  {% if value_json.FanSpeed is defined %}
    "{% if value_json.FanSpeed == 0 -%}0{%- elif value_json.FanSpeed > 0 -%}4{%- endif %}"
  {% else %}
    "{% if states('fan.master_bedroom_fan.attributes.speed') == 'off' -%}0{%- elif states('fan.master_bedroom_fan.attributes.speed') != 'off' -%}4{%- endif %}" 
  {% endif %}

I added an “off” speed to the speeds list.

I also tried it with just the first “if” statement thinking it would try to update the value at all if the statement didn’t evaluate to true:

state_value_template: >
  {% if value_json.FanSpeed is defined %}
    "{% if value_json.FanSpeed == 0 -%}0{%- elif value_json.FanSpeed > 0 -%}4{%- endif %}"
  {% endif %}

Neither way works tho.

I’m pretty sure the problem is that I have no idea how to test the Fanspeed value is being returned.

I’ll keep poking at it unless someone has any other ideas.

I think it needs an elif at the end for power1 on and off. Just a hunch. Can we use pass in the imposed state in a template?

I’m not sure I understand.

Examples?

@finity
I was thinking something like this

{% if value_json.FanSpeed == 0 -%}0{%- elif value_json.FanSpeed > 0 -%}4{%- elif 
value_json.POWER1 == "ON" -%}
{%- elif value_json.POWER1 == "OFF" -%}{%- endif %}

I wondered if it would template without a value after the if and it does. If it didn’t, I was thinking pass (from python) might work.

If this is the mqtt message, maybe it would quash the error if we gave it a meaningless dict value that fit the mqtt messages (listed below):

stat/iFan1/POWER1 ON
cmnd/iFan1/POWER1 OFF
stat/iFan1/RESULT {"POWER1":"OFF"}
stat/iFan1/POWER1 OFF

EDIT: It’s the conditional "value_json.FanSpeed > 0 " that causes the error to be thrown and this keeps any abberant statement like POWER1 from reaching an else endpoint. I’m not really clear how to get around this hurdle and keep everything working. .

@finity
Something tells me that we’re going at the fan component wrong and that’s why it’s giving the error. While the error is innocuous, it says that something isn’t right the way it’s set up.

My understanding of it is that because tasmota published all results to one topic and that topic includes both light and fan, the fan component fails. It’s weird because it’s parsing the JSON incorrectly and trying to read the “POWER1”:“ON” component as fanspeed. To me, this seems like a problem on the HA end but I’m not familiar enough with the codebase to try to find why it parses incorrectly.

If you agree, I guess we should think about reporting an issue on github.

I didnt like the fan component/card so I set it up with switches, automation, script and input_number

the switches

- platform: mqtt
  name: "Room Two FanLight"
  command_topic: "cmnd/sonoffifan/roomtwo/power1"
  state_topic: "stat/sonoffifan/roomtwo/POWER1"
  optimistic: false
  qos: 1
  payload_on: "ON"
  payload_off: "OFF"
  retain: false  
- platform: mqtt
  name: "Room Two FanSpeed1"
  command_topic: "cmnd/sonoffifan/roomtwo/result/fanspeed"
  state_topic: "stat/sonoffifan/roomtwo/RESULT"
  optimistic: false
  qos: 1
  payload_on: 1
  payload_off: 0
  value_template: '{%- if value_json.FanSpeed == 1 -%}1{%- elif value_json.FanSpeed == 2 or value_json.FanSpeed == 3 or value_json.FanSpeed == 0 -%}0{%- endif -%}'
  retain: false  
- platform: mqtt
  name: "Room Two FanSpeed2"
  command_topic: "cmnd/sonoffifan/roomtwo/result/fanspeed"
  state_topic: "stat/sonoffifan/roomtwo/RESULT"
  optimistic: false
  qos: 1
  payload_on: 2
  payload_off: 0
  value_template: '{%- if value_json.FanSpeed == 2 -%}2{%- elif value_json.FanSpeed == 1 or value_json.FanSpeed == 3 or value_json.FanSpeed == 0 -%}0{%- endif -%}'
  retain: false
- platform: mqtt
  name: "Room Two FanSpeed3"
  command_topic: "cmnd/sonoffifan/roomtwo/result/fanspeed"
  state_topic: "stat/sonoffifan/roomtwo/RESULT"
  optimistic: false
  qos: 1
  payload_on: 3
  payload_off: 0
  value_template: '{%- if value_json.FanSpeed == 3 -%}3{%- elif value_json.FanSpeed == 1 or value_json.FanSpeed == 2 or value_json.FanSpeed == 0 -%}0{%- endif -%}' 
  retain: false

The input number

office_fan:
  name: Fan Speed
  initial: 0
  min: 0
  max: 3
  step: 1
  mode: slider
  unit_of_measurement: step
  icon: mdi:fan

the automaiton

- id: office_fan_presets
  alias: Office fan input slider
  trigger:
  - platform: state
    entity_id: input_number.office_fan
  action:
  - service_template: script.office_fan_speed_{{ trigger.to_state.state|int }}

scripts

office_fan_speed_0:
  sequence:
  - service: switch.turn_off
    entity_id: switch.room_two_fanspeed1
office_fan_speed_1:
  sequence:
  - service: switch.turn_on
    entity_id: switch.room_two_fanspeed1
office_fan_speed_2:
  sequence:
  - service: switch.turn_on
    entity_id: switch.room_two_fanspeed2
office_fan_speed_3:
  sequence:
  - service: switch.turn_on
    entity_id: switch.room_two_fanspeed3

I’ve posted another thread trying to get some help working this out:

But so far I’m not figuring out why it’s not working.

What’s really strange is that even with the error popping up the fan component isn’t really technically “failing”. everything still works. It just complains that the message doesn’t contain the “FanSpeed” key.

Aside from figuring out how to prevent the log entry from popping up I’m not even sure it’s worth trying to put much more time into it. :thinking:

And I’m not even sure it’s an “issue” since the error is actually valid.

I’ll try some more things tho to see if I can get it worked out.

Appreciate the effort. I’m thinking the problem might be in the MQTT fan component. JSON parsers shouldn’t look at other keys, but I can understand why it would throw an error if it wasn’t in the dictionary. I’ve tried several times to add it to the dictionary using the template various ways but nothing has worked.

Just to finalize this thread, here is the code that works correctly and gets rid of the json error:

- platform: mqtt  
    name: "Master Bedroom Fan"
    command_topic: "cmnd/sonoff_MBR_fan/FanSpeed"
    speed_command_topic: "cmnd/sonoff_MBR_fan/FanSpeed"    
    state_topic: "stat/sonoff_MBR_fan/RESULT"
    speed_state_topic: "stat/sonoff_MBR_fan/RESULT"
    state_value_template: >
      {% if value_json.FanSpeed is defined %}
        {% if value_json.FanSpeed == 0 -%}0{%- elif value_json.FanSpeed > 0 -%}4{%- endif %}
      {% else %}
        {% if states.fan.master_bedroom_fan.state == 'off' -%}0{%- elif states.fan.master_bedroom_fan.state == 'on' -%}4{%- endif %}
      {% endif %}
    speed_value_template: "{{ value_json.FanSpeed }}"
    availability_topic: tele/sonoff_MBR_fan/LWT
    payload_off: "0"
    payload_on: "4"
    payload_low_speed: "1"
    payload_medium_speed: "2"
    payload_high_speed: "3"
    payload_available: Online
    payload_not_available: Offline
    speeds:
      - off
      - low
      - medium
      - high

I ended up having to remove the " from inside the “if” statement but I’m still not sure exactly why.

Thanks to @gpbenton in the other thread for helping me work thru this.

5 Likes

man! That is so many if statements we can call it AI. Tested just now and works great. Just formatted the block a little different:

  state_value_template: >-
                        {% if value_json.FanSpeed is defined %}
                            {% if value_json.FanSpeed == 0 -%}0
                            {%- elif value_json.FanSpeed > 0 -%}2
                            {%- endif %}
                        {%- else -%}
                            {% if states.fan.iFan1.state == 'off' -%}0
                            {%- elif states.fan.iFan1.state == 'on' -%}2
                            {%- endif %}
                        {%- endif %}
1 Like

This would be great to merge into the iFan02 entry on the Tasmota wiki!

1 Like

Did it yesterday. Used Finity post as the reference. Anyone can edit the wiki, so feel free. :smile:

@jumblies

That’s weird. So did I…:thinking:

Thanks for the info, I was annoyed by this error.
Another thing I suggest adding to the configuration is querying the fan state at startup, since tasmota send different topic for telemetry and command result, if HASS is restarted while the fan is on, it will never update with the correct status unless a command is issued.
To over come this I add the following to the automations:

- id: Startup_Automations
  alias: Startup Automations
  hide_entity: True
  trigger:
    platform: homeassistant
    event: start
  action:
   - service: mqtt.publish
     data:
      topic: 'cmnd/sonoff_MBR_fan/FanSpeed'
      payload: ''

This will send a command at startup to request the current fan speed.

Another nice option is to use packages folder so the fan configuration can be under one file, example at:
https://www.home-assistant.io/docs/configuration/packages/

1 Like

Thanks for the suggestion on the query at startup but I’m already doing that. That was something I found out about over on the tasmota ifan02 issues thread.

I haven’t spent any time trying to figure out packages yet. Maybe I will someday as it looks like a way to uncomplicated things a bit.

@finity
I missed this. I wonder if we’re editing different wiki pages. I put mine on the iFan page. Did you put yours on the HA page? If so, Probably clearer for me to link to yours there? Open source documentation is messy enough and if we can just have one working template, I think it’ll reduce user frustration.

I have this unit in my gym and what I want is if there is a humidity and/or temp differential between floor and ceiling, it runs the fan to cool off a rider on excercise bike. I’ve looked and there is a definite “sweat” gradient from floor to ceiling during exercise.