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 }}"