I’m sorry but I was just doing the test, unfortunately I was away from home for work. thank you very much for the momentary resolution, I will adopt it immediately but I hope they resolve. Thanks again
Hi,
Just got back after a couple of months off, But i now see a border around all my buttons?
Any ideas on how to remove?
Read the OP.
Hi everyone,
Can you please help me?
I have an LG washing machine that reports the time remaining in the wash cycle as h:m (1:35 for example).
Does anyone have any advice on how to make this time appear in the circle (to the right of the icon) in the same format as for person how long they are at home/not_home?
Like, for example, 1h 35m until the end of the cycle, so that it shows like 2h. And under 1h until the end of the cycle (like 55m) it was displayed as 55m etc
Thank you so much
I actually just did this with my LG washer / dryer, and my cat caused me to spill coffee all over my bedding this morning so I can show you what it looks like in action. I set up a custom template so the state displays run cycle if the unit is on, and if it’s off, the state displays how long it’s been since it was last on. The circle itself runs off a percentage value remain_time / initial_time * 100
while the text inside the circle displays total minutes remaining. I use card_mod to hide the circle if it’s off.
edit: simplify template
packages/laundry.yaml
template:
- sensor:
- unique_id: washer
name: >
{{ states.sensor.washer.attributes.friendly_name }}
state: >
{%- if states.sensor.washer.state == "off" -%}
{% set time_diff = as_timestamp(now()) - as_timestamp(states.sensor.washer.last_changed) %}
{% set time_diff_minutes = time_diff/60 %}
{% set time_diff_hours = time_diff_minutes/60 %}
{% set time_diff_days = time_diff_hours/24 %}
{% if time_diff_minutes <= 59 %}
{{ time_diff_minutes | round(0) }} min{% if time_diff_minutes > 1 %}s{% endif %} ago
{% elif time_diff_minutes > 59 and time_diff_minutes < 1440 %}
{{ time_diff_hours | round(0) }} hour{% if time_diff_hours > 1 %}s{% endif %} ago
{% else %}
{{ time_diff_days | round(0) }} day{% if time_diff_days > 1 %}s{% endif %} ago
{% endif %}
{%- elif states.sensor.washer.state == "on" -%}
{{ states.sensor.washer.attributes.run_state }}
{%- endif -%}
attributes:
remain_time: >
{% set h, m, s = states.sensor.washer.attributes.remain_time.split(":") %}
{{ ((h | int * 60) + (m | int) + (s | int) / 60) | round() }}
initial_time: >
{% set h, m, s = states.sensor.washer.attributes.initial_time.split(":") %}
{{ ((h | int * 60) + (m | int) + (s | int) / 60) | round() }}
- sensor:
- unique_id: dryer
name: >
{{ states.sensor.dryer.attributes.friendly_name }}
state: >
{% if states.sensor.dryer.state == "off" %}
{% set time_diff = as_timestamp(now()) - as_timestamp(states.sensor.dryer.last_changed) %}
{% set time_diff_minutes = time_diff/60 %}
{% set time_diff_hours = time_diff_minutes/60 %}
{% set time_diff_days = time_diff_hours/24 %}
{% if time_diff_minutes <= 59 %}
{{ time_diff_minutes | round(0) }} min{% if time_diff_minutes > 1 %}s{% endif %} ago
{% elif time_diff_minutes > 59 and time_diff_minutes < 1440 %}
{{ time_diff_hours | round(0) }} hour{% if time_diff_hours > 1 %}s{% endif %} ago
{% else %}
{{ time_diff_days | round(0) }} day{% if time_diff_days > 1 %}s{% endif %} ago
{% endif %}
{% elif states.sensor.dryer.state == "on" %}
{{ states.sensor.dryer.attributes.run_state }}
{% endif %}
attributes:
remain_time: >
{% set h, m, s = states.sensor.dryer.attributes.remain_time.split(":") %}
{{ ((h | int * 60) + (m | int) + (s | int) / 60) | round() }}
initial_time: >
{% set h, m, s = states.sensor.dryer.attributes.initial_time.split(":") %}
{{ ((h | int * 60) + (m | int) + (s | int) / 60) | round() }}
my button cards are set up like this
- type: custom:button-card
entity: sensor.template_washer
tap_action:
!include popup/laundry.yaml
template:
- base
- icon_washer
- circle
variables:
state_on: >
[[[ return ['Detecting', 'Washing', 'Rinsing', 'Spinning'].indexOf(!entity || entity.state) !== -1; ]]]
circle_input: >
[[[
if (entity) {
let initial_time = entity.attributes.initial_time,
remain_time = entity.attributes.remain_time,
percent = (remain_time / initial_time) * 100,
result = Math.round(percent);
return ['Detecting', 'Washing', 'Rinsing', 'Spinning'].includes(entity.state) ? result : 'NA';
}
]]]
circle_input_unit: 'm'
circle_text: >
[[[
if (entity) {
let remain_time = entity.attributes.remain_time;
return ['Detecting', 'Washing', 'Rinsing', 'Spinning'].includes(entity.state) ? remain_time : 'NA';
}
]]]
card_mod:
style: |
#circle {
{%- if states.sensor.template_washer.attributes.remain_time == 0 -%}
display:none !important;
{% endif %}
}
- type: custom:button-card
entity: sensor.template_dryer
tap_action:
!include popup/laundry.yaml
template:
- base
- icon_dryer
- circle
variables:
state_on: >
[[[ return ['Detecting', 'Drying', 'Cooling'].indexOf(!entity || entity.state) !== -1; ]]]
circle_input: >
[[[
if (entity) {
let initial_time = entity.attributes.initial_time,
remain_time = entity.attributes.remain_time,
percent = (remain_time / initial_time) * 100,
result = Math.round(percent);
return ['Detecting', 'Drying', 'Cooling'].includes(entity.state) ? result : 'NA';
}
]]]
circle_input_unit: 'm'
circle_text: >
[[[
if (entity) {
let remain_time = entity.attributes.remain_time;
return ['Detecting', 'Drying', 'Cooling'].includes(entity.state) ? remain_time : 'NA';
}
]]]
card_mod:
style: |
#circle {
{%- if states.sensor.template_dryer.attributes.remain_time == 0 -%}
display:none !important;
{% endif %}
}
and you have to make a couple edits to button_card_templates/circle.yaml
so the text can be a different value than circle_input.
Change line 68 from
<text id="circle_value" x="50%" y="52%">${input}${tspan}${unit}</tspan></text>
to
<text id="circle_value" x="50%" y="52%">${domain === 'sensor' ? ctext : input}${tspan}${unit}</tspan></text>
and add ctext = variables.circle_text || ' ',
between line 31 and 32.
That will affect all sensors with the circle template, but there aren’t any default sensor cards that use the circle template.
and lastly, I made a couple of animated icons based on the mdi icons. I used the fan animation as inspiration.
add to icons.yaml
icon_washer:
styles:
custom_fields:
icon:
- width: 78%
- margin-left: -6%
custom_fields:
icon: >
[[[
let center = `
<path d="M31.8,23.1c3.8,3.8,3.8,9.8,0,13.6c-3.8,3.8-9.8,3.8-13.6,0L31.8,23.1"/>
<path fill="none" d="M25,15.4c-8,0-14.4,6.4-14.4,14.4S17,44.3,25,44.3s14.4-6.4,14.4-14.4S33,15.4,25,15.4z"/>
`,
base = `
<path fill="#9da0a2" d="M10.6,1.1h28.7c2.6,0,4.8,2.1,4.8,4.8v38.4c0,2.6-2.1,4.8-4.8,4.8H10.6c-2.6,0-4.8-2.1-4.8-4.8V5.8C5.8,3.2,8,1.1,10.6,1.1 M13.1,5.8c-1.4,0-2.4,1.1-2.4,2.4c0,1.4,1.1,2.4,2.4,2.4s2.4-1.1,2.4-2.4S14.3,5.8,13.1,5.8 M20.2,5.8c-1.4,0-2.4,1.1-2.4,2.4 c0,1.4,1.1,2.4,2.4,2.4c1.4,0,2.4-1.1,2.4-2.4S21.5,5.8,20.2,5.8 M25,15.4c-8,0-14.4,6.4-14.4,14.4S17,44.3,25,44.3 s14.4-6.4,14.4-14.4S33,15.4,25,15.4z"/>
`,
style = `
<svg viewBox="0 0 50 50">
<style>
@keyframes rotate {
0% {
visibility: visible;
transform: rotate(0deg) translateZ(0);
}
100% {
transform: rotate(720deg) translateZ(0);
}
}
.start {
animation: rotate 2.8s ease-in;
transform-origin: center 60%;
fill: #5daeea;
visibility: hidden;
will-change: transform;
}
.on {
animation: rotate 1.8s linear infinite;
transform-origin: center 60%;
fill: #5daeea;
animation-delay: 2.8s;
visibility: hidden;
will-change: transform;
}
.end {
animation: rotate 2.8s;
transform-origin: center 60%;
fill: #9ca2a5;
animation-timing-function: cubic-bezier(0.61, 1, 0.88, 1);
will-change: transform;
}
.start_timeout {
animation: rotate 1.8s linear infinite;
transform-origin: center 60%;
fill: #5daeea;
visibility: hidden;
will-change: transform;
}
.end_timeout {
fill: #9ca2a5;
}
</style>
`;
if (variables.state_on) {
return `${style}${base}<g class="start">${center}</g><g class="on">${center}</g></svg>`;
}
if (!variables.state_on) {
return `${style}${base}<g class="end">${center}</g></svg>`;
}
if (variables.state_on && variables.timeout > 2000) {
return `${style}${base}<g class="start_timeout">${center}</g></svg>`;
} else {
return `${style}${base}<g class="end_timeout">${center}</g></svg>`;
}
]]]
icon_dryer:
styles:
custom_fields:
icon:
- width: 78%
- margin-left: -6%
custom_fields:
icon: >
[[[
let center = `
<path d="M15.7,21.5h4.6c-0.6,3.3,0,5.2,1.4,6.7c2.6,2.5,3.8,5.8,3.1,10.1h-4.6c0.6-3.3,0-5.2-1.4-6.7 C16.2,28.9,15.1,25.7,15.7,21.5"/>
<path d="M25.3,21.5h4.6c-0.6,3.3,0,5.2,1.4,6.7c2.6,2.5,3.8,5.8,3.1,10.1h-4.6c0.6-3.3,0-5.2-1.4-6.7 C25.8,28.9,24.6,25.7,25.3,21.5z"/>
<path fill="none" d="M25,15.4c-8,0-14.4,6.4-14.4,14.4S17,44.3,25,44.3s14.4-6.4,14.4-14.4S33,15.4,25,15.4"/>
`,
base = `
<path fill="#9da0a2" d="M10.6,1.1h28.7c2.6,0,4.8,2.1,4.8,4.8v38.4c0,2.6-2.1,4.8-4.8,4.8H10.6c-2.6,0-4.8-2.1-4.8-4.8V5.8C5.8,3.2,8,1.1,10.6,1.1 M13.1,5.8c-1.4,0-2.4,1.1-2.4,2.4c0,1.4,1.1,2.4,2.4,2.4s2.4-1.1,2.4-2.4S14.3,5.8,13.1,5.8 M20.2,5.8c-1.4,0-2.4,1.1-2.4,2.4 c0,1.4,1.1,2.4,2.4,2.4c1.4,0,2.4-1.1,2.4-2.4S21.5,5.8,20.2,5.8 M25,15.4c-8,0-14.4,6.4-14.4,14.4S17,44.3,25,44.3 s14.4-6.4,14.4-14.4S33,15.4,25,15.4"/>
`,
style = `
<svg viewBox="0 0 50 50">
<style>
@keyframes rotate {
0% {
visibility: visible;
transform: rotate(0deg) translateZ(0);
}
100% {
transform: rotate(720deg) translateZ(0);
}
}
.start {
animation: rotate 2.8s ease-in;
transform-origin: center 60%;
fill: #5daeea;
visibility: hidden;
will-change: transform;
}
.on {
animation: rotate 1.8s linear infinite;
transform-origin: center 60%;
fill: #5daeea;
animation-delay: 2.8s;
visibility: hidden;
will-change: transform;
}
.end {
animation: rotate 2.8s;
transform-origin: center 60%;
fill: #9ca2a5;
animation-timing-function: cubic-bezier(0.61, 1, 0.88, 1);
will-change: transform;
}
.start_timeout {
animation: rotate 1.8s linear infinite;
transform-origin: center 60%;
fill: #5daeea;
visibility: hidden;
will-change: transform;
}
.end_timeout {
fill: #9ca2a5;
}
</style>
`;
if (variables.state_on) {
return `${style}${base}<g class="start">${center}</g><g class="on">${center}</g></svg>`;
}
if (!variables.state_on) {
return `${style}${base}<g class="end">${center}</g></svg>`;
}
if (variables.state_on && variables.timeout > 2000) {
return `${style}${base}<g class="start_timeout">${center}</g></svg>`;
} else {
return `${style}${base}<g class="end_timeout">${center}</g></svg>`;
}
]]]
I know this is a bit different than what you had asked for, but I’m sure you can find some code in here to help you accomplish what you’re after.
Thanks again for this! was just trying to figure out how to achive the same with my sauna to let the circle show the progress of heating till set temperature.
Got it figured out now based on your code!
Great thanks a lot!! Would anyone be able to help adjust the letter m and h to be in the same plane as the number of hours? They saw a smaller difference in height
That is set with the tspan
element, specifically dy="-.4"
is what is raising the text above the baseline. If you want to change it for everything, you can adjust the tspan
variable in circle.yaml
and set dy="0"
(or a larger positive value to shift it further down).
Keep in mind the font size is different for unit vs text (10.5px vs 14px) as well. You can adjust that in the styles in circle.yaml
. If the font size is the same for unit & text, then dy should be 0 to get the same baseline. If you want to keep the smaller size, you may have to set dy to a positive value to shift it further down.
If you don’t want to change it for everything, you could define an alternate tspan
variable and add a check for 'sensor'
similar to how I replaced the input
with ctext
in the #circle_value
text element.
I’m trying to accomplish a backup for plex last added but I’m unsure how to proceed. Hopefully, someone has some pointers . Simplified whenever the Main server with plex is offline I get no image and I want to bypass that somehow and ideally make it a bit obvious that the server is down.
Before:
After:
or
Current issue:
Whenever my server is offline the [sensor.plex_recently_added] returns “cannot be reached” and as such, the media card displays an empty space. (Conditional media is for Last Added although its unreachable)
What I’m trying to achieve:
1.Create a new condition where instead of the [sensor.plex_recently_added] it takes the output image (which is still present in the /www/upcoming-media-card-images/plex/Plex_Recently_Added/ NAME.jpg)
2. Display that image instead whenever the server holding plex is unreachable due to Shutdown/Sleep
3. Display a text/image or something which should point me toward the fact that the server is “off”
Or altogether don’t rely on the sensor.plex_recently_added but create “something” that only points towards the image and thus, is always available. And only use the recently added to deal with updating the image.
I do know that the sensor carries the title and other information; however I do not care if the title was missing as long as I see an image
Thanks for all your good Job !
I verry like all what you do !
Can you please share your !include popup/laundry.yaml
Thanks
Sure, you have to make some extra sensors if you want the graph. Edit you don’t need the extra sensors, you can use apex charts with attributes.
this is my popup/laundry.yaml
action: fire-dom-event
haptic: medium
browser_mod:
service: browser_mod.popup
data:
title: Laundry
card_mod:
style:
#popup header
.: |
div.content {
margin-top: -24px !important;
}
content:
type: custom:tabbed-card
styles:
--mdc-theme-primary: var(--primary-text-color)
--mdc-tab-text-label-color-default: rgba(var(--rgb-primary-text-color), 0.8)
--mdc-typography-button-font-size: 14px
tabs:
- card:
type: vertical-stack
cards:
- type: entities
card_mod:
class: content
style: |
#states {
padding-top: 1.2em;
padding-bottom: 0em;
}
entities:
- type: custom:mushroom-entity-card
entity: sensor.washer
name: Washer
icon: mdi:washing-machine
primary_info: name
secondary_info: state
card_mod:
style: |
mushroom-card {
margin: -5px -13px 0 -4px;
}
- type: attribute
entity: sensor.washer
attribute: run_state
icon: mdi:washing-machine
name: Run State
- type: attribute
entity: sensor.washer
attribute: current_course
icon: mdi:format-list-bulleted-square
name: Current Course
- type: attribute
entity: sensor.washer
attribute: spin_speed
icon: mdi:rotate-right
name: Spin Speed
- type: attribute
entity: sensor.washer
attribute: water_temp
icon: mdi:thermometer
name: Water Temp
- type: attribute
entity: sensor.washer
attribute: remain_time
icon: mdi:clock
name: Time Remaining
- type: custom:apexcharts-card
layout: minimal
locale: en
graph_span: 8h
show:
loading: false
apex_config:
plotOptions:
area:
fillTo: end
grid:
padding:
top: -15
fill:
type: gradient
gradient:
type: vertical
opacityFrom: 0.8
opacityTo: 0
stops:
- 0
- 99
- 100
stroke:
width: 4
tooltip:
style:
fontSize: 14px
x:
format: dddd HH:mm
chart:
height: 100px
offsetY: -20px
xaxis:
crosshairs:
show: false
series:
- entity: sensor.washer
attribute: remain_time
name: Time Remaining
color: '#385581'
type: area
fill_raw: last
group_by:
func: raw
duration: 1h
attributes:
label: Washer
- card:
type: vertical-stack
cards:
- type: entities
card_mod:
class: content
style: |
#states {
padding-top: 1.2em;
padding-bottom: 0em;
}
entities:
- type: custom:mushroom-entity-card
entity: sensor.dryer
name: Dryer
icon: mdi:tumble-dryer
primary_info: name
secondary_info: state
card_mod:
style: |
mushroom-card {
margin: -5px -13px 0 -4px;
}
- type: attribute
entity: sensor.dryer
attribute: run_state
icon: mdi:tumble-dryer
name: Run State
- type: attribute
entity: sensor.dryer
attribute: current_course
icon: mdi:format-list-bulleted-square
name: Current Course
- type: attribute
entity: sensor.dryer
attribute: dry_level
icon: mdi:water-off
name: Dry Level
- type: attribute
entity: sensor.dryer
attribute: temp_control
icon: mdi:thermometer
name: Temp Control
- type: attribute
entity: sensor.dryer
attribute: remain_time
icon: mdi:clock
name: Time Remaining
- type: custom:apexcharts-card
layout: minimal
locale: en
graph_span: 8h
show:
loading: false
apex_config:
plotOptions:
area:
fillTo: end
grid:
padding:
top: -15
fill:
type: gradient
gradient:
type: vertical
opacityFrom: 0.8
opacityTo: 0
stops:
- 0
- 99
- 100
stroke:
width: 4
tooltip:
style:
fontSize: 14px
x:
format: dddd HH:mm
chart:
height: 100px
offsetY: -20px
xaxis:
crosshairs:
show: false
series:
- entity: sensor.dryer
attribute: remain_time
name: Time Remaining
color: '#385581'
type: area
fill_raw: last
group_by:
func: raw
duration: 1h
attributes:
label: Dryer
I was trying the above weather widget. How i can add the left margin? seems to be off
Figured out - margin-left: 10px
When I look in my logfile I get "*
[homeassistant.helpers.template] Template variable warning: ‘None’ has no attribute ‘state’ when rendering ' {% set lights = [
what does that mean ?
Probably you have at least one wrong entity in the sidebar.yaml . Did you replace Mattias’es ones with yours?
active: >
<b>
{% set lights = [
states.light.vardagsrum_tv,
...........
states.switch.deltaco_sh_p01_socket
] %}
looking great on desktop.
Any ideas, on how to add a line break, or marquee on mobile?
what do you mean by “wrong” ? a typo ?
Well if I understand it correctly for HA - “None” is a state which means undefined. Thus you might have a sensor, but it has not been initialized to a value yet, or there is a misspelling and thus that sensor doesn’t actually exist and therefore it is “None”.
You could check this in various ways, either by checking them through Developer Tools>States for each sensor/entity which you added in your template; Or copying your template in Developer Tools>Templates and then testing that one to check which is the one which returns “None”
So if the template was like this
{% set lights = [
states.light.vardagsrum_tv
] %}
.......
It would return the None template issue because the light doesn’t actually exist as seen below.
This has been bothering me, too.
Your question was just the push I needed to try and come up with a temporary solution - and I think I got something working.
I’d much prefer if the root cause got fixed, but let’s make this a learning experience.
It’s not the most elegant, but it does the job – hopefully.
Preview
Plex Recently Added Backup
Requirements
- Helper entity
- Template sensor
- Template select (change)
- Automation
- swipe-card (change)
- conditional_media (change)
Helper (Helper entity, to store the info)
Example: input_text.backup_plex_recently_added
I created one via the GUI:
Navigate using command: Press the letter C → Type: Helpers → Press enter
Or, browse here: Settings → Devices & Services → Helpers → Create Helper → Text
OBS: Maximum length should be 255
Template sensor (To make it easier with JavaScript later)
This is unnecessary, but it makes sense to me that we have a sensor with attributes.
I tried creating an attribute with a dict similar to the ‘Recently Added’ sensor, but jinja and the formatting got weird on me, so I just did this for now:
This sensor is grabbing the state of the input_text helper, and cleans it up.
Like this
Template select
Updated the select template to handle the new sensor.
Automation (To take backup of 1 item in the ‘Recently Added’ sensor)
Not tested properly yet…
Triggers
platform: state
entity_id:
- sensor.recently_added_mix
to: Online
Conditions
condition: template
value_template: >-
{{ trigger.to_state.state not in [trigger.from_state.state, 'cannot be
reached', 'unavailable', 'undefined','unknown','none','null'] }}
Actions
service: input_text.set_value
data:
value: >-
{% if not states('sensor.recently_added_mix') in
['unavailable','undefined','unknown','none','null','0'] %}
{% set state = namespace(return='') %}
{% set data = state_attr('sensor.recently_added_mix','data') %}
{%- for value in data %}
{%- if not loop.first and value is defined and state.return == '' %}
{%- if not value.number is defined %}
{% set state.return =
"aired:" + value.aired + "|" +
"title:" + value.title + "|" +
"fanart:" + value.fanart + "|" +
"poster:" + value.poster
%}
{%- else %}
{% set state.return =
"aired:" + value.aired + "|" +
"title:" + value.title + "|" +
"number:" + value.number + "|" +
"fanart:" + value.fanart + "|" +
"poster:" + value.poster
%}
{%- endif %}
{%- endif %}
{%- endfor %}
{{ state.return }}
{% endif %}
target:
entity_id: input_text.backup_plex_recently_added
lovelace.yaml – swipe-card update
button_card_templates.yaml – conditional_media update
(state_display and background-image)
Edit: Added a change in the text color.
This is optional, of course, but I wanted another indicator that something was wrong.
conditional_media:
- color: >
[[[
if (entity.state === "Active") {
return entity === undefined
? '#97989c'
: 'rgba(239, 239, 239, 0.5)';
}
else {
return entity === undefined
? '#97989c'
: '#efefef';
}
]]]
PS: I haven’t tested it fully yet, so try at your own risk
Where do put my enitiy for the temperature on the clima tab?