did you found a solution? get the same problem
I’ve just finished bleeding of the setup for the old one, I will enjoy it for a while before to try the new!
yeah and its still pre beta… not really all the functions and bugs. You can’t make it the default Dashboard, what is a no go atm.
I got a request via chat to add some more picture, if naybody like I can add the adapted code for my personal need which I have taken out of these thread
Büro/Office: I add in all main rooms icons in the upper right corner which indicate if the radiator is on or off, if on then the icon is blue. Beside the temp icon I add an window open or close icon which check if window open detection is on then there is an grey icon and when the window is detected as open over the radiator then the icon is blue.
By the weather part I just add a fourth indication and middle the whole part for my person look and feel.
The radiator background gets white when heating is on, the icon gets blue and the valve state of the ventil is under the icon whit the related value. When the radiator is in eco mode the icon will be green otherwise gray as above. Current temp is in the circle and on the left side the expected temp.
Dishwasher integration with related pop up taken from Ngoc git.
Add small icon for blink cameras, pi-hole, low battery, ambilight, light who are on and battery state of the tablet.
Media part actually with gallery function, which is played stored pictures when no media.player is playing. Currently I´m adding trakt as sensor which is working and maybe add kodi as well.
The popup for the lights filter first and second floor and show only active lamps.
Battery icon everywhere where it is needed appear when battery is low.
All set up flexible as possible for me over variables to add the additional function icons everywhere I need to have them.
Hello, I have been trying to implement this now for some days but I’m struggling with the background of the popup. I can’t find anywhere where it gets its background. Can you please point me in the right direction?
Thx.
Hello, can you share the codes, I’m interested in the ones from the thermostats. Tnx
Hi, here the code for the radiator:
I split the battery and valve parts, so that I can add them in other cards where I want to have these parts alone.
- type: custom:button-card
entity: climate.wohnzimmer
name: Front
show_state: false
tap_action:
action: more-info
custom_fields:
graph:
card:
entities:
- entity: sensor.wohnzimmer_temperature
- entity: sensor.wohnzimmer_position
color: gray
y_axis: secondary
variables:
valve: '[[[ return states["sensor.wohnzimmer_position"].state]]]'
battery_temp: '[[[ return states["sensor.wohnzimmer_battery"].state]]]'
triggers_update:
- sensor.wohnzimmer_temperature
- sensor.wohnzimmer_position
template: [valve, radiator, battery_temp]
radiator:
template:
- base
- circle
variables:
state: >
[[[
return entity?.attributes.hvac_action;
]]]
state_on: >
[[[
return entity?.attributes.hvac_action === 'heating';
]]]
circle_input: >
[[[
if (entity) {
const temp = entity.attributes.current_temperature;
return parseFloat(temp).toFixed(1);
}
]]]
circle_input_unit: '°C'
state_display: >
[[[ return entity.attributes.hvac_action === 'idle' ? 'Aus' : 'Heizen'; ]]]
custom_fields:
graph:
card:
type: "custom:mini-graph-card"
height: 140
hours_to_show: 24
points_per_hour: 1
line_width: 8
font_size: 75
decimals: 0
show:
name: false
icon: false
state: false
legend: false
points: false
fill: fade
animate: true
color_thresholds:
- color: '#276696'
value: 17
- color: '#22878c'
value: 18
- color: '#228c3d'
value: 19
- color: '#d35400'
value: 20
- color: '#e6370b'
value: 21
- color: '#cc1f08'
value: 22
card_mod:
style: |
:host{
--ha-card-border-width: 0px;
}
icon: |
[[[
var action = entity.attributes.hvac_action;
var eco_mode = entity.attributes.eco_mode;
var state = entity.state;
var svg_color;
if (state === 'off') {
svg_color = '#127612';
} else if (action === 'heating') {
svg_color = '#3182b7';
} else if (action === 'idle' && eco_mode === 'ON') {
svg_color = '#127612';
} else {
svg_color = '#97989c';
}
var temperature = entity.attributes.temperature;
var current_temperature = entity.attributes.current_temperature;
var text_color;
if (temperature === current_temperature) {
text_color = '#97989c'; // Grau, wenn gleich
} else {
text_color = action === 'heating' ? '#3182b7' : (action === 'idle' && eco_mode === 'ON' ? '#127612' : '#3182b7');
}
return `<div style="display: flex; align-items: center; justify-content: flex-start; position: relative; width: 87%;">
<svg viewBox="-949 951 100 125"><style>@keyframes animate{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);}}.animate{animation: animate 0.8s; transform-origin: center;}</style>
<path fill="#9da0a2" d="M-895.9,1020.1v-56.7c0-5.5-4.5-10-10-10c-5.5,0-10,4.5-10,10v56.7c-3.7,3-6,7.6-6,12.4c0,8.8,7.2,16,16,16 c8.8,0,15.9-7.2,15.9-16C-890,1027.7-892.2,1023.1-895.9,1020.1z M-905.9,1045.1c-6.9,0-12.5-5.6-12.5-12.5c0-4.4,2.3-8.4,6-10.7 v-58.4c0-3.6,2.9-6.6,6.6-6.6c3.6,0,6.6,2.9,6.6,6.6v58.4c3.6,2.3,6,6.3,6,10.7C-893.4,1039.5-899,1045.1-905.9,1045.1z"/>
<path fill="${svg_color}" d="M-902.8,1024v-22.9c0-1.7-1.4-3.1-3.1-3.1c-1.7,0-3.1,1.4-3.1,3.1v22.9c-3.5,1.3-6,4.6-6,8.5c0,5,4.1,9.1,9.1,9.1 c5,0,9.1-4.1,9.1-9.1C-896.8,1028.6-899.3,1025.3-902.8,1024z"/>
<rect fill="#9da0a2" x="-892.4" y="974.9" width="7.7" height="3.4"/>
<rect fill="#9da0a2" x="-892.4" y="986.3" width="16.3" height="3.4"/>
<rect fill="#9da0a2" x="-892.4" y="997.6" width="7.7" height="3.4"/>
<rect fill="#9da0a2"v x="-892.4" y="1008.9" width="16.3" height="3.4"/>
</svg>
<span style="position: absolute; right: -12%; top: 5%; transform: translateY(-50%); font-size: calc(var(--button-card-font-size) * 0.6);">${temperature}°C</span>
</div>`;
]]]
styles:
card:
- background-color: >
[[[
return entity?.attributes.hvac_action === 'heating'
? 'rgba(255, 255, 255, 0.85)'
: 'rgba(115, 115, 115, 0.25)';
]]]
- color: >
[[[
return entity?.attributes.hvac_action === 'heating'
? '#3182b7'
: '#97989c';
]]]
custom_fields:
icon:
- width: 108%
- margin-left: -27%
temperature:
- font-size: calc(var(--button-card-font-size) * 0.6)
- right: 10%
- top: 50%
- transform: translateY(-50%)
graph:
- bottom: 0%
- left: 0%
- width: 130%
- position: absolute
- margin: 0% 0% -13% -15%
circle:
- display: initial
- width: 90%
- margin: -6% -5% 0 0
- justify-self: end
- opacity: 1
- --c-fill-color-on: rgba(255,255,255,0.04)
- --c-stroke-color-on: '#3182b7'
- --c-fill-color-off: rgba(255,255,255,0.04)
- --c-stroke-color-off: 'none'
style: |
ha-card {
box-shadow: none;
}
name:
- place-self: start
- margin-top: -55%
valve:
styles:
custom_fields:
valve:
- position: absolute
- right: -6%
- top: 58%
- font-size: calc(var(--button-card-font-size) * .2 * var(--card-phone))
- transition: top 250ms ease-out
- '--text-color-sensor': >-
[[[
var hvac_action = states[entity.entity_id].attributes.hvac_action;
if (hvac_action === 'heating' || variables.valve > 50) return "#3182b7";
else if (variables.valve >= 1 && hvac_action === 'heating') return "#3182b7";
return "#97989c";
]]]
custom_fields:
valve: |
[[[
var hvac_action = states[entity.entity_id].attributes.hvac_action;
var valve_icon = hvac_action === 'heating' ? 'open' : 'closed';
return `<ha-icon icon="mdi:valve-${valve_icon}" style="width:10%; color: var(--text-color-sensor);"></ha-icon><span>${variables.valve}%</span>`;
]]]
battery_temp:
custom_fields:
battery_temp: |
[[[
if (variables.battery_temp == '100') {
return `<ha-icon icon="" style="width:100%;display:flex;color: #EF4F1A;"></ha-icon>`;
}
if (variables.battery_temp == 'unavailable') {
return `<ha-icon icon="mdi:battery-alert-variant-outline" style="width:100%;display:flex;display:flex;color: #EF4F1A;"></ha-icon>`;
}
if (variables.battery_temp <= '10') {
return `<ha-icon icon="mdi:battery-alert-variant-outline" style="width:100%;display:flex;color: #EF4F1A;"></ha-icon>`;
}
if (variables.battery_temp <= '20') {
return `<ha-icon icon="mdi:battery-20" style="width:100%;display:flex;color: #EF4F1A;"></ha-icon>`;
}
if (variables.battery_temp == 'on') {
return `<ha-icon icon="mdi:battery-alert-variant-outline" style="width:100%;display:flex;color: #EF4F1A;"></ha-icon>`;
}
else {
return `<ha-icon icon="" style="width:100%;display:flex;color: #EF4F1A;"></ha-icon>`;
}
]]]
styles:
custom_fields:
battery_temp:
- position: absolute
# - height: auto
- transition: 0.25s
- width: 14%
# - right: -9%
# - padding: 5%
# - margin: -10%
# - top: 65%
- right: |
[[[
return entity.state === 'on'
? '-11%'
: '-11%';
]]]
- top: |
[[[
return entity.state === 'on'
? '44%'
: '44%';
]]]
the sensors I used:
# - platform: template
# sensors:
wohnzimmer_temperature:
friendly_name: Wohnzimmer Temperatur
unit_of_measurement: '°C'
value_template: "{{ state_attr('climate.wohnzimmer', 'current_temperature') }}"
# - platform: template
# sensors:
wohnzimmer_position:
friendly_name: Wohnzimmer Position
unit_of_measurement: '%'
value_template: "{{ state_attr('climate.wohnzimmer', 'position') }}"
I hope I didn´t missed anything
Hi VietNgoc,
thanks for sharing your git. Can you tell me how you define the related kodi sensor for the movie intergration:
sensor.kodi_added_movie_*
with
added_movie
- type: grid
title: Movie
view_layout:
grid-area: movie
columns: 1
cards:
- type: custom:auto-entities
filter:
include:
- entity_id: 'sensor.kodi_added_movie_*'
options:
type: custom:button-card
template:
- added_movies
card:
type: custom:swipe-card
parameters:
watchSlidesProgress: false
slidesPerView: 1
speed: 700
roundLengths: true
grabCursor: false
followFinger: false
pagination:
type: bullets
clickable: true
dynamicBullets: true
dynamicMainBullets: 1
effect: cube
cubeEffect:
shadow: false
autoplay:
delay: 10000
disableOnInteraction: false
pauseOnMouseEnter: true
card_param: cards
sort:
count: 10
the needed part for my need from your media integration I got, but the kodi sensor confuses me…
I am trying to make a dashboard for mobile
I use a swiper card, but at the right, the card is not fully there
i tried card width, but that doesnt change
- type: custom:swipe-card
card_width: auto
any ideas ?
edit: when I resize my window on desktop and resize it to original, it is ok…
as rquested by message:
widget_weather.yaml
widget_weather:
template:
- base
variables:
temp_min: ''
temp_max: ''
humidity: ''
feels: ''
current_weather: ''
is_bellow_horrizon: >
[[[
if (states['sun.sun'].state == 'below_horizon') {
return true;
}
]]]
aspect_ratio: 1/1
show_icon: false
show_entity_picture: true
show_name: true
show_state: true
show_label: true
tap_action:
action: more-info
styles:
grid:
- grid-template-areas: |
"n"
"temp"
"i"
"s"
"l"
- grid-template-columns: 1fr
- grid-template-rows: 1fr 1fr
- gap: 0%
- overflow: visible
card:
- padding: 11.5% 10.5% 10.5% 11.5%
- color: rgba(255, 255, 255, 0.6)
- background: >
[[[
let weather = states[variables.current_weather].state.toLowerCase();
let now = new Date();
let isDaytime = now.getHours() >= 6 && now.getHours() < 18;
if (!isDaytime) {
return `linear-gradient(to top, rgba(255, 192, 203, 0.5) 0%, rgba(90,113,157,0.4) 100%) 100% / cover, url(/local/svg/weather/gif/${weather}-night.gif)`;
} else {
return `linear-gradient(to top, rgba(255, 192, 203, 0.5) 0%, rgba(90,113,157,0.4) 100%) 100% / cover, url(/local/svg/weather/gif/${weather}-day.gif)`;
}
]]]
- background-size: cover
state:
# - text-transform: uppercase
- margin-top: 5px
- line-height: 100%
name:
- place-self: start
# - text-transform: uppercase
- font-weight: 500
- font-family: Futura
- letter-spacing: 0.1vw
- margin-top: -7%
img_cell:
- justify-content: start
- overflow: visible
icon:
- width: 25%
- margin-top: -26px
label:
- place-self: center
- text-align: center
- margin-top: 3%
- margin-bottom: -7%
- align-items: center
custom_fields:
temp:
- place-self: start
- margin-top: -27px
- font-family: Futura
- color: rgba(240, 255, 255, 0.8)
label: >
[[[
return `
<table style="width: 100%; text-align: left;">
<tr>
<td style="width: 20%;">
<ha-icon icon="mdi:water-percent" style="width: 1.5em; height: 1.5em;"></ha-icon>
</td>
<td style="width: 30%;">
<span>${states[variables.humidity].state}%</span>
</td>
<td style="width: 50%; text-align: center;">
-
<td style="width: 20%;">
<ha-icon icon="mdi:weather-windy" style="width: 1.5em; height: 1.5em;"></ha-icon>
</td>
<td style="width: 30%;">
<span>${states[variables.temp_max].state}kmh</span>
</td>
</tr>
<tr>
<td style="width: 20%;">
<ha-icon icon="mdi:thermometer" style="width: 1.5em; height: 1.5em;"></ha-icon>
</td>
<td style="width: 30%;">
<span>${states[variables.temp_min].state}°C</span>
</td>
<td style="width: 50%; text-align: center;">
-
</td>
<td style="width: 20%;">
<ha-icon icon="mdi:weather-sunny" style="width: 1.5em; height: 1.5em;"></ha-icon>
</td>
<td style="width: 30%;">
<span>${states[variables.feels].state}°C</span>
</td>
</tr>
</table>
`
]]]
custom_fields:
temp: >
[[[ return entity.attributes.temperature + "°C"; ]]]
entity_picture: >
[[[
let weather = states[variables.current_weather].state.toLowerCase();
if ((weather == 'sunny') && (states['sun.sun'].state == 'above_horizon'))
return "/local/svg/weather/clear-day.svg";
if ((weather == 'sunny') || (weather == 'clear-night') && (states['sun.sun'].state == 'below_horizon'))
return "/local/svg/weather/clear-night.svg";
if (weather == 'fog')
return "/local/svg/weather/fog.svg";
if ((weather == 'partlycloudy') && (states['sun.sun'].state == 'above_horizon'))
return "/local/svg/weather/partly-cloudy-day.svg";
if ((weather == 'partlycloudy') && (states['sun.sun'].state == 'below_horizon'))
return "/local/svg/weather/partly-cloudy-night.svg";
if (weather == 'rainy')
return "/local/svg/weather/rain.svg";
if (weather == 'sleet')
return "/local/svg/weather/sleet.svg";
if (weather == 'snow')
return "/local/svg/weather/snow.svg";
if (weather == 'cloudy')
return "/local/svg/weather/cloudy.svg";
else (weather == 'wind')
return "/local/svg/weather/wind.svg";
]]]
extra_styles: |
[[[
return `
#name {
font-size: 0.9vw;
}
#temp {
font-size: 2.0vw;
}
#state {
font-size: 0.9vw;
}
#label {
font-size: 0.7vw;
white-space: wrap;
}
@media screen and (max-width: 1500px) {
#name {
font-size: 1.1vw;
}
#temp {
font-size: 2vw;
}
#state {
font-size: 1.2vw;
}
#label {
font-size: 0.7vw;
}
@media screen and (max-width: 800px) {
#name {
font-size: 3vw;
margin-top: -5%;
}
#temp {
font-size: 4vw;
margin-top: -4px !important;
}
#state {
font-size: 2.1vw;
}
#icon {
display: none !important;
}
#label {
font-size: 1.5vw;
font-weight: 500 !important;
margin-top: 5%;
margin-bottom: 0%;
}
}
`
]]]
ui_lovelace.yaml:
- type: custom:button-card
entity: weather.openweathermap
name: Steninge
double_tap_action:
action: more-info
tap_action:
!include popup/weather.yaml
template:
- widget_weather
variables:
temp_min: sensor.aussen_rain
temp_max: sensor.aussen_wind
humidity: sensor.aussen_humidity
feels: sensor.aussen_feels
current_weather: weather.openweathermap
sensors need to defined and pictures must be in the right folders.
Andrew, can you explane me exactly what you do to fit it at a iPad?
May somebody is interested. I always faced the problem that Sonos show no picture when source is TV. I didn´d find a way around in the thread yet, so I take some time and add a fixed picture for Sonos.
Furthermore I add that also devices which have the state “on” instead of “playing” is now shown as well, for example
Then, if more than one device is playing or on will now swap every 30 seconds.
tv_media.yaml
homeassistant:
customize:
media_player.tv_wohnzimmer_2:
friendly_name: TV Wohnzimmer
device_class: speaker
media_player.lea:
friendly_name: Sonos Lea
device_class: speaker
media_player.vardagsrum:
friendly_name: Sonos
device_class: speaker
sensor.ps5_101_activity:
friendly_name: PS5 Activity
device_class: tv
media_player.fernseher_maja_2:
friendly_name: TV Maja
device_class: tv
media_player.tv_schlafzimmer_tv:
friendly_name: Schlafzimmer
device_class: tv
media_player.wohnzimmer_oben:
friendly_name: Echo Wohnzimmer Oben
device_class: speaker
media_player.schlafzimmer:
friendly_name: Echo Schlafzimmer
device_class: speaker
media_player.buro:
friendly_name: Echo Büro
device_class: speaker
media_player.maja:
friendly_name: Echo Maja
device_class: speaker
media_player.kuche:
friendly_name: Echo Küche
device_class: speaker
media_player.dm900_2:
friendly_name: dm900
device_class: tv
template:
- select:
- name: conditional_media
state: >
{% set recently_added = 'Neu hinzugefügt' %}
{% set media_players = [
states.media_player.tv_wohnzimmer_2,
states.media_player.vardagsrum,
states.media_player.lea,
states.sensor.ps5_101_activity,
states.media_player.wohnzimmer_oben,
states.media_player.schlafzimmer,
states.media_player.schlafzimmer_tv,
states.media_player.dm900_2,
states.media_player.buro,
states.media_player.kuche,
states.media_player.maja ] %}
{% macro media(state) %}
{% set state = media_players | selectattr('state','eq',state) | list %}
{% set last_changed = recently_added if state | length == 0 else state | map(attribute='last_changed') | list | max %}
{{ state | selectattr('last_changed','eq', last_changed) | map(attribute='name') | list | join }}
{% endmacro %}
{% set active_players = media_players | selectattr('state','in',['playing','on']) | list %}
{% if active_players | length == 0 %}
{{ recently_added }}
{% else %}
{% set current_index = (states('input_number.current_media_index') | int) % (active_players | length) %}
{% set current_player = active_players[current_index] %}
{{ current_player.name }}
{% endif %}
options: >
{% set recently_added = ['Neu hinzugefügt'] %}
{% set media_players = [
states.media_player.tv_wohnzimmer_2,
states.media_player.vardagsrum,
states.media_player.lea,
states.sensor.ps5_101_activity,
states.media_player.wohnzimmer_oben,
states.media_player.schlafzimmer,
states.media_player.schlafzimmer_tv,
states.media_player.dm900_2,
states.media_player.buro,
states.media_player.maja,
states.media_player.kuche ] %}
{{ recently_added + media_players | map(attribute='name') | list }}
select_option:
service: select.select_option
target:
entity_id: select.conditional_media
data:
option: >
{{ option }}
# Additional Home Assistant configuration to handle index rotation
input_number:
current_media_index:
name: Current Media Index
initial: 0
min: 0
max: 1000
step: 1
#################################################
# #
# CONDITIONAL MEDIA #
# #
#################################################
conditional_media:
aspect_ratio: 1000/996
template:
- base
- base_media
- icon_play_pause
# - icon_playing_bars
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 = "Players";
}
});
if (entity) {
let elt = this.shadowRoot,
await = setTimeout(marquee, 100),
data = entity.attributes.data,
artist = entity.attributes.media_artist,
title = entity.attributes.media_title,
originaltitle = entity.attributes.originaltitle,
game_title = entity.attributes.title_name;
var output = artist === undefined && title !== undefined
? title
: game_title !== undefined
? `${game_title}`
: title === undefined && artist !== undefined
? artist
: title !== undefined && artist !== undefined
? `<div id="title" style="font-weight: 800; text-transform: uppercase; font-family: Raleway; letter-spacing: 0.07vw;">${title}</div><span style="font-size: 0.90em; color: #efefefd1; font-family: Raleway; text-transform: capitalize; letter-spacing: 0.03vw;">${artist}</span>`
: variables.translate_idle;
function marquee() {
let state = elt.getElementById("title"),
container = elt.getElementById("container");
if (state && container) {
state.innerHTML = title;
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 = `${title} ${spacer} ${title} `;
state.classList.add("marquee");
}
});
ro.observe(state);
ro.observe(container);
}
}
return output;
}
]]]
styles:
grid:
- gap: 0.65%
name:
- justify-self: flex-start
- line-height: 120%
- padding: 0.2vw
- margin: -0.2vw
- color: rgba(255,255,255,0.6)
- display: >
[[[
if (window.matchMedia('(max-width: 800px)').matches)
return 'none';
if (window.matchMedia('(max-width: 1440px)').matches)
return 'block';
else return 'block';
]]]
state:
- line-height: 120%
- max-width: 100%
- text-shadow: 3px 1px 4px black
- text-transform: uppercase
- padding-bottom: >
[[[
return variables.is_kodi || variables.media_on ? '9%' : '4%';
]]]
- overflow: visible
card:
- padding: 5.75% 5.75% 0 5.75%
- border-radius: calc(var(--button-card-border-radius) / 2)
- background: &media_background >
[[[
if (entity) {
if (variables.is_youtube) {
return `rgba(115, 115, 115, 0.2) center center/cover no-repeat`;
} else {
let data = entity.attributes.data;
return data && (data[variables.i].entity_picture)
? `rgba(115, 115, 115, 0.2) center center/cover no-repeat`
: data && (data[variables.i].fanart)
? `rgba(115, 115, 115, 0.2) top center/cover no-repeat`
: `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})`;
}
if (entity?.attributes?.app_id === 'com.bamtechmedia.dominguez.main.MainActivity-com.disney.disneyplus') {
return `url(/local/icons/Disney+.jpg)`;
}
if (entity?.attributes?.app_id === 'com.amazon.ignition.IgnitionActivity-com.amazon.amazonvideo.livingroom') {
return `url(/local/icons/prime.video.jpg)`;
}
if (entity?.attributes?.app_id === 'com.amazon.amazonvideo.livingroom') {
return `url(/local/icons/prime.video.jpg)`;
}
if (entity?.attributes?.app_id === 'com.netflix.ninja') {
return `url(/local/icons/netflix.png)`;
}
if (entity?.attributes?.app_id === 'de.cyberdream.dreamepg.MainActivityTV-de.cyberdream.dreamepg.tv.player') {
return `url(/local/icons/cyberdream.png)`;
}
if (entity?.attributes?.app_id === 'com.nordvpn.android.tv.MainActivity-com.nordvpn.android') {
return `url(/local/icons/nordvpn.png)`;
}
if (entity?.attributes?.app_id === 'se.svt.svtplay.ui.tv.profile.ProfilePickerActivity-se.svt.android.svtplay') {
return `url(/local/icons/svt.jpg)`;
}
if (entity?.attributes?.media_title === 'TV') {
return `url(/local/icons/fernsehen.png)`;
}
if (entity?.attributes?.media_content_type === 'tvshow') {
return `url(/local/icons/fernsehen.png)`;
}
if (entity?.attributes?.activity === 'idle') {
return `url(/local/icons/cyberdream.png)`;
}
if (entity?.attributes?.app_id === 'org.droidtv.channels.ChannelsActivity-org.droidtv.channels') {
return `url(/local/icons/fernsehen.png)`;
}
else {
let data = entity.attributes.data,
game_image = entity.attributes.title_image;
return game_image !== undefined
? `url("${game_image}")`
: data && (data[variables.i].poster || data[variables.i].fanart)
? `linear-gradient(to top, rgba(0, 0, 0, .65) 0%, rgba(0, 0, 0, 0) 100%), url("${data[variables.i].entity_picture}"), url("${data[variables.i].fanart}")`
: `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.80)'
: '#9da0a2';
]]]
blur_overlay:
- display: block
- position: absolute
- width: 122%
- height: 101%
- filter: var(--blur-intensity)
- clip-path: >
[[[
if (entity) {
if (variables.is_youtube) {
return `inset(74% 7% 3.45% 9% round 0 0 calc(var(--button-card-border-radius) / 2) calc(var(--button-card-border-radius) / 2))`;
} else {
return `inset(80% 3.45% 3.45% 5.45% round 0 0 calc(var(--button-card-border-radius) / 2) calc(var(--button-card-border-radius) / 2))`;
}
}
]]]
- background: *media_background
- background-image: *media_background_image
# - left: -10%
# - bottom: -5%
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 ' ';
]]]
automation for a 30sec refresh:
alias: Rotate Media Player
description: ""
trigger:
- platform: time_pattern
seconds: /30
action:
- service: input_number.set_value
data_template:
entity_id: input_number.current_media_index
value: >
{% set current_index = states('input_number.current_media_index') | int
%} {% set active_players = [
states.media_player.tv_wohnzimmer_2,
states.media_player.tv_wohnzimmer,
states.media_player.vardagsrum,
states.media_player.lea,
states.sensor.ps5_101_activity,
states.media_player.wohnzimmer_oben,
states.media_player.schlafzimmer,
states.media_player.schlafzimmer_tv,
states.media_player.dm900_2,
states.media_player.buro,
states.media_player.kuche,
states.media_player.maja ] | selectattr('state','in',['playing','on']) | list %}
{% set new_index = (current_index + 1) % (active_players | length) %} {{
new_index }}
Hello everybody. Very interesting project @Mattias_Persson , I’ve been using it for a long time. But now I would like to insert the value of the temperature and humidity sensors in the name of the room… is this possible?
Very thanks
Hi, recently I created a template for this change, I share it with everyone…
add 2 variables as temp and humid sensors. add to button card. see below, then create a new template for this change.
type: custom:button-card
entity: light.living_room_group
name: Lounge
double_tap_action: !include ../shared/popup/rooms/livingroom.yaml
hold_action: !include ../shared/honeycomb/living.yaml
template:
- rooms_base
- icon_couch_lamp
- change_grid_title
variables:
tempsensor: sensor.office_temp_humid_temperature
humidsensor: sensor.office_temp_humid_humidity
add the new template also to the button card, this template is to change only the grid title, so you just need to add it to one of the cards in your grid card.
change_grid_title:
state_display: >
[[[
// Add event listener to reset flag when dashboard changes
window.addEventListener("location-changed", () => {
// Reset the flag when the dashboard changes
window.gridTitleProcessed = false;
});
if (!window.gridTitleProcessed) {
let sensorState = parseFloat(states[variables.tempsensor].state),
humidityState = parseFloat(states[variables.humidsensor].state);
if (entity) {
let parentElement = this.getRootNode().host;
let headerTitle = findFirstH1Above(parentElement);
let currentTitle = headerTitle.innerText;
function findFirstH1Above(element) {
let currentElement = element;
while (currentElement) {
// Check for <h1> in the current element's shadow root, if it exists
if (currentElement.shadowRoot) {
const shadowH1 = currentElement.shadowRoot.querySelector('h1');
if (shadowH1) {
return shadowH1;
}
}
// Check for <h1> in the current element's light DOM
const lightH1 = currentElement.querySelector('h1');
if (lightH1) {
return lightH1;
}
// Move to the parent node
currentElement = currentElement.getRootNode().host;
// If the current element has no parent (we're at the document level), break the loop
if (!currentElement) {
break;
}
}
console.log('No <h1> element found above the given element');
return null;
}
headerTitle.style.display = 'flex';
headerTitle.style.width = '100%';
headerTitle.style.justifyContent = 'space-between';
headerTitle.style.alignItems = 'center';
headerTitle.style.paddingInline = 'inherit';
headerTitle.innerHTML = `
<div>${currentTitle}</div>
<div style="font-size: x-large;">
${sensorState.toFixed(0)}°
${humidityState.toFixed(0)}%
</div>
`;
}
window.gridTitleProcessed = true;
}
]]]
Hey VietNgoc,
great work from you.
I’ve been following your config on Github for a while, but can’t find this code from above there. Is the Github not up to date?
Hi, I upload to public repo mostly when I have some major change in code. Otherwise, I have already added this part… thanks
I’ve read somewhere that style is not working on mobile. is there a way to resize it another way N
This is truly amazing. I wasn’t able to do it because I lacked the skill, but thank you very much
Good afternoon everybody. I wanted to have the buttons at the bottom like “page 1, page 2, page 3, etc…” and change only part of the screen as shown in the photo. Buttons are no problem creating them. But is this possible to do? Has anyone done it?
Thanks
wrap all parts as one card, then use this plugin. But you will have a lot of work to assign the right template for buttons. Or easier if you make a new view, and assign the same sidebar to each one.
I had a similar method for my config for a while, but I don’t use it anymore. For demonstration I send example of view for my media library, example of use for switching pages Prev / Next