2026-07-15
md
ESPHome on a Treatlife SS02S Single Pole Switch (CB3S-V200/BK7238)
<-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. ESPHome Device Configuration
  3. Auto Discovery of ESPHome Devices in Domoticz
  4. ESPHome Device Configuration for Domoticz
  5. Installing ESPHome on Linux Mint

Switcheroo at the Switch toc

S002S Model This is a switch which has been in production for a long time as model SS01S. The plastic shell created in 2019 is still being used as far as I can make out. The LED board, on which the Wi-Fi module is also soldered, is just as old and it's still being used. 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.

The 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). Furthermore, when the LED board was revealed after opening the switch following the instructions in the TreatLife Intertek teardown & programming tutorial - WB3S/BK7231 - 100% local Home Assistant control video, the Wi-Fi module had a CB3S silkscreened label.

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 in its single pole Wi-Fi switch.

cb3s-v200 module

While CB3S is silk screened on the circuit board, 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 (10 July 2026).

ESPHome Device Configuration toc

Here is 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

Wish I could say that these BK7238 GPIO numbers were obtained with the LibreTiny PinScan example. Unfortunately, I could not get that project to work and the pins were identified by trial and error. Initially it seemed that the LED and relay pins were the same as with the BK7231 on the CB3S board, so only two pins needed to be found. Later on I realized that the white LED and the relay pins were backward but luckily; even with that error, it was possible to get the relay to work while the white LED could not be controlled.

Here 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 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: generic-bk7238-tuya # CB3S-V200 board Ref: https://docs.libretiny.eu/boards/generic-bk7238-tuya/ framework: version: 0.0.0 source: https://github.com/libretiny-eu/libretiny # (1.13.0 or newer) esphome: name: ${device_name} output: - platform: gpio id: switch_output # pin: P24 # WB3S and CB3S boards pin: P8 # CB3S-V200 board - platform: gpio id: white_led_output pin: # number: P9 # WB3S board # number: P8 # CB3S board number: P24 # CB3S-V200 board inverted: true 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 CB3S-V200/BK7238 module, the only difference with the original configuration file is the addition of the web server component.

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 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!

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.

To compile and upload the firmware to the device use the run command instead of compile. As can be seen, upload was done over a serial link similar to what was shown in the Elektroda video.

