private@homelab: ~/latest
Home Assistant · Zigbee2MQTT · local control
private@homelab:~$ cat guides/article.md
·
· ·
9–13 minutes
read

Sonoff TRVZB Radiator Valve: Zigbee2MQTT + Home Assistant

Pair the Sonoff TRVZB into Zigbee2MQTT with no Sonoff bridge or eWeLink account, set valve opening degree, and drive it off an external room sensor.

The SONOFF TRVZB is a battery-powered Zigbee radiator thermostat with an M30 × 1.5mm connection. It can pair with an independently supported Zigbee2MQTT coordinator without a SONOFF bridge or eWeLink account. The mechanical fit and the source of its control temperature matter as much as pairing.

This guide uses SONOFF’s product/manual information and the TRVZB device reference, checked against converters 26.115.1 in Zigbee2MQTT 2.14.2. It includes current temperature-source names and a guarded Home Assistant synchronization example. No valve was installed or heating performance measured here.

What the TRVZB is and who it fits

The native fitting is M30 × 1.5mm. Other valves may need the correct adapter and pin extension; an included adapter assortment does not guarantee every radiator fits. Identify the existing valve, then use SONOFF’s adapter-selection guide and the installation manual. Check the actual package contents before assuming a particular adapter is supplied.

The product specification calls for three 1.5V LR6 alkaline AA batteries, normally purchased separately. SONOFF says typical batteries last more than six months, depending on cells and conditions; that is a vendor estimate rather than a measured replacement interval here. The exact TRVZB label matters when newer thermostat models have different features.

Remove only the thermostatic head as directed, rather than loosening the water-containing valve body. The new head must seat correctly and reach the valve pin. If an adapter or pin arrangement is wrong, a completed Zigbee interview cannot fix it. Check fit before relying on the motor’s adaptation result.

Pairing with Zigbee2MQTT — no Sonoff bridge required

Mechanical adaptation precedes the normal pairing step; it is not simply a calibration that joining automatically performs. Follow the model’s installation sequence:

  1. Fit the correct batteries and allow the installation/adaptation preparation display to finish flashing.
  2. Install and fasten the head using the correct fitting/adapter. Short-press the middle button to start adaptation, then wait for initialization to finish and the temperature display to appear. If it reports a fit/calibration error, check mounting and the valve mechanism before joining.
  3. Enable joining in Zigbee2MQTT. Put the valve in manual mode, turn the dial counterclockwise until it shows OF, then hold the middle button for three seconds until the network icon flashes.
  4. Wait for the interview and configuration to complete, assign a friendly name such as radiator_livingroom, and inspect the actual exposes.
  5. Close joining and test an ordinary setpoint/mode change. Confirm fresh temperature and operating-state reports, then check the radiator’s physical response under normal heating-system operation.

The pairing window lasts three minutes according to the manual. If it expires, repeat the documented OF/button step. The device page has additional display-specific recovery notes for failed adaptation; do not treat every failed interview as a reason to factory-reset a working network. Our coordinator comparison covers hardware choice separately.

This shell command shows the bridge’s device list. Replace the broker address/base topic and add your broker’s required credentials or TLS options. Confirm the exact model/name in the returned JSON; a listed device still needs the functional checks above:

Device list — shell
mosquitto_sub -h 192.168.10.20 -t 'zigbee2mqtt/bridge/devices' -C 1

Controls and diagnostics, explained

The installed version and device firmware determine which controls work. These are the main current controls and diagnostics; a property name is not necessarily the Home Assistant entity ID:

Property Values / access Use and limitation
occupied_heating_setpoint 4–35°C, 0.5° steps; set/get Requested thermostat target
local_temperature Reported climate temperature; get Do not assume every firmware reports the selected external reading here
system_mode off, auto, heat; set/get Off/frost, device schedule or manual heating control
running_state idle, heat; get Reported valve operating state, not proof the boiler is supplying heat
local_temperature_calibration −12.7 to +12.7°C, 0.2° steps Temperature offset, distinct from motor adaptation
temperature_sensor_select local_temperature, remote_temperature, remote_source_offline; set/get Local control source, remote source or remote-offline fallback status
external_temperature_input 0–99.9°C; set/get External measurement supplied by another automation
valve_opening_degree 0–100%; set/get; firmware ≥1.1.4 Opening end-position percentage; default 100
valve_closing_degree 0–100%; set/get; firmware ≥1.1.4 Closing end-position percentage; default 100 means full closure
frost_protection_temperature 4–35°C; set/get Off-mode frost threshold, not a floor overriding every schedule
child_lock LOCK / UNLOCK; set/get Locks physical input
open_window ON / OFF; set/get Enables the valve’s temperature-drop response
idle_steps, closing_steps Reported motor counts; get only Adaptation diagnostics
Opening/closing limit and motor-running voltages mV; get only Motor diagnostics, not writable position controls
weekly_schedule_[day] Up to six transitions per day; set, no get Device schedule used in auto mode
temperature_accuracy −1 to −0.2°C in 0.2° steps; firmware ≥1.3.0 Control hysteresis, not an accuracy guarantee for the thermometer
smart_temperature_control true / false on supported firmware Adaptive PID control; incompatible controls become unavailable

