Add (bring back) friendly_name to template sensors

Thanks! I can’t believe I overlooked the existing ability to define custom attributes in the sensor’s configuration. I even have existing examples of it in my own system! :man_facepalming:

Unfortunately, what failed to work in my tests was overriding friendly_name. For example, this Template Sensor on my test system:

  - name: All Lights On
    state: "{{ states.light | selectattr('state', 'eq', 'on' | list | count }}"
    attributes:
      entities: "{{ states.light | selectattr('state', 'eq', 'on') | map(attribute='name') | list | join(', ') }}"
      friendly_name: "{{'Thingamajig'}}"
      type: "{{'Widget'}}"
      location: "{{'Rock and a hard place'}}"

Rendered this:

Screenshot from 2021-05-08 12-42-36

Its friendly_name should be “Thingamajig” but it’s still based on name. I don’t know if that’s by design or a bug.

it needs something to update it, it’s working for my ‘county’ coronavirus entity, which is based on rest

I turned on a light, which served to update the sensor’s state and its (custom) entities attribute but not friendly_name. It’s still called “All Lights on”.

Screenshot from 2021-05-08 12-52-18

this is mine:

  - unique_id: corona_virus_county
    state: >
      {%- set features = state_attr('sensor.corona_virus_county_rest', 'features') %}
      {%- set items = features | map(attribute='attributes') | list %}
      {%- if items | length > 0 %}
        {%- set item = items | first %}
        {%- set last_updated = item.Last_Update | int / 1000 %}
        {{ last_updated | timestamp_custom('%Y-%m-%dT%H:%M:%S.%f+00:00', False) }}
      {%- else %}
        {{ states('sensor.corona_virus_county_rest') }}
      {%- endif %}
    availability: >
      {%- set features = state_attr('sensor.corona_virus_county_rest', 'features') %}
      {%- set features = features | map(attribute='attributes') | list %}
      {{ features | length > 0 }}
    attributes:
      template: corona_virus
      friendly_name: >
        {%- set features = state_attr('sensor.corona_virus_county_rest', 'features') %}
        {%- set items = features | map(attribute='attributes') | list %}
        {%- if items | length > 0 %}
          {%- set item = items | first %}
          Corona Virus {{ item.Admin2 }}
        {%- else %}
          Corona Virus {{ state_attr('sensor.corona_virus_county_rest', 'county') }}
        {%- endif %}

I never assigned it a name though.

Ahah! That’s it!

I removed name, added unique_id: all_lights_on and here’s the result:

It created a sensor whose object_id combines the word “template” with the value of its unique_id. Now its friendly_name is “Thingamajig”.

Interesting, I thought name is required but the documentation clearly shows it’s optional.

2 Likes

Nice, so then it works.

  1. Use unique_id.
  2. Don’t use name.
  3. Add a friendly_name attributes template.
  4. Profit.
9 Likes

Just for laughs, I also tried eliminating both name and unique_id. It passed Check Configuration and produced this:

Screenshot from 2021-05-08 13-06-59

Not a recommended way of creating (nameless) sensors but it (surprisingly) works.

TBH, I bet this works on other template integrations too. The existence of the friendly name attribute is what causes the problems. Without name, friendly_name doesn’t exist and it defaults to <states_obj>.name when shown in the UI.

As long as the value assigned to unique_id is meaningful, the user retains control over the sensor’s object_id (but with “template_” prepended to it) as well as its friendly_name. Good enough for me.

I just add a template attribute to all my templates instead of adding it to the object_id.

- sensor:
  - unique_id: something_xyz
    ...
    attributes:
      template: <description of wtf it does>

Adding the unique_id gives you the control the name in the UI too. If name doesn’t exist, it’ll use the unique_id as the object_id. If name and unique_id exist, it’ll take the name and chop it into a object_id. If name exists and unique_id doesn’t, you won’t be able to edit it in the UI and it’ll chop the name into the object_id. And you’ve already seen what it does without a name and a unique_id.

1 Like

you’ve been at it while Ive been away :wink: thanks!

and no, I haven’t tried that yet, though I did try to understand the code, and especially this on friendly_names.

Thats why I was confused friendly_name not to be mentioned in the documentation. Given the fact it is such a system wide default configuration variable, it does feel awkward we should now configure it under the manually added attributes (templates), and not have it as a default option perse. (hence my FR…)

Please let me ask if I overlooked another possible feature, namely the much anticipated template variables? It would be so great if we could set a variable, to be used in all following templates of the same sensor. Or maybe even better, use the state of the main state in all other templates, as a config entity.

