Beginner's templating question

That’s why I asked. Before coding it’s great to describe your goal as clear as possible. Then choose how to achieve it.

In your case you’ll need more than one sensor so you don’t need one template that does everything.
One option is to create as many template sensors as you like and in each one use a shortened version that extracts only data that’s required - in case of Min temp you might remove all related to ns.max_temp from its template.

Yes, there will be a lot of similar code in your templates but there’s little you can do about it.

You can try to create one template sensor with additional attributes - it might be sensible if you don’t use your sensors/attributes directly but create binary template sensors like binary_sensor.max_temp_higher_than. The advantage is it’s like one sensor but it holds all relevant data so if you need to change/add something, it’s the same entity and you know where it is.

I’d suggest to start with separate template sensors and see if it works for you. When you have more experience and are more familiar with Jinja/tmplate sensors and how HA works in general, you may have a better idea and refactor your config accordingly.

Sorry, but you do know that you can just simply track a value and close the shutters if it goes above 21" and open them if if goes below 20.5" (say)
Or have blinds that come down to 50% if the sun is between 160" and 200" azimuth with (say) an elevation below 40"
Why do you need max and mins ?

Here the TS deals with weather forecast so I presume he’s getting ready for a sunny day or something.

Yes I know. But I am interested in the forecast. For example, I would like to close the shutters of the greenhouse at 8 o’clock in the morning if it’s getting more than 21°C that day. If I close them if it is already 21°C it’s kind of too late…



EDIT

See petro’s template in the next post. It uses a far more streamlined approach than what I presented below. I’ll leave this here for the curious but I recommend using petro’s template.



After a bit of experimentation (and discovering a few things you cannot do in Jinja2) I’ve created the following template to extract the current day’s minimum and maximum temperatures. Basically, it does the same thing AhmadK’s example did (iterates through the forecast data) but uses a different technique to determine the minimum and maximum values.

To experiment with it, go to Developer Tools > Templates and paste the following into the Template Editor:

{% set start = (now().replace(hour=0,minute=0,second=0).timestamp() * 1000) | int %}
{% set end = start + 86400000 %}
{% set ns = namespace(x='') %}

{% for d in state_attr('weather.openweathermap', 'forecast') if start <= d.datetime < end %}
  {% set ns.x = ns.x ~ d.temperature ~ ' ' %}
{% endfor %}
{% set temps = ns.x.split() | map("float") | list %}

Minimum: {{ temps | min }}
Maximum: {{ temps | max }}

I don’t have an OpenWeatherMap weather entity but I simulated it and the template produced today’s (April 2) minimum and maximum values using the sample data you provided.

To use it, create two Template Sensors, one for maximum and another for minimum. Here’s an example of a maximum sensor. The minimum version’s template would be 99% the same except the final filter would be min instead of max.

  - platform: template
    sensors:
      today_max_temp:
        friendly_name: 'Today Maximum Temperature'
        unit_of_measurement: '°C'
        value_template: >-
          {% set start = (now().replace(hour=0,minute=0,second=0).timestamp() * 1000) | int %}
          {% set end = start + 86400000 %}
          {% set ns = namespace(x='') %}
          {% for d in state_attr('weather.openweathermap', 'forecast') if start <= d.datetime < end %}
            {% set ns.x = ns.x ~ d.temperature ~ ' ' %}
          {% endfor %}
          {{ ns.x.split() | map("float") | list | max }}

How the template works:

  1. It creates two timestamps representing the start and end of the current day. It’s multiplied by 1000 so that it matches OpenWeathermap’s datetime format.
  2. It create a global string variable called ns.x. This string will collect all of today’s temperatures (delimited by a space).
  3. The forecast attribute contains a list. The for-loop iterates through that list but only for the items whose datetime falls between start and end. In other words, only for items containing today’s weather data.
  4. A matching item’s temperature value is appended to the ns.x string variable along with a space character (to serve as a delimiter).
  5. Finally, the ns.x string is converted to a list and the max filter is used to find the highest value in the list. The conversion is a multi-step process consisting of:
    • Splitting the string. This creates a list where each item within the list is a string.
    • Converting the list’s items from string to float (i.e. converting string values to numeric values).
    • Converting the mapped result back to a list.
    • Finally, finding the highest value in the list.
