neon.ninja

Sharing enlightening moments of home automation

Taking the old ceiling fan for a smart spin

I have recently bought a Brilliant Smart WiFi Ceiling Fan Controller for a bedroom ceiling fan in our house. This is a Tuya device but I wanted to avoid signing up to the Tuya cloud service to operate my ceiling fan under all circumstances. In this article I just wanted to share a few learnings and observations.

Like many other devices the controller uses the ESP to communicate with the world and a separate MCU to control the fan and lights.

Unfortunately – as far as I know – ESPHome does not yet fully support all use-cases to control an MCU, so I decided to give Tasmota a chance which has recently added and improved support to control an MCU. Thanks to some amazing pre-work in the HA community forum I did not have to start at zero. Still, the learning curve is pretty steep if you have never used Tasmota before and the concept is quite different to ESPHome which has become my number one choice when adopting ESP devices into my home automation system.

Prerequisites

Tasmota firmware from development branch

The old Tasmota 6.7.1 did not yet support all the features required to use this fan controller, so I had to compile my own firmware. I followed the instructions in the Tasmota wiki, used VS Studio and were able to compile a 7.0.0.4 firmware within an hour.

In the meantime a new Tasmota major release has been published, and I have flashed a standard image, using version 7.1.1 now.

Tuya-Convert

I have adopted plenty of Tuya devices using Tuya-Convert. I am now using a dedicated Raspberry Pi 3 running Raspbian 10. It is connected via Ethernet to my network so that I keep full remote control while Tuya-Convert uses the WiFi adapter.

I used Tuya-Convert version 2.2.0 with a manual patch of one file that was required to convert some other devices.

Configuration

Tasmota

Tasmota Module Parameters

There are 3 items that need to be mapped to Tasmota controls. The following configuration worked for me and correctly linked light and dimmer, and also automatically generated a light entity and fan power switch entity using auto-discovery.

# Configure Power1 (fnId=11) as Fan power (dpId=1)
TuyaMCU 11,1
# Configure Power2 (fnId=12) as Light (dpId=9)
TuyaMCU 12,9
# Configure Dimmer (fnId=21) as Light Dimmer (dpId=10)
TuyaMCU 21,10

I connected an LED light to my fan which comes with its own LED driver. The driver itself has a control input which is not compatible with the fan controller. Instead the fan controller dims by changing the voltage which would make the LED to blink. To avoid that I just limited the dimmer range.

# Dimmer is not working with my LED driver. Limit range.
DimmerRange 100,100

The following rule listens to changes coming from the MCU and initiated by using the remote control. Each code corresponds to a fan speed, and the action then publishes the current speed value via MQTT so that Home Asssistant can update the fan entity. I decided to go with non-retained messages in this case and instead query the speed on Home Assistant start-up.

# Rule: Publish speed to MQTT when using the remote control.
Rule1 on TuyaReceived#Data=55AA03070005030400010016 DO Publish esp_fan_bedroom/stat/RESULT {"Speed":1} endon on TuyaReceived#Data=55AA03070005030400010117 DO Publish esp_fan_bedroom/stat/RESULT {"Speed":2} endon on TuyaReceived#Data=55AA03070005030400010218 DO Publish esp_fan_bedroom/stat/RESULT {"Speed":3} endon
Rule1 ON

The second rule listens to incoming triggers initiated from changing the speed of the Home Assistant fan entity. The payload in the MQTT message is something like speed=1 and the action taken is to turn on the fan (Power1 1) and then send the speed value. For example, TuyaSend4 3,0 sends an enum value of 0 (speed 1/low) to dpId 3.

# Rule: Set speed when commands arrive from HA via MQTT.
Rule2 on Event#speed=1 DO Backlog Power1 1; TuyaSend4 3,0 endon on Event#speed=2 DO Backlog Power1 1; TuyaSend4 3,1 endon on Event#speed=3 DO Backlog Power1 1; TuyaSend4 3,2 endon
Rule2 ON

