Portrait Michael Malura

Zigbee Smart Heating: Telegraf Crashes and TRVs Lie

I have 6 Zigbee devices for heating control: 4 Sonoff thermostats (TRVs) and 2 temperature sensors. But only 3 of them showed up in InfluxDB. Telegraf was running, zigbee2mqtt too, but something in between was broken. So I debugged it.

The Zigbee smart heating setup ran for a few days, then I noticed that not all devices were delivering data. Time to debug.

Telegraf crashes with bridge topics

Telegraf subscribed to zigbee2mqtt/+, a wildcard that matches ALL topics. That went wrong because zigbee2mqtt also sends zigbee2mqtt/bridge messages with arrays and nested objects. Telegraf's JSON parser couldn't handle them and crashed.

The fix was explicit device topics instead of a wildcard in the Telegraf config:

[[inputs.mqtt_consumer]]
  topics = [
    "zigbee2mqtt/Büro Temp",
    "zigbee2mqtt/Büro groß",
    "zigbee2mqtt/Büro klein",
    "zigbee2mqtt/Wohnzimmer Temp",
    "zigbee2mqtt/Wohnzimmer groß",
    "zigbee2mqtt/Wohnzimmer klein",
  ]

After that all 6 devices arrived in InfluxDB.

TRV measures way too warm

The thermostat "Büro klein" showed 24°C even though the external sensor reported 21°C. The valve regulated accordingly wrong. Turned out that temperature_sensor_select was set to internal. The internal sensor sits right on the radiator and measures the radiator temperature, not the room air.

So I switched it to the external sensor via MQTT:

mosquitto_pub -t "zigbee2mqtt/Büro klein/set" \
  -m '{"temperature_sensor_select": "external_2"}'

Now the TRV regulates based on the real room sensor.

valve_opening_degree misunderstanding

I thought valve_opening_degree showed the current valve position in percent. But it stayed constantly at 100%, regardless of whether the valve was open or closed. Research in the zigbee2mqtt documentation and GitHub issues led to the realization that the field is a calibration limit, not the position.

The Sonoff TRVZB doesn't output the actual valve position as a percentage. Only running_state (idle/heat) shows whether it's actively heating.

So I removed the panel and built a state timeline for running_state instead. For that I had to add running_state to the Telegraf config as json_string_fields:

json_string_fields = ["running_state", "battery", "linkquality"]

Now I can see for each TRV whether it's currently heating or idle. That's enough.

Lessons Learned

  • Wildcards in MQTT subscriptions are dangerous when the topics have different structures
  • TRVs with an internal sensor are unreliable → always use external sensors
  • Read the documentation before getting annoyed about "broken" values, sometimes fields don't mean what you think

The heating control now runs cleanly. All 6 devices log correctly, the TRVs regulate based on real room temperatures.

Zigbee Geräte Status
Zigbee Geräte Status
16.04.2026 updated 27.06.2026
Share X Reddit Hacker News LinkedIn E-Mail