Tiemme 4Heat Stove WiFi Controller

I noticed that yesterday and some little bugs like upper/lower cases of some letters. I will edit the code now and also add some other codes. After this, I will work on the error messages.

I unpacked the 4heat app (unpacked app) and I found some .js files named controllers.js
it seems inside there are all the codes the app recognizes.
i also cleaned a bit the file. both files you may download them in here

1 Like

Did you try changing the speed? usually, it is 9600 or 14400?

Also another code:

J30001000000000031 - Check Up
          {% elif SensorCode == 31 %}
            Check Up

I will change it now, in my 4heat 31, 32, and 33 is ignition. But checkup seems logical.

I have quickly scrolled throw the two files and can confirm tat this is the application code.
It consists of basically two parts, the local communication and the cloud communication.

Cause my 4heat interface is a branded resell of Oranier, we might get some more information if I unpack there App as well.

Keep you posted tonight …

Here the package again

homeassistant:
  customize:
    package.node_anchors:
      customize: &customize
        package: "4heat"
sensor:
  - platform: tcp
    name: 4heat_response
    host: 192.168.0.144
    port: 80
    timeout: 5
    buffer_size: 2048
    value_template: "{{ value|truncate(254, True) }}"
    payload: '["SEL","0"]'

  - platform: template
    sensors:
      stove_temp0:
        friendly_name: "4heat Boiler Water Temperature"
        value_template: "{{ int(states('sensor.4heat_response')[states('sensor.4heat_response').find('J30017')+6:states('sensor.4heat_response').find('J30017')+18]) }}"
        unit_of_measurement: "°C"
        device_class: temperature
      stove_temp1:
        friendly_name: "4heat Boiler SET Temperature"
        value_template: "{{ int(states('sensor.4heat_response')[states('sensor.4heat_response').find('B20180')+6:states('sensor.4heat_response').find('B20180')+18]) }}"
        unit_of_measurement: "°C"
        device_class: temperature
      stove_stat:
        friendly_name: "4heat Status"
        value_template: >
          {% set SensorResponse = states('sensor.4heat_response') %}
          {% set SensorCode = int(SensorResponse[SensorResponse.find('J30001')+6:SensorResponse.find('J30001')+18]) %}

          {% if SensorCode == 0 %}
            Off
          {% elif SensorCode == 10 %}
            Recover Ignition
          {% elif SensorCode == 30 %}
            Ignition Mode
          {% elif SensorCode == 31 %}
            Check Up
          {% elif SensorCode == 32 %}
            Ignition Mode
          {% elif SensorCode == 33 %}
            Ignition Mode
          {% elif SensorCode == 3 %}
            Stabilization Mode
          {% elif SensorCode == 5 %}
            Run Mode
          {% elif SensorCode == 7 %}
            Extinguishing
          {% elif SensorCode == 9 %}
            Block mode
          {% else %}
            Unknown mode : {{ SensorCode }}
          {% endif %}
      stove_err:
        friendly_name: "4heat Error"
        value_template: "{{ int(states('sensor.4heat_response')[states('sensor.4heat_response').find('J30002')+6:states('sensor.4heat_response').find('J30002')+18]) }}"
      stove_exhaust:
        friendly_name: "4heat Exhaust Temperature"
        value_template: "{{ int(states('sensor.4heat_response')[states('sensor.4heat_response').find('J30005')+6:states('sensor.4heat_response').find('J30005')+18]) }}"
        unit_of_measurement: "°C"
        device_class: temperature
      stove_speed:
        friendly_name: "4heat Speed"
        value_template: >
          {% set SensorResponse = states('sensor.4heat_response') %}
          {% set SensorCode = int(SensorResponse[SensorResponse.find('J30011')+6:SensorResponse.find('J30011')+18]) %}

          {% if SensorCode < 110 %}
            {{ SensorCode }}
          {% elif SensorCode == 110 %}
            Off
          {% elif SensorCode == 255 %}
            Ignition Mode
          {% else %}
            Unknown mode : {{ SensorCode }}
          {% endif %}

With all new discovered States and two minor bugfixes

maybe we should unpack the latest app, this one i found online for download. The new versions maybe have the rest of the codes that are unknown till now.

Error list:

Error 01: Safety Thermostat HV1: signalled also in case of Stove OFF
Error 02: Safety PressureSwitch HV2: signalled with Combustion Fan ON
Error 03: Extinguishing for Exhausting Temperature lowering
Error 04: Extinguishing for water over Temperature
Error 05: Extinguishing for Exhausting over Temperature
Error 07: Encoder Error: No Encoder Signal (in case of P25=1 or 2)
Error 08: Encoder Error: Combustion Fan regulation failed (in case of P25=1 or 2)
Error 09: Low pressure in to the Boiler
Error 10: High pressure in to the Boiler Error 11: DAY and TIME not correct due to prolonged absence of Power Supply
Error 12: Failed Ignition
Error 15: Lack of Voltage Supply
Error 18: Lack of fuel

1 Like

One more code:

J30001000000000006 - Modulation
          {% elif SensorCode == 6 %}
            Modulation
1 Like

Can someone verify the next codes:

J30001000000000008 - Safety
J30001000000000011 - Standby

@azos ?

I can confirm this one, I just saw it on my stove.

J30001000000000011 - Standby

