What's this timestamp/string?

HI, Using the googlehome component we get a sensor for an alarm which shows in how many minutes/hours the alarm will fire.

56

If I use this same sensor’s state in a template, {{states('sensor.woonkamer_speaker_alarm')}},this is the outcome:

I would like to have it show the in xx minutes, so had a quick peek in the source code, which does:

    async def async_update(self):
        """Update the data."""
        await self._client.update_alarms(self._host)
        data = self.hass.data[GOOGLEHOME_DOMAIN][self._host]

        alarms = data.get('alarms')[self._condition]
        if not alarms:
            self._available = False
            return
        self._available = True
        time_date = dt_util.utc_from_timestamp(min(element['fire_time']
                                                   for element in alarms)
                                               / 1000)
        self._state = time_date.isoformat()

Not yet familiar with this, Id like to ask some help transforming the state from the time-string to the ‘in xx minutes’ format, using a value_template like:

 {% set state = states('sensor.woonkamer_speaker_alarm') %}
 {% if state == 'unavailable' %} Not set
 {% else %} {{state}}
 {% endif %}

if I enter the sensor in the dev-state it has the time string also as its state:

and, and this might be it, shows device_class: timestamp ? Where is this defined, not here: https://www.home-assistant.io/components/binary_sensor/#device-class

adding that device_class to my sensor does indeed change in to the desired in xxx minutes format, but , it also changes the Not set back in to ‘Invalid date’… which was the reason to create a template sensor in the first place…

Please have a look?

that function returns a timestamp datetime string or datetime object, has nothing to do with ‘x seconds ago’. The UI handles the transformation from timestamp into the format you are looking for.

it is the device_class doing the transformation. Without it, I get the timestring and ‘Not set’. With the device_class, I get the correct ‘In xx minutes’ but also the ‘Invalid date’’.

I want ‘In xxx minutes’ if set, and ‘Not set’ if not set…

The ui is handling the transformation, not the device class. The device class lets the ui know what to do with the output.

You can’t get what you want without doing the calculation yourself and then you’d also need to attach the sensor.time sensor to it as well.

Ok, thanks, thats worded better indeed. Noted.

Yes I think that’s what I was looking for :wink: so how would I need to adapt my template sensor to give the end result I am looking for?

I see the .utc_from_timestamp and .isoformat as important elements in the source code, but how to use these?

if I can get that to work, maybe a PR could be done to change the silly ‘invalid date’ to ‘Not set’…

So on this one, I’m going to let you figure this out because you have this code in your existing configuration. You should know how to do this by now. Subtract the timestamps and convert the information in to the proper days, hours, minutes, and seconds.

haha, ok, hear you.
just to be sure about what you mean, like this:

{% set alarm = as_timestamp(states('sensor.woonkamer_speaker_alarm'))- now().timestamp()%}
in {{alarm/60}} minutes

and then of course add some extra logic to filter weeks, days hours etc etc?

well wouldn’t you know:

           {% set timestamp = as_timestamp(states('sensor.woonkamer_speaker_alarm')) | int %}
          {%- macro pluralize(value, phrase) %}
          {%- set end = 's' if value > 1 else '' %}
          {{- '{} {}{}'.format(value, phrase, end) if value > 0 else '' }}
          {%- endmacro %}
          {% if timestamp %}
            {% set time = timestamp-now().timestamp() %}
            {% set seconds = pluralize((time|int % 60) // 1, 'second') %}
            {% set minutes = pluralize((time|int % 3600) // 60, 'minute') %}
            {% set hours = pluralize((time|int % 86400) // 3600, 'hour') %}
            {% set days = pluralize(time|int // 86400, 'day') %}
            {% set tlist = [ days, hours, minutes, seconds ] | select('!=', '') | list %}
            {% if tlist | length == 0 %}
              {% set phrase = 'less than 1 min' %}
            {% elif tlist | length == 1 %}
              {% set phrase = tlist[0] %}
            {% elif tlist | length == 2 %}
              {% set phrase = tlist | join(' and ') %}
            {% else %}
              {% set phrase = tlist[:-1] | join(', ') + ', and ' + tlist[-1] %}
            {% endif %}
             in {{ phrase }} at {{timestamp|timestamp_custom ('%H:%M') }}
          {% else %}
            Alarm is not set, relax
          {% endif %}

still it isnt as simple as that… the googlehome sensor using device_class: timestamp shows the last minutes in seconds counting down, and also the seconds past the set alarm time:

50

Ive added seconds to the template above, but thats not yet as it should be I guess.

All in all this seems undoable, or at least a lot of templating to mimic that behavior, which is builtin somehow in HA. If only it would show Not set, instead of ‘Invalid date’, which might even be considered bad programming (it isn’t a bug perse)

Hoping someone can help me here because i’m really struggling…

Using this code:

            {% set was_status = states('sensor.washer_washer_machine_state') %}
            {% set timestamp = as_timestamp(states('sensor.washer_washer_completion_time')) | int %}
            {%- macro pluralize(value, phrase) %}
            {%- set end = '' if value > 1 else '' %}
            {{- '{} {}{}'.format(value, phrase, end) if value > 0 else '' }}
            {%- endmacro %}
            {% if timestamp %}
              {% set time = timestamp-now().timestamp() %}
              {% set seconds = pluralize((time|int % 60) // 1, 'seconden') %}
              {% set minutes = pluralize((time|int % 3600) // 60, 'minuten') %}
              {% set hours = pluralize((time|int % 86400) // 3600, 'uur') %}
              {% set days = pluralize(time|int // 86400, 'day') %}
              {% set tlist = [ hours, minutes ] | select('!=', '') | list %}
              {% if tlist | length == 0 %}
                {% set phrase = '1 minuut' %}
              {% elif tlist | length == 1 %}
                {% set phrase = tlist[0] %}
              {% elif tlist | length == 2 %}
                {% set phrase = tlist | join(' and ') %}
              {% else %}
                {% set phrase = tlist[:-1] | join(', ') + ', en ' + tlist[-1] %}
              {% endif %}
              Wasmachine over {{ phrase }} klaar
            {% else %}
            {% endif %}

But i want to add the ‘sensor.washer_washer_machine_state’. So when this sensor status = ‘run’ it runs the timer. If not, i don’t want to mention the timer in my Lovelace.

Hoping someone can help me, thanks!