How to make Sensor show minutes or hours instead of 0.52 hours = 30 minutes

Created a test “duration” sensor:

sensor:
  - platform: template
    sensors:

      test_device_class_duration:
        device_class: duration
        value_template: >-
          {% set INPUT_NAME = "input_number.test_device_class_duration" -%}
          {{ states(INPUT_NAME) }}

But this sensor does not show a time:
изображение

Also, I expected a special icon automatically assigned for this sensor.

Tried the same, it shows a time if you add unit_of_measurement: h to the template sensor.
20220512_120803

No clue about the icon.

1 Like

I managed to get a proper presentation by adding UoM!

I wonder which device_classes also need adding UoM to be presented properly…

All of them for sensors.

I mean:

  1. To make the value to be displayed with UoM - surely we must specify UoM.
  2. But at least the duration sensor is displayed in hh:mm:ss format only if UoM is specified.

i.e. the displayed VALUE is different for the “duration”.
That is why I am asking (sorry for off-topic) about different device_classes whose presentation depends on presence of UoM.

All device classes for sensor need UoM so that it can be used properly in home assistant. This is the bases for converting values from one unit to another (I.e. energy panel, converting c to f, etc). This is no different for duration. You need to let the system know what the duration units are in so that it can properly change the display for you.

EDIT: I think the only exception is timestamps, which are unitless

Probably I need to create test sensors for all device_classes and see what changes if UoM is specified.
Thanks a lot for clarifications!

It’s in the early stages, so I wouldn’t expect sweeping changes to your UI. C to F has been there from the beginning of time. So that one is unique. All the rest are within the last year.

I created test sensors for different dev_classes - here is a code-generator below.
Probably my test is wrong since I am using input_number values which do not have device_class specified, but they have UoMs specified.

{% set CLASSES_SENSOR = [
  ("aqi","AQI"),
  ("apparent_power","VA"),
  ("battery","%"),
  ("carbon_dioxide","CO2"),
  ("carbon_monoxide","CO"),
  ("current","A"),
  ("duration","h"),
  ("energy","kWh"),
  ("frequency","MHz"),
  ("gas","\u006d\u00b3"),
  ("humidity","%"),
  ("illuminance","lx"),
  ("monetary","€"),
  ("nitrogen_dioxide","µg/m³"),
  ("nitrogen_monoxide","µg/m³"),
  ("nitrous_oxide","µg/m³"),
  ("ozone","µg/m³"),
  ("pm1","µg/m³"),
  ("pm10","µg/m³"),
  ("pm25","µg/m³"),
  ("power_factor","%"),
  ("power","W"),
  ("pressure","hPa"),
  ("reactive_power","var"),
  ("signal_strength","dB"),
  ("sulphur_dioxide","µg/m³"),
  ("temperature","°C"),
  ("volatile_organic_compounds","µg/m³"),
  ("voltage","V")
] %}

{% set CLASSES_BINARY_SENSOR = [
  "battery",
  "battery_charging",
  "cold",
  "connectivity",
  "door",
  "garage_door",
  "gas",
  "heat",
  "light",
  "lock",
  "moisture",
  "motion",
  "moving",
  "occupancy",
  "opening",
  "plug",
  "power",
  "presence",
  "problem",
  "running",
  "safety",
  "smoke",
  "sound",
  "tamper",
  "update",
  "vibration",
  "window"
] %}

