Beginner's templating question

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?

Well this unfortunately does not solve your problem, but in the long run it might be easier to ask the maintainer (who is it?) of the OWM platform to include directly within the platform’s code… :thinking:

PS: The OWM One Call API is being implemented (Convert OpenweatherMap Integration to use “one-call-api”). So just be patient… :slightly_smiling_face:

Hi,

referring to the generator

{{ state_attr('weather.openweathermap', 'forecast') | selectattr('datetime', '>', start) | selectattr('datetime','<=', end) | map(attribute='temperature') | list | max }}

how would the generator look like if the datetime comparison should take place by comparing with a datetime string?

The datetime which my forecasts deliver are strings of different formats depending on the weather provider, like this:

‘2020-10-10T07:00:00+00:00’
‘2020-10-10’

you won’t be able to use a generator. You’ll need a for loop and convert each string timestamp to a int timestamp.

Actually it is already in the needed format:

platform: template
  sensors:
    min_temp_next_24h_home:
      friendly_name: Min temperature in the next 24h at home
      value_template: >-
          {% set start = (now().replace(hour=0,minute=0,second=0)) %}
          {% set end = (start + timedelta(days=1)) %}
          {{ state_attr('weather.openweathermap_home', 'forecast') | selectattr('datetime', '>', start) | selectattr('datetime','<=', end) | map(attribute='temperature') | list | min }}
    max_temp_next_24h_home:
      friendly_name: Max temperature in the next 24h at home
      value_template: >-
          {% set start = (now().replace(hour=0,minute=0,second=0)) %}
          {% set end = (start + timedelta(days=1)) %}
          {{ state_attr('weather.openweathermap_home', 'forecast') | selectattr('datetime', '>', start) | selectattr('datetime','<=', end) | map(attribute='temperature') | list | max }}
    max_raining_next_24h_home:
      friendly_name: Max precipitation in the next 24h at home
      value_template: >-
          {% set start = (now().replace(hour=0,minute=0,second=0)) %}
          {% set end = (start + timedelta(days=1)) %}
          {{ state_attr('weather.openweathermap_home', 'forecast') | selectattr('datetime', '>', start) | selectattr('datetime','<=', end) | selectattr('precipitation','!=', None) | map(attribute='precipitation') | list |max }}

Dear all
According to this article I configured a sensor for today’s max temperature:

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

Since a couple of weeks/months there occures an error. When I try to validate the code in the developer tools - template register I get the following output:

TypeError: '>=' not supported between instances of 'str' and 'int'

What might be the problem? How can I fix this string? Is this error related to the updates on homeassistant?

that’s a string

that’s an int


You can’t convert datetime to an int without using a forloop, so if you want to keep your code the way it is, you need to adjust {% set end = start + 86400000 %} to be a datetime string. And to configure that line, we’d need to know the format of datetime.

EDIT: to further clarify, post a screenshot of your attributes for weather.home

Dear Petro
Thank you for your response. Here is the screenshot of the attributes of weather.home:

How can I adjust the datetime string?

You can’t adjust the datetime string, so we adjust what you’re comparing to.

  - platform: template
    sensors:
      day_max_temp:
        friendly_name: "Max. Tagestemperatur"
        unit_of_measurement: "°C"
        entity_id: weather.home
        value_template: >
          {% set format = '%Y-%m-%dT%H:%M:%S+00:00' %}
          {% set start = now().replace(hour=0,minute=0,second=0, microsecond=0) %}
          {% set end = (start + timedelta(days=1)) | timestamp_custom(format, false) %}
          {% set start = start | timestamp_custom(format, false) %}
          {{ state_attr('weather.home', 'forecast') | selectattr('datetime', '>=', start) | selectattr('datetime','<=', end) | map(attribute='temperature') | list | max }}

Thank you Petro
Hmmmm… When I copy and paste your configuration to the Template-Tool I still get the an error, but a little different one:

TypeError: '<=' not supported between instances of 'int' and 'datetime.datetime'

Am I still comparing apples with pears?

1 Like

Just in case someone else has this same issue, I changed a bit the code to make it work (I’m a n00b, so it might be a better way of doing this)

This works with Accuweather, but you can adjust it to you service

template:
    - sensor:
      - name: "Today Maximum Temperature"
        unique_id: "today_maximum_temperature"
        device_class: temperature
        unit_of_measurement: "°F"
        state: >
            {% set start = now().replace(hour=0,minute=0,second=0, microsecond=0) %}
            {% set end = (start + timedelta(days=1)) %}
            {% set start = start.strftime("%Y-%m-%dT%H:%M:%S+00:00") %}
            {% set end = end.strftime("%Y-%m-%dT%H:%M:%S+00:00") %}
            {{ state_attr('weather.home', 'forecast') | selectattr('datetime', '>=', start) | selectattr('datetime','<=', end) | map(attribute='temperature') | list | max }}
3 Likes

Just wanted to thank DaveH for this. Just what I was looking for. Well, almost.
Here is the code modified for Open Weather Map showing minimum temp today with a second sensor for showing minimum forecast temperature over the next 24 hours which I plan to use as a frost warning for garden plant protection purposes


template:
  - sensor:
    - name: "Today Minimum Temperature"
      unique_id: "today_minimum_temperature"
      device_class: temperature
      unit_of_measurement: "°C"
      state: >
          {% set start = now().replace(hour=0,minute=0,second=0, microsecond=0) %}
          {% set end = (start + timedelta(days=1)) %}
          {% set start = start.strftime("%Y-%m-%dT%H:%M:%S+00:00") %}
          {% set end = end.strftime("%Y-%m-%dT%H:%M:%S+00:00") %}
          {{ state_attr('weather.openweathermap', 'forecast') | selectattr('datetime', '>=', start) | selectattr('datetime','<=', end) | map(attribute='temperature') | list | min }}
#
  - sensor:
    - name: "24H Minimum Temperature"
      unique_id: "24h_minimum_temperature"
      device_class: temperature
      unit_of_measurement: "°C"
      state: >
          {% set start = now() %}
          {% set end = (start + timedelta(days=1)) %}
          {% set start = start.strftime("%Y-%m-%dT%H:%M:%S+00:00") %}
          {% set end = end.strftime("%Y-%m-%dT%H:%M:%S+00:00") %}
          {{ state_attr('weather.openweathermap', 'forecast') | selectattr('datetime', '>=', start) | selectattr('datetime','<=', end) | map(attribute='temperature') | list | min }}