I’m not sure how to verify J30001000000000008 - Safety but looking at the android app codes it is, yes.

1 Like

I finally killed my Wifi module, it is stuck in a boot loop but before I where able to discover some commands.
There is SEC, which can switch on '["SEC","1","J30253000000000001"]', off '["SEC","1","J30254000000000001"]' and unblock '["SEC","1","J30255000000000001"]'.

With CF7 could the network information be queried the other CF1 - 6 look like configuration commands for the setup.

I have also unpacked my branded APP and the command JSON looks like yours.

The controller JS is a bit different but not much.

My stove returns 24 values:

SEL,24,J30001000000000006,J30002000000000000,J30005000000000357,J30006000000000025,J40007000000000000,B20364000000000007,B20575000000000001,J30026000000000378,J30012000000000000,J30017000000000072,J30020000000000000,J30084000000000001,B20381000000000005,B20385000000000000,B20493000000000030,B20199000000000072,B20225000000000055,B20369000000000006,B20570000000000000,B20369000000000006,B20365000000000030,B20366000000000075,B20374000000000045,B20375000000000070

with 462 char.

As soon as I have back the wifi access I’ll test the meanwhile build integration.
This is my python test script:

#!/usr/bin/env python
#import appdaemon.plugins.hass.hassapi as hass
import socket
import sys
from time import sleep
from unittest import result

TCP_IP = '192.168.0.144'
TCP_PORT = 80
BUFFER_SIZE = 1024
MESSAGE = '["SEL","0"]'
#MESSAGE = '["CF6","0"]' # WLAN info
#MESSAGE = '["CF7","0"]' # WLAN info
#MESSAGE = '["CF4","0"]' # Set WLAN info
#MESSAGE = '["SEC","1","J30254000000000001"]'
#MESSAGE = '["SEC","1","J30253000000000001"]'

class FourHeat():

    def initialize(self):
        self.log("Hello from AppDaemon")
        self.run_every(self.handle_query_info, "now", 10)

    def handle_query_info(self):
        print("Update Data " + MESSAGE)
        result = ""
        print(len(result))
        while 0 == len(result): 
            try:
                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                s.settimeout(10)
                s.connect((TCP_IP, TCP_PORT))
                s.send(MESSAGE)
                #s.send(ONMESG)
                result = s.recv(BUFFER_SIZE)
                s.close()
            except Exception as err:
                sleep(5)
                print(err)
                s.close()
        print("Done, Data:")
        result = result.replace("[","")
        result = result.replace("]","")
        result = result.replace('"',"")
        li = result.split(",")
        print(result)
        print(len(result))
        print(li)
        for x in li:
            print(x)

def main():
    f = FourHeat()
    f.handle_query_info()


if __name__ == '__main__':
    sys.exit(main())

Hope that helps for the moment

2 Likes

I’ve managed to get some info on RS485 it uses RJ45 connector with the following pinout

PIN4 → A/+
PIN5 → B/-
PIN7 → +12V
PIN8 → GND

Regarding the protocol being used for screen is Modbus RTU at 19200

I was able to get some messages decoded with IONinja but modubus message lengths are all wrong most of them have length which is not multiple of 2 bytes and. And messages are somewhat fine until touch screen is connected. Connecting the screen starts returning all sorts of bad data and most of the messages have invalid checksums. But I was able to get some messages decoded when it send the firmware version of the screen on the bus.

Maybe they are using some sort of custom modbus implementation so a further debugging is needed. I’m working for the first time with modbus so any suggestions from someone with experience are welcome

In any way i think modbus is very complex protocol for remote control. Getting info on RS232 will be a way better solution but I don’t have the 4 heat module to be able to sniff the communication.

I have the module. It uses RJ11 cable and only the 4 wires in the mid. I think it is straight cable. How can I help? @najdanovicivan

First we need to find the correct pinout

RJ11 is 4pin connector. On NG21 board there is RJ12 which has 6 pins.

Does the module uses any other cables beside that one ? eg. external cable for power supply

Can you also check how many wires are inside the connector on the NG21 (Main Board) side and how wires are places. Eg colors/pin positions. Image of the bottom side of that connector will be useful

I found this video Installation 4HEAT MORETTI DESIGN - YouTube

So it uses only one cable. So we should at least have 4 wires, GND, VCC, RX, TX

2 Likes

@najdanovicivan
Ivane,
i just took photos of the cable, as I suspected it is a straight cable and uses only the mid 4 pins. Here is the photo.

@zauberertz
Thomas,
I tried the wifi commands CF6 then CF7. After receiving the info of my wifi setup with CF7, the 4heat device went dumb, no communication, anything. Resetting from the power supply was not working, so I reset it via the button. During the setup with the app, the device didn’t save the config and was ready to setup again (blinking blue and red).
At some moment I tried and added fixed IP, instead of using DHCP. That worked. Now I use fixed IP.

Thats might the same issue I had with my unit.
I have been able to recover it. My problem where that it did not find its way back into my wifi. So I gave it a different IP at the DHCP cause the script was still running and tried to pull data. After completing the setup i switched back to the original IP and everything worked fine agin.

It looks like the CF commands put the device in a special state where you not able to pull data. Further more it causes issues when you do so.

I have build about 70% of the integration and hope to finish to night .

1 Like