thanks, consider it done check have entity group members trigger update · Issue #392 · custom-cards/button-card · GitHub and fiddled in this Need help selecting entities in grouped groups, in Python script - #9 by Mariusthvdb … seems related and useful to the community to have that in the toolbox per design.
I’ve given you the answer on the other thread. It solves partially your problem but will not update if an entity in the group updates until I implement your feature request.
You always have the solution to build sensors in the backend but then you’d have to build one for each group which I can understand… is painful.
I’m trying to include a lock icon (which is tied to an input_boolean) in the upperleft position of my light button card. I have a button card for each light and the entity is passed through, this works great as it supposed to. But now I want create an input_boolean for each light, that shows the state on the upper left corner (it’s just as a state, so doesn’t do any action). But I want to incorporate this in my template so I can use the exact same code in my main view and only need to add stuff to my template. Maybe with some extra variables?
This is my code btw
light:
deep_press: true
hold_action:
action: more-info
haptic: heavy
aspect_ratio: 1/1
show_icon: true
show_label: true
show_name: true
show_state: false
size: 50%
label: |
[[[
var bri = Math.round(entity.attributes.brightness / 2.55);
return (bri ? bri : '0');
]]]
state:
- styles:
card:
- background-color: var(--card-background-light)
# - transition: all 1s ease
icon:
- color: var(--light-entity-color)
# - transition: all 0.5s ease
name:
- color: var(--button-text-color)
state:
- color: var(--button-text-color)
value: 'on'
- styles:
label:
- filter: opacity(0%)
value: 'off'
styles:
card:
- background-color: var(--card-background-off)
- font-size: 12px
grid:
- grid-template-areas: '"i" "n" "s"'
- grid-template-columns: 1fr
- grid-template-rows: 1fr min-content min-content
img_cell:
- align-self: start
- text-align: start
- position: absolute
- bottom: 1px
label:
- overflow: visible
- position: absolute
- right: 13px
- top: 9px
- font-weight: bold
- color: var(--light-entity-color)
name:
- padding-bottom: 5px
- font-weight: bold
state:
- justify-self: start
- padding-left: 10px
- text-transform: lowercase
tap_action:
action: toggle
haptic: medium
I hope my question is clear and someone can point me in the right direction.
Edit: just to clarify, this has nothing to do with the lock object that button card supports. I need to tie them to input_booleans for each entity. Users can toggle the input_boolean through the frontend (with a popup card I create). This will then be used in Node-RED to allow/disable lights turning off based on motion. This works fine as is, but now I need to show the lock icon in a way that I can just use one template, instead of writing each button card individually.
HI , May i get your wallpaper , and if you can tell me Where did you get those icons , and how to create the space in between the culums.
thanks
Oh, sorry my fault! Thank you!
just for reference in this group, with guidance from @petro ,(tagged to say thank you once more!) this template was created to count the unique members and total members of a group (which can include self references to groups and entities)
- type: custom:button-card
entity: group.all_inside_lights
template: button_title_counter
group_expand: true
# triggers_update: input_boolean.run_lights_summary
label: >
[[[
function flatten(entity_id, result=[], searched=[]) {
var state = states[entity_id];
if (state) {
var entities = state.attributes.entity_id;
if (entities) {
searched.push(entity_id);
entities.forEach(entity_id => {
if (! result.includes(entity_id) && ! searched.includes(entity_id))
flatten(entity_id, result, searched);
});
}
else
result.push(entity_id);
}
}
var light_ids = [];
flatten(entity.entity_id, light_ids);
var count = 0;
light_ids.forEach(entity_id => {
var state = states[entity_id];
if (state && state.state === 'on')
count++;
});
if (count == light_ids.length) return 'All ' + light_ids.length + ' lights on';
if (count == 0) return 'No lights on';
return 'Lights on: ' + count + ' of ' + light_ids.length;
]]]
eg have a group with a double entity, or one of the sibling groups containing an already contained group/entity:
all_inside_lights:
name: All inside lights
icon: mdi:lightbulb-outline
entities:
- group.main_inside_lights
- group.guest_inside_lights
- group.living_ceiling_spots
- group.main_inside_lights # <---
HI,
here is the Code. Its a Code from @Petro:
That code uses lovelace gen, it’s also out of date. This is the current version, i’m not sure why it’s still using picture-elements, I thought I switched away from that. There must be a reason (that I can’t remember) why that wasn’t done.
type: picture-elements
image: /local/images/transparent_1to1.png
style: |
ha-card {
border-radius: 15px;
}
elements:
- type: custom:mini-graph-card
style:
top: 40%
left: 50%
width: 100%
height: 80%
translate: translate(-50%, -50%)
'--paper-card-background-color': 'rgba(0, 0, 0, 0.0)'
'--ha-card-background': "rgba(0, 0, 0, 0.0)"
'--ha-card-box-shadow': 'none'
z-index: 3
pointer-events: none
entities:
- {{ entity }}
group: true
points_per_hour: 1
hour24: true
line_color: var(--paper-item-icon-active-color)
line_width: 10
hours_to_show: 24
update_interval: 600
show:
name: false
icon: false
state: false
points: false
legend: false
average: false
extrema: false
labels: false
fill: false
labels_secondary: false
name_adaptive_color: false
icon_adaptive_color: false
- type: custom:button-card
style:
top: 50%
left: 50%
width: 100%
translate: translate(-50%, -50%)
aspect_ratio: 1/1
entity: {{ entity }}
color: var(--paper-item-icon-color)
show_name: true
show_label: true
show_icon: true
show_last_changed: true
size: 70%
tap_action:
action: more-info
haptic: light
styles:
icon:
- opacity: 0.3
- width: 100%
img_cell:
- top: 0%
- left: 30%
- position: absolute
- z-index: 2
grid:
- grid-template-areas: '"info info" "n n" "l l"'
- grid-template-columns: 40% 1fr
- grid-template-rows: 1fr min-content min-content
- position: relative
card:
- padding: 10px
- z-index: 1
name:
- justify-self: start
- align-self: end
- font-weight: bold
- font-family: Helvetica
- font-size: 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
- z-index: 5
label:
- justify-self: start
- align-self: end
- font-weight: bold
- font-family: Helvetica
- font-size: 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
- z-index: 5
custom_fields:
info:
- align-self: start
- width: 40%
- z-index: 5
custom_fields:
info: >
[[[
var entity_id = (entity === undefined) ? 'Invalid Entity' : entity.entity_id;
var statestr = (entity === undefined || entity.state === undefined) ? null : entity.state;
var units = (statestr && entity.attributes.unit_of_measurement) ? entity.attributes.unit_of_measurement : null;
var date = (statestr && entity.attributes.device_class === 'timestamp') ? new Date(statestr) : null;
var value;
if (statestr && date === null) {
if (statestr.split('.').length - 1 <= 1){
var test = parseFloat(parseFloat(statestr).toFixed(2));
value = (isNaN(test)) ? null : test;
// test if units are in the state because some sensors are stupid. Looking
// at you synology.
const expr = /[^-.0-9]+/;
var has_units = expr.test(statestr.trim());
// console.log(`${entity_id}: "${statestr}" ${matches}`);
if (value && has_units)
units = statestr.replace(/[.0-9]+/, '');
}
}
// console.log(`${entity_id}: ${statestr}, ${units}, ${date}, ${value}`);
const length = 50;
const width = 3;
var radius = length / 2;
if (date){
let now = new Date();
var tdelta = Math.floor((now - date)/1000);
// console.log(`${entity_id}: ${tdelta}`);
function plural(descriptor, divisor){
var ret = Math.floor(tdelta/divisor);
return (ret == 1) ? [ret, descriptor] : [ret, `${descriptor}s`];
}
var values;
if (tdelta < 60)
values = plural('second', 1);
else if (tdelta < 60 * 60)
values = plural('minute', 60);
else if (tdelta < 60 * 60 * 24)
values = plural('hour', 60 * 60);
else if (tdelta < 7 * 60 * 60 * 24)
values = plural('day', 60 * 60 * 24);
else
values = plural('week', 7 * 60 * 60 * 24);
return `
<svg viewBox="0 0 50 50">
<circle cx="25" cy="25" r="${radius}" fill="var(--paper-item-icon-active-color)" />
<text x="50%" y="43%" fill="var(--paper-card-background-color)" font-weight="bold" font-size="14" text-anchor="middle" alignment-baseline="middle">${values[0]}<tspan x="50%" dy="1.2em" font-size="10" font-weight="normal" >${values[1]}</tspan>
</text>
</svg>
`;
}
else if (value && units && units === '%') {
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="var(--paper-item-icon-color)" opacity="0.5" stroke-width="${width}" />
<circle style="
transform: rotate(-90deg);
transform-origin: 50% 50%;
stroke-dasharray: ${circumference};
stroke-dashoffset: ${circumference - value / 100 * 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="14" text-anchor="middle" alignment-baseline="middle">${value}<tspan font-size="10" font-weight="normal" >%</tspan>
</text>
</svg>
`;
}
else if (value && units && units.includes('°')) {
return `
<svg viewBox="0 0 50 50">
<circle cx="25" cy="25" r="${radius}" fill="var(--paper-item-icon-active-color)" />
<text x="50%" y="54%" fill="var(--paper-card-background-color)" font-weight="bold" font-size="14" text-anchor="middle" alignment-baseline="middle">${value}<tspan font-size="10" font-weight="normal" >${units}</tspan>
</text>
</svg>
`;
}
else if (value && units && units.length > 1) {
var y = (String(value).length > units.length) ? "50%" : "43%";
return `
<svg viewBox="0 0 50 50">
<circle cx="25" cy="25" r="${radius}" fill="var(--paper-item-icon-active-color)" />
<text x="50%" y="${y}" fill="var(--paper-card-background-color)" font-weight="bold" font-size="14" text-anchor="middle" alignment-baseline="middle">${value}<tspan x="50%" dy="1.2em" font-size="10" font-weight="normal" >${units}</tspan>
</text>
</svg>
`;
}
else if (value) {
return `
<svg viewBox="0 0 50 50">
<circle cx="25" cy="25" r="${radius}" fill="var(--paper-item-icon-active-color)" />
<text x="50%" y="54%" fill="var(--paper-card-background-color)" font-weight="bold" font-size="14" text-anchor="middle" alignment-baseline="middle">${value}<tspan font-size="10" font-weight="normal" >${units}</tspan>
</text>
</svg>
`;
}
return `
<svg viewBox="0 0 50 50">
<circle cx="25" cy="25" r="${radius}" fill="var(--paper-item-icon-active-color)" />
<text x="50%" y="54%" fill="var(--paper-card-background-color)" font-weight="bold" font-size="14" text-anchor="middle" alignment-baseline="middle">${statestr}
</text>
</svg>
`;
]]]
You’ll need to do the following to get it to work on your system:
Make an image that has a 1 to 1 aspect ratio. You’ll need to make sure it’s transparent. I used a 100 x 100 pixel transparent image.
replace both instances of {{ entity }} with your entity_id.
sir how do u create the template file in home assistant for :
button_card_templates:
ceiling-fan-icon-settings:
show_icon: true
show_label: false
show_name: false
styles:
card:
- height: 36px
- width: 50px
grid:
- grid-template-areas: ‘“i”’
- grid-template-columnns: auto
icon:
- height: 26px
- width: 26px
state:
- value: ‘on’
spin: true
Hi
I got three buttons with fan speed, 1 … 3
- type: horizontal-stack
cards:
- type: 'custom:button-card'
entity: switch.fan_1
color_type: card
color: rgb(66, 134, 244)
icon: mdi:numeric-1-box-outline
styles:
card:
- height: 50px
- type: 'custom:button-card'
entity: switch.fan_2
color_type: card
color: rgb(66, 134, 244)
icon: mdi:numeric-2-box-outline
styles:
card:
- height: 50px
- type: 'custom:button-card'
entity: switch.fan_3
color_type: card
color: rgb(66, 134, 244)
icon: mdi:numeric-3-box-outline
styles:
card:
- height: 50px
So if I click fan1, status be:
[fan 1 on][fan 2 off][fan 3 off],
so now if I click fan 2 button, I want rest to default to off and and fan 2 to be on.
[fan 1 off][fan 2 on][fan 3 off]
is there a way to update the status of other button?
It would be easier if you made this on the backend with template switches instead of trying to do it with the button card.
how do I update the switch status without doing a service call from a template switches , I know you can do service call, I want to just to update the status.
value_template handles a switch being on or off. Are all 3 of these switches a single fan? How are they integrated into HA?
Yep all three switches for a single fan and switches are configure as follows
- platform: broadlink
mac: abc
switches:
- name: Study room celing fan speed 1
command_on: sgDYAAkfCR4dCwkfHQs
command_off: sgDYAAkfCR4dCwkfHQs
- name: Study room celing fan speed 2
command_on: shIyAAseCh8
command_off: shIyAAseCh8LHgsfHwsKHx
- name: Study room celing fan speed 3
command_on: shAyAAseCx8LHgsfHgsLHh4LHwofCwseH
command_off: shAyAAseCx8LHgsfHgsL
And I don’t want to call the device each time I’m updating the status.
Here’s the updated version, it’s also in my github now
# lovelace_gen
{% set color = color|default('var(--paper-item-icon-active-color)') %}
{% set aspect_ratio = aspect_ratio|default('1/1') %}
type: custom:button-card
aspect_ratio: {{ aspect_ratio }}
entity: {{ entity }}
icon: {{ icon }}
color: var(--paper-item-icon-color)
show_name: true
show_label: true
show_icon: true
show_last_changed: true
size: 70%
tap_action:
action: more-info
haptic: light
styles:
icon:
- opacity: 0.3
- width: 100%
img_cell:
- top: 0%
- left: 30%
- position: absolute
- z-index: 2
grid:
- grid-template-areas: '"info info" "n n" "l l"'
- grid-template-columns: 40% 1fr
- grid-template-rows: 1fr min-content min-content
- position: relative
card:
- padding: 10px
- border-radius: 15px
- z-index: 0
name:
- justify-self: start
- align-self: end
- font-weight: bold
- font-family: Helvetica
- font-size: 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
- z-index: 5
label:
- justify-self: start
- align-self: end
- font-weight: bold
- font-family: Helvetica
- font-size: 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
- z-index: 5
custom_fields:
plot:
- position: absolute
- top: 55%
- left: 50%
- width: calc(100% + 25px)
- transform: translate(-50%, calc(-50% + 10px))
- z-index: 3
- --paper-card-background-color: 'rgba(0, 0, 0, 0.0)'
- --ha-card-background: "rgba(0, 0, 0, 0.0)"
- --ha-card-box-shadow: 'none'
- pointer-events: none
info:
- align-self: start
- width: 40%
- z-index: 5
custom_fields:
plot:
card:
type: custom:mini-graph-card
entities:
- {{ entity }}
group: true
points_per_hour: 1
hour24: true
line_color: {{ color }}
line_width: 10
hours_to_show: 24
update_interval: 600
show:
name: false
icon: false
state: false
points: false
legend: false
average: false
extrema: false
labels: false
fill: false
labels_secondary: false
name_adaptive_color: false
icon_adaptive_color: false
info: >
[[[
var entity_id = (entity === undefined) ? 'Invalid Entity' : entity.entity_id;
var statestr = (entity === undefined || entity.state === undefined) ? null : entity.state;
var units = (statestr && entity.attributes.unit_of_measurement) ? entity.attributes.unit_of_measurement : null;
var date = (statestr && entity.attributes.device_class === 'timestamp') ? new Date(statestr) : null;
var value;
if (statestr && date === null) {
if (statestr.split('.').length - 1 <= 1){
var test = parseFloat(parseFloat(statestr).toFixed(2));
value = (isNaN(test)) ? null : test;
// test if units are in the state because some sensors are stupid. Looking
// at you synology.
const expr = /[^-.0-9]+/;
var has_units = expr.test(statestr.trim());
// console.log(`${entity_id}: "${statestr}" ${matches}`);
if (value && has_units)
units = statestr.replace(/[.0-9]+/, '');
}
}
// console.log(`${entity_id}: ${statestr}, ${units}, ${date}, ${value}`);
const length = 50;
const width = 3;
var radius = length / 2;
if (date){
let now = new Date();
var tdelta = Math.floor((now - date)/1000);
// console.log(`${entity_id}: ${tdelta}`);
function plural(descriptor, divisor){
var ret = Math.floor(tdelta/divisor);
return (ret == 1) ? [ret, descriptor] : [ret, `${descriptor}s`];
}
var values;
if (tdelta < 60)
values = plural('second', 1);
else if (tdelta < 60 * 60)
values = plural('minute', 60);
else if (tdelta < 60 * 60 * 24)
values = plural('hour', 60 * 60);
else if (tdelta < 7 * 60 * 60 * 24)
values = plural('day', 60 * 60 * 24);
else
values = plural('week', 7 * 60 * 60 * 24);
return `
<svg viewBox="0 0 50 50">
<circle cx="25" cy="25" r="${radius}" fill="{{ color }}" />
<text x="50%" y="43%" fill="var(--paper-card-background-color)" font-weight="bold" font-size="14" text-anchor="middle" alignment-baseline="middle">${values[0]}<tspan x="50%" dy="1.2em" font-size="10" font-weight="normal" >${values[1]}</tspan>
</text>
</svg>
`;
}
else if (value && units && units === '%') {
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="var(--paper-item-icon-color)" opacity="0.5" stroke-width="${width}" />
<circle style="
transform: rotate(-90deg);
transform-origin: 50% 50%;
stroke-dasharray: ${circumference};
stroke-dashoffset: ${circumference - value / 100 * 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="14" text-anchor="middle" alignment-baseline="middle">${value}<tspan font-size="10" font-weight="normal" >%</tspan>
</text>
</svg>
`;
}
else if (value && units && units.includes('°')) {
return `
<svg viewBox="0 0 50 50">
<circle cx="25" cy="25" r="${radius}" fill="{{ color }}" />
<text x="50%" y="54%" fill="var(--paper-card-background-color)" font-weight="bold" font-size="14" text-anchor="middle" alignment-baseline="middle">${value}<tspan font-size="10" font-weight="normal" >${units}</tspan>
</text>
</svg>
`;
}
else if (value && units && units.length > 1) {
var y = (String(value).length > units.length) ? "50%" : "43%";
return `
<svg viewBox="0 0 50 50">
<circle cx="25" cy="25" r="${radius}" fill="{{ color }}" />
<text x="50%" y="${y}" fill="var(--paper-card-background-color)" font-weight="bold" font-size="14" text-anchor="middle" alignment-baseline="middle">${value}<tspan x="50%" dy="1.2em" font-size="10" font-weight="normal" >${units}</tspan>
</text>
</svg>
`;
}
else if (value) {
return `
<svg viewBox="0 0 50 50">
<circle cx="25" cy="25" r="${radius}" fill="{{ color }}" />
<text x="50%" y="54%" fill="var(--paper-card-background-color)" font-weight="bold" font-size="14" text-anchor="middle" alignment-baseline="middle">${value}<tspan font-size="10" font-weight="normal" >${units}</tspan>
</text>
</svg>
`;
}
return `
<svg viewBox="0 0 50 50">
<circle cx="25" cy="25" r="${radius}" fill="{{ color }}" />
<text x="50%" y="54%" fill="var(--paper-card-background-color)" font-weight="bold" font-size="14" text-anchor="middle" alignment-baseline="middle">${statestr}
</text>
</svg>
`;
]]]
Without polling the device, you’ll have to keep track of what was last pressed in the backend. This will cause your system to also get out of sync with the devices during restart of HA.
You have many options:
- Make a template fan using send_command services.
- Make template switches with send_command services, attach the value_template to an input_select that ‘stores’ the which switch was last pressed.
- Attempt to make this work with just the button card, but you’d need to query the state (which you said you didn’t want to do)
Either way, all of these are grounds for a separate post because they all require other integrations.
Quick question, I decided to use input_select and how do you update the input select from the button?
This is my input selection
input_select:
fan_speed:
name: fan speed
options:
- one
- two
- none
initial: none
button
- type: vertical-stack
title: Study room Fan
cards:
- type: horizontal-stack
cards:
- type: 'custom:button-card'
styles:
card:
- height: 50px
- width: 50px
entity: switch.study_room_celing_fan_speed_two
service:
domain: input_select
action: select_option
data:
entity_id: input_select.fan_speed
option: one
show_name: false
color_type: card
color: rgb(66, 134, 244)
state:
- value: 'off'
color: rgb(255, 0, 0)
icon: mdi:fan
somehow input select doesnt get updated
Yes, as I said before, this needs to be done OUTSIDE the button card. It has to be done with a template fan or with template switches.
EDIT: Unless you’re doing it with an automation
if that’s the case, your service is incorrectly formatted.
tap_action:
action: call-service
service: input_select.select_option
service_data:
entity_id: input_select.fan_speed
option: one
Hi at all… someone could help me to make my custombutton card blinking only when another entity is on??? ths is my code:
color_type: icon
entity: input_boolean.ad_alarm
hold_action: none
icon: 'mdi:battery-charging'
show_label: true
show_state: false
name: BATTERY
size: 20%
state:
- label: |
[[[
if (states['alert.battery'].state == 'on')
return "ALLARM";
return "ACTIVE";
]]]
styles:
icon:
- color: |
[[[
if (states['input_boolean.ad_alarm'].state == 'on')
return 'green';
return '';
]]]
label:
- color: |
[[[
if (states['alert.battery'].state == 'on')
return 'red';
return '';
]]]
- font-size: 14px
- font-weight: 600
name:
- color: '#ffffff'
- font-size: 16px
- font-weight: 600
value: 'on'
styles:
card:
- height: 120px
label:
- font-weight: bold
type: 'custom:button-card'
What I need is to make the card blinking only when alert.battery is ON
Thanks a lot
Hi Petro,
what ist new in this Version?
works without lovelace gen?
it’s not using 3 cards to make a single button. It’s no longer using the picture-elements. Also, I think I fixed a bunch of random errors in the codebase.