Mariusthvdb / custom-ui

Add templates and icon_color to Home Assistant UI
161 stars 30 forks source link

Custom-ui templated attributes dont show in dev tools and backend Jinja templates #110

Closed SiriosDev closed 8 months ago

SiriosDev commented 9 months ago

After adding icon_color via customization it doesn't appear in attributes, i.e. unusable with templates, the most I got is icon_color under templates but it's just the js code

below are respectively:

```jinja2 // // {% set SENSOR = 'sensor.pirateweather_apparent_temperature' %} {% for attr in states [SENSOR].attributes %} {{ attr }} {% endfor %} // // ``` ```yaml state_class attribution unit_of_measurement device_class friendly_name hide_attributes templates ```

image

#customizaion.yaml
sensor.pirateweather_apparent_temperature:
  templates:
    icon_color: >
      const val = parseInt(state);
      const valColorMap = [
        { value: -10, color: "#0033ff" },
        { value: -8, color: "#0963ff" },
#removed some entry for better reading
        { value: 24, color: "#feac07" },
        { value: 26, color: "#fb9300" },
        { value: 28, color: "#ff6f00" },
        { value: 30, color: "#ff4802" },
        { value: 32, color: "#ff2803" },
        { value: 34, color: "#ff0506" },
        { value: 36, color: "#d9031e" },
        { value: 38, color: "#b90135" },
        { value: 40, color: "#930058" },
        { value: 42, color: "#70016f" }
      ];

      var color;
      for (const vcm of valColorMap) {
        if (val < vcm.value) {
          color = vcm.color;
          break;
        }
      }

      return color;
Mariusthvdb commented 9 months ago

first things first: did you install custom-ui? (show inspector console to be sure)

next: where did you add this customization? it should be in the correct hierarchy compared to homeassisant, see the docs.

if above is correct, please add a simple and direct (no templates) customization like

homeassistant:
  customize:
    sensor.pirateweather_apparent_temperature:
      icon_color: red

to see if its working as it should

if yes, simplify that mapper, not sure where you got that from.... I didnt yet meet a beginner on custom-ui with a syntax as complex as that.

try a simpler version like:

          icon_color: >
            if (state === 'unknown') return 'grey';
            if (state < -20) return 'black';
            if (state < -15) return 'navy';
            if (state < -10) return 'darkblue';
            if (state < -5) return 'mediumblue';
            if (state < 0) return 'blue';
            if (state < 5) return 'dodgerblue';
            if (state < 10) return 'lightblue';
            if (state < 15) return 'turquoise';
            if (state < 20) return 'lightgreen';
            if (state < 25) return 'darkgreen';
            if (state < 30) return 'orange';
            if (state < 35) return 'crimson';
            return 'firebrick';

fwiw, I changed the JS a bit, and this does work as expected (though missing the catch for 'unknown'):

      temp_color: &temp_color
        hide_attributes: templates
        templates:
          icon_color: >
            const val = parseInt(state);
            const valColorMap = [
              { value: -20, color: 'black' },
              { value: -15, color: 'navy' },
              { value: -10, color: 'darkblue' },
              { value: -5, color: 'mediumblue' },
              { value: 0, color: 'blue' },
              { value: 5, color: 'dodgerblue' },
              { value: 10, color: 'lightblue' },
              { value: 15, color: 'turquoise' },
              { value: 20, color: 'lightgreen' },
              { value: 25, color: 'darkgreen' },
              { value: 30, color: "orange" },
              { value: 35, color: "crimson" }
            ];

            return valColorMap.find(mapping => val < mapping.value)?.color || 'firebrick';
Scherm­afbeelding 2023-11-18 om 10 53 47

can even leave out the const val = parseInt(state); and use state directly in the return:

Scherm­afbeelding 2023-11-18 om 11 01 28

further simplification of the mapping can be done using using array destructuring

      temp_color: &temp_color
        hide_attributes: templates
        templates:
          icon_color: >
            const valColorMap = [
              [-20,'black'],
              [-15,'navy'],
              [-10,'darkblue'],
              [-5,'mediumblue'],
              [0,'blue'],
              [5,'dodgerblue'],
              [10,'lightblue'],
              [15,'turquoise'],
              [20,'lightgreen'],
              [25,'darkgreen'],
              [30,'orange'],
              [35,'crimson']
            ];

            if (state === 'unknown') return 'grey';
            return valColorMap.find(([threshold]) => state < threshold)?.[1]
                   || 'firebrick';
