Binary sensor not evaluated in sensor template

Hello there,

So, recently the electricity rates changed in Spain and I had to reconfigure my sensors in order to keep track of consumption. To give a bit of context the new rates are as follows.

  • 3 different rates during the day on weekdays

  • 1 rate during weekends and holidays

I got a couple of templatsensors to keep track of the current rate and prices, all based on binary_sensor.workday.

  - platform: workday
    country: ES
    workdays: [mon, tue, wed, thu, fri]
    excludes: [sat, sun, holiday]
    add_holidays:
      - 'XXXX-XX-XX'

The first one checks the current rate to trigger an automation which changes the rate in the utility_meter platform:

tramos_hora_pvpc:
      friendly_name: "Tramos Horarios PVPC" 
      value_template: >-
        {% set current_hour = strptime(states('sensor.time'), "%H:%M").hour %}
        {% if current_hour < 8 and (states('binary_sensor.workday') == 'on') %}
          Tarifa Valle
        {% elif 8 <= current_hour < 10 and (states('binary_sensor.workday') == 'on') %}
          Tarifa Plana
        {% elif 10 <= current_hour < 14 and (states('binary_sensor.workday') == 'on') %}
          Tarifa Punta
        {% elif 14 <= current_hour < 18 and (states('binary_sensor.workday') == 'on') %}
          Tarifa Plana
        {% elif 18 <= current_hour < 22 and (states('binary_sensor.workday') == 'on') %}
          Tarifa Punta
        {% elif 22 <= current_hour < 0 and (states('binary_sensor.workday') == 'on') %}
          Tarifa Plana
        {% else %}
          Tarifa Valle
        {% endif %}

The second template sensor calculates the total electricity bill based on the utility_meter data as follows:

coste_energia_hora:
      friendly_name: "Coste Energia Hora Workday"
      unit_of_measurement: '€'
      icon_template: mdi:currency-eur
      value_template: "{%- if states('sensor.pvpc') -%}
        {%- if now().hour < 8 and (states('binary_sensor.workday') == 'on') -%}
          {{ ((  states('sensor.hourly_energy_valle') | float * 0.002215 + states('sensor.hourly_energy_valle') | float * states('sensor.pvpc') | float) * 1.21 ) | round(2) }}
        {%- elif now().hour >= 8 and now().hour < 10 and (states('binary_sensor.workday') == 'on') -%}
          {{ ((  states('sensor.hourly_energy_plana') | float * 0.0602012 + states('sensor.hourly_energy_plana') | float * states('sensor.pvpc') | float) * 1.21 ) | round(2) }}
        {%- elif now().hour >= 10 and now().hour < 14 and (states('binary_sensor.workday') == 'on') -%}
          {{ ((  states('sensor.hourly_energy_punta') | float * 0.0602012 + states('sensor.hourly_energy_punta') | float * states('sensor.pvpc') | float) * 1.21 ) | round(2) }}
        {%- elif now().hour >= 14 and now().hour < 18 and (states('binary_sensor.workday') == 'on') -%}
          {{ ((  states('sensor.hourly_energy_plana') | float * 0.0602012 + states('sensor.hourly_energy_plana') | float * states('sensor.pvpc') | float) * 1.21 ) | round(2) }}
        {%- elif now().hour >= 18 and now().hour < 22 and (states('binary_sensor.workday') == 'on') -%}
          {{ ((  states('sensor.hourly_energy_punta') | float * 0.0602012 + states('sensor.hourly_energy_punta') | float * states('sensor.pvpc') | float) * 1.21 ) | round(2) }}
        {%- elif now().hour >=22 and (states('binary_sensor.workday') == 'on') -%}
          {{ ((  states('sensor.hourly_energy_plana') | float * 0.0602012 + states('sensor.hourly_energy_plana') | float * states('sensor.pvpc') | float) * 1.21 ) | round(2) }} 
        {%- else -%} 
          {{ ((  states('sensor.hourly_energy_valle') | float * 0.002215 + states('sensor.hourly_energy_valle') | float * states('sensor.pvpc') | float) * 1.21 ) | round(2) }}
        {%- endif -%}
        {%- else -%}unknown
        {%- endif -%}"

The issue here is that it seems that the (states('binary_sensor.workday') == 'on') is not being evaluated and therefore it allways jumps to the {%- else -%} block.

