logo elektroda
logo elektroda
X
logo elektroda

QIACHIP Universal WIFI Ceiling Fan Light Remote Control Kit - BK7231N - CB2S

echojjj 
QIACHIP Universal WIFI Ceiling Fan Light Remote Control Kit
model: KLCW-110v/220v
buy: amazon.com, aliexpress.com

It transforms your traditional ceiling fan and its light into a "smart" fan and light!
Packaging of the QIACHIP ceiling fan WiFi remote control kit.QIACHIP ceiling fan and light remote control kit


This controller has the following functions:
Turn the fan on or off.
Turn the light on or off.
Set the speed of the fan to low, medium or high.
Set a timer to automatically turn the fan off after a number of hours.
Display how much time is remaining after the timer has been set.
Turn the controller's signal beep on or off.

I first bought this ceiling fan/light controller after seeing it listed as a Tasmota supported device. Out of the box, this device can be controlled by its RF remote control or the Smart Life (cloud) app. Smart Life is compatible with Alexa for voice control. But, it's always my goal to keep my smart home devices out of the cloud and have local control. Tasmota is the answer for ESP-based devices. This fan controller has the CB2S module with Beken BK7231N so I would need an ESP drop-in replacement like TYWE2S (ESP-02S) in order to flash Tasmota. So, I ordered the TYWE2S from aliexpress and knew it would take quite a long time for it to arrive.

But, wait...

In the meantime, I discovered OpenBeken firmware supporting the BK7231N (also BK7231T, XR809 and BL602). Wow!

Connections and flashing the firmware:
When OTA programming method becomes available in the near future, you will not have to do this! :D



First, I had to cut the RX and TX traces between the CB2S module and TuyaMCU. I connected RX and TX on the module to TX and RX of my CH340 USB to TTL HW597 Converter. I powered the module with an external USB cable (phone charger wires). I connected 5V(+) wire to the AMS1117 input and (-) to GND. The (-) wire has to also be connected to the HW597's GND. I used a breadboard to make the connections. Using the breadboard makes it simple to disconnect and reconnect power which is part of the programming process.

To flash the OpenBeken firmware I used hid_download_py. But first, I saved the original firmware for tuya-cloudcutter, so that this fan controller will be programmable OTA (over-the-air) and you will not have to do any wire connections or soldering!

Terminal window showing the process of flashing OpenBeken firmware on a BK7231N device.

After flashing the firmware, I soldered wires to reconnect the RX and TX from CB2S to the TuyaMCU. The RF remote control continues to work. Now it's time to do the OpenBeken config.

Mapping TuyaMCU to OpenBeken channels:
TuyaMCU is a little tricky if you have to figure out for yourself the different dpId's, functions and data types. Fortunately for me, this had already been mostly done and available online in Tasmota's template page for this fan controller. One was missing which I found belongs to the controller's beep.

This is the autoexec.bat script which maps the functions of the controller.

// start MCU driver
startDriver TuyaMCU
// let's say that channel 1 is dpid1 - fan on/off
setChannelType 1 toggle
// map dpid1 to channel1, var type 1 (boolean)
linkTuyaMCUOutputToChannel 1 1 1
// let's say that channel 2 is dpid9 - light on/off
setChannelType 2 toggle
// map dpid9 to channel2, var type 1 (boolean)
linkTuyaMCUOutputToChannel 9 1 2
//channel 3 is dpid3 - fan speed
setChannelType 3 LowMidHigh
// map dpid3 to channel3, var type 4 (enum)
linkTuyaMCUOutputToChannel 3 4 3
//dpId 17 = beep on/off
setChannelType 4 toggle
linkTuyaMCUOutputToChannel 17 1 4
//
//
//dpId 6, dataType 4-DP_TYPE_ENUM = set timer
setChannelType 5 TextField
linkTuyaMCUOutputToChannel 6 4 5
//
//
//dpId 7, dataType 2-DP_TYPE_VALUE = timer remaining
setChannelType 6 ReadOnly
linkTuyaMCUOutputToChannel 7 2 6


Home Assistant [version 2022.5.5] setup for reference:
There are really many ways to set up the fan controller in Home Assistant. I have a ceiling fan that has three speeds (low, medium, high) and a light. The controller has a built-in countdown timer to automatically turn the fan off after a number of hours. Instead of using the built-in timer function like I did, you could easily create an automation using a Home Assistant timer.

My Home Assistant config:

fan:
 
  - platform: mqtt
    name: "Living Room Fan"
    state_topic: "living-room-fan/1/get"
    command_topic: "living-room-fan/1/set"
    payload_on: '1'
    payload_off: '0'
    percentage_state_topic: "living-room-fan/3/get"
    percentage_value_template: >-
      {% if value == '0' %}
      33
      {% elif value == '1' %}
      67
      {% elif value == '2' %}
      100
      {% else %}
      0
      {% endif %}
    percentage_command_topic: "living-room-fan/3/set"
    percentage_command_template: >-
      {% if value > 0 and value <= 33 %}
      0
      {% elif value > 33 and value <= 67 %}
      1
      {% elif value > 67 and value <= 100 %}
      2
      {% endif %}
    availability_topic: "living-room-fan/connected"
    payload_available: "online"
    payload_not_available: "offline"
    unique_id: "living-room-fan"
    qos: 1
    retain: true
 
