658 lines
22 KiB
Nix
Executable File
658 lines
22 KiB
Nix
Executable File
{
|
|
config,
|
|
lib,
|
|
namespace,
|
|
...
|
|
}:
|
|
with lib;
|
|
let
|
|
inherit (lib.${namespace}) mkBoolOpt;
|
|
cfg = config.${namespace}.services.home-assistant.automation.voice-routines;
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# BEDTIME ROUTINE
|
|
# Triggers: "goodnight", "bedtime", "I'm going to sleep"
|
|
# Actions: dim bedroom lights, set fan to sleep mode,
|
|
# turn off other lights, TTS confirm on Voice satellite,
|
|
# then turn off bedroom lights after 30s
|
|
# ---------------------------------------------------------------------------
|
|
bedtimeAutomation = ''
|
|
- id: 'voice_bedtime_routine'
|
|
alias: Voice - Bedtime Routine
|
|
description: 'Triggered by voice: dim lights, set fan to sleep mode, turn off living room'
|
|
triggers:
|
|
- trigger: conversation
|
|
command:
|
|
- goodnight
|
|
- good night
|
|
- bedtime
|
|
- time for bed
|
|
- going to sleep
|
|
- heading to bed
|
|
conditions: []
|
|
actions:
|
|
- parallel:
|
|
- action: light.turn_on
|
|
data:
|
|
brightness_pct: 10
|
|
color_temp_kelvin: 2700
|
|
transition: 5
|
|
target:
|
|
entity_id: light.bedroom_lights
|
|
- action: light.turn_off
|
|
data:
|
|
transition: 3
|
|
target:
|
|
entity_id:
|
|
- light.living_room_lights
|
|
- light.front_closet_lights
|
|
- action: fan.set_preset_mode
|
|
data:
|
|
preset_mode: sleep
|
|
target:
|
|
entity_id: fan.bedroom_fan
|
|
- action: fan.turn_on
|
|
target:
|
|
entity_id: fan.bedroom_air_purifier
|
|
- delay:
|
|
seconds: 3
|
|
- action: tts.speak
|
|
data:
|
|
cache: true
|
|
message: >-
|
|
Goodnight! Bedroom lights are dimmed, fan is in sleep mode,
|
|
and all other lights are off. Sleep well.
|
|
media_player_entity_id: media_player.home_assistant_voice_09cf6a_media_player
|
|
target:
|
|
entity_id: tts.piper
|
|
- delay:
|
|
seconds: 30
|
|
- action: light.turn_off
|
|
data:
|
|
transition: 10
|
|
target:
|
|
entity_id: light.bedroom_lights
|
|
mode: single
|
|
'';
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# GOOD MORNING ROUTINE
|
|
# Triggers: "good morning", "wake up", "rise and shine"
|
|
# Actions: gradually brighten bedroom lights to warm white, announce
|
|
# weather + briefing via TTS on Voice satellite
|
|
# ---------------------------------------------------------------------------
|
|
morningAutomation = ''
|
|
- id: 'voice_morning_routine'
|
|
alias: Voice - Good Morning Routine
|
|
description: 'Triggered by voice: brighten lights gradually and announce morning briefing'
|
|
triggers:
|
|
- trigger: conversation
|
|
command:
|
|
- good morning
|
|
- good morning home
|
|
- wake up
|
|
- rise and shine
|
|
- morning briefing
|
|
- morning report
|
|
conditions: []
|
|
actions:
|
|
- action: light.turn_on
|
|
data:
|
|
brightness_pct: 40
|
|
color_temp_kelvin: 3000
|
|
transition: 10
|
|
target:
|
|
entity_id: light.bedroom_lights
|
|
- delay:
|
|
seconds: 5
|
|
- action: light.turn_on
|
|
data:
|
|
brightness_pct: 80
|
|
color_temp_kelvin: 4000
|
|
transition: 15
|
|
target:
|
|
entity_id: light.bedroom_lights
|
|
- action: tts.speak
|
|
data:
|
|
cache: false
|
|
message: >-
|
|
Good morning! Today's weather is {{ states('weather.forecast_home') }},
|
|
with a temperature of {{ state_attr('weather.forecast_home', 'temperature') }}
|
|
degrees.
|
|
{% set lights_on = [
|
|
('Living Room', states('light.living_room_lights')),
|
|
('Bedroom', states('light.bedroom_lights')),
|
|
('Front Closet', states('light.front_closet_lights'))
|
|
] | selectattr(1, 'eq', 'on') | map(attribute=0) | list %}
|
|
{% if lights_on | length > 0 %}
|
|
{{ lights_on | length }} lights left on.
|
|
{% endif %}
|
|
{% if states('vacuum.garbage_goober') == 'error' %}
|
|
Garbage Goober needs attention.
|
|
{% endif %}
|
|
Have a great day!
|
|
media_player_entity_id: media_player.home_assistant_voice_09cf6a_media_player
|
|
target:
|
|
entity_id: tts.piper
|
|
mode: restart
|
|
'';
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# HOME STATUS SUMMARY
|
|
# Triggers: "home status", "what's on", "status report"
|
|
# ---------------------------------------------------------------------------
|
|
homeStatusAutomation = ''
|
|
- id: 'voice_home_status'
|
|
alias: Voice - Home Status Summary
|
|
description: 'Triggered by voice: announce active devices and any alerts'
|
|
triggers:
|
|
- trigger: conversation
|
|
command:
|
|
- home status
|
|
- status report
|
|
- house status
|
|
- what is on
|
|
- what is running
|
|
conditions: []
|
|
actions:
|
|
- action: tts.speak
|
|
data:
|
|
cache: false
|
|
message: >-
|
|
{% set lights_on = [
|
|
('Living Room', states('light.living_room_lights')),
|
|
('Bedroom', states('light.bedroom_lights')),
|
|
('Front Closet', states('light.front_closet_lights'))
|
|
] | selectattr(1, 'eq', 'on') | map(attribute=0) | list %}
|
|
{% if lights_on %}
|
|
Lights on: {{ lights_on | join(', ') }}.
|
|
{% else %}
|
|
All lights are off.
|
|
{% endif %}
|
|
Bedroom fan is {{ states('fan.bedroom_fan') }},
|
|
preset {{ state_attr('fan.bedroom_fan', 'preset_mode') or 'unknown' }}.
|
|
Living room purifier is {{ states('fan.living_room_air_purifier') }},
|
|
bedroom purifier is {{ states('fan.bedroom_air_purifier') }}.
|
|
Garbage Goober is {{ states('vacuum.garbage_goober') }}.
|
|
BedJet is {{ states('climate.bedjet_dbbf_c222') }}.
|
|
media_player_entity_id: media_player.home_assistant_voice_09cf6a_media_player
|
|
target:
|
|
entity_id: tts.piper
|
|
mode: restart
|
|
'';
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# PET CARE - Manual feed Joey
|
|
# ---------------------------------------------------------------------------
|
|
feedJoeyAutomation = ''
|
|
- id: 'voice_feed_joey'
|
|
alias: Voice - Feed Joey
|
|
description: 'Triggered by voice: dispense food for Joey'
|
|
triggers:
|
|
- trigger: conversation
|
|
command:
|
|
- feed Joey
|
|
- give Joey food
|
|
- Joey is hungry
|
|
- Joey needs food
|
|
- dispense food for Joey
|
|
conditions: []
|
|
actions:
|
|
- action: button.press
|
|
target:
|
|
entity_id: button.joey_smart_feeder_manual_feed
|
|
- action: tts.speak
|
|
data:
|
|
cache: true
|
|
message: Dispensing food for Joey now.
|
|
media_player_entity_id: media_player.home_assistant_voice_09cf6a_media_player
|
|
target:
|
|
entity_id: tts.piper
|
|
mode: single
|
|
'';
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# PET CARE - Manual feed Luci
|
|
# ---------------------------------------------------------------------------
|
|
feedLuciAutomation = ''
|
|
- id: 'voice_feed_luci'
|
|
alias: Voice - Feed Luci
|
|
description: 'Triggered by voice: dispense food for Luci'
|
|
triggers:
|
|
- trigger: conversation
|
|
command:
|
|
- feed Luci
|
|
- give Luci food
|
|
- Luci is hungry
|
|
- Luci needs food
|
|
- dispense food for Luci
|
|
conditions: []
|
|
actions:
|
|
- action: button.press
|
|
target:
|
|
entity_id: button.luci_smart_feeder_manual_feed
|
|
- action: tts.speak
|
|
data:
|
|
cache: true
|
|
message: Dispensing food for Luci now.
|
|
media_player_entity_id: media_player.home_assistant_voice_09cf6a_media_player
|
|
target:
|
|
entity_id: tts.piper
|
|
mode: single
|
|
'';
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# PET CARE - Last fed status
|
|
# ---------------------------------------------------------------------------
|
|
petStatusAutomation = ''
|
|
- id: 'voice_pet_status'
|
|
alias: Voice - Pet Feeding Status
|
|
description: 'Triggered by voice: announce when pets were last fed'
|
|
triggers:
|
|
- trigger: conversation
|
|
command:
|
|
- when was Joey last fed
|
|
- when did Joey eat
|
|
- has Joey been fed
|
|
- when was Luci last fed
|
|
- when did Luci eat
|
|
- has Luci been fed
|
|
- pet feeding status
|
|
- when were the cats last fed
|
|
- have the cats been fed
|
|
conditions: []
|
|
actions:
|
|
- action: tts.speak
|
|
data:
|
|
cache: false
|
|
message: >-
|
|
{% set joey_last = state_attr('automation.joey_s_scheduled_feeding', 'last_triggered') %}
|
|
{% set luci_last = state_attr('automation.luci_s_scheduled_feeding', 'last_triggered') %}
|
|
{% if joey_last %}
|
|
Joey was last fed {{ relative_time(joey_last) }} ago.
|
|
{% else %}
|
|
I do not have a record of Joey last feeding.
|
|
{% endif %}
|
|
{% if luci_last %}
|
|
Luci was last fed {{ relative_time(luci_last) }} ago.
|
|
{% else %}
|
|
I do not have a record of Luci last feeding.
|
|
{% endif %}
|
|
media_player_entity_id: media_player.home_assistant_voice_09cf6a_media_player
|
|
target:
|
|
entity_id: tts.piper
|
|
mode: restart
|
|
'';
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# AIR QUALITY - Night mode: quiet purifiers at night (22:00)
|
|
# ---------------------------------------------------------------------------
|
|
airQualityNightAutomation = ''
|
|
- id: 'air_quality_night_mode'
|
|
alias: Air Quality - Night Mode
|
|
description: 'At 10pm reduce air purifiers to low for quiet sleep'
|
|
triggers:
|
|
- trigger: time
|
|
at: "22:00:00"
|
|
conditions:
|
|
- condition: state
|
|
entity_id: fan.bedroom_air_purifier
|
|
state: "on"
|
|
actions:
|
|
- action: fan.set_percentage
|
|
data:
|
|
percentage: 20
|
|
target:
|
|
entity_id:
|
|
- fan.bedroom_air_purifier
|
|
- fan.living_room_air_purifier
|
|
mode: single
|
|
'';
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# AIR QUALITY - Day mode: restore purifiers in morning (08:00)
|
|
# ---------------------------------------------------------------------------
|
|
airQualityDayAutomation = ''
|
|
- id: 'air_quality_day_mode'
|
|
alias: Air Quality - Day Mode
|
|
description: 'At 8am restore air purifiers to normal operating speed'
|
|
triggers:
|
|
- trigger: time
|
|
at: "08:00:00"
|
|
conditions:
|
|
- condition: state
|
|
entity_id: fan.bedroom_air_purifier
|
|
state: "on"
|
|
actions:
|
|
- action: fan.set_percentage
|
|
data:
|
|
percentage: 60
|
|
target:
|
|
entity_id:
|
|
- fan.bedroom_air_purifier
|
|
- fan.living_room_air_purifier
|
|
mode: single
|
|
'';
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# AIR QUALITY - Voice control
|
|
# ---------------------------------------------------------------------------
|
|
airQualityVoiceAutomation = ''
|
|
- id: 'voice_air_quality'
|
|
alias: Voice - Air Quality Control
|
|
description: 'Voice commands to control air purifiers'
|
|
triggers:
|
|
- trigger: conversation
|
|
command:
|
|
- turn on air purifiers
|
|
- start air purifiers
|
|
- air purifiers on
|
|
- turn off air purifiers
|
|
- stop air purifiers
|
|
- air purifiers off
|
|
- air purifiers max
|
|
- set air purifiers to max
|
|
- air purifiers low
|
|
- set air purifiers to low
|
|
- quiet air purifiers
|
|
- air quality status
|
|
- how is the air quality
|
|
- what is the air quality
|
|
conditions: []
|
|
actions:
|
|
- choose:
|
|
- conditions:
|
|
- condition: template
|
|
value_template: >-
|
|
{{ 'off' in trigger.sentence.lower() or 'stop' in trigger.sentence.lower() }}
|
|
sequence:
|
|
- action: fan.turn_off
|
|
target:
|
|
entity_id:
|
|
- fan.bedroom_air_purifier
|
|
- fan.living_room_air_purifier
|
|
- action: tts.speak
|
|
data:
|
|
cache: true
|
|
message: Air purifiers turned off.
|
|
media_player_entity_id: media_player.home_assistant_voice_09cf6a_media_player
|
|
target:
|
|
entity_id: tts.piper
|
|
- conditions:
|
|
- condition: template
|
|
value_template: >-
|
|
{{ 'max' in trigger.sentence.lower() }}
|
|
sequence:
|
|
- action: fan.turn_on
|
|
target:
|
|
entity_id:
|
|
- fan.bedroom_air_purifier
|
|
- fan.living_room_air_purifier
|
|
- action: fan.set_percentage
|
|
data:
|
|
percentage: 100
|
|
target:
|
|
entity_id:
|
|
- fan.bedroom_air_purifier
|
|
- fan.living_room_air_purifier
|
|
- action: tts.speak
|
|
data:
|
|
cache: true
|
|
message: Air purifiers set to maximum.
|
|
media_player_entity_id: media_player.home_assistant_voice_09cf6a_media_player
|
|
target:
|
|
entity_id: tts.piper
|
|
- conditions:
|
|
- condition: template
|
|
value_template: >-
|
|
{{ 'low' in trigger.sentence.lower() or 'quiet' in trigger.sentence.lower() }}
|
|
sequence:
|
|
- action: fan.turn_on
|
|
target:
|
|
entity_id:
|
|
- fan.bedroom_air_purifier
|
|
- fan.living_room_air_purifier
|
|
- action: fan.set_percentage
|
|
data:
|
|
percentage: 20
|
|
target:
|
|
entity_id:
|
|
- fan.bedroom_air_purifier
|
|
- fan.living_room_air_purifier
|
|
- action: tts.speak
|
|
data:
|
|
cache: true
|
|
message: Air purifiers set to low.
|
|
media_player_entity_id: media_player.home_assistant_voice_09cf6a_media_player
|
|
target:
|
|
entity_id: tts.piper
|
|
- conditions:
|
|
- condition: template
|
|
value_template: >-
|
|
{{ 'status' in trigger.sentence.lower() or 'quality' in trigger.sentence.lower() }}
|
|
sequence:
|
|
- action: tts.speak
|
|
data:
|
|
cache: false
|
|
message: >-
|
|
Living room purifier is {{ states('fan.living_room_air_purifier') }}
|
|
at {{ state_attr('fan.living_room_air_purifier', 'percentage') | int(default=0) }} percent.
|
|
Bedroom purifier is {{ states('fan.bedroom_air_purifier') }}
|
|
at {{ state_attr('fan.bedroom_air_purifier', 'percentage') | int(default=0) }} percent.
|
|
media_player_entity_id: media_player.home_assistant_voice_09cf6a_media_player
|
|
target:
|
|
entity_id: tts.piper
|
|
default:
|
|
- action: fan.turn_on
|
|
target:
|
|
entity_id:
|
|
- fan.bedroom_air_purifier
|
|
- fan.living_room_air_purifier
|
|
- action: tts.speak
|
|
data:
|
|
cache: true
|
|
message: Air purifiers are now on.
|
|
media_player_entity_id: media_player.home_assistant_voice_09cf6a_media_player
|
|
target:
|
|
entity_id: tts.piper
|
|
mode: restart
|
|
'';
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# VACUUM - Voice control for Garbage Goober
|
|
# ---------------------------------------------------------------------------
|
|
vacuumVoiceAutomation = ''
|
|
- id: 'voice_vacuum_control'
|
|
alias: Voice - Vacuum Control
|
|
description: 'Voice commands to start, stop, dock, and check Garbage Goober'
|
|
triggers:
|
|
- trigger: conversation
|
|
command:
|
|
- start vacuuming
|
|
- start the vacuum
|
|
- run the vacuum
|
|
- vacuum the apartment
|
|
- send out Garbage Goober
|
|
- Garbage Goober go
|
|
- clean the apartment
|
|
- stop vacuuming
|
|
- stop the vacuum
|
|
- pause the vacuum
|
|
- send the vacuum home
|
|
- dock the vacuum
|
|
- Garbage Goober return
|
|
- vacuum status
|
|
- where is the vacuum
|
|
- how is Garbage Goober doing
|
|
- what is Garbage Goober doing
|
|
conditions: []
|
|
actions:
|
|
- choose:
|
|
- conditions:
|
|
- condition: template
|
|
value_template: >-
|
|
{{ 'stop' in trigger.sentence.lower() or 'pause' in trigger.sentence.lower() }}
|
|
sequence:
|
|
- action: vacuum.stop
|
|
target:
|
|
entity_id: vacuum.garbage_goober
|
|
- action: tts.speak
|
|
data:
|
|
cache: true
|
|
message: Garbage Goober has been stopped.
|
|
media_player_entity_id: media_player.home_assistant_voice_09cf6a_media_player
|
|
target:
|
|
entity_id: tts.piper
|
|
- conditions:
|
|
- condition: template
|
|
value_template: >-
|
|
{{ 'dock' in trigger.sentence.lower()
|
|
or 'home' in trigger.sentence.lower()
|
|
or 'return' in trigger.sentence.lower() }}
|
|
sequence:
|
|
- action: vacuum.return_to_base
|
|
target:
|
|
entity_id: vacuum.garbage_goober
|
|
- action: tts.speak
|
|
data:
|
|
cache: true
|
|
message: Sending Garbage Goober back to its dock.
|
|
media_player_entity_id: media_player.home_assistant_voice_09cf6a_media_player
|
|
target:
|
|
entity_id: tts.piper
|
|
- conditions:
|
|
- condition: template
|
|
value_template: >-
|
|
{{ 'status' in trigger.sentence.lower()
|
|
or 'where' in trigger.sentence.lower()
|
|
or 'how' in trigger.sentence.lower()
|
|
or 'what' in trigger.sentence.lower() }}
|
|
sequence:
|
|
- action: tts.speak
|
|
data:
|
|
cache: false
|
|
message: >-
|
|
Garbage Goober is currently {{ states('vacuum.garbage_goober') }}.
|
|
{% set battery = state_attr('vacuum.garbage_goober', 'battery_level') %}
|
|
{% if battery is not none %}
|
|
Battery is at {{ battery }} percent.
|
|
{% endif %}
|
|
media_player_entity_id: media_player.home_assistant_voice_09cf6a_media_player
|
|
target:
|
|
entity_id: tts.piper
|
|
default:
|
|
- condition: state
|
|
entity_id: vacuum.garbage_goober
|
|
state: docked
|
|
- action: vacuum.start
|
|
target:
|
|
entity_id: vacuum.garbage_goober
|
|
- action: tts.speak
|
|
data:
|
|
cache: true
|
|
message: Garbage Goober is starting to clean.
|
|
media_player_entity_id: media_player.home_assistant_voice_09cf6a_media_player
|
|
target:
|
|
entity_id: tts.piper
|
|
mode: single
|
|
'';
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# PRESENCE - Away mode when Matt leaves home
|
|
# ---------------------------------------------------------------------------
|
|
awayModeAutomation = ''
|
|
- id: 'presence_away_mode'
|
|
alias: Presence - Away Mode
|
|
description: 'When Matt leaves: turn off all lights, dock vacuum if running'
|
|
triggers:
|
|
- trigger: state
|
|
entity_id: person.matt_jallen
|
|
from: home
|
|
to: not_home
|
|
for:
|
|
minutes: 5
|
|
conditions: []
|
|
actions:
|
|
- action: light.turn_off
|
|
target:
|
|
entity_id:
|
|
- light.living_room_lights
|
|
- light.bedroom_lights
|
|
- light.front_closet_lights
|
|
- if:
|
|
- condition: not
|
|
conditions:
|
|
- condition: state
|
|
entity_id: vacuum.garbage_goober
|
|
state: docked
|
|
then:
|
|
- action: vacuum.return_to_base
|
|
target:
|
|
entity_id: vacuum.garbage_goober
|
|
mode: single
|
|
'';
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# PRESENCE - Welcome home
|
|
# ---------------------------------------------------------------------------
|
|
welcomeHomeAutomation = ''
|
|
- id: 'presence_welcome_home'
|
|
alias: Presence - Welcome Home
|
|
description: 'When Matt arrives home: turn on living room lights, TTS welcome'
|
|
triggers:
|
|
- trigger: state
|
|
entity_id: person.matt_jallen
|
|
to: home
|
|
from: not_home
|
|
conditions: []
|
|
actions:
|
|
- action: light.turn_on
|
|
data:
|
|
brightness_pct: 80
|
|
color_temp_kelvin: 3500
|
|
transition: 2
|
|
target:
|
|
entity_id: light.living_room_lights
|
|
- action: tts.speak
|
|
data:
|
|
cache: false
|
|
message: >-
|
|
Welcome home! The time is {{ now().strftime('%I:%M %p') }}.
|
|
{% if states('vacuum.garbage_goober') not in ['docked', 'idle'] %}
|
|
Garbage Goober is still {{ states('vacuum.garbage_goober') }}.
|
|
{% endif %}
|
|
media_player_entity_id: media_player.home_assistant_voice_09cf6a_media_player
|
|
target:
|
|
entity_id: tts.piper
|
|
mode: single
|
|
'';
|
|
|
|
voiceRoutineAutomations = concatStrings [
|
|
bedtimeAutomation
|
|
morningAutomation
|
|
homeStatusAutomation
|
|
feedJoeyAutomation
|
|
feedLuciAutomation
|
|
petStatusAutomation
|
|
airQualityNightAutomation
|
|
airQualityDayAutomation
|
|
airQualityVoiceAutomation
|
|
vacuumVoiceAutomation
|
|
awayModeAutomation
|
|
welcomeHomeAutomation
|
|
];
|
|
in
|
|
{
|
|
options.${namespace}.services.home-assistant.automation.voice-routines = {
|
|
enable = mkBoolOpt true "Enable voice routines and presence automations";
|
|
};
|
|
|
|
config = lib.mkIf (config.${namespace}.services.home-assistant.enable && cfg.enable) {
|
|
environment.etc."hass/voice-routines.yaml" = {
|
|
text = voiceRoutineAutomations;
|
|
user = "hass";
|
|
group = "hass";
|
|
};
|
|
};
|
|
}
|