Beginner's templating question

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

I’ve tried this, but keep on getting an error TypeError: ‘>=’ not supported between instances of ‘str’ and ‘int’

Looking at this it appears I need to convert the filter for datetime selectattr(‘datetime’, ‘>’, start) to an INT, but i have tried many combinations, but doesnt work. Any ideas?

That purely depends on what the datetime string represents.

The code im using:

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

The data it is checking:

temperature: 2
humidity: 79
pressure: 1026
wind_bearing: 50
wind_speed: 5
visibility: 16
attribution: Data from National Weather Service/NOAA
forecast:
  - detailed_description: ''
    temperature: 4
    datetime: '2020-05-08T07:00:00-06:00'
    condition: cloudy
    precipitation_probability: 0
    wind_bearing: 247.5

I believe i need to change the selectattr so it is comparing and int to an int, but im struggling to find out how to convert it within that function.

Hi, I tried to get the max/min Results of some OpenWeatherMap-Forecasts like above described.
I want to know the max/min Temperature in the next 24 hours and the max Windspeed/Cloud Coverage/Rain also in the next 24h.

I used this code:

# Maximale und minimale Temperaturwerte aus Openweathermap
  - platform: template
    sensors:
      min_temp_next_24h:
        friendly_name: Minimale Temperatur in den naechsten 24h
        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 }}         
      max_temp_next_24h:
        friendly_name: Maximale Temperatur in den naechsten 24h
        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 }}
      max_windspeed_next_24h:
        friendly_name: Maximale Windgeschwindigkeit in den naechsten 24h
        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='wind_speed') | list | max }}
      max_cloudcoverage_next_24h:
        friendly_name: Maximale Bewoelkung in den naechsten 24h
        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='cloud_coverage') | list | max }}
      max_raining_next_24h:
        friendly_name: Maximale Regenmenge in den naechsten 24h
        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='rain') | list | max }}

But there must be an error in the code.
There is just a result for min and max temperature.
And the other sensors just show “unknown”. Maybe the name of the attribute is wrong. But i can’t find the right name.
Can someone help with the code?

Do those attributes exist in the forecast? Are those attributes numbers?