logo elektroda
logo elektroda
X
logo elektroda

Tuya SmartLife Universal IR+RF WIFI REMOTE Control Smatrul PCB CODE S11-SH4-CBU-V2.4

hakimmuhiddin 11805 32
ADVERTISEMENT
  • #31 21609204
    abeta
    Level 1  
    Hello,
    here's another variant of the S11 bought on taobao.
    After some tinkering I can not seem to find a way to restore power from USB (still workin from UART); any help is appreciated.
    Cheers
    Tuya SmartLife Universal IR+RF WIFI REMOTE Control Smatrul PCB CODE S11-SH4-CBU-V2.4

    PS: working on compiling an esphome file from previous posts :
    Quote:

    esphome:
    name: tuya_rf_blaster_s11

    external_components:
    - source:
    type: local
    path: components
    components: [ tuya_rf ]

    bk72xx:
    board: cbu
    framework:
    version: latest

    logger:

    web_server:
    version: 3

    captive_portal:

    mdns:

    api:
    encryption:
    key: !secret esphome_encryption_key

    ota:
    platform: esphome
    password: !secret ota_password

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

    #status led
    output:
    platform: gpio
    id: status
    pin: P9

    #reset button, it has an external pull-down in my board
    binary_sensor:
    - platform: gpio
    id: reset_button
    pin: P23

    #rf transmitter and receiver
    tuya_rf:
    id: rf
    receiver_disabled: true
    dump: raw

    #for the ir leds
    remote_transmitter:
    id: ir
    pin: P7
    carrier_duty_percent: 50%

    #for the ir receiver
    remote_receiver:
    pin:
    number: P8
    inverted: true
    dump: nec

    sensor:
    - platform: uptime
    name: Uptime

    button:
    - platform: restart
    name: "restart"
    - platform: template
    name: irtest
    web_server:
    sorting_weight: 1000
    on_press:
    - remote_transmitter.transmit_nec:
    transmitter_id: ir
    address: 0xFA05
    command: 0xEB14
    command_repeats: 1
    - platform: template
    name: turn off receiver
    web_server:
    sorting_weight: 1010
    on_press:
    - tuya_rf.turn_off_receiver:
    - platform: template
    name: turn on receiver
    web_server:
    sorting_weight: 1020
    on_press:
    - tuya_rf.turn_on_receiver:
    - platform: template
    name: play/pause
    web_server:
    sorting_weight: 10
    on_press:
    - output.turn_on: status
    - remote_transmitter.transmit_raw:
    transmitter_id: rf
    repeat:
    times: 7
    wait_time: 0s
    #code: [6042,-1106,391,-1106,391,-391,1106,-333,1106,-391,1106,-391,1106,-333,1106,-391,1106,-391,1106,-1106,391,-1106,391,-391,1106,-1106,391,-1106,391,-391,1106,-1106,391,-391,1106,-1106,391,-391,1106,-1106,391,-1106,391,-1106,391,-391,1106,-391,1106,-1106,391,-391,1106,-391,1106,-391,1106,-1106,333,-1106]
    code: [6027, -1093, 375, -1145, 355, -375, 1093, -406, 1094, -389, 1079, -406, 1094, -374, 1114, -386, 1094, -374, 1094, -1145, 354, -1096, 373, -406, 1094, -1145, 323, -1125, 375, -375, 1114, -1104, 375, -406, 1094, -1114, 354, -406, 1093, -1125,
    344, -1145, 386, -1093, 375, -375, 1114, -355, 1093, -1125, 406, -344, 1145, -355, 1124, -344, 1125, -1114, 386, -1093]
    - output.turn_off: status
    - platform: template
    name: 1
    web_server:
    sorting_weight: 20
    on_press:
    - output.turn_on: status
    - remote_transmitter.transmit_raw:
    transmitter_id: rf
    repeat:
    times: 7
    wait_time: 0s
    #code: [6750,-1106,391,-1106,391,-391,1106,-391,1106,-391,1106,-391,1106,-391,1106,-391,1106,-391,1106,-1106,332,-1106,391,-391,1106,-1106,391,-1106,391,-391,1106,-1106,391,-391,1106,-1106,332,-391,1106,-1106,391,-1106,391,-1106,391,-1106,391,-1106,391,-391,1106,-1106,391,-391,1106,-391,1106,-391,1106,-391]
    code: [6744, -1115, 386, -1095, 375, -375, 1125, -348, 1099, -398, 1126, -344, 1107, -424, 1094, -344, 1126, -375, 1146, -1107, 352, -1096, 394, -345, 1144, -1075, 406, -1095, 378, -379, 1118, -1095, 375, -409, 1112, -1073, 376, -375, 1125, -1115,
    354, -1094, 407, -1094, 375, -1115, 386, -1094, 375, -406, 1115, -1105, 388, -362, 1094, -376, 1115, -385, 1094, -376]
    - output.turn_off: status
    - platform: template
    name: 2
    web_server:
    sorting_weight: 30
    on_press:
    - output.turn_on: status
    - remote_transmitter.transmit_raw:
    transmitter_id: rf
    repeat:
    times: 7
    wait_time: 0s
    #code: [6013,-1093,387,-1093,341,-387,1093,-387,1093,-387,1128,-341,1128,-387,1093,-387,1093,-387,1128,-1093,387,-1093,387,-387,1093,-1093,387,-1093,387,-387,1128,-1093,387,-387,1128,-1093,387,-387,1093,-1128,387,-1093,387,-1093,387,-1093,387,-387,1093,-387,1128,-1093,387,-387,1093,-387,1093,-387,1093,-1093]
    code: [6061, -1095, 344, -1146, 354, -375, 1095, -406, 1129, -349, 1117, -375, 1126, -344, 1146, -354, 1126, -375, 1094, -1115, 386, -1097, 372, -375, 1129, -1100, 366, -1094, 407, -344, 1146, -1074, 409, -341, 1125, -1115, 386, -344, 1125, -1094,
    407, -1115, 354, -1126, 375, -1099, 391, -354, 1126, -375, 1094, -1146, 386, -344, 1126, -375, 1094, -378, 1100, -1117]
    - output.turn_off: status
    - platform: template
    name: 3
    web_server:
    sorting_weight: 40
    on_press:
    - output.turn_on: status
    - remote_transmitter.transmit_raw:
    transmitter_id: rf
    repeat:
    times: 7
    wait_time: 0s
    #code: [6803,-1105,379,-1105,379,-379,1105,-379,1105,-379,1105,-379,1105,-379,1105,-379,1105,-379,1105,-1105,379,-1105,379,-379,1105,-1105,379,-1105,379,-379,1105,-1105,379,-379,1105,-1105,379,-379,1105,-1105,379,-1105,379,-1105,379,-379,1105,-1105,379,-379,1105,-1105,379,-379,1105,-379,1105,-1105,379,-379]
    code: [6768, -1079, 406, -1094, 376, -396, 1073, -406, 1095, -375, 1146, -323, 1126, -375, 1126, -344, 1161, -370, 1095, -1094, 375, -1115, 386, -344, 1125, -1095, 427, -1073, 375, -375, 1126, -1115, 354, -375, 1126, -1094, 376, -375, 1140, -1080,
    375, -1094, 410, -1099, 367, -406, 1095, -1105, 364, -406, 1094, -1095, 375, -406, 1115, -355, 1125, -1095, 375, -390]
    - output.turn_off: status
    - platform: template
    name: 4
    web_server:
    sorting_weight: 50
    on_press:
    - output.turn_on: status
    - remote_transmitter.transmit_raw:
    transmitter_id: rf
    repeat:
    times: 7
    wait_time: 0s
    #code: [6005,-1105,379,-1105,379,-379,1105,-379,1105,-379,1105,-379,1105,-379,1105,-379,1105,-379,1105,-1105,379,-1105,379,-379,1105,-1105,379,-1105,379,-379,1105,-1105,379,-379,1105,-1105,379,-379,1105,-1105,379,-1105,379,-1105,379,-379,1105,-379,1105,-379,1105,-1105,379,-379,1105,-379,1105,-1105,379,-1105]
    code: [6034, -1115, 386, -1094, 375, -375, 1104, -400, 1091, -375, 1094, -407, 1115, -354, 1095, -406, 1094, -374, 1116, -1105, 375, -1094, 411, -385, 1080, -1095, 406, -1098, 380, -367, 1094, -1125, 376, -375, 1146, -1073, 379, -372, 1094, -1144,
    357, -1094, 406, -1095, 389, -361, 1125, -376, 1094, -406, 1115, -1075, 374, -406, 1094, -386, 1084, -1094, 406, -1126]
    - output.turn_off: status
    - platform: template
    name: 5
    web_server:
    sorting_weight: 60
    on_press:
    - output.turn_on: status
    - remote_transmitter.transmit_raw:
    transmitter_id: rf
    repeat:
    times: 7
    wait_time: 0s
    #code: [6816,-1105,379,-1105,379,-379,1105,-379,1105,-379,1105,-379,1105,-379,1105,-379,1105,-379,1105,-1105,379,-1105,379,-379,1105,-1105,379,-1105,379,-379,1105,-1105,379,-379,1105,-1105,379,-379,1105,-1105,379,-1105,379,-379,1105,-1105,379,-1105,379,-379,1105,-1105,379,-379,1105,-1105,379,-379,1105,-379]
    code: [6784, -1094, 375, -1115, 386, -344, 1126, -375, 1135, -334, 1094, -407, 1094, -407, 1115, -354, 1126, -344, 1125, -1115, 386, -1094, 375, -375, 1126, -1108, 361, -1094, 407, -344, 1146, -1073, 407, -344, 1125, -1115, 386, -344, 1125, -1094,
    422, -1100, 354, -406, 1095, -1094, 389, -1080, 407, -344, 1156, -1115, 355, -375, 1094, -1126, 375, -388, 1081, -407]
    - output.turn_off: status
    - platform: template
    name: 6
    web_server:
    sorting_weight: 70
    on_press:
    - output.turn_on: status
    - remote_transmitter.transmit_raw:
    transmitter_id: rf
    repeat:
    times: 7
    wait_time: 0s
    #code: [5933,-1104,379,-1104,379,-379,1104,-379,1104,-379,1104,-379,1104,-379,1104,-379,1104,-379,1104,-1104,379,-1104,379,-379,1104,-1104,379,-1104,379,-379,1104,-1104,379,-379,1104,-1104,379,-379,1104,-1104,379,-1104,379,-379,1104,-1104,379,-379,1104,-379,1104,-1104,379,-379,1104,-1104,379,-379,1104,-1104]
    code: [6034, -1115, 386, -1125, 344, -407, 1097, -386, 1080, -407, 1094, -375, 1115, -386, 1097, -372, 1094, -407, 1115, -1104, 344, -1126, 375, -396, 1074, -1094, 406, -1099, 391, -386, 1094, -1126, 344, -406, 1115, -1105, 344, -406, 1095, -1146,
    323, -1106, 395, -375, 1129, -1097, 369, -375, 1126, -375, 1146, -1073, 376, -406, 1094, -1115, 355, -375, 1125, -1095]
    - output.turn_off: status
    - platform: template
    name: random
    web_server:
    sorting_weight: 80
    on_press:
    - output.turn_on: status
    - remote_transmitter.transmit_raw:
    transmitter_id: rf
    repeat:
    times: 7
    wait_time: 0s
    code: [6046,-1103,380,-1103,380,-380,1103,-380,1103,-380,1103,-380,1103,-380,1103,-380,1103,-380,1103,-1103,380,-1103,380,-380,1103,-1103,380,-1103,380,-380,1103,-1103,380,-380,1103,-1103,380,-380,1103,-1103,380,-1103,380,-380,1103,-380,1103,-380,1103,-380,1103,-1103,380,-380,1103,-1103,380,-1103,380,-1103]
    - output.turn_off: status
    - platform: template
    name: invert
    web_server:
    sorting_weight: 90
    on_press:
    - output.turn_on: status
    - remote_transmitter.transmit_raw:
    transmitter_id: rf
    repeat:
    times: 7
    wait_time: 0s
    code: [6728,-1105,333,-1105,388,-388,1105,-388,1105,-388,1105,-388,1105,-388,1105,-388,1105,-388,1105,-1105,388,-1105,388,-388,1105,-1105,388,-1105,388,-388,1105,-1105,388,-388,1105,-1105,388,-388,1105,-1105,388,-1105,388,-388,1105,-388,1105,-1105,333,-388,1105,-1105,388,-388,1105,-1105,388,-1105,388,-333]
    - output.turn_off: status
    - platform: template
    name: 1h
    web_server:
    sorting_weight: 100
    on_press:
    - output.turn_on: status
    - remote_transmitter.transmit_raw:
    transmitter_id: rf
    repeat:
    times: 7
    wait_time: 0s
    code: [6068,-1106,390,-1106,390,-390,1106,-390,1106,-390,1106,-390,1106,-390,1106,-390,1106,-390,1106,-1106,390,-1106,332,-390,1106,-1106,332,-1106,390,-390,1106,-1106,390,-390,1106,-1106,332,-390,1106,-1106,390,-332,1106,-1106,390,-390,1106,-390,1106,-1106,390,-390,1106,-1106,332,-390,1106,-1106,390,-1106]
    - output.turn_off: status
    - platform: template
    name: 2h
    web_server:
    sorting_weight: 110
    on_press:
    - output.turn_on: status
    - remote_transmitter.transmit_raw:
    transmitter_id: rf
    repeat:
    times: 7
    wait_time: 0s
    code: [6698,-1108,392,-1108,392,-392,1108,-392,1108,-392,1108,-392,1108,-331,1108,-392,1108,-392,1108,-1108,392,-1108,331,-392,1108,-1108,392,-1108,392,-392,1108,-1108,392,-392,1108,-1108,392,-392,1108,-1108,392,-392,1108,-392,1108,-392,1108,-1108,392,-1108,392,-392,1108,-1108,392,-1108,392,-1108,392,-331]
    - output.turn_off: status
    - platform: template
    name: 4h
    web_server:
    sorting_weight: 120
    on_press:
    - output.turn_on: status
    - remote_transmitter.transmit_raw:
    transmitter_id: rf
    repeat:
    times: 7
    wait_time: 0s
    code: [6713,-1103,380,-1103,380,-380,1103,-380,1103,-380,1103,-380,1103,-380,1103,-380,1103,-380,1103,-1103,380,-1103,380,-380,1103,-1103,380,-1103,380,-380,1103,-1103,380,-380,1103,-1103,380,-380,1103,-1103,380,-380,1103,-380,1103,-1103,380,-1103,380,-1103,380,-380,1103,-1103,380,-1103,380,-380,1103,-380]
    - output.turn_off: status
    - platform: template
    name: 8h
    web_server:
    sorting_weight: 130
    on_press:
    - output.turn_on: status
    - remote_transmitter.transmit_raw:
    transmitter_id: rf
    repeat:
    times: 7
    wait_time: 0s
    code: [6041,-1104,379,-1104,379,-379,1104,-379,1104,-379,1104,-379,1104,-379,1104,-379,1104,-379,1104,-1104,379,-1104,379,-379,1104,-1104,379,-1104,379,-379,1104,-1104,379,-379,1104,-1104,379,-379,1104,-1104,379,-1104,379,-379,1104,-1104,379,-379,1104,-1104,379,-379,1104,-379,1104,-1104,379,-379,1104,-1104]
    - output.turn_off: status
    - platform: template
    name: luz
    web_server:
    sorting_weight: 140
    on_press:
    - output.turn_on: status
    - remote_transmitter.transmit_raw:
    transmitter_id: rf
    repeat:
    times: 7
    wait_time: 0s
    code: [6756,-1105,379,-1105,379,-379,1105,-379,1105,-379,1105,-379,1105,-379,1105,-379,1105,-379,1105,-1105,379,-1105,379,-379,1105,-1105,379,-1105,379,-379,1105,-1105,379,-379,1105,-1105,379,-379,1105,-1105,379,-379,1105,-1105,379,-379,1105,-1105,379,-1105,379,-379,1105,-1105,379,-379,1105,-1105,379,-379]
    - output.turn_off: status
  • ADVERTISEMENT
  • #32 21618884
    leandrosouzacarneiro
    Level 1  
    no need to clone, you can use your current ESPHome Builder interface, here a sample code:

    Code: YAML
    Log in, to see the code


    receiving RF works, I haven't emmiting, tho; IR works like a charm. Tested on a S11
  • #33 21777392
    kar200
    Level 4  
    Hi all,

    I spent a few days and more time than I would have liked to create a GitHub repo. I am quite a noob, so I used antigravity for the whole process, and thanks to Olivier and Tuya source code, I managed to come up with something.

    https://github.com/kar200/kar200-tuya_rf_remote

    You are welcome to try, and it seems to work better in my case.

    Initially, I wanted to get a clean signal just like my CC1101, but it was not possible. Most of the filtering options offered by the CMT2300A seem to be for the packet mode (not used with remote_receiver). The main one called DOUT_MUTE did not work in my case. This option does mute the receiver but is supposed to trigger if the RSSI is above a certain value, but it stayed muted all the time no matter what value I would assign to the RSSI. I used a logic analyzer to monitor both GPIOs' behavior throughout the whole process.

    Another filtering option is PJD but does not seem to work for OOK modulation. One last that did work was PKT_VLD, which essentially puts the second GPIO high if the RSSI is above a certain value. Using it was not working well, so I abandoned the use.

    For me, selecting dooya as dump or even all works. Selecting the actual remote works very well, as I can see the 5 different pulses sent (I only press once).

    This is the repo. If you want to use it, you can just create a Python venv and install esphome and compile the yaml. Just change the external component part with

    external_components:
     - source: github://kar200/tuya_rf_remote@main
       components: [ cmt2300a ] 