I configured auto-discovery which generates a status sensor, a light switch and a power switch for the fan. This also swaps the MQTT command and topic around.

# Set HA auto discover.
SetOption19 1

Home Assistant

Auto-discovery

Assuming that you have MQTT already set up in general, the new device should automatically appear in Home Assistant, and you should see 3 entities:

  • Light
  • Fan power
  • Status

Fan

The fan configuration is a bit more complex, so let’s have a look in detail:

  • Availability: The Tasmota device sends telemetry data on [device]/tele/LWT, and we can subscribe to those updates.
  • State: In the above configuration we have tied the fan power to POWER1 and have to subscribe to the corresponding stat messages and send via the cmnd topic.
  • Speed: This is a bit trickier. To change the speed, a payload like speed=2 needs to be sent to the [device]/cmnd/Event topic. This is then picked up by Rule2 in the Tasmota configuration. When the fan speed changes – as defined in Rule1 – the device confirms the speed as JSON payload which can be extracted and transformed into a payload like speed=2 that the fan definition below understands.
fan:
  - platform: mqtt
    name: "Fan Bedroom"
    availability_topic: "esp_fan_bedroom/tele/LWT"
    payload_available: "Online"
    payload_not_available: "Offline"
    state_topic: "esp_fan_bedroom/stat/POWER1"
    command_topic: "esp_fan_bedroom/cmnd/POWER1"
    payload_on: "ON"
    payload_off: "OFF"
    speed_state_topic: "esp_fan_bedroom/stat/RESULT"
    speed_value_template: "{% if value_json is defined and value_json.Speed is defined %}speed={{ value_json.Speed }}{% endif %}"
    speed_command_topic: "esp_fan_bedroom/cmnd/Event"
    payload_low_speed: "speed=1"
    payload_medium_speed: "speed=2"
    payload_high_speed: "speed=3"
    qos: 1
    speeds:
      - low
      - medium
      - high

The following automation is required to retrieve the latest state of the fan – power and speed. It executes two commands with empty payloads which should trigger the device to send the current state as a result.

automation:
  - alias: "Update fan power state on start-up"
    trigger:
      platform: homeassistant
      event: start
    action:
      - service: mqtt.publish
        data:
          topic: "esp_fan_bedroom/cmnd/POWER1"
          payload: ""
      - service: mqtt.publish
        data:
          topic: "esp_fan_bedroom/cmnd/Event/speed"
          payload: ""
Fan Entity Details (MQTT fan via Tasmota)

Device Monitoring

After having deployed many ESP based devices already, I found it quite useful to keep some information about the device itself in HA. I have added the following sensors and script which replicated from what I normally get in ESPHome.

binary_sensor:
  - platform: mqtt
    name: "ESP Fan Bedroom Status"
    state_topic: "esp_fan_bedroom/tele/LWT"
    payload_on: 'Online'
    payload_off: 'Offline'
    device_class: connectivity

sensor:
  - platform: template
    sensors:
      # Fan Master Bedroom
      esp_fan_bedroom_ip_address:
        friendly_name: "ESP Fan Bedroom IP Address"
        value_template: "{{ state_attr('sensor.esp_fan_bedroom_status', 'IPAddress') }}"
        availability_template: "{{ is_state('binary_sensor.esp_fan_bedroom_status', 'on') }}"
      esp_fan_bedroom_rssi:
        friendly_name: "ESP Fan Bedroom RSSI"
        value_template: "{{ state_attr('sensor.esp_fan_bedroom_status', 'RSSI') }}"
        icon_template: 'mdi:wifi'
        unit_of_measurement: 'dB'
        availability_template: "{{ is_state('binary_sensor.esp_fan_bedroom_status', 'on') }}"
      esp_fan_bedroom_uptime:
        friendly_name: "ESP Fan Bedroom Uptime"
        value_template: "{{ state_attr('sensor.esp_fan_bedroom_status', 'Uptime') | regex_replace(find='T', replace='d, ', ignorecase=False) }}"
        icon_template: 'mdi:clock-start'
        availability_template: "{{ is_state('binary_sensor.esp_fan_bedroom_status', 'on') }}"
      esp_fan_bedroom_version:
        friendly_name: "ESP Fan Bedroom Version"
        value_template: "{{ state_attr('sensor.esp_fan_bedroom_status', 'Version') }}"
        icon_template: 'mdi:information'
        availability_template: "{{ is_state('binary_sensor.esp_fan_bedroom_status', 'on') }}"

