Tried a bunch of things… even tried putting it inside of a layout card to control it a bit more. Is there a way to get the button to “fill” the space of its container? I just can’t seem to get the sizes to be the same. Really open to any suggestions…
For anyone curious… was finally able to get it to work. Basically used layout card to make a grid layout. The key was setting “height: 100%” in my button-card template to force the buttons to use the space provided by the grid.
I’m trying out templates for the first time and I’m attempting to turn as much of the following into a template as possible as I have five gates and I’m constantly tweaking so a template would make life much easier.
I’ve got most of it working but I’m stuck on the two custom_fields
sections as I don’t know how to return a variable in those sections. I’ve defined the card at the bottom just in case I’ve not done that correctly either. Can anyone assist please?
color: green
color_type: icon
custom_fields:
notification: |
[[[ return states['sensor.steel_gate_battery'].state ]]]
entity: binary_sensor.steel_gate
icon: mdi:gate
name: Steel
size: 50%
state:
- color: red
icon: mdi:gate
styles:
icon:
- animation: blink 5s ease infinite
value: 'on'
- color: green
icon: mdi:gate
value: 'off'
- color: orange
icon: mdi:gate-alert
styles:
icon:
- animation: blink 3s ease infinite
value: unavailable
styles:
card:
- border-radius: 10%
- background-color: '--paper-card-background-color'
custom_fields:
notification:
- background-color: |
[[[
if (states['sensor.steel_gate_battery'].state >= 98)
return "green";
return "red";
]]]
- border-radius: 50%
- position: absolute
- left: 75%
- top: 5%
- height: 25px
- width: 25px
- font-size: 12px
- line-height: 23px
- color: var(--text-color)
grid:
- position: relative
type: custom:button-card
cards:
- template: gates
entity: binary_sensor.steel_gate
variables:
e_n_value: states.sensor.steel_gate_battery.state
type: custom:button-card
Cracked it!
button_card_templates:
gates:
color: green
color_type: icon
custom_fields:
notification: |
[[[ return (states[variables.e_n_value].state) ]]]
size: 50%
variables:
notification_entity: n_e_value
state:
- color: red
icon: mdi:gate
styles:
icon:
- animation: blink 5s ease infinite
value: 'on'
- color: green
icon: mdi:gate
value: 'off'
- color: orange
icon: mdi:gate-alert
styles:
icon:
- animation: blink 3s ease infinite
value: unavailable
styles:
card:
- border-radius: 10%
- background-color: '--paper-card-background-color'
custom_fields:
notification:
- background-color: |
[[[
if ((states[variables.e_n_value].state) >= 95)
return "green";
return "red";
]]]
- border-radius: 50%
- position: absolute
- left: 75%
- top: 5%
- height: 25px
- width: 25px
- font-size: 12px
- line-height: 23px
- color: var(--text-color)
grid:
- position: relative
cards:
- template: gates
entity: binary_sensor.steel_gate
variables:
e_n_value: sensor.steel_gate_battery
type: custom:button-card
Another random one I’m struggling with… trying to make a single button, that shows two icons… e.g. two different states at the same time… and has a single tap_action. Possible?
Check this other post I did that might be similar to what you want to do:
Actually came up with a kinda hack… Actually made my own icons…
Now I need to figure out how to change the color of different parts of the icon…
Almost fully there now…
Basically the main icon is an SVG I am drawing with JS Templating to color different paths. The button opens a popup where i have controls for the individual doors and “dual” door functions. The issue is that when I click the main icon the “multiple” actions are being triggered… e.g. the buttons in the popup are somehow being triggered even though I clicked on the main icon…
Thoughts?
- type: custom:button-card
tap_action:
action: fire-dom-event
browser_mod:
service: browser_mod.popup
data:
title: Single Garage Door
content:
type: vertical-stack
cards:
- type: custom:frigate-card
cameras:
- camera_entity: camera.garage
- type: horizontal-stack
cards:
- entity: cover.single_garage_door
name: Open
icon: "emf:garage-single-open"
type: "custom:button-card"
aspect_ratio: 2/1
tap_action:
action: call-service
service: cover.open_cover
service_data:
entity_id: "cover.single_garage_door"
- entity: cover.single_garage_door
name: Crack
icon: "emf:garage-single-cracked"
type: "custom:button-card"
aspect_ratio: 2/1
tap_action:
action: call-service
service: button.press
service_data:
entity_id: "button.single_crack"
- entity: cover.single_garage_door
name: Close
icon: "emf:garage-single-closed"
type: "custom:button-card"
aspect_ratio: 2/1
tap_action:
action: call-service
service: cover.close_cover
service_data:
entity_id: "cover.single_garage_door"
- type: horizontal-stack
cards:
- entity: cover.double_garage_door
name: Open
icon: "emf:garage-double-open"
type: "custom:button-card"
aspect_ratio: 2/1
tap_action:
action: call-service
service: cover.open_cover
service_data:
entity_id: "cover.double_garage_door"
- entity: cover.double_garage_door
name: Crack
icon: "emf:garage-double-cracked"
type: "custom:button-card"
aspect_ratio: 2/1
tap_action:
action: call-service
service: button.press
service_data:
entity_id: "button.double_crack"
- entity: cover.double_garage_door
name: Close
icon: "emf:garage-double-closed"
type: "custom:button-card"
aspect_ratio: 2/1
tap_action:
action: call-service
service: cover.close_cover
service_data:
entity_id: "cover.double_garage_door"
- type: horizontal-stack
cards:
- entity: cover.double_garage_door
name: Open
icon: "emf:garage-dual-open-open"
type: "custom:button-card"
aspect_ratio: 2/1
tap_action:
action: nothing
multi_calls: |
[[[
hass.callService(
"cover",
"open_cover",
{ entity_id: "cover.double_garage_door"}
);
hass.callService(
"cover",
"open_cover",
{ entity_id: "cover.single_garage_door"}
);
]]]
- entity: cover.double_garage_door
name: Crack & Closed
icon: "emf:garage-dual-closed-cracked"
type: "custom:button-card"
aspect_ratio: 2/1
tap_action:
action: nothing
multi_calls: |
[[[
hass.callService(
"cover",
"close_cover",
{ entity_id: "cover.double_garage_door"}
);
hass.callService(
"button",
"press",
{ entity_id: "button.single_crack"}
);
]]]
- entity: cover.double_garage_door
name: Close
icon: "emf:garage-dual-closed-closed"
type: "custom:button-card"
aspect_ratio: 2/1
tap_action:
action: nothing
multi_calls: |
[[[
hass.callService(
"cover",
"close_cover",
{ entity_id: "cover.double_garage_door"}
);
hass.callService(
"cover",
"close_cover",
{ entity_id: "cover.single_garage_door"}
);
]]]
entity:
name: Garage
show_name: true
show_icon: false
size: 80%
styles:
card:
- padding: 0.2em
- "--mdc-ripple-color": yellow
- "--mdc-ripple-press-opacity": 0.5
- height: 100%
icon:
- opacity: 0.5
# - max-height: 4.5rem #tweaking the auto-size to prevent vertical inflation of the UI on my wall tablets
name:
- font-size: 0.65em
- white-space: normal
state:
- font-size: 0.65em
- white-space: normal
label:
- font-size: 0.4em
- white-space: normal
grid:
- grid-template-areas: '"info" "n"'
- grid-template-columns: 1fr
- grid-template-rows: 1fr min-content
custom_fields:
info:
- opacity: 0.5
custom_fields:
info: >
[[[
var colorSingle = '#0000FF';
var colorDouble = '#0000FF';
if ((states['cover.single_garage_door'].state == 'open') && !(states['sensor.single_garage_door_position'].state == 'Cracked')) {
colorSingle = '#00FF00';
} else if ((states['cover.single_garage_door'].state == 'open') && (states['sensor.single_garage_door_position'].state == 'Cracked')) {
colorSingle = '#FF0000';
}
if ((states['cover.double_garage_door'].state == 'open') && !(states['sensor.double_garage_door_position'].state == 'Cracked')) {
colorDouble = '#00FF00';
} else if ((states['cover.double_garage_door'].state == 'open') && (states['sensor.double_garage_door_position'].state == 'Cracked')) {
colorDouble = '#FF0000';
}
var toReturn = '<svg viewBox="0 0 24 24" version="1.1" id="svg67">';
toReturn += `<path
style="stroke-width:0.715542;fill:var(--primary-text-color)"
d="M 7.1992188,6.5 0.80078125,9.6992188 V 18.5 H 2.0800781 V 11.300781 H 12.320312 V 18.5 h 0.0039 v 0.02539 h 1.599609 v -7.199219 h 8 v 7.199219 h 1.59961 V 9.7265625 l -5.59961,-3.2011719 -4.978516,2.8457032 z"
id="path65"
inkscape:label="garage" />
<path
style="stroke-width:0.715542;fill:${colorSingle}"
d="m 14.724609,12.125 v 1.601562 H 21.125 V 12.125 Z"
id="path238"
inkscape:label="single-open" />
<path
style="stroke-width:0.715542;fill:${colorDouble}"
d="m 2.7207031,12.099609 v 1.59961 h 8.9589849 v -1.59961 z"
id="path236"
inkscape:label="double-open" />`
if (states['cover.single_garage_door'].state == 'closed') {
toReturn += `<path
style="stroke-width:0.715542;fill:${colorSingle}"
d="m 14.724609,16.925781 v 1.59961 H 21.125 v -1.59961 z"
id="path246"
inkscape:label="single-closed" />
<path
style="stroke-width:0.715542;fill:${colorSingle}"
d="M 14.724609,14.525391 V 16.125 H 21.125 v -1.599609 z"
id="path242"
inkscape:label="single-cracked" />`;
} else if ((states['cover.single_garage_door'].state == 'open') && (states['sensor.single_garage_door_position'].state == 'Cracked')) {
toReturn += `<path
style="stroke-width:0.715542;fill:${colorSingle}"
d="M 14.724609,14.525391 V 16.125 H 21.125 v -1.599609 z"
id="path242"
inkscape:label="single-cracked" />`;
};
if (states['cover.double_garage_door'].state == 'closed') {
toReturn += `<path
style="stroke-width:0.715542;fill:${colorDouble}"
d="M 2.7207031,16.900391 V 18.5 h 8.9589849 v -1.599609 z"
id="path244"
inkscape:label="double-closed" />
<path
style="stroke-width:0.715542;fill:${colorDouble}"
d="m 2.7207031,14.5 v 1.599609 H 11.679688 V 14.5 Z"
id="path240"
inkscape:label="double-cracked" />`;
} else if ((states['cover.double_garage_door'].state == 'open') && (states['sensor.double_garage_door_position'].state == 'Cracked')) {
toReturn += `<path
style="stroke-width:0.715542;fill:${colorDouble}"
d="m 2.7207031,14.5 v 1.599609 H 11.679688 V 14.5 Z"
id="path240"
inkscape:label="double-cracked" />`;
};
return toReturn + '</svg>';
]]]
Are you looking for already working custom cards?
If yes, please vote for this feature request.
For anyone interested… built a two car garage into a single button. Made custom SVGs, with states for open/closed/cracked … as well as animated states for opening/closing … The action is a popup that has buttons to control all the states as well as a frigate card from my garage camera. It’s still a work in progress. But pretty fun and cool I think.
type: custom:button-card
tap_action:
action: fire-dom-event
browser_mod:
service: browser_mod.popup
data:
title: Single Garage Door
content:
type: vertical-stack
cards:
- type: custom:frigate-card
cameras:
- camera_entity: camera.garage
- type: horizontal-stack
cards:
- entity: cover.single_garage_door
name: Open
icon: "emf:garage-single-open"
type: "custom:button-card"
aspect_ratio: 2/1
tap_action:
action: call-service
service: cover.open_cover
service_data:
entity_id: "cover.single_garage_door"
- entity: cover.single_garage_door
name: Crack
icon: "emf:garage-single-cracked"
type: "custom:button-card"
aspect_ratio: 2/1
tap_action:
action: call-service
service: button.press
service_data:
entity_id: "button.single_crack"
- entity: cover.single_garage_door
name: Close
icon: "emf:garage-single-closed"
type: "custom:button-card"
aspect_ratio: 2/1
tap_action:
action: call-service
service: cover.close_cover
service_data:
entity_id: "cover.single_garage_door"
- type: horizontal-stack
cards:
- entity: cover.double_garage_door
name: Open
icon: "emf:garage-double-open"
type: "custom:button-card"
aspect_ratio: 2/1
tap_action:
action: call-service
service: cover.open_cover
service_data:
entity_id: "cover.double_garage_door"
- entity: cover.double_garage_door
name: Crack
icon: "emf:garage-double-cracked"
type: "custom:button-card"
aspect_ratio: 2/1
tap_action:
action: call-service
service: button.press
service_data:
entity_id: "button.double_crack"
- entity: cover.double_garage_door
name: Close
icon: "emf:garage-double-closed"
type: "custom:button-card"
aspect_ratio: 2/1
tap_action:
action: call-service
service: cover.close_cover
service_data:
entity_id: "cover.double_garage_door"
- type: horizontal-stack
cards:
- entity: cover.double_garage_door
name: Open
icon: "emf:garage-dual-open-open"
type: "custom:button-card"
aspect_ratio: 2/1
tap_action:
action: call-service
service: button.press
service_data:
entity_id: "button.open_both"
- entity: cover.double_garage_door
name: Crack & Closed
icon: "emf:garage-dual-closed-cracked"
type: "custom:button-card"
aspect_ratio: 2/1
tap_action:
action: call-service
service: button.press
service_data:
entity_id: "button.single_crack_and_close_double"
- entity: cover.double_garage_door
name: Close
icon: "emf:garage-dual-closed-closed"
type: "custom:button-card"
aspect_ratio: 2/1
tap_action:
action: call-service
service: button.press
service_data:
entity_id: "button.close_both"
entity:
name: Garage
show_name: true
show_icon: false
size: 80%
styles:
card:
- padding: 0.2em
- "--mdc-ripple-color": yellow
- "--mdc-ripple-press-opacity": 0.5
- height: 100%
icon:
- opacity: 0.5
# - max-height: 4.5rem #tweaking the auto-size to prevent vertical inflation of the UI on my wall tablets
name:
- font-size: 0.65em
- white-space: normal
state:
- font-size: 0.65em
- white-space: normal
label:
- font-size: 0.4em
- white-space: normal
grid:
- grid-template-areas: '"info" "n"'
- grid-template-columns: 1fr
- grid-template-rows: 1fr min-content
custom_fields:
info:
- opacity: 0.5
custom_fields:
info: >
[[[
var cssStyleSheet = '';
var stateColors = {
'closed': '#0000FF',
'open': '#00FF00',
'cracked': '#FF0000',
'closing': '#FFFF00',
'opening': '#FF00FF'
};
var stateSingle = "unknown";
if ((states['cover.single_garage_door'].state == 'open') && !(states['sensor.single_garage_door_position'].state == 'Cracked')) {
stateSingle = "open";
} else if ((states['cover.single_garage_door'].state == 'open') && (states['sensor.single_garage_door_position'].state == 'Cracked')) {
stateSingle = "cracked";
} else if (states['cover.single_garage_door'].state == 'opening') {
stateSingle = "opening";
} else if (states['cover.single_garage_door'].state == 'closing') {
stateSingle = "closing";
} else if (states['cover.single_garage_door'].state == 'closed') {
stateSingle = "closed";
}
var stateDouble = "unknown";
if ((states['cover.double_garage_door'].state == 'open') && !(states['sensor.double_garage_door_position'].state == 'Cracked')) {
stateDouble = "open";
} else if ((states['cover.double_garage_door'].state == 'open') && (states['sensor.double_garage_door_position'].state == 'Cracked')) {
stateDouble = "cracked";
} else if (states['cover.double_garage_door'].state == 'opening') {
stateDouble = "opening";
} else if (states['cover.double_garage_door'].state == 'closing') {
stateDouble = "closing";
} else if (states['cover.double_garage_door'].state == 'closed') {
stateDouble = "closed";
}
var svgOutline = `<path
style="stroke-width:0.715542;fill:var(--primary-text-color)"
d="M 7.1992188,6.5 0.80078125,9.6992188 V 18.5 H 2.0800781 V 11.300781 H 12.320312 V 18.5 h 0.0039 v 0.02539 h 1.599609 v -7.199219 h 8 v 7.199219 h 1.59961 V 9.7265625 l -5.59961,-3.2011719 -4.978516,2.8457032 z"
id="path65"
inkscape:label="garage" />`;
var svgSingleTop = `<path
style="stroke-width:0.715542;fill:${stateColors[stateSingle]}"
d="m 14.724609,12.125 v 1.601562 H 21.125 V 12.125 Z"
id="svgSingleTop"
inkscape:label="single-open" />`;
var svgSingleMiddle = `<path
style="stroke-width:0.715542;fill:${stateColors[stateSingle]}"
d="M 14.724609,14.525391 V 16.125 H 21.125 v -1.599609 z"
id="svgSingleMiddle"
inkscape:label="single-cracked" />`;
var svgSingleBottom = `<path
style="stroke-width:0.715542;fill:${stateColors[stateSingle]}"
d="m 14.724609,16.925781 v 1.59961 H 21.125 v -1.59961 z"
id="svgSingleBottom"
inkscape:label="single-closed" />`;
var svgDoubleTop = `<path
style="stroke-width:0.715542;fill:${stateColors[stateDouble]}"
d="m 2.7207031,12.099609 v 1.59961 h 8.9589849 v -1.59961 z"
id="svgDoubleTop"
inkscape:label="double-open" />`;
var svgDoubleMiddle = `<path
style="stroke-width:0.715542;fill:${stateColors[stateDouble]}"
d="m 2.7207031,14.5 v 1.599609 H 11.679688 V 14.5 Z"
id="svgDoubleMiddle"
inkscape:label="double-cracked" />`;
var svgDoubleBottom = `<path
style="stroke-width:0.715542;fill:${stateColors[stateDouble]}"
d="M 2.7207031,16.900391 V 18.5 h 8.9589849 v -1.599609 z"
id="svgDoubleBottom"
inkscape:label="double-closed" />`;
var toReturn = '<svg viewBox="0 0 24 24" version="1.1" id="svg67">';
toReturn += svgOutline;
if (stateSingle === 'open') {
toReturn += svgSingleTop;
} else if (stateSingle === 'cracked') {
toReturn += svgSingleTop + svgSingleMiddle;
} else if (stateSingle === 'closed') {
toReturn += svgSingleTop + svgSingleMiddle + svgSingleBottom;
} else if (stateSingle === 'closing') {
toReturn += svgSingleTop + svgSingleMiddle + svgSingleBottom;
cssStyleSheet += `<style>
@keyframes hideshow {
0% { opacity: 1; }
25% { opacity: 1; }
50% { opacity: 0; }
75% { opacity: 0; }
100% { opacity: 0; }
}
#svgSingleTop {
animation: hideshow 4s ease infinite;
}
#svgSingleMiddle {
opacity: 0;
animation: hideshow 4s 0.5s ease infinite;
}
#svgSingleBottom {
opacity: 0;
animation: hideshow 4s 1.0s ease infinite;
}
</style>`;
} else if (stateSingle === 'opening') {
toReturn += svgSingleTop + svgSingleMiddle + svgSingleBottom;
cssStyleSheet += `<style>
@keyframes hideshow {
0% { opacity: 1; }
25% { opacity: 1; }
50% { opacity: 0; }
75% { opacity: 0; }
100% { opacity: 0; }
}
#svgSingleBottom {
animation: hideshow 4s ease infinite;
}
#svgSingleMiddle {
opacity: 0;
animation: hideshow 4s 0.5s ease infinite;
}
#svgSingleTop {
opacity: 0;
animation: hideshow 4s 1.0s ease infinite;
}
</style>`;
} else {
}
if (stateDouble === 'open') {
toReturn += svgDoubleTop;
} else if (stateDouble === 'cracked') {
toReturn += svgDoubleTop + svgDoubleMiddle;
} else if (stateDouble === 'closed') {
toReturn += svgDoubleTop + svgDoubleMiddle + svgDoubleBottom;
} else if (stateDouble === 'closing') {
toReturn += svgDoubleTop + svgDoubleMiddle + svgDoubleBottom;
cssStyleSheet += `<style>
@keyframes hideshow {
0% { opacity: 1; }
25% { opacity: 1; }
50% { opacity: 0; }
75% { opacity: 0; }
100% { opacity: 0; }
}
#svgDoubleTop {
animation: hideshow 4s ease infinite;
}
#svgDoubleMiddle {
opacity: 0;
animation: hideshow 4s 0.5s ease infinite;
}
#svgDoubleBottom {
opacity: 0;
animation: hideshow 4s 1.0s ease infinite;
}
</style>`;
} else if (stateDouble === 'opening') {
toReturn += svgDoubleTop + svgDoubleMiddle + svgDoubleBottom;
cssStyleSheet += `<style>
@keyframes hideshow {
0% { opacity: 1; }
25% { opacity: 1; }
50% { opacity: 0; }
75% { opacity: 0; }
100% { opacity: 0; }
}
#svgDoubleBottom {
animation: hideshow 4s ease infinite;
}
#svgDoubleMiddle {
opacity: 0;
animation: hideshow 4s 0.5s ease infinite;
}
#svgDoubleTop {
opacity: 0;
animation: hideshow 4s 1.0s ease infinite;
}
</style>`;
} else {
}
return toReturn + cssStyleSheet + '</svg>';
]]]
Does anyone know if there is anyway to make an icon flash two different colours?
I can use the below code to make it flash on a certain state, however this is only flashing the icon on and off. But if I wanted to flash between two colours (for example flash between red and green), is there anyway to do that?
Hope that makes sense!
Thanks
state:
- value: 1
styles:
icon:
- animation: blink 5s ease infinite
Look above, there was a reference to a dual toggle a few posts up. You can do it using keyframes
Look at the post I made above. I use them to animate an SVG.
Can some one give me a hand with the active/background’s variable?
I want to differentiate the active option from the others:
In this case the activated options are 30º, as the angle, and Normal, as the Mode; but I can’t seem to find the right way to differentiate those from the others…
type: vertical-stack
cards:
- type: entity
entity: fan.fan
state_color: true
attribute: percentage
unit: '%'
- type: horizontal-stack
cards:
- show_name: true
show_icon: true
type: custom:button-card
name: 30º
tap_action:
action: call-service
service: script.fan_30
show_state: false
color_type: card
color: rgb(66, 134, 244)
icon: ''
- show_name: true
show_icon: false
color_type: card
color: rgb(66, 134, 244)
type: custom:button-card
name: 60º
tap_action:
action: call-service
service: script.fan_60
show_state: false
icon: ''
- show_name: true
show_icon: false
type: custom:button-card
name: 90º
tap_action:
action: call-service
service: script.fan_90
show_state: false
color_type: card
color: rgb(66, 134, 244)
icon: ''
- show_name: true
show_icon: false
type: custom:button-card
name: 120º
tap_action:
action: call-service
service: script.fan_120
show_state: false
color_type: card
color: rgb(66, 134, 244)
icon: ''
- type: horizontal-stack
cards:
- show_name: true
show_icon: true
type: custom:button-card
name: Normal
tap_action:
action: call-service
service: script.fan_normal
show_state: false
icon: ''
- show_name: true
show_icon: true
type: custom:button-card
name: Breeze
tap_action:
action: call-service
service: script.fan_breeze
show_state: false
icon: ''
- type: custom:button-card
show_name: true
show_icon: true
show_state: false
entity: number.lr_hvac_tadiran_set_setpoint
name: |
[[[return ‘ok’;]]]
size: 100%
color: |
[[[ return ‘red’;]]]
not showing the red color. what is wrong?
thanks
Is there a way to display the name of the linked room on the place name? In Jinja we can use area_name but I don’t know what the js template of this is.
I have a question concerning the JavaScript templates in this card.
Configuration excerpt:
tmpl_btn_roll:
variables:
preset: open # closed, shade, blinds
set_width: 7 #6.8 #"rem" will be added later
enty: null #placeholder
entity: '[[[ return variables.enty ]]]'
size: 24px
...and so on
Further down the road I want to access an attribute of the entity.
This attribute’s name is provided via the variable preset
.
If I try
styles:
grid: # div#container.vertical.no-state
- grid-template: '"i l" auto'
card: # ha-card#card.button-card-main.type-custom-button-card
- border-style: >
[[[ var v_pos = states[variables.enty].attributes.current_position;
if (v_pos == states[variables.enty].attributes.${variables.preset}) return 'dashed';
return 'solid'; ]]]
it produces an error: ButtonCardJSTemplateError: SyntaxError: Unexpected token '{' in 'var v_pos = states[variables.enty].attributes.current_position; if (v_pos == states[variables....'
How do I access an attribute which name is changing?