leoshusar / 4heat-esphome

ESPHome integration for Tiemme 4Heat controllers.
MIT License
7 stars 1 forks source link

4Heat for ESPHome

This is a custom ESPHome integration for interfacing Tiemme 4Heat controllers.

Usage

Simply add this to your config:

external_components:
  source: github://leoshusar/4heat-esphome

And configure your components. You can also skip directly to the configuration example.

Sections

Available components:

Custom variable types

4Heat response data

I made the response parsing quite strict. If the parsing fails, it will log a warning and ignore the received value.

Currently only bool and int parsing is supported, because I haven't seen any other data types (yet).

Sometimes the data might look like this: D10000SYEVO0000562.

Someone here found that the SYEVO part is probably useless, so I simply strip it and work with only the part after. I have never seen this in a normal operation, the D10000 datapoint is some diagnostic something (response to C10000000000000000). But keep this in mind when creating custom parsers - the received data might be only 7 characters long.

Custom parsers

Every component supports custom data parser. You will get std::vector<uint8_t> data to work with, with only the data part of the received message (without the datapoint ID), and you must return a value of the correct type. If you don't want to return anything (you receive data you don't expect), return {} - empty std::optional.

If your parser doesn't return any value, the default one is then not called.

Use case example: Datapoint J40007 tells if external thermostat relay is ON or OFF. But it doesn't return boolean value 0 or 1, it returns 000000000100 if it's OFF and 000000000000 if it's ON. So I used custom parser like this:

binary_sensor:
  - platform: fourheat
    name: Room thermostat state
    datapoint: J40007
    parser: return data[data.size() - 3] == '0';

This code simply checks if the 3rd last char is '0'.

Datapoints

As written above, datapoints usually look like XYYYYY, where X is a letter and Y is a digit.

Components are configured using response datapoints. Query datapoint is then calculated automatically (by "decrementing" the first prefix letter by one). You can also specify your own query datapoint, which will override the calculated one.

Components like number or select are listening on both query and response datapoints. If you send a command to read/write datapoint, the controller responds immediately, but on the query datapoint. With this you will get immediate confirmation and you won't need to use optimistic mode.

4Heat hardware

That person here also found that there are different Tiemme controllers. Some will work with this integration, some might work, some won't, because they use Hayes AT commands.

ESPHome hardware

You only need an ESP and an RS232 module.

My controller uses RJ 11 6P4C connector and has this pinout:

Don't use the VCC for powering your ESP though, there is not much current and your 4Heat controller will start acting strange.

Config example

You can find my full config in the example.yaml.

I am using external room thermostat. If you want to use the internal one, you should be able to use J30006 for reading room temperature (sensor component) and B20493 for reading and setting target room temperature (number component). Or you can merge them all in the full climate component.

Web UI example

Official 4Heat WiFi module

If you have the official WiFi module and want to integrate it to HA, you can use this integration (or my fork with an attempt to handle timeouts somehow).

But I recommend switching to ESPHome, if you can. Their mobile app is... not great, the WiFi module itself often timeouts, it also SENDS DATA TO THEIR AZURE CLOUD VIA UNENCRYPTED HTTP. It also doesn't report too often, only like once or twice per minute. Even if you spam the module every second, the module just responds with cached values.

FourHeat Component

The base component which handles all UART communication. Requires UART Bus.

Be aware that UART0 is by default used by the logger component. If you want to use it for fourheat, you either need to disable logging into serial or change the logger UART to other one.

# Example configuration entry
uart:
  tx_pin: GPIO5
  rx_pin: GPIO4
  baud_rate: 9600

fourheat:

To disable serial logging:

logger:
  baud_rate: 0

Configuration variables:

FourHeat Binary sensor

The fourheat binary sensor platform creates a binary sensor from a fourheat component.

Requires FourHeat Component to be configured.

binary_sensor:
  # Datapoint binary sensor
  - platform: fourheat
    name: My Binary Sensor
    datapoint: J30000
    query_datapoint: I30000
    parser: return data[data.size() - 1] != '0';

  # Offline sensor
  - platform: fourheat
    name: Module Offline Sensor
    type: module_offline

Configuration variables:

Datapoint

FourHeat Button

The fourheat button platform creates a button from a fourheat component.

Requires FourHeat Component to be configured.

Since the button platform is stateless, it doesn't query any data.

button:
  - platform: fourheat
    name: My Button
    datapoint: J30000
    press_data: '1'

Configuration variables:

FourHeat Climate

The fourheat climate platform creates a climate from a fourheat component.

Requires FourHeat Component to be configured.

Currently only heating mode is supported, just because I don't know if 4Heat supports anything with cooling.

climate:
  - platform: fourheat
    name: My Climate
    datapoint: J30000
    current_temperature_datapoint: J30001
    target_temperature_datapoint: B20000
    query_datapoint: I30000
    query_current_temperature_datapoint: I30001
    query_target_temperature_datapoint: A20000
    on_datapoint: J30010
    off_datapoint: J30011
    on_data: '1'
    off_data: '1'
    parser: return data[data.size() - 1] != '0';
    current_temperature_parser: |-
      std::string int_str(data.begin(), data.end());
      return stoi(int_str);
    target_temperature_parser: |-
      std::string int_str(data.begin(), data.end());
      return stoi(int_str);

Configuration variables:

FourHeat Number

The fourheat number platform creates a number from a fourheat component.

Requires FourHeat Component to be configured.

number:
  - platform: fourheat
    name: My Number
    datapoint: B20000
    query_datapoint: A20000
    min_value: 0
    max_value: 90
    step: 1
    parser: |-
      std::string int_str(data.begin(), data.end());
      return stoi(int_str);

Configuration variables:

FourHeat Select

The fourheat select platform creates a select from a fourheat component.

Requires FourHeat Component to be configured.

select:
  - platform: fourheat
    name: My Select
    datapoint: B20000
    query_datapoint: A20000
    optimistic: true
    options:
      1: "Option A"
      2: "Option B"
      3: "Option C"
    parser: |-
      std::string int_str(data.begin(), data.end());
      return stoi(int_str);

Configuration variables:

FourHeat Sensor

The fourheat sensor platform creates a sensor from a fourheat component.

Requires FourHeat Component to be configured.

sensor:
  - platform: fourheat
    name: My Sensor
    datapoint: J30000
    query_datapoint: I30000
    parser: |-
      std::string int_str(data.begin(), data.end());
      return stoi(int_str);

Configuration variables:

FourHeat Switch

The fourheat switch platform creates a switch from a fourheat component.

Requires FourHeat Component to be configured.

switch:
  - platform: fourheat
    name: My Switch
    datapoint: J30000
    query_datapoint: I30000
    on_datapoint: J30010
    off_datapoint: J30011
    on_data: '1'
    off_data: '1'
    parser: return data[data.size() - 1] != '0';

Configuration variables:

FourHeat Text Sensor

The fourheat text sensor platform creates a text sensor from a fourheat component.

Requires FourHeat Component to be configured.

text_sensor:
  - platform: fourheat
    name: My Text Sensor
    datapoint: J30000
    query_datapoint: I30000
    options:
      1: "Option A"
      2: "Option B"
      3: "Option C"
    parser: |-
      std::string int_str(data.begin(), data.end());
      return stoi(int_str);

Configuration variables: