I’m fascinated that no one seems to mind that the countdown timer doesn’t show a remaining countdown time in state, nor even atribute, but only if it’s active or not. It’s so illogical, that I would like to meet the guy who did it. Imagine you get task to create timer and you do not think the remaining time is most relevant. I´m sorry.
You don’t want that value changing in an attribute, you’ll have a database change every second if you do. That’s why it’s done in the frontend. If you want a countdown, make a template sensor that has the value of the ending time as a state. Wherever you put it in the UI will show it’s countdown, live.
Understand what you are saying and the decision about timer was made that it has limited purpose. I would expect from timer as a click option to show remaining time because the database can handle this as nothing when you use it for minutes, once in a while and it should be up to the user to choose from, to help him and save his time. Now to the logic workaround with templates.
You wrote: If you want a countdown, make a template sensor that has the value of the ending time as a state. Wherever you put it in the UI will show it’s countdown, live.
template:
- sensor:
- name: "countdown"
state: >
{% set fin = state_attr('timer.countdown', 'finishes_at') %}
{{ '00' if fin == None else as_datetime(fin).astimezone().time() }}
Above it is, the ending time. Anywhere in card I put it I see ending time what is logical, not remaining time as you wrote. Only timer itself in only one type card of entities showing remaining time. So foreground countdown not much from it.
Working solution as you wrote above with writing to database:
template:
- sensor:
- name: "countdown2"
state: >
{% set fin = state_attr('timer.countdown', 'finishes_at') %}
{{ '00' if fin == None else (as_datetime(fin) - now()).total_seconds() | timestamp_custom('%M:%S', false) }}
Now I can send via mqtt the remaining time via sensor.countdown2 to electronic clock display.
But yes, I can save the writting to database using calculation directly in mqtt payload:
payload: "{{ (as_datetime(state_attr('timer.countdown', 'finishes_at')) - now()).total_seconds() | timestamp_custom('%M:%S', false) }}"
Plus automatisation to set duration from input to timer.
Plus automatisation to update remaining / send via mqtt.
also if anybody will find it usefull:
I can take duration from input_datatime like this:
{% set dur = strptime(states('input_datetime.minutka'), "%H:%M:%S") %}
I can create final time like this:
{% set fin = (now() + timedelta(hours = dur.hour, minutes = dur.minute)) %}
but in template sensor it would be updated as time goes, not once with manual trigger:
template:
- sensor:
- name: "finaltime"
state: >
{% set dur = strptime(states('input_datetime.minutka'), "%H:%M:%S") %}
{{ now() + timedelta(hours = dur.hour, minutes = dur.minute) }}
- sensor:
- name: "countdown"
state: >
{% set fin = states('sensor.finaltime') %}
{{ (as_datetime(fin) - now()).total_seconds() | timestamp_custom('%M:%S', false) }}
So I learned a lot again, which I will forget until next time. Again, I thought I’d use the timer helper and it would save me hours of searching, learning to write, but as every HA user knows, if you want something, carve it out.
Thank you petro for helping.
FWIW, I show the remaining time by embedding a custom:button-card inside another custom:button-card like this:
- type: 'custom:button-card'
entity: switch.office_bath_light
name: 'Bath Light'
variables:
timer_var: "timer.office_bath_light"
template:
- base_card
- timer_template
button_card_templates:
base_card:
state_color: true
show_label: true
tap_action:
action: toggle
styles:
card:
- border-radius: 6px
- height: 70px
- margin: 3px
- padding: 8px
grid:
- grid-template-areas: '"i timer" "n n"'
- grid-template-rows: 40px 1fr
- grid-template-columns: 40px 1fr
img_cell:
- align-self: start
- text-align: start
- justify-self: start
- place-self: start
- margin-right: 20px
icon:
- align-self: start
- justify-self: start
- height: 30px
- width: 30px
name:
- justify-self: center
- font-size: 13px
- margin: 0
label:
- align-self: end
- justify-self: end
- font-size: 12px
custom_fields:
timer:
- justify-self: end
- align-self: start
- font-size: 13px
timer_template:
variables:
timer_var: "placeholder"
triggers_update: all
custom_fields:
timer:
card:
type: custom:button-card
entity: '[[[ return variables.timer_var ]]]'
show_name: false
show_icon: false
show_state: true
styles:
card:
- font-size: 12px
- box-shadow: none
- background-color: "transparent"
- border: none
state:
- color: 'red'
- opacity: >
[[[
return states[variables.timer_var].state === 'idle' ? '0' : '1';
]]]
Hi @vonagio @123 @petro
I`ve made this sensor to show the remaining time based of the choosen program. If the dishwasher is powered on the sensor will display the time remaining of the program if the dishwasher is powered off the sensor will display " : -:-- "
Here is the sensor:
- platform: template
sensors:
remaining_time:
friendly_name: "Remaining Time"
value_template: >
{% if states('sensor.402110526515021364_bsh_common_option_remainingprogramtime') == 'unavailable' %} -:--
{% elif (as_timestamp(states('sensor.402110526515021364_bsh_common_option_remainingprogramtime'))) >0 %}
{% set sec = as_timestamp(states('sensor.402110526515021364_bsh_common_option_remainingprogramtime'))-as_timestamp(now()) %}
{%set hr = (sec / 3600) | int %}
{%set min = sec / 60 - hr * 60%}
{% if hr > 0 and is_state('switch.402110526515021364_bsh_common_setting_powerstate', 'on' ) %}
{{"%d:%02d" % (hr, min + 1)}}
{% elif sec | round(1, default=0) <0 %}
-:--
{%elif is_state('switch.402110526515021364_bsh_common_setting_powerstate', 'on' )%}
{{"%d:%02d" % (hr, min + 1)}}
{%else%}
-:--
{% endif %}
{% endif %}
Hope this will work also for you
Also see this
Thanks, but that still won’t update once a second. Not only that, but the code can be optimized as well.
template:
- trigger:
- platform: time_pattern
seconds: "/1"
sensor:
- name: Remaining Time
state: >
{% set entity_id = 'sensor.402110526515021364_bsh_common_option_remainingprogramtime' %}
{% if entity_id | has_value and is_state('switch.402110526515021364_bsh_common_setting_powerstate', 'on') %}
{% set td = states(entity_id) | as_datetime | as_local - now() %}
{{ "%d:%02d" % (td.seconds // 3600, td.seconds // 60 % 60) }}
{% else %}
-:--
{% endif %}
If you don’t care about the second updates…
template:
- sensor:
- name: Remaining Time
state: >
{% set entity_id = 'sensor.402110526515021364_bsh_common_option_remainingprogramtime' %}
{% if entity_id | has_value and is_state('switch.402110526515021364_bsh_common_setting_powerstate', 'on') %}
{% set td = states(entity_id) | as_datetime | as_local - now() %}
{{ "%d:%02d" % (td.seconds // 3600, td.seconds // 60 % 60) }}
{% else %}
-:--
{% endif %}
Hi Richard
I like the idea, but I can’t figure out where to define the timer_template and button_card_templates in order to use them.
Can you please elaborate on that.
BR Poul Anker
really appreciate your answer.
Thank You for posting your code. It helped me to implement my countdown sensor.
There is a typo in this line. Should be
{{ "%d:%02d" % (td.seconds // 3600, td.seconds // 60 % 60) }}
Thanks, missed that.
I tried using your code, but i doesn’t work.
The sensor just never updates for me.
If i go and have a look in the logs i see an error that the update for my sensor failed
This is the code for my sensor:
- trigger:
- trigger: time
at: '00:00'
- trigger: homeassistant
event: start
sensor:
- name: "Washer Countdown"
state: >-
{% set f = state_attr('timer.test_timer', 'finishes_at') %}
{{ 'Idle' if f == None else (as_datetime(f) - now()).total_seconds() | timestamp_custom('%H:%M:%S', false) }}
This is the code for my automation:
alias: "Washer - Update Countdown timer "
description: Update sensor.washer_countdown when timer is active
triggers:
- trigger: time_pattern
seconds: "*"
conditions:
- condition: state
entity_id: timer.test_timer
state: active
actions:
- action: homeassistant.update_entity
data:
entity_id:
- sensor.washer_countdown
mode: single
if i copy the code for the sensor in the Template area of the developer tools it does work.
Any idea what i’m doing wrong?
Main goal is to get this to work in a button in paper-buttons-row
change
seconds: /1
The trigger works as expected with that code.
When i look at the trace of the automation it looks like it worked, but the update entity action seems to fail somehow
even when i just run the Action in the developer tools it doesn’t update the entity
I don’t understand what you are trying to do, I can see the countdown of a sensor in a card markdown like this:
{% set default = "2024-04-12T00:00:00.000000Z" %}
{% set defaultresult = (( default | as_datetime - now()).total_seconds() // 60 ) %}
<font size="2">started from {{ ((((state_attr('sensor.my_sensor', 'date_start_tz') |replace ('n.d.',default) | as_datetime - now()).total_seconds() // 60 )|replace(defaultresult,'')|replace('-','')| float(0) / 1)-1 ) |replace('.0','') }} min.</font>
<font size="2">start in {{ ((((state_attr('sensor.my_sensor', 'nextdate_start_tz') |replace ('n.d.',default) | as_datetime - now()).total_seconds() // 60 )|replace(defaultresult,'')| float(0) / 1)+1 ) |replace('.0','')}} min.</font>
or
{% set f = state_attr('timer.test_timer', 'finishes_at') %}
{% if f == None %}
Idle
{% else %}
{% set time_left = (as_datetime(f) - now()).total_seconds() %}
{% set hours = (time_left // 3600) %}
{% set minutes = ((time_left % 3600) // 60) %}
{% set seconds = (time_left % 60) %}
{{ '%02d:%02d:%02d' | format(hours, minutes, seconds) }}
{% endif %}
Main goal is to show the time left of a timer entity in a button on a paper-button-rows card
in those buttons if you show the state of the timer entity it just says Idle or Active, you don’t get the countdown.
So i found the code i used in this thread. It’s just not working for me. The action just doesn’t update the sensor as you would expect
try
{{ 'Idle' if f == None else ((as_datetime(f) - now()).total_seconds() | round(0)) | timestamp_custom('%H:%M:%S', false) }}
I just did the following test and then the sensor did update:
start timer
restart home assistant
after that the sensor showed the time, which makes sense since one of the triggers for the sensor is to refresh on a restart of home assistant.
So the problem really just is this part of the automation
actions:
- action: homeassistant.update_entity
data:
entity_id:
- sensor.washer_countdown
it does not update the sensor as you would expect, it doesn’t do anything
I’m sorry I don’t understand what you are doing, you are trying to reload the data of a sensor called “washer_countdown” which I have no idea what it is.