2026-08-06
md
ESPHome on a Treatlife SS02S Single Pole Switch (CB3S-V200/BK7238) 2026
<-A Beken BK7231T Device In Domoticz

This time, I did my homework and made sure that it would be possible to change the firmware of the Treatlife Single Pole Wi-Fi switch before buying anything. The results from the search on the web were so promising that I felt confident that it would be possible to create the desired firmware with ESPHome. Consequently, I purchased a package containing four of the switches.

4 Pack

Of course, things didn't go quite as smoothly as hoped because the product received did not match what was described by tinkerers on the Web. However after some struggles, the light switch works completely locally in our Domoticz based home automation system. Indeed, once the new firmware was installed on the switch, it was automatically integrated into Domoticz in what was perhaps the quickest and easiest procedure I have ever experienced. Presumably Home Assistant users would have a similar experience.

Table of Content

  1. Switcheroo at the Switch
  2. AKA Tuya T1-3S Module
  3. ESPHome Device Configuration
  4. Uploading the ESPHome Firmware

Switcheroo at the Switch toc

S002S ModelThe first surprise when the switches were delivered was the label on the back of the device. The model was identified as an SS02S and not a bosma-171 as advertised on the seller's web site. That was comforting because the ESPHome devices repository has a YAML configuration file for that model: Treatlife SS02S 2-Way Wall Switch (2-way is American for single pole). I then easily opened the switch following the instructions in the TreatLife Intertek teardown & programming tutorial - WB3S/BK7231 - 100% local Home Assistant control video which was one of the sources which lead me to believe that the firmware of the device could be replaced. As before, the electronics were divided between two printed circuit boards. These are no longer connected with a ribbon cable which required relatively expensive connectors on each board. Instead there is a 5 pin header on the board screwed to the front plate of the switch that plugs into a female header on the board labelled SS02S_POWER_V4.1. There is no need to do anything with that board which contains the power supply and the relay.

Two PCBs inside the switch

To reprogram the Wi-Fi chip which is on the PCB screwed to the face plate, four screws have to be removed and carefully set aside along with a short spring that keeps the momentary push button in the open position most of the time.

This is a switch which has been in production for a long time as model SS01S. The LED board, on which the Wi-Fi module is soldered, has been in use since the start of 2019. The initial wireless module (an esp01_1m see Blakadder templates, ESPHome Devices respository) was based on the ESP8266. Since then, the wireless module has been replaced twice with devices based on Beken microcontrollers.

Push-button circuitThe second surprise came after successfully compiling and flashing the ESPHome firmware using the CB3S version of the YAML configuration file from the device repository. Frustratingly, the switch could be turned on or off with the virtual switch on the web server, but the main switch button was ineffective. Tracing the circuit for the button confirmed that it was connected to pin 7 of the module. Then I verified with a VOM that when the button was pressed, pin 7 was brought down to ground and that, otherwise, it was pulled up to 3.3 volts through an external resistor.

The penny dropped when the Beken chip used was identified with the ltchiptool utility installed in a Python virtual environment called ve_ltchiptool.

(ve_ltchiptool) michel@trig:~/ve_ltchiptool$ ltchiptool flash info -d /dev/ttyUSB1 bk72xxgen2 I: Connecting to 'Beken 72xx (RISC-V & ARM)' on /dev/ttyUSB1 @ 115200 I: |-- Success! Chip info: BK7238 I: Reading chip info... I: Chip: BK7238 I: +-----------------------+-------------------------------------+ I: | Name | Value | I: +-----------------------+-------------------------------------+ I: | Protocol Type | FULL | I: | Chip Type | BK7238 | I: | Bootloader Type | BK7238 2.0.0 (T1) | I: | Chip ID | 0x7238 | I: | Boot Version String | N/A | I: | | | I: | Flash ID | 85 20 15 | I: | Flash Size (by ID) | 2 MiB | I: | Flash Size (detected) | 2 MiB | I: | | | I: | Encryption Key | 00d76a00 00d76a00 00d76a00 00d76a00 | I: | | (likely invalid - unreadable) | I: +-----------------------+-------------------------------------+ I: |-- Finished in 1.156 s