light:
 
  - platform: mqtt
    name: "Living Room Light"
    state_topic: "living-room-fan/2/get"
    command_topic: "living-room-fan/2/set"
    payload_on: '1'
    payload_off: '0'
    availability_topic: "living-room-fan/connected"
    payload_available: "online"
    payload_not_available: "offline"
    qos: 1
    retain: true
 
sensor:
 
  - platform: mqtt
    name: "Living Room Fan Timer"
    state_topic: "living-room-fan/5/get"
    availability_topic: "living-room-fan/connected"
    payload_available: "online"
    payload_not_available: "offline"
    qos: 1
    
  - platform: mqtt
    name: "Living Room Fan Timer Remaining"
    state_topic: "living-room-fan/6/get"
    availability_topic: "living-room-fan/connected"
    payload_available: "online"
    payload_not_available: "offline"
    qos: 1
 
switch:
 
  - platform: mqtt
    name: "Living Room Fan Beep"
    state_topic: "living-room-fan/4/get"
    command_topic: "living-room-fan/4/set"
    payload_on: '1'
    payload_off: '0'
    availability_topic: "living-room-fan/connected"
    payload_available: "online"
    payload_not_available: "offline"
    qos: 1
    retain: true
    icon: mdi:volume-high
  
  - platform: template
    switches:
      living_room_fan_speed_low:
        friendly_name: Living Room Fan Speed Low
        value_template: "{{ is_state('input_number.living_room_fan_speed', '0.0') and is_state('fan.living_room_fan', 'on') }}"
        turn_on:
          - service: fan.turn_on
            target:
              entity_id: fan.living_room_fan
          - service: fan.set_percentage
            data:
              percentage: 33
            target:
              entity_id: fan.living_room_fan
        turn_off:
          - service: fan.turn_off
            target:
              entity_id: fan.living_room_fan

      living_room_fan_speed_med:
        friendly_name: Living Room Fan Speed Med
        value_template: "{{ is_state('input_number.living_room_fan_speed', '1.0') and is_state('fan.living_room_fan', 'on') }}"
        turn_on:
          - service: fan.turn_on
            target:
              entity_id: fan.living_room_fan
          - service: fan.set_percentage
            data:
              percentage: 67
            target:
              entity_id: fan.living_room_fan
        turn_off:
          - service: fan.turn_off
            target:
              entity_id: fan.living_room_fan

      living_room_fan_speed_high:
        friendly_name: Living Room Fan Speed High
        value_template: "{{ is_state('input_number.living_room_fan_speed', '2.0') and is_state('fan.living_room_fan', 'on') }}"
        turn_on:
          - service: fan.turn_on
            target:
              entity_id: fan.living_room_fan
          - service: fan.set_percentage
            data:
              percentage: 100
            target:
              entity_id: fan.living_room_fan
        turn_off:
          - service: fan.turn_off
            target:
              entity_id: fan.living_room_fan


Home Assistant automation to capture the fan speed:

alias: Track Living Room Fan Speed
description: ''
trigger:
  - platform: mqtt
    topic: living-room-fan/3/get
condition:
  - condition: template
    value_template: '{{ trigger.payload | int > -1 }}'
action:
  - service: input_number.set_value
    data:
      value: '{{ trigger.payload | int }}'
    target:
      entity_id: input_number.living_room_fan_speed
mode: single


Home Assistant automation to set the fan timer:

alias: Set Living Room Fan Timer
description: ''
trigger:
  - platform: state
    entity_id:
      - input_number.set_living_room_fan_timer
condition:
  - condition: state
    entity_id: fan.living_room_fan
    state: 'on'
  - condition: template
    value_template: '{{ trigger.to_state.state | int > 0 }}'
action:
  - service: mqtt.publish
    data:
      topic: ceiling-fan/5/set
      qos: '1'
      payload_template: '{{ trigger.to_state.state | int }}'
mode: restart


Home Assistant automation to cancel the fan timer:

alias: Cancel Living Room Fan Timer
description: ''
trigger:
  - platform: state
    entity_id:
      - input_number.set_living_room_fan_timer
    to: '0.0'
condition:
  - condition: state
    entity_id: fan.living_room_fan
    state: 'on'
  - condition: template
    value_template: '{{ states(''sensor.living_room_fan_timer_remaining'') > 0 }}'
action:
  - service: fan.turn_off
    data: {}
    target:
      entity_id: fan.living_room_fan
  - wait_for_trigger:
      - platform: mqtt
        topic: ceiling-fan/1/get
        payload: '0'
  - delay:
      hours: 0
      minutes: 0
      seconds: 1
      milliseconds: 0
  - service: fan.turn_on
    data:
      percentage: >-
        {% if is_state('input_number.living_room_fan_speed','0') %} 33 {% elif
        is_state('input_number.living_room_fan_speed','1') %} 67 {% elif
        is_state('input_number.living_room_fan_speed','2') %} 100 {% else %} 33
        {% endif %}
    target:
      entity_id: fan.living_room_fan
