Convert seconds to days, hours, minutes

My envisalink sensors return a last_tripped_time that is in seconds and I’d like convert that to days, hours and minutes. I found a python module that does that simply, but I’m not sure how to integrate it. It works from a python console, but HA doesn’t see it.

I’m new to HA, python, jinja2, etc.

binary_sensor.breakfast_nook_window:
  show_last_changed: True
  friendly_name: Nook Window
  value_template: '{ humanfriendly.format_timespan(last_tripped_time, detailed=False, max_units=3) }'

On a side note, my python version is apparently 2.7.9. Is that right?

2 Likes

An expert programmer needs to actually help you… but I play one on TV.

I know Home Assistant is written in Python 3, not 2.7… If Home Assistant is working then it may not be an issue.

Next, I was reading about humanfriendly… it needs to be imported - not native to python - not sure it’s included with Home Assistant… Again you need a real programmer here. But I did stay at a holiday inn express last night.

I did find this and it may solve the issue: https://home-assistant.io/docs/configuration/templating/
More specifically this timestamp thingy:
{{ as_timestamp(states.binary_sensor.garage_door.last_changed) }}

{{ as_timestamp(now()) - as_timestamp(states.binary_sensor.garage_door.last_changed) }}

Good Luck - Hope I helped a little.

Thanks. I did add it with pip and then import. I appended its location to pythonpath, but it kept getting removed. They must have made it fool proof. I dabble in programming for fun, but most of the HA stuff is new to me. I’ve always learned by glomming other people’s work and bending it to my will, but not having much luck here. Everything seems to work despite the apparent wrong python version.

What version do you get from ‘python -V’?

I use the AIO installer on a RPi3. When I type python -V I also get 2.7.9. I dabble in python and wish I could get someone to show me the ropes on where I can help with the project.

I specifically want to change the “off” color of the optimistic true switches from the default “on” blue color. See it’s blue because off is on… When off should not be blue or on at all. lol It’s a over-simplistic programming error that should be spanked.

Have you tried the timestamp yet?

This must be way off. It passes the syntax checker, but doesn’t show up in the front end or States area:

- platform: template
  sensors:
    breakfast_nook_window_time:
    show_last_changed: True
    friendly_name: Nook Window time
    value_template: '{{ as_timestamp(states.binary_sensor.breakfast_nook_window.state) }} | {{ as_timestamp(now()) - as_timestamp(states.binary_sensor.breakfast_nook_window_last_changed) }}'

{{ as_timestamp(now()) - as_timestamp(binary_sensor.breakfast_nook_window.last_changed) }}

breakfast nook window PERIOD not underscore… if not last_changed try last_tripped_time hmm…

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