Custom UI - icon color change

In my case there is a difference:

  1. Here no differences:
homeassistant:
  customize_glob:

    sensor.battery_*:
      templates:
        icon_color: >
          if (['unavailable', 'unknown'].includes(state)) return 'brown';
          if (state <= Number(entities['input_number.battery_level_critical'].state)) return 'red';
          if (state <= Number(entities['input_number.battery_level_warning'].state)) return 'rgb(250,218,67)';
          return 'green';
        last_updated: return entity.last_updated;

      hide_attributes:
        - templates
        - icon_color
  1. Here there is a difference:
homeassistant:
  customize_glob:

    sensor.battery_*:
      templates:
        icon_color: >
          if (['unavailable', 'unknown'].includes(state)) return 'brown';
          if (state <= Number(entities['input_number.battery_level_critical'].state)) return 'red';
          if (state <= Number(entities['input_number.battery_level_warning'].state)) return 'rgb(250,218,67)';
          return 'green';

      hide_attributes:
        - templates
        - icon_color

So, only adding "last_updated: return entity.last_updated;" removes the differences.

OK, could it be a cashing issues? I cleared the browser’s cashe, restarted HA & tried to reproduce the same condition - now I do NOT see these differences.

1 Like

ah yes, the wonderful cache issues…

what you can do too, is only hide the templates, and not the icon_color. I always like to have it in the more-info anyways

OK, so now we have 2 issues to solve:

  1. Support "entities" inside button-card (waiting for RomRider).
  2. Rectify that flickering with “attributes” dropdown menu.

May I ask you about one more thing?
You proposed to add a "last_updated" attribute above.
Does it mean that ANY attribute may be added to a set of entities?

Particularly, lets consider this example:
I have a set of "binary_sensor.battery_charging_life360_*" entities keeping a battery’s state (charging or not).

Examples of names:

  • battery_charging_life360_mama
  • battery_charging_life360_papa