The reference also lists temporary_mode_select (boost/timer), temporary_mode_duration and timer_mode_target_temp. Boost is described as up to 180 minutes; timer up to 24 hours. Check current firmware and returned state rather than assuming every field is implemented on an older unit.

Opening and closing percentages describe the configured end positions, not measured water flow. Limiting heating’s opening does not inherently require reducing full closure. For example, 30% opening and 70% closing aim to leave a similar partial position in both states; those settings are not a guarantee of fixed pin travel, room temperature or flow. In particular, a reduced closing value can leave the valve partly open when you expect it to shut.

OTA issue #1062 reports calibration loss/incomplete closure with these settings on firmware 1.4.1; the reporter did not establish whether 1.4.4 fixed it. That is a reported fault, not a reproduced universal effect. For incomplete closure, check fit, cells, configured end positions and the documented adaptation process before assuming hardware failure or performing a reset.

SONOFF’s smart-temperature-control note requires firmware 1.4.4 or later. It describes adaptive PID operation and says valve-opening-percentage and temperature-accuracy controls are unavailable when enabled. Do not combine incompatible manual-limit assumptions with that mode.

Our debounce/throttle guide covers publication filtering, but it does not repair the measurement, motor fit or external-source freshness.

Calibrating against the valve’s sensor vs. using an external temperature sensor

With the built-in source selected, radiator proximity can make its reading differ from a separate room sensor. Compare repeated readings under useful operating conditions before choosing a fixed offset. An offset is suitable for a reasonably consistent difference; it cannot remove every changing thermal gradient.

The current released TRVZB converter uses local_temperature for the built-in source and remote_temperature for supplied readings. remote_source_offline represents the firmware’s fallback to the built-in sensor. Raw states 1 and 3 both decode as remote; state 2 decodes as offline. These are not three separate external sensor slots.

Older installations used internal/external/external_2/external_3. Use the values actually supported by your installed definition, rather than blindly pasting a newer label. Issue #29650 records older state changes and user workarounds. A newer 2.14.2 report describes published legacy values conflicting with the declared new options. Neither proves that every valve randomly changes source. If you see an invalid-option error, compare raw MQTT, discovery, loaded converters and versions before forcing an old string into a current select.

For a unit matching the current definition, first supply a known numeric reading, then select the remote source. This Unix-shell example is a manual configuration check, not a measured room temperature:

Manual external-temperature check — shell
mosquitto_pub -h 192.168.10.20 -t 'zigbee2mqtt/radiator_livingroom/set' -m '{"external_temperature_input":21.4}'
mosquitto_pub -h 192.168.10.20 -t 'zigbee2mqtt/radiator_livingroom/set' -m '{"temperature_sensor_select":"remote_temperature"}'

Check the returned source/input values and actual behavior. local_temperature is the device-reported thermostat attribute; compare it with the supplied input and a separate reference instead of assuming it always equals the selected remote value. External input is not automatically synchronized by Zigbee2MQTT.

A Home Assistant automation can send changed readings and periodically refresh an unchanged valid value. The following is one automation for the UI’s YAML editor; in automations.yaml, add it as a list item. Replace the sensor and MQTT topic, and enable it only after verifying the manual setup:

Home Assistant automation — single UI YAML mapping
alias: Sync living room TRV external temperature
triggers:
  - trigger: state
    entity_id: sensor.living_room_temperature
  - trigger: time_pattern
    minutes: "/5"
  - trigger: homeassistant
    event: start
conditions:
  - condition: template
    value_template: >-
      {{ is_number(states('sensor.living_room_temperature'))
         and 0 <= (states('sensor.living_room_temperature') | float) <= 99.9 }}
