Convert seconds to days, hours, minutes

binary_sensor:
  - platform: template
    sensors:
      breakfast_nook_window_time:
        friendly_name: Nook Window time
        value_template: '{{ as_timestamp(binary_sensor.breakfast_nook_window) }} | {{ as_timestamp(now()) - as_timestamp(binary_sensor.breakfast_nook_window.last_tripped_time) }}'

Cannot read property ‘v’ of undefined

Well, I’m still stumped. I don’t see where as_timestamp can take a number, assume it’s seconds and convert it as I need, so as a test I replaced that with just the current time and it still didn’t add the last_time_tripped to the new entity. I started looking at humanfriendly from this thread: https://stackoverflow.com/questions/775049/python-time-seconds-to-hms That would solve the conversion, but why can’t I get that attribute in the new entity?

Getting this as the first log entry: “Could not render template Nook Window time, the state is unknown” followed later by, “Could not render template Nook Window time: UndefinedError: ‘homeassistant.core.State object’ has no attribute ‘last_tripped_time’”

Added ‘entity_id: sensor.time’ to fix that, but no help

states.binary_sensor.breakfast_nook_window.attributes.last_tripped_time removed the secondary errors but still no attribute

sensor:
  - platform: time_date
    display_options:
      - 'time'

binary_sensor:
  - platform: template
    sensors:
      breakfast_nook_window_time:
        friendly_name: Nook Window time
        value_template: '{{ as_timestamp(states.binary_sensor.breakfast_nook_window.last_tripped_time.state) }} | {{ as_timestamp(now())}}'
        device_class: opening
        entity_id: sensor.time

Would something like this work?

sensor:
  - platform: template
    sensors:
      breakfast_nook_window_time:
        friendly_name: Nook Window time
        value_template: >-
          {% set time = states.binary_sensor.breakfast_nook_window.attributes.last_tripped_time %}
          {% set minutes = ((time % 3600) / 60) | int %}
          {% set hours = ((time % 86400) / 3600) | int %}
          {% set days = (time / 86400) | int %}

          {%- if time < 60 -%}
            Less than a minute
          {%- else -%}
            {%- if days > 0 -%}
              {%- if days == 1 -%}
                1 day
              {%- else -%}
                {{ days }} days
              {%- endif -%}
            {%- endif -%}
            {%- if hours > 0 -%}
              {%- if days > 0 -%}
                {{ ', ' }}
              {%- endif -%}
              {%- if hours == 1 -%}
                1 hour
              {%- else -%}
                {{ hours }} hours
              {%- endif -%}
            {%- endif -%}
            {%- if minutes > 0 -%}
              {%- if days > 0 or hours > 0 -%}
                {{ ', ' }}
              {%- endif -%}
              {%- if minutes == 1 -%}
                1 minute
              {%- else -%}
                {{ minutes }} minutes
              {%- endif -%}
            {%- endif -%}
          {%- endif -%}

Btw, this sensor cannot be a binary_sensor as such a sensor can only have 2 states, so I turned it into a regular sensor.

6 Likes

Works like a champ! I though I was just changing an attribute, which is different from the entity’s state. Also like instantiating an object in Java and changing your copy. Can you enlighten me?

Thanks

All the template sensor does in this case, thanks to the value_template is change the visual representation of the last_tripped_time of your binary_sensor. It doesn’t do anything to the attribute itself, or the entity the attribute belongs to.

I use very similar sensors in my setup to show the uptime of my Raspberry Pi and the runtime of Home Assistant. So I just took the yaml-code from one of those two sensors, and edited it to suit your scenario.

Does anyone know how to set up the uptime sensor?
It can only show minutes, days or hours. https://home-assistant.io/components/sensor.uptime/
Would really like for that one to show up the same way as the sensor.last_boot or as you have mentioned @fanaticDavid

The uptime sensor is very limited in functionality. I’m still using my template sensor for exactly that reason:

