hexadecimal
{{ 0x680ae2fffe82bf8b == "0x680ae2fffe82bf8b" }}
// False
untested but try this
{% set lights = [
states.switch['0x680ae2fffe82bf8b'],
states.switch['0x842e14fffe7f2dd9']
] %}
hexadecimal
{{ 0x680ae2fffe82bf8b == "0x680ae2fffe82bf8b" }}
// False
untested but try this
{% set lights = [
states.switch['0x680ae2fffe82bf8b'],
states.switch['0x842e14fffe7f2dd9']
] %}
Once again, you are my hero
Thanks !
I have two things i need help with.
I cannot get the cards to look right. The icons and text doesn’t line up correctly. See picture below
I cannot get the packground image to show. Where do i add background image?
I have removed extra styles (extra_styles) to resolve problem.
Have you followed all the steps outlined in the installation instructions? hass-config/INSTALL.md at 132cbbd2f8c4b29f4c100cf9a4e99327094049a9 · matt8707/hass-config · GitHub
Given just the screenshot I can’t tell what the issue is.
In the www folder see hass-config/www at master · matt8707/hass-config · GitHub
Did you have a fix for this issue? Initially my loader.svg image was missing but is is definitly in the folder now. But still have the same issue as you have or had.
Would be great to learn if you fixed it and in which way.
Or to the others, how to fix the issue that the loader.svg is not popping up in the cards.
It shows a missing picture icon, whilst loader.svg is placed in the www folder.
Hi. Did you find how to fix this ? I have the same problem
Did you reload the dashboard page after loading the loader.svg?
I had the same issue and I just copied all the images in the www folder from the GitHub to my HA folder. After reloading the page (and closing and reopening the app on the phone) the load animation started working correctly on both.
Somehow it started working today out of the blue, I restared home assistant, reload the dashboard on the browser aswell. But at that time didn’t work.
So it is fixed now
No. Sorry didn’t have enough time ;-(
Has someone added a progressbar for the duration of a actually playing movie in the Media card?
Can anyone tell me why I can’t go further to the left? Or what I have to change so that I can get further to the left?
- type: conditional
conditions:
- entity: select.conditional_media
state: Kueche
card:
type: custom:button-card
template:
- conditional_media
- icon_apple_tv
entity: media_player.kueche
custom_fields:
progress:
card:
type: custom:bar-card
height: 0.4em
entities:
- entity: sensor.appletv_kueche_progress
positions:
icon: 'off'
indicator: 'off'
name: 'off'
value: 'off'
color: >
[[[ return 'var(--primary-color)'; ]]]
max: '100'
min: '0'
target: '0'
decimal: '2'
unit_of_measurement: ' '
severity:
- hide: true
styles:
custom_fields:
progress:
- position: absolute
- width: 100%
- height: 100%
- margin: 70% 10% 0 0
- display: initial
- opacity: 1
- justify-self: end
```
I’ve been trying to figure out the PS5 integration! Would you mind sharing your code?
Add sensor.ps5_activity
as if it was a media player in packages/tv_media.yaml
To get the other info you’ll need to add some checks in button_card_templates/media.yaml
for entity.attributes.title_image
and entity.attributes.title_name
.
I edited my file pretty heavily so I just applied the edits to the original one. It should work, but let me know if it doesn’t.
button_card_templates/media.yaml
#################################################
# #
# BASE MEDIA #
# #
#################################################
base_media:
variables:
media_on: >
[[[ return !entity || ['playing', 'paused'].indexOf(entity.state) !== -1; ]]]
media_off: >
[[[ return !entity || ['off', 'idle', 'standby', 'unknown', 'unavailable', 'none'].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: >
[[[
let game_image = entity.attributes.title_image;
if (variables.is_youtube) {
return `#efefef`;
} else {
return entity && game_image !== undefined
? '#efefef'
: variables.media_on && variables.entity_picture === undefined
? 'rgba(0, 0, 0, 0.6)'
: variables.media_off
? '#97989c'
: '#efefef';
}
]]]
- text-shadow: >
[[[
let game_image = entity.attributes.title_image;
if (variables.is_youtube) {
return `1px 1px 5px rgba(18, 22, 23, 0.9)`;
} else {
return entity && game_image !== undefined
? '1px 1px 5px rgba(18, 22, 23, 0.9)'
: variables.media_off || variables.entity_picture === undefined
? 'none'
: '1px 1px 5px rgba(18, 22, 23, 0.9)';
}
]]]
#################################################
# #
# MEDIA #
# #
#################################################
media:
template:
- base
- base_media
styles:
custom_fields:
icon:
- width: 70%
- margin-left: 2%
- fill: '#9da0a2'
- display: >
[[[
let game_image = entity.attributes.title_image;
if (variables.is_youtube) {
return `none`;
}
else {
return entity && game_image !== undefined
? 'none'
: variables.media_off || variables.entity_picture === undefined
? 'initial'
: 'none';
}
]]]
card:
- background-color: none
- background-size: cover
- background-position: center
- background-image: >
[[[
let game_image = entity.attributes.title_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 entity && game_image !== undefined
? `linear-gradient(0deg, rgba(0,0,0,.8) 0%, rgba(0,0,0,0) 100%), url(${game_image})`
: 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 #
# #
#################################################
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,
game_title = entity.attributes.title_name;
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
: game_title !== undefined
? `${game_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: &media_background_image >
[[[
if (entity) {
if (variables.is_youtube) {
return `url(${states[this._config?.triggers_update].state})`;
} else {
let data = entity.attributes.data,
game_image = entity.attributes.title_image;
return game_image !== undefined
? `url("${game_image}")`
: 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: *media_background_image
- 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 ' ';
]]]
Then you’ll also need to add sensor.ps5_activity
as if it was a media player in ui-lovelace.yaml
(this is the media section only and you only need to add the PlayStation bits)
#################################################
# #
# MEDIA #
# #
#################################################
- type: grid
title: Media
view_layout:
grid-area: media
columns: 1
cards:
- type: custom:swipe-card
parameters:
speed: 550
spaceBetween: 40
threshold: 5
cards:
- type: horizontal-stack
cards:
- type: conditional
conditions:
- entity: select.conditional_media
state_not: Shield TV
- entity: select.conditional_media
state_not: Master Bedroom TV
- entity: select.conditional_media
state_not: PS5 Activity
- entity: select.conditional_media
state_not: Garage TV
- entity: select.conditional_media
state_not: Upstairs TV
card:
type: custom:button-card
entity: sensor.plex_recently_added
name: Recently Added
tap_action:
action: none
template:
- conditional_media
- icon_plex
- type: conditional
conditions:
- entity: select.conditional_media
state: Shield TV
card:
type: custom:button-card
entity: media_player.shield_tv_plex
triggers_update: sensor.youtube_watching
template:
- conditional_media
- icon_shield_tv
- type: conditional
conditions:
- entity: select.conditional_media
state: Master Bedroom TV
card:
type: custom:button-card
entity: media_player.master_bedroom_tv_plex
triggers_update: sensor.youtube_watching
template:
- conditional_media
- icon_google_tv
- type: conditional
conditions:
- entity: select.conditional_media
state: Upstairs TV
card:
type: custom:button-card
entity: media_player.upstairs_tv_plex
triggers_update: sensor.youtube_watching
template:
- conditional_media
- icon_google_tv
- type: conditional
conditions:
- entity: select.conditional_media
state: PS5 Activity
card:
type: custom:button-card
entity: sensor.ps5_activity
template:
- conditional_media
- icon_playstation
- type: conditional
conditions:
- entity: select.conditional_media
state: Garage TV
card:
type: custom:button-card
entity: media_player.garage_tv_plex
template:
- conditional_media
- icon_google_tv
- type: grid
columns: 2
cards:
- type: custom:button-card
entity: media_player.shield_tv_plex
triggers_update: sensor.youtube_watching
name: Shield TV
template:
- media
- icon_shield_tv
- type: custom:button-card
entity: media_player.master_bedroom_tv_plex
triggers_update: sensor.youtube_watching
name: Master Bedroom TV
template:
- media
- icon_google_tv
- type: custom:button-card
entity: sensor.ps5_activity
name: PS5 Activity
template:
- media
- icon_playstation
- type: custom:button-card
entity: media_player.garage_tv_plex
name: Garage TV
template:
- media
- icon_google_tv
- type: grid
columns: 2
cards:
- type: custom:button-card
entity: media_player.upstairs_tv_plex
triggers_update: sensor.youtube_watching
name: Upstairs TV
template:
- media
- icon_google_tv
and I made a PlayStation icon to match the other media player icons.
button_card_templates/icons.yaml
icon_playstation:
custom_fields:
icon: >
<svg viewBox="0 0 50 50">
<path d="M49.5,11.8l-0.2-2.4c-0.5-2.7-2.1-4.9-4.2-6.6c-1.9-1.6-4.1-2.4-6.7-2.4L27.5,0.3L11,0.4c-0.5,0-0.9,0-1.4,0.1 C7.8,0.8,6.2,1.6,4.8,2.7C1.9,5,0.5,7.9,0.4,11.5v26.7c0.1,1.1,0.1,2,0.3,3C1.4,43.8,3,45.8,5,47.4c1.9,1.4,4.1,2.2,6.5,2.2 l13.7,0.1c0,0,13.3-0.1,13.4-0.2c0.7,0,1.3-0.1,1.9-0.2c2.8-0.6,5.1-2.2,6.8-4.4c1.3-1.7,2.1-3.7,2.2-5.9l0.1-6.7L49.5,11.8z M19.2,29.1l-6.2,2.2c-1.1,0.4-1.3,0.9-0.4,1.2c0.9,0.3,2.5,0.2,3.6-0.2l3-1.1v3.1c-0.2,0-0.4,0.1-0.6,0.1c-3,0.5-6.1,0.3-9.2-0.7 c-2.9-0.8-3.4-2.5-2.1-3.5c1.2-0.9,3.3-1.6,3.3-1.6l8.5-3V29.1z M26.3,15.9V38l-6-1.9V9.7c2.5,0.5,6.2,1.6,8.2,2.3 c5,1.7,6.8,3.9,6.8,8.8c0,4.7-2.9,6.5-6.6,4.7v-8.8c0-1-0.2-2-1.2-2.3C26.8,14.1,26.3,14.8,26.3,15.9z M43,31.3 c-0.7,0.9-2.5,1.5-2.5,1.5l-13,4.7v-3.5l9.6-3.4c1.1-0.4,1.3-0.9,0.4-1.2c-0.9-0.3-2.5-0.2-3.6,0.2l-6.4,2.3v-3.6l0.4-0.1 c0,0,1.8-0.7,4.4-0.9c2.6-0.3,5.8,0,8.3,1C43.4,29.1,43.7,30.4,43,31.3z"/>
</svg>
It should look something like this
EDIT: edited base media variables to include ‘none’ in media_off
media_off: >
[[[ return !entity || ['off', 'idle', 'standby', 'unknown', 'unavailable', 'none'].indexOf(entity.state) !== -1; ]]]
EDIT2: line 95 media.yaml
let game_image = entity.attributes.title_image;
okay i get it to work,
but when i use my mobile or tablet it the progress moves a little bit to the right and top. But i use % as margin values.
here on my phone
i updatet the grid
styles:
grid:
- grid-template-areas: |
"icon circle"
"progress progress"
"n n"
"s s"
- grid-template-columns: repeat(2, 1fr)
- grid-template-rows: auto repeat(3, min-content)
- gap: 1.3%
- align-items: start
and added the #progress to the extra_styles
extra_styles: >
[[[
if (entity) {
let hs = entity.attributes.hs_color === undefined,
h = hs || entity.attributes.hs_color[0],
s = hs || entity.attributes.hs_color[1],
l_min = 28,
l_max = 48,
l_calc = entity.attributes.brightness / 2.54 * (l_max - l_min) / 100 + l_min;
var light_color = entity.attributes.color_mode === 'color_temp' || entity.attributes.color_mode === 'brightness'
? `hsl(204, 58%, ${l_calc}%);`
: `hsl(${h}, ${s}%, ${l_calc}%);`;
}
return `
svg {
--light-color:
${ variables.state_on && entity.attributes.brightness !== undefined
? light_color
: variables.state_on && entity.attributes.brightness === undefined
? 'var(--state-icon-active-color);'
: 'var(--state-icon-color);'
}
}
#container {
text-align: left !important;
}
#name, #state {
font-size: 1.32vw;
letter-spacing: -0.02vw;
}
#state::first-letter {
text-transform: uppercase;
}
/* portrait */
@media screen and (max-width: 1200px) {
#name, #state {
font-size: 2vw;
}
}
/* phone */
@media screen and (max-width: 800px) {
#name, #state {
font-size: 3vw;
}
}
/* tilt */
#ripple, .js-tilt-glare {
clip-path: inset(0 round var(--custom-button-card-border-radius));
overflow: hidden;
}
.js-tilt-glare {
z-index: 1;
}
.js-tilt-glare-inner {
background-color: rgba(0,0,0,0.9);
}
#container {
transform: translateZ(${variables.tilt_options.parallax});
}
#card {
transform-style: preserve-3d;
overflow: visible;
}
${this._config.template.includes('conditional_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(--custom-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') ? `
:host {
--name-font-size: 1.22vw;
--name-icon-size: 1.5vw;
--notify-font-size: 0.9vw;
--notify-box-size: 1.8vw;
--name-padding-v: 0.7vw;
--name-padding-h: 1.1vw;
--progress-padding-v: 0.7vw;
--progress-padding-h: 1.1vw;
--card-border-radius: 0.6vw;
}
#ripple, .js-tilt-glare {
border-radius: calc(var(--card-border-radius) - 0.1vw);
clip-path: inset(0 round calc( var(--custom-button-card-border-radius) - 0.1vw ));
}
#progress {
padding: var(--progress-padding-v) var(--progress-padding-h);
}
#name {
font-size: var(--name-font-size);
padding: var(--name-padding-v) var(--name-padding-h);
letter-spacing: 0.012vw;
}
ha-icon {
width: var(--name-icon-size);
vertical-align: 7%;
padding-right: 0.1vw;
opacity: 0.4;
}
#card {
border-radius: var(--card-border-radius);
background: rgba(115, 115, 115, 0.04);
}
#notify {
font-size: var(--notify-font-size);
width: var(--notify-box-size);
height: var(--notify-box-size);
line-height: var(--notify-box-size);
padding-right: 0.5px;
padding-top: 0.5px;
}
/* portrait */
@media screen and (max-width: 1200px) {
#name {
font-size: calc(var(--name-font-size) * 1.4);
padding: calc(var(--name-padding-v) * 1.4) calc(var(--name-padding-h) * 1.4);
}
#progress {
padding: calc(var(--progress-padding-v) * 1.4) calc(var(--progress-padding-h) * 1.4);
}
ha-icon {
width: calc(var(--name-icon-size) * 1.4);
}
#card {
border-radius: calc(var(--card-border-radius) * 1.4);
margin: 0 0.5vw;
}
#notify {
font-size: calc(var(--notify-font-size) * 1.4);
width: calc(var(--notify-box-size) * 1.4);
height: calc(var(--notify-box-size) * 1.4);
line-height: calc(var(--notify-box-size) * 1.4);
}
}
/* phone */
@media screen and (max-width: 800px) {
#name {
font-size: calc(var(--name-font-size) * 2.7);
padding: calc(var(--name-padding-v) * 2.7) calc(var(--name-padding-h) * 2.7);
letter-spacing: 0.12vw;
}
#progress {
margin: calc(var(--progress-padding-v) * 2.7) calc(var(--progress-padding-h) * 2.7);
}
ha-icon {
width: calc(var(--name-icon-size) * 2.7);
}
#card {
border-radius: calc(var(--card-border-radius) * 2.7);
background: rgba(115, 115, 115, 0.08);
margin: 0 0.5vw;
}
#notify {
font-size: calc(var(--notify-font-size) * 2.7);
width: calc(var(--notify-box-size) * 2.7);
height: calc(var(--notify-box-size) * 2.7);
line-height: calc(var(--notify-box-size) * 2.7);
padding: 0;
}
}
`:''}
`
]]]
but still no change, any ideas perhaps`?
I updated browser-mod today now double tap isn’t working. Is that a known issue - I didn’t see anything in the docs?
Edit: required a cache clear to fix.
Thanks for sharing your code! I copied your code over to mine exactly, but now I am now seeing the below javascript error on all media button cards:
ButtonCardJSTemplateError: ReferenceError: game_image is not defined in ‘game_image = entity.attributes.title_image;
if (variables.is_youtube) {
return `linear-gra…’
I must be missing something. Also verified that the PS5 integration is active:
My bad. media.yaml line 95 add let
in front of game_image = entity.attributes.title_image;
...
- background-image: >
[[[
let game_image = entity.attributes.title_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})`;
}
...
how did you create this sensor?