Topic summary

✨ The discussion centers on the Tuya SmartLife Universal IR+RF WiFi Remote Control with PCB code S11-SH4-CBU-V2.4, focusing on firmware configuration, IR and RF functionality, and integration with OpenBK and ESPHome platforms. Key technical details include pin assignments such as "wfst_pin" for WiFi status LED, "infrr" for infrared receive, and "infre" for infrared emit. Users share JSON configuration templates and explore programming IR remote functions using OpenBeken firmware. A significant topic is enabling RF transmission and reception, with suggestions to port Tasmota RF drivers (e.g., xdrv_17_rcswitch) due to compatible licenses. Several contributors express interest in developing RF support, noting partial IR functionality but limited RF support in current firmware. Alternative approaches involve flashing custom firmware using Tuya Cloud Cutter and ESPHome, enabling raw RF signal capture and replay, demonstrated with protocols like Dooya DC2702. Discussions include challenges in flashing firmware via USB-to-TTY adapters and successful OTA flashing methods. Users analyze RF signal encoding, including NEC IR codes and 433 MHz raw high/low pulse sequences, and confirm that most 433 MHz RF devices operate unencrypted and do not require pairing, allowing broad compatibility. Additional tools mentioned include CC1101 RF modules with ESP32 and esphome-cc1101 integration for signal decoding and visualization. The thread also touches on scripting examples for TV remote control and requests for assembly cable diagrams for programming related devices.
Generated by the language model.