Scherm­afbeelding 2023-11-18 om 11 17 58
SiriosDev commented 9 months ago

first things first: did you install custom-ui? (show inspector console to be sure)

I'm not sure, but I think you mean this? image

next:where did you ad this customization? it should be in the correct hierarchy compared to homeassisant, see the docs.

above (hierarchically) I only have this glob (to make the webui neat ) :

"*.*":
  hide_attributes:
    - templates

now know that I wrote the code, following this page (specifically I read the piece from sensor.synology_status_volume_1) that says to put icon_color inside templates

anyway,

this working

homeassistant:
  customize:
    sensor.pirateweather_apparent_temperature:
      icon_color: red

this not working

          icon_color: >
            if (state === 'unknown') return 'grey';
            if (state < -20) return 'black';
            if (state < -15) return 'navy';
            if (state < -10) return 'darkblue';
            if (state < -5) return 'mediumblue';
            if (state < 0) return 'blue';
            if (state < 5) return 'dodgerblue';
            if (state < 10) return 'lightblue';
            if (state < 15) return 'turquoise';
            if (state < 20) return 'lightgreen';
            if (state < 25) return 'darkgreen';
            if (state < 30) return 'orange';
            if (state < 35) return 'crimson';
            return 'firebrick';

unfortunately as before it has effect on the web ui, but I can't get it via jinja template (on the contrary the one before to put it red works)

simplify that mapper, not sure where you got that from.... I didnt yet meet a beginner on custom-ui with a syntax as complex as that.

I didn't find it 😅😅, I wrote it based on an old jinja2 template I used before

SiriosDev commented 9 months ago

i saw the edits now i will try those as well

edit: nope😢

Mariusthvdb commented 9 months ago

Not sure what you mean getting it via Jinja templates?

This has nothing to do with Jinja....

Please post the complete yaml for this customization including the top 'homeassistant'

SiriosDev commented 9 months ago

as you wrote in the readme, some cards are incompatible, we need to use card-mod, which uses jinja templates (also called home assistant templates) to set the color of these incompatible cards

customization entry


sensor.pirateweather_apparent_temperature: 
  templates:
    icon_color: >
      const val = parseInt(state);
      const valColorMap = [
        { value: -20, color: 'black' },
        { value: -15, color: 'navy' },
        { value: -10, color: 'darkblue' },
        { value: -5, color: 'mediumblue' },
        { value: 0, color: 'blue' },
        { value: 5, color: 'dodgerblue' },
        { value: 10, color: 'lightblue' },
        { value: 15, color: 'turquoise' },
        { value: 20, color: 'lightgreen' },
        { value: 25, color: 'darkgreen' },
        { value: 30, color: "orange" },
        { value: 35, color: "crimson" }
      ];

      return valColorMap.find(mapping => val < mapping.value)?.color || 'firebrick';

card config

type: tile
entity: sensor.pirateweather_apparent_temperature
vertical: false
name: Percepita
show_entity_picture: false
card_mod:
  style: |
    ha-card {
        --tile-color: {{state_attr ('sensor.pirateweather_apparent_temperature', 'icon_color')}} !important;
    }

image image

working example (but with template sensor)

sensor entry

- sensor:
    - name: "uv_level"
      unique_id: 439bafe4-af31-4683-b249-b7ed53e6ee5b
      icon: mdi:sun-wireless
      state: >-
        {% from 'uv_tool.jinja' import uv_index2level %}
        {{ uv_index2level('sensor.pirateweather_uv_index', 'binary_sensor.notte') }}
      attributes:
        icon_color: >-
          {%- set state = this.state %}
          {%- if state == "Basso" %}
          #008000
          {%- elif state == "Medio" %}
          #ffff00
          {%- elif state == "Alto" %}
          #ffa500
          {%- elif state == "Molto Alto" %}
          #ff0000
          {%- elif state == "Estremo" %}
          #8a2be2
          {%- endif %}

card configuration

type: tile
vertical: false
entity: sensor.uv_level
card_mod:
  style: |
    ha-card {
        --tile-color: {{state_attr ('sensor.uv_level', 'icon_color')}} !important;
    }

image image

Mariusthvdb commented 9 months ago

sorry, but you are not going to solve your JS card with showing jinja templates....

please keep the issue tidy, because this is rather confusing.

your top post is a regular more-info of a single entity, so that should just work with the templates I provided.

please keep your search to solving that in your config.