Each sensor has an attribute "location" (equal to the associated Life360 device_tracker's state):

      battery_charging_life360_mama:
        value_template: ......
        device_class: battery_charging
        attribute_templates:
          location: "{%  set SOURCE_DEVICE = 'mama' -%}
                     {%- set SOURCE_SENSOR_FULL = 'device_tracker.life360_' + SOURCE_DEVICE -%}
                     {%- set LOCATION = states(SOURCE_SENSOR_FULL) -%}
                     {%- if LOCATION == 'home' -%}
                     {{ 'Home' }}
                     {%- elif LOCATION == 'not_home' -%}
                     {{ 'Away' }}
                     {%- else -%}
                     {{ LOCATION }}
                     {%- endif %}"

Currently I have to repeat the same code for the attribute for each sensor.
Is it possible to specify smth like this:


homeassistant:
  customize_glob:

    binary_sensor.battery_charging_life360_*:
      templates:
        location: "{%  set SOURCE_DEVICE = SOMETHING EXTRACTED FROM THE ENTITY'S NAME -%}
                   {%- set SOURCE_SENSOR_FULL = 'device_tracker.life360_' + SOURCE_DEVICE -%}
                   {%- set LOCATION = states(SOURCE_SENSOR_FULL) -%}
                   {%- if LOCATION == 'home' -%}
                   {{ 'Home' }}
                   {%- elif LOCATION == 'not_home' -%}
                   {{ 'Away' }}
                   {%- else -%}
                   {{ LOCATION }}
                   {%- endif %}"

yes, thats entirely possible, but you must write it in javascript. Have a look at this friendly_name:

    sensor.*_sensor_light_level_raw:
      templates:
        icon_color: >
          if (state < 1) return 'black';
          if (state < 3000) return 'maroon';
          if (state < 10000) return 'firebrick';
          if (state < 17000) return 'orange';
          if (state < 22000) return 'green';
          if (state < 25500) return 'gold';
          if (state < 28500) return 'teal';
          if (state < 33000) return 'dodgerblue';
          if (state < 40000) return 'lightskyblue';
          if (state < 40000) return 'lightblue';
          return 'lightcyan';
        friendly_name: >
          function capitalizeFirstLetter(string) {
              return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
              }
          var id = entity.entity_id.split('.')[1].split('_sensor_light_level_raw')[0].replace(/_/g,' ');
          var id = capitalizeFirstLetter(id);
          if (state < 1) return id + ': dark';
          if (state < 3000 ) return id + ': bright moonlight';
          if (state < 10000) return id + ': night light';
          if (state < 17000) return id + ': dimmed light';
          if (state < 22000) return id + ': \'cosy\' living room';
          if (state < 25500 ) return id + ': \'normal\' non-task light';
          if (state < 28500) return id + ': working / reading';
          if (state < 33000) return id + ': inside daylight';
          if (state < 40000) return id + ': maximum to avoid glare';
          if (state < 51000) return id + ': clear daylight';
          return id + ': direct sunlight';
      unit_of_measurement: lm

where before I had to write the same template in Jinja for all individual sensors (27)…
a bit over the top, but yo can add /set any attribute using custom-ui like that

having said that, dont underestimate the use of the template-entity-raw:

  - type: custom:auto-entities
    card:
      type: entities
      title: Philips light level raw sensors
      show_header_toggle: false
    filter:
      include:
        - entity_id: '*_sensor_light_level'
          options:
            type: custom:template-entity-row
            name: >
              {% if state_attr(config.entity,'friendly_name') is not none %}
              {{state_attr(config.entity,'friendly_name').split(' sensor light level')[0]}}
              {% else %} Tbd
              {% endif %}
            state: >
              {{state_attr(config.entity,'lightlevel')}} lm
            secondary: >
              {% set light_level = state_attr(config.entity,'lightlevel')|int %}
              {% if light_level < 1 %} dark
              {% elif light_level < 3000 %} bright moonlight
              {% elif light_level < 10000 %} night light
              {% elif light_level < 17000 %} dimmed light
              {% elif light_level < 22000 %} 'cosy' living room
              {% elif light_level < 25500 %} 'normal' non-task light
              {% elif light_level < 28500 %} working / reading
              {% elif light_level < 33000 %} inside daylight
              {% elif light_level < 40000 %} maximum to avoid glare
              {% elif light_level < 51000 %} clear daylight
              {% else %} direct sunlight
              {% endif %}
    sort:
      method: state
      numeric: true


not identical, but rather useful too. Guess it all depends on your preferences

1 Like

Marius, this is great)))
Will try to add attributes, will post here in case of problems.
Thank you!

Marius, testing with adding attributes.
Is it possible to reduce this code?

  customize_glob:
    binary_sensor.zzzzzzzzzzzzzzzzz*:
      templates:
        attr_1: >
          function Foo(string) {
              return AAAAAAAAA;
              };
          .... use Foo() ....
          return XXX;

        attr_2: >
          function Foo(string) {
              return AAAAAAAAA;
              };
          .... use Foo() ....
          return YYY;

        attr_3: >
          function Foo(string) {
              return AAAAAAAAA;
              };
          .... use Foo() ....
          return ZZZ;

The issue is that some function is supposed to be used for each attribute…


The most important question.
I cannot understand why my “Template” tab does not see added attributes - at least if they are added as templates.

Here is a customization:

  customize_glob:
    binary_sensor.battery_charging_life360_*:
      templates:
        battery_level: >
          var SOURCE_DEVICE = entity.entity_id.split('battery_charging_life360_')[1];
          var SOURCE_SENSOR_FULL = 'sensor.battery_life360_' + SOURCE_DEVICE;
          var LEVEL = parseFloat(entities[SOURCE_SENSOR_FULL].state);
          return (LEVEL / 100.0);

      hide_attributes:
        - templates