script:
  esp_fan_bedroom_restart:
    alias: "ESP Fan Bedroom Restart"
    sequence:
      - service: mqtt.publish
        data:
          topic: "esp_fan_bedroom/cmnd/Restart"
          payload: "1"
Fan Device Monitoring

Ceiling Fan

Originally I was planning to use this fan controller with a Spyda 36″ ceiling fan in one of the kid’s bedrooms. Unfortunately it turned out that the speed control did not really work with that fan, i.e. there was no noticeable difference in fan speed when changing between the 3 speeds.

Ceiling Fan

Instead I had this fan controller retrofitted onto an Lucci ceiling fan where the previous non-smart ceiling controller’s speed control was already broken. This is a better fit and the 3 speeds actually work. The built-in lamp can be turned on and off, but like the LED in the Spyda fan, the lamp in this ceiling fan does not support dimming.

Fan Remote Control

Observations

  • I have to admit that Tasmota is very powerful and supports many devices and sensors. However, there are also a lot of conventions and other magic going on under the hood which makes it quite hard as a beginner to get the configuration right. Luckily the Tasmota wiki is quite comprehensive, but I had to read a lot until I got my configuration right.
  • A while ago I made a switch from ESPEasy to ESPHome, and one of the reasons for that step was that I preferred a framework where I can define all the sensors and pins and everything upfront in a human-readable configuration file that I can version and easily backup. With Tasmota it feels like taking a step backwards – at least in this case – where I uploaded a generic firmware to the device and then had to configure the device through its web interface. This may be less of an issue in cases where the whole device configuration is available as a template.
  • Automated device discovery is great – if it works. I couldn’t really find out in which cases Tasmota exposes a relay as a switch or a light. There is an option to expose all relays as lights, but that is not what I needed for this fan controller.
  • Another user in the HA community forum has taken the above configuration and slightly refined it in a way that does not require any rules in the Tasmota device itself, which makes the HA configuration a bit more complex. Please have a look at the blog entry for a comparison.

Outlook

I am now still left with a new ceiling fan without smart control. Luckily there are alternatives, and I am in the process of adopting a SRL Tech fan controller which has turned out to work very similarly like the Brilliant one. I will share a working configuration as soon as possible.

Compatibility

At the time of writing this post, I used:

  • Home Assistant 0.103.4 with Python 3.7.5
  • Tasmota 7.1.1
  • Tuya-Convert 2.2.0 on Raspbian 10 (Buster)

Update 01 July 2021 – Tasmota firmware upgrade

I just updated this fan controller to the latest Tasmota version – 9.5.0 – and can report that the above configuration still works fine. I am now using the Home Assistant Tasmota integration and this requires version 9.2.0 at the minimum, and you need to run command SetOption19 0 in the Tasmota console for discovery. As a result new entities may be created in Home Assistant and you will need to manually remove the old ones and rename the entity IDs of the new ones.

Just make sure you follow the recommended Tasmota upgrade path, and with the fan controller – due to its limited memory you need to first install the minimal version followed by the full version in each step of the path.

Update 19 Aug 2021 – Speeds

With the migration of fan speeds to percentages in Home Assistant 2021.4, the fan controller configuration requires some updates. Compared to the example above some configuration variables have to be removed and some other added:

  • Removed
    • speed_state_topic
    • speed_value_template
    • speed_command_topic
    • payload_low_speed
    • payload_medium_speed
    • payload_high_speed
    • speeds
  • Added
    • speed_range_max: In the case of this fan controller this is set to 3.
    • percentage_command_topic: Same as the speed_command_topic before.
    • percentage_command_template: This template translates the percentage value into a speed value understood by the Tasmota rules.
    • percentage_state_topic: Same as the speed_state_topic before.
    • percentage_value_template: This ttemplate translates the value received from the controller into a percentage value.

