feat(hass): use ha-fallback with custom sentences
All checks were successful
Discord / discord commits (push) Has been skipped

This commit is contained in:
matt1432 2024-10-07 15:15:29 -04:00
parent 938a703e92
commit eb5f04096e
13 changed files with 1122 additions and 313 deletions

View file

@ -11,10 +11,58 @@
services = { services = {
home-assistant = { home-assistant = {
package =
(pkgs.home-assistant.override {
packageOverrides = final: prev: {
# Needed for spotifyplus
inherit (self.packages.${pkgs.system}) urllib3;
# Version before HassStartTimer
home-assistant-intents = final.buildPythonPackage rec {
pname = "home-assistant-intents";
version = "2024.4.3";
format = "wheel";
disabled = final.pythonOlder "3.9";
src = final.fetchPypi {
inherit version format;
pname = "home_assistant_intents";
dist = "py3";
python = "py3";
hash = "sha256-GraYVtioKIoKlPRBhhhzlbBfI6heXAaA1MQpUqAgEDQ=";
};
build-system = [
final.setuptools
];
doCheck = false;
pytestFlagsArray = [
"intents/tests"
];
};
};
})
.overrideAttrs {
disabledTestPaths = [
# we neither run nor distribute hassfest
"tests/hassfest"
# we don't care about code quality
"tests/pylint"
# redundant component import test, which would make debugpy & sentry expensive to review
"tests/test_circular_imports.py"
# don't bulk test all components
"tests/components"
# Make old intent version build
"tests/scripts/test_check_config.py"
"tests/test_bootstrap.py"
"tests/helpers"
];
};
customComponents = builtins.attrValues { customComponents = builtins.attrValues {
inherit inherit
(self.legacyPackages.${pkgs.system}.hass-components) (self.legacyPackages.${pkgs.system}.hass-components)
extended-ollama-conversation extended-ollama-conversation
ha-fallback-conversation
tuya-local tuya-local
; ;
}; };

View file

@ -1,8 +1,5 @@
# I use nix2yaml from ../default.nix to convert this to YAML and place it in the functions of extended_ollama_conversation # I use nix2yaml from ../default.nix to convert this to YAML and place it in the functions of extended_ollama_conversation
let [
inherit (import ../../../../../lib {}) lib;
inherit (lib) concatStrings concatStringsSep splitString;
in [
{ {
spec = { spec = {
name = "get_attributes"; name = "get_attributes";
@ -26,283 +23,4 @@ in [
value_template = "{{ states[entity_id] }}"; value_template = "{{ states[entity_id] }}";
}; };
} }
{
spec = {
name = "timer_start";
description = "Use this function to start a timer in Home Assistant whose ID defaults to 1.";
parameters = {
type = "object";
properties = {
hours = {
type = "string";
description = "The amount of hours the timer should run for.";
};
minutes = {
type = "string";
description = "The amount of minutes the timer should run for.";
};
seconds = {
type = "string";
description = "The amount of seconds the timer should run for.";
};
};
required = [];
};
};
function = {
type = "script";
sequence = [
{
service = "script.assist_timerstart";
# dummy ID that won't be used by the script
target.entity_id = "timer.assist_timer1";
data = {
duration = concatStrings [
''{% if not hours %} {% set hours = "0" %} {% endif %}''
''{% if not minutes %} {% set minutes = "0" %} {% endif %}''
''{% if not seconds %} {% set seconds = "0" %} {% endif %}''
''{{ hours | int(default=0) }}:{{ minutes | int(default=0) }}:{{ seconds | int(default=0) }}''
];
};
}
];
};
}
{
spec = {
name = "timer_stop";
description = "Use this function to stop a timer in Home Assistant.";
parameters = {
type = "object";
properties = {
timer_number = {
type = "string";
description = "The number of the timer";
enum = ["1" "2" "3"];
};
};
required = ["timer_number"];
};
};
function = {
type = "script";
sequence = [
{
service = "script.assist_timerstop";
target.entity_id = ''{{ "timer.assist_timer" ~ timer_number }}'';
}
];
};
}
{
spec = {
name = "timer_pause";
description = "Use this function to pause a timer in Home Assistant.";
parameters = {
type = "object";
properties = {
timer_number = {
type = "string";
description = "The number of the timer";
enum = ["1" "2" "3"];
};
};
required = ["timer_number"];
};
};
function = {
type = "script";
sequence = [
{
service = "script.assist_timerpause";
target.entity_id = ''{{ "timer.assist_timer" ~ timer_number }}'';
data = {
timer_action = "pause";
};
}
];
};
}
{
spec = {
name = "timer_unpause";
description = "Use this function to unpause or resume a timer in Home Assistant.";
parameters = {
type = "object";
properties = {
timer_number = {
type = "string";
description = "The number of the timer";
enum = ["1" "2" "3"];
};
};
required = ["timer_number"];
};
};
function = {
type = "script";
sequence = [
{
service = "script.assist_timerpause";
target.entity_id = ''{{ "timer.assist_timer" ~ timer_number }}'';
data = {
timer_action = "resume";
};
}
];
};
}
{
spec = {
name = "timer_duration";
description = "Use this function to get the remaining duration of a timer in Home Assistant.";
parameters = {
type = "object";
properties = {
timer_number = {
type = "string";
description = "The number of the timer";
enum = ["1" "2" "3"];
};
};
required = ["timer_number"];
};
};
function = {
type = "template";
value_template = concatStringsSep " " (splitString "\n" ''
{%- set entity_id = "timer.assist_timer" ~ timer_number %}
{%- set timer_amount = states.timer
| selectattr("state","eq","active")
| selectattr("entity_id","match","timer.assist_timer*")
| map(attribute="entity_id")
| list
| length -%}
{% if timer_amount == 0 %}
There are no timers active.
{% else %}
{%- if entity_id != "all" and entity_id != "null" %}
{%- set active_timers = states.timer
| selectattr("state","eq","active")
| selectattr("entity_id","match",entity_id)
| list -%}
{%- else%}
{%- set active_timers = states.timer
| selectattr("state","eq","active")
| selectattr("entity_id","match","timer.assist_timer*")
| list -%}
{%- endif %}
{% if active_timers|length == 0 %}
{%- if entity_id != "all" and entity_id != "null" %}
This timer is not active.
{%- else %}
There are no timers active.
{%- endif %}
{% elif active_timers | length > 1 %}
There are {{active_timers|length }} timers active.
{% endif %}
{% for timer in active_timers %}
{% set timer_id = timer.entity_id %}
{% set timer_finishes_at = state_attr(timer_id, "finishes_at") %}
{% set time_remaining = as_datetime(timer_finishes_at) - now() %}
{% set hours_remaining = time_remaining.total_seconds() // 3600 %}
{% set minutes_remaining = (time_remaining.total_seconds() % 3600) // 60 %}
{% set seconds_remaining = time_remaining.total_seconds() % 60 %}
{% if timer.state == "active" or timer.state == "paused" %}
{% if entity_id != timer_id %}
{{ state_attr(timer_id, "friendly_name")[9:] }} {% if timer.state == "paused" %} is paused and {% endif %} has
{% else %}
There are
{% endif %}
{% if hours_remaining > 0 %}{{ hours_remaining | round }} hours {% endif %}
{% if minutes_remaining == 1 %}1 minute {% endif %}
{% if minutes_remaining > 1 %}{{ minutes_remaining | round }} minutes {% endif %}
{% if seconds_remaining == 1 and hours_remaining == 0%}1 seconde {% endif %}
{% if seconds_remaining > 1 and hours_remaining == 0 %}{{ seconds_remaining | round }} seconds {% endif %}remaining.
{% endif %}
{% endfor %}
{% endif %}
'');
};
}
{
spec = {
name = "play_artist";
description = "Use this function to play music from an artist";
parameters = {
type = "object";
properties.query = {
type = "string";
description = "The query";
};
required = ["query"];
};
};
function = {
type = "script";
sequence = [
{
service = "netdaemon.spotify_play_artist";
data = {
criteria = "{{ query }}";
};
}
];
};
}
] ]

View file

@ -48,5 +48,4 @@ entity_id,name,state,aliases,attributes
``` ```
The current state of devices is provided in available devices. The current state of devices is provided in available devices.
Do not ask for confirmation to execute a service.
Do not restate or appreciate what user says, rather make a quick inquiry. Do not restate or appreciate what user says, rather make a quick inquiry.

View file

@ -77,6 +77,14 @@ in {
"switch.smartplug3" "switch.smartplug3"
]; ];
} }
{
type = "entities";
entities = [
"timer.assist_timer1"
"timer.assist_timer2"
"timer.assist_timer3"
];
}
]; ];
} }
]; ];

