Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
034419f954
|
|||
f5953d23e6
|
|||
473526390e
|
|||
a5a9d081d2
|
|||
0f25ce6f6a
|
|||
eced9a763e
|
|||
5331c0d08a
|
|||
c9e4a11604
|
|||
d55ad66264
|
|||
d56d899588
|
|||
6afb3b7cb7
|
|||
e2ea214832
|
|||
b1543676d5
|
|||
bc45d6b7fd
|
|||
1a706153a8
|
|||
95b2c8cfc5
|
|||
61b04c05c6
|
|||
41141e94df
|
|||
cc9ec0b211
|
|||
adf881a106
|
|||
6ee298a3d2
|
|||
aa6358ce19
|
|||
abe62888b2
|
|||
0cabab0462
|
|||
034cf2f972
|
|||
1d246e8018
|
|||
5cffb7208f
|
|||
a7b1a53754
|
|||
de5efd39b4
|
@ -1 +1 @@
|
|||||||
2025.5.2
|
2025.7.1
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -20,6 +20,7 @@
|
|||||||
/glances/
|
/glances/
|
||||||
/downloads/
|
/downloads/
|
||||||
/lightwand/
|
/lightwand/
|
||||||
|
/bubble/Scratchpad/
|
||||||
|
|
||||||
# ignore any of these files no matter where they are using double *
|
# ignore any of these files no matter where they are using double *
|
||||||
**.DS_Store
|
**.DS_Store
|
||||||
|
102
automations.yaml
102
automations.yaml
@ -1869,54 +1869,70 @@
|
|||||||
to: 'on'
|
to: 'on'
|
||||||
id: recliner-on
|
id: recliner-on
|
||||||
trigger: state
|
trigger: state
|
||||||
|
alias: Recliner Mode On
|
||||||
- entity_id: input_boolean.recliner_mode
|
- entity_id: input_boolean.recliner_mode
|
||||||
from: 'on'
|
from: 'on'
|
||||||
to: 'off'
|
to: 'off'
|
||||||
id: recliner-off
|
id: recliner-off
|
||||||
trigger: state
|
trigger: state
|
||||||
|
alias: Recliner Mode Off
|
||||||
conditions: []
|
conditions: []
|
||||||
actions:
|
actions:
|
||||||
- choose:
|
- alias: Routing
|
||||||
|
choose:
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: trigger
|
- condition: trigger
|
||||||
id: recliner-on
|
id: recliner-on
|
||||||
|
alias: Recliner Mode On
|
||||||
sequence:
|
sequence:
|
||||||
- target:
|
- target:
|
||||||
entity_id: input_select.basement_studio_scenes
|
entity_id: input_select.basement_studio_scenes
|
||||||
data:
|
data:
|
||||||
option: Stairwell
|
option: Stairwell
|
||||||
action: input_select.select_option
|
action: input_select.select_option
|
||||||
|
alias: Set scene to Stairwell
|
||||||
- target:
|
- target:
|
||||||
entity_id:
|
entity_id:
|
||||||
- input_boolean.white_noise_basement
|
- input_boolean.white_noise_basement
|
||||||
- input_boolean.studio_quiet
|
- input_boolean.studio_quiet
|
||||||
data: {}
|
data: {}
|
||||||
action: input_boolean.turn_on
|
action: input_boolean.turn_on
|
||||||
- if:
|
alias: Turn on white noise and Studio Quiet
|
||||||
|
- alias: Turn off TV
|
||||||
|
if:
|
||||||
- condition: template
|
- condition: template
|
||||||
value_template: "{% if is_state('media_player.basement_tv','playing') %}\n
|
value_template: "{% if is_state('media_player.basement_tv','playing') %}\n
|
||||||
\ false\n{% elif is_state('media_player.basement_tv','paused') or is_state('media_player.basement_tv','idle')
|
\ false\n{% elif is_state('media_player.basement_tv','paused') or is_state('media_player.basement_tv','idle')
|
||||||
%}\n {{ state_attr('media_player.basement_tv','app_name') in ['TV','Android
|
%}\n {{ state_attr('media_player.basement_tv','app_name') in ['TV','Android
|
||||||
TV Launcher'] }}\n{% else %}\n false\n{% endif %}\n"
|
TV Launcher'] }}\n{% else %}\n false\n{% endif %}\n"
|
||||||
|
alias: If nothing is playing
|
||||||
then:
|
then:
|
||||||
- target:
|
- target:
|
||||||
entity_id: media_player.basement_tv
|
entity_id: media_player.basement_tv
|
||||||
data: {}
|
data: {}
|
||||||
action: media_player.turn_off
|
action: media_player.turn_off
|
||||||
- if:
|
alias: Turn off TV
|
||||||
- condition: not
|
enabled: false
|
||||||
|
- alias: Turn off computer monitors
|
||||||
|
if:
|
||||||
|
- alias: If I'm not watching something
|
||||||
|
condition: not
|
||||||
conditions:
|
conditions:
|
||||||
- condition: state
|
- condition: state
|
||||||
entity_id: media_player.tony_asus
|
entity_id: media_player.tony_asus
|
||||||
state: playing
|
state: playing
|
||||||
|
alias: PC playing video or music
|
||||||
then:
|
then:
|
||||||
- target:
|
- target:
|
||||||
entity_id: script.tony_desktop_displays_off
|
entity_id: script.tony_desktop_displays_off
|
||||||
data: {}
|
data: {}
|
||||||
action: script.turn_on
|
action: script.turn_on
|
||||||
|
alias: Turn off computer monitors
|
||||||
|
enabled: false
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: trigger
|
- condition: trigger
|
||||||
id: recliner-off
|
id: recliner-off
|
||||||
|
alias: Recliner Mode Off
|
||||||
sequence:
|
sequence:
|
||||||
- data: {}
|
- data: {}
|
||||||
target:
|
target:
|
||||||
@ -2046,10 +2062,12 @@
|
|||||||
- script.tony_desktop_displays_on
|
- script.tony_desktop_displays_on
|
||||||
data: {}
|
data: {}
|
||||||
action: script.turn_on
|
action: script.turn_on
|
||||||
|
enabled: false
|
||||||
- target:
|
- target:
|
||||||
entity_id: media_player.basement_tv
|
entity_id: media_player.basement_tv
|
||||||
data: {}
|
data: {}
|
||||||
action: media_player.turn_on
|
action: media_player.turn_on
|
||||||
|
enabled: false
|
||||||
mode: restart
|
mode: restart
|
||||||
- id: '1696286540644'
|
- id: '1696286540644'
|
||||||
alias: Basement Lights Adaptive Resync
|
alias: Basement Lights Adaptive Resync
|
||||||
@ -5569,53 +5587,59 @@
|
|||||||
- id: '1722386174249'
|
- id: '1722386174249'
|
||||||
alias: Tina Meds Cleanup
|
alias: Tina Meds Cleanup
|
||||||
description: Handles the setting/clearing of medication configs for Tina
|
description: Handles the setting/clearing of medication configs for Tina
|
||||||
trigger:
|
triggers:
|
||||||
- platform: state
|
- entity_id:
|
||||||
entity_id:
|
|
||||||
- input_boolean.tina_morning_meds_reminder
|
- input_boolean.tina_morning_meds_reminder
|
||||||
from: 'on'
|
from: 'on'
|
||||||
to: 'off'
|
to: 'off'
|
||||||
id: morning-reminders-off
|
id: morning-reminders-off
|
||||||
alias: Morning reminders off
|
alias: Morning reminders off
|
||||||
|
trigger: state
|
||||||
- alias: Night reminders off
|
- alias: Night reminders off
|
||||||
platform: state
|
|
||||||
entity_id:
|
entity_id:
|
||||||
- input_boolean.tina_night_meds_reminder
|
- input_boolean.tina_night_meds_reminder
|
||||||
from: 'on'
|
from: 'on'
|
||||||
to: 'off'
|
to: 'off'
|
||||||
id: night-reminders-off
|
id: night-reminders-off
|
||||||
- platform: event
|
trigger: state
|
||||||
event_type: ios.notification_action_fired
|
- event_type: ios.notification_action_fired
|
||||||
event_data:
|
event_data:
|
||||||
actionName: TINA_MORNING_MEDS_TAKEN
|
actionName: TINA_MORNING_MEDS_TAKEN
|
||||||
id: morning-taken
|
id: morning-taken
|
||||||
alias: Morning taken
|
alias: Morning taken
|
||||||
|
trigger: event
|
||||||
- alias: Night taken
|
- alias: Night taken
|
||||||
platform: event
|
|
||||||
event_type: ios.notification_action_fired
|
event_type: ios.notification_action_fired
|
||||||
event_data:
|
event_data:
|
||||||
actionName: TINA_NIGHT_MEDS_TAKEN
|
actionName: TINA_NIGHT_MEDS_TAKEN
|
||||||
id: night-taken
|
id: night-taken
|
||||||
|
trigger: event
|
||||||
- alias: Morning skipped
|
- alias: Morning skipped
|
||||||
platform: event
|
|
||||||
event_type: ios.notification_action_fired
|
event_type: ios.notification_action_fired
|
||||||
event_data:
|
event_data:
|
||||||
actionName: TINA_MORNING_MEDS_SKIPPED
|
actionName: TINA_MORNING_MEDS_SKIPPED
|
||||||
id: morning-skipped
|
id: morning-skipped
|
||||||
|
trigger: event
|
||||||
- alias: Night skipped
|
- alias: Night skipped
|
||||||
platform: event
|
|
||||||
event_type: ios.notification_action_fired
|
event_type: ios.notification_action_fired
|
||||||
event_data:
|
event_data:
|
||||||
actionName: TINA_NIGHT_MEDS_SKIPPED
|
actionName: TINA_NIGHT_MEDS_SKIPPED
|
||||||
id: night-skipped
|
id: night-skipped
|
||||||
- platform: state
|
trigger: event
|
||||||
entity_id:
|
- entity_id:
|
||||||
- person.christina_stork
|
- person.christina_stork
|
||||||
from: home
|
from: home
|
||||||
id: left
|
id: left
|
||||||
alias: Left
|
alias: Left
|
||||||
condition: []
|
trigger: state
|
||||||
action:
|
- trigger: state
|
||||||
|
entity_id:
|
||||||
|
- person.christina_stork
|
||||||
|
to: Bob Evans
|
||||||
|
id: at-work
|
||||||
|
alias: At Work
|
||||||
|
conditions: []
|
||||||
|
actions:
|
||||||
- alias: Routing
|
- alias: Routing
|
||||||
choose:
|
choose:
|
||||||
- conditions:
|
- conditions:
|
||||||
@ -5624,19 +5648,19 @@
|
|||||||
- morning-reminders-off
|
- morning-reminders-off
|
||||||
alias: Morning Reminders Off
|
alias: Morning Reminders Off
|
||||||
sequence:
|
sequence:
|
||||||
- service: counter.reset
|
- metadata: {}
|
||||||
metadata: {}
|
|
||||||
data: {}
|
data: {}
|
||||||
target:
|
target:
|
||||||
entity_id: counter.tina_morning_meds_reminder_count
|
entity_id: counter.tina_morning_meds_reminder_count
|
||||||
alias: Reset morning reminder count
|
alias: Reset morning reminder count
|
||||||
- service: script.text_notify
|
action: counter.reset
|
||||||
data:
|
- data:
|
||||||
type: alert
|
type: alert
|
||||||
who: tina
|
who: tina
|
||||||
message: clear_notification
|
message: clear_notification
|
||||||
tag: tina-morning-meds
|
tag: tina-morning-meds
|
||||||
alias: Clear morning notification
|
alias: Clear morning notification
|
||||||
|
action: script.text_notify
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: trigger
|
- condition: trigger
|
||||||
id:
|
id:
|
||||||
@ -5644,66 +5668,66 @@
|
|||||||
alias: Night reminders off
|
alias: Night reminders off
|
||||||
sequence:
|
sequence:
|
||||||
- alias: Reset night reminder count
|
- alias: Reset night reminder count
|
||||||
service: counter.reset
|
|
||||||
metadata: {}
|
metadata: {}
|
||||||
data: {}
|
data: {}
|
||||||
target:
|
target:
|
||||||
entity_id: counter.tina_night_meds_reminder_count
|
entity_id: counter.tina_night_meds_reminder_count
|
||||||
- service: script.text_notify
|
action: counter.reset
|
||||||
data:
|
- data:
|
||||||
type: alert
|
type: alert
|
||||||
who: tina
|
who: tina
|
||||||
message: clear_notification
|
message: clear_notification
|
||||||
tag: tina-night-meds
|
tag: tina-night-meds
|
||||||
alias: Clear night notification
|
alias: Clear night notification
|
||||||
|
action: script.text_notify
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: trigger
|
- condition: trigger
|
||||||
id:
|
id:
|
||||||
- morning-taken
|
- morning-taken
|
||||||
alias: Morning taken
|
alias: Morning taken
|
||||||
sequence:
|
sequence:
|
||||||
- service: input_boolean.turn_on
|
- metadata: {}
|
||||||
metadata: {}
|
|
||||||
data: {}
|
data: {}
|
||||||
target:
|
target:
|
||||||
entity_id: input_boolean.tina_morning_meds_taken
|
entity_id: input_boolean.tina_morning_meds_taken
|
||||||
alias: Turn on morning meds taken
|
alias: Turn on morning meds taken
|
||||||
|
action: input_boolean.turn_on
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: trigger
|
- condition: trigger
|
||||||
id:
|
id:
|
||||||
- night-taken
|
- night-taken
|
||||||
alias: Night taken
|
alias: Night taken
|
||||||
sequence:
|
sequence:
|
||||||
- service: input_boolean.turn_on
|
- metadata: {}
|
||||||
metadata: {}
|
|
||||||
data: {}
|
data: {}
|
||||||
target:
|
target:
|
||||||
entity_id: input_boolean.tina_night_meds_taken
|
entity_id: input_boolean.tina_night_meds_taken
|
||||||
alias: Turn on night meds taken
|
alias: Turn on night meds taken
|
||||||
|
action: input_boolean.turn_on
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: trigger
|
- condition: trigger
|
||||||
id:
|
id:
|
||||||
- morning-skipped
|
- morning-skipped
|
||||||
alias: Morning skipped
|
alias: Morning skipped
|
||||||
sequence:
|
sequence:
|
||||||
- service: input_boolean.turn_off
|
- metadata: {}
|
||||||
metadata: {}
|
|
||||||
data: {}
|
data: {}
|
||||||
target:
|
target:
|
||||||
entity_id: input_boolean.tina_morning_meds_reminder
|
entity_id: input_boolean.tina_morning_meds_reminder
|
||||||
alias: Deactivate morning reminders
|
alias: Deactivate morning reminders
|
||||||
|
action: input_boolean.turn_off
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: trigger
|
- condition: trigger
|
||||||
id:
|
id:
|
||||||
- night-skipped
|
- night-skipped
|
||||||
alias: Night skipped
|
alias: Night skipped
|
||||||
sequence:
|
sequence:
|
||||||
- service: input_boolean.turn_off
|
- metadata: {}
|
||||||
metadata: {}
|
|
||||||
data: {}
|
data: {}
|
||||||
target:
|
target:
|
||||||
entity_id: input_boolean.tina_night_meds_reminder
|
entity_id: input_boolean.tina_night_meds_reminder
|
||||||
alias: Deactivate night reminders
|
alias: Deactivate night reminders
|
||||||
|
action: input_boolean.turn_off
|
||||||
- conditions:
|
- conditions:
|
||||||
- condition: trigger
|
- condition: trigger
|
||||||
id:
|
id:
|
||||||
@ -5725,7 +5749,6 @@
|
|||||||
alias: Night meds reminder active
|
alias: Night meds reminder active
|
||||||
then:
|
then:
|
||||||
- alias: Send critical TTS notification
|
- alias: Send critical TTS notification
|
||||||
service: script.text_notify
|
|
||||||
metadata: {}
|
metadata: {}
|
||||||
data:
|
data:
|
||||||
type: critical
|
type: critical
|
||||||
@ -5733,6 +5756,19 @@
|
|||||||
title: HEY DUMBASS
|
title: HEY DUMBASS
|
||||||
message: YOU FORGOT TO TAKE YOUR MEDS!!!!!
|
message: YOU FORGOT TO TAKE YOUR MEDS!!!!!
|
||||||
tag: tina-left-meds
|
tag: tina-left-meds
|
||||||
|
action: script.text_notify
|
||||||
|
- conditions:
|
||||||
|
- condition: trigger
|
||||||
|
id:
|
||||||
|
- at-work
|
||||||
|
alias: At Work
|
||||||
|
sequence:
|
||||||
|
- action: input_boolean.turn_off
|
||||||
|
metadata: {}
|
||||||
|
data: {}
|
||||||
|
target:
|
||||||
|
entity_id: input_boolean.tina_night_meds_taken
|
||||||
|
alias: Turn off Night Meds Taken
|
||||||
mode: queued
|
mode: queued
|
||||||
max: 10
|
max: 10
|
||||||
- id: '1722387020007'
|
- id: '1722387020007'
|
||||||
|
42
bubble/Main Button Floors/code.js
Normal file
42
bubble/Main Button Floors/code.js
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
`${(() => {
|
||||||
|
const occupancy = hass?.states[this.config?.main_button_floors?.occupancy_entity]?.state || '';
|
||||||
|
const hot = hass?.states[this.config?.main_button_floors?.hot_entity]?.state || '';
|
||||||
|
const cold = hass?.states[this.config?.main_button_floors?.cold_entity]?.state || '';
|
||||||
|
|
||||||
|
let bg_color = 'var(--bubble-main-background-color)';
|
||||||
|
let occupied_color = 'var(--accent-color)';
|
||||||
|
let hot_color = 'var(--error-color)';
|
||||||
|
let cold_color = 'var(--purple-color)';
|
||||||
|
|
||||||
|
// Main button background
|
||||||
|
const mainButton = card?.querySelector('.bubble-button-background');
|
||||||
|
if (mainButton) {
|
||||||
|
mainButton.style.opacity = '1';
|
||||||
|
mainButton.style.backgroundColor = occupancy === 'on' ? occupied_color : bg_color;
|
||||||
|
mainButton.style.transition = 'background-color 1s';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sub button 1
|
||||||
|
const subButton1 = card?.querySelector('.bubble-sub-button-1');
|
||||||
|
if (subButton1) {
|
||||||
|
if (hot === 'on') {
|
||||||
|
subButton1.style.backgroundColor = hot_color;
|
||||||
|
} else if (cold === 'on') {
|
||||||
|
subButton1.style.backgroundColor = cold_color;
|
||||||
|
} else if (occupancy === 'on') {
|
||||||
|
subButton1.style.backgroundColor = occupied_color;
|
||||||
|
} else {
|
||||||
|
subButton1.style.backgroundColor = bg_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unavailable state
|
||||||
|
if (mainButton && occupancy === 'unavailable') {
|
||||||
|
mainButton.classList.add('is-unavailable');
|
||||||
|
} else if (mainButton) {
|
||||||
|
mainButton.classList.remove('is-unavailable');
|
||||||
|
}
|
||||||
|
|
||||||
|
// No CSS string needed
|
||||||
|
return '';
|
||||||
|
})()}`
|
22
bubble/Main Button Floors/editor.yaml
Normal file
22
bubble/Main Button Floors/editor.yaml
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
- type: expandable
|
||||||
|
title: Entity Configuration
|
||||||
|
icon: mdi:format-list-bulleted
|
||||||
|
schema:
|
||||||
|
- name: occupancy_entity
|
||||||
|
label: Occupancy Entity
|
||||||
|
selector:
|
||||||
|
entity:
|
||||||
|
device_class: occupancy
|
||||||
|
required: false
|
||||||
|
- name: hot_entity
|
||||||
|
label: Hot Entity
|
||||||
|
selector:
|
||||||
|
entity:
|
||||||
|
device_class: heat
|
||||||
|
required: false
|
||||||
|
- name: cold_entity
|
||||||
|
label: Cold Entity
|
||||||
|
selector:
|
||||||
|
entity:
|
||||||
|
device_class: cold
|
||||||
|
required: false
|
73
bubble/Main Button Floors/import.yaml
Normal file
73
bubble/Main Button Floors/import.yaml
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
main_button_floors:
|
||||||
|
name: Main Button Floors
|
||||||
|
version: '1.1'
|
||||||
|
creator: Tony Stork
|
||||||
|
supported:
|
||||||
|
- button
|
||||||
|
description: Module to provide theming for the main indoor floor buttons
|
||||||
|
code: |
|
||||||
|
${(() => {
|
||||||
|
const occupancy = hass?.states[this.config?.main_button_floors?.occupancy_entity]?.state || '';
|
||||||
|
const hot = hass?.states[this.config?.main_button_floors?.hot_entity]?.state || '';
|
||||||
|
const cold = hass?.states[this.config?.main_button_floors?.cold_entity]?.state || '';
|
||||||
|
|
||||||
|
let bg_color = 'var(--bubble-main-background-color)';
|
||||||
|
let occupied_color = 'var(--accent-color)';
|
||||||
|
let hot_color = 'var(--error-color)';
|
||||||
|
let cold_color = 'var(--purple-color)';
|
||||||
|
|
||||||
|
// Main button background
|
||||||
|
const mainButton = card?.querySelector('.bubble-button-background');
|
||||||
|
if (mainButton) {
|
||||||
|
mainButton.style.opacity = '1';
|
||||||
|
mainButton.style.backgroundColor = occupancy === 'on' ? occupied_color : bg_color;
|
||||||
|
mainButton.style.transition = 'background-color 1s';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sub button 1
|
||||||
|
const subButton1 = card?.querySelector('.bubble-sub-button-1');
|
||||||
|
if (subButton1) {
|
||||||
|
if (hot === 'on') {
|
||||||
|
subButton1.style.backgroundColor = hot_color;
|
||||||
|
} else if (cold === 'on') {
|
||||||
|
subButton1.style.backgroundColor = cold_color;
|
||||||
|
} else if (occupancy === 'on') {
|
||||||
|
subButton1.style.backgroundColor = occupied_color;
|
||||||
|
} else {
|
||||||
|
subButton1.style.backgroundColor = bg_color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unavailable state
|
||||||
|
if (mainButton && occupancy === 'unavailable') {
|
||||||
|
mainButton.classList.add('is-unavailable');
|
||||||
|
} else if (mainButton) {
|
||||||
|
mainButton.classList.remove('is-unavailable');
|
||||||
|
}
|
||||||
|
|
||||||
|
// No CSS string needed
|
||||||
|
return '';
|
||||||
|
})()}
|
||||||
|
editor:
|
||||||
|
- type: expandable
|
||||||
|
title: Entity Configuration
|
||||||
|
icon: mdi:format-list-bulleted
|
||||||
|
schema:
|
||||||
|
- name: occupancy_entity
|
||||||
|
label: Occupancy Entity
|
||||||
|
selector:
|
||||||
|
entity:
|
||||||
|
device_class: occupancy
|
||||||
|
required: false
|
||||||
|
- name: hot_entity
|
||||||
|
label: Hot Entity
|
||||||
|
selector:
|
||||||
|
entity:
|
||||||
|
device_class: heat
|
||||||
|
required: false
|
||||||
|
- name: cold_entity
|
||||||
|
label: Cold Entity
|
||||||
|
selector:
|
||||||
|
entity:
|
||||||
|
device_class: cold
|
||||||
|
required: false
|
24
bubble/Main Button Outdoors/code.js
Normal file
24
bubble/Main Button Outdoors/code.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
`${(() => {
|
||||||
|
const occupancy = hass?.states[this.config?.main_button_outdoors?.occupancy_entity]?.state || '';
|
||||||
|
|
||||||
|
let bg_color = 'var(--bubble-main-background-color)';
|
||||||
|
let occupied_color = 'var(--accent-color)';
|
||||||
|
|
||||||
|
// Main button background
|
||||||
|
const mainButton = card?.querySelector('.bubble-button-background');
|
||||||
|
if (mainButton) {
|
||||||
|
mainButton.style.opacity = '1';
|
||||||
|
mainButton.style.backgroundColor = occupancy === 'on' ? occupied_color : bg_color;
|
||||||
|
mainButton.style.transition = 'background-color 1s';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unavailable state
|
||||||
|
if (mainButton && occupancy === 'unavailable') {
|
||||||
|
mainButton.classList.add('is-unavailable');
|
||||||
|
} else if (mainButton) {
|
||||||
|
mainButton.classList.remove('is-unavailable');
|
||||||
|
}
|
||||||
|
|
||||||
|
// No CSS string needed
|
||||||
|
return '';
|
||||||
|
})()}`
|
10
bubble/Main Button Outdoors/editor.yaml
Normal file
10
bubble/Main Button Outdoors/editor.yaml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
- type: expandable
|
||||||
|
title: Entity Configuration
|
||||||
|
icon: mdi:format-list-bulleted
|
||||||
|
schema:
|
||||||
|
- name: occupancy_entity
|
||||||
|
label: Occupancy Entity
|
||||||
|
selector:
|
||||||
|
entity:
|
||||||
|
device_class: occupancy
|
||||||
|
required: false
|
43
bubble/Main Button Outdoors/import.yaml
Normal file
43
bubble/Main Button Outdoors/import.yaml
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
main_button_outdoors:
|
||||||
|
name: Main Button Outdoors
|
||||||
|
version: '1.1'
|
||||||
|
creator: Tony Stork
|
||||||
|
supported:
|
||||||
|
- button
|
||||||
|
description: Module to provide theming for outdoor floor buttons
|
||||||
|
code: |
|
||||||
|
${(() => {
|
||||||
|
const occupancy = hass?.states[this.config?.main_button_outdoors?.occupancy_entity]?.state || '';
|
||||||
|
|
||||||
|
let bg_color = 'var(--bubble-main-background-color)';
|
||||||
|
let occupied_color = 'var(--accent-color)';
|
||||||
|
|
||||||
|
// Main button background
|
||||||
|
const mainButton = card?.querySelector('.bubble-button-background');
|
||||||
|
if (mainButton) {
|
||||||
|
mainButton.style.opacity = '1';
|
||||||
|
mainButton.style.backgroundColor = occupancy === 'on' ? occupied_color : bg_color;
|
||||||
|
mainButton.style.transition = 'background-color 1s';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unavailable state
|
||||||
|
if (mainButton && occupancy === 'unavailable') {
|
||||||
|
mainButton.classList.add('is-unavailable');
|
||||||
|
} else if (mainButton) {
|
||||||
|
mainButton.classList.remove('is-unavailable');
|
||||||
|
}
|
||||||
|
|
||||||
|
// No CSS string needed
|
||||||
|
return '';
|
||||||
|
})()}
|
||||||
|
editor:
|
||||||
|
- type: expandable
|
||||||
|
title: Entity Configuration
|
||||||
|
icon: mdi:format-list-bulleted
|
||||||
|
schema:
|
||||||
|
- name: occupancy_entity
|
||||||
|
label: Occupancy Entity
|
||||||
|
selector:
|
||||||
|
entity:
|
||||||
|
device_class: occupancy
|
||||||
|
required: false
|
24
bubble/Popup Accent Color Button/code.js
Normal file
24
bubble/Popup Accent Color Button/code.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
`${(() => {
|
||||||
|
const state = hass?.states[this.config?.entity]?.state || '';
|
||||||
|
|
||||||
|
let bg_color = 'var(--background-color-2)';
|
||||||
|
let accent_color = 'var(--accent-color)';
|
||||||
|
|
||||||
|
// Main button background
|
||||||
|
const mainButton = card?.querySelector('.bubble-button-background');
|
||||||
|
if (mainButton) {
|
||||||
|
mainButton.style.opacity = '1';
|
||||||
|
mainButton.style.backgroundColor = state === 'on' ? accent_color : bg_color;
|
||||||
|
mainButton.style.transition = 'background-color 1s';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unavailable state
|
||||||
|
if (mainButton && state === 'unavailable') {
|
||||||
|
mainButton.classList.add('is-unavailable');
|
||||||
|
} else if (mainButton) {
|
||||||
|
mainButton.classList.remove('is-unavailable');
|
||||||
|
}
|
||||||
|
|
||||||
|
// No CSS string needed
|
||||||
|
return '';
|
||||||
|
})()}`
|
33
bubble/Popup Accent Color Button/import.yaml
Normal file
33
bubble/Popup Accent Color Button/import.yaml
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
popup_accent_color_button:
|
||||||
|
name: Popup Accent Color Button
|
||||||
|
version: '1.0'
|
||||||
|
creator: Tony Stork
|
||||||
|
supported:
|
||||||
|
- button
|
||||||
|
description: Will turn the button to accent color variable if config entity is on, otherwise default style applies
|
||||||
|
code: |-
|
||||||
|
${(() => {
|
||||||
|
const state = hass?.states[this.config?.entity]?.state || '';
|
||||||
|
|
||||||
|
let bg_color = 'var(--background-color-2)';
|
||||||
|
let accent_color = 'var(--accent-color)';
|
||||||
|
|
||||||
|
// Main button background
|
||||||
|
const mainButton = card?.querySelector('.bubble-button-background');
|
||||||
|
if (mainButton) {
|
||||||
|
mainButton.style.opacity = '1';
|
||||||
|
mainButton.style.backgroundColor = state === 'on' ? accent_color : bg_color;
|
||||||
|
mainButton.style.transition = 'background-color 1s';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unavailable state
|
||||||
|
if (mainButton && state === 'unavailable') {
|
||||||
|
mainButton.classList.add('is-unavailable');
|
||||||
|
} else if (mainButton) {
|
||||||
|
mainButton.classList.remove('is-unavailable');
|
||||||
|
}
|
||||||
|
|
||||||
|
// No CSS string needed
|
||||||
|
return '';
|
||||||
|
})()}
|
||||||
|
editor: ''
|
24
bubble/Popup Security Button/code.js
Normal file
24
bubble/Popup Security Button/code.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
`${(() => {
|
||||||
|
const state = hass?.states[this.config?.entity]?.state || '';
|
||||||
|
|
||||||
|
let bg_color = 'var(--background-color-2)';
|
||||||
|
let red_color = 'var(--error-color)';
|
||||||
|
|
||||||
|
// Main button background
|
||||||
|
const mainButton = card?.querySelector('.bubble-button-background');
|
||||||
|
if (mainButton) {
|
||||||
|
mainButton.style.opacity = '1';
|
||||||
|
mainButton.style.backgroundColor = state === 'on' ? red_color : bg_color;
|
||||||
|
mainButton.style.transition = 'background-color 1s';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unavailable state
|
||||||
|
if (mainButton && state === 'unavailable') {
|
||||||
|
mainButton.classList.add('is-unavailable');
|
||||||
|
} else if (mainButton) {
|
||||||
|
mainButton.classList.remove('is-unavailable');
|
||||||
|
}
|
||||||
|
|
||||||
|
// No CSS string needed
|
||||||
|
return '';
|
||||||
|
})()}`
|
33
bubble/Popup Security Button/import.yaml
Normal file
33
bubble/Popup Security Button/import.yaml
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
popup_security_button:
|
||||||
|
name: Popup Security Button
|
||||||
|
version: '1.0'
|
||||||
|
creator: Tony Stork
|
||||||
|
supported:
|
||||||
|
- button
|
||||||
|
description: Will turn the button red if there is a security fault, otherwise default style applies
|
||||||
|
code: |-
|
||||||
|
${(() => {
|
||||||
|
const state = hass?.states[this.config?.entity]?.state || '';
|
||||||
|
|
||||||
|
let bg_color = 'var(--background-color-2)';
|
||||||
|
let red_color = 'var(--error-color)';
|
||||||
|
|
||||||
|
// Main button background
|
||||||
|
const mainButton = card?.querySelector('.bubble-button-background');
|
||||||
|
if (mainButton) {
|
||||||
|
mainButton.style.opacity = '1';
|
||||||
|
mainButton.style.backgroundColor = state === 'on' ? red_color : bg_color;
|
||||||
|
mainButton.style.transition = 'background-color 1s';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unavailable state
|
||||||
|
if (mainButton && state === 'unavailable') {
|
||||||
|
mainButton.classList.add('is-unavailable');
|
||||||
|
} else if (mainButton) {
|
||||||
|
mainButton.classList.remove('is-unavailable');
|
||||||
|
}
|
||||||
|
|
||||||
|
// No CSS string needed
|
||||||
|
return '';
|
||||||
|
})()}
|
||||||
|
editor: ''
|
32
bubble/Popup Temperature Button/code.js
Normal file
32
bubble/Popup Temperature Button/code.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
`${(() => {
|
||||||
|
const hot = hass?.states[this.config?.popup_temperature_button?.hot_entity]?.state || '';
|
||||||
|
const cold = hass?.states[this.config?.popup_temperature_button?.cold_entity]?.state || '';
|
||||||
|
|
||||||
|
let bg_color = 'var(--background-color-2)';
|
||||||
|
let hot_color = 'var(--error-color)';
|
||||||
|
let cold_color = 'var(--cyan-color)';
|
||||||
|
|
||||||
|
// Main button background
|
||||||
|
const mainButton = card?.querySelector('.bubble-button-background');
|
||||||
|
if (mainButton) {
|
||||||
|
mainButton.style.opacity = '1';
|
||||||
|
if (hot === 'on') {
|
||||||
|
mainButton.style.backgroundColor = hot_color;
|
||||||
|
} else if (cold === 'on') {
|
||||||
|
mainButton.style.backgroundColor = cold_color;
|
||||||
|
} else {
|
||||||
|
mainButton.style.backgroundColor = bg_color;
|
||||||
|
}
|
||||||
|
mainButton.style.transition = 'background-color 1s';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unavailable state
|
||||||
|
if (mainButton && state === 'unavailable') {
|
||||||
|
mainButton.classList.add('is-unavailable');
|
||||||
|
} else if (mainButton) {
|
||||||
|
mainButton.classList.remove('is-unavailable');
|
||||||
|
}
|
||||||
|
|
||||||
|
// No CSS string needed
|
||||||
|
return '';
|
||||||
|
})()}`
|
14
bubble/Popup Temperature Button/editor.yaml
Normal file
14
bubble/Popup Temperature Button/editor.yaml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
- type: expandable
|
||||||
|
title: Entity Configuration
|
||||||
|
icon: mdi:format-list-bulleted
|
||||||
|
schema:
|
||||||
|
- name: hot_entity
|
||||||
|
label: Hot Entity
|
||||||
|
selector:
|
||||||
|
entity:
|
||||||
|
device_class: heat
|
||||||
|
- name: cold_entity
|
||||||
|
label: Cold Entity
|
||||||
|
selector:
|
||||||
|
entity:
|
||||||
|
device_class: cold
|
55
bubble/Popup Temperature Button/import.yaml
Normal file
55
bubble/Popup Temperature Button/import.yaml
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
popup_temperature_button:
|
||||||
|
name: Popup Temperature Button
|
||||||
|
version: '1.0'
|
||||||
|
creator: Tony Stork
|
||||||
|
supported:
|
||||||
|
- button
|
||||||
|
description: Will turn the button red if the room is too hot, cyan if too cold, otherwise default style applies
|
||||||
|
code: |-
|
||||||
|
${(() => {
|
||||||
|
const hot = hass?.states[this.config?.popup_temperature_button?.hot_entity]?.state || '';
|
||||||
|
const cold = hass?.states[this.config?.popup_temperature_button?.cold_entity]?.state || '';
|
||||||
|
|
||||||
|
let bg_color = 'var(--background-color-2)';
|
||||||
|
let hot_color = 'var(--error-color)';
|
||||||
|
let cold_color = 'var(--cyan-color)';
|
||||||
|
|
||||||
|
// Main button background
|
||||||
|
const mainButton = card?.querySelector('.bubble-button-background');
|
||||||
|
if (mainButton) {
|
||||||
|
mainButton.style.opacity = '1';
|
||||||
|
if (hot === 'on') {
|
||||||
|
mainButton.style.backgroundColor = hot_color;
|
||||||
|
} else if (cold === 'on') {
|
||||||
|
mainButton.style.backgroundColor = cold_color;
|
||||||
|
} else {
|
||||||
|
mainButton.style.backgroundColor = bg_color;
|
||||||
|
}
|
||||||
|
mainButton.style.transition = 'background-color 1s';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unavailable state
|
||||||
|
if (mainButton && state === 'unavailable') {
|
||||||
|
mainButton.classList.add('is-unavailable');
|
||||||
|
} else if (mainButton) {
|
||||||
|
mainButton.classList.remove('is-unavailable');
|
||||||
|
}
|
||||||
|
|
||||||
|
// No CSS string needed
|
||||||
|
return '';
|
||||||
|
})()}
|
||||||
|
editor:
|
||||||
|
- type: expandable
|
||||||
|
title: Entity Configuration
|
||||||
|
icon: mdi:format-list-bulleted
|
||||||
|
schema:
|
||||||
|
- name: hot_entity
|
||||||
|
label: Hot Entity
|
||||||
|
selector:
|
||||||
|
entity:
|
||||||
|
device_class: heat
|
||||||
|
- name: cold_entity
|
||||||
|
label: Cold Entity
|
||||||
|
selector:
|
||||||
|
entity:
|
||||||
|
device_class: cold
|
92
bubble/Popup Timer Card/code.js
Normal file
92
bubble/Popup Timer Card/code.js
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
:host{
|
||||||
|
--circle-color: var(--bubble-accent-color, var(--accent-color));
|
||||||
|
--percentage: ${(() => {
|
||||||
|
card.timerEntity = hass.states[entity];
|
||||||
|
const now = new Date();
|
||||||
|
const endTime = new Date(card.timerEntity.attributes.finishes_at);
|
||||||
|
const runningTime = Math.round((endTime - now) / 1000);
|
||||||
|
const maxtime = Math.round(new Date("1970-01-01 " + card.timerEntity.attributes.duration + " UTC") / 1000);
|
||||||
|
const remainingTime = Math.round(new Date("1970-01-01 " + card.timerEntity.attributes.remaining + " UTC") / 1000);
|
||||||
|
|
||||||
|
var percentage = 0;
|
||||||
|
if (isNaN(runningTime)) {
|
||||||
|
percentage = 100 - Math.round( 100.0 * remainingTime / maxtime);
|
||||||
|
} else {
|
||||||
|
percentage = 100 - Math.round( 100.0 * runningTime / maxtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNaN(percentage)) {
|
||||||
|
return "0%";
|
||||||
|
} else {
|
||||||
|
return "" + percentage +"%";
|
||||||
|
}
|
||||||
|
})()};
|
||||||
|
}
|
||||||
|
.bubble-icon-container {
|
||||||
|
background: radial-gradient(
|
||||||
|
var(--card-background-color) 60%,
|
||||||
|
transparent 0%
|
||||||
|
), conic-gradient(
|
||||||
|
var(--circle-color) var(--percentage) 0%,
|
||||||
|
var(--card-background-color) 0% 100%
|
||||||
|
) !important;
|
||||||
|
}
|
||||||
|
.bubble-icon-container:after {
|
||||||
|
content: "" !important;
|
||||||
|
height: 100% !important;
|
||||||
|
width: 100% !important;
|
||||||
|
position: absolute !important;
|
||||||
|
border-radius: 50% !important;
|
||||||
|
background: (var(--bubble-button-icon-background-color), 0.1) !important;
|
||||||
|
}
|
||||||
|
${(() => {
|
||||||
|
function UpdateState(){
|
||||||
|
try {
|
||||||
|
let now = new Date();
|
||||||
|
let endTime = new Date(card.timerEntity.attributes.finishes_at);
|
||||||
|
let runningTime = Math.round((endTime - now)/1000);
|
||||||
|
let hours = Math.floor(runningTime / 3600);
|
||||||
|
let minutes = Math.floor((runningTime - (hours * 3600)) / 60);
|
||||||
|
let remainingSeconds = runningTime % 60;
|
||||||
|
|
||||||
|
card.querySelector('.bubble-state').innerText =
|
||||||
|
(hours > 0 ? (hours + ":") : "") +
|
||||||
|
("0" + minutes).slice(-2) + ":" +
|
||||||
|
("0" + remainingSeconds).slice(-2);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
card.querySelector('.bubble-state').innerText = card.timerEntity.attributes.duration;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (card.timer == null && card.timerEntity.state === 'active') {
|
||||||
|
card.timer = setInterval(()=>{UpdateState()}, 500);
|
||||||
|
}else if (card.timerEntity.state != 'active'){
|
||||||
|
clearInterval(card.timer);
|
||||||
|
card.timer = null;
|
||||||
|
if (card.timerEntity.state !='paused') {
|
||||||
|
card.querySelector('.bubble-state').innerText = card.timerEntity.attributes.duration;
|
||||||
|
} else if(card.timerEntity.state==='paused') {
|
||||||
|
card.querySelector('.bubble-state').innerText = card.timerEntity.attributes.remaining;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})()}
|
||||||
|
|
||||||
|
${(() => {
|
||||||
|
subButtonIcon[0].setAttribute("icon",card.timerEntity.state != 'active' ?'mdi:play' : 'mdi:replay');
|
||||||
|
})()}
|
||||||
|
${(() => {
|
||||||
|
if (card.timerEntity.state != 'active') {
|
||||||
|
card.querySelector('.bubble-sub-button-2').classList.add("hidden");
|
||||||
|
}
|
||||||
|
})()}
|
||||||
|
${(() => {
|
||||||
|
if (card.timerEntity.state === 'idle') {
|
||||||
|
card.querySelector('.bubble-sub-button-3').classList.add("hidden");
|
||||||
|
}
|
||||||
|
})()}
|
||||||
|
${(() => {
|
||||||
|
if (card.timerEntity.state === 'idle') {
|
||||||
|
card.querySelector('.bubble-sub-button-4').classList.add("hidden");
|
||||||
|
}
|
||||||
|
})()}
|
101
bubble/Popup Timer Card/import.yaml
Normal file
101
bubble/Popup Timer Card/import.yaml
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
popup_timer_card:
|
||||||
|
name: Popup Timer Card
|
||||||
|
version: '1.0'
|
||||||
|
creator: Tony Stork
|
||||||
|
supported:
|
||||||
|
- button
|
||||||
|
description: Will turn the button red if the entity state is on, otherwise default style applies
|
||||||
|
code: |-
|
||||||
|
:host{
|
||||||
|
--circle-color: var(--bubble-accent-color, var(--accent-color));
|
||||||
|
--percentage: ${(() => {
|
||||||
|
card.timerEntity = hass.states[entity];
|
||||||
|
const now = new Date();
|
||||||
|
const endTime = new Date(card.timerEntity.attributes.finishes_at);
|
||||||
|
const runningTime = Math.round((endTime - now) / 1000);
|
||||||
|
const maxtime = Math.round(new Date("1970-01-01 " + card.timerEntity.attributes.duration + " UTC") / 1000);
|
||||||
|
const remainingTime = Math.round(new Date("1970-01-01 " + card.timerEntity.attributes.remaining + " UTC") / 1000);
|
||||||
|
|
||||||
|
var percentage = 0;
|
||||||
|
if (isNaN(runningTime)) {
|
||||||
|
percentage = 100 - Math.round( 100.0 * remainingTime / maxtime);
|
||||||
|
} else {
|
||||||
|
percentage = 100 - Math.round( 100.0 * runningTime / maxtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNaN(percentage)) {
|
||||||
|
return "0%";
|
||||||
|
} else {
|
||||||
|
return "" + percentage +"%";
|
||||||
|
}
|
||||||
|
})()};
|
||||||
|
}
|
||||||
|
.bubble-icon-container {
|
||||||
|
background: radial-gradient(
|
||||||
|
var(--card-background-color) 60%,
|
||||||
|
transparent 0%
|
||||||
|
), conic-gradient(
|
||||||
|
var(--circle-color) var(--percentage) 0%,
|
||||||
|
var(--card-background-color) 0% 100%
|
||||||
|
) !important;
|
||||||
|
}
|
||||||
|
.bubble-icon-container:after {
|
||||||
|
content: "" !important;
|
||||||
|
height: 100% !important;
|
||||||
|
width: 100% !important;
|
||||||
|
position: absolute !important;
|
||||||
|
border-radius: 50% !important;
|
||||||
|
background: (var(--bubble-button-icon-background-color), 0.1) !important;
|
||||||
|
}
|
||||||
|
${(() => {
|
||||||
|
function UpdateState(){
|
||||||
|
try {
|
||||||
|
let now = new Date();
|
||||||
|
let endTime = new Date(card.timerEntity.attributes.finishes_at);
|
||||||
|
let runningTime = Math.round((endTime - now)/1000);
|
||||||
|
let hours = Math.floor(runningTime / 3600);
|
||||||
|
let minutes = Math.floor((runningTime - (hours * 3600)) / 60);
|
||||||
|
let remainingSeconds = runningTime % 60;
|
||||||
|
|
||||||
|
card.querySelector('.bubble-state').innerText =
|
||||||
|
(hours > 0 ? (hours + ":") : "") +
|
||||||
|
("0" + minutes).slice(-2) + ":" +
|
||||||
|
("0" + remainingSeconds).slice(-2);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
card.querySelector('.bubble-state').innerText = card.timerEntity.attributes.duration;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (card.timer == null && card.timerEntity.state === 'active') {
|
||||||
|
card.timer = setInterval(()=>{UpdateState()}, 500);
|
||||||
|
}else if (card.timerEntity.state != 'active'){
|
||||||
|
clearInterval(card.timer);
|
||||||
|
card.timer = null;
|
||||||
|
if (card.timerEntity.state !='paused') {
|
||||||
|
card.querySelector('.bubble-state').innerText = card.timerEntity.attributes.duration;
|
||||||
|
} else if(card.timerEntity.state==='paused') {
|
||||||
|
card.querySelector('.bubble-state').innerText = card.timerEntity.attributes.remaining;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})()}
|
||||||
|
|
||||||
|
${(() => {
|
||||||
|
subButtonIcon[0].setAttribute("icon",card.timerEntity.state != 'active' ?'mdi:play' : 'mdi:replay');
|
||||||
|
})()}
|
||||||
|
${(() => {
|
||||||
|
if (card.timerEntity.state != 'active') {
|
||||||
|
card.querySelector('.bubble-sub-button-2').classList.add("hidden");
|
||||||
|
}
|
||||||
|
})()}
|
||||||
|
${(() => {
|
||||||
|
if (card.timerEntity.state === 'idle') {
|
||||||
|
card.querySelector('.bubble-sub-button-3').classList.add("hidden");
|
||||||
|
}
|
||||||
|
})()}
|
||||||
|
${(() => {
|
||||||
|
if (card.timerEntity.state === 'idle') {
|
||||||
|
card.querySelector('.bubble-sub-button-4').classList.add("hidden");
|
||||||
|
}
|
||||||
|
})()}
|
||||||
|
editor: ''
|
21
bubble/Rotating Icon/import.yaml
Normal file
21
bubble/Rotating Icon/import.yaml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
rotating_icon:
|
||||||
|
name: Rotating Icon
|
||||||
|
version: '0.1'
|
||||||
|
creator: Tony Stork
|
||||||
|
supported:
|
||||||
|
- button
|
||||||
|
- climate
|
||||||
|
- media-player
|
||||||
|
- pop-up
|
||||||
|
- separator
|
||||||
|
- horizontal-buttons-stack
|
||||||
|
description: Simple, make the icon rotate when the config entity is on
|
||||||
|
code: |-
|
||||||
|
.bubble-icon {
|
||||||
|
animation: ${state === 'on' ? 'slow-rotate 2s linear infinite' : ''};
|
||||||
|
}
|
||||||
|
@keyframes slow-rotate {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
editor: ''
|
34
bubble/State Color Button/code.js
Normal file
34
bubble/State Color Button/code.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
`${(() => {
|
||||||
|
let state;
|
||||||
|
if (this.config?.state_color_button?.alt_entity) {
|
||||||
|
state = hass?.states[this.config?.state_color_button?.alt_entity]?.state || '';
|
||||||
|
} else {
|
||||||
|
state = hass?.states[this.config?.entity]?.state || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
let bg_color = 'var(--bubble-main-background-color)';
|
||||||
|
|
||||||
|
// Use the configured color or default to accent color
|
||||||
|
let on_color = this.config?.state_color_button?.color
|
||||||
|
? `var(--${this.config.state_color_button.color})`
|
||||||
|
: 'var(--accent-color)';
|
||||||
|
|
||||||
|
// Main button background
|
||||||
|
const mainButton = card?.querySelector('.bubble-button-background');
|
||||||
|
if (mainButton) {
|
||||||
|
mainButton.style.opacity = '1';
|
||||||
|
mainButton.style.backgroundColor = state === 'on' ? on_color : bg_color;
|
||||||
|
mainButton.style.transition = 'background-color 1s';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unavailable state
|
||||||
|
if (mainButton && state === 'unavailable') {
|
||||||
|
mainButton.style.opacity = '0.5';
|
||||||
|
mainButton.classList.add('is-unavailable');
|
||||||
|
} else if (mainButton) {
|
||||||
|
mainButton.classList.remove('is-unavailable');
|
||||||
|
}
|
||||||
|
|
||||||
|
// No CSS string needed
|
||||||
|
return '';
|
||||||
|
})()}`
|
10
bubble/State Color Button/editor.yaml
Normal file
10
bubble/State Color Button/editor.yaml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
- name: color
|
||||||
|
label: Color (CSS Variable)
|
||||||
|
selector:
|
||||||
|
text: {}
|
||||||
|
required: false
|
||||||
|
- name: alt_entity
|
||||||
|
label: Entity (Optional, overrides main config)
|
||||||
|
selector:
|
||||||
|
entity: {}
|
||||||
|
required: false
|
61
bubble/State Color Button/import.yaml
Normal file
61
bubble/State Color Button/import.yaml
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
state_color_button:
|
||||||
|
name: State Color Button
|
||||||
|
version: 1.1.2
|
||||||
|
creator: Tony Stork
|
||||||
|
supported:
|
||||||
|
- button
|
||||||
|
description: |-
|
||||||
|
Module for status buttons that turn a color based on the state of the config entity. Will default to the accent color in your theme. Use the name of a CSS variable. You can also specify an alternate entity to get state from, this will override the main card config.
|
||||||
|
<br><br>
|
||||||
|
Example:
|
||||||
|
<br><br>
|
||||||
|
<code-block><pre>
|
||||||
|
color: error-color
|
||||||
|
alt_entity: sensor.your_face
|
||||||
|
</pre></code-block>
|
||||||
|
code: |-
|
||||||
|
${(() => {
|
||||||
|
let state;
|
||||||
|
if (this.config?.state_color_button?.alt_entity) {
|
||||||
|
state = hass?.states[this.config?.state_color_button?.alt_entity]?.state || '';
|
||||||
|
} else {
|
||||||
|
state = hass?.states[this.config?.entity]?.state || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
let bg_color = 'var(--bubble-main-background-color)';
|
||||||
|
|
||||||
|
// Use the configured color or default to accent color
|
||||||
|
let on_color = this.config?.state_color_button?.color
|
||||||
|
? `var(--${this.config.state_color_button.color})`
|
||||||
|
: 'var(--accent-color)';
|
||||||
|
|
||||||
|
// Main button background
|
||||||
|
const mainButton = card?.querySelector('.bubble-button-background');
|
||||||
|
if (mainButton) {
|
||||||
|
mainButton.style.opacity = '1';
|
||||||
|
mainButton.style.backgroundColor = state === 'on' ? on_color : bg_color;
|
||||||
|
mainButton.style.transition = 'background-color 1s';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unavailable state
|
||||||
|
if (mainButton && state === 'unavailable') {
|
||||||
|
mainButton.style.opacity = '0.5';
|
||||||
|
mainButton.classList.add('is-unavailable');
|
||||||
|
} else if (mainButton) {
|
||||||
|
mainButton.classList.remove('is-unavailable');
|
||||||
|
}
|
||||||
|
|
||||||
|
// No CSS string needed
|
||||||
|
return '';
|
||||||
|
})()}
|
||||||
|
editor:
|
||||||
|
- name: color
|
||||||
|
label: Color (CSS Variable)
|
||||||
|
selector:
|
||||||
|
text: {}
|
||||||
|
required: false
|
||||||
|
- name: alt_entity
|
||||||
|
label: Entity (Optional, overrides main config)
|
||||||
|
selector:
|
||||||
|
entity: {}
|
||||||
|
required: false
|
@ -825,7 +825,21 @@
|
|||||||
'ottobre',
|
'ottobre',
|
||||||
'novembre',
|
'novembre',
|
||||||
'dicembre',
|
'dicembre',
|
||||||
]
|
],
|
||||||
|
'time_of_hour':{
|
||||||
|
0: '{hour}',
|
||||||
|
1: '{hour} e un minuto',
|
||||||
|
15: '{hour} ed un quarto',
|
||||||
|
30: '{hour} e mezzo',
|
||||||
|
45: '15 minuti alle {hour}',
|
||||||
|
59: 'un minuto alle {hour}',
|
||||||
|
'past_hour': '{hour} e {minute}',
|
||||||
|
'to_hour': '{hour} meno {minute}',
|
||||||
|
},
|
||||||
|
'time_of_day':{
|
||||||
|
'midnight': 'mezzanotte',
|
||||||
|
'noon': 'mezzogiorno',
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'pt':{
|
'pt':{
|
||||||
'_language': 'Português',
|
'_language': 'Português',
|
||||||
@ -1041,7 +1055,21 @@
|
|||||||
'Październik',
|
'Październik',
|
||||||
'Listopad',
|
'Listopad',
|
||||||
'Grudzień',
|
'Grudzień',
|
||||||
]
|
],
|
||||||
|
'time_of_hour': {
|
||||||
|
0: '{hour}',
|
||||||
|
1: 'minuta po {hour}',
|
||||||
|
15: 'kwadrans po {hour}',
|
||||||
|
30: 'pół godziny po {hour}',
|
||||||
|
45: 'za kwadrans {hour}',
|
||||||
|
59: 'za minutę {hour}',
|
||||||
|
'past_hour': '{minute} po {hour}',
|
||||||
|
'to_hour': '{minute} do {hour}'
|
||||||
|
},
|
||||||
|
'time_of_day': {
|
||||||
|
'midnight': 'północ',
|
||||||
|
'noon': 'południe'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
'ru':{
|
'ru':{
|
||||||
'_language': 'Русский',
|
'_language': 'Русский',
|
||||||
@ -1779,9 +1807,9 @@
|
|||||||
{%- else %}
|
{%- else %}
|
||||||
{%- set t = translate('ago', language=language) %}
|
{%- set t = translate('ago', language=language) %}
|
||||||
{%- if '%s' in t %}
|
{%- if '%s' in t %}
|
||||||
{{ t % items }}
|
{{- t % items }}
|
||||||
{%- else %}
|
{%- else %}
|
||||||
{{- items }} {{ translate('ago', language=language) }}
|
{{- items }} {{ t }}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- else %}
|
{%- else %}
|
||||||
@ -2045,7 +2073,7 @@
|
|||||||
{%- if '%s' in t %}
|
{%- if '%s' in t %}
|
||||||
{{- t % ret }}
|
{{- t % ret }}
|
||||||
{%- else %}
|
{%- else %}
|
||||||
{{- ret }} {{ translate('ago', language=language) }}
|
{{- ret }} {{ t }}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
@ -236,7 +236,7 @@
|
|||||||
'hour': ['ч', 'час', 'часа', 'часов'],
|
'hour': ['ч', 'час', 'часа', 'часов'],
|
||||||
'minute': ['м', 'минута', 'минуты', 'минут'],
|
'minute': ['м', 'минута', 'минуты', 'минут'],
|
||||||
'second': ['с', 'секунда', 'секунды', 'секунд'],
|
'second': ['с', 'секунда', 'секунды', 'секунд'],
|
||||||
'millisecond': ['мс', 'милисекунда', 'милисекунды', 'милисекунд'],
|
'millisecond': ['мс', 'миллисекунда', 'миллисекунды', 'миллисекунд'],
|
||||||
'combine': 'и',
|
'combine': 'и',
|
||||||
'error': 'Неверная дата',
|
'error': 'Неверная дата',
|
||||||
}
|
}
|
||||||
@ -337,6 +337,22 @@
|
|||||||
'error': 'Érvénytelen dátum',
|
'error': 'Érvénytelen dátum',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'language': 'tr',
|
||||||
|
'plural_form': 'english',
|
||||||
|
'phrases': {
|
||||||
|
'year': ['yıl', 'yıl', 'yıl'],
|
||||||
|
'month': ['ay', 'ay', 'ay'],
|
||||||
|
'week': ['hf', 'hafta', 'hafta'],
|
||||||
|
'day': ['gün', 'gün', 'gün'],
|
||||||
|
'hour': ['sa', 'saat', 'saat'],
|
||||||
|
'minute': ['dk', 'dakika', 'dakika'],
|
||||||
|
'second': ['sn', 'saniye', 'saniye'],
|
||||||
|
'millisecond': ['ms', 'milisaniye', 'milisaniye'],
|
||||||
|
'combine': 've',
|
||||||
|
'error': 'Geçersiz tarih',
|
||||||
|
}
|
||||||
|
},
|
||||||
] -%}
|
] -%}
|
||||||
|
|
||||||
{# macro to convert the abbreviated input for the not_use and always_show lists to the full time part names #}
|
{# macro to convert the abbreviated input for the not_use and always_show lists to the full time part names #}
|
||||||
|
@ -27,8 +27,15 @@
|
|||||||
{% set period_str = period_str(team) %}
|
{% set period_str = period_str(team) %}
|
||||||
{% set game_clock = state_attr(team,'clock') | lower %}
|
{% set game_clock = state_attr(team,'clock') | lower %}
|
||||||
{% if state_attr(team,'league') == 'MLB' %}
|
{% if state_attr(team,'league') == 'MLB' %}
|
||||||
|
{% if 'rain delay' in game_clock %}
|
||||||
|
{# Handle cases like "Rain Delay, Top 1st" #}
|
||||||
|
{% set status, inning = game_clock.split(',', 1) %}
|
||||||
|
{% set inning_parts = inning.split(' ') %}
|
||||||
|
in a {{ status | trim }} in the {{ inning_parts[1] ~ ' of the ' ~ inning_parts[2] }} {{ period_str }}
|
||||||
|
{% else %}
|
||||||
{% set inning_parts = game_clock.split(' ') %}
|
{% set inning_parts = game_clock.split(' ') %}
|
||||||
in the {{ inning_parts[0] ~ ' of the ' ~ inning_parts[1] ~ ' ' ~ period_str }}
|
in the {{ inning_parts[0] ~ ' of the ' ~ inning_parts[1] ~ ' ' ~ period_str }}
|
||||||
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if ' - ' in game_clock %}
|
{% if ' - ' in game_clock %}
|
||||||
{% set clock_time, quarter = game_clock.split(' - ') %}
|
{% set clock_time, quarter = game_clock.split(' - ') %}
|
||||||
|
@ -19,15 +19,15 @@
|
|||||||
{% if type in ['alerts','full'] %}
|
{% if type in ['alerts','full'] %}
|
||||||
{% if is_state('input_boolean.tornado_alarm','on') %}
|
{% if is_state('input_boolean.tornado_alarm','on') %}
|
||||||
We are under a tornado warning. If you are not already in shelter, you should be. Get on it!
|
We are under a tornado warning. If you are not already in shelter, you should be. Get on it!
|
||||||
{% if state_attr('binary_sensor.tornado_warning','confirmed' == true) %}
|
{% if state_attr('binary_sensor.tornado_warning','confirmed') == true %}
|
||||||
A tornado has been confirmed in the area. Please take shelter immediately!
|
A tornado has been confirmed in the area. Please take shelter immediately!
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% elif is_state('binary_sensor.severe_thunderstorm_warning','on') %}
|
{% elif is_state('binary_sensor.severe_thunderstorm_warning','on') %}
|
||||||
We are under a severe thunderstorm warning.
|
We are under a severe thunderstorm warning.
|
||||||
{% if state_attr('binary_sensor.severe_thunderstorm_warning','tornado_possible' == true) %}
|
{% if state_attr('binary_sensor.severe_thunderstorm_warning','tornado_possible') == true %}
|
||||||
The incoming storm has the potential to produce a tornado, so please pay attention and prepare to take shelter!
|
The incoming storm has the potential to produce a tornado, so please pay attention and prepare to take shelter!
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if state_attr('binary_sensor.severe_thunderstorm_warning','considerable_destructive' == true) %}
|
{% if state_attr('binary_sensor.severe_thunderstorm_warning','considerable_destructive') == true %}
|
||||||
This storm has the potential to cause considerable damage. Please take shelter and stay safe!
|
This storm has the potential to cause considerable damage. Please take shelter and stay safe!
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% elif states('sensor.weatheralerts_active_alerts') > '0' and method != 'dashboard' %}
|
{% elif states('sensor.weatheralerts_active_alerts') > '0' and method != 'dashboard' %}
|
||||||
@ -39,9 +39,24 @@
|
|||||||
There is lightning in the area. Nearest strike is {{ ltgdist }} miles away.
|
There is lightning in the area. Nearest strike is {{ ltgdist }} miles away.
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if is_state('binary_sensor.raining','on') %}
|
{% if is_state('binary_sensor.raining','on') %}
|
||||||
|
{% if states('sensor.home_tempest_cloud_sensors_precipitation_intensity') not in ['unavailable','unknown','no_rain'] %}
|
||||||
|
{% set intensity = states('sensor.home_tempest_cloud_sensors_precipitation_intensity') %}
|
||||||
|
{% if intensity == 'very_light' %}
|
||||||
|
There is currently a very light drizzle falling.
|
||||||
|
{% elif intensity == 'light' %}
|
||||||
|
There is currently light rain falling. Front porch windows should be okay, but other windows should be closed.
|
||||||
|
{% elif intensity == 'moderate' %}
|
||||||
|
It is raining pretty good outside, you should probably make sure all windows are closed.
|
||||||
|
{% elif intensity in ['heavy','very_heavy'] %}
|
||||||
|
There is heavy rain falling, please make sure all doors and windows are closed at this time.
|
||||||
|
{% elif intensity == 'extreme' %}
|
||||||
|
It is raining extremely hard outside. Make sure all doors and windows are closed, and I recommend staying inside until it calms down. Perhaps check for roof leaks as well.
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
It is currently raining. Make sure all doors and windows are closed!
|
It is currently raining. Make sure all doors and windows are closed!
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
{% if state_attr('weather.iron_nerd_weather_station','visibility') | int < 3 %}
|
{% if state_attr('weather.iron_nerd_weather_station','visibility') | int < 3 %}
|
||||||
Caution: Current outdoor visibility is {{ state_attr('weather.iron_nerd_weather_station','visibility') }} miles.
|
Caution: Current outdoor visibility is {{ state_attr('weather.iron_nerd_weather_station','visibility') }} miles.
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -60,15 +75,15 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% if is_state('input_boolean.tornado_alarm','on') %}
|
{% if is_state('input_boolean.tornado_alarm','on') %}
|
||||||
"We are under a tornado warning. If you are not already in shelter, you should be. Get on it! "
|
"We are under a tornado warning. If you are not already in shelter, you should be. Get on it! "
|
||||||
{% if state_attr('binary_sensor.tornado_warning','confirmed' == true) %}
|
{% if state_attr('binary_sensor.tornado_warning','confirmed') == true %}
|
||||||
"A tornado has been confirmed in the area. Please take shelter immediately! "
|
"A tornado has been confirmed in the area. Please take shelter immediately! "
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% elif is_state('binary_sensor.severe_thunderstorm_warning','on') %}
|
{% elif is_state('binary_sensor.severe_thunderstorm_warning','on') %}
|
||||||
"We are under a severe thunderstorm warning. "
|
"We are under a severe thunderstorm warning. "
|
||||||
{% if state_attr('binary_sensor.severe_thunderstorm_warning','tornado_possible' == true) %}
|
{% if state_attr('binary_sensor.severe_thunderstorm_warning','tornado_possible') == true %}
|
||||||
"The incoming storm has the potential to produce a tornado, so please pay attention and prepare to take shelter! "
|
"The incoming storm has the potential to produce a tornado, so please pay attention and prepare to take shelter! "
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if state_attr('binary_sensor.severe_thunderstorm_warning','considerable_destructive' == true) %}
|
{% if state_attr('binary_sensor.severe_thunderstorm_warning','considerable_destructive') == true %}
|
||||||
"This storm has the potential to cause considerable damage. Please take shelter and stay safe! "
|
"This storm has the potential to cause considerable damage. Please take shelter and stay safe! "
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% elif is_state('input_boolean.tornado_watch','on') %}
|
{% elif is_state('input_boolean.tornado_watch','on') %}
|
||||||
@ -90,6 +105,42 @@
|
|||||||
"The nearest lightning strike is {{ ltgdist }} miles away. "
|
"The nearest lightning strike is {{ ltgdist }} miles away. "
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if is_state('binary_sensor.raining','on') %}
|
{% if is_state('binary_sensor.raining','on') %}
|
||||||
|
{% if states('sensor.home_tempest_cloud_sensors_precipitation_intensity') not in ['unavailable','unknown','no_rain'] %}
|
||||||
|
{% set intensity = states('sensor.home_tempest_cloud_sensors_precipitation_intensity') %}
|
||||||
|
{% if intensity == 'very_light' %}
|
||||||
|
{{ [
|
||||||
|
"There is currently a very light drizzle falling. ",
|
||||||
|
"It is drizzling outside, but it is not too bad. ",
|
||||||
|
"The sky is spitting on us. That's not very nice, but a mild inconvenience at most. "
|
||||||
|
] | random }}
|
||||||
|
{% elif intensity == 'light' %}
|
||||||
|
{{ [
|
||||||
|
"There is currently light rain falling. ",
|
||||||
|
"It is raining lightly outside, but it is not too bad. ",
|
||||||
|
"It kinda wainin outside, but just a little. "
|
||||||
|
] | random }}
|
||||||
|
"Front porch windows should be okay, but other windows should be closed. "
|
||||||
|
{% elif intensity == 'moderate' %}
|
||||||
|
{{ [
|
||||||
|
"It is raining pretty good outside, you should probably make sure all windows are closed. ",
|
||||||
|
"It is raining at a decent rate outside, please make sure all windows are closed. "
|
||||||
|
"If you look outside, you will see that it wainin. "
|
||||||
|
] | random }}
|
||||||
|
{% elif intensity in ['heavy','very_heavy'] %}
|
||||||
|
{{ [
|
||||||
|
"There is heavy rain falling, please make sure all doors and windows are closed at this time. ",
|
||||||
|
"It is raining heavily outside, please make sure all doors and windows are closed. ",
|
||||||
|
"It wainin sideways! Please make sure all doors and windows are closed. "
|
||||||
|
] | random }}
|
||||||
|
{% elif intensity == 'extreme' %}
|
||||||
|
{{ [
|
||||||
|
"It is raining extremely hard outside. ",
|
||||||
|
"There is a torrential downpour outside. ",
|
||||||
|
"Holy crap, I have never seen it rain this hard before. "
|
||||||
|
] | random }}
|
||||||
|
"Make sure all doors and windows are closed, and I recommend staying inside until it calms down. Perhaps check for roof leaks as well. "
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
{{ [
|
{{ [
|
||||||
"I have looked outside and determined that it is raining. ",
|
"I have looked outside and determined that it is raining. ",
|
||||||
"If you look outside the window, you will notice, it wainin. ",
|
"If you look outside the window, you will notice, it wainin. ",
|
||||||
@ -97,6 +148,7 @@
|
|||||||
"There appears to be excessive moisture currently falling from the sky. Plan accordingly. ",
|
"There appears to be excessive moisture currently falling from the sky. Plan accordingly. ",
|
||||||
] | random }}
|
] | random }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
{% if (state_attr('weather.iron_nerd_weather_station','visibility') | int ) < 3 %}
|
{% if (state_attr('weather.iron_nerd_weather_station','visibility') | int ) < 3 %}
|
||||||
{{ [
|
{{ [
|
||||||
"It is foggy outside, please exercise caution when driving. ",
|
"It is foggy outside, please exercise caution when driving. ",
|
||||||
|
@ -239,6 +239,9 @@ script:
|
|||||||
server_maintenance_annc:
|
server_maintenance_annc:
|
||||||
alias: Server Maintenance Announcement
|
alias: Server Maintenance Announcement
|
||||||
sequence:
|
sequence:
|
||||||
|
- service: input_boolean.turn_on
|
||||||
|
target:
|
||||||
|
entity_id: input_boolean.server_maintenance
|
||||||
- service: script.status_annc
|
- service: script.status_annc
|
||||||
data:
|
data:
|
||||||
who: "{{ who|default('everywhere') }}"
|
who: "{{ who|default('everywhere') }}"
|
||||||
@ -248,6 +251,9 @@ script:
|
|||||||
server_maintenance_done_annc:
|
server_maintenance_done_annc:
|
||||||
alias: Server Maintenance Done Announcement
|
alias: Server Maintenance Done Announcement
|
||||||
sequence:
|
sequence:
|
||||||
|
- service: input_boolean.turn_off
|
||||||
|
target:
|
||||||
|
entity_id: input_boolean.server_maintenance
|
||||||
- service: script.status_annc
|
- service: script.status_annc
|
||||||
data:
|
data:
|
||||||
who: "{{ who|default('everywhere') }}"
|
who: "{{ who|default('everywhere') }}"
|
||||||
|
@ -68,6 +68,7 @@ weather:
|
|||||||
{{ forecasts | selectattr('forecast','defined') | map(attribute='forecast') | list | first }}
|
{{ forecasts | selectattr('forecast','defined') | map(attribute='forecast') | list | first }}
|
||||||
pressure_template: >
|
pressure_template: >
|
||||||
{% set pressures = [
|
{% set pressures = [
|
||||||
|
states.sensor.home_tempest_local_slp,
|
||||||
states.sensor.home_tempest_cloud_sensors_sea_level_pressure,
|
states.sensor.home_tempest_cloud_sensors_sea_level_pressure,
|
||||||
states.sensor.home_pressure,
|
states.sensor.home_pressure,
|
||||||
states.sensor.kdfi_barometric_pressure
|
states.sensor.kdfi_barometric_pressure
|
||||||
@ -173,6 +174,7 @@ weather:
|
|||||||
{{ forecasts | selectattr('forecast','defined') | map(attribute='forecast') | list | first }}
|
{{ forecasts | selectattr('forecast','defined') | map(attribute='forecast') | list | first }}
|
||||||
pressure_template: >
|
pressure_template: >
|
||||||
{% set pressures = [
|
{% set pressures = [
|
||||||
|
states.sensor.home_tempest_local_slp,
|
||||||
states.sensor.home_tempest_cloud_sensors_sea_level_pressure,
|
states.sensor.home_tempest_cloud_sensors_sea_level_pressure,
|
||||||
states.sensor.home_pressure,
|
states.sensor.home_pressure,
|
||||||
states.sensor.kdfi_barometric_pressure
|
states.sensor.kdfi_barometric_pressure
|
||||||
|
@ -13,3 +13,10 @@ sensor:
|
|||||||
state_characteristic: mean
|
state_characteristic: mean
|
||||||
max_age:
|
max_age:
|
||||||
hours: 24
|
hours: 24
|
||||||
|
binary_sensor:
|
||||||
|
- platform: trend
|
||||||
|
sensors:
|
||||||
|
local_average_gas_trend:
|
||||||
|
entity_id: sensor.local_average_gas_price
|
||||||
|
friendly_name: Local Average Gas Trend
|
||||||
|
unique_id: 3405a536-1e02-412f-916b-1a62c9cb8a2e
|
||||||
|
@ -44,6 +44,9 @@ input_boolean:
|
|||||||
adaptive_lighting_adjustments:
|
adaptive_lighting_adjustments:
|
||||||
name: Adaptive Lighting Adjustments
|
name: Adaptive Lighting Adjustments
|
||||||
icon: mdi:knob
|
icon: mdi:knob
|
||||||
|
sunset_lights_triggered:
|
||||||
|
name: Sunset Lights Triggered
|
||||||
|
icon: mdi:weather-sunset
|
||||||
|
|
||||||
input_number:
|
input_number:
|
||||||
upstairs_bathroom_motion_off_delay:
|
upstairs_bathroom_motion_off_delay:
|
||||||
@ -215,6 +218,13 @@ input_number:
|
|||||||
mode: box
|
mode: box
|
||||||
unit_of_measurement: lx
|
unit_of_measurement: lx
|
||||||
icon: mdi:sun-wireless
|
icon: mdi:sun-wireless
|
||||||
|
sunset_lights_outdoor_lux_threshold:
|
||||||
|
name: Sunset Lights Outdoor Lux Threshold
|
||||||
|
min: 0
|
||||||
|
max: 10000
|
||||||
|
step: 100
|
||||||
|
unit_of_measurement: lx
|
||||||
|
icon: mdi:sun-wireless
|
||||||
|
|
||||||
# Settings for adaptive adjustments
|
# Settings for adaptive adjustments
|
||||||
daytime_colortemp_front_porch:
|
daytime_colortemp_front_porch:
|
||||||
|
@ -602,26 +602,16 @@ script:
|
|||||||
{% set low = states('sensor.overnight_lowest_temperature') | int %}
|
{% set low = states('sensor.overnight_lowest_temperature') | int %}
|
||||||
{% set high = states('sensor.todays_high_temp') | int %}
|
{% set high = states('sensor.todays_high_temp') | int %}
|
||||||
{% set kallen_bedtime = state_attr('input_datetime.kallen_bedtime','timestamp') | int %}
|
{% set kallen_bedtime = state_attr('input_datetime.kallen_bedtime','timestamp') | int %}
|
||||||
|
{% set kallen_fantime = state_attr('input_datetime.kallen_fan','timestamp') | int %}
|
||||||
|
{% set bedroom_hot = is_state('binary_sensor.kallen_bedroom_hot','on') %}
|
||||||
{% set cutoff = 81000 %} {# Cutoff time is 22:30 #}
|
{% set cutoff = 81000 %} {# Cutoff time is 22:30 #}
|
||||||
{% if is_state('binary_sensor.kallen_school_tomorrow','on') %}
|
{% if is_state('input_boolean.hot_day','on') or bedroom_hot == true %}
|
||||||
{% if is_state('input_boolean.hot_day','on') %}
|
{{ (kallen_fantime - 3600) | timestamp_custom('%H:%M',false) }}
|
||||||
{{ (kallen_bedtime - 3600) | timestamp_custom('%H:%M',false) }}
|
|
||||||
{% elif low >= 56 or high >= 75 %}
|
{% elif low >= 56 or high >= 75 %}
|
||||||
{{ (kallen_bedtime - 1800) | timestamp_custom('%H:%M',false) }}
|
{{ (kallen_bedtime - 1800) | timestamp_custom('%H:%M',false) }}
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ kallen_bedtime | timestamp_custom('%H:%M',false) }}
|
{{ kallen_bedtime | timestamp_custom('%H:%M',false) }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% elif low > 60 or high > 74 %}
|
|
||||||
{% if kallen_bedtime < cutoff %}
|
|
||||||
{{ kallen_bedtime | timestamp_custom('%H:%M',false) }}
|
|
||||||
{% else %}
|
|
||||||
22:00
|
|
||||||
{% endif %}
|
|
||||||
{% elif 56 <= low <= 60 %}
|
|
||||||
22:30
|
|
||||||
{% else %}
|
|
||||||
00:00
|
|
||||||
{% endif %}
|
|
||||||
- service: input_datetime.set_datetime
|
- service: input_datetime.set_datetime
|
||||||
entity_id: input_datetime.master_bedroom_fan
|
entity_id: input_datetime.master_bedroom_fan
|
||||||
data:
|
data:
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
input_boolean:
|
||||||
|
server_maintenance:
|
||||||
|
name: Server Maintenance
|
||||||
|
icon: mdi:wrench-clock
|
||||||
|
|
||||||
input_select:
|
input_select:
|
||||||
log_level:
|
log_level:
|
||||||
name: Log Level
|
name: Log Level
|
||||||
|
@ -57,6 +57,7 @@ ## HACS Components
|
|||||||
- [GasBuddy](https://github.com/firstof9/ha-gasbuddy)
|
- [GasBuddy](https://github.com/firstof9/ha-gasbuddy)
|
||||||
- [Union Pacific Big Boy Tracker](https://github.com/jheizer/up_4014_tracker)
|
- [Union Pacific Big Boy Tracker](https://github.com/jheizer/up_4014_tracker)
|
||||||
- [WeatherFlow Forecast](https://github.com/briis/weatherflow_forecast)
|
- [WeatherFlow Forecast](https://github.com/briis/weatherflow_forecast)
|
||||||
|
- [NWS SPC Outlook](https://github.com/sedward5/nws_spc_outlook)
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
@ -111,6 +112,7 @@ ## HACS Lovelace Cards
|
|||||||
- [Weather Chart Card](https://github.com/mlamberts78/weather-chart-card)
|
- [Weather Chart Card](https://github.com/mlamberts78/weather-chart-card)
|
||||||
- [Comfortable Environment Card](https://github.com/argaar/comfortable-environment-card)
|
- [Comfortable Environment Card](https://github.com/argaar/comfortable-environment-card)
|
||||||
- [Versatile Thermostat UI Card](https://github.com/jmcollin78/versatile-thermostat-ui-card)
|
- [Versatile Thermostat UI Card](https://github.com/jmcollin78/versatile-thermostat-ui-card)
|
||||||
|
- [Gauge Card Pro](https://github.com/benjamin-dcs/gauge-card-pro)
|
||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
@ -854,6 +854,12 @@ adaptive_on_first_floor:
|
|||||||
adaptive_on_second_floor:
|
adaptive_on_second_floor:
|
||||||
alias: Adaptive on Second Floor
|
alias: Adaptive on Second Floor
|
||||||
sequence:
|
sequence:
|
||||||
|
- action: switch.turn_on
|
||||||
|
metadata: {}
|
||||||
|
data: {}
|
||||||
|
target:
|
||||||
|
entity_id: switch.adaptive_lighting_stairwell
|
||||||
|
alias: Turn on adaptive lighting in stairwell
|
||||||
- if:
|
- if:
|
||||||
- condition: state
|
- condition: state
|
||||||
entity_id: light.hallway_overhead
|
entity_id: light.hallway_overhead
|
||||||
|
Reference in New Issue
Block a user