The resulting configuration for my fan controllers then looks as follows:

fan:
  - platform: mqtt
    name: "Fan Bedroom"
    availability_topic: "esp_fan_bedroom/tele/LWT"
    payload_available: "Online"
    payload_not_available: "Offline"
    state_topic: "esp_fan_bedroom/stat/POWER1"
    command_topic: "esp_fan_bedroom/cmnd/POWER1"
    payload_on: "ON"
    payload_off: "OFF"
    qos: 1
    speed_range_max: 3
    percentage_command_topic: "esp_fan_bedroom/cmnd/Event"
    percentage_command_template: "speed={{ (value | int) }}"
    percentage_state_topic: "esp_fan_bedroom/stat/RESULT"
    percentage_value_template: "{% if value_json is defined and value_json.Speed is defined %}{{ (value_json.Speed | int) }}{% endif %}"

It would actually be possible to simplify the templates by implementing the percentages directly in the Tasmota rules, but for now I decided to translate the 3 speeds into percentages inside the Home Assistant templates.

Update 06 Sep 2021 – Fixes

Unfortunately I realised that I copied the wrong MQTT fan configuration in my last update in August, so I fixed that in the above.

In a nutshell, with the speed_range_max setting you can essentially align the actual speeds on the device with the Home Assistant configuration and thereby circumventing the conversion to and from percentages. So, by setting this to 3 as in the example above you can send the speed value straight to the device, and in return when receiving a value you need to parse the value from the JSON provided.


Smarter Fans Series

  1. Retrofitted smart fan controller flashed with Tasmota onto old ceiling fan
  2. Flashed ESPHome on brand new ceiling fan controller
  3. Flashed ESPHome on Sonoff RF Bridge to control new ceiling fan.

Comments

