MQTT control of DC fan/light

Hi all

I’ve search through the forums (and elsewhere) to see if I can solve my issue–no luck so far. I have a couple of DC fans in the house (one with a integrated LED light). These fans (and light) are controlled solely (till now) by 433MHz RF remotes.

I have a Tasmota-flashed Sonoff RF Bridge which I’ve managed to use (though MQTT) to allow control of the fans. I’ve done this by having the RF bridge “learning” the RF signals for each of the key buttons on the remote (fan speeds 1 to 5, fan off, and for one fan, light on/off [its one button; same code for on and off]).

This allows me to control the fans and lights in HA, but is far from elegant. For each fan I essentially have a list of the “lightning” switches–the first of which (the the slash through it) set the fan on and to that speed, the second of which does nothing (and the same for the light switch on the fan in HA).

There are three things I’d like to resolve (the first may be made redundant by the second):

Firstly, is there are way to only have a single “button” (image/icon/etc) where I have the two lightning icons at the moment (its annoying as the second does nothing)?

Secondly, is there a way to have speed settings (0 to 5) rather than the series of switches (I had a play with the MQTT Fan template but it didn’t seem to make sense in my circumstance). I note that there is no “On” button for the fan remote–hitting a speed just turns it on to that speed.

Thirdly, I’d like to be able to update the state displayed in HA (if I can resolve the two points above) when the fan speed/state (an light on/off) state in changed using the physical remote. As there is no “state” sensor, the only way I could see to do this, is if the displayed “state” is updated both when a selection is made though HA (should just work once the above is resolved) and also updated when teh RF Bridge reads the signal for the change of state (i.e. teh sme one assigned to MQTT commands through “teaching” the RF Bridge" (e.g. the “light toggle” code is tele/sonoff_rfb_01/RESULT = {"RfReceived":{"Sync":5710,"Low":320,"High":920,"Data":"917106","RfKey":"None"}}).

For reference, my current config for the fan (with light) is:

switch:
  - platform: mqtt
    name: "Office fan speed 1"
    command_topic: "cmnd/sonoff_rfb_01/RfKey1"
    optimistic: true
  - platform: mqtt
    name: "Office fan speed 2"
    command_topic: "cmnd/sonoff_rfb_01/RfKey2"
    optimistic: true
  - platform: mqtt
    name: "Office fan speed 3"
    command_topic: "cmnd/sonoff_rfb_01/RfKey3"
    optimistic: true
  - platform: mqtt
    name: "Office fan speed 4"
    command_topic: "cmnd/sonoff_rfb_01/RfKey4"
    optimistic: true
  - platform: mqtt
    name: "Office fan speed 5"
    command_topic: "cmnd/sonoff_rfb_01/RfKey5"
    optimistic: true
  - platform: mqtt
    name: "Office fan off"
    command_topic: "cmnd/sonoff_rfb_01/RfKey6"
    optimistic: true
  - platform: mqtt
    name: "Office light"
    command_topic: "cmnd/sonoff_rfb_01/RfKey7"
    optimistic: true

Any help or suggestions appreciated!

I think you should try implementing it as an mqtt cover, using the postion parameter to represent the state of the fan.

Have considered using an input_select with an automation? It would address your first two requirements.

An input_select is rendered as a drop-down list in the UI. You could define the fans like this:

input_select:
  fan1:
    name: Office fan
    options:
      - 'off'
      - speed 1
      - speed 2
      - speed 3
      - speed 4
      - speed 5
    initial: 'off'
  fan2:
    name: Bedroom fan
    options:
      - 'off'
      - speed 1
      - speed 2
      - speed 3
      - speed 4
      - speed 5
    initial: 'off'

The automation would be triggered by changes to input_select.fan1 (and the other fans). Based on the selected option (off or speed level) the automation would publish the appropriate payload for the RF Bridge.

There is an MQTT Fan object:

MQTT Fan

And a custom Lovelace Fan Card:

Lovelace Fan Control

I am fairly certain these could be combined for a pleasing control system.

1 Like

MQTT Fan supports 3 speeds (low, medium, high). These fans have 5 speeds. How do you propose to make MQTT Fan handle 5 levels?

Ah, indeed it does :slight_smile: Bummer…

Yep… that’s one of the reasons I gave up on MQTT Fan after having a bit of a play with it.

But MQTT Cover and input_select look like they might be viable. Once I’ve had time to try them out, I’ll report back (or more like, seek help!).

Thanks all so far!

FWIW, here’s the default appearance of the two input_selects in the UI.

Screenshot%20from%202019-03-28%2022-40-00

Thanks, writing it up in my lunch break at the moment!

The input_select part looks pretty straightforward - I’m more concerns with the automations!

This should get you started.

 - alias: 'Publish RF Key'
   trigger:
     - platform: state
       entity_id: input_select.fan1
   action:
     - service: mqtt.publish
       data_template:
         topic: >-
         {% set topics = {'off':'6', 'speed 1':'1', 'speed 2':'2', 'speed 3':'3','speed 4':'4', 'speed 5':'5'} %}
         cmnd/sonoff_rfb_01/RfKey{{ topics[trigger.to_state.state] if trigger.to_state.state in topics.keys() else 'unknown' }}
         payload: ""

Wow! Thank you very much!

Okay… trying a small variation on that (just because my fan speed numbers are not intuitive)…

config…

#DC Fan Control
input_select:
  fan_office:
    name: Office fan
    options:
      - 'off'
      - '5 (very slow)'
      - '4 (slow)'
      - '3 (medium)'
      - '2 (fast)'
      - '1 (very fast)'

automations…

#DC Fan Controls
- alias: 'Office Fan Set'
  trigger:
    - platform: state
      entity_id: input_select.fan_office
  action:
    - service: mqtt.publish
      data_template:
        topic: >-
        {% set topics = {'off':'6', '1 (very fast)':'1', '2 (fast)':'2', '3 (medium)':'3','4 (slow)':'4', '5 (very slow)':'5'} %}
        cmnd/sonoff_rfb_01/RfKey{{ topics[trigger.to_state.state] if trigger.to_state.state in topics.keys() else 'unknown' }}
        payload: ""

However, I get this error when I do a config check Error loading /config/configuration.yaml: while scanning for the next token found character '%' that cannot start any token in "/config/automations.yaml", line 12, column 10

(line 12, column 10 is the first % in the {% set topics = line)

Any suggestions 123?

Ignore that… configs not reloaded properly… no error after restart.

Okay… so I have this “sort of” working…

The input_select entity shows up on UI, selecting one of the fan speed levels triggers the automation, and an MQTT message is send… however, its not the right one (and therefore does nothing).

When I trigger a fan speed selection (3 in this case) using the switch previously configured (which though cludgey, does work), I see the following output in the web console for my Tasmota-Sonoff RF Bridge:
14:40:15 MQT: stat/sonoff_rfb_01/RESULT = {"RfKey3":"Learned sent"}

However, when triggered by the automation, the console shows this:
14:40:24 MQT: stat/sonoff_rfb_01/RESULT = {"Command":"Unknown"}

I’m wondering if the set topics portion of the automation is not returning correctly to the MQTT command string?

Sorted… just bad yaml spacing at the end of my automations file (in front of payload)…

In case its of use to someone in the future:

#DC Fan Controls
- alias: 'Office Fan Set'
  trigger:
    - platform: state
      entity_id: input_select.fan_office
  action:
    - service: mqtt.publish
      data_template:
        topic: >-
          {% set topics = {'Off':6, 'Very slow':5, 'Slow':4, 'Medium':3, 'Fast':2, 'Very fast':1} %}
          cmnd/sonoff_rfb_01/RfKey{{ topics[trigger.to_state.state] if trigger.to_state.state in topics.keys() else 'unknown' }}
        payload: ""

Now to get state updates when triggered from the physical remote (and figure out the light)… looking at this for inspiration.

Thanks very much for starting me on the right track 123!

And done! Sync working:

#DC Fan Sync
- alias: 'Office Fan Sync'
  trigger:
    - platform: mqtt
      topic: tele/sonoff_rfb_01/RESULT
  action:
    service: input_select.select_option
    data_template:
      entity_id: input_select.fan_office
      option: >-
        {% if '"RfKey":1}' in trigger.payload %}Very fast
        {% elif '"RfKey":2}' in trigger.payload %}Fast
        {% elif '"RfKey":3}' in trigger.payload %}Medium
        {% elif '"RfKey":4}' in trigger.payload %}Slow
        {% elif '"RfKey":5}' in trigger.payload %}Very slow
        {% elif '"RfKey":6}' in trigger.payload %}Off
        {% endif %}

In case anyone wonders, the closing } in the various ''"RfKey":1}' checks is to prevent double counting between 1 and the teens (11, 12 etc) which run my other fan.

Thanks again all - now to figure out what to do with the light.

Another way to handle the option:

      option: >-
         {% set speeds = {'"RfKey":6}':'Off', '"RfKey":1}':'Very fast', '"RfKey":2}':'Fast', '"RfKey":3}':'Medium','"RfKey":4}':'Slow', '"RfKey":5}':'Very slow'} %}
         {% for i in speeds %}
         {% if i in trigger.payload %} {{speeds[i]}} {% endif %}
         {% endfor %}

Glad to hear you found the input_select solution to be easier to implement than expected.

Thanks again for all your help… I’ve now posted my full solutions/outcome in “Share your Project” here, in case it helps anyone.