button_card_templates:
variable_template:
variables:
dashboardversion: 1.3.2
var_assistsat_entity: |-
[[[
return localStorage.getItem("view_assist_sensor")
]]]
var_dashboard: |-
[[[
try {
return hass.states[variables.var_assistsat_entity].attributes.dashboard || '/view-assist';
} catch {
return '/view-assist';
}
]]]
var_mic_switch: |-
[[[
try {
var micdevice = hass.states[variables.var_assistsat_entity].attributes.mute_switch;
return `${micdevice}`;
} catch { return ""}
]]]
var_wake_switch: |-
[[[
try {
var micdevice = hass.states[variables.var_assistsat_entity].attributes.mic_device;
if (micdevice.startsWith("assist_satellite.")) {
var wakebutton = micdevice.replace("assist_satellite.", "button.") + "_wake";
if (wakebutton in hass.states) {
return `${wakebutton}`;
}
}
return "";
} catch {
return "";
}
]]]
var_mediaplayer_device: |-
[[[
try {
var mediadevice = hass.states[variables.var_assistsat_entity].attributes.mediaplayer_device;
return `${mediadevice}`;
} catch { return "";}
]]]
var_mediaplayer_mute: |-
[[[
try {
var mediadevice = hass.states[variables.var_assistsat_entity].attributes.mediaplayer_device;
var mediaplayerstate = hass.states[mediadevice].attributes.is_volume_muted;
return `${mediaplayerstate}`;
} catch { return "";}
]]]
var_assistsat_time_format: |-
[[[
if (variables.var_assistsat_entity_use_24_hour_time) {
return '%H:%M';
} else {
return '%l:%M';
}
]]]
var_current_time: |-
[[[
return ``;
]]]
var_date_short: |-
[[[
return ``;
]]]
var_date_long: |-
[[[
return ``;
]]]
var_assistsat_entity_font_style: |
[[[
try
{
return states[variables.var_assistsat_entity].attributes.font_style;
} catch { return "Roboto"}
]]]
var_assistsat_entity_weather_entity: |
[[[
try
{
return states[variables.var_assistsat_entity].attributes.weather_entity;
} catch { return ""}
]]]
var_assistsat_entity_responsive_status_icons_size: |
[[[
try {
const baseSize = states[variables.var_assistsat_entity].attributes.status_icons_size || "6vw";
if (window.viewAssistResponsive?.orientation === "portrait") {
const numericValue = parseFloat(baseSize);
const unit = baseSize.replace(numericValue.toString(), '');
return `${numericValue * 1.5}${unit}`;
}
return baseSize;
} catch {
return window.viewAssistResponsive?.orientation === "portrait" ? "9vw" : "6vw";
}
]]]
var_assistsat_entity_use_24_hour_time: |
[[[
try
{
return states[variables.var_assistsat_entity].attributes.use_24_hour_time;
} catch { return false}
]]]
var_title: |-
[[[
try
{
return states[variables.var_assistsat_entity].attributes.title;
} catch { return ""}
]]]
var_message: |-
[[[
try
{
return states[variables.var_assistsat_entity].attributes.message;
} catch { return ""}
]]]
var_image: |-
[[[
try
{
return states[variables.var_assistsat_entity].attributes.image;
} catch { return ""}
]]]
var_font_size: |-
[[[
try
{
return states[variables.var_assistsat_entity].attributes.message_font_size;
}
catch { return ""}
]]]
var_weather_temperature: |-
[[[
try
{
return (states[variables.var_assistsat_entity_weather_entity].attributes.temperature + '°');
}
catch { return ""}
]]]
var_weather_icon: |-
[[[
const weatherIconsDay = {
"clear-night": "mdi:weather-night",
"cloudy": "mdi:weather-cloudy",
"dust": "mdi:weather-dust",
"fog": "mdi:weather-fog",
"hail": "mdi:weather-hail",
"hazy": "mdi:weather-hazy",
"hurricane": "mdi:weather-hurricane",
"lightning": "mdi:weather-lightning",
"lightning-rainy": "mdi:weather-lightning-rainy",
"partlycloudy": "mdi:weather-partly-cloudy",
"partly-lightning": "mdi:weather-partly-lightning",
"partly-rainy": "mdi:weather-partly-rainy",
"partly-snowy": "mdi:weather-partly-snowy",
"partly-snowy-rainy": "mdi:weather-partly-snowy-rainy",
"pouring": "mdi:weather-pouring",
"rainy": "mdi:weather-rainy",
"snowy": "mdi:weather-snowy",
"snowy-heavy": "mdi:weather-snowy-heavy",
"snowy-rainy": "mdi:weather-snowy-rainy",
"sunny": "mdi:weather-sunny",
"tornado": "mdi:weather-tornado",
"windy": "mdi:weather-windy",
"windy-variant": "mdi:weather-windy-variant",
};
const weatherIconsNight = {
...weatherIconsDay,
clear: "mdi:weather-night",
sunny: "mdi:weather-night",
partlycloudy: "mdi:weather-night-partly-cloudy",
};
try
{
var condition = states[variables.var_assistsat_entity_weather_entity].state;
if (states['sun.sun'] === 'above_horizon') {
var weather_icon = weatherIconsDay[condition];
} else {
var weather_icon = weatherIconsDay[condition];
}
if (typeof(weather_icon) === 'undefined') {
var weather_icon = "mdi:help"
}
return `${weather_icon}`;
} catch { return ""}
]]]
var_current_view: |-
[[[
try {
const pathname = window.location.pathname;
const match = pathname.match(/\/view-assist\/([^\/]+)/);
return match && match[1] ? match[1] : "";
} catch {
return "";
}
]]]
responsive_base:
variables:
var_orientation_sensor: |-
[[[
try {
const orientationSensor = hass.states[variables.var_assistsat_entity]?.attributes?.orientation_sensor;
if (orientationSensor && orientationSensor in hass.states) {
const state = hass.states[orientationSensor].state;
if (state === "portrait" || state === "landscape") {
return state;
}
}
return "";
} catch {
return "";
}
]]]
var_orientation:
value: |-
[[[
const sensorOrientation = variables.var_orientation_sensor;
const windowOrientation = window.innerHeight > window.innerWidth
? "portrait"
: "landscape";
const currentOrientation = sensorOrientation || windowOrientation;
if (!window.viewAssistResponsive) {
window.viewAssistResponsive = {
orientation: currentOrientation,
sensor_available: !!sensorOrientation,
lastUpdate: Date.now()
};
} else {
const oldOrientation = window.viewAssistResponsive.orientation;
window.viewAssistResponsive.sensor_available = !!sensorOrientation;
if (oldOrientation !== currentOrientation) {
window.viewAssistResponsive.orientation = currentOrientation;
window.viewAssistResponsive.lastUpdate = Date.now();
window.dispatchEvent(new CustomEvent('view-assist-responsive-change', {
detail: window.viewAssistResponsive,
bubbles: true
}));
}
}
return window.viewAssistResponsive.orientation;
]]]
force_eval: true
body_template:
template:
- variable_template
- status_icons_content
- responsive_base
show_state: false
show_icon: false
show_name: false
tap_action:
action: call-service
service: view_assist.set_state
service_data:
entity_id: >-
[[[ try { return variables.var_assistsat_entity } catch { return ""
}]]]
mode: hold
double_tap_action:
action: call-service
service: view_assist.set_state
service_data:
entity_id: >-
[[[ try { return variables.var_assistsat_entity } catch { return "" }
]]]
mode: normal
hold_action:
action: call-service
service: switch.toggle
service_data:
entity_id: '[[[ try { return variables.var_mic_switch } catch { return "" } ]]]'
styles:
grid:
- grid-template-areas: |
"title status"
"message message"
"assist assist"
- grid-template-rows: min-content 1fr
- grid-template-columns: 1fr 1fr
- row-gap: .5rem
card:
- min-height: |-
[[[
try {
const screenMode = hass.states[variables.var_assistsat_entity]?.attributes?.screen_mode;
if (screenMode === 'no_hide' || screenMode === 'hide_sidebar') {
return 'calc(100vh - var(--header-height))';
}
return '100vh';
} catch {
return '100vh';
}
]]]
- max-height: |-
[[[
try {
const screenMode = hass.states[variables.var_assistsat_entity]?.attributes?.screen_mode;
if (screenMode === 'no_hide' || screenMode === 'hide_sidebar') {
return 'calc(100vh - var(--header-height))';
}
return '100vh';
} catch {
return '100vh';
}
]]]
- height: |-
[[[
try {
const screenMode = hass.states[variables.var_assistsat_entity]?.attributes?.screen_mode;
if (screenMode === 'no_hide' || screenMode === 'hide_sidebar') {
return 'calc(100vh - var(--header-height))';
}
return '100vh';
} catch {
return '100vh';
}
]]]
- aspect-ratio: |-
[[[
if (!window.viewAssistResponsive) return "16 / 9";
return window.viewAssistResponsive.orientation === "portrait" ? "9 / 16" : "16 / 9";
]]]
- background: |
[[[
if (variables.background != null) {
return `center / cover no-repeat url(${variables.background})`
} else if (variables.var_background != null) {
return `center / cover no-repeat url(${variables.var_background})`
} else {
return `center / cover no-repeat ${variables.background_color}`
}
]]]
- background-size: cover
- border-radius: 0px
- overflow: hidden
- color: white
- font-family: |-
[[[
return `"${variables.var_assistsat_entity_font_style}", sans-serif`;
]]]
- font-weight: 300
- position: relative
- box-sizing: border-box
custom_fields:
title:
- position: absolute
- justify-self: start
- align-self: start
- z-index: 1
- font-size: |-
[[[
return window.viewAssistResponsive?.orientation === "portrait" ? "220%" : "200%";
]]]
- font-weight: 400
- width: max-content
- margin-left: 2%
- margin-top: '-4%'
status:
- position: absolute
- justify-self: end
- align-self: end
- justify-content: right
- top: 0vh
- right: 0vw
- z-index: 1
status_icons_content:
custom_fields:
title: '[[[ return variables.var_title ]]]'
status:
card:
type: custom:layout-card
layout_type: custom:horizontal-layout
cards:
- type: custom:layout-card
layout_type: grid-layout
layout:
margin: 0
card_margin: 0
place-content: end
grid-template-columns: |-
[[[
const baseIconSize = variables.var_assistsat_entity_responsive_status_icons_size;
return `repeat(auto-fit, minmax(${baseIconSize}, ${baseIconSize}))`;
]]]
cards: |-
[[[{
const buttonList = [];
try {
const vaEntity = variables.var_assistsat_entity;
if (!vaEntity || !hass.states[vaEntity]) {
return [];
}
const statusIcons = hass.states[vaEntity].attributes.status_icons || [];
const menuItems = hass.states[vaEntity].attributes.menu_items || [];
const menuActive = hass.states[vaEntity].attributes.menu_active || false;
const currentView = variables.var_current_view;
const availableTemplates = new Set();
try {
const lovelace = document.querySelector("home-assistant")
?.shadowRoot?.querySelector("home-assistant-main")
?.shadowRoot?.querySelector("ha-drawer partial-panel-resolver ha-panel-lovelace")
?.lovelace;
if (lovelace?.config?.button_card_templates) {
Object.keys(lovelace.config.button_card_templates).forEach(template => {
availableTemplates.add(template);
});
}
} catch (e) {
}
function isCurrentView(item) {
if (!currentView) return false;
if (typeof item === 'string' && !item.includes(':')) {
if (item === currentView) return true;
const homePath = hass.states[vaEntity]?.attributes?.home_screen || "/view-assist/clock";
const homeView = homePath.split('/').pop() || "clock";
const templateViewMap = {
"home": homeView
};
if (templateViewMap[item] === currentView) return true;
return false;
}
if (typeof item === 'string' && item.includes(':')) {
const parts = item.split('|');
const typeAndTarget = parts[0];
const [type, target] = typeAndTarget.split(':');
if (type === 'view') {
const viewName = target.includes('/') ?
target.split('/').pop() : target;
return viewName === currentView;
}
}
return false;
}
const addedItems = new Set();
function addIconToList(icon, isDynamicItem = false) {
if (icon === "menu") return;
if (isCurrentView(icon)) {
return;
}
let buttonConfig;
if (isDynamicItem) {
const type = icon.split(':')[0];
buttonConfig = {
type: "custom:button-card",
template: `dynamic_${type}_item`,
variables: {
menu_item: icon,
entity_id: vaEntity
}
};
} else {
if (availableTemplates.size > 0 && !availableTemplates.has(icon)) {
buttonConfig = {
type: "custom:button-card",
template: "icon_template",
icon: "mdi:alert-circle-outline",
name: icon,
styles: {
card: [{ "border": "2px dashed rgba(255, 152, 0, 0.8)" }],
icon: [{ "color": "rgba(255, 152, 0, 0.9)" }],
name: [{
"font-size": "0.7em",
"color": "rgba(255, 152, 0, 0.9)",
"padding-top": "4px"
}]
},
show_name: true,
tap_action: {
action: "none"
}
};
} else {
buttonConfig = {
type: "custom:button-card",
template: icon
};
}
}
const key = icon;
if (addedItems.has(key)) return;
addedItems.add(key);
buttonList.push(buttonConfig);
}
if (menuActive) {
const reversedMenuItems = [...menuItems].reverse();
reversedMenuItems.forEach(item => {
if (item !== "menu") {
if (item.includes(':')) {
addIconToList(item, true);
} else {
addIconToList(item, false);
}
}
});
}
statusIcons.forEach(icon => {
if (icon !== "menu") {
if (icon.includes(':')) {
addIconToList(icon, true);
} else {
addIconToList(icon, false);
}
}
});
if (hass.states[vaEntity].attributes.menu_config === "menu_enabled_button_visible" &&
!addedItems.has("menu")) {
buttonList.push({
type: "custom:button-card",
template: "menu"
});
}
} catch (e) {
}
return buttonList;
}]]]
status_icons_overlay:
template:
- variable_template
- responsive_base
- status_icons_content
show_state: false
show_icon: false
show_name: false
triggers_update: all
styles:
card: null
custom_fields:
status:
- position: fixed
- top: |-
[[[
try {
const screenMode = hass.states[variables.var_assistsat_entity]?.attributes?.screen_mode;
if (screenMode === 'no_hide' || screenMode === 'hide_sidebar') {
return 'calc(0vh + var(--header-height))';
}
return '0vh';
} catch {
return '0vh';
}
]]]
- right: 0vw
- z-index: 4
icon_template:
template: variable_template
color_type: card
show_name: false
size: 90%
padding: 0px
styles:
card:
- background-color: transparent
- border-width: 0px
- aspect-ratio: 1 / 1
icon:
- display: grid
- color: white
dynamic_view_item:
template: icon_template
icon: |-
[[[
const parts = variables.menu_item.split('|');
const icon = parts.length > 1 ? parts[1] : 'view-dashboard';
return `mdi:${icon}`;
]]]
tap_action:
action: call-service
service: view_assist.navigate
service_data:
device: '[[[ return variables.entity_id; ]]]'
path: |-
[[[
const parts = variables.menu_item.split('|');
const typeAndTarget = parts[0];
const target = typeAndTarget.split(':')[1];
const base = variables.var_dashboard || '/view-assist';
return target.startsWith('/') ? target : `${base}/${target}`;
]]]
dynamic_entity_item:
template: icon_template
state_display: none
entity: |-
[[[
const parts = variables.menu_item.split('|');
const typeAndTarget = parts[0];
return typeAndTarget.split(':')[1];
]]]
icon: |-
[[[
const parts = variables.menu_item.split('|');
const typeAndTarget = parts[0];
const entityId = typeAndTarget.split(':')[1];
const iconOptions = parts.length > 1 ? parts[1].split(',') : ['help-circle'];
let icon = iconOptions[0];
if (iconOptions.length > 1 && hass.states[entityId]) {
const state = hass.states[entityId].state;
if (state === 'off' && iconOptions[1]) {
icon = iconOptions[1];
}
}
return `mdi:${icon}`;
]]]
tap_action:
action: toggle
entity: |-
[[[
const parts = variables.menu_item.split('|');
const typeAndTarget = parts[0];
return typeAndTarget.split(':')[1];
]]]
hold_action:
action: more-info
entity: |-
[[[
const parts = variables.menu_item.split('|');
const typeAndTarget = parts[0];
return typeAndTarget.split(':')[1];
]]]
dynamic_service_item:
template: icon_template
icon: |-
[[[
const parts = variables.menu_item.split('|');
const icon = parts.length > 1 ? parts[1] : 'cog';
return `mdi:${icon}`;
]]]
tap_action:
action: call-service
service: |-
[[[
const parts = variables.menu_item.split('|');
const typeAndTarget = parts[0];
return typeAndTarget.split(':')[1];
]]]
service_data: {}
mediaplayer:
type: custom:button-card
template: icon_template
icon: mdi:volume-off
tap_action:
action: call-service
service: media_player.volume_mute
service_data:
entity_id: '[[[ return variables.var_mediaplayer_device ]]]'
is_volume_muted: false
mic:
type: custom:button-card
template: icon_template
icon: mdi:microphone-off
tap_action:
action: call-service
service: homeassistant.turn_off
service_data:
entity_id: '[[[ return variables.var_mic_switch ]]]'
hold:
type: custom:button-card
template: icon_template
icon: mdi:hand-back-left
tap_action:
action: call-service
service: view_assist.set_state
service_data:
mode: normal
entity_id: '[[[ return variables.var_assistsat_entity ]]]'
cycle:
type: custom:button-card
template: icon_template
icon: mdi:sync
tap_action:
action: call-service
service: view_assist.set_state
service_data:
mode: normal
entity_id: '[[[ return variables.var_assistsat_entity ]]]'
dnd:
type: custom:button-card
template: icon_template
icon: mdi:minus-circle
tap_action:
action: call-service
service: view_assist.set_state
service_data:
do_not_disturb: false
entity_id: '[[[ return variables.var_assistsat_entity ]]]'
weather:
type: custom:button-card
template: icon_template
icon: mdi:weather-sunny
tap_action:
action: call-service
service: view_assist.navigate
service_data:
device: '[[[ return variables.var_assistsat_entity ]]]'
path: '[[[ return `${variables.var_dashboard}/weather` ]]]'
home:
type: custom:button-card
template: icon_template
icon: mdi:home
tap_action:
action: call-service
service: view_assist.navigate
service_data:
device: '[[[ return variables.var_assistsat_entity ]]]'
path: home
menu:
type: custom:button-card
template: icon_template
icon: mdi:menu
tap_action:
action: call-service
service: view_assist.toggle_menu
service_data:
entity_id: '[[[ return variables.var_assistsat_entity ]]]'
show: >-
[[[ return
!states[variables.var_assistsat_entity].attributes.menu_active ]]]
hold_action:
action: call-service
service: view_assist.set_state
service_data:
entity_id: '[[[ return variables.var_assistsat_entity ]]]'
mode: hold
camera:
type: custom:button-card
template: icon_template
icon: mdi:cctv
tap_action:
action: call-service
service: view_assist.navigate
service_data:
device: '[[[ return variables.var_assistsat_entity ]]]'
path: '[[[ return `${variables.var_dashboard}/camera` ]]]'
music:
type: custom:button-card
template: icon_template
icon: mdi:music
tap_action:
action: call-service
service: view_assist.navigate
service_data:
device: '[[[ return variables.var_assistsat_entity ]]]'
path: '[[[ return `${variables.var_dashboard}/music` ]]]'
wake:
type: custom:button-card
template: icon_template
icon: mdi:button-pointer
tap_action:
action: call-service
service: button.press
service_data:
entity_id: "[[[ return variables.var_wake_switch ]]]"
views:
- title: Home