You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

915 lines
41 KiB

######################################################################
# @CCOSTAN - Follow Me on X
# For more info visit https://www.vcloudinfo.com/click-here
# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig
# -------------------------------------------------------------------
# Kiosk Tablets - Fully recovery and Kiosk Satellite camera policy
# Keeps the Bedroom tablet stable and drives state-based Kitchen Show camera views.
# -------------------------------------------------------------------
# Related Issue: 1875
# Related Issue: 1890
# Related Issue: 1895
# Notes: `/dashboard-bedroom/home` remains the canonical desktop/future-hardware route.
# Notes: The Android 5 Fully tablet uses `/local/bedroom-kiosk.html`, a lightweight renderer.
# Notes: Shared camera, header, and alert sensors keep both Bedroom renderers DRY.
# Notes: Fully controls apply only to the legacy Bedroom tablet.
# Notes: Kitchen Show uses Kiosk Satellite discovery entities; no screensaver helper is required.
# Notes: Kiosk Satellite 2026.8.65+ owns HA kiosk-mode hiding, connection recovery, HA camera import, and HLS-first playback; no kiosk-mode custom resource is loaded.
# Notes: Kitchen Show stays dark while the house is empty or asleep and wakes only for occupied-house events.
# Notes: Garage takes over while either door is moving/open and remains for three minutes after both close; Front Door takes over while unlocked.
# Notes: At 07:00, Home Assistant stages a pending Kiosk Satellite release, then dispatches Joanna daily until installation is verified.
# Notes: Wake events only restore brightness/focus; URL reloads require page drift.
# Notes: Fully auto-reload on screen-on/screensaver-stop is disabled to avoid motion wake reload loops.
# Notes: Startup recovery waits for HA's initial websocket state burst to settle.
# Notes: Brightness recovery only runs when both SleepIQ in-bed sensors are off.
# Notes: Fully availability/page/app/power plus Kitchen connectivity, current-page/screenshot freshness, and update state feed Systems telemetry.
# Notes: Kitchen updates are advisory telemetry and do not raise kiosk or Systems fault rollups.
# Notes: Kiosk attention sensors expose only their stable status attribute so recorder preserves problem transitions without heartbeat churn.
# Notes: Nearby daytime rain or lightning starts a five-minute NOAA radar view; the ambient banner offers daylight replay while the event remains active.
# Notes: Actionable Kitchen banner slides open one shared short-lived detail surface; camera events retain priority.
# Notes: Phyn detail can restore a closed main valve only after an explicit on-screen confirmation.
# Notes: Rheem faults outrank low-hot-water reminders and reuse the hot-water diagnostic detail surface.
# Video: https://youtu.be/ChgEu0IDWzc
######################################################################
input_text:
kitchen_kiosk_detail_view:
name: "Kitchen Kiosk Detail View"
initial: none
max: 128
timer:
kitchen_kiosk_radar_display:
name: "Kitchen Kiosk Radar Display"
duration: "00:05:00"
restore: true
icon: mdi:radar
kitchen_kiosk_detail_display:
name: "Kitchen Kiosk Detail Display"
duration: "00:03:00"
restore: false
icon: mdi:card-text-outline
automation:
- alias: "Bedroom Kiosk Tablet - Return to Kiosk View"
id: 11e50d2e-f66f-4fd0-86f4-bdca075c3a1c
mode: single
max_exceeded: silent
trigger:
- platform: state
entity_id: switch.alarm_panel_1_screen
to: "on"
for: "00:00:03"
id: wake
- platform: state
entity_id: switch.alarm_panel_1_screensaver
to: "off"
for: "00:00:03"
id: wake
- platform: state
entity_id:
- sensor.alarm_panel_1_current_page
- sensor.alarm_panel_1_foreground_app
- number.alarm_panel_1_screen_brightness
for: "00:00:10"
id: drift
- platform: time_pattern
minutes: "/1"
id: periodic
- platform: homeassistant
event: start
id: startup
condition:
- condition: state
entity_id: switch.alarm_panel_1_screen
state: "on"
- condition: state
entity_id: switch.alarm_panel_1_screensaver
state: "off"
- condition: template
value_template: >-
{% set current_page = states('sensor.alarm_panel_1_current_page') %}
{% set foreground_app = states('sensor.alarm_panel_1_foreground_app') %}
{% set brightness = states('number.alarm_panel_1_screen_brightness') %}
{% set bed_clear = is_state('binary_sensor.sleepnumber_carlo_carlo_is_in_bed', 'off')
and is_state('binary_sensor.sleepnumber_carlo_stacey_is_in_bed', 'off') %}
{% set invalid = ['unknown', 'unavailable', 'none', ''] %}
{{ (current_page not in invalid and '/local/bedroom-kiosk.html' not in current_page)
or (foreground_app not in invalid and foreground_app != 'de.ozerov.fully')
or (bed_clear and brightness not in invalid and brightness | float(100) < 40) }}
action:
- choose:
- conditions:
- condition: trigger
id: startup
sequence:
- delay: "00:02:00"
- variables:
previous_page: "{{ states('sensor.alarm_panel_1_current_page') }}"
previous_app: "{{ states('sensor.alarm_panel_1_foreground_app') }}"
previous_brightness: "{{ states('number.alarm_panel_1_screen_brightness') }}"
invalid:
- unknown
- unavailable
- none
- ""
- variables:
brightness_low: >-
{{ is_state('binary_sensor.sleepnumber_carlo_carlo_is_in_bed', 'off')
and is_state('binary_sensor.sleepnumber_carlo_stacey_is_in_bed', 'off')
and previous_brightness not in invalid
and previous_brightness | float(100) < 40 }}
foreground_drift: >-
{{ previous_app not in invalid and previous_app != 'de.ozerov.fully' }}
page_drift: >-
{{ previous_page not in invalid
and '/local/bedroom-kiosk.html' not in previous_page }}
- choose:
- conditions:
- condition: template
value_template: "{{ brightness_low | bool }}"
sequence:
- service: number.set_value
target:
entity_id: number.alarm_panel_1_screen_brightness
data:
value: 100
- choose:
- conditions:
- condition: template
value_template: "{{ foreground_drift | bool }}"
sequence:
- service: button.press
target:
entity_id: button.alarm_panel_1_bring_to_foreground
- choose:
- conditions:
- condition: template
value_template: "{{ page_drift | bool }}"
sequence:
- choose:
- conditions:
- condition: template
value_template: "{{ foreground_drift | bool }}"
sequence:
- delay: "00:00:02"
- service: button.press
target:
entity_id: button.alarm_panel_1_load_start_url
- service: script.send_to_logbook
data:
topic: "KIOSK"
message: >-
Bedroom tablet reloaded after page drift from
{{ previous_page }} (foreground app: {{ previous_app }};
brightness: {{ previous_brightness }}).
- alias: "Kitchen Kiosk Satellite - State Camera Policy"
id: 4c3ddc5b-1fe2-4c11-a77c-e2c15d374e77
mode: restart
trigger:
- platform: state
entity_id: sensor.kiosk_active_camera_view
condition:
- condition: state
entity_id: binary_sensor.kitchen_kiosk_should_be_on
state: "on"
action:
- service: script.kitchen_kiosk_apply_camera_policy
- alias: "Kitchen Kiosk Satellite - Screen Policy"
id: 99d8d43b-9448-4916-b313-8117a038baaf
mode: restart
trigger:
- platform: state
entity_id: binary_sensor.kitchen_kiosk_should_be_on
to: "on"
- platform: state
entity_id: light.kitchen_show_screen
to: "on"
- platform: state
entity_id: binary_sensor.kitchen_kiosk_should_be_on
to: "off"
action:
- condition: template
value_template: >-
{{ states('binary_sensor.kitchen_kiosk_should_be_on') in ['on', 'off'] }}
- variables:
desired_volume: >-
{{ 10 if is_state('binary_sensor.kitchen_kiosk_should_be_on', 'on') else 0 }}
# Android reports the nearest hardware volume step (13% for a 10% request).
- if:
- condition: template
value_template: >-
{{ (states('number.kitchen_show_volume') | int(-1)
- desired_volume | int(-1)) | abs > 3 }}
then:
- service: number.set_value
target:
entity_id: number.kitchen_show_volume
data:
value: "{{ desired_volume | int(0) }}"
- choose:
- conditions:
- condition: state
entity_id: binary_sensor.kitchen_kiosk_should_be_on
state: "on"
sequence:
# Kiosk Satellite owns idle dimming. This event-driven dismiss
# wakes to the dashboard without a poller repeatedly forcing the
# panel on during an occupied day.
- service: button.press
target:
entity_id: button.kitchen_show_postpone_screensaver
- service: script.kitchen_kiosk_apply_camera_policy
default:
- service: timer.cancel
target:
entity_id: timer.kitchen_kiosk_detail_display
- service: button.press
target:
entity_id: button.kitchen_show_close_camera_view
- service: light.turn_off
target:
entity_id: light.kitchen_show_screen
- alias: "Kitchen Kiosk Satellite - Daylight Radar Trigger"
id: 411dc0c0-a291-48e7-a493-2481a8d9477d
description: "Show NOAA radar for five minutes when a nearby daytime rain or lightning event begins."
mode: restart
trigger:
- platform: state
entity_id: binary_sensor.kiosk_rain_radar_weather_event
to: "on"
condition:
- condition: state
entity_id: binary_sensor.kiosk_rain_radar_weather_event
state: "on"
- condition: state
entity_id: timer.kitchen_kiosk_radar_display
state: idle
action:
- service: script.kitchen_kiosk_show_event
data:
event_type: radar
- alias: "Kitchen Kiosk Satellite - Clear Detail View"
id: 17bef67a-f68e-4b57-b04c-c2b890fafb77
description: "Clear transient banner detail state after timeout or household shutdown."
mode: restart
trigger:
- platform: event
event_type: timer.finished
event_data:
entity_id: timer.kitchen_kiosk_detail_display
- platform: event
event_type: timer.cancelled
event_data:
entity_id: timer.kitchen_kiosk_detail_display
action:
- service: input_text.set_value
target:
entity_id: input_text.kitchen_kiosk_detail_view
data:
value: none
- alias: "Kitchen Kiosk Satellite - Refresh Systems Snapshot"
id: e920cab1-59d3-4d45-8aad-67170127504f
description: "Reconcile an active startup storm, then refresh the Systems dashboard screenshot."
mode: single
max_exceeded: silent
trigger:
- platform: event
event_type: homeassistant_started
id: startup
- platform: time_pattern
minutes: "/15"
id: periodic
action:
- delay: "{{ '00:03:00' if trigger.id == 'startup' else '00:00:00' }}"
- choose:
- conditions:
- condition: trigger
id: startup
sequence:
- service: automation.trigger
target:
entity_id: automation.kitchen_kiosk_satellite_daylight_radar_trigger
data:
skip_condition: false
- condition: template
value_template: >-
{% set last_seen = as_timestamp(states('sensor.kitchen_show_last_seen'), 0) %}
{{ last_seen > 0 and (as_timestamp(now()) - last_seen) < 300 }}
- service: button.press
target:
entity_id: button.kitchen_show_take_screenshot
- alias: "Kitchen Kiosk Satellite - Update Joanna Dispatch"
id: 199e30f0-e28c-4842-953d-a65bc4b4e1d3
description: "At 07:00, stage and dispatch Joanna daily while a Kiosk Satellite release remains pending for the Kitchen Show."
mode: single
max_exceeded: silent
trigger:
- platform: time
at: "07:00:00"
condition:
- condition: state
entity_id: update.kitchen_show_update
state: "on"
- condition: template
value_template: >-
{% set installed = state_attr('update.kitchen_show_update', 'installed_version') | default('', true) | string %}
{% set latest = state_attr('update.kitchen_show_update', 'latest_version') | default('', true) | string %}
{{ installed not in ['', 'unknown', 'unavailable']
and latest not in ['', 'unknown', 'unavailable']
and installed != latest }}
action:
- variables:
installed_version: >-
{{ state_attr('update.kitchen_show_update', 'installed_version') | default('unknown', true) }}
latest_version: >-
{{ state_attr('update.kitchen_show_update', 'latest_version') | default('unknown', true) }}
release_url: >-
{{ state_attr('update.kitchen_show_update', 'release_url') | default('not provided', true) }}
structured_request: |-
KITCHEN_KIOSK_SATELLITE_UPDATE_REQUEST
target_device=Kitchen Show
update_entity=update.kitchen_show_update
installed_version={{ installed_version }}
target_version={{ latest_version }}
release_url={{ release_url }}
authorization=This dispatch authorizes installing the pending Kiosk Satellite application update on the Kitchen Show only. Do not update LineageOS, Home Assistant, or unrelated applications and do not factory-reset or re-enroll the tablet.
required_action=Home Assistant already invoked update.install and allowed two minutes for the signed installer payload to stage. If the update is still pending, use the pre-authorized Joanna ops helper /opt/codex/bin/kitchen-kiosk-update --expected-version {{ latest_version }} to complete this Kiosk Satellite update over the existing LAN-only management path.
required_verification=Do not stop at a successful service call. Verify update.kitchen_show_update reports installed_version equal to latest_version, in_progress is false, the Kitchen Show returns online, sensor.kitchen_show_current_page is the expected kiosk dashboard, sensor.kitchen_show_remote_admin is available, and a fresh screenshot can be requested.
failure_policy=If the signed release cannot be installed safely or the device does not recover, stop without changing unrelated software and report the blocking evidence.
- service: update.install
continue_on_error: true
target:
entity_id: update.kitchen_show_update
- delay: "00:02:00"
- condition: state
entity_id: update.kitchen_show_update
state: "on"
- service: script.send_to_logbook
data:
topic: "KIOSK"
message: >-
Home Assistant staged and Joanna dispatched Kitchen Show Kiosk Satellite from
{{ installed_version }} to {{ latest_version }}.
- service: script.joanna_dispatch
data:
trigger_context: "HA automation kitchen_kiosk_satellite_update_joanna_dispatch (Kitchen Kiosk Satellite - Update Joanna Dispatch)"
source: "home_assistant_automation.kitchen_kiosk_satellite_update_dispatch"
summary: >-
Kiosk Satellite {{ latest_version }} is available for Kitchen Show;
installed version is {{ installed_version }}.
request: "{{ structured_request }}"
entity_ids:
- update.kitchen_show_update
- sensor.kitchen_show_last_seen
- sensor.kitchen_show_current_page
- sensor.kitchen_show_remote_admin
- button.kitchen_show_take_screenshot
diagnostics: >-
update_state={{ states('update.kitchen_show_update') }};
in_progress={{ state_attr('update.kitchen_show_update', 'in_progress') }};
last_seen={{ states('sensor.kitchen_show_last_seen') }};
current_page={{ states('sensor.kitchen_show_current_page') }};
remote_admin={{ states('sensor.kitchen_show_remote_admin') }}
template:
- sensor:
- name: "Kiosk Active Camera View"
unique_id: kiosk_active_camera_view
icon: mdi:camera-switch
state: >-
{% if is_state('binary_sensor.kiosk_garage_camera_active', 'on') %}
garage
{% elif is_state('lock.front_door', 'unlocked') %}
front_door
{% else %}
none
{% endif %}
- name: "Bedroom Kiosk Header"
unique_id: bedroom_kiosk_header
icon: mdi:bed-clock
state: >-
{% set alarm = states('sensor.bedroom_next_wake_alarm') %}
{% set alarm_ts = as_timestamp(alarm, none) %}
{% set alarm_source = states('sensor.bedroom_next_wake_alarm_source')
| replace(' Bedroom', '') %}
{% if alarm_ts is not none %}
NEXT ALARM - {{ alarm_source }} · {{ alarm_ts | timestamp_custom('%a %-I:%M %p') }}
{% else %}
NO BEDROOM WAKE ALARM SET
{% endif %}
attributes:
detail: >-
{% set weather = states('weather.pirateweather') | replace('_', ' ') | title %}
{% set temperature = state_attr('weather.pirateweather', 'temperature') %}
{% set secure = is_state('group.garage_doors', 'closed')
and is_state('group.locks', 'locked')
and is_state('group.entry_points', 'off') %}
{{ 'House secured' if secure else 'Check house security' }} ·
{{ temperature | round(0) if temperature is number else '--' }}° · {{ weather }}
- name: "Kiosk Household Alert"
unique_id: kiosk_household_alert
icon: mdi:message-alert-outline
state: >-
{% set alerts = state_attr('sensor.nws_alerts_alerts', 'Alerts') | default([], true) %}
{% set hot_water = states('sensor.rheem_wh_available_hot_water') | float(100) %}
{% set rheem_alert_count = states('sensor.rheem_wh_alert_count') | int(0) %}
{% set tomorrow = (now() + timedelta(days=1)).strftime('%Y-%m-%d') %}
{% set battery = states('sensor.spaceship_battery_level') | float(100) %}
{% set ns = namespace(name='', raw='') %}
{% for name, person, location in [
('Carlo', 'person.carlo', 'sensor.carlo_location_display'),
('Stacey', 'person.stacey', 'sensor.stacey_location_display'),
('Justin', 'person.justin', 'sensor.justin_location_display'),
('Paige', 'person.paige', 'sensor.paige_location_display')
] %}
{% if not ns.name and states(person) not in ['home', 'unknown', 'unavailable'] %}
{% set ns.name = name %}
{% set ns.raw = states(location) if states(location) not in ['unknown', 'unavailable'] else states(person) %}
{% endif %}
{% endfor %}
{% if alerts | count > 0 %}
WEATHER ALERT - {{ alerts[0].Event | default('National Weather Service') }}
{% elif is_state('binary_sensor.front_door_packages_present', 'on') %}
PACKAGE AT THE FRONT DOOR
{% elif is_state('group.entry_points', 'on') %}
ENTRY POINT OPEN
{% elif states('group.locks') not in ['locked', 'unknown', 'unavailable'] %}
CHECK THE FRONT DOOR LOCK
{% elif rheem_alert_count > 0 %}
WATER HEATER ALERT - {{ rheem_alert_count }} ACTIVE
{% elif hot_water < 30 %}
HOT WATER IS RUNNING LOW
{% elif now().strftime('%a') in ['Wed', 'Sun']
and not is_state('input_boolean.garbage_cans_out', 'on') %}
{{ 'GARBAGE + RECYCLING' if now().strftime('%a') == 'Wed' else 'GARBAGE' }} DAY
{% elif states('input_datetime.water_delivery_date') == tomorrow %}
WATER DELIVERY TOMORROW
{% elif battery < 50 and is_state('switch.spaceship_charge', 'off')
and is_state('person.carlo', 'home') and is_state('person.stacey', 'home') %}
PLUG IN THE TESLA
{% elif ns.name %}
{% set location = ns.raw | replace(ns.name ~ ' ', '') %}
{{ ns.name }} - {{ location.split(' (since ')[0] }}
{% else %}
EVERYTHING IS HANDLED
{% endif %}
attributes:
detail: >-
{% set alerts = state_attr('sensor.nws_alerts_alerts', 'Alerts') | default([], true) %}
{% set hot_water = states('sensor.rheem_wh_available_hot_water') | float(100) %}
{% set rheem_alert_count = states('sensor.rheem_wh_alert_count') | int(0) %}
{% set tomorrow = (now() + timedelta(days=1)).strftime('%Y-%m-%d') %}
{% set battery = states('sensor.spaceship_battery_level') | float(100) %}
{% set ns = namespace(name='', raw='') %}
{% for name, person, location in [
('Carlo', 'person.carlo', 'sensor.carlo_location_display'),
('Stacey', 'person.stacey', 'sensor.stacey_location_display'),
('Justin', 'person.justin', 'sensor.justin_location_display'),
('Paige', 'person.paige', 'sensor.paige_location_display')
] %}
{% if not ns.name and states(person) not in ['home', 'unknown', 'unavailable'] %}
{% set ns.name = name %}
{% set ns.raw = states(location) if states(location) not in ['unknown', 'unavailable'] else states(person) %}
{% endif %}
{% endfor %}
{% if alerts | count > 0 %}
{{ (alerts[0].Headline | default(alerts[0].Description, true))
| replace('\n', ' ') | truncate(300, true) }}
{% elif is_state('binary_sensor.front_door_packages_present', 'on') %}
Remember to bring it inside.
{% elif is_state('group.entry_points', 'on') %}
Check the exterior doors and windows.
{% elif states('group.locks') not in ['locked', 'unknown', 'unavailable'] %}
Lock status is {{ states('group.locks') | replace('_', ' ') }}.
{% elif rheem_alert_count > 0 %}
Rheem reports {{ rheem_alert_count }} active {{ 'alert' if rheem_alert_count == 1 else 'alerts' }}.
Status is {{ states('sensor.rheem_wh_diagnostic_status') | replace('_', ' ') }}.
Check Home Assistant Repairs for the diagnostic snapshot.
{% elif hot_water < 30 %}
{{ hot_water | round(0) }}% is available - keep showers short.
{% elif now().strftime('%a') in ['Wed', 'Sun']
and not is_state('input_boolean.garbage_cans_out', 'on') %}
Put the cans at the curb.
{% elif states('input_datetime.water_delivery_date') == tomorrow %}
Put the empty bottles out.
{% elif battery < 50 and is_state('switch.spaceship_charge', 'off')
and is_state('person.carlo', 'home') and is_state('person.stacey', 'home') %}
Model Y battery is {{ battery | round(0) }}%.
{% elif ns.name %}
{% set parts = ns.raw.split(' (since ') %}
{{ 'Since ' ~ (parts[1] | replace(')', '')) if parts | count > 1 else 'Away from home' }}
{% else %}
No active household alerts or reminders.
{% endif %}
- binary_sensor:
- name: "Kiosk Garage Camera Active"
unique_id: kiosk_garage_camera_active
icon: mdi:garage-alert
delay_off: "00:03:00"
state: >-
{{ states('cover.large_garage_door') in ['opening', 'open', 'closing']
or states('cover.small_garage_door') in ['opening', 'open', 'closing'] }}
- name: "Kiosk Rain Radar Weather Event"
unique_id: kiosk_rain_radar_weather_event
icon: mdi:radar
delay_on: "00:02:00"
state: >-
{% set invalid = ['unknown', 'unavailable', 'none', ''] %}
{% set precip = states('sensor.pirateweather_precip') | lower %}
{% set intensity = states('sensor.pirateweather_precip_intensity') | float(0) %}
{% set storm_distance_state = states('sensor.pirateweather_nearest_storm_distance') %}
{% set storm_distance_miles = storm_distance_state | float(999) %}
{% set lightning_count = states('sensor.blitzortung_lightning_counter') | int(0) %}
{% set lightning_distance_state = states('sensor.blitzortung_lightning_distance') %}
{% set lightning_distance_miles = lightning_distance_state | float(9999) / 1.609344 %}
{{ is_state('binary_sensor.kitchen_kiosk_should_be_on', 'on')
and is_state('sun.sun', 'above_horizon')
and (
precip == 'rain'
or intensity > 0.2
or (storm_distance_state not in invalid and storm_distance_miles <= 10)
or (lightning_count > 0
and lightning_distance_state not in invalid
and lightning_distance_miles <= 10)
) }}
- name: "Kiosk Rain Radar Active"
unique_id: kiosk_rain_radar_active
icon: mdi:radar
state: >-
{{ is_state('binary_sensor.kitchen_kiosk_should_be_on', 'on')
and is_state('sun.sun', 'above_horizon')
and is_state('timer.kitchen_kiosk_radar_display', 'active') }}
- name: "Kitchen Kiosk Should Be On"
unique_id: kitchen_kiosk_should_be_on
icon: mdi:monitor-eye
state: >-
{% set guest = is_state('input_boolean.guest_mode', 'on') %}
{% set sitter = is_state('input_boolean.house_sitter_present', 'on') %}
{% set family_home = is_state('group.family', 'home') %}
{% set carlo_bed = is_state('binary_sensor.sleepnumber_carlo_carlo_is_in_bed', 'on') %}
{% set stacey_bed = is_state('binary_sensor.sleepnumber_carlo_stacey_is_in_bed', 'on') %}
{% set bedtime = (carlo_bed or stacey_bed)
and (carlo_bed or is_state('person.carlo', 'not_home'))
and (stacey_bed or is_state('person.stacey', 'not_home')) %}
{{ guest or sitter or (family_home and not bedtime) }}
attributes:
reason: >-
{% if is_state('input_boolean.guest_mode', 'on') %}
guest mode
{% elif is_state('input_boolean.house_sitter_present', 'on') %}
house sitter present
{% elif not is_state('group.family', 'home') %}
nobody home
{% elif is_state('binary_sensor.sleepnumber_carlo_carlo_is_in_bed', 'on')
and is_state('binary_sensor.sleepnumber_carlo_stacey_is_in_bed', 'on') %}
household asleep
{% elif is_state('binary_sensor.sleepnumber_carlo_carlo_is_in_bed', 'on')
and is_state('person.stacey', 'not_home') %}
Carlo asleep and Stacey away
{% elif is_state('binary_sensor.sleepnumber_carlo_stacey_is_in_bed', 'on')
and is_state('person.carlo', 'not_home') %}
Stacey asleep and Carlo away
{% else %}
household active
{% endif %}
- name: "Bedroom Kiosk Needs Attention"
unique_id: bedroom_kiosk_needs_attention
device_class: problem
icon: mdi:tablet-alert
delay_on: "00:02:00"
delay_off: "00:00:30"
state: >-
{% set invalid = ['unknown', 'unavailable', 'none', ''] %}
{% set page = states('sensor.alarm_panel_1_current_page') %}
{% set app = states('sensor.alarm_panel_1_foreground_app') %}
{% set battery = states('sensor.alarm_panel_1_battery') | float(0) %}
{{ page in invalid
or app in invalid
or '/local/bedroom-kiosk.html' not in page
or app != 'de.ozerov.fully'
or (battery < 20 and not is_state('binary_sensor.alarm_panel_1_plugged_in', 'on')) }}
attributes:
status: >-
{% set invalid = ['unknown', 'unavailable', 'none', ''] %}
{% set page = states('sensor.alarm_panel_1_current_page') %}
{% set app = states('sensor.alarm_panel_1_foreground_app') %}
{% set battery = states('sensor.alarm_panel_1_battery') | float(0) %}
{% if page in invalid or app in invalid %}
offline
{% elif '/local/bedroom-kiosk.html' not in page %}
page drift
{% elif app != 'de.ozerov.fully' %}
app drift
{% elif battery < 20 and not is_state('binary_sensor.alarm_panel_1_plugged_in', 'on') %}
low battery
{% else %}
online
{% endif %}
- name: "Kitchen Kiosk Needs Attention"
unique_id: kitchen_kiosk_needs_attention
device_class: problem
icon: mdi:monitor-alert
delay_on: "00:02:00"
delay_off: "00:00:30"
state: >-
{% set invalid = ['unknown', 'unavailable', 'none', ''] %}
{% set screenshot = as_timestamp(states('sensor.kitchen_show_last_screenshot'), 0) %}
{% set page = states('sensor.kitchen_show_current_page') %}
{% set remote_admin = states('sensor.kitchen_show_remote_admin') %}
{% set connectivity = states('binary_sensor.kitchen_show_connectivity') %}
{% set battery = states('sensor.kitchen_show_battery') | float(0) %}
{% set device_offline = connectivity != 'on' %}
{% set screenshot_stale = screenshot == 0 or (as_timestamp(now()) - screenshot) > 2700 %}
{{ device_offline
or page in invalid
or remote_admin in invalid
or '/dashboard-kiosk-satellite-staging/home' not in page
or (battery < 20 and not is_state('binary_sensor.kitchen_show_charging', 'on'))
or screenshot_stale }}
attributes:
status: >-
{% set invalid = ['unknown', 'unavailable', 'none', ''] %}
{% set screenshot = as_timestamp(states('sensor.kitchen_show_last_screenshot'), 0) %}
{% set page = states('sensor.kitchen_show_current_page') %}
{% set remote_admin = states('sensor.kitchen_show_remote_admin') %}
{% set connectivity = states('binary_sensor.kitchen_show_connectivity') %}
{% set battery = states('sensor.kitchen_show_battery') | float(0) %}
{% if connectivity != 'on' %}
offline
{% elif page in invalid or remote_admin in invalid %}
telemetry unavailable
{% elif '/dashboard-kiosk-satellite-staging/home' not in page %}
page drift
{% elif battery < 20 and not is_state('binary_sensor.kitchen_show_charging', 'on') %}
low battery
{% elif screenshot == 0 or (as_timestamp(now()) - screenshot) > 2700 %}
screenshot stale
{% elif is_state('update.kitchen_show_update', 'on') %}
update available
{% else %}
online
{% endif %}
- name: "Kiosk Devices Need Attention"
unique_id: kiosk_devices_need_attention
device_class: problem
icon: mdi:tablet-cellphone
state: >-
{{ is_state('binary_sensor.bedroom_kiosk_needs_attention', 'on')
or is_state('binary_sensor.kitchen_kiosk_needs_attention', 'on') }}
attributes:
status: >-
{% set bedroom = is_state('binary_sensor.bedroom_kiosk_needs_attention', 'on') %}
{% set kitchen = is_state('binary_sensor.kitchen_kiosk_needs_attention', 'on') %}
{% if bedroom and kitchen %}
Bedroom and Kitchen need attention
{% elif bedroom %}
Bedroom needs attention
{% elif kitchen %}
Kitchen needs attention
{% else %}
All kiosks online
{% endif %}
devices: >-
{% set ns = namespace(items=[]) %}
{% if is_state('binary_sensor.bedroom_kiosk_needs_attention', 'on') %}
{% set ns.items = ns.items + ['Bedroom'] %}
{% endif %}
{% if is_state('binary_sensor.kitchen_kiosk_needs_attention', 'on') %}
{% set ns.items = ns.items + ['Kitchen'] %}
{% endif %}
{{ ns.items }}
script:
kitchen_kiosk_apply_camera_policy:
alias: "Kitchen Kiosk - Apply Camera Policy"
mode: restart
variables:
desired_view: >-
{{ {'garage': 'Garage', 'front_door': 'Front Door'}.get(
states('sensor.kiosk_active_camera_view'), 'none') }}
desired_button: >-
{{ 'button.kitchen_show_show_garage'
if desired_view == 'Garage'
else 'button.kitchen_show_show_front_door' }}
sequence:
- choose:
- conditions:
- condition: template
value_template: "{{ desired_view in ['Garage', 'Front Door'] }}"
sequence:
- condition: template
value_template: >-
{{ states('sensor.kitchen_show_active_camera_view') != desired_view }}
- service: script.kitchen_kiosk_show_event
data:
event_type: camera
show_button: "{{ desired_button }}"
default:
- choose:
- conditions:
- condition: template
value_template: >-
{{ states('sensor.kitchen_show_active_camera_view')
not in ['none', 'unknown', 'unavailable'] }}
sequence:
- service: button.press
target:
entity_id: button.kitchen_show_close_camera_view
- service: button.press
target:
entity_id: button.kitchen_show_bring_to_front
kitchen_kiosk_show_event:
alias: "Kitchen Kiosk - Show Display Event"
mode: restart
fields:
event_type:
name: Event type
description: Event renderer to show on the Kitchen kiosk.
required: true
selector:
select:
options:
- radar
- camera
- detail
show_button:
name: Camera view button
description: Kiosk Satellite MQTT button for the native camera view.
required: false
selector:
entity:
domain: button
sequence:
- condition: template
value_template: >-
{{ event_type in ['camera', 'detail']
or (
event_type == 'radar'
and is_state('binary_sensor.kitchen_kiosk_should_be_on', 'on')
and is_state('sun.sun', 'above_horizon')
and is_state('binary_sensor.kiosk_rain_radar_weather_event', 'on')
) }}
- service: light.turn_on
target:
entity_id: light.kitchen_show_screen
- service: button.press
target:
entity_id: button.kitchen_show_postpone_screensaver
- service: button.press
target:
entity_id: button.kitchen_show_bring_to_front
- choose:
- conditions:
- condition: template
value_template: "{{ event_type == 'radar' }}"
sequence:
- service: timer.cancel
target:
entity_id: timer.kitchen_kiosk_detail_display
- service: timer.start
target:
entity_id: timer.kitchen_kiosk_radar_display
data:
duration: "00:05:00"
- conditions:
- condition: template
value_template: "{{ event_type == 'camera' }}"
sequence:
- service: timer.cancel
target:
entity_id: timer.kitchen_kiosk_detail_display
- condition: template
value_template: >-
{{ show_button is defined and show_button | string | length > 0 }}
- delay: "00:00:01"
- service: button.press
target:
entity_id: "{{ show_button }}"
kitchen_kiosk_show_detail:
alias: "Kitchen Kiosk - Show Banner Detail"
mode: restart
fields:
detail_type:
name: Detail type
description: Contextual detail renderer requested by the active banner slide.
required: true
selector:
select:
options:
- weather
- package
- family
- entry_points
- phyn
- hot_water
detail_subject:
name: Detail subject
description: Optional alert ID or person entity for the detail renderer.
required: false
selector:
text:
variables:
normalized_type: "{{ detail_type | default('', true) | lower }}"
normalized_subject: "{{ detail_subject | default('', true) | string }}"
allowed_people:
- person.carlo
- person.stacey
- person.justin
- person.paige
phyn_alert_entities:
- binary_sensor.garage_phyn_battery_alert
- binary_sensor.garage_phyn_freeze_warning_alert
- binary_sensor.garage_phyn_high_pressure_alert
- binary_sensor.garage_phyn_leak_alert
- binary_sensor.garage_phyn_offline_leak_shutoff_alert
- binary_sensor.garage_phyn_pinhole_leak_alert
- binary_sensor.garage_phyn_recurring_flow_alert
- binary_sensor.garage_phyn_temperature_alert
detail_is_valid: >-
{% set phyn_alert = expand(phyn_alert_entities)
| selectattr('state', 'eq', 'on') | list | count > 0 %}
{{ is_state('binary_sensor.kitchen_kiosk_should_be_on', 'on')
and (
(normalized_type == 'weather' and states('sensor.nws_alerts_alerts') | int(0) > 0)
or (normalized_type == 'package' and is_state('binary_sensor.front_door_packages_present', 'on'))
or (normalized_type == 'family'
and normalized_subject in allowed_people
and states(normalized_subject) not in ['home', 'unknown', 'unavailable'])
or (normalized_type == 'entry_points' and is_state('group.entry_points', 'on'))
or (normalized_type == 'phyn'
and (phyn_alert or states('valve.phyn_shutoff_valve') != 'open'))
or (normalized_type == 'hot_water'
and (
is_state('binary_sensor.rheem_wh_problem', 'on')
or states('sensor.rheem_wh_available_hot_water') | float(100) < 30
))
) }}
detail_duration: >-
{{ '00:05:00' if normalized_type in ['weather', 'phyn'] else '00:03:00' }}
detail_value: >-
{{ normalized_type ~ ('|' ~ normalized_subject if normalized_subject | length > 0 else '') }}
sequence:
- condition: template
value_template: "{{ detail_is_valid }}"
- service: timer.cancel
target:
entity_id: timer.kitchen_kiosk_radar_display
- service: input_text.set_value
target:
entity_id: input_text.kitchen_kiosk_detail_view
data:
value: "{{ detail_value }}"
- service: timer.start
target:
entity_id: timer.kitchen_kiosk_detail_display
data:
duration: "{{ detail_duration }}"
- service: script.kitchen_kiosk_show_event
data:
event_type: detail
kitchen_kiosk_restore_phyn_water:
alias: "Kitchen Kiosk - Restore Phyn Water"
mode: single
sequence:
- condition: state
entity_id: timer.kitchen_kiosk_detail_display
state: active
- condition: template
value_template: >-
{{ states('input_text.kitchen_kiosk_detail_view').split('|')[0] == 'phyn'
and is_state('valve.phyn_shutoff_valve', 'closed') }}
- service: valve.open_valve
target:
entity_id: valve.phyn_shutoff_valve
- service: script.send_to_logbook
data:
topic: WATER
message: "Kitchen Show requested that the Phyn main water valve be turned on."

Powered by TurnKey Linux.