Sharing enlightening moments of home automation

Regain Local Control to Smart Panel Heater

It’s time for an update on my Arlec panel heater (Model PEH223HA) after I partially lost control of the device in Home Assistant. So, here are the steps that I took to regain access.


  • The climate device in Home Assistant was still showing up, so the MQTT integration was still working fine in principal.
  • Changing the Mode or Fan Mode did not work anymore; I could still select a different option, but it would change back to the previous value after a couple of seconds, and there was clearly no change on the device itself.
  • I was not able to change the target temperature anymore.

Tasmota update

The first thing I did is update the device itself to the latest Tasmota version. I originally intalled version 9.4.0 and shortly after updated to 9.5.0 but that is where I stayed for the last two years.

  1. Backup your configuration. In the device’s web UI click Configuration -> Backup Configuration
  2. Download and install minimal Tasmota binary. This step is required due to the limited memory on the device itself. After installing the minimal binary the only next step you can take is to install another binary.
  3. Download and install standard (without any customisations) Tasmota binary.

After the update I just quickly checked that all the configuration was still there, and indeed the device was still configured just as before the update, but I still had not regained full control in Home Assistant.


To trouble-shoot what was going on I looked at three different things:

  1. I looked into the device log. Click Console button in the device’s web UI, and messages show up. What I immediately noticed here was that the serial messages received from the MCU (that controls the thermostat) where incomplete (Example: {"SSerialReceived":"). So that was a first hint that something was wrong in the serial communication.
  2. I then used mosquitto_sub to listen to any messages exchanged on my MQTT broker. And here those same serial messages appeared wrong, too (Example: {"SSerialReceived":"A~"}). All messages received clearly were not HEX encoded.
  3. I also closely observed the Home Assistant UI when making changes to the climate entity. Toast messages appeared in the bottom left indicating that something may be configured incorrectly in the entity itself. Some messages were clearly related to the above issue where I was expecting a HEX encoded value which Home Assistant was attempting to decode but of course failed. Other messages were indicating that I may have missed a update or breaking change message in one of the many releases since my original implementation.

Fixing serial communication

After reading through issue reports in Tasmota’s GitHub repository I found hints that some time in early 2022 a setting related to serial communication was changed that may have broken my configuration. All I had to do is define a serial delimiter to fix this issue; the following command needs to be execute on the device’s Console:

SerialDelimiter 254

After making this configuration change, the serial messages were again issued in HEX format.

Fixing Home Assistant configuration

I made some modifications to my climate entity configuration:

  1. Modernised the YAML configuration: Now, climate goes underneath the mqtt integration. This is actually something I had already done some time after the 2022.06 release where the old way was deprecated.
  2. Added mode_command_topic and mode_command_template

Here is the complete YAML configuration of the climate entity for locally controlling the panel heater.

    - name: "Panel Heater Office"
      unique_id: "esp_panel_heater_office_climate"
      availability_topic: "esp_panel_heater_office/tele/LWT"
      payload_available: "Online"
      payload_not_available: "Offline"
        - "off"
        - "heat"
      mode_state_topic: "esp_panel_heater_office/tele/RESULT"
      mode_state_template: "{% if value_json['SSerialReceived'][20:22] == '00' %}off{% else %}heat{% endif %}"
      mode_command_topic: "esp_panel_heater_office/cmnd/sserialsend5"
      mode_command_template: >
        {% set modes = { 'off': '02', 'heat': '01' } %}
        {% set fan_modes = { 'off': '00', 'low': '02', 'high': '03', 'anti-frost': '04'} %}
        {{ ["F1F10210", modes[value], "0000000000", fan_modes[state_attr('climate.panel_heater_office', 'fan_mode')], ('%#x' % (state_attr('climate.panel_heater_office', 'temperature') | int))[2:], "01000001000001", (('%#x' % ( 21 + (modes[value] | int) + (fan_modes[state_attr('climate.panel_heater_office', 'fan_mode')] | int) + (state_attr('climate.panel_heater_office', 'temperature') | int)))[2:] | upper), "7E"] | join }}
      power_command_topic: "esp_panel_heater_office/cmnd/sserialsend5"
      payload_on: "F1F10210010000000000000000000001000001157E"
      payload_off: "F1F10210020000000000000000000001000001167E"
        - "off"
        - "low"
        - "high"
        - "anti-frost"
      fan_mode_state_topic: "esp_panel_heater_office/tele/RESULT"
      fan_mode_state_template: "{% if value_json['SSerialReceived'][20:22] == '02' %}low{% elif value_json['SSerialReceived'][20:22] == '03' %}high{% elif value_json['SSerialReceived'][20:22] == '04' %}anti-frost{% else %}off{% endif %}"
      fan_mode_command_topic: "esp_panel_heater_office/cmnd/sserialsend5"
      fan_mode_command_template: >
        {% set modes = { 'off': '02', 'heat': '01' } %}
        {% set fan_modes = { 'off': '00', 'low': '02', 'high': '03', 'anti-frost': '04'} %}
        {{ ["F1F10210", modes[states('climate.panel_heater_office')], "0000000000", fan_modes[value], ('%#x' % (state_attr('climate.panel_heater_office', 'temperature') | int))[2:], "01000001000001", (('%#x' % ( 21 + (modes[states('climate.panel_heater_office')] | int) + (fan_modes[value] | int) + (state_attr('climate.panel_heater_office', 'temperature') | int)))[2:] | upper), "7E"] | join }}
      temperature_state_topic: "esp_panel_heater_office/tele/RESULT"
      temperature_state_template: "{{ value_json['SSerialReceived'][22:24] | int(base=16) }}"
      temperature_unit: "C"
      min_temp: 18.0
      max_temp: 30.0
      temperature_command_topic: "esp_panel_heater_office/cmnd/sserialsend5"
      temperature_command_template: >
        {% set modes = { 'off': '02', 'heat': '01' } %}
        {% set fan_modes = { 'low': '02', 'high': '03', 'anti-frost': '04'} %}
        {{ ["F1F10210", modes[states('climate.panel_heater_office')], "0000000000", fan_modes[state_attr('climate.panel_heater_office', 'fan_mode')], ('%#x' % (value | int))[2:], "01000001000001", (('%#x' % ( 21 + (modes[states('climate.panel_heater_office')] | int) + (fan_modes[state_attr('climate.panel_heater_office', 'fan_mode')] | int) + (value | int)))[2:] | upper), "7E"] | join }}
      precision: 1.0
      current_temperature_topic: "esp_panel_heater_office/tele/RESULT"
      current_temperature_template: "{{ value_json['SSerialReceived'][28:30] | int(base=16) }}"


So, after all this, at its core it was probably just the two missing lines in the YAML configuration that prevented me from full local access of the panel heater. The other issue I experienced was probably just due to the decision to update to the latest Tasmota version which required me to add that new serial delimiter.

Either way, I just wanted to share my journey and the configuration that keeps working in my ecosystem with the current Tasmota version and Home Assistant version.


At the time of writing this post, I used:

  • Home Assistant 2023.11.2 with Python 3.11.6 in Docker
  • Tasmota 13.2.0


Leave a Reply

Your email address will not be published. Required fields are marked *