The battery level is taken from the paired sensor.
The results:
image

But this added attribute is not available in the Template tab:

Does that mean that Custom UI templates work ONLY for presentation and cannot be used for any calculations on server side?
Now I see that I cannot use the added attributes at least in auto-entities::template, in card-mod templates.
Then I will have to use Custom UI only for:

  • icon
  • icon color
  • entity picture
  • device_class

Just for test - let’s add "device_class" by Custom UI (not as template):

  customize_glob:
    binary_sensor.battery_charging_life360_*:
      device_class: battery_charging
      templates:
        battery_level: >
          var SOURCE_DEVICE = entity.entity_id.split('battery_charging_life360_')[1];
          var SOURCE_SENSOR_FULL = 'sensor.battery_life360_' + SOURCE_DEVICE;
          var LEVEL = parseFloat(entities[SOURCE_SENSOR_FULL].state);
          return (LEVEL / 100.0);

The result - there is a "device_class" attribute:
image
The Template tab so far is OK:

And now let’s add the "device_class" as a template:

  customize_glob:
    binary_sensor.battery_charging_life360_*:
      # device_type: mobile
      # device_class: battery_charging
      templates:
        battery_level: >
          var SOURCE_DEVICE = entity.entity_id.split('battery_charging_life360_')[1];
          var SOURCE_SENSOR_FULL = 'sensor.battery_life360_' + SOURCE_DEVICE;
          var LEVEL = parseFloat(entities[SOURCE_SENSOR_FULL].state);
          return (LEVEL / 100.0);

        device_class: return 'battery_charging';

The result - there is a "device_class" attribute:

The Template tab - same problem, the added "device_class" does not exist:

yes, thats is a certain thing. Custom-ui is frontend only. It can use backend (global) entities, but not the other way around.
Just like Backend cant do anything with the output of custom cards in Lovelace which is essentially the same.

why would you want to create your own device_class? this doesn’t exist, so will never work? A device_class is only useful when recognized/implemented in core backend, for setting an icon.

If you want that, you can set a customize_glob in an icon template:

  customize_domain:
    switch:
      templates:
        <<: &toggle_icon
          icon: >
            if (state == 'on') return 'mdi:toggle-switch';
            return 'mdi:toggle-switch-off';

and re-use the *toggle_icon anchor wherever you want

of course, you can use a true device_class in custom-ui like:

  customize_domain:
    binary_sensor:
      device_class: presence

which would be useless but just to illustrate. More useful would be:

  customize_glob:
    binary_sensor.motion_*
      device_class: presence

    sensor.*_motion_sensor_battery:
      unit_of_measurement: '%'
      device_class: battery

    sensor.*_sensor_calibrated_temperature:
      unit_of_measurement: °C
      device_class: temperature

Of course you can then check for those device_classes in backend jinja. If thats what you mean, I must rectify my opening answer above…

1 Like

No, it is not my OWN device_class.
I was going to use Custom UI in a wrong way - I wanted to add properties & attributes to many sensors.
I have ~10 sensors with similar attributes (including device_class) and wanted to add these attributes by using Custom UI.

Yes, this is what I wrote above.
The only difference that I added a device_class for SOME entities, not for a domain.

Correct, that is why I wrote above:

crossposted… sorry, see post above
you can even add attributes to your liking and filter on those

homeassistant:
  customize:
    sensor.second_updater:
      icon: mdi:clock
      package: Test

    input_number.test_minute:
      package: Test

    input_boolean.test:
      package: Test

Unfortunately, my added attributes are not visible at least for "auto-entities::template".
Also I cannot use these attributes in automations.
So for now I decided to use Custom UI only for:

  • icon color for batteries dependingly on charge level (earlier was managed by card-mod);
  • entity_picture for persons…
  - type: custom:auto-entities
    card:
      type: entities
      title: Attribute Package
    filter:
      include:
        - attributes:
           package: Test

  - type: custom:auto-entities
    card:
      type: entities
      title: Template Attribute Package
    filter:
      template: >
        {{states|selectattr('attributes.package','eq','Test')
          |map(attribute='entity_id')|list}}