did you give it a restart in between changing those templates? Normally, the change would kick in on a reload of customizations, and a state change. Sometimes, a restart is needed.

all I can think of is that your customization is not placed correctly in your yaml, thats why I asked to show the full yaml structure

BUT: in all of your screenshots, your icons are colored. Why are you saying it does not work?? it seems to be working alright?

SiriosDev commented 9 months ago

you're right let's go step by step

Mariusthvdb commented 9 months ago

well, your last statement is not correct. As a matter of fact, you can use the icon_color attribute in any other template or config, as it's added to the entity directly. There is always an icon_color attribute on the entity, if installed correctly and set with proper syntax. As Ive shown in the screenshots.

if the syntax is incorrect, check inspector for any warnings

That has nothing to do with the cards in the Frontend.

some Frontend cards see the attribute icon_color, and some dont. If not, then you need to find another way to do what you want (can be card_mod, or other custom card)

concluding:

as is displayed by your colored icons in all screenshots above, custom-ui is working properly. seems we can close, and you need to take your quest to the community if you still have one.

SiriosDev commented 9 months ago

there is absolutely no question that the color is computed correctly, as you say the icon changes color in the more-info popup, the problem is that the HA templates and consequently card-mod do not see this "field".

the following template string {{state_attr ('sensor.pirateweather_apparent_temperature', 'icon_color')}}, is (almost) the user friendly version of the command I put in the first comment, it returns an attribute value given an entity and the attribute name, the problem is that it returns nothing.

I did everything:

Mariusthvdb commented 9 months ago

Please post a screenshot of this entity in dev tools /states?

Both from the attributes list and from the view when clicking the entity atop:

image

SiriosDev commented 9 months ago

here image also in this screen it appears as in the pop up, but I don't understand why then the templates don't "see" it image

Mariusthvdb commented 9 months ago

yes, I now see what you mean, and., tbh, that is new to me. reading back, I now also understand your post.....

great find.

In all the years I use custom-ui, this never happened.

either something changed in the attributes handling in core HA, or the latest update(s) of custom-ui broke that functionality..

maybe I need to reiterate and subsequently test the last few version.....

I dont think the hide attributes has anything to do with it, but it is the simplest test we can do, by leaving that out and see what happens.

SiriosDev commented 9 months ago

Oh, great finally! Sorry if I've misexplained myself so far. 😅😅

I can tell you right now that even without hide it doesn't work, my first attempt was without hide, in fact during my try and error I thought hide was a requirement for it to work

Mariusthvdb commented 9 months ago

yes, Ive asked in dev core on discord, and meanwhile I see it happening system wide. All works, except the attribute in the template., or the attributes column...

let me try a fixed color... yes that is still correct:

Scherm­afbeelding 2023-11-18 om 23 20 32 Scherm­afbeelding 2023-11-18 om 23 21 16
SiriosDev commented 9 months ago

yea i confirm setting a fixed color, without template like the first snippet here, work perfectly

Mariusthvdb commented 9 months ago

well, ive gone back to my original custom-ui as far back as possible, and none of them show the templated attributes anymore. So definitely a change I HA handling of those... yet another set back for custom-ui users, though not completely disastrous, as this is an edge case usecase...

it might also be a bug, so Ill file it anyways, if only because of the discrepancy between the attributes filter listing and the set state box...

Scherm­afbeelding 2023-11-18 om 23 38 14 Scherm­afbeelding 2023-11-18 om 23 38 40
SiriosDev commented 9 months ago

yeah sure, imho may be a bug, cause work everywhere except templates

Mariusthvdb commented 9 months ago

as a side note: the 'experimental' functionality to set an attribute icon_color on a template sensor in HA yaml directly does make the attribute appear and allow it to be templated

Scherm­afbeelding 2023-11-20 om 08 12 55 Scherm­afbeelding 2023-11-20 om 08 13 28
        attributes:
#experimental!
          icon_color: >
            {{'gold' if this.state|int(default=-1) != 0 else 'gray'}}

ofc, this can only be done on entities of integrations that support custom attributes in HA core by design, like the template integration.

also note it does not show the template itself in the attributes, which ofc is nice, as it doesnt fill the state machine with that code.

Not fixing the issue at hand, just letting you know

SiriosDev commented 9 months ago

Yeye I know already using it on temples entities, as you say the problem is "normal" entities

Mariusthvdb commented 9 months ago