Once again, Treatlife has switched the wireless module on the SS02 LED board of its single pole Wi-Fi switch. While CB3S is silk screened just under the PCB antenna, the module is identified as a CB3S-V200 on the paper label affixed to the RF shield. This seems to be the current norm for modules containing a BK7238 chip. Support for that chip was added to LibreTiny version 1.13.0 in late June 2026 (see Commit 428eb9e). Unfortunately, there is no CB3S-V200 board definition at this time (August 6, 2026).

However...

AKA Tuya T1-3S Module toc

CB3S-V200 pinout After getting to know the LibreTiny environment and using some pretty basic tools, I was able to work out the pad definitions of the Wi-Fi module.

As the commit history of my CB3S-V200-BK7238 GitHub repository amply shows, it took a while and some effort to get to that definition. Then in late July, I had the brilliant idea of checking all LibreTiny definitions of boards based on the BK7238. I was pleased to find out that there was a compatible board definition, namely, the Tuya T1-3S Wi-Fi Module.

There was a discrepancy between the T1-3S definition and my July definition of the CB3S-V200-BK7238. On double-checking, I confirmed that the mistake was mine. Pad 21 of the module is not connected to any BK7238 GPIO pin. How did I make that mistake? Wishful thinking on my part perhaps? If I had been right and GPIO 7 were connected to pad 21, the module would have had a complete JTAG port with pads 5, 6, 7 and 21 connected to GPIO 6, 8, 9 and 7 respectively which correspond to the four mandatory JTAG signals TCK, TDI, TD0 and TMS respectively. The missing TMS connection means that there is no possibility of using JTAG for flashing or debugging the Beken chip.

Note:

The repository contains a PlatformIO project whose purpose is to verify the pad definition shown on the diagram. If the platformio.ini configuration file is examined, it will be obvious that the generic-bk7238 board definition could be used. If the array of untested GPIO ports had been defined as

const int untestedCount = 3; const int untested[untestedCount] = {PIN_P7, PIN_P21, PIN_P28};
instead of
const int untestedCount = 3; const int untested[untestedCount] = {7, 21, 28};

in main.cpp, the project would not compile using the t1-3s board. The generic board definition is, not surprisingly, a superset of the t1-3s definition. For that reason it is better to use the more restrictive t1-3s board definition.

That array of untested GPIO pins is used to verify that pads 21 and 22 of the Wi-Fi module are not connected to any of the GPIO pins of the microcontroller. See function TestUnknownPad(). That is basically the way I went about identifying the connections between the module pads and the microcontroller GPIO pins. I started with almost all GPIO pins in the untested array and almost all entries in the gpios array set to NC. The exceptions were pads 15 and 16 which I knew were connected to GPIO 10 and 11 (RX1 and TX1) and, of course, pads 1, 3, 8 and 9. As the GPIO pin connected to a pad was identified, the GPIO pin number was moved out of the untested array and the NC value was changed to the found GPIO pin in the gpios array.

PinScan

I would probably have had an easier time if I had used the LibreTiny PinScan example. Unfortunately, I had some problem getting that utility running and once it did run on the BK7238, I did not understand the output. I attached too much significance to the deprecation notice and didn't realise that the displayed D1, D2 , etc., values displayed by PinScan were the Aduino I/O numbers of the GPIO ports.

Here is how I modified the setup() function of PinScan to get it to work.