- platform: template
  sensors:
    since_last_boot_templated:
      value_template: >-
        {%- if states.sensor.since_last_boot -%}
          {%- set slb = states.sensor.since_last_boot.state.split(' ') -%}
          {%- set count = slb | length -%}
          {%- set hms = slb[count - 1] -%}
          {%- set hms_split = hms.split(':') -%}
          {%- set hours = hms_split[0] | int -%}
          {%- set minutes = hms_split[1] | int -%}
          {%- if count == 3 -%}
            {%- set days = slb[0] | int -%}
          {%- else -%}
            {%- set days = 0 -%}
          {%- endif -%}

          {%- if days == 0 and hours == 0 and minutes == 0 -%}
            less than a minute
          {%- else -%}
            {%- if days > 0 -%}
              {%- if days == 1 -%}
                1 day
              {%- else -%}
                {{ days }} days
              {%- endif -%}
            {%- endif -%}
            {%- if hours > 0 -%}
              {%- if days > 0 -%}
                {{ ', ' }}
              {%- endif -%}
              {%- if hours == 1 -%}
                1 hour
              {%- else -%}
                {{ hours }} hours
              {%- endif -%}
            {%- endif -%}
            {%- if minutes > 0 -%}
              {%- if days > 0 or hours > 0 -%}
                {{ ', ' }}
              {%- endif -%}
              {%- if minutes == 1 -%}
                1 minute
              {%- else -%}
                {{ minutes }} minutes
              {%- endif -%}
            {%- endif -%}
          {%- endif -%}
        {%- else -%}
          n/a
        {%- endif -%}
      entity_id: sensor.since_last_boot

The entity sensor.since_last_boot on which I based the sensor above, is provided by the System Monitor.

Thank you, @fanaticDavid but I don`t need the sensor for how long it has been I restartet the pi, I want the time since I last restartet homeassistant.

Before I used this to control it:

 - platform: command_line
   name: "HA Uptime"
   command: echo "$(($(date +%s) - $(date -d "$(head -n1 /config/home-assistant.log | cut -d' ' -f-2)" +%s)))"
   scan_interval: 60
   value_template: >-
     {% set uptime = value | int %}
     {% set minutes = ((uptime % 3600) / 60) | int %}
     {% set hours = ((uptime % 86400) / 3600) | int %}
     {% set days = (uptime / 86400) | int %}

     {%- if uptime < 60 -%}
       Less than a minute
     {%- else -%}
       {%- if days > 0 -%}
         {%- if days == 1 -%}
           1 day
         {%- else -%}
           {{ days }} days
         {%- endif -%}
       {%- endif -%}
       {%- if hours > 0 -%}
         {%- if days > 0 -%}
           {{ ', ' }}
         {%- endif -%}
         {%- if hours == 1 -%}
           1 hour
         {%- else -%}
           {{ hours }} hours
         {%- endif -%}
       {%- endif -%}
       {%- if minutes > 0 -%}
         {%- if days > 0 or hours > 0 -%}
           {{ ', ' }}
         {%- endif -%}
         {%- if minutes == 1 -%}
           1 minute
         {%- else -%}
           {{ minutes }} minutes
         {%- endif -%}
       {%- endif -%}
     {%- endif -%}

But I have moved my database to MariaDB, so I can`t use that anymore.
Therefore I just need a template to convert minutes to the same way this did with seconds. I am not sure how.

1 Like

My bad, I didn’t read the Uptime Sensor page completely so I wrongly assumed it was the host’s uptime being displayed.

In my setup, I use the following command_line sensor for my Home Assistant uptime:

- platform: command_line
  name: "HA runtime"
  command: echo "$(($(date +%s) - $(date --date="`systemctl show home-assistant.service -p ActiveEnterTimestamp | awk -F'=' '{print $2}'`" "+%s")))"
  scan_interval: 60
  value_template: >-
    {% set uptime = value | int %}
    {% set minutes = ((uptime % 3600) / 60) | int %}
    {% set hours = ((uptime % 86400) / 3600) | int %}
    {% set days = (uptime / 86400) | int %}

    {%- if uptime < 60 -%}
      less than a minute
    {%- else -%}
      {%- if days > 0 -%}
        {%- if days == 1 -%}
          1 day
        {%- else -%}
          {{ days }} days
        {%- endif -%}
      {%- endif -%}
      {%- if hours > 0 -%}
        {%- if days > 0 -%}
          {{ ', ' }}
        {%- endif -%}
        {%- if hours == 1 -%}
          1 hour
        {%- else -%}
          {{ hours }} hours
        {%- endif -%}
      {%- endif -%}
      {%- if minutes > 0 -%}
        {%- if days > 0 or hours > 0 -%}
          {{ ', ' }}
        {%- endif -%}
        {%- if minutes == 1 -%}
          1 minute
        {%- else -%}
          {{ minutes }} minutes
        {%- endif -%}
      {%- endif -%}
    {%- endif -%}

