LibreTiny - ESPHome - Tongou Rail Switch Configuration (Tuya BK7231N, CBU module)

Hi,
Wasn’t sure where else to post this, but wanted to share the config I’ve put together for a tongou rail switch as it took me quite a while to get right. Hope it helps someone.

substitutions:
  name: tuya-smartbreaker-01
  board: cbu
esphome:
  name: $name
  friendly_name: $name
  on_boot:
    priority: -100
    then:
      switch.turn_on: relay
libretiny:
  board: $board
  framework:
    version: dev
# Enable logging - NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE
logger:

# ******  MQTT Currently Broken for LibreTiny-ESPhome ********** https://github.com/kuba2k2/libretiny/issues/80

ota:
  password: !secret ota_password
wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  ap:
    ssid: "$name"
    password: !secret ap_password
captive_portal:
api:
  encryption: 
    key: !secret encryption_key

switch:
  - platform: template
    name: $name Relay
    id: relay
    turn_on_action:
      - switch.turn_on: on_relay
    turn_off_action:
      - switch.turn_on: off_relay
    optimistic: true
    internal: true
  - platform: gpio
    pin:
      number: P24
      inverted: true
    id: off_relay
    name: "OFF Relay"
    restore_mode: ALWAYS_OFF
    internal: True
    interlock: [on_relay]
    on_turn_on:
      - light.turn_off: led
      - binary_sensor.template.publish:
          id: relaystate
          state: OFF
      - delay: 100ms
      - switch.turn_off: off_relay
  - platform: gpio
    pin:
      number: P26
      inverted: true
    id: on_relay
    name: "ON Relay"
    restore_mode: ALWAYS_OFF
    internal: True
    interlock: [off_relay]
    on_turn_on:
      - light.turn_on: led
      - binary_sensor.template.publish:
          id: relaystate
          state: ON
      - delay: 100ms
      - switch.turn_off: on_relay
button:
  - platform: template
    name: "$name Toggle Relay"
    id: soft_button
    on_press:
      switch.toggle: relay
  - platform: restart
    name: "$name Restart Button"
binary_sensor:
  - platform: gpio
    pin: 
      number: P17
      inverted: true
      mode:
        input: true
    name: "$name Button"
    id: hard_button
    on_press:
      switch.toggle: relay
    internal: true
  - platform: template
    name: $name Relay State
    id: relaystate
light:
  - platform: binary
    name: "$name LED"
    output: led_output
    id: led
    internal: true
output:
  - id: led_output
    platform: gpio
    pin:
      number: P15
      inverted: true
      mode:
        output: true
4 Likes

Hi!
I try to flash such a device with firmware LibreTiny - ESPHome, using raspberry pi, but every time I get an error message.

[!] The profile you selected did not result in a successful exploit.

Please tell me which profile file you used.
Thanks!

Yeah. I had the same problem unfortunately so had to connect wires to the module and flash over serial.

Hi! the Pin for flash over serial are:
GND 13
3.3V 14
TX1 15
RX1 16
in the right bottom corner?

Correct. As long as your one has the CBU module. It should be printed on it if I recall.

https://developer.tuya.com/en/docs/iot/cbu-module-datasheet?id=Ka07pykl5dk4u

Thank you for the code, this is what I needed, but there are no energy monitoring sensors in your code. I have added power consumption monitoring sensors

Code for switch and power consumption monitoring AT-Q-SY1-JWT

#####################################################################################
###################################### Variables ####################################
substitutions:
  name: at-switch-with-energy-meter
  board: cbu

#####################################################################################
################################# Basic configuration ###############################
esphome:
  name: $name
  friendly_name: $name
  comment: AT Switch with energy meter AT-Q-SY1-JWT

#CBU Wi-Fi Module https://docs.libretiny.eu/boards/cbu/
bk72xx:
  board: cbu

#Beken chips, unlike ESP, do not have an RTC memory for storing data. The settings are saved in flash memory every 10 minutes, not every time you change. If you need to shorten the time, then use the code below

#https://github.com/libretiny-eu/libretiny/issues/75
#https://github.com/libretiny-eu/libretiny/issues/41
preferences:
  flash_write_interval: 1min

#####################################################################################
################################## WiFi and hotspot #################################
#WiFi credentials to connect the card to your home network
wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  fast_connect: off
  reboot_timeout: 5min

#If there is no connection to WiFi, the access point will rise
  ap:
    ssid: ESP DINSwitchAtQs
    password: !secret ap_esp_password
    ap_timeout: 1 min
    manual_ip:
      static_ip: 192.168.4.1
      gateway: 192.168.4.1
      subnet: 255.255.255.0

#The mdns component causes a host to advertise itself on the local network using the multicast DNS (mDNS) protocol, the default for mDNS is disabled: false
mdns:
  disabled: false

#The captive portal component in ESPHome is a backup mechanism in case the connection to the configured WiFi fails
captive_portal:

#Web server
web_server:
  port: 80