View file

@ -0,0 +1,23 @@
{
language = "en";
intents = {
PlayArtist.data = [
{
sentences = [
"play [some] music from [artist] {artist}"
];
}
];
};
lists = {
artist.wildcard = true;
};
responses.intents = {
PlayArtist.default = ''
Searching for {{ slots.artist }} on Spotify and playing their top songs.
'';
};
}

View file

@ -6,26 +6,23 @@
... ...
}: let }: let
inherit (lib) getExe; inherit (lib) getExe;
inherit (pkgs.writers) writeYAML;
in { in {
systemd.services.home-assistant.preStart = let systemd.services.home-assistant.preStart = let
WorkingDirectory = "/var/lib/hass"; WorkingDirectory = "/var/lib/hass";
creds = config.sops.secrets.spotifyd.path; creds = config.sops.secrets.spotifyd.path;
spotify = writeYAML "assist_spotify.yaml" (import ./spotify-sentences.nix);
in in
getExe (pkgs.writeShellApplication { getExe (pkgs.writeShellApplication {
name = "spotify-plus-creds"; name = "spotify-files";
text = '' text = ''
mkdir -p ${WorkingDirectory}/custom_sentences/en
cp -f ${spotify} ${WorkingDirectory}/custom_sentences/en
cp -f ${creds} ${WorkingDirectory}/.storage/SpotifyWebApiPython_librespot_credentials.json cp -f ${creds} ${WorkingDirectory}/.storage/SpotifyWebApiPython_librespot_credentials.json
''; '';
}); });
services.home-assistant = { services.home-assistant = {
# Needed for spotifyplus
package = pkgs.home-assistant.override {
packageOverrides = _: super: {
inherit (self.packages.${pkgs.system}) urllib3;
};
};
customComponents = builtins.attrValues { customComponents = builtins.attrValues {
inherit inherit
(self.legacyPackages.${pkgs.system}.hass-components) (self.legacyPackages.${pkgs.system}.hass-components)
@ -36,5 +33,17 @@ in {
extraComponents = [ extraComponents = [
"spotify" "spotify"
]; ];
config.intent_script = {
PlayArtist = {
async_action = "false";
action = [
{
service = "netdaemon.spotify_play_artist";
data.criteria = "{{ artist }}";
}
];
};
};
}; };
} }

View file

@ -0,0 +1,942 @@
{
language = "en";
intents = {
TimerDuration.data = [
{
sentences = [
"how [much] long[er] on [the] {entity_id} timer"
"how much time is left on [the] {entity_id} timer"
"how long until [the] {entity_id} timer (is finished|finishes)"
];
}
{
sentences = [
"how [much] long[er] on [the] timer[s]"
"how much time is left on [the] {entity_id} timer[s]"
"how long until [the] timer[s] (is finished|finishes)"
];
slots.entity_id = "null";
}
];
TimerPause.data = [
{
sentences = ["(pause|interrupt) [the] {entity_id} timer[s]"];
slots.timer_action = "pause";
}
{
sentences = ["(pause|interrupt) [the] timer[s]"];
slots = {
entity_id = "null";
timer_action = "pause";
};
}
{
sentences = ["(pause|interrupt) all timer[s]"];
slots = {
entity_id = "all";
timer_action = "pause";
};
}
{
sentences = ["(resume|continue) [the] {entity_id} timer[s]"];
slots.timer_action = "resume";
}
{
sentences = ["(resume|continue) [the] timer[s]"];
slots = {
entity_id = "null";
timer_action = "resume";
};
}
{
sentences = ["(resume|continue) all timer[s]"];
slots = {
entity_id = "all";
timer_action = "resume";
};
}
];
TimerStart.data = [
{
sentences = [
"(start|set) [a] timer (for|with) {hours} hour[s] [and] {minutes} minute[s] [and] {seconds} seconde[s]"
];
}
{
sentences = [
"(start|set) [(a|an)] timer (for|with) {hours} hour[s]"
"(start|set) [(a|an)] {hours} hour[s] timer"
];
slots = {
minutes = 0;
seconds = 0;
};
}
{
sentences = [
"(start|set) [a] timer (for|with) {minutes} minute[s]"
"(start|set) [(a|an)] {minutes} minute[s] timer"
];
slots = {
hours = 0;
seconds = 0;
};
}
{
sentences = [
"(start|set) [a] timer (for|with) {seconds} seconde[s]"
"(start|set) [(a|an)] {seconds} second[s] timer"
];
slots = {
hours = 0;
minutes = 0;
};
}
{
sentences = [
"(start|set) [a] timer (for|with) {minutes} minute[s] [and] {seconds} seconde[s]"
];
slots.hours = 0;
}
{
sentences = [
"(start|set) [a] timer (for|with) {hours} hour[s] [and] {minutes} minute[s]"
];
slots.seconds = 0;
}
];
TimerStop.data = [
{sentences = ["(stop|cancel|turn off) [the] {entity_id} timer[s]"];}
{
sentences = ["(stop|cancel|turn off) [the] timer[s]"];
slots.entity_id = "null";
}
];
};
lists = {
entity_id.values = [
{
"in" = "(first|one|1)";
out = "timer.assist_timer1";
}
{
"in" = "(second|two|2)";
out = "timer.assist_timer2";
}
{
"in" = "(third|three|3)";
out = "timer.assist_timer3";
}
{
"in" = "(all|every)";
out = "all";
}
];
hours.values = [
{
"in" = "(one|1)";
out = 1;
}
{
"in" = "(two|2)";
out = 2;
}
{
"in" = "(three|3)";
out = 3;
}
{
"in" = "(four|4)";
out = 4;
}
{
"in" = "(five|5)";
out = 5;
}
{
"in" = "(six|6)";
out = 6;
}
{
"in" = "(seven|7)";
out = 7;
}
{
"in" = "(eight|8)";
out = 8;
}
{
"in" = "(nine|9)";
out = 9;
}
{
"in" = "(ten|10)";
out = 10;
}
{
"in" = "(eleven|11)";
out = 11;
}
{
"in" = "(twelve|12)";
out = 12;
}
{
"in" = "(thirteen|13)";
out = 13;
}
{
"in" = "(fourteen|14)";
out = 14;
}
{
"in" = "(fifteen|15)";
out = 15;
}
{
"in" = "(sixteen|16)";
out = 16;
}
{
"in" = "(seventeen|17)";
out = 17;
}
{
"in" = "(eighteen|18)";
out = 18;
}
{
"in" = "(nineteen|19)";
out = 19;
}
{
"in" = "(twenty|20)";
out = 20;
}
{
"in" = "(twenty-one|21)";
out = 21;
}
{
"in" = "(twenty-two|22)";
out = 22;
}
{
"in" = "(twenty-three|23)";
out = 23;
}
{
"in" = "(twenty-four|24)";
out = 24;
}
];
minutes.values = [
{
"in" = "(one|1)";
out = 1;
}
{
"in" = "(two|2)";
out = 2;
}
{
"in" = "(three|3)";
out = 3;
}
{
"in" = "(four|4)";
out = 4;
}
{
"in" = "(five|5)";
out = 5;
}
{
"in" = "(six|6)";
out = 6;
}
{
"in" = "(seven|7)";
out = 7;
}
{
"in" = "(eight|8)";
out = 8;
}
{
"in" = "(nine|9)";
out = 9;
}
{
"in" = "(ten|10)";
out = 10;
}
{
"in" = "(eleven|11)";
out = 11;
}
{
"in" = "(twelve|12)";
out = 12;
}
{
"in" = "(thirteen|13)";
out = 13;
}
{
"in" = "(fourteen|14)";
out = 14;
}
{
"in" = "(fifteen|15)";
out = 15;
}
{
"in" = "(sixteen|16)";
out = 16;
}
{
"in" = "(seventeen|17)";
out = 17;
}
{
"in" = "(eighteen|18)";
out = 18;
}
{
"in" = "(nineteen|19)";
out = 19;
}
{
"in" = "(twenty|20)";
out = 20;
}
{
"in" = "(twenty-one|21)";
out = 21;
}
{
"in" = "(twenty-two|22)";
out = 22;
}
{
"in" = "(twenty-three|23)";
out = 23;
}
{
"in" = "(twenty-four|24)";
out = 24;
}
{
"in" = "(twenty-five|25)";
out = 25;
}
{
"in" = "(twenty-six|26)";
out = 26;
}
{
"in" = "(twenty-seven|27)";
out = 27;
}
{
"in" = "(twenty-eight|28)";
out = 28;
}
{
"in" = "(twenty-nine|29)";
out = 29;
}
{
"in" = "(thirty|30)";
out = 30;
}
{
"in" = "(thirty-one|31)";
out = 31;
}
{
"in" = "(thirty-two|32)";
out = 32;
}
{
"in" = "(thirty-three|33)";
out = 33;
}
{
"in" = "(thirty-four|34)";
out = 34;
}
{
"in" = "(thirty-five|35)";
out = 35;
}
{
"in" = "(thirty-six|36)";
out = 36;
}
{
"in" = "(thirty-seven|37)";
out = 37;
}
{
"in" = "(thirty-eight|38)";
out = 38;
}
{
"in" = "(thirty-nine|39)";
out = 39;
}
{
"in" = "(forty|40)";
out = 40;
}
{
"in" = "(forty-one|41)";
out = 41;
}
{
"in" = "(forty-two|42)";
out = 42;
}
{
"in" = "(forty-three|43)";
out = 43;
}
{
"in" = "(forty-four|44)";
out = 44;
}
{
"in" = "(forty-five|45)";
out = 45;
}
{
"in" = "(forty-six|46)";
out = 46;
}
{
"in" = "(forty-seven|47)";
out = 47;
}
{
"in" = "(forty-eight|48)";
out = 48;
}
{
"in" = "(forty-nine|49)";
out = 49;
}
{
"in" = "(fifty|50)";
out = 50;
}
{
"in" = "(fifty-one|51)";
out = 51;
}
{
"in" = "(fifty-two|52)";
out = 52;
}
{
"in" = "(fifty-three|53)";
out = 53;
}
{
"in" = "(fifty-four|54)";
out = 54;
}
{
"in" = "(fifty-five|55)";
out = 55;
}
{
"in" = "(fifty-six|56)";
out = 56;
}
{
"in" = "(fifty-seven|57)";
out = 57;
}
{
"in" = "(fifty-eight|58)";
out = 58;
}
{
"in" = "(fifty-nine|59)";
out = 59;
}
{
"in" = "(sixty|60)";
out = 60;
}
];
seconds.values = [
{
"in" = "(one|1)";
out = 1;
}
{
"in" = "(two|2)";
out = 2;
}
{
"in" = "(three|3)";
out = 3;
}
{
"in" = "(four|4)";
out = 4;
}
{
"in" = "(five|5)";
out = 5;
}
{
"in" = "(six|6)";
out = 6;
}
{
"in" = "(seven|7)";
out = 7;
}
{
"in" = "(eight|8)";
out = 8;
}
{
"in" = "(nine|9)";
out = 9;
}
{
"in" = "(ten|10)";
out = 10;
}
{
"in" = "(eleven|11)";
out = 11;
}
{
"in" = "(twelve|12)";
out = 12;
}
{
"in" = "(thirteen|13)";
out = 13;
}
{
"in" = "(fourteen|14)";
out = 14;
}
{
"in" = "(fifteen|15)";
out = 15;
}
{
"in" = "(sixteen|16)";
out = 16;
}
{
"in" = "(seventeen|17)";
out = 17;
}
{
"in" = "(eighteen|18)";
out = 18;
}
{
"in" = "(nineteen|19)";
out = 19;
}
{
"in" = "(twenty|20)";
out = 20;
}
{
"in" = "(twenty-one|21)";
out = 21;
}
{
"in" = "(twenty-two|22)";
out = 22;
}
{
"in" = "(twenty-three|23)";
out = 23;
}
{
"in" = "(twenty-four|24)";
out = 24;
}
{
"in" = "(twenty-five|25)";
out = 25;
}
{
"in" = "(twenty-six|26)";
out = 26;
}
{
"in" = "(twenty-seven|27)";
out = 27;
}
{
"in" = "(twenty-eight|28)";
out = 28;
}
{
"in" = "(twenty-nine|29)";
out = 29;
}
{
"in" = "(thirty|30)";
out = 30;
}
{
"in" = "(thirty-one|31)";
out = 31;
}
{
"in" = "(thirty-two|32)";
out = 32;
}
{
"in" = "(thirty-three|33)";
out = 33;
}
{
"in" = "(thirty-four|34)";
out = 34;
}
{
"in" = "(thirty-five|35)";
out = 35;
}
{
"in" = "(thirty-six|36)";
out = 36;
}
{
"in" = "(thirty-seven|37)";
out = 37;
}
{
"in" = "(thirty-eight|38)";
out = 38;
}
{
"in" = "(thirty-nine|39)";
out = 39;
}
{
"in" = "(forty|40)";
out = 40;
}
{
"in" = "(forty-one|41)";
out = 41;
}
{
"in" = "(forty-two|42)";
out = 42;
}
{
"in" = "(forty-three|43)";
out = 43;
}
{
"in" = "(forty-four|44)";
out = 44;
}
{
"in" = "(forty-five|45)";
out = 45;
}
{
"in" = "(forty-six|46)";
out = 46;
}
{
"in" = "(forty-seven|47)";
out = 47;
}
{
"in" = "(forty-eight|48)";
out = 48;
}
{
"in" = "(forty-nine|49)";
out = 49;
}
{
"in" = "(fifty|50)";
out = 50;
}
{
"in" = "(fifty-one|51)";
out = 51;
}
{
"in" = "(fifty-two|52)";
out = 52;
}
{
"in" = "(fifty-three|53)";
out = 53;
}
{
"in" = "(fifty-four|54)";
out = 54;
}
{
"in" = "(fifty-five|55)";
out = 55;
}
{
"in" = "(fifty-six|56)";
out = 56;
}
{
"in" = "(fifty-seven|57)";
out = 57;
}
{
"in" = "(fifty-eight|58)";
out = 58;
}
{
"in" = "(fifty-nine|59)";
out = 59;
}
{
"in" = "(sixty|60)";
out = 60;
}
];
};
responses.intents = {
TimerDuration.default = ''
{%- set timer_amount = states.timer
| selectattr('state','eq','active')
| selectattr('entity_id','match','timer.assist_timer*')
| map(attribute='entity_id')
| list
| length -%}
{% if timer_amount == 0 %}
There are no timers active.
{% else %}
{%- if slots.entity_id != 'all' and slots.entity_id != 'null' %}
{%- set active_timers = states.timer
| selectattr('state','eq','active')
| selectattr('entity_id','match',slots.entity_id)
| list -%}
{%- else%}
{%- set active_timers = states.timer
| selectattr('state','eq','active')
| selectattr('entity_id','match','timer.assist_timer*')
| list -%}
{%- endif %}
{% if active_timers|length == 0 %}
{%- if slots.entity_id != 'all' and slots.entity_id != 'null' %}
This timer is not active.
{%- else %}
There are no timers active.
{%- endif %}
{% elif active_timers|length > 1 %}
There are {{active_timers|length }} timers active.
{% endif %}
{% for timer in active_timers %}
{% set timer_id = timer.entity_id %}
{% set timer_finishes_at = state_attr(timer_id, 'finishes_at') %}
{% set time_remaining = as_datetime(timer_finishes_at) - now() %}
{% set hours_remaining = time_remaining.total_seconds() // 3600 %}
{% set minutes_remaining = (time_remaining.total_seconds() % 3600) // 60 %}
{% set seconds_remaining = time_remaining.total_seconds() % 60 %}
{% if timer.state == "active" or timer.state == "paused" %}
{% if slots.entity_id != timer_id %}
{{ state_attr(timer_id, 'friendly_name')[9:] }}
{% if timer.state == "paused" %}
is paused and
{% endif %}
has
{% else %}
There are
{% endif %}
{% if hours_remaining > 0 %}
{{ hours_remaining | round }} hours
{% endif %}
{% if minutes_remaining == 1 %}
1 minute
{% endif %}
{% if minutes_remaining > 1 %}
{{ minutes_remaining | round }} minutes
{% endif %}
{% if seconds_remaining == 1 and hours_remaining == 0%}
1 seconde
{% endif %}
{% if seconds_remaining > 1 and hours_remaining == 0 %}
{{ seconds_remaining | round }} seconds
{% endif %}
remaining.
{% endif %}
{% endfor %}
{% endif %}
'';
TimerPause.default = ''
{%- if slots.timer_action is set or slots.timer_action != "" -%}
{%- set timer_action = slots.timer_action -%}
{%- else -%}
{%- set timer_action = "resume" -%}
{%- endif -%}
{%- set timer_amount = states.timer
| selectattr('state','eq','active')
| selectattr('entity_id','match','timer.assist_timer*')
| map(attribute='entity_id')
| list
| length -%}
{% if timer_amount == 0 %}
There are no timers active.
{% elif timer_amount > 1 and slots.entity_id == 'null' %}
There are multiple timers active.
{{ (["Please specify which timer you mean.", "Please specify which timer.", "Specify which timer you mean.", ""] | random) }}
{% elif slots.entity_id == 'all' %}
{{ (["Understood. ", "Okay. ", "Of course. ", ""] | random) }}.
All timers
{% if timer_action == "pause" %}
paused
{% else %}
resumed
{% endif %}
.
{% elif (as_timestamp(now()) - as_timestamp(states.timer.assist_timer1.last_changed) < 3 and states('timer.assist_timer1') == 'idle') or
(as_timestamp(now()) - as_timestamp(states.timer.assist_timer2.last_changed) < 3 and states('timer.assist_timer2') == 'idle') or
(as_timestamp(now()) - as_timestamp(states.timer.assist_timer3.last_changed) < 3 and states('timer.assist_timer3') == 'idle') %}
Timer
{% if timer_action == "pause" %}
paused
{% else %}
resumed
{% endif %}
.
{% elif (timer_amount == 1 and slots.entity_id == 'null') or
(slots.entity_id == 'timer.assist_timer1' and states('timer.assist_timer1') != 'idle') or
(slots.entity_id == 'timer.assist_timer2' and states('timer.assist_timer2') != 'idle') or
(slots.entity_id == 'timer.assist_timer3' and states('timer.assist_timer3') != 'idle') %}
{{ (["Understood. ", "Okay. ", "Of course. ", ""] | random) }}Timer
{% if timer_action == "pause" %}
paused
{% else %}
resumed
{% endif %}
.
{% else %}
This timer is not active.
{% endif %}
'';
TimerStart.default = ''
{{ (["Understood. ", "Okay. ", "Of course. ", ""] | random) +
(["I will start a timer for ", "Timer started with ", "Starting timer with ", "Timer active for "] | random)}}
{% if (slots.hours | int(default=0)) == 1 %}
1 hour
{% elif (slots.hours | int(default=0)) > 1 %}
{{ (slots.hours | int)}} hours
{% endif %}
{% if (slots.hours | int(default=0)) > 0 and ((slots.minutes | int(default=0)) > 0 or (slots.seconds | int(default=0)) > 0) %}
and
{% endif %}
{% if (slots.minutes | int(default=0)) == 1 %}
1 minute
{% elif (slots.minutes | int(default=0)) > 1 %}
{{ (slots.minutes | int)}} minutes
{% endif %}
{% if (slots.minutes | int(default=0)) > 0 and (slots.seconds | int(default=0)) > 0 %}
and
{% endif %}
{% if (slots.seconds | int(default=0)) == 1 %}
1 second
{% elif (slots.seconds | int(default=0)) > 1 %}
{{ (slots.seconds | int)}} secondes
{% endif %}.
'';
TimerStop.default = ''
{%- set timer_amount = states.timer
| selectattr('state','eq','active')
| selectattr('entity_id','match','timer.assist_timer*')
| map(attribute='entity_id')
| list
| length -%}
{% set mediaplayer = namespace(entity=[]) %}
{% for player in states.media_player %}
{%- if ((state_attr(player.entity_id, 'media_content_id') | lower != 'none'
and state_attr(player.entity_id, 'media_content_id')[:47][38:] == 'Timer.mp3')
or state_attr(player.entity_id, 'media_title') | lower == 'timer')
and states(player.entity_id) == 'playing' -%}
{%- set mediaplayer.entity = player.entity_id -%}
{% endif -%}
{% endfor %}
{% if mediaplayer.entity[:12] == 'media_player' %}
{{ (["Understood. ", "Okay. ", "Of course. ", ""] | random) }}Timer stopped.
{% elif timer_amount == 0 and
(as_timestamp(now()) - as_timestamp(states.timer.assist_timer1.last_changed) > 3 and states('timer.assist_timer1') == 'idle') and
(as_timestamp(now()) - as_timestamp(states.timer.assist_timer2.last_changed) > 3 and states('timer.assist_timer2') == 'idle') and
(as_timestamp(now()) - as_timestamp(states.timer.assist_timer3.last_changed) > 3 and states('timer.assist_timer3') == 'idle') %}
There are no timers active.
{% elif (slots_entity_id == 'timer.assist_timer1' and states('timer.assist_timer1') == 'idle') or
(slots_entity_id == 'timer.assist_timer2' and states('timer.assist_timer2') == 'idle') or
(slots_entity_id == 'timer.assist_timer3' and states('timer.assist_timer3') == 'idle') %}
This timer is not active.
{% elif timer_amount > 1 and slots_entity_id == 'null' %}
There are multiple timers active.
{{ (["Please specify which timer you mean.", "Please specify which timer.", "Specify which timer you mean.", ""] | random) }}
{% elif slots_entity_id == 'all' %}
{{ (["Understood. ", "Okay. ", "Of course. ", ""] | random) }}All timers stopped.
{% else %}
{{ (["Understood. ", "Okay. ", "Of course. ", ""] | random) }}Timer stopped.
{% endif %}
'';
};
}

View file

@ -1,6 +1,11 @@
# From https://github.com/don86nl/ha_intents/blob/main/config/packages/assist_timers.yaml # From https://github.com/don86nl/ha_intents/blob/main/config/packages/assist_timers.yaml
{lib, ...}: let {
inherit (lib) concatStrings concatStringsSep; lib,
pkgs,
...
}: let
inherit (lib) concatStrings concatStringsSep getExe;
inherit (pkgs.writers) writeYAML;
mkTimer = id: { mkTimer = id: {
"assist_timer${toString id}" = { "assist_timer${toString id}" = {
@ -38,6 +43,19 @@
timer_media_location = "/path/to/file.mp3"; timer_media_location = "/path/to/file.mp3";
}; };
in { in {
systemd.services.home-assistant.preStart = let
WorkingDirectory = "/var/lib/hass";
timer = writeYAML "assist_timers.yaml" (import ./timer-sentences.nix);
in
getExe (pkgs.writeShellApplication {
name = "timer-files";
text = ''
mkdir -p ${WorkingDirectory}/custom_sentences/en
cp -f ${timer} ${WorkingDirectory}/custom_sentences/en
'';
});
services.home-assistant = { services.home-assistant = {
config = { config = {
homeassistant.customize."script.assist_timerstart" = {inherit settings;}; homeassistant.customize."script.assist_timerstart" = {inherit settings;};
@ -48,6 +66,43 @@ in {
# Makes location of a timer customizable from the UI # Makes location of a timer customizable from the UI
input_text = (mkLocation 1) // (mkLocation 2) // (mkLocation 3); input_text = (mkLocation 1) // (mkLocation 2) // (mkLocation 3);
intent_script = {
TimerStart = {
async_action = "false";
action = [
{
service = "script.assist_timerstart";
data.duration = "{{hours | int(default=0)}}:{{ minutes | int(default=0) }}:{{ seconds | int(default=0) }}";
}
];
};
TimerStop = {
async_action = true;
action = [
{
service = "script.assist_timerstop";
data.entity_id = "{{ entity_id }}";
}
];
};
TimerPause = {
async_action = true;
action = [
{
service = "script.assist_timerpause";
data = {
entity_id = "{{ entity_id }}";
timer_action = "{{ timer_action }}";
};
}
];
};
TimerDuration = {
async_action = true;
action = [{stop = "";}];
};
};
# Automate some logic # Automate some logic
automation = [ automation = [
{ {
@ -133,14 +188,6 @@ in {
}; };
} }
{
alias = "Store current device volume";
variables = {
device_volume = ''{{ state_attr(timer_target, 'volume_level') }}'';
};
}
{ {
alias = "Media file or TTS"; alias = "Media file or TTS";
@ -229,17 +276,6 @@ in {
} }
]; ];
} }
{
alias = "Restore device previous volume";
service = "media_player.volume_set";
target.entity_id = ''{{ timer_target }}'';
data = {
volume_level = ''{{ device_volume }}'';
};
}
]; ];
} }

Binary file not shown.

BIN
flake.nix

Binary file not shown.

View file

@ -192,6 +192,11 @@ let
owner = "TheNimaj"; owner = "TheNimaj";
repo = "extended_ollama_conversation"; repo = "extended_ollama_conversation";
} }
{
owner = "m50";
repo = "ha-fallback-conversation";
}
{ {
owner = "make-all"; owner = "make-all";
repo = "tuya-local"; repo = "tuya-local";
@ -222,6 +227,10 @@ let
owner = "fwartner"; owner = "fwartner";
repo = "home-assistant-wakewords-collection"; repo = "home-assistant-wakewords-collection";
} }
{
owner = "don86nl";
repo = "ha_intents";
}
{ {
owner = "berti24"; owner = "berti24";
repo = "dracul-ha"; repo = "dracul-ha";

View file

@ -4,6 +4,7 @@ pkgs.lib.makeScope pkgs.newScope (hass: let
hass.callPackage file (inputs // extraArgs // {}); hass.callPackage file (inputs // extraArgs // {});
in { in {
extended-ollama-conversation = buildHassComponent ./extended-ollama-conversation {}; extended-ollama-conversation = buildHassComponent ./extended-ollama-conversation {};
ha-fallback-conversation = buildHassComponent ./ha-fallback-conversation {};
netdaemon = buildHassComponent ./netdaemon {}; netdaemon = buildHassComponent ./netdaemon {};
spotifyplus = import ./spotifyplus ({inherit buildHassComponent;} // inputs); spotifyplus = import ./spotifyplus ({inherit buildHassComponent;} // inputs);
tuya-local = buildHassComponent ./tuya-local {}; tuya-local = buildHassComponent ./tuya-local {};

View file

@ -0,0 +1,16 @@
{
ha-fallback-conversation-src,
buildHomeAssistantComponent,
...
}: let
inherit (builtins) fromJSON readFile;
manifest = fromJSON (readFile "${ha-fallback-conversation-src}/custom_components/fallback_conversation/manifest.json");
in
buildHomeAssistantComponent {
owner = "m50";
inherit (manifest) domain version;
src = ha-fallback-conversation-src;
}