I am hoping someone can help me because I am tired of fighting with AI to try to figure this out. I am using custom:button-card for my entire dashboard. I am using a base template as shown below.
base:
variables:
state_on: >
[[[ return ['on', 'home', 'heat_cool', 'Running', 'Fresh', 'Charging', 'charging', 'Started', 'locked', 'Empty', 'Dirty', 'Auto'].indexOf(!entity || entity.state) !== -1; ]]]
state_home: >
[[[ return ['home'].indexOf(!entity || entity.state) !== -1; ]]]
state_zone: >
[[[ return ['Flinner', 'Kelly', 'Stantec', 'Friendship', 'TPA', 'SVS'].indexOf(!entity || entity.state) !== -1; ]]]
state_away: >
[[[ return ['not_home'].indexOf(!entity || entity.state) !== -1; ]]]
state_empty: >
[[[ return ['Empty'].indexOf(!entity || entity.state) !== -1; ]]]
state_done: >
[[[ return ['Done'].indexOf(!entity || entity.state) !== -1; ]]]
state_auto: >
[[[ return ['Auto'].indexOf(!entity || entity.state) !== -1; ]]]
state_used: >
[[[ return ['Used'].indexOf(!entity || entity.state) !== -1; ]]]
state_clean: >
[[[ return ['Clean'].indexOf(!entity || entity.state) !== -1; ]]]
state_dirty: >
[[[ return ['Dirty'].indexOf(!entity || entity.state) !== -1; ]]]
state_charging: >
[[[ return ['Charging', 'charging'].indexOf(!entity || entity.state) !== -1; ]]]
state_discharging: >
[[[ return ['Not Charging', 'not charging', 'discharging'].indexOf(!entity || entity.state) !== -1; ]]]
state_unlocked: >
[[[ return ['unlocked'].indexOf(!entity || entity.state) !== -1; ]]]
state_locked: >
[[[ return ['locked'].indexOf(!entity || entity.state) !== -1; ]]]
state: >
[[[ return !entity || entity.state; ]]]
entity_id: >
[[[ return !entity || entity.entity_id; ]]]
entity_picture: >
[[[ return !entity || entity.attributes.entity_picture; ]]]
is_youtube: >
[[[
let is_youtube = entity?.attributes?.app_id === 'com.google.ios.youtube',
sensor = this?._config?.triggers_update,
media_title = entity?.attributes?.media_title,
watching_title = states[sensor]?.attributes?.title;
if (is_youtube && media_title === watching_title) {
return true;
}
]]]
translate_home: Home
translate_not_home: Away
translate_open: Open
translate_closed: Closed
translate_occupied: Occupied
translate_not_occupied: Empty
translate_on: "On"
translate_off: "Off"
translate_detected: "Detected"
translate_clear: "Clear"
translate_playing: "Playing"
translate_paused: "Paused"
translate_NotCharging: "Discharging"
triggers_update:
- "[[[ return variables.sensor_entity; ]]]"
- "[[[ return variables.timer_entity; ]]]"
tap_action:
action: more-info
aspect_ratio: 1/1
show_state: true
show_icon: false
styles:
grid:
- grid-template-areas: |
"icon circle"
"n n"
"s s"
- grid-template-columns: repeat(2, 1fr)
- grid-template-rows: auto repeat(3, min-content)
- gap: 1.3%
- align-items: start
- will-change: transform
- position: relative
name:
- justify-self: start
- line-height: 110%
- font-size: 15px
- font-weight: bold
state:
- justify-self: start
- line-height: 110%
- font-size: 12px
card:
- background-image: >
[[[
if (variables.state_home) {
return `linear-gradient(to bottom, rgba(50,168,82,1) 0%, rgba(50,168,82,1) 50%, rgba(0,0,0,0) 50%)`;
}
if (variables.state_away) {
return 'linear-gradient(to bottom, rgba(255,0,0,1) 0%, rgba(255,0,0,1) 50%, rgba(0,0,0,0) 50%)';
}
if (variables.state_zone) {
return `linear-gradient(to bottom, rgba(49,130,183,1) 0%, rgba(49,130,183,1) 50%, rgba(0,0,0,0) 50%)`;
}
if (variables.state_empty) {
return 'linear-gradient(to bottom, rgba(50,168,82,1) 0%, rgba(50,168,82,1) 50%, rgba(0,0,0,0) 50%)';
}
if (variables.state_done) {
return 'linear-gradient(to bottom, rgba(255,0,0,1) 0%, rgba(255,0,0,1) 50%, rgba(0,0,0,0) 50%)';
}
if (variables.state_auto) {
return 'linear-gradient(to bottom, rgba(50,168,82,1) 0%, rgba(50,168,82,1) 50%, rgba(0,0,0,0) 50%)';
}
if (variables.state_used) {
return 'linear-gradient(to bottom, rgba(255,0,0,1) 0%, rgba(255,0,0,1) 50%, rgba(0,0,0,0) 50%)';
}
if (variables.state_clean) {
return 'linear-gradient(to bottom, rgba(255,0,0,1) 0%, rgba(255,0,0,1) 50%, rgba(0,0,0,0) 50%)';
}
if (variables.state_dirty) {
return 'linear-gradient(to bottom, rgba(50,168,82,1) 0%, rgba(50,168,82,1) 50%, rgba(0,0,0,0) 50%)';
}
if (variables.state_charging) {
return 'linear-gradient(to bottom, rgba(50,168,82,1) 0%, rgba(50,168,82,1) 50%, rgba(0,0,0,0) 50%)';
}
if (variables.state_discharging) {
return 'linear-gradient(to bottom, rgba(255,0,0,1) 0%, rgba(255,0,0,1) 50%, rgba(0,0,0,0) 50%)';
}
if (variables.state_unlocked) {
return 'linear-gradient(to bottom, rgba(255,0,0,1) 0%, rgba(255,0,0,1) 50%, rgba(0,0,0,0) 50%)';
}
if (variables.state_locked) {
return 'linear-gradient(to bottom, rgba(50,168,82,1) 0%, rgba(50,168,82,1) 50%, rgba(0,0,0,0) 50%)';
} else {
return 'linear-gradient(to bottom, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 50%, rgba(0,0,0,0) 50%)';
}
]]]
- overflow: hidden
- border-radius: 10px
- border-width: 0px
- -webkit-tap-highlight-color: rgba(0,0,0,0)
- transition: none
- --mdc-ripple-color: >
[[[
return variables.state_on
? 'var(--contrast1)'
: '#97989c';
]]]
- color: >
[[[
return variables.state_on
? 'var(--contrast1)'
: '#97989c';
]]]
- background-color: >
[[[
return variables.state_on
? 'var(--contrast20)'
: 'rgba(115, 115, 115, 0.25)';
]]]
custom_fields:
circle: >
[[[
const timerEntity = variables.timer_entity;
if (!timerEntity) return '';
const timerState = states[timerEntity]?.state;
return timerState === 'active' ? 'circle_cd' : 'circle_info';
]]]
There is alot here I know (I used this thread and have gone from there), but I am fighing with the circle custom_field. I have multiple timers that I want to see on the cards when they are active. I created the circle_cd template that incorporates another custom:button-card to display the countdown. I have circle_info for other information displayed on the cards. I call the two templates as necessary. The code is below.
The issue I am having is when both are included as a template. I have a template in the base file that I was hoping would choose between the two templates based on whether timer_entity is active. If I have one or the other, the templates work as expected. When I have both called out, it does not switch to circle_cd when the timer becomes active.
circle_cd:
styles:
custom_fields:
circle:
- width: 88%
- margin: -3% 2% 0 0
- justify-self: end
- opacity: 1
custom_fields:
circle:
card:
type: custom:button-card
entity: "[[[ return variables.timer_entity; ]]]"
aspect_ratio: 1/1
show_icon: false
show_name: false
show_state: true
styles:
card:
- border: none
- background: none
- background-color: none
- display: >
[[[
return states[variables.timer_entity]?.state === 'active' ? 'block' : 'none';
]]]
state:
- font-size: 14px
- font-weight: 700
- color: >
[[[
return variables.state_on
? 'var(--contrast1)'
: '#97989c';
]]]
circle_info:
styles:
card:
- --c-stroke-color-on: var(--contrast1)
- --c-stroke-color-off: none
- --c-stroke-color-state-off: "#97989c"
- --c-fill-color-on: none
- --c-fill-color-off: none
- --c-stroke-width: 2.3
- --c-font-color-on: var(--contrast1)
- --c-font-color-off: none
- --c-font-color-state-off: "#97989c"
- --c-font-size: 14px
- --c-unit-font-size: 10.5px
- --c-font-weight: 700
- --c-letter-spacing: -0.02rem
custom_fields:
circle:
- width: 88%
- margin: -3% 2% 0 0
- justify-self: end
- opacity: 1
custom_fields:
circle: >
[[[
const input = variables.circle_input;
if (input === null) {
return '';
}
let r = 22, c = r * 2 * Math.PI;
let domain = entity.entity_id.split('.')[0],
state = variables.state,
unit = variables.circle_input_unit || ' ';
const circle = (percentage, displayText, unit, isDisplay = false) => {
let strokeColor = 'var(--c-stroke-color-on)';
let fontColor = 'var(--c-font-color-on)';
if (isDisplay && !variables.state_on) {
strokeColor = 'var(--c-stroke-color-state-off)';
fontColor = 'var(--c-font-color-state-off)';
} else if (!variables.state_on && !isDisplay) {
strokeColor = 'var(--c-stroke-color-off)';
fontColor = 'var(--c-font-color-off)';
}
return `
<svg viewBox="0 0 50 50">
<style>
circle {
transform: rotate(-90deg);
transform-origin: 50% 50%;
stroke-dasharray: ${c};
stroke-dashoffset: ${c - percentage / 100 * c};
stroke-width: var(--c-stroke-width);
stroke: ${strokeColor};
fill: ${variables.state_on ? 'var(--c-fill-color-on)' : 'var(--c-fill-color-off)'};
}
text {
font-size: var(--c-font-size);
font-weight: var(--c-font-weight);
letter-spacing: var(--c-letter-spacing);
fill: ${fontColor};
}
tspan {
font-size: var(--c-unit-font-size);
}
#circle_value, tspan {
text-anchor: middle;
dominant-baseline: central;
}
</style>
<circle id="circle_stroke" cx="25" cy="25" r="${r}"/>
<text id="circle_value" x="50%" y="52%">${displayText}${unit}</text>
</svg>
`;
};
const personIcon = (path, stateOn) => {
let fillColor = stateOn ? 'var(--c-stroke-color-on)' : 'var(--c-stroke-color-state-off)';
return `
<svg viewBox="0 0 50 50">
<style>
path {
fill: ${fillColor};
transform: scale(1.0);
transform-origin: center;
}
</style>
<path d="${path}"/>
</svg>
`;
};
if (domain === 'sensor' && entity.entity_id.includes('battery')) {
const batteryLevel = parseFloat(input);
return circle(batteryLevel, batteryLevel, unit, true);
}
if (domain === 'light' && state === 'on') {
const brightness = entity.attributes.brightness;
const percentage = brightness ? Math.round((brightness / 255) * 100) : 100;
return circle(percentage, percentage, '%');
}
if (domain === 'fan') {
if (state === 'on') {
const percentage = entity.attributes.percentage;
let displayText = '';
if (percentage === 33) displayText = 'LOW';
else if (percentage === 66) displayText = 'MED';
else if (percentage === 100) displayText = 'HIGH';
else displayText = 'ON';
return circle(percentage, displayText, '');
}
}
if (domain === 'climate') {
let displayText = `${input}`;
return circle(100, displayText, unit, true);
}
if (domain === 'binary_sensor') {
let time = c => {
let s = (c / 1e3),
m = (c / 6e4),
h = (c / 36e5),
d = (c / 864e5);
return s < 60
? parseInt(s) + 's'
: m < 60 ? parseInt(m) + 'm'
: h < 24 ? parseInt(h) + 'h'
: parseInt(d) + 'd';
};
let timeValue = states[variables.retain] === undefined || states[variables.retain].state === 'unavailable'
? time(Date.now() - Date.parse(entity.last_changed))
: time(Date.now() - Date.parse(states[variables.retain].state));
return circle(100, timeValue, ' ');
}
if (domain === 'person') {
const paths = {
'home': 'M22 37.75V28.75H28V37.75H35.5V25.75H40L25 12.25 10 25.75H14.5V37.75H22Z',
'Friendship': 'M25 11.5 8.5 20.5 25 29.5 38.5 22.135V32.5H41.5V20.5M14.5 26.77V32.77L25 38.5 35.5 32.77V26.77L25 32.5 14.5 26.77Z',
'Stantec': 'M22 10.75H28A3 3 0 0 1 31 13.75V16.75H37A3 3 0 0 1 40 19.75V36.25A3 3 0 0 1 37 39.25H13C11.335 39.25 10 37.9 10 36.25V19.75C10 18.085 11.335 16.75 13 16.75H19V13.75C19 12.085 20.335 10.75 22 10.75M28 16.75V13.75H22V16.75H28Z',
'Kelly': 'M25 11.5 11.5 19.3V38.5H20.5L24.85 34 29.5 38.5H38.5V19.3L25 11.5M18.85 37V28L23.35 32.5 18.85 37M20.35 26.5H29.35L24.85 31 20.35 26.5M30.85 37 26.35 32.5 30.85 28V37M29.5 23.5H20.2V20.5H29.5V23.5Z',
'Flinner': 'M25 29.5A3 3 0 0 1 22 26.5C22 24.835 23.35 23.5 25 23.5A3 3 0 0 1 28 26.5 3 3 0 0 1 25 29.5M17.5 17.5C17.5 15.835 18.835 14.5 20.5 14.5A3 3 0 0 1 23.5 17.5 3 3 0 0 1 20.5 20.5C18.835 20.5 17.5 19.15 17.5 17.5M25 10C19.645 10 14.845 12.31 11.5 16L25 40 38.5 16C35.17 12.31 30.355 10 25 10Z',
'TPA': 'M37.855 29.29 40 27.145 37.855 25 32.5 30.355 19.645 17.5 25 12.145 22.855 10 20.71 12.145 18.565 10 15.355 13.21 13.21 11.065 11.065 13.21 13.21 15.355 10 18.565 12.145 20.71 10 22.855 12.145 25 17.5 19.645 30.355 32.5 25 37.855 27.145 40 29.29 37.855 31.435 40 34.645 36.79 36.79 38.935 38.935 36.79 36.79 34.645 40 31.435 37.855 29.29Z',
'SVS': 'M25 11.5 8.5 20.5 25 29.5 38.5 22.135V32.5H41.5V20.5M14.5 26.77V32.77L25 38.5 35.5 32.77V26.77L25 32.5 14.5 26.77Z',
'not_home': 'M42.25 27.25 36.25 33.25V28.75H22.75V25.75H36.25V21.25L42.25 27.25M12.25 37.75V25.75H7.75L22.75 12.25 33.25 21.7V22.75H29.935L22.75 16.285 15.25 23.035V34.75H30.25V31.75H33.25V37.75H12.25Z'
};
let path = paths[entity.state];
return `
<svg viewBox="0 0 50 50">
${circle(100, '', '', true)}
${personIcon(path, variables.state_on)}
</svg>
`;
}
if (variables.state_on) {
return circle(100, input, unit);
}
]]]
Any help would be greatly appreciated. Is what I am trying to do even achievable?