diff --git a/config/automation/kitchen_sink_circadian.yaml b/config/automation/kitchen_sink_circadian.yaml index 275f7fab..927b28b0 100644 --- a/config/automation/kitchen_sink_circadian.yaml +++ b/config/automation/kitchen_sink_circadian.yaml @@ -9,6 +9,7 @@ # Related Issue: n/a # Notes: Uses color temperature only to avoid inherited color scenes. # TV playback keeps the sink off so media time does not re-light it. +# Notes: Office lamp switch off-gates the sink while active PC work is in progress. ###################################################################### - alias: "Kitchen Sink Circadian Daylight" @@ -35,6 +36,10 @@ entity_id: media_player.living_room_ultra to: "playing" id: tv_playing + - platform: state + entity_id: switch.office_lamp_switch + to: "on" + id: working - platform: sun event: sunrise offset: "-00:30:00" @@ -75,6 +80,8 @@ {% set stacey_awake = is_state('person.stacey', 'home') and is_state('binary_sensor.sleepnumber_carlo_stacey_is_in_bed', 'off') %} {{ carlo_awake or stacey_awake }} + working_active: >- + {{ is_state('switch.office_lamp_switch', 'on') }} target_kelvin: >- {% set elevation = state_attr('sun.sun', 'elevation') | float(-90) %} {% if elevation <= -2 %} @@ -102,12 +109,13 @@ {{ is_state('group.family', 'home') and is_state('input_boolean.guest_mode', 'off') and not (tv_active | bool) + and not (working_active | bool) and ((awake_home | bool) or is_state('light.sink', 'on')) and (is_state('light.sink', 'on') or now().hour >= 4) }} - choose: - conditions: - condition: template - value_template: "{{ tv_active | bool }}" + value_template: "{{ tv_active | bool or working_active | bool }}" sequence: - service: light.turn_off target: diff --git a/config/packages/README.md b/config/packages/README.md index 977c5990..9793672d 100755 --- a/config/packages/README.md +++ b/config/packages/README.md @@ -59,7 +59,7 @@ Live collection of plug-and-play Home Assistant packages. Each YAML file in this | [telegram_bot.yaml](telegram_bot.yaml) | Legacy Telegram transport marker for BearClaw; the shared `joanna_send_telegram` helper now forwards through the codex_appliance direct Telegram API. | `rest_command.bearclaw_telegram_send`, `script.joanna_send_telegram` | | [phynplus.yaml](phynplus.yaml) | Phyn shutoff automations with push + Activity feed + Repairs issues for leak events. | `valve.phyn_shutoff_valve`, `binary_sensor.phyn_leak_test_running`, `repairs.create` | | [water_delivery.yaml](water_delivery.yaml) | ReadyRefresh delivery date helper with night-before + garage door Alexa reminders, plus helper-change audit logging and Telegram confirmations. | `input_datetime.water_delivery_date`, `script.send_to_logbook`, `script.joanna_send_telegram`, `notify.alexa_media_garage` | -| [vacation_mode.yaml](vacation_mode.yaml) | Auto-enable vacation mode after 24 hours away or no bed use, track sitter analytics/secure-house checks, and deliver Chromecast-first vacation briefings with a garage Alexa welcome. | `input_boolean.vacation_mode`, `input_boolean.house_sitter_present`, `sensor.vacation_house_sitter_*`, `group.garage_doors`, `lock.front_door`, `script.notify_engine`, `script.joanna_send_telegram` | +| [vacation_mode.yaml](vacation_mode.yaml) | Auto-enable vacation mode after 24 hours away or no bed use, track sitter analytics/secure-house checks, and deliver exact sitter-facing briefings with garage Alexa support. | `input_boolean.vacation_mode`, `input_boolean.house_sitter_present`, `input_datetime.vacation_house_sitter_*`, `sensor.vacation_house_sitter_*`, `group.garage_doors`, `lock.front_door`, `script.notify_engine`, `script.joanna_send_telegram` | | [maintenance_log.yaml](maintenance_log.yaml) | Joanna maintenance webhook ingest for water softener salt with idempotent event handling, Activity feed logging, and recorder-backed helper history for long-term graphing. | `automation.maintenance_log_joanna_webhook_ingest`, `input_number.water_softener_salt_total_added_lb`, `counter.water_softener_salt_event_count`, `sensor.water_softener_salt_days_since_last_add` | | [powerwall.yaml](powerwall.yaml) | Track Tesla Powerwall grid status, push live outage tracking to mobile targets, and shed loads automatically when off-grid (alerts include Activity feed + Repairs). | `binary_sensor.powerwall_grid_status`, `sensor.powerwall_*`, `script.notify_live_activity`, `repairs.create` | | [tesla_model_y.yaml](tesla_model_y.yaml) | Remind the garage and parents to plug in the Model Y after low-battery arrivals and after 8 PM when it is home but not charging. | `sensor.spaceship_battery_level`, `switch.spaceship_charge`, `notify.alexa_media_garage`, `script.notify_engine` | diff --git a/config/packages/docker_infrastructure.yaml b/config/packages/docker_infrastructure.yaml index 66dea236..dfa813f8 100644 --- a/config/packages/docker_infrastructure.yaml +++ b/config/packages/docker_infrastructure.yaml @@ -137,10 +137,15 @@ switch: - switch.pihole_secondary_container_2 - switch.poker_tracker_container - switch.poker_tracker_container_2 + - switch.portainer_agent_container + - switch.portainer_agent_container_2 - switch.portainer_container - switch.portainer_container_2 + - switch.postgres_webhooks_backup_container - switch.postgres_webhooks_engine_container - switch.postgres_webhooks_engine_container_2 + - switch.rc_price_checker_container + - switch.rc_price_checker_container_2 - switch.redis_webhooks_engine_container - switch.redis_webhooks_engine_container_2 - switch.rvtools_ppt_web_container @@ -155,6 +160,7 @@ switch: - switch.unifi_container_2 - switch.webhooks_engine_container - switch.webhooks_engine_container_2 + - switch.wordpress_db_backup_container - switch.wordpress_db_container - switch.wordpress_db_container_2 - switch.wordpress_wp_container diff --git a/config/packages/vacation_mode.yaml b/config/packages/vacation_mode.yaml index dcfb1b60..b64a03a1 100644 --- a/config/packages/vacation_mode.yaml +++ b/config/packages/vacation_mode.yaml @@ -9,7 +9,8 @@ # Related Issue: 793 # Notes: Vacation mode auto-enables after 24 hours of family absence or 24 hours without bed use while the family is away. # Notes: General vacation speech uses Chromecast only; the garage Alexa welcome is the one local-device exception. -# Notes: Visit analytics come from native entity attributes plus recorder-backed sensors instead of extra helper entities. +# Notes: Visit analytics use recorder-backed visit counts plus arrival/departure helpers for accurate durations. +# Notes: Dorm zones are reported as away locations, not Bear Stone home. ###################################################################### input_boolean: @@ -22,6 +23,25 @@ input_boolean: icon: mdi:account-key initial: off +input_datetime: + vacation_house_sitter_last_arrival: + name: Vacation House Sitter Last Arrival + has_date: true + has_time: true + vacation_house_sitter_last_departure: + name: Vacation House Sitter Last Departure + has_date: true + has_time: true + +input_number: + vacation_house_sitter_last_visit_minutes: + name: Vacation House Sitter Last Visit Minutes + min: 0 + max: 1440 + step: 0.1 + mode: box + unit_of_measurement: min + sensor: - platform: history_stats name: Vacation House Sitter Visit Count @@ -51,38 +71,35 @@ template: {% endif %} last_arrival_at: >- {% set vacation_start = as_timestamp(states.input_boolean.vacation_mode.last_changed, 0) %} - {% set raw = state_attr('automation.vacation_mode_house_sitter_arrival', 'last_triggered') %} + {% set raw = states('input_datetime.vacation_house_sitter_last_arrival') %} {% set ts = as_timestamp(raw, 0) %} - {% if ts >= vacation_start and ts > 0 %} - {{ as_local(raw).isoformat() }} + {% if is_state('input_boolean.vacation_mode', 'on') and ts >= vacation_start and ts > 0 %} + {{ as_local(as_datetime(raw)).isoformat() }} {% else %} none {% endif %} last_departure_at: >- {% set vacation_start = as_timestamp(states.input_boolean.vacation_mode.last_changed, 0) %} - {% set raw = state_attr('automation.vacation_mode_house_sitter_departure', 'last_triggered') %} + {% set raw = states('input_datetime.vacation_house_sitter_last_departure') %} {% set ts = as_timestamp(raw, 0) %} - {% if ts >= vacation_start and ts > 0 %} - {{ as_local(raw).isoformat() }} + {% if is_state('input_boolean.vacation_mode', 'on') and ts >= vacation_start and ts > 0 %} + {{ as_local(as_datetime(raw)).isoformat() }} {% else %} none {% endif %} last_visit_minutes: >- {% set vacation_start = as_timestamp(states.input_boolean.vacation_mode.last_changed, 0) %} - {% set arrival = state_attr('automation.vacation_mode_house_sitter_arrival', 'last_triggered') %} - {% set departure = state_attr('automation.vacation_mode_house_sitter_departure', 'last_triggered') %} - {% set arrival_ts = as_timestamp(arrival, 0) %} - {% set departure_ts = as_timestamp(departure, 0) %} - {% if arrival_ts >= vacation_start and departure_ts >= arrival_ts %} - {{ ((departure_ts - arrival_ts) / 60) | round(1) }} + {% set departure_ts = as_timestamp(states('input_datetime.vacation_house_sitter_last_departure'), 0) %} + {% if is_state('input_boolean.vacation_mode', 'on') and departure_ts >= vacation_start %} + {{ states('input_number.vacation_house_sitter_last_visit_minutes') | float(0) }} {% else %} 0 {% endif %} hours_since_last_visit: >- {% set vacation_start = as_timestamp(states.input_boolean.vacation_mode.last_changed, 0) %} - {% set departure = state_attr('automation.vacation_mode_house_sitter_departure', 'last_triggered') %} + {% set departure = states('input_datetime.vacation_house_sitter_last_departure') %} {% set departure_ts = as_timestamp(departure, 0) %} - {% if departure_ts >= vacation_start %} + {% if is_state('input_boolean.vacation_mode', 'on') and departure_ts >= vacation_start %} {{ ((as_timestamp(now()) - departure_ts) / 3600) | round(1) }} {% else %} 0 @@ -160,6 +177,7 @@ automation: - platform: state entity_id: group.family to: 'home' + for: "00:02:00" condition: - condition: template @@ -255,7 +273,7 @@ automation: entry_delay: >- {{ '00:05:00' if trigger.id == 'garage' else '00:02:00' }} vacation_start_ts: "{{ as_timestamp(states.input_boolean.vacation_mode.last_changed, 0) }}" - last_departure_raw: "{{ state_attr('automation.vacation_mode_house_sitter_departure', 'last_triggered') }}" + last_departure_raw: "{{ states('input_datetime.vacation_house_sitter_last_departure') }}" last_departure_ts: "{{ as_timestamp(last_departure_raw, 0) }}" visit_number: "{{ (states('sensor.vacation_house_sitter_visit_count') | int(0)) + 1 }}" away_duration: >- @@ -286,17 +304,57 @@ automation: This is the first house-sitter visit for this vacation. {% endif %} carlo_location: >- + {% set person_state = states('person.carlo') %} {% set place = states('sensor.carlo_place') %} - {{ place if place not in ['unknown', 'unavailable', 'none', ''] else states('person.carlo') }} + {% set label = place if place not in ['unknown', 'unavailable', 'none', ''] else person_state %} + {% if person_state == 'driving' or label.startswith('Driving') %} + driving near {{ label | replace('Driving near ', '') | replace('Driving', '') | trim }} + {% elif person_state == 'home' %} + at Bear Stone home + {% elif 'Dorm' in label %} + away at {{ label }} + {% else %} + at {{ label }} + {% endif %} stacey_location: >- + {% set person_state = states('person.stacey') %} {% set place = states('sensor.stacey_place') %} - {{ place if place not in ['unknown', 'unavailable', 'none', ''] else states('person.stacey') }} + {% set label = place if place not in ['unknown', 'unavailable', 'none', ''] else person_state %} + {% if person_state == 'driving' or label.startswith('Driving') %} + driving near {{ label | replace('Driving near ', '') | replace('Driving', '') | trim }} + {% elif person_state == 'home' %} + at Bear Stone home + {% elif 'Dorm' in label %} + away at {{ label }} + {% else %} + at {{ label }} + {% endif %} justin_location: >- + {% set person_state = states('person.justin') %} {% set place = states('sensor.justin_place') %} - {{ place if place not in ['unknown', 'unavailable', 'none', ''] else states('person.justin') }} + {% set label = place if place not in ['unknown', 'unavailable', 'none', ''] else person_state %} + {% if person_state == 'driving' or label.startswith('Driving') %} + driving near {{ label | replace('Driving near ', '') | replace('Driving', '') | trim }} + {% elif person_state == 'home' %} + at Bear Stone home + {% elif 'Dorm' in label %} + away at {{ label }} + {% else %} + at {{ label }} + {% endif %} paige_location: >- + {% set person_state = states('person.paige') %} {% set place = states('sensor.paige_place') %} - {{ place if place not in ['unknown', 'unavailable', 'none', ''] else states('person.paige') }} + {% set label = place if place not in ['unknown', 'unavailable', 'none', ''] else person_state %} + {% if person_state == 'driving' or label.startswith('Driving') %} + driving near {{ label | replace('Driving near ', '') | replace('Driving', '') | trim }} + {% elif person_state == 'home' %} + at Bear Stone home + {% elif 'Dorm' in label %} + away at {{ label }} + {% else %} + at {{ label }} + {% endif %} garbage_message: >- {% set day = now().strftime('%a') %} {% if day in ['Tue', 'Sat'] %} @@ -316,8 +374,8 @@ automation: House sitter arrival detected through the {{ entry_label }}. The family was last home {{ away_duration }} ago. {{ visit_context }} - Carlo is at {{ carlo_location }}. Stacey is at {{ stacey_location }}. - Justin is at {{ justin_location }}. Paige is at {{ paige_location }}. + Carlo is {{ carlo_location }}. Stacey is {{ stacey_location }}. + Justin is {{ justin_location }}. Paige is {{ paige_location }}. Please check Molly's food, water, and litter box. {{ package_message }} {{ garbage_message }} @@ -341,6 +399,12 @@ automation: entity_id: - input_boolean.house_sitter_present + - service: input_datetime.set_datetime + target: + entity_id: input_datetime.vacation_house_sitter_last_arrival + data: + timestamp: "{{ now().timestamp() }}" + - service: automation.trigger target: entity_id: automation.late_night_helper @@ -376,6 +440,7 @@ automation: - service: script.speech_processing data: media_player: media_player.livingroomcc + speech_direct: true speech_message: "{{ arrival_message }}" - alias: 'Vacation Mode Sitter Checklist Follow-Up' @@ -411,6 +476,7 @@ automation: - service: script.speech_processing data: media_player: media_player.livingroomcc + speech_direct: true speech_message: "{{ checklist_message }}" - alias: 'Vacation Mode House Sitter Departure' @@ -442,12 +508,27 @@ automation: exit_label: >- {{ 'garage door' if trigger.id == 'garage' else 'front door' }} visit_count: "{{ states('sensor.vacation_house_sitter_visit_count') | int(0) }}" + visit_minutes_numeric: >- + {% set seconds = (as_timestamp(now()) - as_timestamp(states.input_boolean.house_sitter_present.last_changed, 0)) | int(0) %} + {{ (seconds / 60) | round(1) }} visit_duration: >- {% set seconds = (as_timestamp(now()) - as_timestamp(states.input_boolean.house_sitter_present.last_changed, 0)) | int(0) %} {% set minutes = (seconds // 60) | int(0) %} {% set remainder = (seconds % 60) | int(0) %} {{ minutes }} minute{{ 's' if minutes != 1 else '' }}{% if remainder > 0 %} and {{ remainder }} second{{ 's' if remainder != 1 else '' }}{% endif %} + - service: input_number.set_value + target: + entity_id: input_number.vacation_house_sitter_last_visit_minutes + data: + value: "{{ visit_minutes_numeric }}" + + - service: input_datetime.set_datetime + target: + entity_id: input_datetime.vacation_house_sitter_last_departure + data: + timestamp: "{{ now().timestamp() }}" + - service: homeassistant.turn_off target: entity_id: input_boolean.house_sitter_present @@ -553,7 +634,7 @@ automation: - condition: template value_template: >- {% set vacation_start = as_timestamp(states.input_boolean.vacation_mode.last_changed, 0) %} - {% set last_departure = as_timestamp(state_attr('automation.vacation_mode_house_sitter_departure', 'last_triggered'), 0) %} + {% set last_departure = as_timestamp(states('input_datetime.vacation_house_sitter_last_departure'), 0) %} {% set baseline = last_departure if last_departure >= vacation_start else vacation_start %} {{ is_state('input_boolean.vacation_mode', 'on') and is_state('input_boolean.house_sitter_present', 'off') @@ -567,7 +648,7 @@ automation: - variables: visit_count: "{{ states('sensor.vacation_house_sitter_visit_count') | int(0) }}" vacation_start: "{{ as_timestamp(states.input_boolean.vacation_mode.last_changed, 0) }}" - last_departure: "{{ as_timestamp(state_attr('automation.vacation_mode_house_sitter_departure', 'last_triggered'), 0) }}" + last_departure: "{{ as_timestamp(states('input_datetime.vacation_house_sitter_last_departure'), 0) }}" baseline: >- {{ last_departure if (last_departure | float(0)) >= (vacation_start | float(0)) else vacation_start }} hours_since: "{{ ((as_timestamp(now()) - (baseline | float(0))) / 3600) | round(1) }}" @@ -677,6 +758,7 @@ automation: - service: script.speech_processing data: media_player: media_player.livingroomcc + speech_direct: true speech_message: "{{ hint_message }}" - delay: "00:20:00" diff --git a/config/recorder.yaml b/config/recorder.yaml index c5b8d687..9ba69e5e 100755 --- a/config/recorder.yaml +++ b/config/recorder.yaml @@ -6,7 +6,7 @@ # Recorder Configuration - database retention and exclusions # Stores HA history while purging noise and controlling DB size. # ------------------------------------------------------------------- -# Notes: Keeps 180 days (1/2 year); excludes vcloudinfo pings, noisy connectivity telemetry, countdown-style alarm helpers, MariaDB snapshot helpers, raw Glances host telemetry, and other high-churn entities; MariaDB via recorder_db_url. +# Notes: Keeps 180 days (1/2 year); excludes vcloudinfo pings, noisy connectivity telemetry, countdown-style alarm helpers, low-value script/button/scene history, MariaDB snapshot helpers, raw Docker/Proxmox/Glances host telemetry, PoE live power, and other high-churn entities; MariaDB via recorder_db_url. ###################################################################### db_url: !secret recorder_db_url purge_keep_days: 180 @@ -14,6 +14,7 @@ auto_purge: true commit_interval: 30 exclude: domains: + - button - camera - device_tracker - event @@ -21,6 +22,8 @@ exclude: - image - media_player - persistent_notification + - scene + - script - sun - update - zone @@ -57,12 +60,68 @@ exclude: - sensor.*_wifi_signal - sensor.*_wifi_signal_strength - sensor.*_wake_alarm_minutes + - sensor.*_cpu_usage_total* + - sensor.*_memory_usage* - sensor.*_temperature_state - sensor.*_humidity_state - sensor.*_last_seen* - sensor.192_168_10_17_* - sensor.docker14_* - sensor.docker69_* + - sensor.alarm_panel_*_free_memory + - sensor.alarm_panel_*_internal_storage_free_space + - sensor.joanna_minutes_since_* + - sensor.node_proxmox*_containers_running + - sensor.node_proxmox*_cpu_used + - sensor.node_proxmox*_disk_used_percentage + - sensor.node_proxmox*_memory_free + - sensor.node_proxmox*_memory_used + - sensor.node_proxmox*_memory_used_percentage + - sensor.node_proxmox*_total_updates + - sensor.node_proxmox*_virtual_machines_running + - sensor.poe_*_poe_power + - sensor.proxmox1_cpu_load + - sensor.proxmox1_cpu_usage + - sensor.proxmox1_disk_free + - sensor.proxmox1_disk_usage + - sensor.proxmox1_disk_used + - sensor.proxmox1_*_disk_read + - sensor.proxmox1_*_disk_write + - sensor.proxmox1_*_rx + - sensor.proxmox1_*_tx + - sensor.proxmox1_memory_free + - sensor.proxmox1_memory_usage + - sensor.proxmox1_memory_use + - sensor.proxmox1_processor_fan_* + - sensor.proxmox1_running + - sensor.proxmox1_sleeping + - sensor.proxmox1_swap_* + - sensor.proxmox1_threads + - sensor.proxmox1_total + - sensor.proxmox2_cpu_load + - sensor.proxmox2_cpu_usage + - sensor.proxmox2_disk_free + - sensor.proxmox2_disk_usage + - sensor.proxmox2_disk_used + - sensor.proxmox2_*_disk_read + - sensor.proxmox2_*_disk_write + - sensor.proxmox2_*_rx + - sensor.proxmox2_*_tx + - sensor.proxmox2_memory_free + - sensor.proxmox2_memory_usage + - sensor.proxmox2_memory_use + - sensor.proxmox2_processor_fan_* + - sensor.proxmox2_running + - sensor.proxmox2_sleeping + - sensor.proxmox2_swap_* + - sensor.proxmox2_threads + - sensor.proxmox2_total + - sensor.qemu_*_cpu_used + - sensor.qemu_*_disk_used_percentage + - sensor.qemu_*_memory_free + - sensor.qemu_*_memory_used + - sensor.qemu_*_memory_used_percentage + - sensor.storage_proxmox*_*_disk_used_percentage - switch.*_do_not_disturb_* - switch.*_repeat_switch - input_text.l10s_vacuum_* diff --git a/config/script/README.md b/config/script/README.md index 34ffb504..4e42fbb4 100755 --- a/config/script/README.md +++ b/config/script/README.md @@ -31,7 +31,7 @@ Reusable scripts that other automations call for notifications, lighting, safety | [notify_live_activity.yaml](notify_live_activity.yaml) | Shared helper for tagged live activity/live update pushes and clear commands. | | [send_to_logbook.yaml](send_to_logbook.yaml) | Generic `logbook.log` helper for Activity feed entries (Issue #1550). | | [joanna_dispatch.yaml](joanna_dispatch.yaml) | Shared AGENT engineer dispatch contract that routes HA-detected issues into Joanna/BearClaw remediation. | -| [speech_engine.yaml](speech_engine.yaml) | TTS/announcement orchestration with templated speech; speech processing also routes garage Echo announcements and office Echo announcements when the office lamp switch indicates active PC work. | +| [speech_engine.yaml](speech_engine.yaml) | TTS/announcement orchestration with templated speech; speech processing can bypass LLM rewriting for exact messages and also routes garage/office Echo announcements. | | [monthly_color_scene.yaml](monthly_color_scene.yaml) | Seasonal lighting scenes used across automations. | | [interior_off.yaml](interior_off.yaml) | One-call "all interior lights off" helper. | diff --git a/config/script/speech_processing.yaml b/config/script/speech_processing.yaml index 7f7bc405..03b26604 100755 --- a/config/script/speech_processing.yaml +++ b/config/script/speech_processing.yaml @@ -9,6 +9,7 @@ # Related Issue: 798 # Notes: Operates only when family/guest/vacation and speech notification # guards allow it, with time-aware volume. +# Notes: Set `speech_direct: true` for exact visitor-facing announcements that should not be rewritten by the LLM. # Notes: Garage Echo is an always-on announcement target. Office Echo is # added when switch.office_lamp_switch is on, which tracks active PC work. ###################################################################### @@ -20,6 +21,11 @@ speech_processing: - event: openai_instructions_sent event_data: instructions: "{{ speech_message | striptags }}" + + - variables: + direct_speech: "{{ speech_direct | default(false) | bool }}" + routed_media_players: "{{ media_player | string | lower }}" + speech_response: "{{ speech_message | striptags | trim }}" - condition: and conditions: @@ -67,16 +73,20 @@ speech_processing: 0.2 {% endif %} - - service: conversation.process - data: - agent_id: conversation.openai_conversation - text: >- - {{ speech_message }} - response_variable: agent + - choose: + - conditions: + - condition: template + value_template: "{{ not direct_speech }}" + sequence: + - service: conversation.process + data: + agent_id: conversation.openai_conversation + text: >- + {{ speech_message }} + response_variable: agent - - variables: - speech_response: "{{ agent.response.speech.plain.speech }}" - routed_media_players: "{{ media_player | string | lower }}" + - variables: + speech_response: "{{ agent.response.speech.plain.speech }}" - service: tts.cloud_say data: diff --git a/config/templates/speech/briefing.yaml b/config/templates/speech/briefing.yaml index ce241a6c..6040edaf 100755 --- a/config/templates/speech/briefing.yaml +++ b/config/templates/speech/briefing.yaml @@ -7,6 +7,8 @@ # Generates macro prompts for weather, reminders, and AI-driven speech routines. # ------------------------------------------------------------------- # Weather, responsibilities, holidays, air quality, and fact prompts parsed by speech_processing/speech_engine. +# Notes: Dorm zones are away from Bear Stone; only person state `home` +# means someone is physically home at this house. ###################################################################### @@ -201,6 +203,8 @@ {% set place_state = states(place_sensor_id) if place_sensor_id in states else 'unknown' %} {% set location_label = place_state if place_state not in ['unknown','unavailable','','none'] else person_state %} {% set location_label = 'Away' if location_label in ['unknown','unavailable','','none'] else location_label %} + {% set at_bear_stone = person_state == 'home' %} + {% set at_dorm = 'Dorm' in location_label %} {% set last_changed = as_timestamp(person.last_changed) %} {% set seconds = (as_timestamp(now()) - last_changed) | int(0) if last_changed else 0 %} {% set hours = (seconds // 3600) | int %} @@ -208,9 +212,13 @@ {% set duration = (hours ~ ' hours') if hours >= 1 else (minutes ~ ' minutes') %} {% if person_state == 'driving' %} {% set driving_label = location_label if location_label != 'Away' else '' %} - {{ name }}: Driving{% if driving_label %} near {{ driving_label }}{% endif %}{% if seconds >= 60 %} for {{ duration }}{% endif %} + {{ name }}: driving{% if driving_label %} near {{ driving_label }}{% endif %}{% if seconds >= 60 %} for {{ duration }}{% endif %} + {% elif at_bear_stone %} + {{ name }}: at Bear Stone home{% if seconds >= 60 %} for {{ duration }}{% endif %} + {% elif at_dorm %} + {{ name }}: away at {{ location_label }}{% if seconds >= 60 %} for {{ duration }}{% endif %} {% else %} - {{ name }}: {{ location_label }}{% if seconds >= 60 %} for {{ duration }}{% endif %} + {{ name }}: away at {{ location_label }}{% if seconds >= 60 %} for {{ duration }}{% endif %} {% endif %} {% endif %} {% endmacro %} @@ -239,6 +247,10 @@ {% set time = current_date.strftime('%I:%M %p') %} [Current date time: {{ month }} {{ day }}, {{ year }} {{ time }}] + [Presence rule: Bear Stone home means a resident's person state is exactly `home`. + Justin Dorm and Paige Dorm are away-from-Bear-Stone locations, not home for this house. + Do not welcome or address residents at dorm zones as being home here.] + [Resident: Location: - {{ friendly_location('person.carlo', 'sensor.carlo_place', 'Carlo') }} - {{ friendly_location('person.stacey', 'sensor.stacey_place', 'Stacey') }}