#Logging
logger:
  level: ERROR
  baud_rate: 0

#Enable API for Home Assistant
api:

#Over-the-air (OTA) update
ota:
  password: "esphome"


#We use components bl0942 from Brokly https://github.com/Brokly/bl0942
#Reason, read here
#https://github.com/libretiny-eu/libretiny/issues/153#issuecomment-1696949291
#https://github.com/libretiny-eu/libretiny/issues/153#issuecomment-1698550337
#The changes to the component consist of first checking the presence of all data and then processing it. In this case, the checksum and header are checked during the #data collection process
#Sensor updates, although performed using loop(), take several cycles. Automatic search for caches in the data stream has been made
#The corrected component completely eliminates all problems and works with any processor
#The differences in versions are not caused by the processing of received uart data, but by different delays between update() and next loop()

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


#####################################################################################
######################################### UART ######################################
uart:
  tx_pin: TX1
  rx_pin: RX1
  id: idUartBus
  baud_rate: 4800
  stop_bits: 1
  data_bits: 8


#####################################################################################
############################### Output platform #####################################
output:
  - id: idLedOutput
    platform: gpio
    pin:
      number: P15
      inverted: true
      mode:
        output: true

#####################################################################################
##################################### Switch ########################################
switch:
  - platform: template
    name: Switch
    id: idSwitch
    icon: mdi:light-switch
    turn_on_action:
      - switch.turn_on: idONRelay
    turn_off_action:
      - switch.turn_on: idOFFRelay
    optimistic: true
    internal: false #Hide - true \show - false
    restore_mode: RESTORE_DEFAULT_ON

  - platform: gpio
    pin:
      number: P24
      inverted: true
    id: idOFFRelay
    name: "OFF Relay"
    restore_mode: ALWAYS_OFF
    internal: True #Hide - true \show - false
    interlock: [idONRelay]
    on_turn_on:
      - light.turn_off: idLed
      - binary_sensor.template.publish:
          id: idSwitchState
          state: OFF
      - delay: 100ms
      - switch.turn_off: idOFFRelay

  - platform: gpio
    pin:
      number: P26
      inverted: true
    id: idONRelay
    name: "ON Relay"
    restore_mode: ALWAYS_OFF
    internal: True #Hide - true \show - false
    interlock: [idOFFRelay]
    on_turn_on:
      - light.turn_on: idLed
      - binary_sensor.template.publish:
          id: idSwitchState
          state: ON
      - delay: 100ms
      - switch.turn_off: idONRelay

#####################################################################################
################################### Light ###########################################
light:
  - platform: binary
    name: "LED"
    id: idLed
    output: idLedOutput
    internal: true #Hide - true \show - false

#####################################################################################
################################## Sensor ###########################################
sensor:
#WiFi signal strength
  - platform: wifi_signal
    name: "RSSI WiFi"
    icon: mdi:wifi
    update_interval: 60s

#Uptime
  - platform: uptime
    name: "Uptime"
    id: idUptime
    icon: mdi:clock-start
    entity_category: diagnostic
    update_interval: 60s

#Free memory
  - platform: template
    name: "Free Mem Size"
    icon: mdi:memory
    entity_category: diagnostic
    lambda: |-
      #ifdef MALLOC_CAP_DEFAULT
         size_t freeValue = heap_caps_get_free_size(MALLOC_CAP_DEFAULT);
      #else
         size_t freeValue = ESP.getFreeHeap();
      #endif
      return freeValue;

#Energy monitoring. Chip BL0942
  - platform: bl0942
    uart_id: idUartBus
    voltage:
      name: "Voltage"
      icon: mdi:sine-wave
    current:
      name: "Current"
      icon: mdi:current-ac
    power:
      name: "Power"
      icon: mdi:flash
      filters:
        multiply: -1
    energy:
      name: "Energy"
      icon: mdi:lightning-bolt
      accuracy_decimals: 10
    frequency:
      name: "Frequency"
      icon: mdi:pulse
      accuracy_decimals: 2
    update_interval: 10s

#####################################################################################
##################################### Text sensor ###################################
text_sensor:
#IP sensor
  - platform: wifi_info
    ip_address:
      name: IP
      icon: mdi:ip-network

#ESPHome Version
  - platform: version
    name: "ESPHome Version"
    hide_timestamp: true

#Time
  - platform: template
    name: "Time"
    icon: mdi:clock-digital
    id: idTime
    update_interval: 10s
    lambda: |-
      auto time_text = id(homeassistant_time).now().strftime("%H:%M:%S / %d-%m-%Y");
      return { time_text };


#####################################################################################
################################### Binary sensor ###################################
binary_sensor:
  - platform: gpio
    pin: 
      number: P17
      inverted: true
      mode:
        input: true
    name: "Button"
    icon: mdi:flash
    id: idHardButton
    on_press:
      switch.toggle: idSwitch
    internal: true
  - platform: template
    name: Switch State
    icon: mdi:light-switch
    id: idSwitchState