actions:
  - action: mqtt.publish
    data:
      topic: zigbee2mqtt/radiator_livingroom/set
      payload: >-
        {{ {'external_temperature_input': states('sensor.living_room_temperature') | float} | tojson }}
mode: single

The numeric/range guard skips unknown and unavailable values instead of converting them to zero. The five-minute refresh is a configurable example, not a vendor-established timeout. It sends only the temperature; it does not repeatedly override the selected source. Disable it when returning to built-in control.

Check the source sensor’s health

A numeric Home Assistant state can still be old. This example does not validate measurement age. Add a freshness/availability check suited to the source sensor’s reporting behavior, and test what the valve does when updates stop. Current documentation describes remote-offline fallback and return to remote when the source reconnects; it does not justify promising that every firmware uses the last value forever or shares one timeout.

Community blueprints can add freshness or selection handling, but read their conditions and version assumptions first. The Aqara SRTS-A01 guide is a comparison of another valve’s external-input workflow, not evidence that its source/fallback behavior is identical.

If you prefer the built-in sensor and an offset, disable external synchronization, select local_temperature on the current definition and verify the returned mode and temperature. A factory reset is a separate last-resort operation: the manual describes holding the middle button while inserting batteries, and warns that all previous settings are removed. Record settings/schedules and plan adaptation and pairing again before doing it.

Frost protection, open-window detection, and on-device schedules

The current converter describes frost_protection_temperature as an off-mode threshold. It opens this valve when the relevant temperature becomes too low; it cannot make an idle boiler or disconnected heating system provide hot water. Do not treat it as verified whole-building freeze protection or a floor overriding every operating mode.

Open-window detection responds to a temperature drop, not an actual window contact. The reference uses more than 1.5°C in 4.5 minutes; the manual describes a temporary 12°C setting and recovery conditions. Check the actual mode/display instead of assuming detection guarantees a fully closed valve.

For device scheduling, auto uses the weekly schedule. Each day accepts up to six HH:mm/temperature transitions, beginning at 00:00, with 4–35°C targets in 0.5° steps. For example, {"weekly_schedule_monday":"00:00/16 06:30/20 22:00/16"} can be published to the valve’s /set topic on a supported definition. Repeat for the other days, choose auto mode and verify the intended changes.

These settings are stored on the device, so normal on-device scheduling does not need a continuously running Home Assistant automation. External-temperature control still depends on fresh supplied measurements. Neither a restart nor a network outage establishes that every function continues unchanged; test the mode you intend as a fallback.

Child lock

Use {"child_lock":"LOCK"} or {"child_lock":"UNLOCK"} with the current definition. It controls physical input; the writable Zigbee controls remain a separate interface. Test the lock and your intended remote control rather than treating it as a security barrier against every configuration change.

FAQ

Can I use it without eWeLink? Yes, through a supported independent Zigbee2MQTT coordinator. The eWeLink data article concerns the separate app service; DIY Mode concerns other Wi-Fi hardware.

How do I use a room sensor? Verify the installed temperature-source names, supply a valid input, select remote control and keep the input refreshed. Check source health and actual fallback behavior.

Do both valve percentages need changing? Not merely to limit the heating opening. Opening and closing are separate end-position controls; reducing closure can leave a partial opening. Check firmware support and adaptive-mode incompatibilities.

Which fitting and batteries? M30 × 1.5mm natively and three 1.5V LR6 alkaline AA cells. Other valves need the verified correct adapter, not a general compatibility promise.

Does it need a SONOFF bridge? Not for the independent supported Zigbee2MQTT path. A coordinator and exact-device support are still required.

Can I keep a schedule on the valve? Yes, the supported weekly schedules run in auto mode. Verify each day’s transition and distinguish the schedule from external-sensor synchronization.

What’s verified, what stays local, what to check yourself

Mechanical/battery instructions come from SONOFF; access, ranges, mode values and firmware-qualified controls were checked in the released converter and device page. The calibration and source-label reports were read as individual reports, with no claim of reproducing or conclusively resolving them. Version differences remain relevant.

The independent thermostat/coordinator/MQTT route can operate without a SONOFF cloud account. OTA downloads, a hosted broker or other Home Assistant services are separate. Verify mechanical adaptation, actual source/input, update health, closure and schedule behavior before relying on the valve for heating.

local-firstHome Assistantno-cloud