#define SERIAL_WAIT 2000 void setup() { Serial.begin(115200); delay(SERIAL_WAIT); Serial.println("\n\n This is Serial speaking"); Serial1.begin(115200); delay(SERIAL_WAIT); Serial1.println("\n\nThis is Serial1 speaking"); #if USE_WIFI wm.addAP(WIFI_SSID, WIFI_PASS); while (wm.run() != WL_CONNECTED) { Serial.println("WiFi connection failed, retrying in 5s"); delay(5000); } server.begin(); server.setNoDelay(true); #else stream = &Serial1; /* #if LT_UART_DEFAULT_SERIAL == 0 output = 0; pinSkip[0] = PIN_SERIAL0_TX; pinSkip[1] = PIN_SERIAL0_RX; #elif LT_UART_DEFAULT_SERIAL == 1 output = 1; pinSkip[0] = PIN_SERIAL1_TX; pinSkip[1] = PIN_SERIAL1_RX; #elif LT_UART_DEFAULT_SERIAL == 2 output = 2; pinSkip[0] = PIN_SERIAL2_TX; pinSkip[1] = PIN_SERIAL2_RX; #endif */ output = 1; pinSkip[0] = PIN_SERIAL1_TX; pinSkip[1] = PIN_SERIAL1_RX; #endif }

The important part of the changes is that stream is set to Serial1 and not Serial as in the original source. I spent too much time trying to figure out the chained UART macros to get Serial mapped to Serial1. In the end, I just gave up and just imposed the mapping in the ugly hack seen above. But at least it works.

ESPHome Device Configuration toc

Given the CB3S-V200 (aka T1-3S) pin definition and the LibreTiny T1-3S board definition (version 1.13.0 or newer), it is a simple thing to add support for the newest hardware version of the smart switch in the ESPHome Treatlife SS02S 2-Way Wall Switch YAML configuration. First let's update the GPIO Pinout table for Treatlife WiFi switches with the I/O pin numbers for the CB3S-V200 module in addition to the older WB3S and CB3S modules.

Function WB3S Pins CB3S Pins CB3S-V200 Pins
White LED (Power Sensor) P9 P8 P24
Status LED P8 P7 P26
Relay 1 P24 P24 P8
Button 1 P6 P6 P9

Below the Basic Configuration from the ESPHome devices repository is modified to support switches with the new C3BS-V200 module by default. Settings for the older Beken based modules are preserved as comments. The YAML configuration file was saved as tlcb3s-v200.yaml in a Python virtual environment for ESPHome called ve_esphome to make compilation very easy.

# Treatlife SS02S Single Pole WiFi Wall Switch # Source: https://devices.esphome.io/devices/treatlife-ss02s/ # Modified to suppport CB3S-V200 (aka T1-3S) module with BK7238 by default # using LibreTiny version 1.13.0 (June 29 2026) or newer # (https://github.com/libretiny-eu/libretiny) substitutions: device_name: treatlifeswitch # change friendly_name: "Treatlife Light Switch" # change icon: "mdi:light-switch" bk72xx: # board: generic-bk7231t-qfn32-tuya # WB3S board Ref: https://docs.libretiny.eu/boards/generic-bk7231t-qfn32-tuya/ # board: cb3s # CB3S board Ref: https://docs.libretiny.eu/boards/cb3s/ board: t1-3s # CB3S-V200 board same as t1-3s board Ref: https://docs.libretiny.eu/boards/t1-3s/ esphome: name: ${device_name} wifi: ssid: !secret wifi_ssid password: !secret wifi_password fast_connect: true ap: ssid: ${device_name} password: !secret esphome_ap_password logger: # level: VERBOSE # change web_server: # version: 3 # change text_sensor: - platform: libretiny version: # creates an informative text sensor name: LibreTiny Version # the firmware version of the switch api: encryption: key: !secret api_encryption_key ota: password: !secret esphome_ota_password output: - platform: gpio id: switch_output # pin: P24 # WB3S and CB3S boards pin: P8 # CB3S-V200 - platform: gpio id: white_led_output pin: # number: P9 # WB3S board # number: P8 # CB3S board number: P24 # CB3S-V200 board light: - platform: binary id: ${device_name} name: ${friendly_name} output: switch_output on_turn_on: - light.turn_on: white_led on_turn_off: - light.turn_off: white_led - platform: binary id: white_led output: white_led_output binary_sensor: - platform: gpio id: ${device_name}_button name: ${friendly_name} Button pin: # number: P6 # WB3S and CB3S boards number: P9 # CB3S-V200 board on_press: - light.toggle: ${device_name} status_led: # Red LED pin: # number: P8 # WB3S board # number: P7 # CB3S board number: P26 # CB3S-V200 board inverted: true