(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.

That is done by pressing the small K1 tactile push-button switch below the main button and LED on the LED board.

| |-- 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. In the next section, I'll show the YAML configuration files that made it possible to install multiple Treatlife SS02S switches in Domoticz.

Auto Discovery of ESPHome Devices in Domoticz toc

When an ESPHome device operates in a Home Assistant environment, communication between the device and the home automation application is through a native API component. Because Domoticz does not support this network protocol, the ubiquitous MQTT protocol is used. This is done by removing the API component in the YAML configuration file of the device and adding the MQTT client component.

mqtt: broker: 192.168.0.22 username: admin password: secretpswd discovery: true # not needed, this is the default value discovery_prefix: homeassistant # not needed, this is the default value discovery_unique_id_generator: mac # generates a "uniq_id" such as"d8fc92112233-switch-565177c4" based on the MAC address

Instead of specifying the IP address of the MQTT broker, its host name can be given as in broker: domserver.local. The username and password configuration variables can be set to the empty string ("") or omitted entirely if the MQTT broker does not require authentication. The magic here is the Home Assistant discovery. Enabling that when both the MQTT Client Gateway with LAN interface and MQTT Auto Discovery Client Gateway with LAN hardware interfaces are running in Domoticz means that the switch will be discovered automatically by the home automation system and handled without any futher configuration. The documentation seems to indicate that just the MQTT Auto Discovery Client Gateway could be sufficient on its own. That seems to be the case for handling the Treatlife switches as explained here. However, our numerous Tasmota devices require that the MQTT Client Gateway remains on line.

The one thing that caused a bit of a problem was the last configuration variable, discovery_unique_id_generator. Its default value is legacy which did not work. With that setting, every Treatlife SS02S switch was given the same unique identifier ("uniq_id":"ESPswitchrelay"), which clearly defeats the purpose and consequently confused the Domoticz MQTT auto discovery client. Only a single virtual switch was created by the client and it could only communication with the device discovered last. When the unique id generator is set to mac each switch has a different identifier based on its MAC address (such as "uniq_id":"d8fc92443322-switch-565177c4"). The Domoticz MQTT auto discovery client was able to distinguish between the real devices and create a distinct virtual switch in the Domoticz database for each device. Here are the configuration topics and payloads that two switches sent to the MQTT broker who then passed them on to the Domoticz MQTT auto discovery client.

RX: [homeassistant/switch/ss02s-443322/relay/config] {"name":"Relay","stat_t":"ss02s-443322/switch/relay/state","cmd_t":"ss02s-443322/switch/relay/command","avty_t":"ss02s-443322/status","uniq_id":"d8fc92443322-switch-565177c4","dev":{"ids":"d8fc92443322","name":"ss02s-443322","sw":"2026.6.4 (config hash 0x1daa611f)","mdl":"generic-bk7238-tuya","mf":"Beken","cns":[["mac","d8fc92443322"]]}} RX: [homeassistant/switch/ss02s-112233/relay/config] {"name":"Relay","stat_t":"ss02s-112233/switch/relay/state","cmd_t":"ss02s-112233/switch/relay/command","avty_t":"ss02s-112233/status","uniq_id":"d8fc92112233-switch-565177c4","dev":{"ids":"d8fc92112233","name":"ss02s-112233","sw":"2026.6.4 (config hash 0xa87dd1bb)","mdl":"generic-bk7238-tuya","mf":"Beken","cns":[["mac","d8fc92112233"]]}}

The switches were correctly discovered by Domoticz and two distinct virtual Light/Switch devices were created.

Auto discovered devices in Domoticz

These virtual devices work exactly as desired; they can turn on or off the real device and their state is updated whenever the real devices are turned on or off manually or with their Web interface.

ESPHome Device Configuration for Domoticz toc

The usual warning applies here. This is my first encounter with ESPHome which strongly suggests that the following should not be construed as a recommendation. All that is being done here is documenting the current configuration of two of the Treatlife switches that have been added to our Domoticz home automation system. That way, it should be easier to improve the configuration later on as I get a better understanding of the ESPHome environment.

Each Treatlife SS02S switch has its own YAML file such as ss02s-112233.yaml. I use the last 3 digits of the Wi-Fi MAC address to create unique file names for each device and elsewhere when it is important to distinguish between the switches.

# Single Treatlife SS02S CB3S-V200/BK7238 WiFi Switch # # Provides unique device_name. # # There must be an entry in !secret devices: for that device # with its required private values # substitutions: device_name: ss02s-112233 devices: !secret devices <<: !include tl-ss02s-base.yaml

That file is very short. It assigns a unique device name to the switch, it reads the devices array from the secrets.yaml file and then it reads in the common configuration for all the Truelife SS02S switches called tl-ss02s-base.yaml. That's where most of the configuration is done. Here is what the secrets configuration file looks like.

# Each device should have unique api key (not needed in Domoticz) and passwords # Ref: https://esphome.io/guides/security_best_practices/#using-secrets-yaml # # Javier Peletier (jpeletier) proposed a clean way to implement that requirement # in a single common secrets.yaml file # Ref: https://github.com/esphome/feature-requests/issues/3171#issuecomment-3587573763 # # passwords should not be integers - start with a letter for example devices: ss02s-443322: ap_pswd: ap_pswd_443322 ota_pswd: ota_pswd_443322 web_user: web_admin_443322 web_pswd: web_pswd_443322 ss02s-112233: ap_pswd: ap_pswd_112233 ota_pswd: ota_pswd_112233 web_user: web_admin_112233 web_pswd: web_pswd_112233 # WiFi and MQTT credentials can be shared across devices wifi_ssid_1: "iotnet" wifi_pswd_1: "iotpwd-99#" wifi_ssid_2: "iotbak" wifi_pswd_2: "iotpwd-kk!" mqtt_broker: domoserver.local mqtt_user: "" mqtt_pswd: ""

Finally here is the common configuration file.

esphome: name: ${device_name} bk72xx: board: generic-bk7238-tuya framework: version: 0.0.0 source: https://github.com/libretiny-eu/libretiny # (1.13.0 or newer) logger: # level: VERBOSE web_server: port: 9009 version: 3 auth: username: ${ devices[device_name].web_user } password: ${ devices[device_name].web_pswd } captive_portal: ota: platform: esphome password: ${devices[device_name].ota_pswd} wifi: networks: - ssid: !secret wifi_ssid_1 password: !secret wifi_pswd_1 - ssid: !secret wifi_ssid_2 password: !secret wifi_pswd_2 fast_connect: true ap: ssid: ${device_name} password: ${devices[device_name].ap_pswd} mqtt: broker: !secret mqtt_broker username: !secret mqtt_user password: !secret mqtt_pswd discovery: true # doesn't seem to matter discovery_prefix: homeassistant # doesn't seem to matter discovery_unique_id_generator: mac # generates a "uniq_id" such as"d8fc92411193-switch-565177c4" from MAC, #text_sensor: # - platform: libretiny # version: # creates an informative text sensor in Domoticz showing te firmware version of the switch # name: LibreTiny Version # ultimately decided to forego this to reduce the autodiscovery clutter output: - platform: gpio id: output_led pin: number: P24 light: - platform: binary id: button_led output: output_led binary_sensor: #main button - platform: gpio #device_class: None # Generic on/off default https://www.home-assistant.io/integrations/binary_sensor/#device-class id: button #name: Button # not adding this make this sensor internal filters: - delayed_on_off: 10ms pin: number: P9 inverted: true mode: INPUT_PULLUP # INPUT would work, there is an external pullup on_press: then: - switch.toggle: relay #- logger.log: "binary_sensor toggled relay" switch: #relay - platform: gpio id: relay name: Relay pin: P8 on_turn_on: - light.turn_on: button_led #- logger.log: "button_led turned on (OFF)" on_turn_off: - light.turn_off: button_led #- logger.log: "button_led turned off (ON)" status_led: # Red LED 'around' the white button LED which flashes on warnings and errors pin: number: P26 inverted: true

The text sensor component identifying the libretiny version was not included. It was useful in the beginning for debugging purposes, but it does add unnecessary auto discovery messages.

Installing ESPHome on Linux Mint toc

Intalling ESPHome in a Python virtual environment on my up-to-date Linux Mint system was straightforward which pleased me because I prefer that approach to Docker installations. However it was not possible to compile any configuration for a Beken chip. The problem was a mismatch in the Python versions of the virtual environment I created for ESPHome and Python version created automatically in the installation of libretiny in PlatformIO.

There was a quick and dirty work around using a symbolic link, but ultimately the much better solution was to delete the virtual environment manually created for ESPHome and recreating it with the version of Python used for the libretiny virtual environment in PlatformIO. This will be explained in more detail hopefully within in a few days.

<-A Beken BK7231T Device In Domoticz