1 Like

you can do this with generators and without the namespace btw

{% set start = (now().replace(hour=0,minute=0,second=0).timestamp() * 1000) | int %}
{% set end = start + 86400000 %}
{{ state_attr('weather.openweathermap', 'forecast') | selectattr('datetime', '>', start) | selectattr('datetime','<=', end) | map(attribute='temperature') | list | max }}

not as easy to read but for learning purposes. Personally, I find generators easy to work with once you get the hang of them.

7 Likes

:man_facepalming:

:clap:

Noice!


EDIT
Frankly, I find your template easier to read than the one I created! A clean left-to-right progression of data running through a series of filters to produce the one thing we want. So neat. I didn’t think this one was possible without iterating though it.

This is amazing!!! I am deeply impressed!!!

I did not understand your code at first because I did not know, that it is possible to use python functions and syntax. For example, I have read about replace filter of Jinja. But I did not know, that it is perfectly fine to use Python’s “hour=0,minute=0,second=0” syntax. Same thing for the timestamp() python function. Where can I find the information on what Python functions I can use within Jinja templates?

I think I do understand the rest of your code now. But I would have never been able to write it myself!

If you have a good source of information about Jinja beside the official docs I would appreciate that!

Thank you very much for the code!

:+1:

There isn’t any. These objects are just passed up to jinja. If you know the object type you are dealing with, most properties and methods are available. Not all things work though. Kinda just have to guess and check.

the normal ansible documentation or the jinja2 website have pretty much everything jinja related. Not everything on the ansible page works though because we are not up to date.

Ok. Thx again. I will try to read and dig in a little deeper… :slightly_smiling_face:

For reference: this is what I have in my sensors.yaml file:

# Day min and max temp
- platform: template
  sensors:
    day_max_temp:
      friendly_name: "Tagshöchsttemperatur"
      unit_of_measurement: "°C"
      entity_id: weather.openweathermap
      value_template: >
        {% set start = (now().replace(hour=0,minute=0,second=0).timestamp() * 1000) | int %}
        {% set end = start + 86400000 %}
        {{ state_attr('weather.openweathermap', 'forecast') | selectattr('datetime', '>=', start) | selectattr('datetime','<=', end) | map(attribute='temperature') | list | max }}

    day_min_temp:
      friendly_name: "Tagstiefsttemperatur"
      unit_of_measurement: "°C"
      entity_id: weather.openweathermap
      value_template: >
        {% set start = (now().replace(hour=0,minute=0,second=0).timestamp() * 1000) | int %}
        {% set end = start + 86400000 %}
        {{ state_attr('weather.openweathermap', 'forecast') | selectattr('datetime', '>=', start) | selectattr('datetime','<=', end) | map(attribute='temperature') | list | min }}
2 Likes

start from here and from there to Jinja website on templates.
you won’t be able to do everything that python allows (you need to use set var = val, no val += 1, variables’ scope is a block etc) but some python types (like strings, datetime) are there and you can use anything they offer. Think about Jinja as a filtering wrapper around python. HA add some functions/filters to it and makes accessible some data types. Here’s how.

Yesterday I started reading “Python Crash Course” by Eric Matthes. Great book! I’ll also continue reading on the Jinja website… :blush:

I have read with interest this thread. While I am impressed with the fantastic solutions that you were given, I thought “how easy it would be in nodered…”.
Have you tried?
If you don’t know python (like me), if you don’t know jinja2 (like me), and unless you want to learn (I don’t) then, I find that node-red make things so much easier than these cryptic (for me) templates.
Worse case scenario in nodered, you will have to write a few lines of javascript.
My 2 cents…
GV

I followed this thread to. Very interesting.

If it is so easy in node-red, why don’t you show us your solution?