{% set code_input_boolean = '
  test_device_class_{0}:' %}

{% set code_input_number = '
  test_device_class_{0}:
    min: -1000000
    max: 1000000
    step: 0.01
    mode: box
    initial: 0
    unit_of_measurement: "{1}"
' %}

{% set code_binary_sensor = '
      test_device_class_{0}:
        device_class: {0}
        value_template: >-
          {{% set INPUT_NAME = "input_boolean.test_device_class_{0}" -%}}
          {{{{ states(INPUT_NAME) }}}}
' %}

{% set code_sensor = '
      test_device_class_{0}:
        device_class: {0}
        unit_of_measurement: "{1}"
        value_template: >-
          {{% set INPUT_NAME = "input_number.test_device_class_{0}" -%}}
          {{{{ states(INPUT_NAME) }}}}
' %}

input_boolean:
{% for class in CLASSES_BINARY_SENSOR -%}
  {{ code_input_boolean.format(class) }}
{%- endfor %}

############################################################################

input_number:
{% for class,uom in CLASSES_SENSOR -%}
  {{ code_input_number.format(class,
                              uom) }}
{%- endfor %}
############################################################################

binary_sensor:
  - platform: template
    sensors:
{% for class in CLASSES_BINARY_SENSOR -%}
  {{ code_binary_sensor.format(class) }}
{%- endfor %}
############################################################################

sensor:
  - platform: template
    sensors:
{% for class,uom in CLASSES_SENSOR -%}
  {{ code_sensor.format(class,
                        uom) }}
{%- endfor %}

Here is a card - use it in Panel mode:

type: horizontal-stack
cards:
  - type: custom:auto-entities
    card:
      type: entities
      title: input_boolean
    unique: entity
    show_empty: true
    filter:
      template: |-
        {% for state in states.input_boolean -%}
          {%- if state.entity_id | regex_match("input_boolean.test_device_class_", ignorecase=False) -%}
            {{
              {
                'entity': state.entity_id,
                'name': state.entity_id.split('test_device_class_')[1]
              }
            }},
          {%- endif -%}
        {%- endfor %}
    sort:
      method: name
  - type: custom:auto-entities
    card:
      type: entities
      title: binary_sensor
    unique: entity
    show_empty: true
    filter:
      template: |-
        {% for state in states.binary_sensor -%}
          {%- if state.entity_id | regex_match("binary_sensor.test_device_class_", ignorecase=False) -%}
            {{
              {
                'entity': state.entity_id,
                'name': state.entity_id.split('test_device_class_')[1]
              }
            }},
          {%- endif -%}
        {%- endfor %}
    sort:
      method: name
  - type: custom:auto-entities
    card:
      type: entities
      title: input_number
    unique: entity
    show_empty: true
    filter:
      template: |-
        {% for state in states.input_number -%}
          {%- if state.entity_id | regex_match("input_number.test_device_class_", ignorecase=False) -%}
            {{
              {
                'entity': state.entity_id,
                'name': state.entity_id.split('test_device_class_')[1]
              }
            }},
          {%- endif -%}
        {%- endfor %}
    sort:
      method: name
  - type: custom:auto-entities
    card:
      type: entities
      title: sensor
    unique: entity
    show_empty: true
    filter:
      template: |-
        {% for state in states.sensor -%}
          {%- if state.entity_id | regex_match("sensor.test_device_class_", ignorecase=False) -%}
            {{
              {
                'entity': state.entity_id,
                'name': state.entity_id.split('test_device_class_')[1]
              }
            }},
          {%- endif -%}
        {%- endfor %}
    sort:
      method: name

So, I do not see any changes in presentation if UoM is specified - only difference is that UoM is displayed after the value.
Exceptions:

  1. “duration” is displayed w/o UoM in “hh:mm:ss” format (which does not occur if UoM is not specified);
  2. “monetary” - no UoM is displayed for sensor:

Also, I changed UoM for some values to see what could happen.
For example, for “frequency” - the value was “xxx MHz”, I changed UoM to “Hz” and reloaded templates - the displayed value is “xxx Hz”:

As for temperature: initially the sensor has UoM =C, then I changed to F - and the value is changed (not correct), UoM not changed:

Is there any template function to show the duration value in a human readable format?

{{ states.sensor.history_stats_sensor.state }} shows a decimal number of hours

timedelta I think.

I would like to know this as well. Here’s what I worked out, but I’m not sure if it’s the right/best way to do it.

{{ timedelta(float(states.sensor.duration.state) / 24) }}

This converts a value like 4.64 to 4:38:24.
It works, but is there a better way?

{{ timedelta(states('sensor.duration') | float(0) / 24) }}

Rather use the states function and provide a default. It’s more robust.

1 Like

Thanks! It seems like extra ‘work’ to do actual maths when the sensor already ‘knows’ what the time is. If I just show the value without a template, it shows as time nicely already, but I want to use the template-entity-row entity, which doesn’t automatically convert.
Is there a simpler way that doesn’t involve this manual work?

There isn’t.

The software doesn’t know anything like this per se. It’s just default behaviour to represent something – of which there can be many ways, and it depends on many factors (datetime values in general depend on your locale).

Ask the maintainer if they’re willing to match HA’s default behaviour.

1 Like

I know this works but I cannot use it for my custom:multiple-entity-row card where I need to give an entity. I cannot manipulate it. How to fix it then?

You can make a template sensor and display that.

Sounds like a complete overload. I already have a template sensor like the thread starter. It is insane that this is necessary for such an easy task. I have 10 of these entities with this requirement. It’s a complete bloat.

Perhaps, but you asked for help which I gave. I don’t know of another way. You can look for a custom card or something that might allow you to do this.

1 Like

Thank you @parautenbach, I was looking for this answer for a couple of hours.

1 Like