Aside from the additions to handle the BK7238 Wi-Fi module, the only differences with the original configuration file are the inclusion of the informative LibreTiny Text Sensor and the web server component which simplified testing the new firmware when Home Assistant is not used.

A secrets.yaml file must be in the same directory as the switch's YAML configuration file. Here is a sample. Of course, the correct Wi-Fi credentials must be provided or else the smart properties of the switch will not be evident at all.

wifi_ssid: "my_wifi" wifi_password: "12345678" api_encryption_key: khLNV859901RmkmEcMx+rxEIl4QO8aJM+n2QLbK1oBo= esphome_ap_password: "abcdefghi" esphome_ota_password: "ota_password"

The api_encryption_key, needed for integration of the switch into Home Assistant and which must be unique for each device, was easily generated.

michel@trig:~$ openssl rand -base64 32 khLNV859901RmkmEcMx+rxEIl4QO8aJM+n2QLbK1oBo=

While trying to add support for the CB3S-V200/BK7238 module to the basic configuration in the Treatlife SS02S 2-Way Wall Switch device in ESPHome Devices, I was gently forced to remove all !secret references for passwords and top-level components such as api: and ota:. It seems to that the aim is to include only hardware configuration elements in the example files on the site. While that aim is understandable, it is a bit of a shame because I found the original basic configuration very useful in trying to understand how ESPHome works and I will be sorry to see the smaller configuration if my pull request is ever accepted! It does not look as there is a need to worry about that.

The configuration can be verified before trying to compile the firmware.

(ve_esphome) michel@trig:~/ve_esphome$ esphome config tlcb3s-v200.yaml INFO ESPHome 2026.6.5 INFO Reading configuration tlcb3s-v200.yaml... substitutions: device_name: treatlifeswitch friendly_name: Treatlife Light Switch icon: mdi:light-switch ... INFO Configuration is valid!

The configuration files will compile with esphome version 2026.6.5 against release 1.13.0 or newer of the LibreTiny platform.

(ve_esphome) michel@trig:~/ve_esphome$ esphome compile tlcb3s-v200.yaml INFO ESPHome 2026.6.5 INFO Reading configuration tlcb3s-v200.yaml... ... Linking .pioenvs/treatlifeswitch/raw_firmware.elf |-- Image 1: raw_firmware.elf | |-- image_bk7238_app.0x011000.rbl | | |-- raw_firmware.bin | |-- image_bk7238_app.0x011000.crc | |-- image_bk7238_app.0x129F0A.rblh | |-- image_bk7238_app.ota.ug.bin | | |-- image_bk7238_app.diff2ya.dat RAM: [== ] 19.5% (used 51028 bytes from 262144 bytes) Flash: [======= ] 67.2% (used 727356 bytes from 1083136 bytes) Building UF2 OTA image |-- esphome_2026.6.5_generic-bk7238-tuya_bk7238_lt1.13.0.uf2 |-- firmware.uf2 |-- firmware.bin =================================================================================== [SUCCESS] Took 48.23 seconds =================================================================================== INFO Build Info: config_hash=0xba02d117 build_time_str=2026-07-09 20:12:03 -0300 INFO Successfully compiled program.

Uploading the ESPHome Firmware toc

The next logical step is to upload the firmware to the BK7238 microcontroller. Compiling and uploading the firmware to the device can be done with the esphome run command. So I soldered the RX1 and TX1 pads of the CBS module on the LED board to Tx and RX pins of USB-serial adapter and the 3.3V and GND pins on the CN1 connector to the corresponding 3.3 volts and GND pins of the USB-serial adapter.