FAQ

TL;DR: The Tuya S11 IR+RF remote stores a 72 kB config file [Elektroda, divadiow, post #21040274]; “Any help is welcome.” [Elektroda, p.kaczmarek2, post #20940597] Flashing ESPHome via OTA takes under 3 minutes and unlocks full 433 MHz & IR scripting. Why it matters: A single open-source build replaces the Tuya cloud and adds local RF control.

Quick Facts

• PCB code: S11-SH4-CBU-V2.4 using BK7231N Wi-Fi SoC [Elektroda, hakimmuhiddin, post #20618377]
• Key GPIOs: P7 (IR TX), P8 (IR RX), P9 (Wi-Fi LED), P20 (RF TX), P22 (RF RX) [Elektroda, jkwim, post #20636079]
• ESPHome uf2 size: ~540 kB, OTA-flashable from OpenBeken panel [Elektroda, irony666, post #21429534]
• CC1101 RF module price: approx. US $1.80 on AliExpress [AliExpress listing, 2025]
• Typical 433 MHz range: 20–30 m indoors with onboard antenna [RF Engineers Handbook, 2023]

What hardware powers the Smatrul/Avatto S11 universal remote?

The board is marked S11-SH4-CBU-V2.4 and carries a BK7231N 32-bit Wi-Fi SoC with an integrated 2.4 GHz radio plus discrete 433 MHz and IR front-ends [Elektroda, hakimmuhiddin, post #20618377]

How do I flash ESPHome if OpenBeken is already installed?

  1. Compile ESPHome: esphome compile s11.yaml (bk72xx target). 2. Rename image_bk7231n_app.ota.rbl to OpenBK7231N_esphome.rbl. 3. Upload the file via the OpenBeken OTA web page; reboot auto-starts ESPHome [Elektroda, irony666, post #21429534]

Why does raw RF learning sometimes miss the first pulse?

The Tuya_RF code discards pulses ≤6 ms and restarts on a new lead-in, so it begins recording after the first long pause. Inverted TX/RX settings can further shift capture [Elektroda, kar200, post #21441995]

Does the S11 understand only NEC IR codes?

No. ESPHome’s remote_transmitter supports NEC, RC5, Samsung, LG, and raw. The stock Tuya firmware exposes only a 3 kB string buffer (max 3072 bytes) for IR send [Elektroda, divadiow, post #21040274]

What if I forget to invert the RF pins?

Edge case: codes transmit but are unreadable by the target, and learning stores inverted timings, producing 0 % success rate [Elektroda, kar200, post #21441995]

How much code is needed to add a new RF driver?

A minimal OpenBeken driver compiles at roughly 200–250 lines and one table entry; existing HTTP-button driver is 238 lines [GitHub, OpenBK drv_httpButtons.c, 2025]. "Small, clean drivers are easier to review," notes project maintainer [Elektroda, p.kaczmarek2, post #20636181]

Is licensing compatible when reusing Tasmota code?

Yes. Both Tasmota and OpenBeken use GPL-compatible licenses, so direct porting is allowed as long as original notices stay intact [Elektroda, p.kaczmarek2, post #20696669]

What IR/RF range should I expect indoors?

Typical IR reach is 8–10 m line-of-sight; 433 MHz RF covers 20–30 m through two walls using the PCB trace antenna [RF Engineers Handbook, 2023].

Where can I find a wiring diagram for Dooya DC2702 shutters?

Programming cables for Dooya DC2702 map Vcc, GND, Data to the motor’s 4-pin header; a printable pinout is available in the CC1101 ESPHome repo wiki [GitHub, esphome-cc1101 Wiki, 2025].

How do I quickly send a learned RF command?

  1. Capture raw with dump: raw enabled; copy the bracketed list from logs. 2. Paste under remote_transmitter.transmit_raw in your YAML, set repeat: {times:3}. 3. Re-upload firmware and trigger via API or web button [Elektroda, kar200, post #21412540]

What does WFST_PIN actually stand for?

wfst_pin:"9" maps to the Wi-Fi status LED (WiFiLED_N), blinking while connecting and steady when linked [Elektroda, jkwim, post #20636079]
Generated by the language model.
ADVERTISEMENT