It would shorten Add (bring back) friendly_name to template sensors - #8 by petro Petro’s template dramatically.

that would allow me to do what I have been trying for a very long time now, in the friendly_name_template: (declare once in an anchor, and insert that anchor in the other 22):

      corridor_terrace_sensor_light_level_raw:
        value_template: >
          {{state_attr('sensor.corridor_terrace_sensor_light_level','lightlevel')}}
#        friendly_name_template: >
#          Corridor terrace:
#          {% set light_level = state_attr('sensor.corridor_terrace_sensor_light_level','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 %}

Because the above needs to be repeated for all (23) sensors individually with the legacy format, I do it in a customization:

        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';

which would be the anchor if the template variables would be available.

now back to your findings above which I havent studied completely yet.

Hi @petro ,

I thought doing so would prevent the auto prepending of the ‘template_’ string to the unique id when it generates the entity id, but it still appears.
How do you manage not to have this in your entity id? Do you edit it afterwards in the UI?

Just add a name and it’ll use the name to create the object id.

1 Like

Thanks for your prompt reply, but it does not really answer my questions, I am afraid. You did not use name, I think. And I wanted to have the friendly_name working as well, which does not seem possible when using name.
What is the exact purpose of your template attribute?

Then just change the entity id through the ui

So I can organize my system and know where it comes from

OK, thanks, that’s what I thought.
It would have been more convenient to be able to control all of these in the yaml configuration. Maybe in the future…

Alright, I misunderstood it. Thanks!

I thought it might be useful to provide a real world example of some hurdles that not being able to manually set the the entity_id AND the friendly_name for each template using the modern template approach. Good news, is that there are a few workarounds, listed above, that have ultimately allowed me to make this work and keep manageable for now, just not as clean as I was able to keep it before.

I have ~100 electrical power sensors I’m tracking in my config. Having this many sensors reporting regularly can cause lots of performance issues, and where I am doing calculations on those sensors, the impact is multiplied by several x. Doing calculations on 3 power sensors together that report state every 5 seconds, you may end up with many more calculated state changes instead of 1. This is ultimately why I wanted to move to the new trigger based sensors where I can just do that calculation every 30 seconds or so. (I do understand there are many different ways I could handle this, but when I started, this seemed like the easiest approach for my needs)

Because each integration uses a slightly different naming standard for reporting power, I chose to make an individual templated sensor for each item I wanted to track. In other words, if my Shelly plug reports power under a sensor name of “sensor.power_office_plug”, then I manually create a template sensor with an entity_id in a naming convention which tells me the breaker box and electrical circuit that device is plugged into. Organization is important, because I’m also doing calculations that look at my total power used on a circuit, then subtract out my known power, like the office plug, to determine what my unknown power usage is on that circuit.

Many of the integrations, like logbook, recorder, and InfluxDB only allow you to easily include / exclude based on entity_id name, so that becomes critical to have named in a standard way otherwise each sensor has to be added manually. When you get to the point of having 100+ devices, the idea of individually editing those names in the GUI also isn’t great. For that reason, I’m using “Name:” to define my new trigger based sensors, which gives me the exact entity_id that need and allows me to use all of my pre-existing logic and dashboards I’ve built in lovelace and Grafana. This is all working fine on the backend which is great, but the unfortunate side effect, is that the “friendly_name” is then forced in the sensor as an attribute matching the entity_id. Similarly to how the integrations mentioned above rely on entity_id, most of the lovelace cards and dashboards have been designed to rely on friendly_name, which causes some challenges. I’m pretty sure it is the dichotomy of accounting for both frontend and backend needs that some people are finding challenging. (Probably in the niche or more complex configurations like mine has become)

Fortunately, the easiest workaround for now, is to add a customization section which maps out all of the friendly names for each of those sensors. Due to the way I designed this, I needed to add 100 entries in the customize section to set the friendly_name for each of those sensors. Doesn’t seem like the cleanest approach, but it is working fine. Ideally, in the future, if I can control both my exact entity_id name and my friendly_name as an attribute where I define my trigger based sensor, it would be a bit nicer, IMO. Thanks all!

3 Likes

I stumbled over the same questions when I tried to migrate my old template sensors to the new syntax but I gave up for now.
I don‘t get it why I am not able to just set the name and ID simple in YAML.
Is there some kind of design guide that changed and the template integration is trying to follow?
Why is unique_id not used for the ID in the GUI and name as name? Why such a strange and unclear behavior?
Before I had to set the ID and then I was able to provide a friendly_name at least for this integration. Others had name. THis is really unintuitive…

1 Like