(ve_esphome) michel@trig:~/ve_esphome$ esphome run tlcb3s-v200.yaml ... Building UF2 OTA image |-- esphome_2026.6.5_generic-bk7238-tuya_bk7238_lt1.13.0.uf2 |-- firmware.uf2 |-- firmware.bin =================================================================================== [SUCCESS] Took 27.97 seconds =================================================================================== INFO Build Info: config_hash=0xa2a94831 build_time_str=2026-07-10 00:32:08 -0300 INFO Successfully compiled program. Found multiple options for uploading, please choose one: [1] /dev/ttyUSB0 (USB2.0-Serial) [2] Over The Air (treatlifeswitch.local) (number): 1 Processing treatlifeswitch (board: generic-bk7238-tuya; framework: arduino; platform: https://github.com/libretiny-eu/libretiny) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Configuring upload protocol... AVAILABLE: uart CURRENT: upload_protocol = uart Looking for upload port... Using manually specified: /dev/ttyUSB0 Uploading .pioenvs/treatlifeswitch/firmware.uf2 |-- Detected file type: UF2 - esphome 2026.6.5 |-- Connecting to 'Beken 7238' on /dev/ttyUSB0 @ 115200 |-- Connect UART1 of the BK7231 to the USB-TTL adapter: | | --------+ +-------------------- | PC | | BK7231 | --------+ +-------------------- | RX | ------ | TX1 (GPIO11 / P11) | TX | ------ | RX1 (GPIO10 / P10) | | | | GND | ------ | GND | --------+ +-------------------- | |-- Using a good, stable 3.3V power supply is crucial. Most flashing issues |-- are caused by either voltage drops during intensive flash operations, |-- or bad/loose wires. | |-- The UART adapter's 3.3V power regulator is usually not enough. Instead, |-- a regulated bench power supply, or a linear 1117-type regulator is recommended. | |-- To enter download mode, the chip has to be rebooted while the flashing program |-- is trying to establish communication. |-- In order to do that, you need to bridge CEN pin to GND with a wire.

From experience with other microcontrollers, I think that the BK7238 based Wifi-module could be flashed successfully with the following connection with a good Serial-Usb adapter.

flashing CB3S-V200 module

Pressing the push button when prompted to short CEN to ground should put the BK7238 in upload mode. This has not been tested, because I do not have a bare CB3S-V200 module. Since the K1 push-button on the LED board does short the CEN and RST pins to ground, I thought that it would work with a CB3S-V200 module soldered to the LED board. Unfortunately, that failed. On looking at the LED board restart circuit (assuming I did not make a mistake when trying to work it out), it looks as if K1 does not just ground CEN when pressed, it actually shorts the 3.3 volt and ground rails.

CB3S-V200 restart circuit

As a consequence, the serial-USB adapter's 3.3 volts and ground pins are shorted when K1 is pressed, which can't be good for the adapter. I assume that it is knocked out while K1 is depressed which means that the serial device (/dev/ttyUSB0 on my Linux system) on the computer disappears with the effect that the connection to the BK7238 is lost. The following configuration with an additional independent power supply works.

additional breadboard power supplyflashing CB3S-V200 module on SS02_LED Board

Not much is required from the additional power supply; a common breadboard power supply connected to a cheap 5 volt wall wart AC adapter was enough to power the LED board while uploading the firwmare.

On pressing K1 just long enough after prompted by esphome, the latter was able to connect to the BK7238 and complete the firmware upload.

| |-- Success! Chip info: BK7238 |-- Writing '.pioenvs/treatlifeswitch/firmware.uf2' | |-- esphome 2026.6.5 @ 2026-07-10 00:32:36 -> generic-bk7238-tuya ################################################################# | |-- Finished in 64.239 s =================================================================================== [SUCCESS] Took 65.06 seconds =================================================================================== INFO Successfully uploaded program. INFO Starting log output from /dev/ttyUSB0 with baud rate 115200 INFO Stacktrace analysis is unavailable: no compatible analyzer found for target platform "bk72xx".

After a while it was possible to open the Web interface at http://treatlifeswitch.local/

Web Interface

Presumably, this is a valid configuration when the home automation system is Home Assistant. I can't vouch for that because we use Domoticz.

<-A Beken BK7231T Device In Domoticz