Calcul du temps restant d'un sensor [Resolu]

Bizarre
On va revérifier si tout est bien en place a adapter selon ton attribut bien sûr

{% set end_time_str = state_attr('climate.zone_0', 'quick_veto_end_date_time') %}
{% set match = end_time_str | regex_match('(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})') %}
{% set end_time = as_timestamp(match[1] ~ '-' ~ match[2] ~ '-' ~ match[3] ~ ' ' ~ match[4] ~ ':' ~ match[5] ~ ':' ~ match[6]) %}
{% set remaining_time = end_time - now().timestamp() %}
{{ '%02d:%02d:%02d' | format((remaining_time // 3600) % 24, (remaining_time // 60) % 60, remaining_time % 60) }}

toujours NOK,
je ne pense faire d’erreur:

    - name: "quick_veto_remaining_time"
      unique_id: "Quick veto remaining time"
      state: >
        {% set end_time_str = state_attr('climate.zone_0', 'quick_veto_end_date_time') %}
        {% set match = end_time_str | regex_match('(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})') %}
        {% set end_time = as_timestamp(match[1] ~ '-' ~ match[2] ~ '-' ~ match[3] ~ ' ' ~ match[4] ~ ':' ~ match[5] ~ ':' ~ match[6]) %}
        {% set remaining_time = end_time - now().timestamp() %}
        {{ '%02d:%02d:%02d' | format((remaining_time // 3600) % 24, (remaining_time // 60) % 60, remaining_time % 60) }}

Voici un code étape par étape pour comprendre

{% set end_time_str = state_attr('climate.zone_0', 'quick_veto_end_date_time') %}

{# On extrait les différentes parties de la date/heure avec des regex #}
{% set year = end_time_str[:4] %}
{% set month = end_time_str[5:7] %}
{% set day = end_time_str[8:10] %}
{% set hour = end_time_str[11:13] %}
{% set minute = end_time_str[14:16] %}
{% set second = end_time_str[17:19] %}

{# On crée un objet datetime à partir des différentes parties #}
{% set end_time = strptime(year ~ "-" ~ month ~ "-" ~ day ~ " " ~ hour ~ ":" ~ minute ~ ":" ~ second, '%Y-%m-%d %H:%M:%S') %}

{# On calcule le temps restant en secondes #}
{% set remaining_time = (end_time - now()).total_seconds() %}

{# On convertit les secondes en heures, minutes et secondes #}
{% set hours = ((remaining_time // 3600) % 24) %}
{% set minutes = ((remaining_time // 60) % 60) %}
{% set seconds = (remaining_time % 60) %}

{# On affiche le temps restant sous la forme HH:MM:SS #}
{{ '%02d:%02d:%02d' | format(hours, minutes, seconds) }}

cette ligne bloque {% set year = end_time_str[:4] %}dans modèle

TypeError: 'datetime.datetime' object is not subscriptable

Erreur de ma part :grin:

{% set end_time_str = state_attr('climate.zone_0', 'quick_veto_end_date_time') %}
{% set end_time = strptime(end_time_str, '%Y-%m-%dT%H:%M:%S') %}
{% set now_time = now().strftime('%Y-%m-%d %H:%M:%S') %}
{% set now_datetime = strptime(now_time, '%Y-%m-%d %H:%M:%S') %}

Debugging info:
- end_time_str: {{ end_time_str }}
- end_time: {{ end_time }}
- now_time: {{ now_time }}
- now_datetime: {{ now_datetime }}

{% set remaining_time = (end_time - now_datetime).total_seconds() %}
{% set hours = ((remaining_time // 3600) % 24) %}
{% set minutes = ((remaining_time // 60) % 60) %}
{% set seconds = (remaining_time % 60) %}

{{ '%02d:%02d:%02d' | format(hours, minutes, seconds) }}

marche pas non plus.
Regarde j’ai créer le même sensor mais avec la date de départ.
j’ai mis ca dans modèle


les deux sensors fonctionnent bien.
et je fais une soustraction alors là ca bloque en me disant que c’est du texte et on est d’accord que l’on ne peux faire d’opération sur du texte…

Oui il faut absolument arriver à convertir la chaîne de caractère je te met un template debugage

sensor:
  - platform: template
    sensors:
      remaining_time:
        friendly_name: "Temps restant de la programmation"
        value_template: >
          {% set end_time_str = state_attr('climate.zone_0', 'quick_veto_end_date_time') %}
          end_time_str: {{ end_time_str }}<br>
          {% set end_time = strptime(end_time_str, '%Y-%m-%dT%H:%M:%S') %}
          end_time: {{ end_time }}<br>
          {% set now_time = as_timestamp(now()) %}
          now_time: {{ now_time }}<br>
          {% set remaining_time = (as_timestamp(end_time) - now_time) | int %}
          remaining_time: {{ remaining_time }}<br>
          {% set hours = ((remaining_time // 3600) % 24) %}
          {% set minutes = ((remaining_time // 60) % 60) %}
          {% set seconds = (remaining_time % 60) %}
          {{ '%02d:%02d:%02d' | format(hours, minutes, seconds) }}

Ce code affichera les étapes de débogage dans l’interface utilisateur Home Assistant. Tu pourras ainsi vérifier chaque étape et corriger les éventuelles erreurs.

il sort un etat unavailable c’est normal ?

pour :

{{ end_time }}
{{ now_time }}
{{ remaining_time }}

il te met invalide ? dans parametre > systeme > journaux tu as un retour sur l’erreur si oui peux tu la copier

Logger: homeassistant.helpers.template
Source: helpers/template.py:660
First occurred: 12:24:33 (8 occurrences)
Last logged: 12:24:33

Template variable error: 'str object' has no attribute 'attributes' when rendering '{% set end_time = strptime(states('climate.zone_0').attributes.quick_veto_end_date_time, "%Y-%m-%dT%H:%M:%S") %} {% set remaining_time = (end_time - now()).total_seconds() %} {% set hours = ((remaining_time // 3600) % 24) %} {% set minutes = ((remaining_time // 60) % 60) %} {% set seconds = (remaining_time % 60) %} {{ '%02d:%02d:%02d' | format(hours, minutes, seconds) }}'
Template variable error: 'str object' has no attribute 'attributes' when rendering '{% set end_time = strptime(states('climate.zone_0').attributes.quick_veto_end_date_time, "%Y-%m-%dT%H:%M:%S") %} {% set remaining_time = (end_time - now()).total_seconds() %} {% set hours = ((remaining_time // 3600) % 24) %} {% set minutes = ((remaining_time // 60) % 60) %} {% set seconds = (remaining_time % 60) %} {{ '%02d:%02d:%02d' | format(hours, minutes, seconds) if remaining_time > 0 else 'Terminé' }}'
Template variable warning: None has no element 0 when rendering '{{ state_attr('switch.sonoff_pow', 'consumption').0 }}'

Logger: homeassistant.helpers.event
Source: helpers/template.py:541
First occurred: 12:24:32 (10 occurrences)
Last logged: 12:24:33

Error while processing template: Template<template=({% set end_time = state_attr('climate.zone_0', 'quick_veto_end_date_time') | regex_replace('T', ' ') | regex_replace('\.\d+$', '') | regex_replace('^.* ', '') %} {% set remaining_minutes = ((as_timestamp(end_time) - now().timestamp()) / 60) | int %} Quick Veto ends at {{ end_time }} (in {{ remaining_minutes }} minutes)) renders=2>
Error while processing template: Template<template=({% set end_time = strptime(states('climate.zone_0').attributes.quick_veto_end_date_time, "%Y-%m-%dT%H:%M:%S") %} {% set remaining_time = (end_time - now()).total_seconds() %} {% set hours = ((remaining_time // 3600) % 24) %} {% set minutes = ((remaining_time // 60) % 60) %} {% set seconds = (remaining_time % 60) %} {{ '%02d:%02d:%02d' | format(hours, minutes, seconds) }}) renders=2>
Error while processing template: Template<template=({% if 'quick_veto_end_date_time' in state_attr('climate.zone_0', 'all') %} {% set end_time = strptime(state_attr('climate.zone_0', 'quick_veto_end_date_time'), "%Y-%m-%dT%H:%M:%S") %} {% set remaining_time = (end_time - now()).total_seconds() %} {% set hours = ((remaining_time // 3600) % 24) %} {% set minutes = ((remaining_time // 60) % 60) %} {% set seconds = (remaining_time % 60) %} {{ '%02d:%02d:%02d' | format(hours, minutes, seconds) }} {% else %} N/A {% endif %}) renders=2>
Error while processing template: Template<template=({% set end_time = strptime(states('climate.zone_0').attributes.quick_veto_end_date_time, "%Y-%m-%dT%H:%M:%S") %} {% set remaining_time = (end_time - now()).total_seconds() %} {% set hours = ((remaining_time // 3600) % 24) %} {% set minutes = ((remaining_time // 60) % 60) %} {% set seconds = (remaining_time % 60) %} {{ '%02d:%02d:%02d' | format(hours, minutes, seconds) if remaining_time > 0 else 'Terminé' }}) renders=2>
Error while processing template: Template<template=({% from 'inversion_state_binary.jinja' import invert %} {{ invert('binary_sensor.monitor_tension_puisard') }}) renders=2>
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 1809, in strptime
    return datetime.strptime(string, fmt)
TypeError: strptime() argument 1 must be str, not datetime.datetime

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 539, in async_render
    render_result = _render_with_context(self.template, compiled, **kwargs)
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 2130, in _render_with_context
    return template.render(**kwargs)
  File "/usr/local/lib/python3.10/site-packages/jinja2/environment.py", line 1301, in render
    self.environment.handle_exception()
  File "/usr/local/lib/python3.10/site-packages/jinja2/environment.py", line 936, in handle_exception
    raise rewrite_traceback_stack(source=source)
  File "<template>", line 1, in top-level template code
  File "/usr/local/lib/python3.10/site-packages/jinja2/sandbox.py", line 393, in call
    return __context.call(__obj, *args, **kwargs)
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 1812, in strptime
    raise_no_default("strptime", string)
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 1589, in raise_no_default
    raise ValueError(
ValueError: Template error: strptime got invalid input '2023-04-25 17:13:00' when rendering template '{% set end_time_str = state_attr('climate.zone_0', 'quick_veto_end_date_time') %} end_time_str: {{ end_time_str }}<br> {% set end_time = strptime(end_time_str, '%Y-%m-%dT%H:%M:%S') %} end_time: {{ end_time }}<br> {% set now_time = as_timestamp(now()) %} now_time: {{ now_time }}<br> {% set remaining_time = (as_timestamp(end_time) - now_time) | int %} remaining_time: {{ remaining_time }}<br> {% set hours = ((remaining_time // 3600) % 24) %} {% set minutes = ((remaining_time // 60) % 60) %} {% set seconds = (remaining_time % 60) %} {{ '%02d:%02d:%02d' | format(hours, minutes, seconds) }}' but no default was specified

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 660, in async_render_to_info
    render_info._result = self.async_render(variables, strict=strict, **kwargs)
  File "/usr/src/homeassistant/homeassistant/helpers/template.py", line 541, in async_render
    raise TemplateError(err) from err
homeassistant.exceptions.TemplateError: ValueError: Template error: strptime got invalid input '2023-04-25 17:13:00' when rendering template '{% set end_time_str = state_attr('climate.zone_0', 'quick_veto_end_date_time') %} end_time_str: {{ end_time_str }}<br> {% set end_time = strptime(end_time_str, '%Y-%m-%dT%H:%M:%S') %} end_time: {{ end_time }}<br> {% set now_time = as_timestamp(now()) %} now_time: {{ now_time }}<br> {% set remaining_time = (as_timestamp(end_time) - now_time) | int %} remaining_time: {{ remaining_time }}<br> {% set hours = ((remaining_time // 3600) % 24) %} {% set minutes = ((remaining_time // 60) % 60) %} {% set seconds = (remaining_time % 60) %} {{ '%02d:%02d:%02d' | format(hours, minutes, seconds) }}' but no default was specified

{% if states('climate.zone_0') != 'unavailable' %} #si le sensor n'est pas indisponible
  {% set end_time_str = state_attr('climate.zone_0', 'quick_veto_end_date_time') %}
  {% set end_time = strptime(end_time_str, '%Y-%m-%dT%H:%M:%S') %}
  {% set remaining_time = (end_time - now()).total_seconds() %}
  {% set hours = ((remaining_time // 3600) % 24) %}
  {% set minutes = ((remaining_time // 60) % 60) %}
  {% set seconds = (remaining_time % 60) %}
  {{ '%02d:%02d:%02d' | format(hours, minutes, seconds) if remaining_time > 0 else 'Terminé' }}
{% else %}
  Indisponible
{% endif %}

Je pense que tu vas pouvoir classer en résolu avec celui-ci tu as juste a remplacer les valeurs par les tiennent :stuck_out_tongue:

{% set end_time_str = state_attr('device_tracker.camsalon', 'last_time_reachable') %}
{% if end_time_str %}
  {% set remaining_time = (as_timestamp(end_time_str) - as_timestamp(now())) %}
  {% set hours = ((remaining_time // 3600) % 24) %}
  {% set minutes = ((remaining_time // 60) % 60) %}
  {% set seconds = (remaining_time % 60) %}
  {% if remaining_time > 0 %}
    Temps restant : {{ '%02d:%02d:%02d' | format(hours, minutes, seconds) }}
  {% else %}
    Terminé
  {% endif %}
{% else %}
  Indisponible
{% endif %}

SUPER !
Ça marche dans modèle mais pas encore dans le fichier template. :+1:
On me réclame pour monter une chambre ikea, alors je suis au regret de faire une pause, mais je reviens dès que possible.
Merci encore pour ton soutien et ta persévérance. :raised_hands: :raised_hands: :raised_hands:

Petit Bonus que j’ai du coup utilisé pour les notification agenda:

{% set event = as_timestamp(states.calendar.agenda_all.attributes.start_time) %}
{% set event_date = event | timestamp_custom('%d/%m/%Y') %}
{% set event_time = event | timestamp_custom('%H:%M') %}
{% set now_date = now().strftime('%d/%m/%Y') %}

{% if event_date == now_date %}
  Aujourd'hui à {{ event_time }}
{% elif event_date == (now() + timedelta(days=1)).strftime('%d/%m/%Y') %}
  Demain à {{ event_time }}
{% else %}
  {{ event_date }} à {{ event_time }}
{% endif %}

Cela affiche si c’est aujourd’hui, demain puis l’heure et les minutes

Hello

Deux infos, pour vos échnages:

  • il ne faut pas oublier la valeur par defaut de as_timestamp(XXx,default=0), il y a plein d’alerte dans les logs sinon
  • avec les macros, on se simplifie le code à mort : 2023.4 - Macros pour Temps

oui, je viens de le voir voici avec la valeurs par default :stuck_out_tongue:

{% set event = as_timestamp(states.calendar.agenda.attributes.start_time) if states.calendar.agenda.attributes.start_time else None %}
{% if event %}
  {% set event_date = event | timestamp_custom('%d/%m/%Y') %}
  {% set event_time = event | timestamp_custom('%H:%M') %}
  {% set now_date = now().strftime('%d/%m/%Y') %}
  {% if event_date == now_date %}
    Aujourd'hui à {{ event_time }}
  {% elif event_date == (now() + timedelta(days=1)).strftime('%d/%m/%Y') %}
    Demain à {{ event_time }}
  {% else %}
    Le {{ event_date }} à {{ event_time }}.
  {% endif %}
{% else %}
  Pas de date définie.
{% endif %}

1 « J'aime »

@Felix62 ça y est tout fonctionne à la perfection.
En fait j’avais des erreurs dans mon yaml template a force de tester on oublie quelques lignes.
Je tiens une fois de plus à te remercier pour ton aide, je n’y serai jamais arrivé tout seul…
Du coup j’aimerai bien comprendre ce que font les premières lignes de ton code qui nous ont sortie de l’impasse.
:wink: :+1:

Oui, je t’en pris sa m’a donné des idées :stuck_out_tongue:

Pour les explications on contrôle bien si il existe un attribut a ton sensor puis on va traduire/remanier en seconde l’affichage pour comparer avec « maintenant » now. puis va comprendre si cela équivaut a 1h ou 1m ou 1 seconde et formater l’affichage pour qu’au final on n’utilise que les infos que tu souhaites

Ok
Je m’endormirai moins bête ce soir…
@+