My Home Assistant instance is based on the All-in-One Installer, so YMMV.

By the way, I don’t see how you switching to MariaDB would’ve broken your sensor. It seems to be based on the Home Assistant log file, not the SQLite database.

You are completely right! It may be due to the upgrade to 0.60, but I`m not sure.
Anyways, it does just continue add time from the state it had, so it now starts up with over 20 hours.
But the uptime sensor does seem correct, so if I just could just use that data to a similar template all would be good.
It comes with an output of “0.00” minutes, so do you know how to change that to days, hours, minutes?
I use Hassio, so I can not use systemctl.

Think I found the solution:

 - platform: template
   sensors:
     ha_uptime_templated:
       value_template: >-
         {% set uptime = states.sensor.time_online.state | int %}
         {% set minutes = ((uptime % 60) / 1) | int %} 
         {% set hours = ((uptime % 1440) / 60) | int %}
         {% set days = (uptime /1440) | int %}

         {%- if uptime < 1 -%}
           Less than a minute
         {%- else -%}
           {%- if days > 0 -%}
             {%- if days == 1 -%}
               1 day
             {%- else -%}
               {{ days }} days
             {%- endif -%}
           {%- endif -%}
           {%- if hours > 0 -%}
             {%- if days > 0 -%}
               {{ ', ' }}
             {%- endif -%}
             {%- if hours == 1 -%}
               1 hour
             {%- else -%}
               {{ hours }} hours
             {%- endif -%}
           {%- endif -%}
           {%- if minutes > 0 -%}
             {%- if days > 0 or hours > 0 -%}
               {{ ', ' }}
             {%- endif -%}
             {%- if minutes == 1 -%}
               1 minute
             {%- else -%}
               {{ minutes }} minutes
             {%- endif -%}
           {%- endif -%}
         {%- endif -%}
1 Like

Have tried to follow along and adapt to my situation with mixed results.
I have an SMNP uptime sensor that returns a timeticks value.

I wanted to achieve the same results as above but instead get this:

Here is my code, noting that timeticks need to be converted to seconds/minutes/hours with a different calculation that normal time

- platform: template
  sensors:
  esxi_real_uptime:
    friendly_name: ESXi Uptime
    value_template: >-
      {% set time = states.sensor.esxi_raw_uptime.state | int %}
      {% set minutes = (time / 6000) | int%}
      {% set hours = (time / 360000) | int %}
      {% set days = (time / 8640000) | int %}

      {%- if time < 6000 -%}
        Less than a minute
      {%- else -%}
        {%- if days > 0 -%}
          {%- if days == 1 -%}
            1 day
          {%- else -%}
            {{ days }} days
          {%- endif -%}
        {%- endif -%}
        {%- if hours > 0 -%}
          {%- if days > 0 -%}
            {{ ', ' }}
          {%- endif -%}
          {%- if hours == 1 -%}
            1 hour
          {%- else -%}
            {{ hours }} hours
          {%- endif -%}
        {%- endif -%}
        {%- if minutes > 0 -%}
          {%- if days > 0 or hours > 0 -%}
            {{ ', ' }}
          {%- endif -%}
          {%- if minutes == 1 -%}
            1 minute
          {%- else -%}
            {{ minutes }} minutes
          {%- endif -%}
        {%- endif -%}
      {%- endif -%}

Not totally sure where I am going wrong here. Spent about 3 hours trying to figure it out with no luck.

Gah, I must be tired. I went back one last time after posting this and found my mistake.

Have to set the actual values for minutes and hours:

      {% set time = states.sensor.esxi_raw_uptime.state | int %}
      {% set minutes = ((time % 360000) / 6000) | int%}
      {% set hours = ((time % 8640000) / 360000) | int %}
      {% set days = (time / 8640000) | int %}

Much better:

Another (quick) way of converting seconds to a (sort of) nice format:

value_template: “{{ ((value | int) / 100) | int | timestamp_custom(‘%j days %H:%M:%S’) }}”

In this case value is in hundred of seconds, hence the value/100.

Addendum: discovered one drawback, days is always one to many because day 0 doesnt exist and datetime starts from day 1.

2 Likes

A further enhancements which hasn’t got the drawback of wrong number of days:

  value_template: >-
    {% set uptime = (value | int) / 100 | int %}
    {% set days = (uptime / 86400) | int %}
    {%- if days > 0 -%}
      {{ days }} days, {{ (uptime - (days * 86400)) | int | timestamp_custom('%H:%M:%S') }}
    {%- else -%}
      {{ uptime | int | timestamp_custom('%H:%M:%S') }}
    {%- endif -%}
2 Likes

I was using the original code but i wanted to shorten the ouput so i modified the code to output 00d 00h 00m. Much better IMO than the elongated 00 days, 00 hours, 00 minutes.

Heres the code:

value_template: >-
{% set time = (value | int) | int %}
{% set minutes = ((time % 360000) / 6000) | int %}
{% set hours = ((time % 8640000) / 360000) | int %}
{% set days = (time / 8640000) | int %}

{%- if time < 6000 -%}
  Less than a minute
{%- else -%}
  {%- if days > 0 -%}
    {{ days }}d
  {%- endif -%}
  {%- if hours > 0 -%}
    {%- if days > 0 -%}
      {{ ' ' }}
    {%- endif -%}
    {{ hours }}h
  {%- endif -%}
  {%- if minutes > 0 -%}
    {%- if days > 0 or hours > 0 -%}
      {{ ' ' }}
    {%- endif -%}
    {{ minutes }}m
  {%- endif -%}
{%- endif -%}
2 Likes

To contribute my version: it abuses Jinja’s whitespace control. Easily extendable to Months, Quarters,Years, etc.

edit //
It was breaking on exactly 60 minutes, 1 day, etc. Should be more robust now!

  # NOTE:
  # - define durations for the various UNITs of time
  #   * modulus helps to reduce "extras" of the larger time units
  # 
  # - now build the string
  #
  # for each UNIT of time that's greater than 1:
  #     if it's not the first loop iteration:
  #         append ", " to the string
  #     else:
  #         1. convert the DURATION to STR
  #         2. split DURATION on "."
  #         3. append the left part (the whole number) to the string
  #         4. append the UNIT to the string
  #
  # ...but if that's no UNITs, then we just started so
  # set the string to "just now"
  #
  - platform: template
    sensors:
      hass_uptime:
        value_template: >-
          {%- set uptime  = states.sensor.hass_uptime_minutes.state | round -%}
          {%- set sep     = ', ' -%}
          {%- set TIME_MAP = {
              'week': (uptime / 10080) % 10080,
               'day': (uptime / 1440) % 7,
              'hour': (uptime / 60) % 24,
            'minute': (uptime % 60)
          }
          -%}

          {%- for unit, duration in TIME_MAP.items() if duration >= 1 -%}
            {%- if not loop.first -%}
              {{ sep }}
            {%- endif -%}
              
            {{ (duration | string).split('.')[0] }} {{ unit }}

            {%- if duration >= 2 -%}
              s
            {%- endif -%}
          {%- endfor -%}

          {%- if uptime < 1 -%}
            just now
          {%- endif -%}
9 Likes

much better than the hacky version I was using which didnt display properly. Thanks for sharing :hugs:

Hi
i want ask will this code work with NUT ?

i want make the Runtime in minute or hour will work ?
i never use template before

thank you

Yes, I am using essentially the same code for mine.

- platform: template
  sensors:  
    nut_ups_runtime_friendly:
    friendly_name: 'Time Remaining'
    value_template: >- 
      {% set time = (states.sensor.nut_ups_battery_runtime.state | int) | int %}
      {% set minutes = ((time % 3600) / 60) | int %}
      {% set hours = ((time % 86400) / 3600) | int %}
      {% set days = (time / 86400) | int %}
    
      {%- if time < 60 -%}
        Less than a minute
        {%- else -%}
        {%- if days > 0 -%}
          {{ days }}d
        {%- endif -%}
        {%- if hours > 0 -%}
          {%- if days > 0 -%}
            {{ ' ' }}
          {%- endif -%}
          {{ hours }}h
        {%- endif -%}
        {%- if minutes > 0 -%}
          {%- if days > 0 or hours > 0 -%}
            {{ ' ' }}
          {%- endif -%}
          {{ minutes }}m
        {%- endif -%}
      {%- endif -%}
2 Likes

thanks for reply
it don’t work for me don’t know why ?
do i need to change the code or not ?

thank you