mode: single


Two Home Assistant helpers:
Two rows of settings entries for Home Assistant with columns Name, Entity ID, and Type.
Fan Auto-Off settings panel in the Home Assistant app. Screenshot of fan speed settings in an app or user interface.

My lovelace cards in Home Assistant:

When the fan timer is set:
Living room fan and light control interface

When the fan timer is not set:
Ceiling fan and light control interface

square: false
columns: 1
type: grid
cards:
  - square: false
    columns: 5
    type: grid
    cards:
      - show_name: true
        show_icon: true
        type: button
        tap_action:
          action: toggle
        entity: light.living_room_light
        show_state: false
        icon: mdi:ceiling-fan-light
      - show_name: true
        show_icon: true
        type: button
        tap_action:
          action: toggle
        icon: mdi:fan-speed-1
        entity: switch.living_room_fan_speed_low
        name: Fan - Low
      - show_name: true
        show_icon: true
        type: button
        tap_action:
          action: toggle
        icon: mdi:fan-speed-2
        entity: switch.living_room_fan_speed_med
        name: Fan - Medium
      - show_name: true
        show_icon: true
        type: button
        tap_action:
          action: toggle
        icon: mdi:fan-speed-3
        entity: switch.living_room_fan_speed_high
        name: Fan - High
      - show_name: true
        show_icon: true
        type: button
        tap_action:
          action: toggle
        entity: switch.living_room_fan_beep
        icon: ''
        name: Controller Beep
  - type: horizontal-stack
    cards:
      - type: entities
        entities:
          - entity: input_number.set_living_room_fan_timer
            icon: ' '
        show_header_toggle: false
      - type: conditional
        conditions:
          - entity: sensor.living_room_fan_timer_remaining
            state_not: '0'
        card:
          type: entity
          entity: sensor.living_room_fan_timer_remaining
          unit: minutes
          name: Fan Timer Remaining
          icon: mdi:timer
      - type: conditional
        conditions:
          - entity: sensor.living_room_fan_timer_remaining
            state_not: '0'
        card:
          show_name: true
          show_icon: false
          type: button
          tap_action:
            action: call-service
            service: input_number.set_value
            service_data:
              value: 0
            target:
              entity_id: input_number.set_living_room_fan_timer
          icon: ''
          name: Cancel Timer
      - type: conditional
        conditions:
          - entity: sensor.living_room_fan_timer_remaining
            state: '0'
        card:
          type: markdown
          content: ' '
      - type: conditional
        conditions:
          - entity: sensor.living_room_fan_timer_remaining
            state: '0'
        card:
          type: markdown
          content: ' '


Alexa voice control via Node-RED [v2.2.2] for reference:
Screenshot from Node-RED showing nodes used for Alexa voice control.Voice control schematic using Node-RED with Amazon Echo Hub.
Screenshot of Node-RED showing a change node with message transformation rules configuration.Node-RED change node screen with data processing settings

Configuring change node in Node-RED for Alexa voice controlScreenshot of a Node-RED interface showing a change node editor.

About Author
echojjj wrote 20 posts with rating 13 . Been with us since 2022 year.

Comments

p.kaczmarek2 01 Jun 2022 06:13

Very good job! I am happy to hear that your fan finally works. It is worth mentioning that I also added an "OffLowMidHigh" option, so instead of this: //channel 3 is dpid3 - fan speed setChannelType... [Read more]

daveproffer 11 Oct 2022 19:18

Thank you for this write up! Do you have a picture of where you did this on the board? Or could point me to the location. Thx. 'cut the RX and TX traces between the CB2S module and TuyaMCU' [Read more]

p.kaczmarek2 11 Oct 2022 19:29

Hey @daveproffer , on this image you can see which traces are RX and TX: You can also take a look at CB2S pinout to determine which signals are RX/TX: https://obrazki.elektroda.pl/5708941200_1665509282_thumb.jpg... [Read more]

rojoricardo 02 Mar 2023 20:40

Did you manage to get the RF control working? [Read more]

p.kaczmarek2 02 Mar 2023 21:19

In this device RF receiver is connected directly to MCU so it's always working, it's not affected by the firmware change of the WiFi module. [Read more]

tiredofit 29 Feb 2024 22:57

I realized I have a few of these in my house - I can't seem to get flashing to work manually probably due to my own inabilities, however I can have it output a random Wifi Network in pairing mode. I see... [Read more]

p.kaczmarek2 01 Mar 2024 08:25

Which version is shown in the Tuya app? Newer builds may be already patched. [Read more]

jjlange91 10 Aug 2024 21:50

I just picked up one of these and am preparing to reflash it. One thing I noticed in the manual is that there is supposed to be a way to put it into WiFi pairing mode by holding down a button combination... [Read more]

divadiow 11 Aug 2024 09:32

I guess you'd need to sniff out what that message the MCU sends to the WiFi module is when you perform the remote button reset combination. OpenBeken won't know what to do with that message though.... [Read more]