Not yet tested but this link may help for timers / lovelace:
This solved it perfectly for me - thanks! It updates in real time and looks good. I had to mickey around with it a bit to get it to center vertically, but it looks good.
Just in case it is useful, I just figured out how to create these templates for my timers.
In the first template, the - 20 part is the initial duration of the timer, the template would be better if I can figure out how to extract the duration and add that in automatically.
There is {{ ( (as_timestamp(now()) - as_timestamp(states.timer.d_heat_1.last_changed)) / 60 ) | round(0) - 20 }} minutes till timer one ends.
T1 was triggered {{ ( (as_timestamp(now()) - as_timestamp(states.timer.d_heat_1.last_changed)) / 60 ) | round(0) }} minutes ago.
not sure I saw the solution mentioned here yet, but for Button-card users this is what Author Romrider suggests:
needs some more work, but you get the idea.
I’m not sure what the question was now but this is my timer button. (It is based on someone else’s template who will probably recognise it but I won’t name them so they don’t get tons of questions )
The circle gets smaller with the time remaining.
yep, nice, recognize the format
the circle is a nice touch indeed
will have a look there…
hmm, can not seem to find it any more in my test file. @klogg would you mind dropping the code here please. (or dm me if you fear any followup )
this must be close, but yours is clearly developed …
Of course not
It has been hacked about a fair bit from many sources so probably has remnants that aren’t strictly necessary anymore. I’ve been meaning to clean up my templates for ages but hey, they work and there are lots more interesting things to do
also I use !include
not button card templates. (Although I am considering changing if I can be convinced the effort to change is worth it?).
# lovelace_gen
type: custom:button-card
aspect_ratio: {{ aspect_ratio | default('1/1') }}
entity: {{ entity }}
name: {{ name }}
icon: {{ icon }}
color: var(--paper-item-icon-color)
show_name: true
show_label: true
show_icon: true
show_state: true
show_last_changed: {{ last_changed | default(true) }}
size: 70%
tap_action:
action: {{ tap_action | default('none') }}
styles:
icon:
- color: >
[[[
if (entity.state == 'active')
return 'rgb(255, 165, 0)';
else return 'unset';
]]]
- opacity: 0.3
- width: 100%
img_cell:
- top: 0%
- left: 30%
- position: absolute
- z-index: 1
grid:
- grid-template-areas: '"info" "n" "s" "l"'
- grid-template-rows: 1fr min-content min-content min-content
- position: relative
card:
- padding: 10px
- border-radius: 5px
name:
- z-index: 2
- justify-self: start
- align-self: end
- font-weight: bold
- font-family: Roboto
- font-size: {{ font_size | default('12px') }}
- text-align: start
- background-image: linear-gradient(to right, white 0%, white 80%, rgba(0,0,0,0))
- -webkit-background-clip: text
- -webkit-text-fill-color: transparent
- position: relative
- display: inline-block
- width: 100%
- align-content: start
- text-align: start
- text-overflow: unset
state:
- z-index: 2
- justify-self: start
- align-self: end
- font-weight: bold
- font-family: Roboto
- font-size: {{ font_size | default('12px') }}
- text-align: start
- background-image: linear-gradient(to right, var(--paper-item-icon-color) 0%, var(--paper-item-icon-color) 80%, rgba(0,0,0,0))
- -webkit-background-clip: text
- -webkit-text-fill-color: transparent
- position: relative
- display: inline-block
- width: 100%
- align-content: start
- text-align: start
- text-overflow: unset
label:
- justify-self: start
- align-self: end
- font-weight: bold
- font-family: Roboto
- font-size: {{ font_size | default('12px') }}
- text-align: start
- background-image: linear-gradient(to right, var(--paper-item-icon-color) 0%, var(--paper-item-icon-color) 80%, rgba(0,0,0,0))
- -webkit-background-clip: text
- -webkit-text-fill-color: transparent
- position: relative
- display: inline-block
- width: 100%
- align-content: start
- text-align: start
- text-overflow: unset
custom_fields:
info:
- z-index: 0
- align-self: start
- width: 40%
custom_fields:
info: |
[[[
if (entity.state === 'active') {
var start_time = new Date();
var end_time = new Date(entity.attributes.finishes_at);
var duration = new Date('1970-01-01T0' + entity.attributes.duration + 'z');
duration = Math.floor(duration.getTime() / 1000);
var remaining_time = Math.floor((end_time.getTime() - start_time.getTime()) / 1000);
const length = 50;
const width = 3;
var radius = length / 2;
radius = (length - 3) / 2;
const circumference = radius * 2 * Math.PI;
return `
<svg viewBox="0 0 50 50">
<circle cx="25" cy="25" r="${radius}" fill="none" stroke="none" opacity="0.5" stroke-width="${width}" />
<circle style="
transform: rotate(-90deg);
transform-origin: 50% 50%;
stroke-dasharray: ${circumference};
stroke-dashoffset: ${circumference - (remaining_time / duration) * circumference};
"
id="c_brightness" cx="25" cy="25" r="${radius}" stroke="var(--paper-item-icon-active-color)" stroke-width="${width}" fill="none" stroke-linecap="round" />
<text x="50%" y="54%" fill="var(--primary-text-color)" font-weight="bold" font-size="15" text-anchor="middle" alignment-baseline="middle">${"Active"}<tspan font-size="10" font-weight="normal" ></tspan>
</text>
</svg>
`;
}
]]]
state:
- value: 'active'
icon: mdi:motion-sensor
styles:
card:
- opacity: 1.0
- box-shadow: 0px 0px 2px 1px var(--paper-item-icon-color)
- animation: wiggle 0.16s 6
name:
- color: white
- opacity: 1.0
state:
- color: gray
label:
- display: none
icon:
- transition: all 2s ease
- value: 'idle'
styles:
card:
- opacity: 0.5
name:
- color: var(--primary-text-color)
state:
- display: none
label:
- color: var(--primary-text-color)
- value: 'unavailable'
styles:
card:
- opacity: 0.2
name:
- color: var(--primary-text-color)
state:
- color: hsl(0, 100%, 50%)
label:
- color: var(--primary-text-color)
extra_styles: |
@keyframes wiggle {
0% { transform: rotate(0deg); }
33% { transform: rotate(10deg); }
66% { transform: rotate(-10deg); }
100% { transform: rotate(0deg); }
}
cool, and yp does the trick, (had to replace the lovelace_gen and add some actions and showing:)
must check circumference (not working at all…) but hey, this is a good start thanks!
followup
edited it to my settings elsewhere, and cleaned the code up a bit, but still no circular indication of the timer, all else works as expected. I guess something is wrong with the template, but I can not debug that.
could anyone with a keen eye please have a look what I missed:
custom_fields:
info: |
[[[
if (entity.state === 'active') {
var start_time = new Date();
var end_time = new Date(entity.attributes.finishes_at);
var duration = new Date('1970-01-01T0' + entity.attributes.duration + 'z');
duration = Math.floor(duration.getTime() / 1000);
var remaining_time = Math.floor((end_time.getTime() - start_time.getTime()) / 1000);
const radius = 20.5;
const circumference = radius * 2 * Math.PI;
return `
<svg viewBox="0 0 50 50">
<circle cx="25" cy="25" r="${radius}"
stroke="var(--active-color)" stroke-width=2 fill="none" stroke-linecap="round"
style="transform: rotate(-90deg);transform-origin: 50% 50%;
stroke-dasharray: ${circumference};
stroke-dashoffset: ${circumference - remaining_time / duration * circumference};"/>
<text x="50%" y="54%" fill="red" font-weight="bold" font-size="12" text-anchor="middle" alignment-baseline="middle">
${"Active"}
</text>
</svg>
`;
}
]]]
state:
- value: active
icon: mdi:timer-sand
spin: true
styles:
card:
- box-shadow: 0px 0px 2px 1px var(--paper-item-icon-color)
- animation: wiggle 0.16s 6
name:
- color: white
state:
- color: gray
label:
- display: none
icon:
- transition: all 2s ease
edit
right, so it was simple… and it suddenly showed fine using
stroke-dashoffset: ${circumference - (remaining_time/duration * circumference)}
dont / and * take precedence over - by default?
then again, changing views and getting back a minute later: full circle again. What is this?
Ciao Marius, hi all,
I return back with this question because I’m not able to do a custom button with the following requirements:
- when I push the button the action is toggle an input_boolean.scaldabagno_temporizzato
- on the corner (top right) the countdown digits of a timer.scaldabagno
(Marius, do you remember? )
Someone can help me?
I’d tried with many type of ideas without a valid result.
Whit timer as entity is easy to do, just use entity.state but whit an input_boolean concatenated with a timer is not easy (for me, of course )
Thanks
I need help! I have read everything above and everywhere else but cannot figure is what is wrong. The template says: typeError: ‘float’ object is not iterable T
The sensor study.timer_end always shows “unavailable” also when the timer.timer_study has an active state
This is the template:
sensor:
- platform: template
sensors:
study.timer_end:
friendly_name: “Time Remaning Study Timer”
device_class: timestamp
entity_id: timer.timer_study
value_template: >-
{%- set duration = state_attr(‘timer.timer_study’ , ‘duration’ ) %}
{%- if duration in [‘none’ , ‘idle’] %}
unavailable
{%- else %}
{% set h, m, s = duration.split(’:’) %}
{% set n = now().timestamp() | list | map(‘int’) %}
{{ (n + h|int * 60 * 60 + m|int * 60 + s|int) | timestamp_custom(’%Y-%m-%dT%H:%M:%S-00:00’, False) }}
{%- endif -%}
The duration of the timer.timer_study is 3:00:00 which comes from a script (below) that get’s the time from another sensor (sensor.set_time) which shows 03:00:00. So this sensor has a leading 0 which is missing in the timer.timer_study states. Not sure whether this is the cause because the timer shows the correct finishing at time 3 hours from when the script ran.
this is the script:
alias: Set Temperature
sequence:
- service: climate.set_temperature
target:
entity_id: ‘{{ states(’‘sensor.set_room’’) }}’
data:
temperature: ‘{{ states(’‘sensor.set_temperature’’) }}’ - service: timer.start
data:
duration: |
{{ states(‘sensor.set_time’) }}
target:
entity_id: timer.timer_study
mode: single
@petro, Your help would be very much appreciated as I spent days to it figure out without success
Here’s the DIY version:
Take the template code and put it in the template editor under the dev tools. Reproduce the error, and then remove lines starting at the end to find out which line gives the error.
Hint: The error your getting means: You have a decimal number and something is trying to loop over it. Look for lines that have loops.
Also, please format your code using the code button or wrap the blocks in 3 backticks.
I’m really trying to get this timer in my HA but due to lack of understanting, I don’t understant () how to get this done.
I’ve put this code in my configuration.yaml:
#Sensore Timer Riscaldamento Boost 1h
sensor:
- platform: mqtt
state_topic: "home/timers/timer.boost.riscaldamento/start"
name: "Timer Start Boost Riscaldamento"
- platform: mqtt
state_topic: "home/timers/timer.boost.riscaldamento/duration"
name: "Timer Durata Boost Riscaldamento"
- platform: template
sensors:
timer_remaining_hms_boost_riscaldamento:
friendly_name: "Timer - Remaining HMS - Boost Riscaldamento"
value_template: >-
{%- if states['sensor.timer_remaining_boost_riscaldamento'].state == 0 -%}
00:00:00
{%- else -%}
{{ states['sensor.timer_remaining_boost_riscaldamento'].state | int | timestamp_custom('%H:%M:%S', 0) }}
{%- endif -%}
entity_id:
- sensor.timer_remaining_boost_riscaldamento
What next? I assume I have to create an automation, but how based on my timer here above?
On my dashboard I have a button which toggles a script that switches on the heating in all rooms for 60 minutes. Next to the name of the button I need to show the remaining time of the task (which should be shown as HH:MM:SS).
Can you please help?
Thanks so much!!!
Petro can you please help?
I’m stuck here…
Dear all, dear @123 , dear @petro,
I likewise tried to built a sensor with the remaining time of a timer as state.
However, I couldn’t handle to do so. I tried two different version I found in the community:
Version 1:
- platform: template
sensors:
remaining_fahrradgarage:
friendly_name: "Remaining Time Fahrradgarage"
value_template: >-
{% set f = state_attr('timer.fahrradgarage', 'finishes_at') %}
{{ '00:00:00' if f == None else
(as_datetime(f) - now()).total_seconds() | timestamp_custom('%H:%M:%S', false) }}
entity_id:
- timer.fahrradgarage
Version 2:
- platform: template
sensors:
timer_end:
friendly_name: "Timer End"
device_class: timestamp
entity_id: timer.fahrradgarage # <--- Your timer (and first line of template)
value_template: >-
{%- set duration = state_attr('timer.fahrradgarage', 'duration') %}
{%- if duration in ['none', 'idle'] %}
unavailable
{%- else %}
{% set h, m, s = duration.split(':') | list | map('int') %}
{% set n = now().timestamp() %}
{{ (n + h * 60 * 60 + m * 60 + s) | timestamp_custom('%Y-%m-%dT%H:%M:%S-00:00', False) }}
{%- endif -%}
This is the output when timer.fahrradgarage is running:
Version 1:
This looks fine, but it refreshes once a minute and the amount of seconds depends on starting time (with a timer duration of 10:00 minutes first output is always 09:59, and then e.g. 08:43, 7:43, 6:43 […] depending on starting time). Issue with this is, that I would like to trigger an automation a a certain amount of minutes (e.g. 05:00) remaining.
Version 2:
This provides a timestamp and not remaining time.
For my purpose the remaining time of the timer or (even better) the passed time of a timer in minutes (without seconds) would be perfect.
Regarding my self: I’m a “try and error” copy and paste coder. Please be pleasant with me
Thank you a lot and all the best
Benedikt
For anyone coming to this thread, this is the way you’d do this in current version of HA.
template:
- trigger:
- platform: time_pattern
seconds: '/1'
sensor:
- name: Countdown
state: >
{{ state_attr('timer.test', 'finishes_at') | as_datetime - now().replace(microsecond=0) }}
availability: >
{{ state_attr('timer.test', 'finishes_at') is not none }}
or if you don’t want the countdown to go unavailable when the timer is not running…
template:
- trigger:
- platform: time_pattern
seconds: '/1'
sensor:
- name: Countdown
state: >
{% set end = state_attr('timer.test', 'finishes_at') %}
{% if end is not none %}
{{ end | as_datetime - now().replace(microsecond=0) }}
{% else %}
No Timer
{% endif %}
Lastly, you should exclude this entity from recorder, otherwise it will write an update to your database every second that the timer is running.
I appreciate the updated comment, but for the life of me I cannot figure out how to use this. I tried adding one of these code blocks to the bottom of my configuration.yaml
file and reloaded my yaml file and I cannot find the Countdown entity anywhere. Can you elaborate on how to use this template code?
thanks!
You paste it in configuration.yaml, restart, then you can find it in developer tools → states page.
thanks, that worked! for future reference, how can I know if a configuration change requires a restart or not? “Template entities” is an option in the YAML config reloading, so I thought I could just reload all the YAML and it would show up that way.
Anytime you add a new integration via yaml, you have to restart. After that, if there’s a reload button for the integration you can reload. If there’s no reload button after you restart (after adding a yaml integration), then you can’t ever use reload as that integration doesn’t support it.
okay, thanks! so now that this template integration has been added, I should be able to reload the Template Entities integration to update it?