28 responses to “Taking the old ceiling fan for a smart spin”

  1. Alex Dantoft Avatar

    Excellent post! Thanks for the write up. I’ve found that getting ceiling fans to work just right depends on a lot of factors – especially how it’s wired in the house. I’m trying out the BOND device that communicates to ceiling fans over RF, but if it doesn’t work well I may go this route.

    1. malte Avatar
      malte

      Thanks for your feedback.
      I guess the main disadvantage of devices such as the Bond is that you don’t get any response from the fan. I am playing around with an IR controller and a wall fan to figure out a good sequence of commands to avoid having to guess the fan’s current state.

  2. Simon Avatar
    Simon

    You extract values from “sensor.esp_fan_bedroom_status” for getting the IP address and such. However, as far as i can see, the only “esp_fan_bedroom_status” sensor you define is a binary_sensor. How do you define a normal sensor called “esp_fan_bedroom_status” so you can extract it’s IP address?

    1. malte Avatar
      malte

      That is a good question – the entity “sensor.esp_fan_bedroom_status” is defined automatically because I have configured auto-discovery. The details are published via MQTT (topic “esp_fan_bedroom/tele/HASS_STATE” in my example) every 10 minutes.

  3. Aaron Avatar
    Aaron

    Great work

  4. Larry Avatar
    Larry

    I’m about to get the sonoff ifan03 and hope to flash it with tasmota 🙂 enjoy your posts, keep them up!

    1. malte Avatar
      malte

      Thanks. Good luck with the iFan03 – at least there is already a template for it: https://templates.blakadder.com/sonoff_ifan03.html

  5. Ed Avatar
    Ed

    I made the mistake of getting a minka aire fan, which uses 303MHz. not easy to find a transmitter, so will probably rip apart the fan remote and connect up to an ESP.

    1. malte Avatar
      malte

      Good luck with that approach.

  6. steve Avatar
    steve

    I have one of these: SRL Tech fan controller – I’d be really interested in your progress using that – I haven’t had much luck so far.

  7. Jason J Avatar
    Jason J

    Malte -thanks so much for such a detailed post. I am one of the unlucky ones and just purchased the fan controller and it has the new Tuya firmware which prevents OTA firmware upgrades.

    I have tried all sorts of ways to hardwire the unit to try and flash with serial cable connection. No luck .. I’m hoping someone else may have worked out how to flash manually.

    All the best and thanks again for the post !

    1. malte Avatar
      malte

      Thanks for your feedback, Jason.
      Sorry to hear that you’re having trouble flashing the controller. This appears to happen more and more with newer hardware.
      Good luck.

  8. zorruno Avatar
    zorruno

    Hi @malte, thanks to you and all the others who share their home automation adventures. Not sure what country you are in? I’m keen to get some of these wall switches…I already have sonoff controllers running tasmota, and these wall plates look like they would match my zemismart light switches quite well. I’m in NZ… local hardware store seems to have plenty of Brilliant Smart branded stuff… but not these, cheers z

    1. malte Avatar
      malte

      Hi zorruno, thanks for your feedback. I’m located in Australia. I bought this kit from JD Lighting and they say on their website that they deliver to NZ.
      However, the smarts are built into the controller (located in the fan’s canopy), not into the wall remote which is just talking RF to the controller. So, I’m not sure if you could make the wall switches work with a Sonoff controller…

      1. zorruno Avatar
        zorruno

        cheers – is it plain 433MHz do you know? Probably a lot to pay just for a 433MHz remote… but they look so similar to my switches!

        1. malte Avatar
          malte

          It says “Operating frequency: 433.9MHz” on the back. However, I just looked at my Sonoff RF Bridge’s log and it does not appear to receive anything from that Brilliant remote control.

  9. Dave M Avatar
    Dave M

    Hi Malte,

    I used this tutorial a while back to get my fans setup however now that I’m trying to change the config to the suit the new fan speed rules I have hit a snag.

    I completely removed the previous config from HA and then upgraded Tasmota on the fan to the latest (9.5.0). HA discovered the fan however it only shows two switches, one for the fan and one for the light. How do I get the fan speeds to work?

    1. malte Avatar
      malte

      Hi Dave,
      thanks for the reminder. I had actually migrated my configuration to percentages already and have been testing this for several weeks now.
      I just posted an update with the new fan configuration.

      1. Dave M Avatar
        Dave M

        Thank you so much! Legend

        1. malte Avatar
          malte

          Hi Dave, please have a look at the latest configuration again – I fixed the entries for percentage_command_template and percentage_value_template above.

          1. Dave M Avatar
            Dave M

            Hi Malte,

            I’m still having trouble with this. It seems that HA is not seeing the fan status at all. If I try to change the fan speed in HA it still shows as OFF.

            This is what I have configured-

            fan:
            – platform: mqtt
            name: “Bedroom Fan”
            unique_id: bedroom_fan
            command_topic: “tasmota/fans/master_bedroom/cmnd/POWER1”
            state_topic: “tasmota/fans/master_bedroom/tele/STATE”
            availability_topic: tasmota/fans/master_bedroom/tele/LWT
            payload_available: Online
            payload_not_available: Offline
            payload_off: “OFF”
            payload_on: “ON”
            qos: 1
            retain: false
            speed_range_max: 3
            percentage_command_topic: “tasmota/fans/master_bedroom/cmnd/Event”
            percentage_command_template: “speed={{ (value | int) }}”
            percentage_state_topic: “tasmota/fans/master_bedroom/stat/RESULT”
            percentage_value_template: “{% if value_json is defined and value_json.Speed is defined %}{{ (value_json.Speed | int) }}{% endif %}”

            I’m not sure what I have done wrong or how to troubleshoot this. Any ideas?

          2. malte Avatar
            malte

            Hi Dave,
            here are some troubleshooting steps I would recommend:
            * Can you actually control the fan (even if the state does not update in HA)?
            * Use a MQTT command line tool to observe the topics and payload that are actually exchanged between HA and the Tasmota device.
            * Do you see regular STATE messages in the MQTT stream? This should appear every 10 minutes.
            * You can force MQTT response from the device by sending commands manually, for example if you send “tasmota/fans/master_bedroom/cmnd/POWER1” with an empty message you should receive a response showing the current state.
            * Check that the Tasmota device configuration is still correct, including tuymcu, rules and options.
            * Check that the MQTT topic configuration on the device matches your above HA topic configuration.

      2. Phil Avatar
        Phil

        Hi Malte

        I have a similar setup with Brilliant Vector 3 fans. Your previous setup with the speeds has worked great until the 2021 HA change. I copied your percentage config that you published, and changed it around to suit my cmnd and state commands for the topics, but HA does not change the fan speed at all.
        Using the remote and viewing the tasmota console on the fan, I can see the remote is sending the correct speed commands, but HA is not sending the commands at all. I get Event:Done on the console, but the speed commands are not being sent through.
        I have not setup the automation part in my yaml file for the startup, as it hasn’t been needed yet.
        Is there anything else I can look at to get it going?
        Thanks

        1. malte Avatar
          malte

          Hi Phil, unfortunately I copied the wrong configuration snippet into my update in August, so that would not actually work. I fixed it above in the meantime – essentially the entries for percentage_command_template and percentage_value_template were not aligned with what the device sends and expects.

          1. Phil Avatar
            Phil

            Hello Malte, the updated configuration has worked a treat. Thanks for your help in getting these fans operational in Home Assistant.

  10. Jason Avatar
    Jason

    The correct code with the new HA MQTT fans settings for speed is;

    - platform: mqtt
      name: "Test Fan"
      command_topic: "cmnd/brilliant_fan/POWER1"
      state_topic: "stat/brilliant_fan/POWER1"
      availability_topic: tele/brilliant_fan/LWT
      payload_off: 'OFF'
      payload_on: 'ON'
      payload_available: Online
      payload_not_available: Offline
      json_attributes_topic: "stat/brilliant_fan"
      state_value_template: "{{ value_json.POWER1 | default('')}}"
      speed_range_min: 1
      speed_range_max: 3
      percentage_command_template: "{{ {0: '0', 1: '3,0', 2: '3,1', 3: '3,2'}[value] | default('1') }}"
      percentage_command_topic: "cmnd/brilliant_fan/TuyaSend4"
      percentage_value_template: "{{ {'0': 0, '3,0': 1, '3,1': 2, '3,2': 3}[value_json.speed] | default('1') }}"
      percentage_state_topic: "stat/brilliant_fan"
    - platform: mqtt
      name: "Lounge Fan"
      command_topic: "cmnd/brilliant_fan/POWER1"
      state_topic: "stat/brilliant_fan/POWER1"
      payload_on: "ON"
      payload_off: "OFF"
      availability_topic: "tele/brilliant_fan/LWT"
      payload_available: "Online"
      payload_not_available: "Offline"
      preset_mode_state_topic: "stat/brilliant_fan/RESULT"
      preset_mode_value_template: >
        {%- if value == '3,0' %}Low
        {%- elif value == '3,1' %}Medium
        {%- elif value == '3,2' %}High
        {%- endif -%}
      preset_mode_command_topic: "cmnd/brilliant_fan/TuyaSend4"
      preset_mode_command_template: >
        {%- if value == "Low" %}3,0
        {%- elif value == "Medium" %}3,1
        {%- elif value == "High" %}3,2
        {%- endif -%}
      qos: 0
      preset_modes:
        - "Low"
        - "Medium"
        - "High"

    If you would prefer to see a drop down list for speeds – Low, Med and High, use this config.
    Just adjust you topics to suit the name of your controller.

    1. malte Avatar
      malte

      Thank you so much for sharing this configuration, Jason!

    2. Linton Avatar
      Linton

      Hey Jason,

      Could you please post your Tasmota rules to go with your test fan config? I’m having a bugger of a time with my 5 speed fan.

      Cheers

Leave a Reply to Jason Cancel reply

Your email address will not be published. Required fields are marked *