hmm, I now see the icon_color attribute itself is also missing in dev tools. How strange, as the above screens show it's still there. maybe a cache thing.

its still working, and set, according to this:

Scherm­afbeelding 2023-11-22 om 11 48 03

and closing the browser, refreshing cache and reopening brings it back...

Scherm­afbeelding 2023-11-22 om 11 50 15

I did check the template integration in HA, but dont see an obvious change there yet. maybe we need to downgrade and see if 2023.10 brings it back

Nope: just tested 2023.10.5 and same issue, attribute comes and goes in dev tools/state, and never in dev tools/template. Unless fixed, or inside template sensor jinja config

    binary_sensor:

      - unique_id: christmas_time
        state: >
          {% set today = now().day %} {% set month = now().month %}
          {{month == 12 and today >= 24 or month == 1 and today == 1}}
        icon: >
          mdi:{{iif(this.state == 'on','string-lights','pine-tree')}}
# experimental
        attributes:
          icon_color: >
            {{iif(this.state == 'on','crimson','green')}}
SiriosDev commented 9 months ago

thats strange

Mariusthvdb commented 9 months ago

changed the title, as I've gone back to previous HA versions, and somehow those templates dont show either.... dont think I will be able to fix this.

the customized attribute is a bonus as it stands, so please live with it, or dont use the templates in the first place.

Unless ofc you have a PR that could make it happen, which I would be glad to add if reliable.

Meanwhile Ive published a minimized custom-ui that only ad the attribute icon_color and nothing else. If you you can use that, feel free to test it.

SiriosDev commented 9 months ago

at the moment I am not very familiar with HA integrations, but never say never, if I figure out how to do it I will definitely make a pr

SiriosDev commented 9 months ago

Soo. At the moment, I solved it with the following workaround, which is to use the python script Entities Script (from HACS) and an automation that runs on each state change by setting the custom attribute one of the services offered

SiriosDev commented 9 months ago

here the yaml for who need it (based on the entity at the top of this issue)


alias: Temp Colorizer
description: "Set Entity color based on state"
trigger:
  - platform: state
    entity_id:
      - sensor.pirateweather_apparent_temperature
condition: []
action:
  - service: python_script.hass_entities
    data:
      action: set_attributes
      entity_id: sensor.pirateweather_apparent_temperature
      attributes:
        - icon_color: |
            {% from 'temperature_colorzier.jinja' import outside_temp %}
            {{ outside_temp('sensor.pirateweather_apparent_temperature') }}
mode: queued
max: 10

the custom jinja code chose a color from an array of tuple (temp - color)

Mariusthvdb commented 9 months ago

there's a lot to be said about that workaround, but most of all, it would become terribly cumbersome doing so for many entities, and it would trigger the state machine constantly.....

you (we) are probably better off trying to find ways not requiring that attribute at all. I mean, where do you need it?

Personally, I've taken out all icon_color attributes except on the template entities (remember: this is an experimental feature made possible by custom-ui) where they are actually visible I the attributes list and iterable,

Other than that, I use card-mod for spicing up the Frontend, and stopped using custom-ui template completely.

(Only downside of that is that the more-info's no longer get the icon_color...)

bratanon commented 8 months ago

Explaining this process involves a technical discussion, but I'll attempt to clarify the concepts:

The custom-ui functionality involves the interception of the homeassistant JavaScript class. This interception targets a specific custom element named homeassistant, where templates specified in YAML attributes are computed. These computed templates are then utilized to modify state objects through the custom element called state-badge, thereby effecting changes in the frontend system.

The widespread presence of the homeassistant custom element allows custom-ui to potentially alter state objects across various pages in the system.

However, there is a limitation when it comes to the "dev tools template" section, as it does not utilize the state-badge custom element. Consequently, modifications made by custom-ui are not applicable in this section, and the state object is read as originally defined in YAML.

This constraint is inherent, and there's no feasible solution.

The computed templates, visible in the "dev tools state" section, are a product of custom-ui's template computation.

Regarding card mod, it calculates Jinja templates by invoking a backend service. However, since the backend is unaware of custom-ui's actions, the results only include attributes defined in YAML. Essentially, using custom-ui in conjunction with card mod in this manner is not viable.

bratanon commented 8 months ago

@SiriosDev @Mariusthvdb I think we can close this as "wont fix", what is your thoughts?

Mariusthvdb commented 8 months ago

Agreed

cant help but remember we could see the templates outcome in Jinja before but can’t reproduce in any older version.

lets go forward.