-
-
Notifications
You must be signed in to change notification settings - Fork 501
Expand file tree
/
Copy pathkiosk_tablet.yaml
More file actions
945 lines (914 loc) · 41.9 KB
/
Copy pathkiosk_tablet.yaml
File metadata and controls
945 lines (914 loc) · 41.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
######################################################################
# @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 display 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's native ESPHome entities; `_2` is the live set while legacy MQTT registry entries coexist.
# Notes: Kiosk Satellite owns HA kiosk-mode hiding, connection recovery, HA camera import, and HLS-first playback; no kiosk-mode custom resource is loaded.
# Notes: Kitchen Show uses the Dim screensaver while empty/asleep; true panel-off is disabled because this Crown build naps Wi-Fi and cannot accept a remote wake.
# Notes: Kitchen Show volume is corrected to 13% at 08:00 and after HA or kiosk startup; manual changes otherwise persist.
# 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: time
at: "08:00:00"
id: daily_volume
- platform: homeassistant
event: start
id: startup_volume
- platform: state
entity_id: binary_sensor.kitchen_kiosk_should_be_on
to: "on"
- platform: state
entity_id: light.kitchen_show_screen_2
to: "on"
- platform: state
entity_id: light.kitchen_show_screen_2
to: "off"
- platform: state
entity_id: binary_sensor.kitchen_show_connectivity_2
to: "on"
id: startup_volume
- platform: state
entity_id: switch.kitchen_show_keep_screen_on_2
to: "off"
- platform: state
entity_id: binary_sensor.kitchen_kiosk_should_be_on
to: "off"
action:
- if:
- condition: template
value_template: >-
{{ trigger is defined
and trigger.id in ['daily_volume', 'startup_volume'] }}
- condition: template
value_template: >-
{% set volume = states('number.kitchen_show_volume_2') %}
{{ volume not in ['unknown', 'unavailable', 'none', '']
and (volume | float(-1)) != 13.0 }}
then:
- service: number.set_value
target:
entity_id: number.kitchen_show_volume_2
data:
value: 13
- condition: template
value_template: >-
{{ states('binary_sensor.kitchen_kiosk_should_be_on') in ['on', 'off'] }}
- choose:
- conditions:
- condition: state
entity_id: binary_sensor.kitchen_kiosk_should_be_on
state: "on"
sequence:
# Keep Android from entering true panel-off and napping Wi-Fi.
# Kiosk Satellite's Dim screensaver still owns idle brightness.
- service: switch.turn_on
target:
entity_id: switch.kitchen_show_keep_screen_on_2
- service: light.turn_on
target:
entity_id: light.kitchen_show_screen_2
- service: button.press
target:
entity_id: button.kitchen_show_postpone_screensaver_2
- service: script.kitchen_kiosk_apply_camera_policy
default:
# This Crown build drops Wi-Fi in true panel-off, so preserve the
# reachable display session and let the Dim screensaver go dark.
- service: switch.turn_on
target:
entity_id: switch.kitchen_show_keep_screen_on_2
- service: timer.cancel
target:
entity_id: timer.kitchen_kiosk_detail_display
- service: button.press
target:
entity_id: button.kitchen_show_close_camera_view_2
- service: light.turn_on
target:
entity_id: light.kitchen_show_screen_2
- service: switch.turn_on
target:
entity_id: switch.kitchen_show_screensaver_active_2
- 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_2'), 0) %}
{{ last_seen > 0 and (as_timestamp(now()) - last_seen) < 300 }}
- service: button.press
target:
entity_id: button.kitchen_show_take_screenshot_2
- 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_2
state: "on"
- condition: template
value_template: >-
{% set installed = state_attr('update.kitchen_show_update_2', 'installed_version') | default('', true) | string %}
{% set latest = state_attr('update.kitchen_show_update_2', '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_2', 'installed_version') | default('unknown', true) }}
latest_version: >-
{{ state_attr('update.kitchen_show_update_2', 'latest_version') | default('unknown', true) }}
release_url: >-
{{ state_attr('update.kitchen_show_update_2', 'release_url') | default('not provided', true) }}
structured_request: |-
KITCHEN_KIOSK_SATELLITE_UPDATE_REQUEST
target_device=Kitchen Show
update_entity=update.kitchen_show_update_2
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_2 reports installed_version equal to latest_version, in_progress is false, the Kitchen Show returns online, sensor.kitchen_show_current_page_2 is the expected kiosk dashboard, sensor.kitchen_show_remote_admin_2 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_2
- delay: "00:02:00"
- condition: state
entity_id: update.kitchen_show_update_2
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_2
- sensor.kitchen_show_last_seen_2
- sensor.kitchen_show_current_page_2
- sensor.kitchen_show_remote_admin_2
- button.kitchen_show_take_screenshot_2
diagnostics: >-
update_state={{ states('update.kitchen_show_update_2') }};
in_progress={{ state_attr('update.kitchen_show_update_2', 'in_progress') }};
last_seen={{ states('sensor.kitchen_show_last_seen_2') }};
current_page={{ states('sensor.kitchen_show_current_page_2') }};
remote_admin={{ states('sensor.kitchen_show_remote_admin_2') }}
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_2'), 0) %}
{% set page = states('sensor.kitchen_show_current_page_2') %}
{% set remote_admin = states('sensor.kitchen_show_remote_admin_2') %}
{% set connectivity = states('binary_sensor.kitchen_show_connectivity_2') %}
{% set battery = states('sensor.kitchen_show_battery_2') | 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_2', 'on'))
or screenshot_stale }}
attributes:
status: >-
{% set invalid = ['unknown', 'unavailable', 'none', ''] %}
{% set screenshot = as_timestamp(states('sensor.kitchen_show_last_screenshot_2'), 0) %}
{% set page = states('sensor.kitchen_show_current_page_2') %}
{% set remote_admin = states('sensor.kitchen_show_remote_admin_2') %}
{% set connectivity = states('binary_sensor.kitchen_show_connectivity_2') %}
{% set battery = states('sensor.kitchen_show_battery_2') | 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_2', 'on') %}
low battery
{% elif screenshot == 0 or (as_timestamp(now()) - screenshot) > 2700 %}
screenshot stale
{% elif is_state('update.kitchen_show_update_2', '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_2'
if desired_view == 'Garage'
else 'button.kitchen_show_show_front_door_2' }}
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_2') != 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_2')
not in ['none', 'unknown', 'unavailable'] }}
sequence:
- service: button.press
target:
entity_id: button.kitchen_show_close_camera_view_2
- service: button.press
target:
entity_id: button.kitchen_show_bring_to_front_2
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_2
- service: button.press
target:
entity_id: button.kitchen_show_postpone_screensaver_2
- service: button.press
target:
entity_id: button.kitchen_show_bring_to_front_2
- 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."