Any advice would be much appreciated.
Thanks

By default, the sensor is created as binary_sensor.workday_sensor. Is that your issue?

:exploding_head: :face_with_hand_over_mouth: This is as funny as embarrassing, didn’t read through all the documentation.

Cheers man!

If you’re interested, you can reduce this:

tramos_hora_pvpc:
      friendly_name: "Tramos Horarios PVPC" 
      value_template: >-
        {% set current_hour = strptime(states('sensor.time'), "%H:%M").hour %}
        {% if current_hour < 8 and (states('binary_sensor.workday') == 'on') %}
          Tarifa Valle
        {% elif 8 <= current_hour < 10 and (states('binary_sensor.workday') == 'on') %}
          Tarifa Plana
        {% elif 10 <= current_hour < 14 and (states('binary_sensor.workday') == 'on') %}
          Tarifa Punta
        {% elif 14 <= current_hour < 18 and (states('binary_sensor.workday') == 'on') %}
          Tarifa Plana
        {% elif 18 <= current_hour < 22 and (states('binary_sensor.workday') == 'on') %}
          Tarifa Punta
        {% elif 22 <= current_hour < 0 and (states('binary_sensor.workday') == 'on') %}
          Tarifa Plana
        {% else %}
          Tarifa Valle
        {% endif %}

to this:

tramos_hora_pvpc:
      friendly_name: "Tramos Horarios PVPC" 
      value_template: >-
        {% set current_hour = now().hour %}
        {% if states('binary_sensor.workday') == 'on' and 0 < current_hour <= 22 %}
          {% if current_hour < 8 %} Tarifa Valle
          {% elif 8 <= current_hour < 10 %} Tarifa Plana
          {% elif 10 <= current_hour < 14 %} Tarifa Punta
          {% elif 14 <= current_hour < 18 %} Tarifa Plana
          {% elif 18 <= current_hour < 22 %} Tarifa Punta
          {% else %} Tarifa Plana
          {% endif %}
        {% else %} Tarifa Valle
        {% endif %}

Thank you! Always interested in learning something new and make my config more readable.

value_template: "Tarifa {{ {'v':'Valle','l':'Plana','u':'Punta'}['vvvvvvvvlluuuulllluuuull'[now().hour if states('binary_sensor.workday_sensor') == 'on' else 0]] }}"

Oh wait, you said more readable…

Is that syntax correct? Thanks but I think I prefer it a bit more verbose… :slight_smile:

1 Like

Yes, it’s correct and works in the template editor. It gives a nice visualisation of the different tariff times in the 'vvvvvvvvlluuuulllluuuull' string, but I agree it’s not that user-friendly. I’d use it in my config though :sunglasses:.

EDIT: final answer — I challenge anyone to do it in fewer characters than this, without renaming the workday sensor:

value_template: "Tarifa {{'VPPalulanlnteaa'[(('0'*8+'11222211'*2)[now().hour*is_state('binary_sensor.workday_sensor','on')])|int::3]}}"

EDIT2: with 2022.7’s new bool function, can save another two characters:

value_template: "Tarifa {{'VPPalulanlnteaa'[(('0'*8+'11222211'*2)[now().hour*states('binary_sensor.workday_sensor')|bool])|int::3]}}"

2 less

value_template: Tarifa {{'VPPalulanlnteaa'[(('0'*8+'11222211'*2)[now().hour*is_state('binary_sensor.workday_sensor','on')])|int::3]}}

Take advantage of the yaml string parsing

EDIT: It’s cheating though because I didn’t change the template. Either way, if a template starts with a string, you don’t need the quotes.

1 Like

Oooh, bending rule 1! Presumably works because it’s not just a template?

Yeah, it’s bending rule 1 for sure. You don’t need quotes if your template starts with characters that make it a string.

I think it could be shortened by 1 char too if you use

states('binary_sensor.workday_sensor')=='on'

Outside that, I can’t see anything else. It’s a nice template. Definitely something i’d use if trying to save memory. We used to use stuff like this in our software from the 90’s when memory was tight.

1 Like

I tried that. Needs an extra set of brackets to evaluate correctly, so ends up 1 char longer.

odd, I would think that == is resolved before the *, but maybe not