not sure what went wrong in your config/ template, but this is very well possible :wink:

btw, and I have been wanting to ask you before, but why do you use these UPPERCASE variable names? Personally I find that very unpleasing to the eye, but maybe you have a special use case for that? Since yaml is case-sensitive, this might even make those configs more error prone, simply by mistyping a Case.

Just to distinguish sensor’s names & variables.

Sometimes I even cannot do simple things.
This example:

  customize_glob:
    sensor.test_placeinfo_*:
      icon: mdi:web
      templates:
        friendly_name: >
          var OBJ_NAME = entity.entity_id.split('placeinfo_')[1];
          var SENSOR_PLACE = 'sensor.place_' + OBJ_NAME;
          return SENSOR_PLACE;

The result:
image
What is wrong here, why friendly_name is not set?

Cleared cache just in case.

first of all, you could shorten to:

  customize_glob:
    sensor.test_placeinfo_*:
      icon: mdi:web
      templates:
        friendly_name: >
          var OBJ_NAME = entity.entity_id.split('placeinfo_')[1];
          return  'sensor.place_' + OBJ_NAME;

having said that, I rewrote your template to my test config:

homeassistant:

  customize_glob:
    '*.test*':
      templates:
        friendly_name: >
          var splitfname = entity.entity_id.split('test')[1];
          var fname = 'Friendly name changed to: ' + splitfname;
          return fname;

and that works wel:

Marius, my case is NOT working.
This is a very simple case.
I cleared cache many times, closed browser etc.

I cannot see any principal difference between non-working code

  customize_glob:
    sensor.test_placeinfo_*:
      icon: mdi:web
      templates:
        friendly_name: >
          var OBJ_NAME = entity.entity_id.split('placeinfo_')[1];
          var SENSOR_PLACE = 'sensor.place_' + OBJ_NAME;
          return OBJ_NAME;

and this working code:

  customize_glob:
    person.*:
      templates:
        entity_picture: >
          var PERSON = entity.entity_id.split('.')[1];
          var PATH = '/local/images/persons/' + PERSON + '.png';
          return PATH;

Achieving small output with such great efforts…

well, what can I say. I’ve shown the base technique is working, and all attributes are seen in dev states/template and can be used in the frontend by auto-entities, both in attributes filter, and template filter.

you might want to test a bit with the variable naming, and, if reloading the “/configuration/server controls/location and customizations” doesnt work, give it a restart.

sometimes the reload doesnt stick and a restart is necessary

I do restart ALWAYS !!!
Without restart it never works in my setup.

So, I do not know what to do else - after every saving changes in yaml file I always restart HA & clear cache (Chrome).
Here I just stuck with friendly_name.

no, most of the time it works without that, but you need to change the state of the customized entity for the new customization to be effective sometimes;-)

please keep on testing, Ive got to go for a moment now (baking Gevulde Koeken), and prepare for tonights match :wink:

Ill check back in later.

Reinstalled Custom UI by HACS - then "friendly_name" changed to test result:
image
Changed a code for the "friendly_name" - again does not work:

        friendly_name: >
          var OBJ_NAME = entity.entity_id.split('placeinfo_')[1];
          var SENSOR_PLACE = 'sensor.place_' + OBJ_NAME + '_xxx';
          return SENSOR_PLACE;

image

Seems there is smth wrong with installed Custom UI.

Removed Custom UI.
Installed it again via HACS.
Same results - wrong friendly_name.
I surrender.

Did you always install via HACS?

I don’t use that myself, and use the manual resources install, or the UI dashboards/resources install

All my integrations & frontend are installed via HACS.
Never had any problem with it.

It is located in HA/www/community/custom-ui folder:
image