logo elektroda
logo elektroda
X
logo elektroda

Atorch S1TW-FR advanced energy meter/thermostat with LCD - cloudless operation

p.kaczmarek2 3564 10

TL;DR

  • An Atorch S1TW-FR LCD energy meter/thermostat was converted into a fully local, cloudless controller.
  • The build flashes OpenBeken onto the CB3S BK7231N WiFi module and maps it to the onboard TuyaMCU over UART.
  • The board uses an HF32FV-16 relay, BL0942 metering, a CH573F RISC-V MCU, and captures dpIDs for voltage 110, current 108, power 109.
  • OpenBeken restores relay control, temperature reading, thermostat modes, child lock, and editable OPP, OVP, OCP, calibration, and schedule fields.
  • Home Assistant discovery still misses the HTTPButtons buttons, and UART sniffing needs isolation because the board lacks galvanic isolation.
Generated by the language model.
ADVERTISEMENT
Treść została przetłumaczona polish » english Zobacz oryginalną wersję tematu
📢 Listen (AI):
  • ATORCH electric energy meter with an LCD screen, waiting for network connection. .
    Here I will show step by step how an advanced energy meter/thermostat with LCD screen can be converted so that it can operate 100% locally, without the cloud and without the manufacturer's servers. I'll be converting the S1TW-FR discussed earlier here, to do this I'll upload OpenBeken to the WiFi module and configure it accordingly to communicate with the TuyaMCU on board.

    It is worth reading the previous section here, where I showed pairing this meter with Tuya:
    Energy meter/thermostat with LCD - S1TW-FR - first impression, Tuya application .
    By the way, let me once again remind you of the collective topic about TuyaMCU:
    TuyaMCU flashing, installation and configuration guide - configure dpID for Home Assistant .
    This topic assumes the reader's knowledge of TuyaMCU.

    Plan of action
    To free this device from the cloud the following steps must be taken:
    1. disassemble the device
    2. intercept the UART communication (TuyaMCU) separately for each operation in the mobile app. This step can be replaced when using Tuya API .
    3. soldering the WiFi module to upload OpenBeken via UART
    4. configuration of OpenBeken based on the acquired TuyaMCU dpID data
    I will try to describe each of the steps here.

    Interior of S1TW-FR .
    We remove the seal and look inside:
    Photo of the S1TW-FR plug-in energy meter on a wooden surface, showing the plug socket and specification label. Close-up of a warranty seal with the text Tear void on a plug-in energy meter. .
    We remove the housing:
    Interior of an open S1TW-FR energy meter showing the circuit board and wiring. .
    S1TW-FR thermostat PCB with desoldered WiFi module on a wooden table .
    The whole is based on the CB3S module (BK7231N); you can upload OpenBeken :
    CB3S module on a device circuit board. .
    But first, let's take a look at the interior. The relay is an HF32FV-16 for 16A 250VAC:
    View of the interior of the device's circuit board featuring a CB3S module and HF32FV-16 relay. .
    There is more going on on the other side of the board. That's because this device is based on the TuyaMCU, so here we have a WiFi module separately, and an additional microcontroller separately:
    Photo of a circuit board of an energy meter/thermostat with exposed LCD section. .
    BL0942 here is responsible for measuring current, voltage and power, it reports the results to the microcontroller right next to it:
    Close-up of a printed circuit board with a BL0942 chip. .
    This MCU next to it is the CH573F (32-bit RISC-V):
    Close-up of a PCB with CH573F microcontroller and BL0942 chip. .
    It is powered by a 3.3V LDO:
    View of the S1TW-FR circuit board with component markings. .
    I was curious about the BP0P189 chip, I think it's something from Bluetooth. I wonder why, since the BK7231 already has BT. I associate the JL logo with other similar chips.
    Atorch S1TW-FR advanced energy meter/thermostat with LCD - cloudless operation .
    There remains the question of power supply. These are provided by the KP3211BSG.
    Close-up of a circuit board with integrated circuits of the S1TW-FR. .
    This is a non-isolated inverter controller, there is no flyback power supply:
    Electrical schematic of KP321XBSG power controller .

    Communication intercept .
    In accordance with the topic on TuyaMCU I have intercepted communication on the RX/TX lines:
    TuyaMCU protocol - communication between microcontroller and WiFi module .
    I used my analyser to capture:
    . TuyaMCU analyser - UART packet decoder for Tuya devices - dpID detector .
    Due to the lack of galvanic isolation with this device, the capture should preferably be done via suitable opto-isolators on both UART lines!!! .
    Alternatively, a completely disconnected (battery-powered) device can be used.
    Here is the captured data, each operation separately. The data presented can be pasted into my analyser to see the dpID of the variables and their types and values. Feel free to experiment on your own. The data so defined will then be used to write the OBK configuration for this device.
    Fragment with measurements (dpID 110, 108, 109): .
    
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00000000FF
    //R WiFi received:
    55AA030000010104
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00240001D1F5
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    55AA030700086E02000400005EC2A5
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    55AA030700086C0200040000001EA1
    //R WiFi received:
    55AA030700086D020004000001AF34
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D6FA
    //S WiFi sent:
    55AA00240001D6FA
    //S WiFi sent:
    55AA00240001D5F9
    //S WiFi sent:
    55AA00000000FF
    //R WiFi received:
    55AA030000010104
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00240001CFF3
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D2F6
    //R WiFi received:
    55AA030000010104
    //S WiFi sent:
    55AA00000000FF
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D2F6
    
    
    .
    Screenshot of TuyaMCU Explorer program showing decoded data. .
    Temperature 18.8°C and other measurements :
    
    //S WiFi sent:
    55AA00000000FF
    //S WiFi sent:
    55AA00000000FF
    //S WiFi sent:
    55AA0001000000
    //R WiFi received:
    55AA030000010003
    //R WiFi received:
    55AA0301002A7B2270223A22726A3834766D79686D306468306A7779222C2276223A22312E312E30222C226D223A307DEF
    //S WiFi sent:
    55AA0002000001
    //R WiFi received:
    55AA0302000004
    //S WiFi sent:
    55AA0008000007
    //S WiFi sent:
    55AA000300010306
    //R WiFi received:
    55AA0307000866020004000000BC39
    //R WiFi received:
    55AA030700087C0200040000029328
    //R WiFi received:
    55AA03070005670100010178
    //R WiFi received:
    55AA03070005650400010078
    //R WiFi received:
    55AA030700087102000400000A5AEC
    //R WiFi received:
    55AA0307000872020004000003E874
    //R WiFi received:
    55AA030700087302000400000BB84D
    //R WiFi received:
    55AA0307000868020004000000007F
    //R WiFi received:
    55AA03070008690200040000000080
    //S WiFi sent:
    55AA00200002010022
    //R WiFi received:
    55AA030700086A0200040000000081
    //R WiFi received:
    55AA030700086B0200040000000082
    //R WiFi received:
    55AA0307000878020004000000008F
    //S WiFi sent:
    55AA000300010407
    //R WiFi received:
    55AA03070008790200040000000090
    //R WiFi received:
    55AA030700087A0200040000000091
    //R WiFi received:
    55AA030700087B0200040000000092
    //R WiFi received:
    55AA030700087002000400000064EB
    //S WiFi sent:
    55AA00000000FF
    //R WiFi received:
    55AA030700086C0200040000000083
    //R WiFi received:
    55AA030700086D0200040000000084
    //R WiFi received:
    55AA030700086E02000400005F0EF2
    //R WiFi received:
    55AA030700087D0200040000000094
    //R WiFi received:
    55AA030700086F0200040000000086
    //R WiFi received:
    55AA03070005740100010084
    //R WiFi received:
    55AA03070005760400010089
    //R WiFi received:
    55AA0307000875020004000000008C
    //R WiFi received:
    55AA0307000877020004000000008E
    //R WiFi received:
    55AA030700057E010001008E
    //R WiFi received:
    55AA03070008800200040000003CD3
    //R WiFi received:
    55AA0303000005
    //R WiFi received:
    55AA0320002806772E74656D700A772E68756D696469747906772E706D323505772E61716908772E646174652E3145
    //R WiFi received:
    55AA0303000005
    //R WiFi received:
    55AA030000010104
    //S WiFi sent:
    55AA002100400108772E74656D702E300004000000040C772E68756D69646974792E3000040000005108772E706D32352E3000040000000707772E6171692E3000040000001DBB
    //R WiFi received:
    55AA0021000020
    //R WiFi received:
    55AA031C00001E
    //S WiFi sent:
    55AA001C00080118041415000B067A
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D1F5
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00000000FF
    //R WiFi received:
    55AA030000010104
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00240001D6FA
    //S WiFi sent:
    55AA00240001D5F9
    //S WiFi sent:
    55AA00240001D5F9
    //S WiFi sent:
    55AA00240001D5F9
    //S WiFi sent:
    55AA00240001D5F9
    //S WiFi sent:
    55AA00240001D1F5
    //S WiFi sent:
    55AA00240001CEF2
    //R WiFi received:
    55AA030000010104
    //S WiFi sent:
    55AA00000000FF
    //S WiFi sent:
    55AA00240001D1F5
    //S WiFi sent:
    55AA00240001D1F5
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D1F5
    //S WiFi sent:
    55AA00240001D1F5
    //R WiFi received:
    55AA030000010104
    //S WiFi sent:
    55AA00000000FF
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D5F9
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D1F5
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    55AA0307000866020004000000BC39
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    55AA030700087C0200040000029328
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    55AA030700086E02000400005E8D70
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    55AA030700086C0200040000001EA1
    //S WiFi sent:
    55AA00240001D6FA
    //R WiFi received:
    55AA030700086D020004000001AC31
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00000000FF
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D5F9
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    55AA030000010104
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D0F4
    //S WiFi sent:
    55AA00240001D3F7
    
    .
    TuyaMCU Explorer screen with UART data .
    Turning on and off several times:
    
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00060005670100010073
    //R WiFi received:
    55AA03070005670100010077
    //R WiFi received:
    55AA03070005650400010078
    //R WiFi received:
    55AA03070005670100010077
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00060005670100010174
    //R WiFi received:
    55AA03070005670100010178
    //R WiFi received:
    55AA03070005650400010078
    //R WiFi received:
    55AA03070005670100010178
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00060005670100010073
    //R WiFi received:
    55AA03070005670100010077
    //R WiFi received:
    55AA03070005650400010078
    //R WiFi received:
    55AA03070005670100010077
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00060005670100010174
    //R WiFi received:
    55AA03070005670100010178
    //R WiFi received:
    55AA03070005650400010078
    //R WiFi received:
    55AA03070005670100010178
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D6FA
    
    
    .
    View of UART communication between WiFi module and microcontroller. .
    Child Lock on and off:
    
    //S WiFi sent:
    55AA00240001D1F5
    //S WiFi sent:
    55AA00060005740100010181
    //R WiFi received:
    55AA03070005740100010185
    //S WiFi sent:
    55AA00240001CEF2
    //S WiFi sent:
    55AA00240001CDF1
    //S WiFi sent:
    55AA00060005740100010080
    //R WiFi received:
    55AA03070005740100010084
    //S WiFi sent:
    55AA00240001CDF1
    //S WiFi sent:
    55AA00240001D1F5
    //S WiFi sent:
    55AA00240001D2F6
    
    
    .
    Screenshot of communication analysis with a WiFi module. .
    Changed OVP from 265 to 275:
    
    //S WiFi sent:
    55AA00240001CFF3
    //S WiFi sent:
    55AA00240001CBEF
    //S WiFi sent:
    55AA00240001CCF0
    //S WiFi sent:
    55AA000600087102000400000ABE4C
    //R WiFi received:
    55AA030700087102000400000ABE50
    //S WiFi sent:
    55AA00240001D1F5
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D1F5
    //S WiFi sent:
    55AA00240001D0F4
    //S WiFi sent:
    55AA00000000FF
    //R WiFi received:
    55AA030000010104
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D1F5
    
    
    .
    Analysis of TuyaMCU communication data on a WiFi module. .
    Changed OCP from 10A to 16A:
    
    //S WiFi sent:
    55AA00240001D0F4
    //S WiFi sent:
    55AA00240001D1F5
    //S WiFi sent:
    55AA00240001D0F4
    //S WiFi sent:
    55AA00240001D1F5
    //S WiFi sent:
    55AA00240001D1F5
    //S WiFi sent:
    55AA000600087202000400000640CB
    //R WiFi received:
    55AA030700087202000400000640CF
    //S WiFi sent:
    55AA00240001D1F5
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00000000FF
    //R WiFi received:
    55AA030000010104
    //S WiFi sent:
    55AA00240001D4F8
    
    
    .
    WiFi communication data with TuyaMCU, displayed as UART packets. .


    Changing the temperature calibration from 0 to 4.5°C:
    
    //S WiFi sent:
    55AA00000000FF
    //S WiFi sent:
    55AA00000000FF
    //S WiFi sent:
    55AA0001000000
    //R WiFi received:
    55AA030000010003
    //R WiFi received:
    55AA0301002A7B2270223A22726A3834766D79686D306468306A7779222C2276223A22312E312E30222C226D223A307DEF
    //S WiFi sent:
    55AA0002000001
    //R WiFi received:
    55AA0302000004
    //S WiFi sent:
    55AA0008000007
    //S WiFi sent:
    55AA000300010306
    //R WiFi received:
    55AA0307000866020004000000BD3A
    //R WiFi received:
    55AA030700087C020004000002952A
    //R WiFi received:
    55AA03070005670100010077
    //R WiFi received:
    55AA0307000565040001027A
    //R WiFi received:
    55AA030700087102000400000ABE50
    //R WiFi received:
    55AA030700087202000400000640CF
    //R WiFi received:
    55AA030700087302000400000BB84D
    //R WiFi received:
    55AA0307000868020004000000007F
    //S WiFi sent:
    55AA00200002010022
    //R WiFi received:
    55AA03070008690200040000000080
    //R WiFi received:
    55AA030700086A0200040000000081
    //R WiFi received:
    55AA030700086B0200040000000082
    //R WiFi received:
    55AA0307000878020004000000008F
    //S WiFi sent:
    55AA000300010407
    //R WiFi received:
    55AA03070008790200040000000090
    //R WiFi received:
    55AA030700087A0200040000000091
    //R WiFi received:
    55AA030700087B0200040000000092
    //S WiFi sent:
    55AA00000000FF
    //R WiFi received:
    55AA030700087002000400000064EB
    //R WiFi received:
    55AA030700086C0200040000000083
    //R WiFi received:
    55AA030700086D0200040000000084
    //R WiFi received:
    55AA030700086E02000400005F2004
    //R WiFi received:
    55AA030700087D0200040000000094
    //R WiFi received:
    55AA030700086F0200040000000086
    //R WiFi received:
    55AA03070005740100010084
    //R WiFi received:
    55AA03070005760400010089
    //R WiFi received:
    55AA0307000875020004000000008C
    //R WiFi received:
    55AA0307000877020004000000008E
    //R WiFi received:
    55AA030700057E010001008E
    //R WiFi received:
    55AA03070008800200040000003CD3
    //R WiFi received:
    55AA0303000005
    //R WiFi received:
    55AA0320002806772E74656D700A772E68756D696469747906772E706D323505772E61716908772E646174652E3145
    //R WiFi received:
    55AA0303000005
    //R WiFi received:
    55AA030000010104
    //S WiFi sent:
    55AA002100400108772E74656D702E300004000000040C772E68756D69646974792E3000040000005008772E706D32352E3000040000000707772E6171692E3000040000001DBA
    //R WiFi received:
    55AA0021000020
    //R WiFi received:
    55AA031C00001E
    //S WiFi sent:
    55AA001C000801180414151B02068C
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    55AA030000010104
    //S WiFi sent:
    55AA00000000FF
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    55AA030000010104
    //S WiFi sent:
    55AA00000000FF
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D5F9
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D5F9
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D5F9
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D5F9
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D5F9
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D5F9
    //R WiFi received:
    55AA030000010104
    //S WiFi sent:
    55AA00000000FF
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00240001D6FA
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D5F9
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    55AA0307000866020004000000BD3A
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    55AA030700087C020004000002952A
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    55AA030700086E02000400005F5B3F
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    //S WiFi sent:
    55AA00000000FF
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    55AA030000010104
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D6FA
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D6FA
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D5F9
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00000000FF
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    55AA030000010104
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D5F9
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D5F9
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D5F9
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    //S WiFi sent:
    55AA00000000FF
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D6FA
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D5F9
    //R WiFi received:
    55AA030000010104
    //S WiFi sent:
    55AA00240001D5F9
    //R WiFi received:
    //S WiFi sent:
    55AA00240001CFF3
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D1F5
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D2F6
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D2F6
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D2F6
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D2F6
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D2F6
    //R WiFi received:
    //S WiFi sent:
    55AA00060008750200040000002DB5
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D1F5
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D7FB
    //R WiFi received:
    55AA03070008770200040000019120
    //S WiFi sent:
    55AA00240001D6FA
    //R WiFi received:
    55AA03070008750200040000002DB9
    //S WiFi sent:
    55AA00240001D7FB
    //R WiFi received:
    //S WiFi sent:
    55AA00000000FF
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D6FA
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D5F9
    //R WiFi received:
    //R WiFi received:
    55AA030000010104
    
    
    .
    Change OPP from 3000W to 3680W: .
    
    //R WiFi received:
    //S WiFi sent:
    55AA00240001CCF0
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D2F6
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00000000FF
    //S WiFi sent:
    55AA000600087302000400000E60F4
    //R WiFi received:
    55AA030000010104
    //R WiFi received:
    55AA030700087302000400000E60F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D0F4
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D3F7
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D2F6
    
    
    .
    Interface displaying communication data between WiFi module and microcontroller. .
    Set cooling start at 21.7°C:
    
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D1F5
    //S WiFi sent:
    55AA0006000869020004000000D955
    //R WiFi received:
    55AA0307000869020004000000D959
    //R WiFi received:
    55AA0307000565040001027A
    //S WiFi sent:
    55AA00240001D1F5
    //R WiFi received:
    55AA03070005670100010178
    //R WiFi received:
    //R WiFi received:
    //S WiFi sent:
    55AA00240001CEF2
    //R WiFi received:
    //S WiFi sent:
    55AA00240001CDF1
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D0F4
    
    
    .
    Screenshot of data analysis from TuyaMCU WiFi module communication .
    Set cooling stop at 25.6°C:
    
    //S WiFi sent:
    55AA000600086B020004000001007F
    //R WiFi received:
    55AA030700086B0200040000010083
    //R WiFi received:
    55AA0307000565040001027A
    //R WiFi received:
    55AA03070005670100010077
    //S WiFi sent:
    55AA00240001D1F5
    //R WiFi received:
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D5F9
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D0F4
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D0F4
    
    
    .
    Tuya packet communication display. .
    Changing the cooling mode to heating:
    
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D2F6
    //S WiFi sent:
    55AA00000000FF
    //R WiFi received:
    55AA030000010104
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA00060005650400010175
    //R WiFi received:
    55AA03070005650400010179
    //R WiFi received:
    55AA03070005650400010179
    //R WiFi received:
    55AA03070005670100010077
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D5F9
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    
    
    .
    Screenshot of TuyaMCU protocol analysis
    Setting the heating start at 12.3°C:
    
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //S WiFi sent:
    55AA00060008680200040000007BF6
    //R WiFi received:
    55AA03070008680200040000007BFA
    //R WiFi received:
    55AA03070005650400010179
    //R WiFi received:
    55AA03070005670100010077
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D5F9
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D6FA
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D6FA
    
    
    .
    Details of TuyaMCU communication protocol between WiFi module and microcontroller. .
    Changed kWh price to 304.52:
    
    //S WiFi sent:
    55AA00240001D3F7
    //S WiFi sent:
    55AA0006000870020004000076F4ED
    //R WiFi received:
    55AA0307000870020004000076F4F1
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D6FA
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    
    
    .
    Screenshot of data communication between the WiFi module and the device. .
    Changing the heating stop to 23.3°C:
    
    //S WiFi sent:
    55AA000600086A020004000000E966
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    55AA030700086A020004000000E96A
    //R WiFi received:
    55AA03070005650400010179
    //R WiFi received:
    55AA03070005670100010077
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D4F8
    //R WiFi received:
    //S WiFi sent:
    55AA00240001D6FA
    
    .
    Screenshot of captured UART communication between microcontroller and WiFi module in TuyaMCU format. .
    With this information now in hand, you can proceed to the next stage.

    Changing the firmware .
    We already have the dpIDs and their roles collected, so we start with just uploading OpenBeken. This requires the WiFi module to be soldered out or at least cutting off its communication with the MCU, as the TuyaMCU uses the same UART port as the programming. I decided to solder out the module myself:
    Image of the interior of an energy meter with the CB3S WiFi module beside it. .
    Then connect the USB to UART converter, according to my flasher's instructions:
    https://github.com/openshwprojects/BK7231GUIFlashTool
    Breadboard with electronic components Prototype setup with USB adapter on a breadboard .
    Computer screen displaying the process of flashing OpenBeken firmware on BK7231N. .
    Here the configuration cannot be automatically loaded.
    After uploading the OBK we are greeted by the OBK access point and web panel:
    WiFi network connection window for OpenBK7231N_B9BCCC78 .
    Screenshot of the OpenBeken interface with configuration buttons. .
    Only then should the module be soldered in place:
    Internal layout of the S1TW-FR device with visible CB3S module CB3S module mounted on a circuit board. Close-up of a CB3S module on a circuit board with black and red wires. WiFi module CB3S on a printed circuit board of an electronic device. .
    First, of course, we set up our WiFi data:
    OpenBK7231N configuration panel with WiFi network options .
    Then only we will configure the TuyaMCU.
    OpenBeken configuration panel for BK7231N module .
    We configure TuyaMCU in the autoexec.bat file, here is how it is created:


    .
    Worthwhile examples are based on:
    https://github.com/openshwprojects/OpenBK7231T_App/blob/main/docs/autoexecExamples.md
    So far, however, the screen is stuck on startup:
    Energy meter display with electrical socket and buttons. .
    Let's write the first, minimal autoexec.bat needed for the screen to respond. You need to run the TuyaMCU driver and force WiFi state 0x04 (we simulate connecting to the cloud this way):
    
    startDriver TuyaMCU
    
    tuyaMCU_defWiFiState 4 
    
    .
    Result:
    ATORCH electric energy meter display with temperature and voltage data .
    Now it is time to read the voltage, current and power. Thanks to the UART packet capture performed earlier, we know under which dpID these values are hidden.
    TuyaMCU Explorer interface for UART data analysis. .
    We enter these into our script and map the dpID to the channels.
    
    startDriver TuyaMCU
    
    tuyaMCU_defWiFiState 4 
    
    // channel types
    setChannelType 2 Voltage_div100
    setChannelType 3 Current_div1000
    setChannelType 4 Power_div10
    
    // linkTuyaMCUOutputToChannel dpId verType tgChannel
    // voltage
    linkTuyaMCUOutputToChannel 110 val 2
    // current
    linkTuyaMCUOutputToChannel 108 val 3
    // power
    linkTuyaMCUOutputToChannel 109 val 4
    
    
    // NOTE: test code only so I can refresh quickly without restarting
    tuyaMcu_sendQueryState
    
    .
    In addition, I added a one-time tuyaMcu_sendQueryState to the script in order to get the measurements faster. This is a prompt call for TuyaMCU to share its state with us.
    Here is the result - it looks ok, although I guess the power needs improvement?
    OpenBeken user interface on WiFi configuration screen

    Now it's time to add the relay control. We will define a toggle channel (on/off) for the relay and also map the dpID accordingly. By the way, I corrected the power divider, as I made a mistake in it by one zero.
    
    startDriver TuyaMCU
    
    tuyaMCU_defWiFiState 4 
    
    // channel types
    setChannelType 1 Toggle
    setChannelType 2 Voltage_div100
    setChannelType 3 Current_div1000
    setChannelType 4 Power_div100
    
    // linkTuyaMCUOutputToChannel dpId verType tgChannel
    // toggle
    linkTuyaMCUOutputToChannel 103 bool 1
    // voltage
    linkTuyaMCUOutputToChannel 110 val 2
    // current
    linkTuyaMCUOutputToChannel 108 val 3
    // power
    linkTuyaMCUOutputToChannel 109 val 4
    
    
    // NOTE: test code only so I can refresh quickly without restarting
    tuyaMcu_sendQueryState
    
    .
    Here is the result after running the above script:
    OpenBeken screen displaying device measurement data .

    However, we are still missing the current time displayed on the device screen. For this, simply enable NTP on OpenBeken, the rest will take place automatically.
    
    startDriver NTP
    
    .
    Now the time on the TuyaMCU is correct.

    Similarly, we can now read the temperature measurements. We already know the dpIDs for the temperature from our analysis. Here, the temperature value is also sent as an integer after having been previously multiplied by 10.
    
    startDriver TuyaMCU
    startDriver NTP
    
    tuyaMCU_defWiFiState 4 
    
    // channel types
    setChannelType 1 Toggle
    setChannelType 2 Voltage_div100
    setChannelType 3 Current_div1000
    setChannelType 4 Power_div100
    setChannelType 5 Temperature_div10
    
    // linkTuyaMCUOutputToChannel dpId verType tgChannel
    // toggle
    linkTuyaMCUOutputToChannel 103 bool 1
    // voltage
    linkTuyaMCUOutputToChannel 110 val 2
    // current
    linkTuyaMCUOutputToChannel 108 val 3
    // power
    linkTuyaMCUOutputToChannel 109 val 4
    // temperature
    linkTuyaMCUOutputToChannel 102 val 5
    
    
    // NOTE: test code only so I can refresh quickly without restarting
    tuyaMcu_sendQueryState
    
    .
    Here is the result, the temperature on the OBK panel:
    Control panel screen for OpenBeken displaying voltage, current, power, and temperature readings. .


    Similarly, we add the other variables. In the case of variables for the configuration, we have a TextField type, where any number can be entered, also as a change of value on the MCU. For example, the OPP Limit can be handled in this way:
    
    startDriver TuyaMCU
    startDriver NTP
    
    tuyaMCU_defWiFiState 4 
    
    // channel types
    setChannelType 1 Toggle
    setChannelType 2 Voltage_div100
    setChannelType 3 Current_div1000
    setChannelType 4 Power_div100
    setChannelType 5 Temperature_div10
    setChannelType 6 TextField
    setChannelType 6 OPP
    
    
    // linkTuyaMCUOutputToChannel dpId verType tgChannel
    // toggle
    linkTuyaMCUOutputToChannel 103 bool 1
    // voltage
    linkTuyaMCUOutputToChannel 110 val 2
    // current
    linkTuyaMCUOutputToChannel 108 val 3
    // power
    linkTuyaMCUOutputToChannel 109 val 4
    // temperature
    linkTuyaMCUOutputToChannel 102 val 5
    // OPP max power (limit)
    linkTuyaMCUOutputToChannel 115 val 6
    
    
    
    // NOTE: test code only so I can refresh quickly without restarting
    tuyaMcu_sendQueryState
    
    .
    In this case the communication works both ways, we can also enter a different value here ourselves and change the maximum power value.
    OpenBK7231N interface with toggle switch on. .
    Once entered, the device responds correctly:
    OpenBeken channel value configuration screen.
    The new value is on the display:
    Display of an advanced energy meter with temperature and power data .

    An analogy can be made for OVP and OCP:
    
    startDriver TuyaMCU
    startDriver NTP
    
    tuyaMCU_defWiFiState 4 
    
    // channel types
    setChannelType 1 Toggle
    setChannelType 2 Voltage_div100
    setChannelType 3 Current_div1000
    setChannelType 4 Power_div100
    setChannelType 5 Temperature_div10
    setChannelType 6 TextField
    setChannelLabel 6 OPP
    setChannelType 7 TextField
    setChannelLabel 7 OVP
    setChannelType 8 TextField
    setChannelLabel  8 OCP
    
    
    // linkTuyaMCUOutputToChannel dpId verType tgChannel
    // toggle
    linkTuyaMCUOutputToChannel 103 bool 1
    // voltage
    linkTuyaMCUOutputToChannel 110 val 2
    // current
    linkTuyaMCUOutputToChannel 108 val 3
    // power
    linkTuyaMCUOutputToChannel 109 val 4
    // temperature
    linkTuyaMCUOutputToChannel 102 val 5
    // OPP max power (limit)
    linkTuyaMCUOutputToChannel 115 val 6
    // OVP
    linkTuyaMCUOutputToChannel 113 val 7
    // OCP
    linkTuyaMCUOutputToChannel 114 val 8
    
    
    
    // NOTE: test code only so I can refresh quickly without restarting
    tuyaMcu_sendQueryState
    
    .
    Here are the new text fields:
    OpenBeken control panel with current measurements and setting change options. .


    The child lock function, which is to protect the panel from the child, is in turn specified by a boolean type variable, so a toggle is useful here too, just like for the relay:
    
    startDriver TuyaMCU
    startDriver NTP
    
    tuyaMCU_defWiFiState 4 
    
    // channel types
    setChannelType 1 Toggle
    setChannelType 2 Voltage_div100
    setChannelType 3 Current_div1000
    setChannelType 4 Power_div100
    setChannelType 5 Temperature_div10
    setChannelType 6 TextField
    setChannelLabel 6 OPP
    setChannelType 7 TextField
    setChannelLabel 7 OVP
    setChannelType 8 TextField
    setChannelLabel  8 OCP
    setChannelType 9 Toggle
    setChannelLabel 9 ChildLock
    
    
    // linkTuyaMCUOutputToChannel dpId verType tgChannel
    // toggle
    linkTuyaMCUOutputToChannel 103 bool 1
    // voltage
    linkTuyaMCUOutputToChannel 110 val 2
    // current
    linkTuyaMCUOutputToChannel 108 val 3
    // power
    linkTuyaMCUOutputToChannel 109 val 4
    // temperature
    linkTuyaMCUOutputToChannel 102 val 5
    // OPP max power (limit)
    linkTuyaMCUOutputToChannel 115 val 6
    // OVP
    linkTuyaMCUOutputToChannel 113 val 7
    // OCP
    linkTuyaMCUOutputToChannel 114 val 8
    // child lock
    linkTuyaMCUOutputToChannel 116 bool 9
    
    
    // NOTE: test code only so I can refresh quickly without restarting
    tuyaMcu_sendQueryState
    
    .
    This allows us to control the child lock function. When changed on the OBK panel, the padlock on the device screen also changes:
    OpenBeken configuration panel with thermostat and energy meter settings .

    This device offers temperature calibration on the side of the MCU itself. This is also where the text box comes in handy:
    
    startDriver TuyaMCU
    startDriver NTP
    
    tuyaMCU_defWiFiState 4 
    
    // channel types
    setChannelType 1 Toggle
    setChannelType 2 Voltage_div100
    setChannelType 3 Current_div1000
    setChannelType 4 Power_div100
    setChannelType 5 Temperature_div10
    setChannelType 6 TextField
    setChannelLabel 6 OPP
    setChannelType 7 TextField
    setChannelLabel 7 OVP
    setChannelType 8 TextField
    setChannelLabel  8 OCP
    setChannelType 9 Toggle
    setChannelLabel 9 ChildLock
    setChannelType 10 TextField
    setChannelLabel 10 TemperatureCalibration
    
    
    
    // linkTuyaMCUOutputToChannel dpId verType tgChannel
    // toggle
    linkTuyaMCUOutputToChannel 103 bool 1
    // voltage
    linkTuyaMCUOutputToChannel 110 val 2
    // current
    linkTuyaMCUOutputToChannel 108 val 3
    // power
    linkTuyaMCUOutputToChannel 109 val 4
    // temperature
    linkTuyaMCUOutputToChannel 102 val 5
    // OPP max power (limit)
    linkTuyaMCUOutputToChannel 115 val 6
    // OVP
    linkTuyaMCUOutputToChannel 113 val 7
    // OCP
    linkTuyaMCUOutputToChannel 114 val 8
    // child lock
    linkTuyaMCUOutputToChannel 116 bool 9
    // temperature calibration
    linkTuyaMCUOutputToChannel 117 val 10
    
    
    // NOTE: test code only so I can refresh quickly without restarting
    tuyaMcu_sendQueryState
    
    .
    Result:
    OCP and Temperature Calibration settings in the configuration panel .
    It is worth remembering that a simple text field does not multiply, so the 45 entered is 4.5°C.

    Similarly, you can add fields for thermostat settings, i.e. heating start, heating end, cooling start, cooling end fields.
    
    startDriver TuyaMCU
    startDriver NTP
    
    tuyaMCU_defWiFiState 4 
    
    // channel types
    setChannelType 1 Toggle
    setChannelType 2 Voltage_div100
    setChannelType 3 Current_div1000
    setChannelType 4 Power_div100
    setChannelType 5 Temperature_div10
    setChannelType 6 TextField
    setChannelLabel 6 OPP
    setChannelType 7 TextField
    setChannelLabel 7 OVP
    setChannelType 8 TextField
    setChannelLabel  8 OCP
    setChannelType 9 Toggle
    setChannelLabel 9 ChildLock
    setChannelType 10 TextField
    setChannelLabel 10 TemperatureCalibration
    setChannelType 11 TextField
    setChannelLabel 11 CoolingStart
    setChannelType 12 TextField
    setChannelLabel 12 CoolingEnd
    setChannelType 13 TextField
    setChannelLabel 13 HeatingStart
    setChannelType 14 TextField
    setChannelLabel 14 HeatingEnd
    
    
    
    // linkTuyaMCUOutputToChannel dpId verType tgChannel
    // toggle
    linkTuyaMCUOutputToChannel 103 bool 1
    // voltage
    linkTuyaMCUOutputToChannel 110 val 2
    // current
    linkTuyaMCUOutputToChannel 108 val 3
    // power
    linkTuyaMCUOutputToChannel 109 val 4
    // temperature
    linkTuyaMCUOutputToChannel 102 val 5
    // OPP max power (limit)
    linkTuyaMCUOutputToChannel 115 val 6
    // OVP
    linkTuyaMCUOutputToChannel 113 val 7
    // OCP
    linkTuyaMCUOutputToChannel 114 val 8
    // child lock
    linkTuyaMCUOutputToChannel 116 bool 9
    // temperature calibration
    linkTuyaMCUOutputToChannel 117 val 10
    // CoolingStart
    linkTuyaMCUOutputToChannel 105 val 11
    // CoolingEnd
    linkTuyaMCUOutputToChannel 107 val 12
    // HeatingStart
    linkTuyaMCUOutputToChannel 104 val 13
    // HeatingEnd
    linkTuyaMCUOutputToChannel 106 val 14
    
    
    
    
    // NOTE: test code only so I can refresh quickly without restarting
    tuyaMcu_sendQueryState
    
    .
    Additional fields on the web panel.
    Temperature settings interface with editable fields.

    The choice of operating mode (normal, heating, cooling) is determined for us by a variable of type enum. You will have to do a bit of fiddling to display it. Of course, it could be displayed as a number, but what for? Better to add separate buttons with nice captions. To do this, we'll use the HTTPButtons driver and add a listen for changes to the channel selected for that mode (addChangeHandler) so that we can manipulate the button colours accordingly and show them which mode is on:
    
    startDriver TuyaMCU
    startDriver NTP
    
    tuyaMCU_defWiFiState 4 
    
    // channel types
    setChannelType 1 Toggle
    setChannelType 2 Voltage_div100
    setChannelType 3 Current_div1000
    setChannelType 4 Power_div100
    setChannelType 5 Temperature_div10
    setChannelType 6 TextField
    setChannelLabel 6 OPP
    setChannelType 7 TextField
    setChannelLabel 7 OVP
    setChannelType 8 TextField
    setChannelLabel  8 OCP
    setChannelType 9 Toggle
    setChannelLabel 9 ChildLock
    setChannelType 10 TextField
    setChannelLabel 10 TemperatureCalibration
    setChannelType 11 TextField
    setChannelLabel 11 CoolingStart
    setChannelType 12 TextField
    setChannelLabel 12 CoolingEnd
    setChannelType 13 TextField
    setChannelLabel 13 HeatingStart
    setChannelType 14 TextField
    setChannelLabel 14 HeatingEnd
    
    
    setChannelType 15 ReadOnly
    setChannelLabel 15 Mode
    
    // linkTuyaMCUOutputToChannel dpId verType tgChannel
    // toggle
    linkTuyaMCUOutputToChannel 103 bool 1
    // voltage
    linkTuyaMCUOutputToChannel 110 val 2
    // current
    linkTuyaMCUOutputToChannel 108 val 3
    // power
    linkTuyaMCUOutputToChannel 109 val 4
    // temperature
    linkTuyaMCUOutputToChannel 102 val 5
    // OPP max power (limit)
    linkTuyaMCUOutputToChannel 115 val 6
    // OVP
    linkTuyaMCUOutputToChannel 113 val 7
    // OCP
    linkTuyaMCUOutputToChannel 114 val 8
    // child lock
    linkTuyaMCUOutputToChannel 116 bool 9
    // temperature calibration
    linkTuyaMCUOutputToChannel 117 val 10
    // CoolingStart
    linkTuyaMCUOutputToChannel 105 val 11
    // CoolingEnd
    linkTuyaMCUOutputToChannel 107 val 12
    // HeatingStart
    linkTuyaMCUOutputToChannel 104 val 13
    // HeatingEnd
    linkTuyaMCUOutputToChannel 106 val 14
    // mode
    /// 0 is manual
    // 1 is heating
    // 2 is cooling
    linkTuyaMCUOutputToChannel 101 val 15
    
    startDriver HTTPButtons
    setButtonEnabled 0 1
    setButtonEnabled 1 1
    setButtonEnabled 2 1
    setButtonLabel 0 Manual
    setButtonLabel 1 Heating
    setButtonLabel 2 Cooling
    setButtonCommand 0 "setChannel 15 0"
    setButtonCommand 1 "setChannel 15 1"
    setButtonCommand 2 "setChannel 15 2"
    alias clear_buttons backlog setButtonColor 0 red;setButtonColor 1 red;setButtonColor 2 red
    clear_buttons 
    
    addChangeHandler Channel15 == 0 backlog clear_buttons ; setButtonColor 0 green
    addChangeHandler Channel15 == 1 backlog clear_buttons ; setButtonColor 1 green
    addChangeHandler Channel15 == 2 backlog clear_buttons ; setButtonColor 2 green
    
    // NOTE: test code only so I can refresh quickly without restarting
    tuyaMcu_sendQueryState
    
    .
    Here is the result on the OBK panel:
    OpenBeken user interface with colorful buttons for different modes. .
    The buttons are visually appealing and responsive:
    Control panel with Manual, Heating, and Cooling modes in OpenBeken app .
    Interestingly, when I set, for example, Heating, and then change the relay status at the very top of the OBK page, the unit itself returns to Manual. Everything works!

    Summary .
    That's it for now. I think I've managed to get the vast majority of the functionality of this device working, even the mode selection and thermostat works, all without the cloud. The device configured in this way can also be connected to Home Assistant, with this particular version the automatic Discovery at the moment not yet discovering the buttons with HTTPButtons, but this should be corrected soon. Feel free to comment, and if anyone has a similar device and wants to convert it to work locally, I'm happy to help.

    Support materials:
    https://github.com/openshwprojects/OpenBK7231T_App
    https://github.com/openshwprojects/BK7231GUIFlashTool
    https://github.com/openshwprojects/OpenBK7231T_App/blob/main/docs/autoexecExamples.md

    Cool? Ranking DIY
    Helpful post? Buy me a coffee.
    About Author
    p.kaczmarek2
    Moderator Smart Home
    Offline 
    p.kaczmarek2 wrote 14386 posts with rating 12308, helped 650 times. Been with us since 2014 year.
  • ADVERTISEMENT
  • #2 21315885
    divadiow
    Level 38  
    Posts: 4833
    Help: 420
    Rate: 851
    Nicely detailed posting, thank you!

    If the TuyaMCU (CH537F) is a lower version than 1.1.0, the Tuya app will offer an update.

    I attach the OTA binary the Tuya app downloads to update the MCU - for anyone that might find this interesting.
    Screenshot of a firmware update window displaying information about a new MCU version (V1.1.0).
    Attachments:
    • Atorch_S1TW-FR_MCU_1.1.0_WCH_CH573F.bin (183.59 KB) You must be logged in to download this attachment.
  • ADVERTISEMENT
  • #3 21315934
    p.kaczmarek2
    Moderator Smart Home
    Posts: 14386
    Help: 650
    Rate: 12308
    And here is firmware dump of the described device (before pairing):
    https://github.com/openshwprojects/FlashDumps/commit/46d6a6584563a567d0cd32b849ab2a96c7972d34
    If you have a Tuya developer account and want to share dpIDs extracted with this method, feel free to do so.
    Helpful post? Buy me a coffee.
  • ADVERTISEMENT
  • #5 21316056
    p.kaczmarek2
    Moderator Smart Home
    Posts: 14386
    Help: 650
    Rate: 12308
    Nice, but it would be nice if they gave the credit for the flash files:
    https://github.com/openshwprojects/FlashDumps

    By the way, do every TuyaMCU device there has this definitions?
    Code: JSON
    Log in, to see the code
    Helpful post? Buy me a coffee.
  • #6 21316089
    divadiow
    Level 38  
    Posts: 4833
    Help: 420
    Rate: 851
    p.kaczmarek2 wrote:
    By the way, do every TuyaMCU device there has this definitions?

    hmm. not sure really. I've definitely seen quite a few with what look like dpIDs set and I assumed they were for TuyaMCU devices. I'm not that clued up on the inner workings of CC and how the profiles are structured though.
  • #7 21316141
    p.kaczmarek2
    Moderator Smart Home
    Posts: 14386
    Help: 650
    Rate: 12308
    The enumeration matches:
    Code: JSON
    Log in, to see the code

    so it's nice and helpful, however, it seems that remaining dpIDs have no names there? So it's not possible to tell which is voltage, etc...
    Helpful post? Buy me a coffee.
  • #8 21316251
    divadiow
    Level 38  
    Posts: 4833
    Help: 420
    Rate: 851
    original

    Code: JSON
    Log in, to see the code


    chatgpt formatted with english translations

    Code: JSON
    Log in, to see the code
  • #9 21316374
    p.kaczmarek2
    Moderator Smart Home
    Posts: 14386
    Help: 650
    Rate: 12308
    That's much better. Maybe we can try to make a script that converts it to OBK autoexec.bat or something?

    By the way, is:
    
    colding
    

    really a correct term there? Shouldn't it be cooling? But again, this device is Chinese...
    Helpful post? Buy me a coffee.
  • ADVERTISEMENT
  • #10 21316382
    divadiow
    Level 38  
    Posts: 4833
    Help: 420
    Rate: 851
    It's not a word I'd attribute any meaning. Could be "cooling"? I didn't give gpt any context to aid translation.

    Added after 3 [minutes]:

    But what does a "cooling" dpID mean anyway?

    Added after 3 [minutes]:

    Socket, hot, cooling. Hmm

    Added after 3 [minutes]:

    p.kaczmarek2 wrote:
    Maybe we can try to make a script that converts it to OBK autoexec.bat or something?

    I imagine any way to make a fully working device more easily, especially if it has TuyaMCU requiring autoexec, would be a welcome step.
  • #11 21316512
    p.kaczmarek2
    Moderator Smart Home
    Posts: 14386
    Help: 650
    Rate: 12308
    divadiow wrote:
    It's not a word I'd attribute any meaning. Could be "cooling"? I didn't give gpt any context to aid translation.

    This word comes from Cloutcutter profile as well. That's how chinese coders name stuff.


    divadiow wrote:

    But what does a "cooling" dpID mean anyway?

    It's one of possible options of operation mode enumeration mentioned in the main article. The following device has 3 supported modes:
    - manual (called "socket")
    - cooling
    - heating

    p.kaczmarek2 wrote:
    Maybe we can try to make a script that converts it to OBK autoexec.bat or something?

    I imagine any way to make a fully working device more easily, especially if it has TuyaMCU requiring autoexec, would be a welcome step.[/quote]
    I can try...
    Helpful post? Buy me a coffee.
