Skip to content

Instantly share code, notes, and snippets.

@ncolomer
Created October 12, 2025 17:02
Show Gist options
  • Save ncolomer/9c24617677f3ceea465b622141396fd6 to your computer and use it in GitHub Desktop.
Save ncolomer/9c24617677f3ceea465b622141396fd6 to your computer and use it in GitHub Desktop.
Sonoff TRVZB External Setpoint
blueprint:
name: Sonoff TRVZB External Setpoint
description: |
Control multiple TRV (Thermostatic Radiator Valve) valves using a single external temperature sensor.
Compatible with both Zigbee2MQTT and ZHA integrations.
Features:
- Directly sets external temperature on TRV (no offset calculation)
- Automatically switches TRV to external sensor mode if needed
- Automatic 2-hour update to prevent TRV fail-safe mode
- Rate limiting to preserve battery life and reduce Zigbee traffic
domain: automation
input:
external_temperature_sensor:
name: External Temperature Sensor
description: The external temperature sensor (e.g., SNZB-02) to use as the reference
selector:
entity:
filter:
- domain: sensor
device_class: temperature
target_trvs:
name: Target TRV Valves (Sonoff TRVZB)
description: Select one or more Sonoff TRVZB valves to control with the external sensor
selector:
target:
entity:
- domain: climate
device:
- manufacturer: SONOFF
model: TRVZB
update_interval:
name: Minimum Update Interval
description: Minimum time between updates on sensor changes to avoid battery drain (in seconds)
default: 300
selector:
number:
min: 60
max: 3600
unit_of_measurement: seconds
mode: slider
mode: restart
trigger:
- platform: state
entity_id: !input external_temperature_sensor
id: sensor_change
- platform: time_pattern
hours: "/2"
id: failsafe_prevention
variables:
external_sensor: !input external_temperature_sensor
target_valves: !input target_trvs
min_interval: !input update_interval
condition:
- alias: Check external sensor is available
condition: template
value_template: "{{ states(external_sensor) not in ['unknown', 'unavailable'] }}"
- alias: Determine if update should proceed
condition: or
conditions:
# Always update every 2 hours to prevent fail-safe mode
- alias: 2-hour failsafe update (bypass rate limiter)
condition: trigger
id: failsafe_prevention
# For sensor changes, respect the rate limiter
- alias: Sensor change with rate limiting
condition: and
conditions:
- alias: Triggered by sensor change
condition: trigger
id: sensor_change
- alias: Rate limiter check (minimum interval elapsed)
condition: template
value_template: >
{{ this.attributes.last_triggered is none or
(now() - this.attributes.last_triggered).total_seconds() >= min_interval }}
action:
- alias: Process each TRV valve
repeat:
for_each: "{{ target_valves.entity_id }}"
sequence:
- variables:
trv_entity: "{{ repeat.item }}"
trv_device_id: "{{ device_id(trv_entity) }}"
trv_external_temperature_input: >
{{ expand(device_entities(trv_device_id))
| selectattr('entity_id', 'search', 'external_temperature_input')
| map(attribute='entity_id')
| list
| first | default('') }}
trv_sensor_select: >
{{ expand(device_entities(trv_device_id))
| selectattr('entity_id', 'search', 'temperature_sensor_select')
| map(attribute='entity_id')
| list
| first | default('') }}
# Step 1: Ensure TRV is set to use "external" temperature sensor (slot 1)
- alias: Switch TRV to external mode if needed
choose:
- conditions:
- alias: Check if sensor select exists and is not set to external
condition: template
value_template: >
{{ trv_sensor_select != '' and
states(trv_sensor_select) != 'external' }}
sequence:
- alias: Set TRV temperature sensor to external (slot 1)
service: select.select_option
target:
entity_id: "{{ trv_sensor_select }}"
data:
option: external
# Step 2: Set the external temperature value
- alias: Check if external temperature input entity exists
condition: template
value_template: "{{ trv_external_temperature_input != '' }}"
- alias: Write external temperature value to TRV
service: number.set_value
target:
entity_id: "{{ trv_external_temperature_input }}"
data:
value: "{{ states(external_sensor) | float }}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment