Help with detecting if a room in the house in below temperature

I’ve created a group.all_radiators containing all my Tado Thermostatic Valves in one group.

My idea is to create a template sensor that iterates over each radiator, and if one of the radiators’ current_temperature is below the rooms desired temperature, then the sensor should be set to “Cold”.

I’m pretty new to Jinja2, so am trying to get my head around the whole variables not being available outside a scope (loop), otherwise I would have just set a variable to cold then returned this variable at the end of the for… loop.

Here’s what I’ve got so far:

      cold_rooms:
        friendly_name: Cold Rooms
        value_template: >
          {% for radiator in states.group.all_radiators.attributes.entity_id %}
          {% if state_attr(radiator,'current_temperature') | float < state_attr(radiator,'temperature') | float %}
          COLD
          {% else %}
          HOT
          {% endif %}
          {% endfor %}

Obviously the result is a mess:

COLD HOT HOT HOT HOT HOT HOT

All I want is Cold to be set as the sensor state if any one of the radiators is colder than its configured temperature. I’m obviously missing something so obvious I will kick myself.

Any help much appreciated :slight_smile:

I know how to fix the loop issue but first I have a request:

Please post an example of the configuration for one of these radiators. I’m curious to know which platform it uses.

One more thing, is each radiator controlled by a climate component?


EDIT
Let me clarify:

If all members of group.all_radiators are climate components (i.e. thermostat) then if current_temperature is lower than temperature it causes the state to change to heat (unless it is off). Creating a template to detect all climate entities whose state is heat is trivial. So is there a special reason for the test you’ve chosen, to compare current_temperature to temperature?


EDIT 2

In case you’re not in the mood to answer questions, :slight_smile: this might meet your needs (assuming the group contains only climate components):

          {% set ns = namespace(cold=0) %}
          {% for r in expand('group.all_radiators') %}
            {% set ns.cold = ns.cold + (1 if r.attributes.current_temperature | float < r.attributes.temperature | float else 0) %}
          {% endfor %}
          {{ 'cold' if ns.cold > 0 else 'hot' }}
1 Like

Thanks for the assistance and your curiosity! Happy to explain further, I just didn’t want to clutter the actual issue with my entire plan.

So I am using Tado TRV’s (thermostatic radiator valves) and am controlling them through the Homekit integration. I used to use the official Tado component but I’m trying to slowly move away from as many clouds as possible. There’s no configuration to post as they show up in my integrations section of HA. Can of course post a screenshot if you want. And yes indeed, each TRV has its own climate component and respond to service calls such as climate.turn_on/off/hvac_mode etc.

When I moved into this house it came with a Samsung Heat Pump controllable via traditional thermostat but also a Wifi kit which is controllable via smart things. So I decided to try to get the TRV’s and the Wifi kit to play nicely together. My idea is as follows:

HA detects that I am leaving work, or within a 5 km radius of my house.
TRVs are set to heat mode, with a target temperature of 20C (or whatever the input_slider is set to).
Template sensor.cold_rooms detects that the actual temperature reported by one of the TRVs is lower that the target target temperature, and so its state becomes COLD.
The COLD indicates that my boiler is actually required to be operational, so another automation turns on my Samsung Heat Pump (boiler).

Obviously I would need to add a few acceptable ranges of temperatures, as I don’t want the boiler constantly switching on or off, but those will come later.

This also gives me the advantage of allowing any home member of activating the heat pump as all they need to do is turn one of the TRVs to their desired temperature.

Last year I was running Tado’s own App logic and presence detection, but my boiler was on a standard timer which ended up costing me much more electricity than was necessary. Hence this whole concept.

Thanks for posting the workaround. I did find a similar workaround to getting a variable to escape a scope, but didn’t manage to get it to work. However I changed ‘namespace’ to something else. Is namespace a system variable or something?

1 Like

namespace is not a variable but a concept used in python to create a collection of unique names. In this case, any variables you create within the for-loop have a scope (i.e. where they are understood to be defined) that is limited to the for-loop. They are undefined outside the for-loop. So we create a a namespace containing one variable whose scope is valid outside and inside the for-loop.


EDIT

I see my previous post has lost its ‘Solution’ tag. Did it fail to work as you expected? Let me know what it’s doing (or not doing) and perhaps I can help you fix it.

1 Like

Hmm strange issue I just noticed. The sensor does not seem to update on my changes. I changed one of the rooms temperatures to 24, as the current temperature is 22:

In the Template Editor sandbox, the result is ‘cold’ as expected:

However the actual sensor is still showing ‘hot’
Capture

Do you think the namespace concept is not returning to the original value of 0 after the template runs?

Here’s the actual sensor template:

      cold_rooms:
        friendly_name: Cold Rooms
        value_template: >
          {% set ns = namespace(cold=0) %}
          {% for r in expand('group.all_radiators') %}
            {% set ns.cold = ns.cold + (1 if r.attributes.current_temperature | float < r.attributes.temperature | float else 0) %}
          {% endfor %}
          {{ 'cold' if ns.cold > 0 else 'hot' }}

The template I suggested will definitely fail to update if used in a Template Sensor. That’s because there’s nothing within the template that Home Assistant can identify as an entity to be monitored except for group.all_radiators. However, the group’s state-changes aren’t what we want to monitor, we want to monitor the state-changes of its members.

Ideally, Home Assistant would understand that expand('group.all_radiators') means we want to monitor all the members of the group for state-changes … but it doesn’t. I’ve posted a Feature Request for it (and you may wish to cast your vote in favor if it). There are two ways to cope with it now:

  1. List all the group’s members in the the Template Sensor’s entity_id option.
  2. Eliminate group.all_radiators from the template and define a list containing them.

Here’s the first workaround. As you can see, it effectively duplicates the group’s membership in entity_id. Home Assistant will easily detect the entities to be monitored and this Template Sensor will trigger when any of them changes state.

      cold_rooms:
        friendly_name: Cold Rooms
        entity_id:
          - climate.tado_office_radiator
          - climate.tado_another_room_radiator
          - climate.tado_etc
        value_template: >
          {% set ns = namespace(cold=0) %}
          {% for r in expand('group.all_radiators') %}
            {% set ns.cold = ns.cold + (1 if r.attributes.current_temperature | float < r.attributes.temperature | float else 0) %}
          {% endfor %}
          {{ 'cold' if ns.cold > 0 else 'hot' }}

Here’s the second workaround. It creates a list called rads containing all the desired radiator entities. Home Assistant will detect the entities to be monitored and the Template Sensor will trigger accordingly.

      cold_rooms:
        friendly_name: Cold Rooms
        value_template: >
          {% set rads = [ states.climate.tado_office_radiator,
                          states.climate.tado_another_room_radiator,
                          states.climate.tado_etc ] %}
          {% set ns = namespace(cold=0) %}
          {% for r in rads %}
            {% set ns.cold = ns.cold + (1 if r.attributes.current_temperature | float < r.attributes.temperature | float else 0) %}
          {% endfor %}
          {{ 'cold' if ns.cold > 0 else 'hot' }}

EDIT
Correction. Added missing final line to the second template:

          {{ 'cold' if ns.cold > 0 else 'hot' }}
2 Likes

Legend mate. TIL :slight_smile: am gonna try out both workarounds when I get back tonight and let you know how it goes. I’ll also vote on that issue. Thanks again.

Ok just tried it out. I went for the second one as its a bit more concise. Just and FYI You did miss out the final ‘return’ line:

{{ 'cold' if ns.cold > 0 else 'hot' }}

After adding that back in it works perfectly. Much appreciated.
I guess I was trying to teach myself Jinja2 while simultaneously attempting to improve my HA config. I wanted to find a way to iterate over groups instead of having to type of every entity_id. But I guess that’s not possible with the current way expand(group) is implemented right now so hopefully your issue gets more than 12 votes and gets implemented! I have definitely learned a lot though so no dramas!

1 Like