Could use a little help for a template

First off…not a programmer, lol. Ive only made a couple basic sensors as well so very new to this.

Trying to get a template setup to convert dimmer power level to wattage. I know this isnt the best way without an actual energy meter device but its what im working with at the moment unitl i decide on an appropriate hardware device for true monitoring/calcs. Not so simple for 240v 2-phase apparently.

I verified the energy usage at each dimmer percentage using a watt meter so i should be in the ball park which is all that really matters for what im going to use this for. I have esphome locked to 5% steps.

This basically works as is right but is not handling the situation where the dimmer is in an off state and i just cant seem to wedge a test for that in my mess. Im sure this is spaghetti mess but gotta start somewhere :slight_smile: Open to a much more elegant way to do this …lm all ears.

Could someone throw me hand in wedging in a test for when the dimmer is off?

code:

{% set powerlevel = (state_attr('light.leddriver', 'brightness') / 255 * 100 | round(0) )| float(0) %}

  {% if is_number(powerlevel) and powerlevel | float >= 90 %}
    880
  {% elif is_number(powerlevel) and powerlevel | float >= 85 %}
    820
  {% elif is_number(powerlevel) and powerlevel | float >= 80 %}
    745
  {% elif is_number(powerlevel) and powerlevel | float >= 75 %}
    680
  {% elif is_number(powerlevel) and powerlevel | float >= 70 %}
    613
  {% elif is_number(powerlevel) and powerlevel | float >= 65 %}
    559
  {% elif is_number(powerlevel) and powerlevel | float >= 60 %}
    500
  {% elif is_number(powerlevel) and powerlevel | float >= 55 %}
    447
  {% elif is_number(powerlevel) and powerlevel | float >= 50 %}
    399
  {% elif is_number(powerlevel) and powerlevel | float >= 45 %}
    349
  {% elif is_number(powerlevel) and powerlevel | float >= 40 %}
    302
  {% elif is_number(powerlevel) and powerlevel | float >= 35 %}
    250
  {% elif is_number(powerlevel) and powerlevel | float >= 30 %}
    205
  {% elif is_number(powerlevel) and powerlevel | float >= 25 %}
    168
  {% elif is_number(powerlevel) and powerlevel | float >= 20 %}
    128
  {% elif is_number(powerlevel) and powerlevel | float >= 15 %}
    90.5
  {% elif is_number(powerlevel) and powerlevel | float < 11 %}
    0
  {% endif %}

You can use integer division > multiply to round your value to the nearest multiple of 5. That eliminates all the >= and makes it easier to set up a power: wattage dictionary.

