Hello. I am new in home assistant. When I press the button, for one second, appears a picture like unavailable image. Can anyone help me to remove this? I dont know why appears…Pleas see the video…I attached also the yaml code
Thanks
You did not.
wallpanel:
enabled: false
hide_toolbar: true
hide_sidebar: true
fullscreen: true
title: Home
resources:
- url: /local/button-card.js
type: module
button_card_templates:
loader:
custom_fields:
loader: |
<img src="/local/loader.svg" width="100%">
tap_action:
loader: |
[[[
if (entity) {
let elt = this.shadowRoot,
loader = (id, style, timeout) => {
elt.getElementById(id) && (elt.getElementById(id).style.display = style,
window.setTimeout(() => {
elt.getElementById('loader').style.display = 'none'
}, 20000))
};
loader('circle', 'none', 'initial'),
loader('loader', 'initial', 'none');
}
]]]
styles:
custom_fields:
loader:
- display: none
- top: '-6%'
- right: '-3.5%'
- width: 52%
- position: absolute
- opacity: 0.5
- pointer-events: none
- filter: |
[[[
return variables.state_on
? 'none'
: 'invert(1)';
]]]
base_updates:
show_state: true
show_name: false
show_icon: false
styles:
state:
- text-align: left
- justify-self: left
- white-space: normal
card:
- cursor: default
- padding: 0.2em 0 0 0.6em
- letter-spacing: var(--mdc-typography-body1-letter-spacing)
tap_action:
href: null
extra_styles: |
#ripple {
display: none;
}
ha-icon {
width: 1.4em;
vertical-align: 12%;
opacity: 0.5;
padding-right: 2px;
}
.title {
font-size: 1.3em;
font-weight: 500;
}
.subtitle {
font-size: 0.95em;
line-height: 0.7em;
padding-left: 3px;
padding-bottom: 10px;
font-weight: 500;
color: #828383;
}
a {
color: var(--primary-color);
}
ul {
margin-top: -0.6em;
font-size: 0.88em;
letter-spacing: 0.5px;
line-height: 1.6em;
}
code {
background-color: var(--secondary-background-color);
}
updates_hass:
template:
- base_updates
- settings
state_display: |
[[[
if (entity) {
let available = states[variables.available].attributes.home_assistant;
let links = new RegExp('<a href="([^"]+)"', "g"),
installed = entity.state,
hass_version_latest = states[variables.latest],
hass_version_latest_beta = states[variables.latest_beta],
hass_release_notes = states[variables.release_notes],
hass_release_notes_beta = states[variables.release_notes_beta];
let latest = installed.includes('b')
? hass_version_latest_beta.state
: hass_version_latest.state;
let release_notes = installed.includes('b')
? marked.parse(hass_release_notes.attributes.body)
: marked.parse(hass_release_notes_beta.attributes.body);
let subtitle = available === 0
? `${variables.translate_no_updates} <b>←</b> ${installed}`
: `${installed} <b>→</b> ${latest} ${variables.translate_available} ${String.fromCodePoint("0x1f389")}`;
let output = available === 0
? '<ul></ul>'
: release_notes.replace(links, '<a href="#" onclick="window.open(\'$1\')"');
return `
<ha-icon icon="mdi:home-assistant"></ha-icon> <span class="title">Home Assistant</span><br>
<p class="subtitle">${subtitle}</p>
${output}
`;
}
]]]
updates_hass_icon_name:
template: icon_name
icon: mdi:update
styles:
card:
- opacity: |
[[[
return entity && (entity.state === states[variables.latest].state ||
entity.state === states[variables.latest_beta].state)
? '0.3'
: '1';
]]]
- display: |
[[[
return entity
? 'flex'
: 'none';
]]]
updates:
template:
- base_updates
- settings
state_display: |
[[[
// variables
let output = '',
updates = states[variables.updates],
hacs_installed = states[variables.hacs_installed]?.attributes.repositories,
other_updates = states[variables.other_updates],
hacs_update = states['update.hacs_update']?.attributes.installed_version,
no_updates = variables.translate_no_updates,
update_available = variables.translate_update_available,
updates_available = variables.translate_updates_available;
const rename = a => {
return a.release_url && a.release_url.indexOf('github.com') > -1
? `${a.release_url.split('/')[3]}/${a.release_url.split('/')[4]}`
: a?.friendly_name;
};
// update entities
Object.keys(states).forEach(key => {
let s = states[key], e = s.entity_id, a = s.attributes;
if (e.includes('update.') && s.state === 'on') {
output += `<li><b><a href="#" onclick="window.open('${a.release_url}');">
${rename(a)}</a></b> ${a.installed_version} <b>→</b> ${a.latest_version}</li>`
}
});
// other updates
let attr = Object.fromEntries(
Object.entries(other_updates?.attributes).filter(([, value]) => value != false));
for (const [, value] of Object.entries(attr)) {
output += `<li>${value}</li>`;
}
// subtitle
let count = updates?.attributes.update_entities + updates?.attributes.other_updates,
subtitle = count === 0
? `${no_updates} <b>←</b> ${hacs_update || ''}`
: `${count} ${count === 1 ? update_available : updates_available} ${String.fromCodePoint('0x1f389')}`;
return `
<ha-icon icon="mdi:package-up"></ha-icon> <span class="title">Integrationer</span><br>
<p class="subtitle">${subtitle}</p>
<ul>${output}</ul>
`;
]]]
updates_icon_name:
template: icon_name
icon: mdi:open-in-new
styles:
card:
- opacity: |
[[[
return entity?.attributes?.update_entities === 0
? '0.3'
: '1';
]]]
hacs_iframe:
tap_action:
action: fire-dom-event
browser_mod:
service: browser_mod.popup
data:
title: ' '
size: fullscreen
content:
type: iframe
aspect_ratio: 16x9.15
url: |
[[[ return `/${hass.panels.config.url_path}/updates` ]]]
template: icon_name
hacs_navigate_ios:
tap_action:
action: fire-dom-event
browser_mod:
service: browser_mod.javascript
data:
code: |
window.location.href = `/${hass.panels.config.url_path}/updates`;
template: icon_name
sidebar:
show_state: false
show_icon: false
tap_action:
action: none
name: |
[[[
if (entity) {
let attr = [];
for (let [k, value] of Object.entries(entity.attributes))
window.navigator.userAgent.match(/iPhone/i)
? k !== 'time' && k !== 'date' && value !== false && (attr += `<p>${k === 'greet' ? `<span class="iphone">${value}</span>` : `${value}`}</p>`)
: value !== false && (attr += `<p>${value}</p>`);
return attr;
}
]]]
extra_styles: |
#card {
padding: 0;
border-width: 0;
font-family: SF Pro Display, Roboto, system-ui;
} #container {
display: flex !important;
} #name {
padding: 1vw 2.5vw 0 var(--custom-layout-card-padding);
white-space: normal;
text-align: left;
} .iphone {
font-size: 1.5em;
color: rgba(255, 255, 255, 0.8);
} .time {
font-size: var(--sidebar-time-font-size);
font-weight: 300;
line-height: var(--sidebar-time-line-height);
letter-spacing: 0.11vw;
margin-left: -0.3vw;
color: rgba(255, 255, 255, 0.8);
} @supports not (-moz-appearance:none) {
.time-colon {
position: relative;
top: -.11em;
}
} p {
font-size: var(--sidebar-font-size);
line-height: var(--sidebar-line-height);
font-weight: 200;
letter-spacing: 0.07vw;
color: #6a7377;
} b {
font-weight: 700;
} p > b {
color: rgba(255, 255, 255, 0.8);
} /* portrait */ @media screen and (max-width: 1200px) {
.time {
font-size: calc(var(--sidebar-time-font-size) * 1.4 );
line-height: calc(var(--sidebar-time-line-height) * 1.4 );
}
p {
font-size: calc(var(--sidebar-font-size) * 1.4 );
line-height: calc(var(--sidebar-line-height) * 1.4 );
}
} /* phone */ @media screen and (max-width: 800px) {
.time {
font-size: calc(var(--sidebar-time-font-size) * 2.6 );
}
p {
font-size: calc(var(--sidebar-font-size) * 2.6 );
line-height: calc(var(--sidebar-line-height) * 2.6 );
letter-spacing: 0.16vw;
}
#name {
padding: 0 0 0 1vw;
}
}
icon_name:
size: 1.4em
color: '#9da0a2'
styles:
grid:
- grid-template-areas: '"i n"'
- grid-column-gap: 0.3em
card:
- color: '#9da0a2'
- border-radius: 0.6em
- padding: 1em 1.4em 1em 1.2em
- width: max-content
- font-size: 1.06em
- font-weight: 500
- letter-spacing: 0.03em
- background: '#FFFFFF10'
icon_only:
show_name: false
color: '#9da0a2'
styles:
card:
- color: '#9da0a2'
- border-radius: 0.6em
- width: 4em
- height: 3.7em
- background: '#FFFFFF10'
person:
template:
- base
- circle
state_display: |
[[[
if (entity) {
return variables.state === 'home'
? variables.translate_home
: variables.state === 'not_home'
? variables.translate_not_home
: variables.state;
}
return variables.translate_unknown;
]]]
triggers_update: sensor.time
tap_action:
action: none
styles:
custom_fields:
icon:
- clip-path: circle()
- width: 82%
- pointer-events: none
- display: grid
custom_fields:
icon: |
[[[
return entity && variables.entity_picture
? `<img src="${variables.entity_picture}" width="100%">`
: null;
]]]
laundry:
template:
- settings
show_icon: false
show_name: false
show_state: true
state_display: |
[[[
if (entity.state === 'idle') {
return variables.translate_idle;
}
]]]
tap_action:
restart: |
[[[
hass.callService('timer', 'cancel', {
entity_id: entity.entity_id
});
hass.callService('timer', 'start', {
entity_id: entity.entity_id
});
]]]
hold_action:
cancel: |
[[[
hass.callService('timer', 'cancel', {
entity_id: entity.entity_id
});
]]]
styles:
card:
- background: '#202a2f30'
- border-radius: 0.7vw
- border: '0.2vw solid #292c2e'
state:
- font-size: 2.7vw
- font-family: SF Mono, Roboto
- opacity: 0.65
- padding: 0.55vw 1.2vw 0.5vw 1.2vw
tilt:
variables:
tilt_enable: |
[[[
// disable on macos app, text appears over popup
if (window.navigator.userAgent.includes("Home Assistant")) {
return false
}
// enable on macos browsers
else if (window.navigator.userAgent.match(/Macintosh; Intel Mac OS X/i)) {
return true;
}
// default - phones, tablets etc
return false;
]]]
tilt_options: |
[[[
let options = {
max: 5,
scale: 1.06,
glare: true,
'max-glare': 0.15,
perspective: 800,
speed: 800,
parallax: '25px'
}
if (this._config.template.includes('conditional_media')) {
options.scale = options.scale % parseInt(options.scale) / 2 + parseInt(options.scale);
options.perspective = options.perspective * 2;
return options;
}
return options;
]]]
custom_fields:
tilt: |
[[[
setTimeout(() => {
let elt = this.shadowRoot,
card = elt.getElementById('card'),
tilt = typeof VanillaTilt === 'function';
if (elt && card && tilt && variables.tilt_enable) {
VanillaTilt.init(card, variables.tilt_options);
} else {
setTimeout(() => {
if (elt && card && tilt && variables.tilt_enable) {
VanillaTilt.init(card, variables.tilt_options);
}
}, 1000);
}
}, 0);
]]]
settings:
variables:
entity_tablet: switch.galaxy_tab_a_screensaver
entity_browser_mod: media_player.tablet
translate_unknown: Unknown
translate_idle: Idle
translate_home: Home
translate_not_home: Away
translate_available: Available
translate_no_updates: No updates available
translate_update_available: Update available
translate_updates_available: Updates available
translate_on: Pornit
translate_off: Oprit
translate_cool: Cool
translate_fan_only: Fan only
translate_playing: Playing
translate_paused: Paused
translate_standby: Standby
extra_styles:
extra_styles: |
[[[
if (entity) {
if (entity.entity_id.split('.')[0] === 'light' && variables.state_on) {
// theme variable and conditions
let style = getComputedStyle(document.body),
theme_var = style.getPropertyValue('--button-card-light-color-temp'),
is_hsl = theme_var.startsWith('hsl('),
is_color_temp = entity.attributes.color_mode === 'color_temp';
if (is_hsl && is_color_temp && entity.attributes.brightness) {
// calculate lightness in hsl
let regex_pattern = /(\d+)(?!.*\d)/g,
brightness = entity.attributes.brightness / 2.54,
lightness = parseFloat(theme_var.match(regex_pattern)[0]),
min = lightness - 10,
max = lightness + 10,
calc_lightness = brightness * (max - min) / 100 + min;
var light_color = theme_var.replace(regex_pattern, calc_lightness);
}
else {
var light_color = 'var(--button-card-light-color)';
}
}
}
return `
/* * * * * * * * * * * * * * * * * *
* *
* LIGHT *
* *
* * * * * * * * * * * * * * * * * */
svg {
--light-color: ${
variables.state_on && entity.attributes.brightness
? light_color
: variables.state_on && !entity.attributes.brightness
? 'var(--state-icon-active-color);'
: 'var(--state-icon-color);' }
}
.light-color {
fill: var(--light-color);
transition: all 0.25s ease-out;
}
/* magnification */
:host {
--card-portrait: 1.4;
--card-phone: 2.271;
}
${this._config.template.includes('light') ? `
/* * * * * * * * * * * * * * * * * *
* *
* CIRCLE SLIDER *
* *
* * * * * * * * * * * * * * * * * */
#circle_slider {
opacity: 0;
appearance: none;
transform: rotate(270deg);
width: 90%;
position: absolute;
pointer-events: none;
cursor: grab;
left: 26%;
margin-top: 13%;
}
#circle_slider::-webkit-slider-thumb {
pointer-events: initial;
appearance: none;
width: 3vw;
height: 3vw;
border-radius: 50%;
background: green;
}
#circle_slider::-webkit-slider-runnable-track {
background: cornflowerblue;
}
#circle_slider::-moz-range-thumb {
pointer-events: initial;
appearance: none;
width: 3vw;
height: 3vw;
border-radius: 50%;
background: green;
}
#circle_slider::-moz-range-track {
background: cornflowerblue;
height: 3vw;
}
/* portrait */
@media screen and (max-width: 1200px) {
#circle_slider::-webkit-slider-thumb {
width: 4vw;
height: 4vw;
}
#circle_slider::-moz-range-thumb {
width: 4vw;
height: 4vw;
}
}
/* phone */
@media screen and (max-width: 800px) {
#circle_slider::-webkit-slider-thumb {
width: 5.8vw;
height: 5.8vw;
}
#circle_slider::-moz-range-thumb {
width: 5.8vw;
height: 5.8vw;
}
}
`:''}
/* * * * * * * * * * * * * * * * * *
* *
* BASE *
* *
* * * * * * * * * * * * * * * * * */
#container {
text-align: left !important;
z-index: 1;
}
#card {
padding: 10.9% 9.9% 8.9% 10.9%;
}
#state::first-letter {
text-transform: uppercase;
}
#name, #state {
font-size: var(--button-card-font-size);
font-weight: var(--button-card-font-weight);
letter-spacing: var(--button-card-letter-spacing);
}
/* portrait */
@media screen and (max-width: 1200px) {
#name, #state {
font-size: calc(var(--button-card-font-size) * var(--card-portrait));
}
}
/* phone */
@media screen and (max-width: 800px) {
#name, #state {
font-size: calc(var(--button-card-font-size) * var(--card-phone));
}
}
${variables.tilt_enable === true ? `
/* * * * * * * * * * * * * * * * * *
* *
* TILT *
* *
* * * * * * * * * * * * * * * * * */
#name, #state {
font-size: calc(var(--button-card-font-size) - var(--z-axis-adjustment));
}
/* portrait */
@media screen and (max-width: 1200px) {
#name, #state {
font-size: calc(calc(var(--button-card-font-size) * var(--card-portrait)) - var(--z-axis-adjustment));
}
}
/* phone */
@media screen and (max-width: 800px) {
#name, #state {
font-size: calc(calc(var(--button-card-font-size) * var(--card-phone)) - var(--z-axis-adjustment));
}
}
#container {
transform: translateZ(${variables.tilt_options.parallax});
}
#circle_slider {
width: 100%;
margin-top: 0;
}
/* adjust circle_slider position for firefox */
@supports (-moz-appearance:none) {
#circle_slider {
margin-top: 13%;
}
}
#card {
padding: 12% 11% 10.5% 12%;
transform-style: preserve-3d;
overflow: visible;
/* firefox pixelated edges */
outline: 1px solid transparent;
}
#ripple, .js-tilt-glare {
clip-path: inset(0 round var(--button-card-border-radius));
overflow: hidden;
}
.js-tilt-glare {
z-index: 1;
}
.js-tilt-glare-inner {
background-color: rgba(0,0,0,0.9);
}
`:''}
${this._config.template.includes('conditional_media') ? `
/* * * * * * * * * * * * * * * * * *
* *
* MEDIA *
* *
* * * * * * * * * * * * * * * * * */
:host {
--blur-intensity: blur(4.5px) brightness(0.8);
}
/* phone */
@media screen and (max-width: 800px) {
:host {
--blur-intensity: blur(2.5px) brightness(0.8);
}
}
#ripple, .js-tilt-glare {
clip-path: inset(0 round calc(var(--button-card-border-radius) / 2));
}
#container {
overflow: hidden;
}
.marquee {
animation: marquee 20s linear infinite;
}
@keyframes marquee {
from {
transform: translateX(0%);
}
to {
transform: translateX(-50%);
}
}
`:''}
${this._config.template.includes('footer') ? `
/* * * * * * * * * * * * * * * * * *
* *
* FOOTER *
* *
* * * * * * * * * * * * * * * * * */
/* magnification */
:host {
--footer-portrait: 1.4;
--footer-phone: 2.8;
}
#ripple, .js-tilt-glare {
border-radius: calc(var(--footer-card-border-radius) - 0.1vw);
clip-path: inset(0 round calc( var(--button-card-border-radius) - 0.1vw ));
}
#name {
font-size: var(--footer-card-font-size);
padding: var(--footer-card-padding-v) var(--footer-card-padding-h);
letter-spacing: 0.05vw;
}
ha-icon {
width: var(--footer-card-icon-size);
vertical-align: 7%;
padding-right: 0.1vw;
opacity: 0.4;
}
#card {
border-radius: var(--footer-card-border-radius);
background: rgba(115, 115, 115, 0.10);
}
#notify {
font-size: var(--footer-notify-font-size);
width: var(--footer-notify-box-size);
height: var(--footer-notify-box-size);
line-height: var(--footer-notify-box-size);
padding-right: 0.5%;
padding-top: 0.5%;
top: var(--footer-notify-top);
right: var(--footer-notify-right);
}
/* portrait */
@media screen and (max-width: 1200px) {
#name {
font-size: calc(var(--footer-card-font-size) * var(--footer-portrait));
padding: calc(var(--footer-card-padding-v) * var(--footer-portrait)) calc(var(--footer-card-padding-h) * var(--footer-portrait));
}
ha-icon {
width: calc(var(--footer-card-icon-size) * var(--footer-portrait));
}
#card {
border-radius: calc(var(--footer-card-border-radius) * var(--footer-portrait));
margin: 0 0.5vw;
}
#notify {
font-size: calc(var(--footer-notify-font-size) * var(--footer-portrait));
width: calc(var(--footer-notify-box-size) * var(--footer-portrait));
height: calc(var(--footer-notify-box-size) * var(--footer-portrait));
line-height: calc(var(--footer-notify-box-size) * var(--footer-portrait));
}
}
/* phone */
@media screen and (max-width: 800px) {
#name {
font-size: calc(var(--footer-card-font-size) * var(--footer-phone));
padding: calc(var(--footer-card-padding-v) * var(--footer-phone)) calc(var(--footer-card-padding-h) * var(--footer-phone));
letter-spacing: 0.05vw;
}
ha-icon {
width: calc(var(--footer-card-icon-size) * var(--footer-phone));
}
#card {
border-radius: calc(var(--footer-card-border-radius) * var(--footer-phone));
background: rgba(115, 115, 115, 0.12);
margin: 0 0.5vw;
}
#notify {
font-size: calc(var(--footer-notify-font-size) * var(--footer-phone));
width: calc(var(--footer-notify-box-size) * var(--footer-phone));
height: calc(var(--footer-notify-box-size) * var(--footer-phone));
line-height: calc(var(--footer-notify-box-size) * var(--footer-phone) + 1px);
top: calc(var(--footer-notify-top) * var(--footer-phone));
right: calc(var(--footer-notify-right) * var(--footer-phone) + 2%);
padding: 0;
}
}
`:''}
`;
]]]
card_light:
show_state: true
state_display: null
size: 40%
styles:
card:
- width: 120px
- height: 120px
grid:
- grid-template-areas: '"i" "n" "s"'
- grid-template-columns: 1fr
- grid-template-rows: 1fr min-content min-content
icon:
- color: var(--button-card-light-color)
img_cell:
- align-self: start
- text-align: start
- color: var(--button-card-light-color)
name:
- color: var(--button-card-light-color)
- justify-self: start
- padding-left: 10px
- font-weight: bold
- font-size: 11pt
state:
- justify-self: start
- padding-left: 10px
- text-transform: capitalize
- font-size: 11pt
- color: var(--button-card-light-color)
state:
- value: 'off'
styles:
card:
- filter: opacity(50%)
icon:
- filter: grayscale(100%)
hold_action:
action: more-info
light:
template:
- base
- circle
- loader
double_tap_action:
action: more-info
variables:
circle_input: |
[[[
if (entity) {
// if light group get brightness from child to remove bounce
let child = entity.attributes.entity_id,
brightness = child && states[child[0]].attributes.brightness
? Math.round(states[child[0]].attributes.brightness / 2.54)
: Math.round(entity.attributes.brightness / 2.54);
return brightness === 0 && entity.state !== 'off'
? 1
: brightness
}
]]]
circle_input_unit: '%'
base:
template:
- settings
- tilt
- extra_styles
variables:
state_on: >
[[[ return ['on', 'home', 'cool', 'fan_only', 'playing', 'unlocked',
'armed_home', 'armed_away', 'armed_night'].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; ]]]
timeout: |
[[[ return !entity || Date.now() - Date.parse(entity.last_changed); ]]]
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;
}
]]]
aspect_ratio: 1/1
show_state: true
show_icon: true
state_display: |
[[[
const stateDict = {
'on': variables.translate_on,
'off': variables.translate_off,
'cool': variables.translate_cool,
'fan_only': variables.translate_fan_only,
};
if (variables.state === true) return variables.translate_unknown;
return stateDict[variables.state];
]]]
tap_action:
ui_sound_tablet: |
[[[
let screensaver = states[variables.entity_tablet] === undefined ||
states[variables.entity_tablet].state;
if (variables.state === 'off' && screensaver === 'off') {
hass.callService('media_player', 'play_media', {
entity_id: variables.entity_browser_mod,
media_content_id: '/local/sound/on.m4a',
media_content_type: 'music'
});
}
if (variables.state_on && screensaver === 'off') {
hass.callService('media_player', 'play_media', {
entity_id: variables.entity_browser_mod,
media_content_id: '/local/sound/off.m4a',
media_content_type: 'music'
});
}
]]]
action: toggle
haptic: medium
double_tap_action:
haptic: success
hold_action:
action: block
styles:
grid:
- grid-template-areas: |
"i circle"
"n n"
"s s"
- grid-template-columns: repeat(2, 1fr)
- grid-template-rows: auto repeat(2, min-content)
- gap: 1.3%
- align-items: start
- will-change: transform
name:
- justify-self: start
- line-height: 121%
state:
- justify-self: start
- line-height: 115%
icon:
- color: var(--button-card-light-color)
- icon_size: 600px
- padding: 0px 0px
- margin-top: '-45%'
- margin-left: '-28%'
card:
- border-radius: 26px
- border-width: 0
- '-webkit-tap-highlight-color': rgba(0,0,0,0)
- transition: none
- '--mdc-ripple-color': |
[[[
return variables.state_on
? 'rgb(0, 0, 0)'
: '#97989c';
]]]
- color: |
[[[
return variables.state_on
? '#4b5254'
: '#97989c';
]]]
- background-color: |
[[[
return variables.state_on
? 'rgba(255, 255, 255, 0.85)'
: 'rgba(115, 115, 115, 0.25)';
]]]
variables:
circle_input: |
[[[
if (entity) {
// if light group get brightness from child to remove bounce
let child = entity.attributes.entity_id,
brightness = child && states[child[0]].attributes.brightness
? Math.round(states[child[0]].attributes.brightness / 2.54)
: Math.round(entity.attributes.brightness / 2.54);
return brightness === 0 && entity.state !== 'off'
? 1
: brightness
}
]]]
circle_input_unit: '%'
circle:
styles:
card:
- '--c-stroke-color-on': '#b0b0b0'
- '--c-stroke-color-off': none
- '--c-fill-color-on': none
- '--c-fill-color-off': rgba(255,255,255,0.04)
- '--c-stroke-width': 2.3
- '--c-stroke-width-dragging': 4
- '--c-font-color': '#97989c'
- '--c-font-size': 14px
- '--c-unit-font-size': 10.5px
- '--c-font-weight': 700
- '--c-letter-spacing': '-0.02rem'
custom_fields:
circle:
- display: initial
- width: 88%
- margin: '-3% 2% 0 0'
- justify-self: end
- opacity: 1
custom_fields:
circle: |
[[[
if (entity) {
let r = 22.1,
c = r * 2 * Math.PI,
tspan = '<tspan dx=".2" dy="-.4">',
domain = entity.entity_id.split('.')[0],
state = variables.state_on,
input = variables.circle_input || ' ',
unit = variables.circle_input_unit || ' ';
/* * * * * * * * * * * * * * * * * *
* *
* CIRCLE *
* *
* * * * * * * * * * * * * * * * * */
let circle = (state, input, unit) => {
return `
<svg viewBox="0 0 50 50">
<style>
circle {
transform: rotate(-90deg);
transform-origin: 50% 50%;
stroke-dasharray: ${c};
stroke-dashoffset: ${typeof input === 'number' && c - input / 100 * c};
stroke-width: var(--c-stroke-width);
stroke: ${state ? 'var(--c-stroke-color-on)' : 'var(--c-stroke-color-off)'};
fill: ${state ? '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: var(--c-font-color);
}
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%">${input}${tspan}${unit}</tspan></text>
</svg>
${domain === 'light' && `
<input id="circle_slider" type="range" min="0" max="100" value="${input}">
`}
`;
}
/* * * * * * * * * * * * * * * * * *
* *
* LIGHT *
* *
* * * * * * * * * * * * * * * * * */
if (domain === 'light' && state) {
// wait 0ms for shadow dom
setTimeout(() => {
// then get elements
let elt = this.shadowRoot,
circle_slider = elt.getElementById('circle_slider'),
circle_value = elt.getElementById('circle_value'),
circle_stroke = elt.getElementById('circle_stroke');
// approximate position of thumb relative to circle
circle_slider.style.top = `${(circle_slider.value - 50) / 1.66 - 1}%`;
// debug position
let debug = false;
if (debug) circle_slider.style.opacity = 0.3;
// pass each event to handler
['click', 'input', 'mousedown', 'mouseup', 'touchstart', 'touchend'].forEach((event) => {
circle_slider.addEventListener(event, handler, { passive: true })
});
function handler(event) {
// "this" refers to slider
if (event.target === this) {
// bypass button-card tap_action
event.stopPropagation();
// update circle_value
circle_value.innerHTML = `${this.value}${tspan}${unit}</tspan>`;
// update stroke
circle_stroke.style.strokeDashoffset = c - this.value / 100 * c;
circle_stroke.style.strokeWidth = 'var(--c-stroke-width-dragging)';
// set cursor while dragging
if (event.type === 'mousedown' || event.type === 'input') {
this.style.cursor = 'grabbing';
} else {
this.style.cursor = 'grab';
}
// reset stroke width if value doesn't change
if (input == this.value && (event.type === 'click' || event.type === 'touchend'))
circle_stroke.style.strokeWidth = 'var(--c-stroke-width)';
// on release
if (event.type === 'mouseup' || event.type === 'touchend') {
// display loader if brightness is 0
if (circle_slider.value == 0 && elt.getElementById('loader')) {
elt.getElementById('loader').style.display = 'initial';
elt.getElementById('circle').style.display = 'none';
}
// set brightness
hass.callService('light', 'turn_on', {
entity_id: entity.entity_id,
brightness_pct: this.value
});
}
}
}
}, 0);
return circle(state, input, unit);
}
/* * * * * * * * * * * * * * * * * *
* *
* PERSON *
* *
* * * * * * * * * * * * * * * * * */
else if (domain === 'person') {
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 input = 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)),
unit = ' ';
return circle(state, input, unit);
}
/* * * * * * * * * * * * * * * * * *
* *
* CLIMATE *
* *
* * * * * * * * * * * * * * * * * */
else if (domain === 'fan') {
return circle(state, input, unit);
}
/* * * * * * * * * * * * * * * * * *
* *
* OTHER *
* *
* * * * * * * * * * * * * * * * * */
else if (variables.state_on) {
return circle(state, input, unit);
}
}
]]]
base_media:
template:
- settings
state_display: |
[[[
const stateDict = {
'on': variables.translate_on,
'off': variables.translate_off,
'playing': variables.translate_playing,
'paused': variables.translate_paused,
'standby': variables.translate_standby,
'idle': variables.translate_idle
};
if (variables.state === true) return variables.translate_unknown;
return stateDict[variables.state];
]]]
variables:
media_on: >
[[[ return !entity || ['playing', 'paused'].indexOf(entity.state) !== -1;
]]]
media_off: >
[[[ return !entity || ['off', 'idle', 'standby', 'unknown',
'unavailable'].indexOf(entity.state) !== -1; ]]]
tap_action:
action: |
[[[
return variables.media_on
? 'call-service'
: 'none';
]]]
service: media_player.media_play_pause
service_data:
entity_id: |
[[[
return variables.entity_id;
]]]
double_tap_action:
action: more-info
styles:
card:
- color: |
[[[
if (variables.is_youtube) {
return `#efefef`;
} else {
return variables.media_on && variables.entity_picture === undefined
? 'rgba(0, 0, 0, 0.6)'
: variables.media_off
? '#97989c'
: '#efefef';
}
]]]
- text-shadow: |
[[[
if (variables.is_youtube) {
return `1px 1px 5px rgba(18, 22, 23, 0.9)`;
} else {
return variables.media_off || variables.entity_picture === undefined
? 'none'
: '1px 1px 5px rgba(18, 22, 23, 0.9)';
}
]]]
media:
template:
- base
- base_media
styles:
custom_fields:
icon:
- width: 70%
- margin-left: 2%
- fill: '#9da0a2'
- display: |
[[[ if (variables.is_youtube) {
return `none`;
} else {
return variables.media_off || variables.entity_picture === undefined
? 'initial'
: 'none';
} ]]]
card:
- background-color: none
- background-size: cover
- background-position: center
- background-image: |
[[[
if (variables.is_youtube) {
return `linear-gradient(0deg, rgba(0,0,0,.8) 0%, rgba(0,0,0,0) 100%), url(${states[this._config?.triggers_update].state})`;
} else {
return variables.media_on && variables.entity_picture === undefined
? 'linear-gradient(0deg, rgba(255, 255, 255, 0.8) 0%, rgba(255, 255, 255, 0.8) 100%)'
: variables.media_off
? 'linear-gradient(0deg, rgba(115, 115, 115, 0.2) 0%, rgba(115, 115, 115, 0.2) 100%)'
: `linear-gradient(0deg, rgba(0,0,0,.8) 0%, rgba(0,0,0,0) 100%), url(${variables.entity_picture})`;
}
]]]
conditional_media:
aspect_ratio: 1000/996
template:
- base
- base_media
- icon_play_pause
variables:
i: |
[[[
if (entity) {
let data = entity.attributes.data;
return data === undefined || Math.floor(Math.random() * (data.length - 1)) + 1;
}
]]]
state_display: |
[[[
let horizontalStack = this.getRootNode().host,
swipeCard = horizontalStack.getRootNode().host,
gridTitle = swipeCard.getRootNode().querySelector("h1");
swipeCard.swiper.on("slideChange", () => {
if (swipeCard.swiper.realIndex === 0) {
gridTitle.textContent = "Media";
}
else if (swipeCard.swiper.realIndex === 1) {
gridTitle.textContent = "Spelare";
}
});
if (entity) {
let elt = this.shadowRoot,
await = setTimeout(marquee, 100),
data = entity.attributes.data,
artist = entity.attributes.media_artist,
title = entity.attributes.media_title;
if (data !== undefined) {
var number = data[variables.i].number === undefined && data[variables.i].aired !== undefined
? `(${data[variables.i].aired.split("-")[0]})`
: data[variables.i].number === undefined && data[variables.i].aired === undefined
? ' '
: data[variables.i].number,
output = `${data[variables.i].title} ${number}`;
} else {
var output = artist === undefined && title !== undefined
? title
: title === undefined && artist !== undefined
? artist
: title !== undefined && artist !== undefined
? `${artist} - ${title}`
: variables.translate_idle;
}
function marquee() {
let state = elt.getElementById("state"),
container = elt.getElementById("container");
if (state && container) {
state.innerHTML = output;
let ro = new ResizeObserver(entries => {
let spacer = " ".repeat(3),
s = entries[0],
c = entries[1],
r = s && s.contentRect &&
c && c.contentRect &&
s.contentRect.width !== 0 &&
c.contentRect.width !== 0;
if (r && s.contentRect.width < c.contentRect.width) {
state.classList.remove("marquee");
}
else if (r && s.contentRect.width >= c.contentRect.width) {
state.innerHTML = `${output} ${spacer} ${output} ${spacer} `;
state.classList.add("marquee");
}
});
ro.observe(state);
ro.observe(container);
}
}
return output;
}
return variables.translate_unknown;
]]]
tap_action:
action: call-service
service: media_player.media_play_pause
service_data:
entity_id: |
[[[ return variables.entity_id; ]]]
styles:
grid:
- gap: 0.65%
name:
- padding: 0.2vw
- margin: '-0.2vw'
state:
- padding-bottom: 5.25%
- max-width: unset
- overflow: visible
card:
- padding: 5.75% 5.25% 0 5.75%
- border-radius: calc(var(--button-card-border-radius) / 2)
- background: rgba(115, 115, 115, 0.2) center center/cover no-repeat
- background-image: |
[[[
if (entity) {
if (variables.is_youtube) {
return `url(${states[this._config?.triggers_update].state})`;
} else {
let data = entity.attributes.data;
return data && (data[variables.i].fanart || data[variables.i].poster)
? `url("${data[variables.i].fanart}"), url("${data[variables.i].poster}")`
: `url("${variables.entity_picture}")`;
}
}
]]]
- color: |
[[[
return entity === undefined
? '#97989c'
: '#efefef';
]]]
- text-shadow: |
[[[
return entity === undefined
? 'none'
: '1px 1px 5px rgba(18, 22, 23, 0.9)';
]]]
custom_fields:
icon:
- width: 30%
- fill: |
[[[
return entity && variables.media_on
? 'rgba(255, 255, 255, 0.8)'
: '#9da0a2';
]]]
blur_overlay:
- display: block
- position: absolute
- width: 103.1%
- height: 103.1%
- filter: var(--blur-intensity)
- clip-path: >
inset(74.5% 1.45% 1.45% 1.45% round 0 0
calc(var(--button-card-border-radius) / 2)
calc(var(--button-card-border-radius) / 2))
- background: center center/cover no-repeat
- background-image: |
[[[
if (entity) {
if (variables.is_youtube) {
return `url(${states[this._config?.triggers_update].state})`;
} else {
let data = entity.attributes.data;
return data && (data[variables.i].fanart || data[variables.i].poster)
? `url("${data[variables.i].fanart}"), url("${data[variables.i].poster}")`
: `url("${variables.entity_picture}")`;
}
}
]]]
- left: '-1.5%'
- bottom: '-1.6%'
custom_fields:
blur_overlay: |
[[[
setTimeout(() => {
let elt = this.shadowRoot,
card = elt.getElementById('card'),
container = elt.getElementById('container'),
blur_overlay = elt.getElementById('blur_overlay');
if (elt && card && container && blur_overlay) {
card.insertBefore(blur_overlay, container);
}
}, 0);
return ' ';
]]]
lock:
tap_action:
loader: |
[[[
let elt = this.shadowRoot;
if (variables.state_on && variables.lock === 'on') {
elt.getElementById('lock').classList.add('locked');
window.setTimeout(() => {
elt.getElementById('lock').classList.remove('locked');
}, 1100);
} else {
// duplicate of "loader" template
let loader = (id, style, timeout) => {
elt.getElementById(id) && (elt.getElementById(id).style.display = style,
window.setTimeout(() => {
elt.getElementById('loader').style.display = 'none'
}, 20000))
};
loader('circle', 'none', 'initial'),
loader('loader', 'initial', 'none');
}
]]]
custom_fields:
circle: |
[[[
if (entity && variables.trigger) {
let state = variables.trigger.state === 'on' ? 'locked' : null;
if (variables.lock === 'on') {
return `
<svg viewBox="0 0 50 50">
<style>
@keyframes locked {
from,
to {
transform: translateX(0);
}
10%,
30%,
50%,
70%,
90% {
transform: translateX(-8%);
}
20%,
40%,
60%,
80% {
transform: translateX(8%);
}
}
.locked {
animation: locked 1.1s;
}
</style>
<path id="lock" class="${state}" d="M8.2 22.6h2.4v-7.2C10.6 7.5 17.1 1 25 1s14.4 6.4 14.4 14.4v7.2h2.4V49H8.2m26.4-26.4v-7.2c0-5.3-4.3-9.6-9.6-9.6s-9.6 4.3-9.6 9.6v7.2"/>
</svg>
`;
}
}
]]]
styles:
custom_fields:
circle:
- width: 45%
- fill: var(--state-icon-color)
- margin: 1% 2% 0 0
- justify-self: end
- opacity: 1
- display: grid
loader:
custom_fields:
loader: |
<img src="/local/loader.svg" width="100%">
tap_action:
loader: |
[[[
if (entity) {
let elt = this.shadowRoot,
loader = (id, style, timeout) => {
elt.getElementById(id) && (elt.getElementById(id).style.display = style,
window.setTimeout(() => {
elt.getElementById('loader').style.display = 'none'
}, 20000))
};
loader('circle', 'none', 'initial'),
loader('loader', 'initial', 'none');
}
]]]
styles:
custom_fields:
loader:
- display: none
- top: '-6%'
- right: '-3.5%'
- width: 52%
- position: absolute
- opacity: 0.5
- pointer-events: none
- filter: |
[[[
return variables.state_on
? 'none'
: 'invert(1)';
]]]
climate_base:
show_icon: false
styles:
name:
- padding: 12px 13px
- font-size: 0.8em
- font-weight: 600
card:
- border-radius: 10px
climate_fan_mode:
variables:
fan_mode: false
tap_action:
action: call-service
service: climate.set_fan_mode
service_data:
entity_id: |
[[[ return !entity || entity.entity_id; ]]]
fan_mode: |
[[[ return variables.fan_mode; ]]]
styles:
card:
- background-color: |
[[[
return !entity || entity.attributes.fan_mode === variables.fan_mode
? "rgba(158, 158, 158, 0.2)"
: "rgba(189, 189, 189, 0.05)";
]]]
template:
- climate_base
climate_swing_mode:
tap_action:
action: call-service
service: climate.set_swing_mode
service_data:
entity_id: |
[[[ return !entity || entity.entity_id; ]]]
swing_mode: |
[[[
return !entity || entity.attributes.swing_mode === 'off'
? 'on'
: 'off';
]]]
styles:
card:
- background-color: |
[[[
return !entity || entity.attributes.swing_mode === "on"
? "rgba(158, 158, 158, 0.2)"
: "rgba(189, 189, 189, 0.05)";
]]]
template:
- climate_base
footer:
template:
- settings
- tilt
- extra_styles
variables:
notify: |
[[[
return false;
]]]
tilt_options: |
[[[
return {
max: 5,
scale: 1.1,
glare: true,
'max-glare': 0.07,
perspective: 1000,
speed: 800,
parallax: '10px'
};
]]]
size: 2vw
show_icon: false
color: '#9da0a2'
custom_fields:
notify: |
[[[
if (Number.isInteger(variables.notify)) {
return variables.notify;
} else if (variables.notify) {
return `<span style="font-weight: 900;">!</span>`;
}
]]]
styles:
card:
- color: '#97989c'
- width: fit-content
- border: 0.12vw solid rgba(115, 115, 115, 0.2)
- transition: none
- padding: 0 0 0.05vw 0
- overflow: visible
- '--mdc-ripple-color': rgba(0, 0, 0, 0.8)
custom_fields:
notify:
- display: |
[[[
if (Number.isInteger(variables.notify)) {
return variables.notify > 0
? 'initial'
: 'none';
}
else if (variables.notify) {
return variables.notify
? 'initial'
: 'none';
}
]]]
- position: absolute
- font-weight: 700
- color: '#d6d6d6'
- background: '#8b3333'
- border-radius: 50%
- text-align: center
- text-overflow: unset
- z-index: 1
tap_action:
haptic: medium
hold_action:
action: block
double_tap_action:
action: block
icon_plex:
custom_fields:
icon: |
<svg viewBox="0 0 50 50">
<path d="M7.7.3h34.6c4.1 0 7.4 3.3 7.4 7.4v34.6c0 4.1-3.3 7.4-7.4 7.4H7.7c-4.1 0-7.4-3.3-7.4-7.4V7.7C.3 3.6 3.6.3 7.7.3z" fill="#282a2d"/>
<path d="M25,7.1H14.6L25,25L14.6,42.9H25L35.4,25L25,7.1z" fill="#e5a00d"/>
</svg>
icon_apple_tv:
custom_fields:
icon: |
<svg viewBox="0 0 50 50">
<path d="M25.2 49.7l-13.7-.1c-2.4 0-4.6-.8-6.5-2.2-2-1.6-3.6-3.6-4.3-6.2-.2-1-.2-1.9-.3-3V11.5C.5 7.9 1.9 5 4.8 2.7 6.2 1.6 7.8.8 9.6.5c.5-.1.9-.1 1.4-.1L27.5.3l10.9.1c2.6 0 4.8.8 6.7 2.4 2.1 1.7 3.7 3.9 4.2 6.6l.2 2.4.1 20.5-.1 6.7c-.1 2.2-.9 4.2-2.2 5.9-1.7 2.2-4 3.8-6.8 4.4-.6.1-1.2.2-1.9.2-.1.1-13.4.2-13.4.2zm-4-27.8c-.9-1.2-2.2-1.6-3.7-1.2-.4.1-.8.2-1.2.4-.3.1-.6.1-.8 0-.4-.1-.8-.3-1.2-.4-.3-.1-.7-.1-1-.1-1.5.2-2.4 1.1-3 2.6-.4 1.1-.3 2.2 0 3.5.4 1.5 1 2.9 2.1 4 .5.6 1.2.9 2 .6 1.1-.5 2.2-.5 3.4 0 .8.3 1.5 0 2.1-.6.7-.8 1.1-1.8 1.6-2.8v-.2c-1-.6-1.7-1.4-1.8-2.7-.2-1.4.5-2.4 1.5-3.1zm9.9-1.4c.1.2.1.3.1.4l3.6 9.5c.1.3.3.4.6.4h.7c.6 0 .6 0 .9-.6l3.7-9.4c.1-.1.1-.3.2-.5H39l-2.9 8.3-3.1-8.3-1.9.2zM27.3 18l-1.3.4c-.5.2-.5.2-.6.7v1.4h-1.6l.1 1.4h1.5v5c0 .7.1 1.4.2 2.1.1.5.3 1 .8 1.4.8.6 2.6.7 3.5.2l-.1-1.2h-1.3c-.5 0-.9-.3-1-.8-.1-.3-.2-.6-.2-1v-5.8H30c0-.5.1-1 0-1.4h-2.7V18zm-8.8-.9c-1.9.3-3 2-2.7 3.2 1.4.2 2.9-1.7 2.7-3.2z"/>
</svg>
icon_spotify:
custom_fields:
icon: |
<svg viewBox="0 0 50 50">
<path d="M25 .3C11.4.3.3 11.4.3 25S11.4 49.7 25 49.7 49.7 38.6 49.7 25 38.6.3 25 .3zm11.3 35.6c-.4.7-1.4 1-2.1.5-5.8-3.5-13.1-4.3-21.7-2.4-.8.2-1.7-.3-1.8-1.2-.2-.8.3-1.7 1.2-1.8 9.4-2.2 17.5-1.2 24 2.8.6.5.9 1.4.4 2.1zm3.1-6.7c-.6.9-1.7 1.2-2.6.6-6.6-4.1-16.8-5.3-24.6-2.9a1.96 1.96 0 0 1-2.4-1.3 1.96 1.96 0 0 1 1.3-2.4c9-2.7 20.1-1.4 27.7 3.3.8.6 1.1 1.8.6 2.7h0zm.2-7c-8-4.7-21.1-5.2-28.7-2.9-1.2.4-2.5-.3-2.9-1.5s.3-2.5 1.5-2.9c8.7-2.6 23.2-2.1 32.4 3.3 1.1.7 1.5 2.1.8 3.2-.6 1.1-2 1.4-3.1.8h0z"/>
</svg>
icon_nest_mini:
custom_fields:
icon: |
<svg viewBox="0 0 50 50">
<path d="M49.7 25c0 13.6-11.1 24.7-24.8 24.7C11.3 49.7.3 38.6.3 25S11.4.3 25 .3 49.7 11.4 49.7 25zm-33.9 0a2.22 2.22 0 0 0-2.2-2.2c-1.2 0-2.3 1-2.3 2.2a2.22 2.22 0 0 0 2.2 2.2c1.3.1 2.3-.9 2.3-2.2h0zm10.8 0c0 1.2.9 2.2 2.2 2.3 1.3 0 2.3-1 2.3-2.2 0-1.3-1-2.3-2.2-2.3-1.3 0-2.3.9-2.3 2.2zm-3.2 0a2.22 2.22 0 0 0-2.2-2.2c-1.2 0-2.3 1-2.3 2.2a2.22 2.22 0 0 0 2.2 2.2c1.3 0 2.3-.9 2.3-2.2h0zm13 2.2a2.22 2.22 0 0 0 2.2-2.2c0-1.2-1-2.3-2.2-2.3a2.22 2.22 0 0 0-2.2 2.2c0 1.3 1 2.3 2.2 2.3z" />
</svg>
icon_play_pause:
styles:
custom_fields:
play_pause:
- top: '-10%'
- right: 0
- bottom: 0
- left: 0
- margin: auto
- width: 25%
- height: 25%
- position: absolute
- fill: '#dedede'
custom_fields:
play_pause: |
[[[
let style = `
<style>
.scale-up {
animation: scale-up 1s forwards;
cubic-bezier(.05, .5, .3, 1);
transform-origin: center center;
}
@keyframes scale-up {
0% {
opacity: 0;
transform: scale(0);
}
20% {
transform: scale(1);
}
30% {
opacity: 1;
}
80% {
opacity: 1;
}
100% {
opacity: 0;
}
}
</style>
`;
if (variables.state === 'paused' && variables.timeout < 2000) {
return `
<svg viewBox="0 0 166 166">${style}
<path class="scale-up" d="M0 0h59.9v166H0zm106.1 0H166v166h-59.9z"/>
</svg>
`;
}
if (variables.state === 'playing' && variables.timeout < 2000) {
return `
<svg viewBox="0 0 166 166">${style}
<path class="scale-up" d="M0 0l166 83L0 166z"/>
</svg>
`;
}
]]]
icon_hue:
styles:
custom_fields:
icon:
- width: 77%
- margin-left: '-14%'
- margin-top: 1%
custom_fields:
icon: |
[[[
let state = variables.state_on && variables.timeout < 2000 ? 'on' : null;
return `
<svg viewBox="0 0 50 50">
<style>
@keyframes on {
0% {
transform: scale(0.85);
}
20% {
transform: scale(1.1);
}
40% {
transform: scale(0.95);
}
60% {
transform: scale(1.03);
}
80% {
transform: scale(0.97);
}
100% {
transform: scale(1);
}
}
.on {
animation: on 0.8s;
transform-origin: center;
}
</style>
<path fill="#9da0a2" d="M27.4 47.3h-4.9s-.7.1-.7.8.4.9.7.9h4.9c.3 0 .7-.1.7-.9s-.7-.8-.7-.8zm3.3-2.9H19.3s-.8 0-.8.8.6.9.8.9h11.5c.2 0 .8-.1.8-.9-.1-.8-.9-.8-.9-.8zm0-3H19.3s-.8 0-.8.8.6.9.8.9h11.5c.2 0 .8-.1.8-.9-.1-.8-.9-.8-.9-.8zm0-2.9H19.3s-.8 0-.8.8.6.9.8.9h11.5c.2 0 .8-.1.8-.9s-.9-.8-.9-.8zm5.2-23.2c-3.3-5.3-7-5.6-10.9-5.6-3.8 0-8.4.4-10.9 5.6-.1.1-.1.3.1.7.4.8 3.3 7.2 3.2 18.8 0 1.1-.1 1.6 0 1.7 0 .1 0 .7 1.1.7h13c1 0 1-.5 1.1-.7v-1.7c-.1-11.6 2.8-18 3.2-18.8.1-.4.1-.5.1-.7"/>
<path class="${state} light-color" d="M14.1 15.3c3.4-.3 7-.4 10.9-.4 3.8 0 7.5.2 10.9.4.4-.4.7-.8.9-1.1C39 8.5 38.9 6.5 38.9 6c-.2-4.4-8.4-5-12.1-5h0-3.4c-3.7 0-12 .5-12.1 5 0 .5-.1 2.5 2.1 8.2 0 .3.3.8.7 1.1z"/>
</svg>
`;
]]]
icon_shade:
styles:
custom_fields:
icon:
- width: 77%
- margin-left: '-15%'
- margin-top: 1%
custom_fields:
icon: |
[[[
let state = variables.state_on && variables.timeout < 2000 ? 'on' : null;
return `
<svg viewBox="0 0 50 50">
<style>
@keyframes on {
0% {
transform: scale(0.85);
}
20% {
transform: scale(1.1);
}
40% {
transform: scale(0.95);
}
60% {
transform: scale(1.03);
}
80% {
transform: scale(0.97);
}
100% {
transform: scale(1);
}
}
.on {
animation: on 0.8s;
transform-origin: center;
}
</style>
<path fill="#9da0a2" d="M26.4 25.6c.6-.3 1.1-.7 1.1-1.3L25 17.9l-2.5 6.4c0 .7.6 1.1 1.1 1.3v20.8h-5.5v2.7h13.7v-2.7h-5.5V25.6z"/>
<path class="${state} light-color" d="M24.6.9l-9.4.5c-.6.1-1.9 0-2.5 2.1s-2.4 9.1-4 16.9c-.2.7-.5 2-.5 2.3s-.4 1.6.9 1.6c.8.1 7.4.3 15.9.3 8.6 0 15.1-.3 15.9-.3 1.3-.1.9-1.3.9-1.6s-.3-1.6-.5-2.3c-1.6-7.8-3.4-14.8-4-16.9s-1.9-2-2.5-2.1c-1.6-.2-6.9-.4-9.4-.5"/>
</svg>
`;
]]]
icon_custom:
show_icon: true
icon: var(--button-card-icon)
icon_tv:
styles:
custom_fields:
icon:
- width: 87%
- margin-top: '-8%'
- fill: |
[[[
return variables.state_on
? '#616161'
: '#9da0a2';
]]]
custom_fields:
icon: |
[[[
let style = `
<style>
@keyframes on {
from {
transform: scaleY(0);
}
to {
transform: scaleY(1);
}
}
.on {
animation: on 1s;
transform-origin: -100% 46%;
animation-fill-mode: forwards;
}
@keyframes off {
from {
transform: scaleY(1);
}
to {
transform: scaleY(0);
}
}
.off {
animation: off 1s;
transform-origin: -100% 46%;
animation-fill-mode: forwards;
}
</style>
`,
path = `
<path d="M46 9.2v27.5H4.1V9.2H46m2.4-2.4H1.6v32.3h46.7c.1 0 .1-32.3.1-32.3zM11.9 43.2h26.3c.6 0 1.1-.4 1.1-1v-.3c0-.6-.4-1.1-1-1.1H11.9c-.6 0-1.1.4-1.1 1v.3a1.11 1.11 0 0 0 1.1 1.1z"/>
`,
gradient = `
<linearGradient id="A" gradientUnits="userSpaceOnUse" x1="5.401" y1="34.714" x2="43.817" y2="11.74">
<stop offset="0" stop-color="#64acb7"/>
<stop offset="1" stop-color="#7fdbe9"/>
</linearGradient>
`;
if (variables.state_on && variables.timeout < 2000) {
return `
<svg viewBox="0 0 50 50"> ${style} ${gradient}
<path d="M2.9,8h44.3v29.9H2.9V8z" fill="#20262890"/>
<path class="on" d="M2.9,8h44.3v29.9H2.9V8z" fill="url(#A)"/> ${path}
</svg>
`;
}
if (variables.state_on && variables.timeout > 2000) {
return `
<svg viewBox="0 0 50 50"> ${gradient}
<path d="M2.9,8h44.3v29.9H2.9V8z" fill="#20262890"/>
<path class="on" d="M2.9,8h44.3v29.9H2.9V8z" fill="url(#A)"/> ${path}
</svg>
`;
}
if (variables.state === 'off' && variables.timeout < 2000) {
return `
<svg viewBox="0 0 50 50"> ${style} ${gradient}
<path class="off" d="M2.9,8h44.3v29.9H2.9V8z" fill="url(#A)"/> ${path}
</svg>
`;
} else {
return `
<svg viewBox="0 0 50 50"> ${style}
${path}
</svg>
`;
}
]]]
icon_ps5:
styles:
custom_fields:
icon:
- width: 89%
- margin-left: '-2%'
- margin-top: '-9%'
custom_fields:
icon: |
[[[
if (variables.state_on && variables.timeout < 2000) {
return `
<svg viewBox="0 0 50 50">
<style>
@keyframes on {
50% {
transform: translateY(-45%);
}
100% {
transform: translateY(0);
}
}
.on {
animation: on 2s cubic-bezier(0.550, 0.085, 0.680, 0.530) both;
}
</style>
<g style="clip-path: url(#mask);">
<g class="on">
<path fill="#00aa9e" d="M49.2 38.9l-75.6-25.1v7.4l75.6 25.2z"/>
<path fill="#f3c202" d="M49.2 46.4l-75.6-25.2v7.5l75.6 25.1z"/>
<path fill="#326db3" d="M49.2 53.8l-75.6-25.1V51l75.6 25.1zm0-22.3L-26.4 6.4v7.4l75.6 25.1z"/>
</g>
</g>
<defs>
<clipPath id="mask">
<path d="M47.5 33.2c-.5-2.2-3.9-3.5-9.1-3.9-3.8-.3-7.5.6-11.1 1.9l-.6.2v-5.7l-5.7.8-4.6 1.6L6 31.9h-.1c-1.9.7-3.8 2.2-3.7 4.2.1 2.1 4.7 2.6 8.2 3.2 3.3.6 6.2.2 8.9-.7l7.3 4.8L33 41l10.7-4h.1c2.8-1 4-2.5 3.7-3.8zm-31.3 2l-3.6 1.3c-2.2.8-4.1-1.1-2.1-1.9l1.7-.6 7.2-2.7v2.8l-3.2 1.1zm22.5-1.1l-1.9.7-10.2 3.7V36l6.5-2.4 3.8-1.3c4-.9 5.6.5 1.8 1.8z"/>
</clipPath>
</defs>
<path fill="#de0029" d="M26.7 14.6v28.7l-7.3-2.5V7.1l9.3 2.6c6 1.7 9.6 5 9.6 10.7-.1 6.7-3 9.4-8.7 7.6V14.9c-.1-1.6-2.9-1.7-2.9-.3h0z"/>
</svg>
`;
}
return variables.state_on && variables.timeout > 2000
? `
<svg viewBox="0 0 50 50">
<path d="M33.1 33.6L26.7 36v-4.5l6.4 2.1h0zM19.4 29l-2.9-1h-.1L6 31.9h-.1-.1l6.3 2.1h.1l7.2-2.7V29zm0 5.1l-3.2 1.1-.3.1 3.5 1.2v-2.4zm17.4.7h0l-10.1 3.7v.4L33 41l10.6-4-6.8-2.2z" fill="#00aa9e" />
<path d="M19.4 38.5l-.1.1c-2.7.9-5.6 1.3-8.9.7-3.5-.6-8.1-1.1-8.2-3.2-.1-2 1.7-3.4 3.6-4.2l6.3 2.1-1.6.6c-2 .8-.1 2.7 2.1 1.9l3.3-1.2 3.5 1.2v2zm7.3 4.8L33 41l-6.3-2.1v4.4" fill="#f3c202" />
<path d="M19.4 29l-2.9-1 2.9-1v2zm28.1 4.2c-.5-2.2-3.9-3.5-9.1-3.9-3.8-.3-7.5.6-11.1 1.9l-.6.2h0l6.5 2.1 3.7-1.3c4-.9 5.6.5 1.8 1.8l-1.9.7 6.8 2.2h.1.1c2.8-.9 4-2.4 3.7-3.7z" fill="#326db3" />
<path d="M26.7 14.6v28.7l-7.3-2.5V7.1l9.3 2.6c6 1.7 9.6 5 9.6 10.7-.1 6.7-3 9.4-8.7 7.6V14.9c-.1-1.6-2.9-1.7-2.9-.3z" fill="#de0029" />
</svg>`
: `
<svg viewBox="0 0 50 50">
<path fill="#9da0a2" d="M43.8 37h-.1l-10.6 4-4.2 1.6v-4.9l8-2.9 1.9-.7c3.8-1.3 2.2-2.7-1.8-1.9l-3.8 1.3-4.3 1.6v-4.5c3.1-1 6.3-1.6 9.5-1.4 5.3.4 8.7 1.6 9.1 3.9.3 1.4-.9 2.9-3.7 3.9zm-26.7-2.1l-.9.3-3.6 1.3c-2.2.8-4.1-1.1-2.1-1.9l1.7-.6 5-1.9v-4.2l-.6.2L6 31.9h-.1c-1.9.7-3.8 2.2-3.7 4.2.1 2.1 4.7 2.6 8.2 3.2 2.4.4 4.6.3 6.7-.1v-4.3zm12.4-20V28c5.7 1.7 8.7-.9 8.7-7.6.1-5.7-3.6-9-9.6-10.7l-9.3-2.6v33.8l7.2 2.5.1.1V14.6c.1-1.4 2.9-1.3 2.9.3z"/>
</svg>`;
]]]
icon_spot:
styles:
custom_fields:
icon:
- width: 74%
- margin-left: '-8%'
- margin-top: 3%
custom_fields:
icon: |
[[[
let state;
if (variables.state_on && variables.timeout < 2000) {
state = 'on';
}
if (variables.state === 'off' && variables.timeout < 2000) {
state = 'off';
}
if (variables.state_on && variables.timeout > 2000) {
state = 'on_timeout';
}
return `
<svg viewBox="0 0 50 50">
<style>
@keyframes on {
0% {
transform: rotateZ(0deg);
animation-timing-function: cubic-bezier(0.7, 0, 0.84, 0);
}
70% {
transform: rotateZ(-15deg);
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}
75% {
transform: rotateZ(-15deg);
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}
88% {
transform: rotateZ(-11deg);
}
100% {
transform: rotateZ(-15deg);
}
}
@keyframes off {
0% {
transform: rotateZ(-15deg);
animation-timing-function: cubic-bezier(0.7, 0, 0.84, 0);
}
70% {
transform: rotateZ(0deg);
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}
75% {
transform: rotateZ(0deg);
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}
88% {
transform: rotateZ(-4deg);
}
100% {
transform: rotateZ(0deg);
}
}
.on {
animation: on 0.7s;
transform-origin: 40% 20%;
animation-fill-mode: forwards;
animation-delay: -0.1s;
}
.off {
animation: off 0.7s;
transform-origin: 40% 20%;
animation-fill-mode: forwards;
}
.on_timeout {
transform: rotateZ(-15deg);
transform-origin: 40% 20%;
}
</style>
<path style="clip-path: url(#mask);" fill="#9da0a2" d="M40.5.8H17.1c-.1 0-.1 0-.1.1A3.12 3.12 0 0 0 20.1 4h6.1c.1 0 .1 0 .1.1v7.4L18 19.1l3.6 3.5 9.1-8.6c.4-.4.6-1 .7-1.6V4c0-.1 0-.1.1-.1h6c1.7.1 3.1-1.3 3-3.1z"/>
<defs>
<clipPath id="mask">
<path class="${state}" d="M0 9.1h24l8.3 8.8H50V-9H0z"/>
</clipPath>
</defs>
<path class="${state} light-color" d="M25.5 46.4s1.4.5 10.4-8.2c.5-.4 6.3-6.3 5.8-7.1-.7-.8-18.6-19.5-18.6-19.5s-.6-.9-8.6 6.4c-.6.5-8.7 8-7.7 9.1l18.7 19.3z"/>
</svg>
`;
]]]
icon_imac:
styles:
custom_fields:
icon:
- width: 80%
- margin-left: 1%
- margin-top: '-5%'
- fill: |
[[[ return variables.state_on ? '#72757c' : '#9da0a2'; ]]]
custom_fields:
icon: |
[[[
let state = variables.state_on && variables.timeout < 2000
? 'on'
: null;
return `
<svg viewBox="0 0 50 50">
<style>
@keyframes on {
from {
opacity: 0.5;
transform: scale(0.6);
}
100% {
opacity: 1;
}
}
.on {
animation: on 0.8s cubic-bezier(0.25, 1, 0.5, 1);
transform-origin: center;
}
</style>
<path class="${state}" d="M31.9 44.5c-1-.3-1.9.4-1.9-3.7h-9.9c0 4.2-.9 3.4-1.9 3.7s-.2.7-.2.7h14.1s.8-.3-.2-.7zM47.6 4.8H2.5c-1.1 0-2 .9-2 2v30.1c0 1.1.9 2 2 2h45c1.1 0 2-.9 2-2v-30a1.95 1.95 0 0 0-1.9-2.1zm-.7 26.4H3.2V7.6H47v23.6z"/>
</svg>
`;
]]]
icon_monitors:
styles:
custom_fields:
icon:
- width: 73%
- margin-left: '-9%'
custom_fields:
icon: |
[[[
let style = `
<style>
@keyframes cone {
35% {
transform: scale(0.8);
animation-timing-function: cubic-bezier(0, 0.55, 0.45, 1);
}
36% {
transform: translateY(0%);
}
49% {
transform: scale(1.25);
}
63% {
transform: scale(0.85);
animation-timing-function: cubic-bezier(0, 0.55, 0.45, 1);
}
77% {
transform: scale(1.15);
animation-timing-function: cubic-bezier(0, 0.55, 0.45, 1);
}
95% {
transform: scale(1);
}
}
.cone {
animation: cone 1.2s;
transform-origin: center;
}
@keyframes speaker {
0% {
transform: scale(1);
}
40% {
transform: scale(1);
}
49% {
transform: scale(0.95);
}
63% {
transform: scale(1);
}
77% {
transform: scale(0.95);
}
100% {
transform: scale(1);
}
}
.speaker {
animation: speaker 1.3s;
transform-origin: center;
}
</style>
`,
paths = `
<g class="speaker">
<path fill="#686868" d="M35.8 46.9H14.2c-1.1 0-2-1-2-2.3V6.7c0-1.3.9-2.3 2-2.3h21.5c1.1 0 2 1 2 2.3v37.9c0 1.2-.9 2.3-1.9 2.3z"/>
<path fill="#2a2a2a" d="M39.2 1H10.8C9.4 1 8.3 2.1 8.2 3.5v42.9a2.65 2.65 0 0 0 2.6 2.6h28.3c1.4 0 2.5-1.2 2.6-2.6V3.5c0-1.4-1.1-2.5-2.5-2.5zM25 7c1.3 0 2.4 1.1 2.4 2.4s-1.1 2.4-2.4 2.4-2.4-1.1-2.4-2.4C22.5 8 23.6 7 25 7zm10.2 35.5l-.4 1.9s-.2.6-.6.6H15.8c-.4 0-.6-.6-.6-.6s-.1-1.1-.4-1.9.6-.9.6-.9h19.3c0-.1.8-.1.5.9z"/>
</g>
<path class="cone" fill="#e5dd00" d="M25 15.7c-6.2 0-11.3 5.1-11.3 11.3S18.8 38.3 25 38.3 36.3 33.2 36.3 27c-.1-6.3-5.1-11.3-11.3-11.3zm0 14.5a3.33 3.33 0 0 1-3.3-3.3 3.33 3.33 0 0 1 3.3-3.3 3.33 3.33 0 0 1 3.3 3.3c-.1 1.9-1.5 3.3-3.3 3.3z"/>
`;
if (variables.state_on && variables.timeout < 2000) {
return `
<svg viewBox="0 0 50 50">
${style}
${paths}
</svg>
`;
}
return variables.state_on && variables.timeout > 2000
? `
<svg viewBox="0 0 50 50">
${paths}
</svg>
`
: `
<svg viewBox="0 0 50 50">
<path fill="#9da0a2" d="M25 18.6c-4.6 0-8.4 3.8-8.4 8.4s3.8 8.4 8.4 8.4 8.4-3.8 8.4-8.4-3.7-8.4-8.4-8.4zm0 11.7a3.33 3.33 0 0 1-3.3-3.3 3.33 3.33 0 0 1 3.3-3.3 3.33 3.33 0 0 1 3.3 3.3c0 1.8-1.4 3.3-3.3 3.3zM39.2 1H10.9C9.4 1 8.3 2.1 8.3 3.6v42.9a2.65 2.65 0 0 0 2.6 2.6h28.3a2.65 2.65 0 0 0 2.6-2.6v-43C41.7 2 40.5.9 39.2 1zM25 7c1.3 0 2.4 1.1 2.4 2.4s-1.1 2.4-2.4 2.4-2.4-1.1-2.4-2.4S23.7 7 25 7zm10.3 35.5l-.4 1.9s-.2.6-.6.6H15.8c-.4 0-.6-.6-.6-.6l-.4-1.9c-.2-.9.6-.9.6-.9h19.3s.9.1.6.9zM25 38.2c-6.2 0-11.3-5.1-11.3-11.3a11.29 11.29 0 1 1 22.6 0c.1 6.3-5 11.3-11.3 11.3z"/>
</svg>
`;
]]]
icon_lamp:
styles:
custom_fields:
icon:
- width: 79%
- margin-left: '-16%'
custom_fields:
icon: |
[[[
let state = variables.state_on && variables.timeout < 2000 ? 'on' : null;
return `
<svg viewBox="0 0 50 50">
<style>
@keyframes on {
0% {
transform: scale(0.85);
}
20% {
transform: scale(1.1);
}
40% {
transform: scale(0.95);
}
60% {
transform: scale(1.03);
}
80% {
transform: scale(0.97);
}
}
.on {
animation: on 0.8s;
transform-origin: center;
}
</style>
<path fill="#9da0a2" d="M26.5 21.8l3.8-6.1H19.7l3.8 6.1c-5 .7-6.3 5.8-5.7 10.2.7 5.1 3.2 10.1 5.7 14.4H19v2.5h11.8v-2.5h-4.5C29 42 31.4 37 32.1 32c.6-4.4-.6-9.4-5.6-10.2zm3.1 9.1c-.3 4.3-2.3 8.7-4.4 12.4l-.2.1v.1-.1c-1.8-3-3.3-6.4-4.1-9.7-.7-3.1-1-7.2 2.7-8.4 1.4-.5 3.1-.1 4.2.8 1.6 1 1.8 3 1.8 4.8z"/>
<path class="${state} light-color" d="M38.1 20L35.7 3.8c-.3-1.9-.4-1.7-.6-2-.9-.6-2.3-.7-2.3-.7H17.4s-1.4 0-2.3.7c-.2.3-.3.1-.6 2C14 5.7 11.9 20 11.9 20s5.8.3 13.4.3h0c7.3 0 12.8-.3 12.8-.3z"/>
</svg>
`;
]]]
icon_climate:
styles:
custom_fields:
icon:
- width: 78%
- margin-left: '-10%'
- fill: >
[[[ return variables.state === 'cool' || variables.state ===
'fan_only' ? '#5daeea' : '#9da0a2'; ]]]
custom_fields:
icon: |
<svg viewBox="0 0 50 50">
<path d="M36.8 1.2v1.7a5.34 5.34 0 0 1-5.3 5.3H18.4a5.34 5.34 0 0 1-5.3-5.3V1.2c-2.6.4-4.7 2.8-4.7 5.6v36.5c0 3.1 2.6 5.7 5.7 5.7h21.8c3.1 0 5.7-2.6 5.7-5.7V6.8c0-2.8-2.1-5.2-4.8-5.6zm-1.7 35.6c-.2 0-.4 0-.5-.1-.4-.1-1.2-.2-2.4-.6-.5-.2-.8-.3-1.2-.4-.3-.1-.7-.3-1.4-.5-1-.4-1.5-.5-1.9-.6-.5-.1-1.1-.2-1.9-.2s-1.4.2-1.9.4c-1 .3-1.8.7-2.1.9l-.6.3a9.75 9.75 0 0 1-1.4.6c-.3.1-.9.3-1.6.3h-.3c-.4 0-1 0-2-.2-.3-.1-.6-.1-.8-.2v-2.7l1.3.3c.5.1 1.3.2 1.7.2.5 0 .9-.2 1.1-.2.4-.1.6-.2 1-.4.2-.1.4-.2.7-.4.4-.2 1.3-.7 2.5-1 .6-.2 1.4-.4 2.5-.5s2 .1 2.5.2c.6.1 1.2.3 2.2.7l1.5.5c.3.1.6.2 1 .4 1 .3 1.8.5 2.1.5h.1v2.7zm0-6c-.2 0-.4 0-.5-.1-.4-.1-1.2-.2-2.4-.6-.5-.2-.8-.3-1.2-.4-.3-.1-.7-.3-1.4-.5-1-.4-1.5-.5-1.9-.6-.5-.1-1.1-.2-1.9-.2s-1.4.2-1.9.4c-1 .3-1.8.7-2.1.9l-.6.3a9.75 9.75 0 0 1-1.4.6c-.3.1-.9.3-1.6.3h-.3c-.4 0-1 0-2-.2-.3-.1-.6-.1-.8-.2v-2.7l1.3.3c.5.1 1.3.2 1.7.2.5 0 .9-.2 1.1-.2.4-.1.6-.2 1-.4.2-.1.4-.2.7-.4.4-.2 1.3-.7 2.5-1 .6-.2 1.4-.4 2.5-.5s2 .1 2.5.2c.6.1 1.2.3 2.2.7l1.5.5c.3.1.6.2 1 .4 1 .3 1.8.5 2.1.5h.1v2.7zm0-6c-.2 0-.4 0-.5-.1-.4-.1-1.2-.2-2.4-.6-.5-.2-.8-.3-1.2-.4-.3-.1-.7-.3-1.4-.5-1-.4-1.5-.5-1.9-.6-.5-.1-1.1-.2-1.9-.2s-1.4.2-1.9.4c-1 .3-1.8.7-2.1.9l-.6.3c-.4.2-.8.4-1.4.6-.3.1-.9.3-1.6.3h-.3c-.4 0-1 0-2-.2-.3-.1-.6-.1-.8-.2v-2.7l1.3.3c.5.1 1.3.2 1.7.2.5 0 .9-.2 1.1-.2.4-.1.6-.2 1-.4.2-.1.4-.2.7-.4.4-.2 1.3-.7 2.5-1 .6-.2 1.4-.4 2.5-.5s2 .1 2.5.2c.6.1 1.2.3 2.2.7l1.5.5c.3.1.6.2 1 .4 1 .3 1.8.5 2.1.5h.1v2.7zM15.7 1.9v-.8h18.6V3c0 1.5-1.2 2.8-2.8 2.8H18.4c-1.5 0-2.8-1.2-2.8-2.8V1.9z"/>
</svg>
icon_bathroom:
styles:
custom_fields:
icon:
- width: 78%
- margin-left: '-10%'
custom_fields:
icon: |
[[[
let state;
if (variables.state_on && variables.timeout < 2000) {
state = 'on';
}
if (variables.state === 'off' && variables.timeout < 2000) {
state = 'off';
}
if (variables.state_on && variables.timeout > 2000) {
state = 'on_timeout';
}
return `
<svg viewBox="0 0 50 50">
<style>
@keyframes on {
0% {
transform: rotateZ(0deg) translate(0%, 0%);
}
100% {
transform: rotateZ(-90deg) translate(-1.5%, 0%);
}
}
@keyframes off {
0% {
transform: rotateZ(-90deg) translate(-1.5%, 0%);
}
45% {
transform: rotateZ(-40deg);
}
55% {
transform: rotateZ(0deg);
}
65% {
transform: rotateZ(-15deg);
}
75% {
transform: rotateZ(0deg);
}
85% {
transform: rotateZ(-5deg);
}
95% {
transform: rotateZ(0deg);
}
}
.on {
animation: on 0.45s;
animation-fill-mode: forwards;
transform-origin: 45% 41%;
transition-timing-function: cubic-bezier(0.85, 0, 0.15, 1);
}
.on_timeout {
transform: rotateZ(-90deg) translate(-1.5%, 0%);
transform-origin: 45% 41%;
}
.off {
animation: off 1.1s linear;
animation-delay: 0.05s;
animation-fill-mode: both;
transform-origin: 45% 41%;
}
</style>
<g class="light-color">
<path d="M12.9 1.2h2.5c1.6 0 2.9 1.3 2.9 2.9v18.6c0 1.4 1.1 2.5 2.4 2.5h20.5c.5 0 1 .4.9 1-.1 2.6-1.2 9.6-10.2 11v7.6c0 .2.2.4.4.4h1.5a1.58 1.58 0 0 1 1.6 1.6v.3a1.58 1.58 0 0 1-1.6 1.6H11a1.58 1.58 0 0 1-1.6-1.6v-.3a1.58 1.58 0 0 1 1.6-1.6h1.6c.2 0 .4-.2.4-.4v-7.6s-5.2-.3-5.2-5.9V4.2c0-1.6 1.3-2.9 2.9-2.9l2.2-.1c0 .1 0 0 0 0z"/>
<path class="${state}" d="M22.3 18.8h18.3a1.58 1.58 0 0 1 1.6 1.6v.6a1.58 1.58 0 0 1-1.6 1.6h-19c-.4 0-.7-.3-.8-.7v-2.3c0-.4.3-.7.7-.8h.8z"/>
</g>
</svg>
`;
]]]
icon_fan2:
styles:
custom_fields:
icon:
- width: 75%
- margin-left: '-3%'
custom_fields:
icon: |
[[[
let path = `
<circle cx="25" cy="25" r="6.6"/>
<path d="M31.9 30.4c-.5.6-1.1 1.1-1.7 1.5-1.4 1.1-3.2 1.7-5.2 1.7-2.3 0-4.5-.9-6-2.4-.9 1.1-1.6 2.3-2.3 3.2l-4.9 5.4c-1.8 2.7.3 5.6 2.5 7 3.9 2.4 9.8 3.1 14.1 1.9 4.6-1.3 7.9-4.7 7.4-9.7-.2-3.4-1.9-6-3.9-8.6zM17 28.3c-.4-1-.6-2.1-.6-3.3a8.7 8.7 0 0 1 6.4-8.4l-1.6-3.5L19 6.2c-1.5-2.8-5-2.5-7.3-1.2-4 2.2-7.5 6.9-8.7 11.3-1.2 4.6.2 9.2 4.7 11.3 3.1 1.3 6.1 1.2 9.3.7zm26.9-17.6c-3.3-3.4-8-4.6-12.1-1.8-2.8 1.8-4.2 4.6-5.5 7.5 4.2.6 7.4 4.2 7.4 8.6 0 .9-.1 1.7-.4 2.5 1.3.2 2.8.3 3.8.4 2.3.4 4.7 1.3 7.1 1.7 3.2.3 4.7-3 4.8-5.6.3-4.6-1.9-10.1-5.1-13.3z"/>
`,
style = `
<svg viewBox="0 0 50 50">
<style>
@keyframes rotate {
0% {
visibility: visible;
transform: rotate(0deg) translateZ(0);
}
100% {
transform: rotate(1080deg) translateZ(0);
}
}
.start {
animation: rotate 2.8s ease-in;
transform-origin: center;
fill: #5daeea;
visibility: hidden;
will-change: transform;
}
.on {
animation: rotate 1.8s linear infinite;
transform-origin: center;
fill: #5daeea;
animation-delay: 2.8s;
visibility: hidden;
will-change: transform;
}
.end {
animation: rotate 2.8s;
transform-origin: center;
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;
fill: #5daeea;
visibility: hidden;
will-change: transform;
}
.end_timeout {
fill: #9ca2a5;
}
</style>
`;
if (variables.state_on && variables.timeout < 2000) {
return `${style}<g class="start">${path}</g><g class="on">${path}</g></svg>`;
}
if (variables.state === 'off' && variables.timeout < 2000) {
return `${style}<g class="end">${path}</g></svg>`;
}
if (variables.state_on && variables.timeout > 2000) {
return `${style}<g class="start_timeout">${path}</g></svg>`;
} else {
return `${style}<g class="end_timeout">${path}</g></svg>`;
}
]]]
icon_closet:
styles:
custom_fields:
icon:
- width: 80%
- margin-left: '-16%'
custom_fields:
icon: |
[[[
let room = `d="M11.4,1.4h27.2v43.1H11.4V1.4z" fill="#bcbcbc"`,
door = `d="M11.4 1.4v43.1h27.2V1.4H11.4zm23 23.4c0 1.1-.9 1.9-1.9 1.9h0c-1.1 0-1.9-.9-1.9-1.9V21c0-1.1.9-1.9 1.9-1.9h0c1.1 0 1.9.9 1.9 1.9v3.8z"`;
if (variables.state_on && variables.timeout < 2000) {
return `
<style>
.state {
animation: state 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
}
.opacity {
animation: opacity 0.5s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
}
@keyframes state {
0% {
transform: none;
fill: #9da0a2;
}
100% {
transform: skewY(10deg) translate(4.5%, -3.9%) scaleX(0.8);
fill: #b68349;
}
}
@keyframes opacity {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
</style>
<svg viewBox="0 0 50 50">
<path class="opacity" ${room}/>
<path class="state" ${door}/>
</svg>
`;
}
if (variables.state_on && variables.timeout > 2000) {
return `
<svg viewBox="0 0 50 50">
<style>
.state_timeout_on {
transform: skewY(10deg) translate(4.5%, -3.9%) scaleX(0.8);
fill: #b68349;
}
</style>
<path ${room}/>
<path class="state_timeout_on" ${door}/>
</svg>
`;
}
return variables.state === 'off' && variables.timeout < 2000 ? `
<style>
.state {
animation: state 0.4s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
}
.opacity {
animation: opacity 0.4s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;
}
.reverse {
animation-direction: reverse;
}
@keyframes state {
0% {
transform: none;
fill: #9da0a2;
}
100% {
transform: skewY(10deg) translate(4.5%, -3.9%) scaleX(0.8);
fill: #b68349;
}
}
@keyframes opacity {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
</style>
<svg viewBox="0 0 50 50">
<path class="opacity reverse" ${room}/>
<path class="state reverse" ${door}/>
</svg>
` : `
<svg viewBox="0 0 50 50">
<style>
.state_timeout_off {
fill: var(--state-icon-color);
}
</style>
<path class="state_timeout_off" ${door}/>
</svg>
`;
]]]
icon_away:
state_display: Auto
styles:
card:
- transition: all 0.3s ease-out
custom_fields:
icon:
- width: 79%
- margin-left: '-1%'
- margin-top: '-1%'
- fill: |
[[[ return variables.state_on ? '#516d82' : '#9da0a2'; ]]]
custom_fields:
icon: |
[[[
let state = variables.state_on ? 'on' : null;
return `
<svg viewBox="0 0 50 50">
<style>
@keyframes on {
10%,
20%,
100% {
transform: rotateZ(0deg);
}
30%,
50%,
70% {
transform: rotateZ(7deg);
}
90% {
transform: rotateZ(3deg);
}
40%,
60%,
80% {
transform: rotateZ(-7deg);
}
}
.on {
animation: on 1.35s cubic-bezier(0.5, 1, 0.89, 1);
animation-fill-mode: both;
transform-origin: 70% 80%;
animation-delay: 0s;
}
</style>
<path class="${state}" d="M32.1 18.4s.3-1.6.7-2.1c.3-.6.9-1.4 1.6-1.8.6-.4 1.1-.7 1.4-.7s.7-.1 1 .1.6.4.8 1.3l.3 2.7.1 2.4.2 4.1c0 .3.2 3.1.2 3.3s.2 2.7.2 3.2l-.1 2.5c.1 1.6.5 3.1-.2 4.6-.6 1.4-1.7 2.7-2.9 3.6-.5.4-1.9 1.3-2.9 1.7-1.1.5-2.2.8-3.3 1.1-.5.1-1.4.4-2.3.3s-1.8-.6-2.1-1l-1.6-2.3c-.6-.8-2.1-2.3-2.3-2.5l-2.7-2.8c-.2-.2-2.7-3.5-2.9-3.8l-3.1-4.7-1.8-3.2-1.5-2.8-.9-1.8c-.1-.2-.3-1.1-.2-1.4.3-1.2 1.4-1.4 2.3-.7.3.2.9 1 1.1 1.3s6.1 8.1 6.1 8.1c.2.3.7.3.9 0s-.1-.7-.2-.9c-.4-.6-8.3-11.5-8.3-11.5s-.6-.9-.7-1.1c-.3-1.1 0-2.3 1.1-2.7s1.9.3 2.6 1.1c.3.3 8.3 11.5 8.3 11.5.2.2.3.3.5.3.3 0 .5-.4.4-.7-.1-.2-.5-.9-.5-.9L11.8 9c-.6-1-.9-2-.1-3 .7-.8 2.2-1.3 3-.2.3.3 10.1 14.3 10.1 14.3.2.2.5.4.7.3.5-.1.3-.7.1-1-.1-.2-8.4-11.8-8.4-11.8-.4-.9-.6-2 .2-2.8 1-1.1 2.5-.5 3.3.5.2.3 1 1.4 1 1.4l2.7 3.7c.1.2 3.4 4.4 3.8 4.8.9 1.1 1.8 2.2 2.7 3.2l.5.5c.1.1.1.4.1.8 0 1.3.1 2.6.1 3.9 0 .2.1.4.2.6.3.3.6.1.7-.2.1-.2 0-2.4 0-2.7-.3-.3-.5-1.3-.4-2.9zM12.2 46.9s-2.8-.8-4.8-2.7-2.6-2.7-2.8-3-1.8-3-2-3.6c-.2-.5-.2-.7.2-1 .4-.4 1-.5 1.3.1.1.2.4 1 .5 1.2s1 1.9 1.7 2.8 1.6 2.2 4.4 3.8c.6.3 1.2.6 1.9.9.3.1.6.2.8.4.1.2.1.6-.1.8-.2.4-.7.4-1.1.3zM7.1 30.7l.9 3.1c.3.7 1.1 2.3 1.9 3.3s2.4 2.6 3.4 3.2 2 1.1 3 1.5c1 .3 1.1.4 1.2.5.3.4.2 1.2-.4 1.3-.2 0-1.2 0-1.8-.3L12 41.7c-.5-.4-3.9-3.1-5.1-6S5.3 31 5.2 30.4s-.2-1.1 0-1.4c.3-.4.9-.8 1.3-.3.2.3.3.6.3.9.1 0 .2.8.3 1.1zm26.8-25s.2-.1.5-.1.8.3 1.4.7 1.9 1 3.6 2.9 2.9 3.9 3.4 5.8c.5 1.8.8 3.1.9 5.5 0 .5.1 1.6 0 1.7-.2.5-.5.7-1 .7-.6 0-.7-.5-.7-1l-.1-2.9c-.1-.6-.3-1.9-.7-2.9-.3-1-.7-2.3-1.7-3.6-.9-1.3-2.1-2.8-3.2-3.5l-2.4-1.5c-.6-.6-.7-1.2 0-1.8zm4.9-2.5s.3-.2.5-.1c.2 0 .7.3.9.4s2.1 1.3 3.6 3c1.5 1.6 3.5 5.1 3.7 7.4.1.4.2.9 0 1-.2.2-.4.4-.7.4-.2 0-.5 0-.7-.1-.1-.2-.4-1.1-.4-1.3s-.6-2-1.1-3.1C44 9.7 43.5 8.5 42 7.1s-2.2-1.9-2.8-2.2-1.1-.6-1.1-1c.1-.3.3-.6.7-.7z"/>
</svg>
`;
]]]
icon_home:
state_display: Auto
styles:
card:
- transition: all 0.3s ease-out
custom_fields:
icon:
- width: 72%
- margin-left: '-1%'
- fill: |
[[[ return variables.state_on ? '#c7983e' : '#9da0a2'; ]]]
custom_fields:
icon: |
[[[
let state = variables.state_on ? 'on' : null;
return `
<svg viewBox="0 0 50 50">
<style>
@keyframes on {
from,
20%,
40%,
60%,
80%,
to {
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
}
0% {
transform: scale(0.3);
}
20% {
transform: scale(1.1);
}
40% {
transform: scale(0.9);
}
60% {
transform: scale(1.03);
}
80% {
transform: scale(0.97);
}
to {
transform: scale(1);
}
}
.on {
animation: on 1s;
transform-origin: center;
}
</style>
<path class="${state}" d="M42.2 28.3c0-.8-.2-1-.2-1L26 12.1s-.5-.4-1-.4-1 .3-1 .3L8.2 27.1c-.4.5-.4.9-.4.9v18.3c0 1.1.9 2 1.9 2h8.2a1.47 1.47 0 0 0 1.5-1.5v-14a1.47 1.47 0 0 1 1.5-1.5h8.4a1.47 1.47 0 0 1 1.5 1.5v14a1.47 1.47 0 0 0 1.5 1.5h8.2c1.1 0 2-.9 2-1.9 0-.2-.3-18.1-.3-18.1zM7.3 25l-1.6 1.5s-.3.3-.5.3-.5 0-.8-.2c-.2-.2-2-2.8-2-2.8s-.1-.4-.1-.7c.1-.3.2-.7.3-.8.4-.1 21.5-20.1 21.5-20.1s.4-.3.9-.3c.4 0 .8.1.9.2s.5.4.5.4l8.9 8.5V6s.1-.4.2-.7c.1-.2.3-.3.4-.3s.3-.1.3-.1h3s.3.1.4.3a1.08 1.08 0 0 1 .3.7v9.8l7.2 6.9s.2.3.3.4c.1.2.1.7.1.7 0 .1-.1.4-.2.5s-1.6 2.5-1.6 2.5-.1.3-.3.3c-.2.1-.4.1-.7 0-.2-.1-.5-.4-.5-.4L26.4 9.4s-.3-.3-.5-.4-.4-.2-.8-.2-.5.1-.8.1c-.1.1-.4.3-.7.5C23.3 9.8 7.3 25 7.3 25z"/>
</svg>
`;
]]]
views:
- title: Home
layout:
grid-template-columns: 25% 22.5% 22.5% 22.5%
grid-column-gap: 18pt
grid-template-rows: auto
grid-template-areas: |
"sidebar lights lights climate"
"sidebar media outlets security"
"sidebar footer footer footer"
type: custom:grid-layout
cards:
- type: custom:vertical-stack-in-card
cards:
- type: markdown
content: ' '
- type: markdown
content: ' {{ states(''sensor.time'') }}'
card_mod:
style: |
ha-card {
font-size: 60px;
font-weight: 250;
}
- type: markdown
content: >-
{{ now().strftime('%A') }}, {{ now().strftime('%B') }} {{
now().day }}
card_mod:
style: |
ha-card {
font-size: 15px;
font-weight: 300;
}
- type: custom:mushroom-title-card
title: ' '
- type: custom:simple-weather-card
entity: weather.home
name: Afară-prognoză
backdrop:
day: '#40445a'
night: '#40445a'
primary_info:
- wind_bearing
- humidity
secondary_info:
- precipitation
- precipitation_probability
- type: custom:mushroom-template-card
primary: Lumini
secondary: '{{ states(''sensor.lights_on_dashboard_counter'') }}'
icon: mdi:lightbulb
icon_color: |-
{% if states('sensor.lights_on_counter') == '0' %}
disabled
{% else %}
amber
{% endif %}
tap_action:
action: none
- type: custom:mushroom-template-card
entity: sensor.camera_de_zi_temperature
icon: mdi:thermometer
icon_color: cyan
primary: '{{ states(''sensor.camera_de_zi_temperature'') }}°C'
secondary: Temperatură living
tap_action:
action: more-info
- type: custom:mushroom-template-card
entity: sensor.camera_de_zi_humidity
icon: mdi:water
icon_color: cyan
primary: '{{ states(''sensor.camera_de_zi_humidity'') }} %Rh'
secondary: Umiditate living
tap_action: null
action: more-info
- type: custom:mushroom-template-card
primary: >-
{{ states("sensor.koogeek_p1_6c7bf8_power") |float
states("sensor.tp_link_smart_plug_8e87_current_consumption") |
float +
states("sensor.tp_link_smart_plug_c07e_current_consumption") |
float +
states("sensor.tp_link_smart_plug_feea_current_consumption") |
float +
states("sensor.tp_link_smart_plug_cf21_current_consumption") |
float }}W
secondary: Consum energie
icon: mdi:lightning-bolt
icon_color: green
tap_action:
action: none
badge_icon: ''
badge_color: ''
- type: custom:mushroom-template-card
primary: '{{ states(''counter.sheetchangecounter'') }} nights'
secondary: since last sheets change
icon: mdi:bed
icon_color: indigo
badge_icon: |-
{% if states('counter.sheetchangecounter') >= 20 %}
mdi:clock
{% else %}
null
{% endif %}
badge_color: |-
{% if states('counter.sheetchangecounter') >= 20 %}
red
{% else %}
null
{% endif %}
- type: custom:button-card
name: Acțiuni rapide
styles:
name:
- justify-self: start
- padding-left: 20px
- font-weight: bold
- font-size: 15pt
- type: custom:mushroom-template-card
entity: null
primary: Charge watch for 25 minutes
secondary: |-
{% if states('timer.watch_charger_timer') == 'active' %}
Now Charging - {% set f = state_attr('timer.watch_charger_timer', 'finishes_at') %}
{{ '00:00:00' if f == None else
(as_datetime(f) - now()).total_seconds() | timestamp_custom('%M', false) }} mins remaining
{% else %}
Tap to start charging
{% endif %}
icon: phu:apple-watch
icon_color: |-
{% if states('timer.watch_charger_timer') == 'active' %}
orange
{% else %}
grey
{% endif %}
double_tap_action:
action: none
hold_action:
action: none
tap_action:
action: call-service
service: automation.trigger
target:
entity_id: automation.watch_charger_timer_manual_start
data:
skip_condition: false
badge_icon: |-
{% if states('timer.watch_charger_timer') == 'active' %}
mdi:clock
{% else %}
null
{% endif %}
badge_color: |-
{% if states('timer.watch_charger_timer') == 'active' %}
orange
{% else %}
null
{% endif %}
- type: custom:mushroom-template-card
primary: |-
{% if states('switch.virtual_switch_1') == 'on' %}
Disable motion sensor
{% else %}
Enable motion sensor
{% endif %}
secondary: |-
{% if states('switch.virtual_switch_1') == 'on' %}
Automations are currently enabled
{% else %}
Automations are currently disabled
{% endif %}
icon: phu:motion-sensor
badge_icon: |-
{% if states('switch.virtual_switch_1') == 'off' %}
null
{% endif %}
badge_color: |-
{% if states('switch.virtual_switch_1') == 'on' %}
null
{% else %}
red
{% endif %}
icon_color: |-
{% if states('switch.virtual_switch_1') == 'on' %}
grey
{% else %}
red
{% endif %}
tap_action:
action: toggle
entity: null
view_layout:
grid-area: sidebar
card_mod:
style: |
ha-card {
border-radius: 0pt
}
resources:
- url: /local/simple-weather-card-bundle.js?v=0.8.5
type: module
- square: true
type: grid
resources:
- url: /hacsfiles/button-card/button-card.js
type: module
cards:
- type: custom:button-card
template:
- circle
- light
entity: switch.bucatarie_switch_1
name: Bucătărie
icon: mdi:lightbulb
size: 80%
show_state: true
aspect_ratio: 1/1
- type: custom:button-card
template:
- circle
- light
entity: switch.living1_switch_1
name: Living 1
icon: mdi:lightbulb
size: 80%
show_state: true
aspect_ratio: 1/1
- type: custom:button-card
template:
- circle
- light
entity: switch.living2_switch_1
name: Living 2
icon: mdi:lightbulb
size: 80%
show_state: true
aspect_ratio: 1/1
- type: custom:button-card
template:
- circle
- light
entity: switch.aubess_smart_switch_test_switch_1
name: Hue Go
icon: phu:go
size: 80%
show_state: true
aspect_ratio: 1/1
- type: custom:button-card
template:
- circle
- light
entity: null
name: Bed LEDs
icon: phu:light-strip
size: 80%
show_state: true
aspect_ratio: 1/1
- type: custom:button-card
template:
- circle
- light
entity: null
name: Ceiling LEDs
icon: phu:light-strip
size: 80%
show_state: true
aspect_ratio: 1/1
- type: custom:button-card
template:
- circle
- light
entity: null
name: Filament Bulb
size: 80%
show_state: true
aspect_ratio: 1/1
- type: custom:button-card
template: base
entity: null
name: String Lights
icon: mdi:string-lights
size: 80%
show_state: true
aspect_ratio: 1/1
columns: 4
title: Lumini
view_layout:
grid-area: lights
- square: true
type: grid
cards:
- type: custom:button-card
template:
- base
entity: null
name: Ceiling Fan
icon: phu:ceiling-fan
size: 80%
show_state: true
aspect_ratio: 1/1
double_tap_action:
action: more-info
- type: custom:button-card
template: base
entity: switch.aubess_smart_switch_test_switch_1
name: Fan Trigger
icon: mdi:thermostat
size: 80%
show_state: true
aspect_ratio: 1/1
tap_action:
action: call-service
service: browser_mod.popup
data:
dismissable: true
autoclose: false
content:
type: custom:mushroom-number-card
entity: null
display_mode: buttons
icon_color: primary
title: Edit Temperature
target:
entity_id: null
- type: custom:button-card
template:
- circle
- light
entity: null
name: Temperature Sensor
size: 80%
show_state: true
aspect_ratio: 1/1
- type: custom:button-card
template:
- circle
- light
entity: null
name: Ambient Light
icon: mdi:brightness-5
size: 80%
show_state: true
aspect_ratio: 1/1
columns: 2
title: Climă/Ventilație
view_layout:
grid-area: climate
- square: false
type: grid
columns: 1
title: Media
cards:
- type: custom:mini-media-player
entity: media_player.family_room_speaker
artwork: full-cover
max_volume: '56'
info: scroll
view_layout:
grid-area: media
- square: true
type: grid
cards:
- type: custom:button-card
template:
- base
entity: null
icon_color: green
name: Bedroom Outlet
icon: mdi:power-plug
size: 80%
show_state: true
aspect_ratio: 1/1
state:
- value: 'on'
styles:
icon:
- color: rgb(0, 175, 0)
- type: custom:button-card
template: base
entity: null
name: Sound Machine
icon: mdi:power
size: 80%
show_state: true
aspect_ratio: 1/1
state:
- value: 'on'
styles:
icon:
- color: rgb(0, 175, 0)
- type: custom:button-card
template: base
entity: null
name: Tablet Charger
color_type: icon
color: rgb(255, 128, 199)
size: 80%
show_state: true
aspect_ratio: 1/1
state:
- value: 'on'
styles:
icon:
- color: rgb(0, 175, 0)
- type: custom:button-card
template: base
entity: null
name: Watch Charger
icon: mdi:lightning-bolt
size: 80%
show_state: true
aspect_ratio: 1/1
state:
- value: 'on'
styles:
icon:
- color: rgb(0, 175, 0)
columns: 2
title: Outlets
view_layout:
grid-area: outlets
- square: true
type: grid
cards:
- type: custom:button-card
template:
- base
entity: null
name: Security System
icon: mdi:shield-lock
size: 80%
show_state: true
aspect_ratio: 1/1
tap_action:
action: more-info
- type: custom:button-card
template: base
entity: null
name: Motion Sensor
icon: mdi:motion-sensor-off
state_display: null
color_type: icon
size: 80%
show_state: true
aspect_ratio: 1/1
state:
- value: 'on'
icon: mdi:motion-sensor
styles:
icon:
- color: rgb(0, 175, 0)
- type: custom:button-card
template: base
entity: null
name: Door
icon: mdi:door
state_display: null
size: 80%
show_state: true
aspect_ratio: 1/1
state:
- value: 'on'
icon: mdi:door-open
styles:
icon:
- color: rgb(235, 0, 0)
- type: custom:button-card
template: base
entity: null
name: Window
icon: mdi:window-closed
state_display: null
size: 80%
show_state: true
aspect_ratio: 1/1
state:
- value: 'on'
icon: mdi:window-open
styles:
icon:
- color: rgb(235, 0, 0)
hold_action:
action: call-service
service: browser_mod.refresh
target:
entity_id: media_player.BROWSER_MOD_ENTITY_HERE
columns: 2
title: Security
view_layout:
grid-area: security
Sorry for creating so many replies, but the code was too long…and couldn’t paste it.
Whoever provided you this is doing you a disservice by loading you down with a super complex dashboard that you’re not able to understand or maintain yourself.
Unless you personally wrote all this (in which case I would guess you’d know the source of the problem or at least would only post the specific part you need help with instead of your entire dashboard), you would be better served using HA-stock or HACS provided custom cards for adding the animation affects that most of this custom javascript seems geared toward providing.
There are a lot of great examples on this forum and elsewhere that can provide inspiration for dashboards that look great and are easier to setup and maintain. Here’s one set of examples.
All that said, my best guess is that this line is the problem:
<img src="/local/loader.svg" width="100%">
Do you actually have this file? You can check by going to <YOUR_HA_URL>/local/loader.svg
(perhaps http://homeassistant.local:8123/local/loader.svg if you have a common setup) in your browser. If you have samba or ssh or any of the other add-ons that would let you see the files, you can also check to see if /config/www/loader.svg
exists.