Sounds interesting! No I have not tried so far. I don’t know Python/Jinja either, but I am quite interested in learning a bit. And I don’t use HASS.IO, so I think that it is not so easy to install NodeRed.

I am using something similar, but, I think more complex. I have defined for my wife and I, we usually cycle to work , what I call a bike comfort index. The idea is to show on lovelace something like this:
Screenshot.04-03-2020-19.40.17

The color of the bike is a combination of min temp, max temp, wind and rain. The values at the 4 corners are the minTemp / maxTemp / rain and max wind.

Getting the values from the weather API up to sending all the results to HA through API is done like this:

The complex part is the javascript in BikeSensorsMF:

minTemp = {}
maxTemp = {}
windGust = {}
maxRain = {}
confort = {}
var windGustmax = 0;
var Tmin = 50;
var Tmax = -30;
var Rain = 0;


for (var i=0; i<24;i++) {
  if (msg.payload.forecast[i].wind.speed > windGustmax) { 
        windGustmax = msg.payload.forecast[i].wind.speed;
    }
  if (msg.payload.forecast[i].wind.gust > windGustmax) { 
        windGustmax = msg.payload.forecast[i].wind.gust;
    } 
  if (msg.payload.forecast[i].T.value < Tmin ) {
        Tmin = msg.payload.forecast[i].T.value;
  }
  if (msg.payload.forecast[i].T.value > Tmax ) {
        Tmax = msg.payload.forecast[i].T.value;
  }  
  Rain += msg.payload.forecast[i].rain["1h"];
}
minTemp.value = Tmin;
maxTemp.value = Tmax;
windGust.value = (windGustmax * 3.6).toFixed(1);
maxRain.value = Rain.toFixed(1);

indice = 0
if ( minTemp.value < -5 ) indice = 6 + indice ;
else if ( minTemp.value < 0 ) indice = 4 + indice ;
else if ( minTemp.value < 5 ) indice = 2 + indice ;
else if ( minTemp.value < 10 ) indice = 1 + indice ;

if ( maxTemp.value > 40 ) indice = 6 + indice ;
else if ( maxTemp.value > 35 ) indice = 4 + indice ;
else if ( maxTemp.value > 30 ) indice = 2 + indice ;
else if ( maxTemp.value > 25 ) indice = 1 + indice ;

if ( windGust.value > 50 ) indice = 10 + indice ;
else if ( windGust.value > 40 ) indice = 6 + indice ;
else if ( windGust.value > 30 ) indice = 4 + indice ;
else if ( windGust.value > 20 ) indice = 1 + indice ;

if ( maxRain.value > 5 ) indice = 6 + indice ;
else if ( maxRain.value > 4 ) indice = 4 + indice ;
else if ( maxRain.value > 3 ) indice = 2 + indice ;
else if ( maxRain.value > 2 ) indice = 1 + indice ;

if ( indice >= 10 ) confort.value = 5;
else if ( indice >= 6 ) confort.value = 4;
else if ( indice >= 4 ) confort.value = 3;
else if ( indice >= 2 ) confort.value = 2;
else confort.value = 1;

return [ minTemp, maxTemp, windGust, maxRain, confort ];

I assume all of this is doable in templates. The problem (for me at least) is the debugging part of templates.
I know very little of javascript. And I was able to do this (crappy) code.

So, not perfect, but, I believe easier to code and to debug than templates. At least for me :slight_smile:

GV

Everyone thinks differently. Personally, I hate looking at flowcharts. Takes to long to read what’s going on, I’ll always stick to my templates.

2 Likes

…but the bike comfort index (sensor.bci) is a great idea… :heart_eyes: :heart_eyes: :heart_eyes:

I appreciate that. The absolute fantastic thing with HA is that you can choose what suits you :slight_smile:
I have migrated from another home automation system a bit more than one year ago. At first, I started with templates and it (almost) killed me!
I am reasonably good in IT but not a programmer at heart. HA + node-red is the right fit for me… For me. Not for everyone.
The title of the thread “Beginner’s templating question” reminded me of my failed attempts from last year.
GV