Minutes into hours and minutes

As @cgtobi said, it’s a local variable and is basically just a copy of the value of sensor.charging_time_left, converted from a string to an integer. And, yes, you could just use states('sensor.charging_time_left) | int everywhere in the template, but that can make the template much less compact and harder to type and read, leading to potential mistakes. That’s generally why I would use a variable. But @cgtobi is definitely right about the value of the sensor potentially changing during the execution of the statement. After 40 years of programming, I can tell you, no matter how unlikely something is, if it’s possible it will happen. Ever hear of the term “glitch”? Well, this type of thing is exactly what’s behind most of them! :wink:

Yes, you can do that like this:

{{ (as_timestamp(now()) + ct * 60) | timestamp_local }}
1 Like

I guss it is then necassary to create a complete new template for this. Can I use the same internal variable “ct” as in the first template or must it have another name?
I would also like to integrate {% if ct == 0 %} Unavailable into the new template but when doing so it returns an error.

- platform: template
  sensors:
    minutes_to_hours:
      value_template: >
        {% set ct = states('sensor.charging_time_left') | int %}
        {% if ct == 0 %}
          Unavailable
        {% elif ct > 60 %}
          {{ ct // 60 }}:{{ '{:0>2d}'.format(ct%60) }} hours
        {% else %}
          {{ ct }} minutes
        {% endif %}

platform: template
    sensors:
      charging_finished:
        value_template: >
          {% set ct = states('sensor.charging_time_left') | int %}
          {% if ct == 0 %}
            Unavailable
          {{ (as_timestamp(now()) + ct * 60) | timestamp_custom("%H:%M") }}

The “scope” of these variables is the template they are in. So you can use the same variable name in multiple templates.

It helps if you provide the actual text of the error. But, in this case, if you haven’t left something out when copying into this post, it looks like you haven’t finished the second template. Also, right now the way you wrote it you can’t tell the difference between ‘unavailable’ and ‘0’. I would think you want something like this:

sensor:
  - platform: template
    sensors:
      minutes_to_hours:
        value_template: >
          {% set ct = states('sensor.charging_time_left') | int %}
          {% if ct == 0 %}
            Unavailable
          {% elif ct > 60 %}
            {{ ct // 60 }}:{{ '{:0>2d}'.format(ct%60) }} hours
          {% else %}
            {{ ct }} minutes
          {% endif %}

binary_sensor:
  - platform: template
      charging_finished:
        value_template: >
          {{ not is_state('sensor.charging_time_left','unavailable') and
             state('sensor.charging_time_left')|int == 0 }}

sorry, the error:

2018-07-06 21:44:04 ERROR (MainThread) [homeassistant.components] Invalid config for [sensor.template]: invalid template (TemplateSyntaxError: Unexpected end of template. Jinja was looking for the following tags: ‘elif’ or ‘else’ or ‘endif’. The innermost block that needs to be closed is ‘if’.) for dictionary value @ data[‘sensors’][‘charging_finished’][‘value_template’]. Got ‘{% set ct = states(‘sensor.charging_time_left’) | int %} {% if ct == 0 %}\n Unavailable\n{{ (as_timestamp(now()) + ct * 60) | timestamp_custom("%H:%M") }}\n’. (See ?, line ?). Please check the docs at https://home-assistant.io/components/sensor.template/

In the second template I want to show the actual time when charging is complete but when ‘sensor.charging_time_left’ is “0” it should display “unavailable” like in the first template.
What is the binary_sensor template exactly doing?

Ok, I misunderstood. From the name of the second sensor I thought you wanted it to indicate whether or not charging was finished, not when it will finish. So maybe:

sensor:
  - platform: template
    sensors:
      minutes_to_hours:
        value_template: >
          {% set ct = states('sensor.charging_time_left') | int %}
          {% if ct == 0 %}
            Unavailable
          {% elif ct > 60 %}
            {{ ct // 60 }}:{{ '{:0>2d}'.format(ct%60) }} hours
          {% else %}
            {{ ct }} minutes
          {% endif %}
      charge_finish_time:
        value_template: >
          {% if is_state('sensor.charging_time_left','unavailable') %}
            Unavailable
          {% else %}
            {% set ct = states('sensor.charging_time_left') | int %}
            {% if ct == 0 %}
              Done
            {% else %}
              {{ (as_timestamp(now()) + ct * 60) | timestamp_custom("%H:%M") }}
            {% endif %}
          {% endif %}

Here I provide separate indications of unavailable and done. If you want to show the time it finished (i.e., in the past), then you’ll need an input_datetime to record the finish time in and an automation to trigger the recording.

EDIT: Fixed typo as described below.

1 Like

It Works :slight_smile: thanks for helping

2 Likes

Is there a way to extend this template so that if the time is > 24h it will format to “1 day”, “2 days” and so on?

Would be nice for uptime sensors.

Yes.

Modify the template so that it first checks if the total number of minutes exceeds 1440 (total minutes in a day = 24 * 60). If it does, uses integer division to divide the total minutes by 1440 to get the number of days (days = total minutes // 1440). Then continue processing to get the hours and minutes.

This topic and one or two others has been extremely helpful for this newbie to calculate time remaining to charge an EV from basic input paramaters. ie enter a start and target percent, and this calculates required kWh, then current charge rate divided into the required kWh gives a time remaining (decimal hours) and then that gets added to the current time in minutes and seconds to give an end time in local time zone. Lastly when the target kWh is delivered, the wifi circuit breaker turns off terminating the charge at the specified battery level.

Losses through the chargring process and temperature can make some variances, but generatlly I am within 1-2% state of charge of the EV battery over a full charge cycle. I’ve done this because the Renault Zoe can’t terminate the charge at a given battery charge level, so this was my solution :slight_smile:

It was a journey but with the community I have been able to get it working and without needing to bother anyone for assistance. Kudos to all!

1 Like

This sensor seems to be exactly what i need but for some reason it does not work for me…

In my code i replaced ‘sensor.charging_time_left’ with my own value and changed out the ‘Unavailable’ with ‘Unkown’ and placed the whole thing in my config.

But i get the following error message when I check my configuration:

Invalid config for [sensor.template]: invalid template (TemplateSyntaxError: unexpected ')') for dictionary value @ data['sensors']['charge_finish_time']['value_template']. Got '{% if is_state(\'sensor.zoe_charging_remaining_time\',\'Unknown\') %}\n Unknown\n{% else %}\n {% set ct = states(\'sensor.zoe_charging_remaining_time\') | int %}\n {% if ct == 0 %)\n Done\n {% else %}\n {{ (as_timestamp(now()) + ct * 60) | timestamp_custom("%H:%M") }}\n {% endif %}\n{% endif %}\n'. (See ?, line ?).

I cant make much sense of it :pensive:

Hi - post your YAML and we will have a look.

Thanks Zoogara, here it is.

sensor:
  - platform: template
    sensors:
      minutes_to_hours:
        value_template: >
          {% set ct = states('sensor.zoe_charging_remaining_time') | int %}
          {% if ct == 0 %}
            Unknown
          {% elif ct > 60 %}
            {{ ct // 60 }}:{{ '{:0>2d}'.format(ct%60) }} hours
          {% else %}
            {{ ct }} minutes
          {% endif %}
      charge_finish_time:
        value_template: >
          {% if is_state('sensor.zoe_charging_remaining_time','Unknown') %}
            Unknown
          {% else %}
            {% set ct = states('sensor.zoe_charging_remaining_time') | int %}
            {% if ct == 0 %)
              Done
            {% else %}
              {{ (as_timestamp(now()) + ct * 60) | timestamp_custom("%H:%M") }}
            {% endif %}
          {% endif %}
2 Likes

                 Replace this ) with a }
                           |
                           |
                           V
            {% if ct == 0 %)
              Done
            {% else %}
2 Likes

Yep - it’s wrong in the original one as well

1 Like

That was it. It works perfectly now :grin: Thanks for your time!

This discussion is helpful. How would I convert the units of hours (which are actually hours and minutes) into hrs:min?

For example, the sensors suggested here report: “1:22 hours”

However, I would prefer: “1 hr 22 min” or “1:22 hrs:min”

Thanks

Never mind, answer is simple:
{% if ct > 60 %}{{ ct // 60 }}:{{ '{:0>2d}'.format(ct%60) }} hrs:min{% else %}{{ct}} min{% endif %}

It might be useful to know about this thread too, since this one is now covering multiple questions and there’s probably more to come: The EPIC Time Conversion and Manipulation Thread!.

I wanted a format of:

1hr 22min

The following did the trick

      workshop_ups_timeleft_in_hr_min:
        value_template: >
          {% set ct = states('sensor.ups_timeleft') | int %}
          {{ (ct | float // 60) | round(0) }}hr {{ (ct | float % 60) | round(0) }}min    
1 Like

or in a custom button card you can write this:

   label: |
      [[[
        var minutes = states['sensor.appliance_minutes_to_end'].state;
        var hours = Math.floor(minutes / 60);
        var remainingMinutes = minutes % 60;
         return 'End in: ' + hours.toString() + ':' + remainingMinutes.toString().padStart(2, '0');
      ]]]