📢 Listen (AI):

Topic summary

✨ The discussion focuses on converting the Atorch S1TW-FR advanced energy meter/thermostat with an LCD screen to operate entirely locally, eliminating reliance on cloud services and manufacturer servers. The process involves disassembling the device, flashing the WiFi module with OpenBeken, and configuring it to communicate with the onboard TuyaMCU. Participants share resources, including firmware dumps and OTA binaries, and discuss the structure of dpIDs for TuyaMCU devices. There is also a conversation about the terminology used in the device's operation modes, particularly the term "colding," which may refer to "cooling." The community emphasizes the importance of sharing knowledge and resources for successful device modification.
Generated by the language model.

FAQ

TL;DR: With 16 A / 250 VAC hardware and “Everything works!” as the practical result, this FAQ shows makers how to convert the Atorch S1TW-FR into a fully local OpenBeken device by flashing the CB3S/BK7231N module, mapping TuyaMCU dpIDs, and faking cloud-connected Wi-Fi state so the LCD, relay, metering, thermostat, and time keep working without Tuya cloud. [#21313613]

Why it matters: It turns a cloud-tied mains energy meter and thermostat into a locally controlled device that still keeps its LCD, relay logic, and thermostat functions.

Approach What you do Main advantage Main limitation
UART capture Sniff RX/TX during app actions Reveals practical dpID behavior from real use Risky on non-isolated mains hardware
Tuya API/model data Extract model definitions and properties Gives names, ranges, enums, and cloudless flags May miss full real-world behavior or require developer access
OpenBeken + autoexec.bat Map discovered dpIDs to channels Delivers 100% local control with web UI Needs flashing and manual configuration

Key insight: The LCD does not fully recover after flashing until OpenBeken starts the TuyaMCU driver and forces Wi-Fi state 0x04. That single compatibility step makes the device behave as if it is cloud-connected while remaining local.

Quick Facts

  • The S1TW-FR uses a CB3S Wi-Fi module with BK7231N, a BL0942 metering chip, a CH573F 32-bit RISC-V MCU, and an HF32FV-16 relay rated 16 A at 250 VAC. [#21313613]
  • Measured and mapped TuyaMCU datapoints include dpID 110 = voltage, 108 = current, 109 = power, 103 = relay, and 102 = temperature. [#21313613]
  • The thermostat-related Celsius setpoints use integer values scaled by ×10, so 21.7 °C, 25.6 °C, 12.3 °C, and 23.3 °C appear as raw numeric writes. [#21313613]
  • Protection and control values shown in testing include OVP 265→275 V, OCP 10→16 A, OPP 3000→3680 W, and temperature calibration 0→4.5 °C. [#21313613]
  • The built-in MCU model data lists 28 properties from dpID 101 to 128, including energy price, total electricity, child lock, temperature unit, cost, and reporting interval 1–90 s. [#21316251]

How do I convert an Atorch S1TW-FR energy meter/thermostat to run fully locally with OpenBeken and no Tuya cloud?

You convert it by flashing OpenBeken to the CB3S Wi-Fi module and then mapping the TuyaMCU dpIDs in autoexec.bat. 1. Open the device and identify the CB3S/BK7231N module. 2. Remove or isolate the Wi-Fi module from the MCU UART, flash OpenBeken, then resolder it. 3. Start TuyaMCU, set tuyaMCU_defWiFiState 4, and link dpIDs for relay, metering, temperature, and thermostat controls. That restores local LCD operation, relay control, time sync, and thermostat features without Tuya servers. [#21313613]

What is TuyaMCU, and how does it affect flashing and configuring the S1TW-FR?

"TuyaMCU" is a serial control architecture that splits a device into a Wi-Fi module and a separate microcontroller, with the MCU handling device logic and exchanging dpID-based packets over UART. On the S1TW-FR, the Wi-Fi module shares its UART with programming, so you must remove the module or cut its MCU connection before flashing. After flashing, OpenBeken must talk back to the MCU using the same dpIDs and simulated Wi-Fi state, or the LCD stays incomplete. [#21313613]

What is a dpID in Tuya devices, and how do I map dpIDs to OpenBeken channels on the Atorch S1TW-FR?

"dpID" is a Tuya datapoint identifier that names one device function, such as relay state, voltage, or a thermostat setpoint, and carries a typed value like bool, val, or enum. On the S1TW-FR, you map dpIDs with linkTuyaMCUOutputToChannel. Example mappings are 103 bool for relay, 110 val for voltage, 108 val for current, 109 val for power, and 102 val for temperature. Then assign channel types like Toggle, Voltage_div100, Current_div1000, Power_div100, or Temperature_div10. [#21313613]

Which components are inside the Atorch S1TW-FR, including the CB3S, BK7231N, BL0942, CH573F, and HF32FV-16 relay?

The S1TW-FR contains a CB3S Wi-Fi module based on BK7231N, a BL0942 metering IC, a CH573F 32-bit RISC-V MCU, and an HF32FV-16 relay rated 16 A at 250 VAC. The board also uses a 3.3 V LDO and a KP3211BSG non-isolated power supply controller. The BL0942 measures voltage, current, and power, while the CH573F manages the TuyaMCU side and LCD logic. [#21313613]

How can I safely intercept UART communication on a non-isolated mains-powered TuyaMCU device like the S1TW-FR?

Use galvanic isolation on both UART lines or use a completely disconnected battery-powered capture setup. The device uses a non-isolated mains supply, and the author explicitly warns that capture should preferably go through suitable opto-isolators on both RX and TX. Direct attachment of a grounded analyzer to a live, non-isolated board is the failure case to avoid. [#21313613]

Why does the S1TW-FR LCD stay stuck on startup after flashing OpenBeken, and how do I fix it with tuyaMCU_defWiFiState 4?

The LCD stays stuck because the TuyaMCU expects a valid Wi-Fi/cloud state from the Wi-Fi module after boot. OpenBeken fixes that by starting the TuyaMCU driver and forcing Wi-Fi state 4, which simulates a connected cloud session. The author states this makes the screen respond again even though the device remains fully local. [#21313613]

What is the minimal autoexec.bat needed to make the Atorch S1TW-FR screen respond after installing OpenBeken?

The minimal autoexec.bat is two lines plus spacing: start the TuyaMCU driver and set Wi-Fi state 4. Use:
  1. startDriver TuyaMCU
  2. tuyaMCU_defWiFiState 4
  3. Reboot or reload the script
That is the smallest working configuration shown to wake the LCD past its startup screen. [#21313613]

How do I read voltage, current, power, relay state, and temperature from the S1TW-FR in OpenBeken using the correct dpIDs?

Map the known dpIDs to typed OpenBeken channels and use the right scale helpers. The working set shown is relay 103 bool, voltage 110 val, current 108 val, power 109 val, and temperature 102 val. The author uses Voltage_div100, Current_div1000, Power_div100, and Temperature_div10, then calls tuyaMcu_sendQueryState to refresh values quickly. That produces live readings in the OBK panel and keeps the device display consistent. [#21313613]

What’s the difference between using UART capture and the Tuya API to discover dpIDs on a TuyaMCU device?

UART capture shows what the device actually sends during real actions, while the Tuya API can provide model definitions without live sniffing. The thread says the UART step can be replaced when using the Tuya API, but the capture method directly exposed practical mappings such as dpIDs 110, 108, 109, 103, and 102. Later posts also show Tuya model data with names, ranges, enums, and cloudless flags for dpIDs 101–128. [#21316251]

How can I add OVP, OCP, OPP, child lock, temperature calibration, and thermostat setpoints to the OpenBeken web panel for the S1TW-FR?

Add them as extra OpenBeken channels and bind each one to its dpID. The thread uses text fields for OPP 115, OVP 113, OCP 114, temperature calibration 117, cooling start 105, cooling end 107, heating start 104, and heating end 106. It uses a toggle for child lock 116. One practical detail matters: the plain text field does not auto-scale, so entering 45 means a calibration of 4.5 °C. [#21313613]

Why does changing the relay state in OpenBeken switch the S1TW-FR back to Manual mode after selecting Heating or Cooling?

Because the device treats relay state and thermostat mode as linked behaviors, changing the relay manually overrides the thermostat mode. The author observed that after selecting Heating with mode buttons, toggling the relay at the top of the OBK page makes the unit return to Manual. On this device, mode enum 101 and relay state 103 are not independent in practice. [#21313613]

How do I use the OpenBeken HTTPButtons driver to create readable Manual, Heating, and Cooling mode buttons for a TuyaMCU thermostat?

Use a read-only channel for mode, then attach three HTTPButtons that write values 0, 1, and 2. The example sets labels Manual, Heating, and Cooling, sends setChannel 15 0/1/2, and uses addChangeHandler rules to color the active button green and the others red. The mapped mode dpID is 101, where 0 = manual, 1 = heating, and 2 = cooling. [#21313613]

What do the S1TW-FR mode enum values "socket", "hot", and "colding" mean in the Tuya or Cloudcutter profile?

They mean Manual, Heating, and Cooling mode. The thread first shows the raw enum values socket, hot, and colding, then clarifies that this device supports three operating modes: manual, cooling, and heating. “Colding” is treated as a misspelled vendor string for cooling, not a separate function. [#21316512]

How does the Tuya app MCU OTA update work for the CH573F on the S1TW-FR, and what changes between firmware versions like 1.1.0?

The Tuya app can offer an MCU OTA update when the CH573F firmware is below version 1.1.0. A follow-up post says the app downloads a binary for that update and shares the file for reference. The thread does not document feature changes between versions, only that the update prompt appears when the MCU version is lower than 1.1.0. [#21315885]

What information in Tuya Cloudcutter or Tuya model definitions can be converted automatically into an OpenBeken autoexec.bat for TuyaMCU devices?

You can convert dpID numbers, access modes, value ranges, scales, enums, names, and cloudless flags into much of an autoexec.bat template. The thread shows a full model with properties 101–128, including names like cur_voltage, cur_power, ovp, ocp, opp, child_lock, and reporting_interval. The remaining limit is that some extracted profiles may expose enums and IDs but still lack enough semantic detail to identify every function with certainty without live testing. [#21316251]
Generated by the language model.
ADVERTISEMENT