#####################################################################################
####################################### Button ######################################
button:
#Restart
  - platform: restart
    name: "Restart"
    icon: mdi:restart


#####################################################################################
####################################### Time ########################################
time:
  - platform: homeassistant
    id: homeassistant_time
1 Like

This works really well, thanks for sharing @camasway and @DivanX10

Only issue I have is that the device switches off when it comes back online after a power outage. I’ve been playing with the restore_mode option in the off_relay part, but this seems to have no effect. It just always switches of when the power returns.

I would like to be able to have it not flip the relay when it powers on and keep the position it had when it powered down.

How can this be achieved?

@hapklaar

Did they add this to the code?

preferences:
  flash_write_interval: 1min

Read below about flash_write_interval here and here.

As they say that by default liberty changes are recorded in flash memory and recorded no more than once every 10 minutes. ESPHome has 1 minute in the component. Read here.. All changes are recorded in flash memory after 10 minutes. Let’s say you turned on the switch and without waiting 10 minutes, took and de-energized the switch, then when the voltage is applied, the switch will not turn on and will be turned off.

I can’t say whether it will be saved to flash memory if you don’t specify flash_write_interval in the code, but I can say that I myself encountered this and I didn’t recover the last state after power supply. Restore_mode didn’t work for me. When I added flash_write_interval: 1min to the code, restore_mode worked.

Adding to the code

preferences:
  flash_write_interval: 1min

Add restore_mode: RESTORE_DEFAULT_ON to the switch code, then turn on the switch and wait for a minute or more, but not less, then de-energize the switch and supply power, the switch will turn on

@DivanX10

Still doesn’t work for me with that config, keeps turning off on boot. Doesn’t matter what restore_mode combinations I use. If I understand correctly the flash write interval shouldn’t even matter when I either use restore_mode: DISABLE or restore_mode: ALWAYS_ON ?

Maybe something else is wrong…

Could you share your yaml, so I can compare?

You misunderstand. restore_mode: ALWAYS_ON or restore_mode: RESTORE_DEFAULT_ON only works if there is a saved state in RTC memory or in flash memory. The ESP12-F does not have RST memory on board, and the ESP32 has RTC memory, so there is no need to specify flush_write_interval: 1 min

How will the state be restored if it is not written to memory? Therefore, for esp8266 wemos mini and ESP12-F is used in the flash_write_interval: 1 min code to write the last state to flash memory and restore it after de-energization

You don’t need to use restore_mode: ALWAYS_ON, use restore_mode: RESTORE_DEFAULT_ON instead. They have a difference.

restore_mode: ALWAYS_ON - always turn on after power supply, even if you turned off
restore_mode: RESTORE_DEFAULT_ON - restore the last state. If the switch was turned off before de-energizing, then after the voltage is applied, the switch will not turn on, if the switch was turned on before de-energizing, then after the voltage is applied, the switch will turn on

Add flash_write_interval: 1min to the code, then fill in the code,then turn on the switch and wait 2 minutes, then de-energize the switch, wait for all entities to become unavailable in Home Assistant, then turn on and your switch will turn on

bk72xx:
  board: cbu
  framework:
    version: dev
    options:
      LT_AUTO_DOWNLOAD_REBOOT: 0
  flash_write_interval: 1min

LT_AUTO_DOWNLOAD_REBOOT: 0 - added so that ESP 12-A does not switch to boot mode after the next power reboot

Screenshots of my config. I posted the code above. The only difference is in the language. I have it in Russian, and here I posted it in English.


2 Likes

Ah, I understand now

I was changing the restore_mode setting on the wrong part of the switch ==> for the off_relay and on_relay. Changed those back to ALWAYS_OFF and added restore_mode: RESTORE_DEFAULT_ON to the template part. Great succes!

Thanks!

Hi folks,

thanks for the infos. I succesfully flashed this Tongou-Switch.

There are 2 LEDs in the switch. I used the following konfiguration.

grafik

Regards
Dodi

1 Like

Guys,
I could really use your help.

I flashed the Tongou Rail Switch with OpenBeken, which seems to be some version of Tasmota. I used a serial connection, Tuya-Cloudcutter didn’t work.
So far so good.

Now I would like to flash your ESPHOME code on the device.
To do that I created a uf2 file and flashed it with ltchiptool. Flashing seems to be succesful. No errors. However, when I visit the ip address of the device I see Tasmota is still running on the device, nothing’s changed!

What I am doing wrong?

I found my error, I was looking at the wrong ip address, it is working now.

Great work guys!

I would like to give this a go.

I’m familiar with ESPHome flashing with a USB serial adapter, but how do you crack these bad boys open to get to the headers?

The sides of my device appear to be rivoted and would need drillng out.

Am I missing something fundamental or has there been an advance in over the air methods I am not aware of?

Any guidance would be gratefully received to get this project underway.

Many thanks in anticipation…

Yeah, I had to drill them out