{%- set entity = 'light.leddriver' %}
{%- set raw_power = state_attr(entity, 'brightness') | float(0) / 255 * 100 %}
{%- set leveled_power = ( raw_power // 5) * 5 %}
{%- set mapper = { 15: 90.5, 20: 128, 25: 168, 30: 205,
35: 250, 40: 302, 45: 349, 50: 399, 55: 447, 60: 500,
65: 559, 70: 613, 75: 680, 80: 745, 85: 820, 90: 880, 95: 880, 100: 880} %}

{{ 0 if (is_state(entity, 'off') or raw_power < 15) else mapper.get(leveled_power) }}
Addendum: Using Comparisons

Just to be clear, you could set up the dictionary using comparisons as the keys instead of using the math trick, and then retrieving “true”…

{% set mapper = { 
power < 15: 0, power >= 15: 90.5, 
power >= 20: 128, power >= 25: 168....} %}
{{ mapper.get(true) }}

But, when doing it that way, you have to be careful about the order based on whether you are using > or <. This is due to the fact that keys must be unique, so each subsequent “true” will overwrite the previous one. Make sure to thoroughly test the output for all possible inputs before putting this method into production.

1 Like

So much elegance :slight_smile:

I knew there had to be a way to reference a table or something more sophisticated than 20 elif statements.

Gonna be re-using this for a few other things i need todo.

Thank you!

Please understand this awesome, but shouldn’t

{%- set raw_power = state_attr(entity, 'brightness') | float(0) / 255 * 100 %}
be
{%- set raw_power = (state_attr(entity, 'brightness') / 255 * 100) | round (0 ) %}
or
{%- set raw_power =(state_attr(entity, 'brightness')/255 * 100) | int |float (0) %}
The round is not being applied unless you bracket the initial equation. I ask because I was seeing a null in a few of the gaps in the mapping when I applied this to icon color base off brightness as a test.

The float() was moved to apply direct to the returned value of state_attr() so that its default value would be applied in the “None” case where the light is off and has no brightness attribute.

There is no round() in my answer… it was made redundant by the integer division trick.

You are correct that OP’s round() was only being applied to the 100. If I were going to use that original approach I would use {{ (state_attr('light.leddriver', 'brightness') | float(0) / 255 * 100) | int }}.

I have run OP’s original if chain version and mine side by side and neither produces a null value if you set the power using {%- set raw_power = state_attr(entity, 'brightness') | float(0) / 255 * 100 %}. OP’s original did have a deadband from 11-14.

If you need help with implementation for your use case, post your actual template so it can be addressed specifically.

I’ve implemented it in several actual templates, but then came across the nulls while tackling the dead band.

I really appreciate the response and your point of view. I’m fairly well-versed in coding but by far not an expert.

Did you experience any lag in polling with your implementations?

If the light is shut off fast there is a delay in color change.

type: custom:stack-in-card
cards:
  - type: custom:mushroom-title-card
    title: Bedroom Lights
  - type: custom:layout-card
    layout_type: custom:grid-layout
    layout:
      grid-template-columns: 1fr 1fr
      margin: 20px 0px 0px 0px
    cards:
      - type: custom:hue-like-light-card
        entity: light.pc_hue_bar
        showSwitch: false
        allowZero: true
        slider: mushroom
        offShadow: false
        tap_action:
          action: more-info
      - type: custom:mushroom-template-card
        primary: '{{state_attr(entity, ''brightness'') }}'
        secondary: >-
          {{ (state_attr(entity, 'brightness') | float(0) / 255 * 100) | int }}
        entity: light.pc_hue_bar
        icon: mdi:lamp
        icon_color: >-
          {%- set entity = 'light.pc_hue_bar' %} {%- set bright =
          (state_attr(entity, 'brightness')/255 * 100) | int %} {%- set
          bright_color = ( bright // 5) * 5 %} {%- set mapper = {  15: 'red',
          20: 'teal', 25: 'teal', 30: 'yellow', 35: 'orange', 40: 'orange', 45:
          'red', 50: 'purple', 55:'lime', 60: 'red', 65:  'yellow', 70:
          'purple', 75: 'green', 80: 'green', 85: 'red', 90:  'yellow', 95:
          'teal', 100: 'orange'} %} {{ 0 if (is_state(entity, 'off') or bright <
          15) else mapper.get(bright_color)
                }}

Your addendum code work best for the light test application. The int conversion no longer mattered and the >= filled in the number gaps I was seeing.

Again thanks for sharing!!

type: custom:stack-in-card
cards:
  - type: custom:mushroom-title-card
    title: Bedroom Lights
  - type: custom:layout-card
    layout_type: custom:grid-layout
    layout:
      grid-template-columns: 1fr 1fr
      margin: 20px 0px 0px 0px
    cards:
      - type: custom:hue-like-light-card
        entity: light.pc_hue_bar
        showSwitch: false
        allowZero: true
        slider: mushroom
        offShadow: false
        tap_action:
          action: more-info
      - type: custom:mushroom-template-card
        primary: '{{state_attr(entity, ''brightness'') }}'
        secondary: >
          {%- set entity = 'light.pc_hue_bar' %}

          {%- set bright = state_attr(entity, 'brightness') | float(0) / 255 *
          100 %}

          {%- set color = ( bright // 5) * 5 %}

          {% set mapper = {  color < 15: 0, color >= 15: 90.5,  color >= 20:
          128, color >= 25: 168, color >= 25: 'red', color >= 30: 'green', color
          >= 35: 'yellow', color >= 40: 'purple', color >= 45: 'cyan', color >=
          50: 'magenta', color >= 55: 'brown' , color >= 60: 'blue', color >=
          65: 'orange', color >= 70: 'red', color >= 75: 'yellow', color >= 80:
          'green', color >= 85: 'purple', color >= 90: 'lime', color >= 95:
          'blue', color >= 100: 'black' } %} {{ mapper.get(true) }}
        entity: light.pc_hue_bar
        icon: mdi:lamp
        icon_color: >
          {%- set entity = 'light.pc_hue_bar' %}

          {%- set bright = state_attr(entity, 'brightness') | float(0) / 255 *
          100 %}

          {%- set color = ( bright // 5) * 5 %}

          {% set mapper = {  color < 15: 'grey', color >= 15: 90.5,  color >=
          20: 128, color >= 25: 168, color >= 25: 'red', color >= 30: 'green',
          color >= 35: 'yellow', color >= 40: 'purple', color >= 45: 'cyan',
          color >= 50: 'magenta', color >= 55: 'brown' , color >= 60: 'blue',
          color >= 65: 'orange', color >= 70: 'red', color >= 75: 'yellow',
          color >= 80: 'green', color >= 85: 'purple', color >= 90: 'lime',
          color >= 95: 'blue', color >= 100: 'black' } %} 
          {{ mapper.get(true) }}

On a side note the Zigebee@MQTT update addressed the lag

Hmmm: dictionary with multiple identical keys (‘true’ and ‘false’). Clever, but don’t come crying when it doesn’t behave how you want. From here:

An alternative mapper, although I suspect the numbers need some work to make it the same as the other one:

{{ {
    0: 'transparent',
    3: 'cyan',
    5: 'yellow',           
   10: 'purple',
   25: 'red',
   50: 'lime',
   75: 'pink',
  100: 'cyan',
  125: 'red',
  150: 'yellow',
  175: 'cyan',
  200: 'lime',
  225: 'blue',
  255: 'black' }
  |dictsort|selectattr(0,'>=',color)
  |first|last }}
1 Like

The lack of int definition caused havoc on the error log.

{%- set entity = 'light.pc_hue_bar' %}

          {%- set raw_power = state_attr(entity, 'brightness') | float(0) / 255
          * 100 %}
           {%- set leveled_power = ( raw_power // 5) * 5 %}
            {%- set mapper = { 
            1 | int(0): 'green', 
            5 | int(0): 'red', 
            15 | int(0): 'blue', 
            20 | int(0): 'yellow', 
            25 | int(0): 'red', 
            30 | int(0): 'blue',
            35 | int(0): 'red',
            40 | int(0): 'blue', 
            45 | int(0): 'red', 
            50 | int(0): 'green', 
            55 | int(0): 'lime', 
            60 | int(0): 'blue',
            65 | int(0): 'pink', 
            70 | int(0): 'cyan', 
            75 | int(0): 'lime',
            80 | int(0): 'black',
            85 | int(0): 'lime',
            90 | int(0): 'red', 
            95 | int(0): 'brown',
            100 | int(0): 'black'} %}

           {{ 0 if (is_state(entity, 'off') and raw_power =0 ) else mapper.get(leveled_power) }}

more interested in learning than anything. Looking for the benift over something like this wher I can set e and x to anything…

{% set e = states('binary_sensor.xxxx') %}
            {% set x = states('input_boolean.yyyy') %}
            {% if (e == 'on' and x == 'on') %} red
            {%  elif (e == 'on' and x == 'off') %} white
            {% elif (e == 'off' and x == 'on') %} yellow
            {% elif (e == 'off' and x == 'off') %} grey
            {% else %}  lightgrey
            {% endif %}

How?! Running |int on an integer is pointless.

Just elegance, I guess. Strings of if/elif get messy.

{% set e = bool(states('binary_sensor.xxxx'),false) %}
{% set x = bool(states('input_boolean.yyyy'),false) %}
{{ iif(e, 'red' if x else 'white', 'yellow' if x else 'grey') }}

Or even more compact but less obvious:

{% set e = bool(states('binary_sensor.xxxx'),false) %}
{% set x = bool(states('input_boolean.yyyy'),false) %}
{{ (('grey','yellow'),('white','red'))[e][x] }}
1 Like

I see! Fairly new to this, but a fast learner. Came across a few examples of code with int on int. The mapper was giving an undefined error and it appeared int related.

@Troon & @Didgeridrew Thank you!! Both your comments helped me understand this concept. The link cleared up so much.

1 Like