feat(hass): use ha-fallback with custom sentences
All checks were successful
Discord / discord commits (push) Has been skipped
All checks were successful
Discord / discord commits (push) Has been skipped
This commit is contained in:
parent
938a703e92
commit
eb5f04096e
13 changed files with 1122 additions and 313 deletions
|
@ -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
|
||||||
;
|
;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 }}";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -77,6 +77,14 @@ in {
|
||||||
"switch.smartplug3"
|
"switch.smartplug3"
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
type = "entities";
|
||||||
|
entities = [
|
||||||
|
"timer.assist_timer1"
|
||||||
|
"timer.assist_timer2"
|
||||||
|
"timer.assist_timer3"
|
||||||
|
];
|
||||||
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
23
devices/homie/modules/home-assistant/spotify-sentences.nix
Normal file
23
devices/homie/modules/home-assistant/spotify-sentences.nix
Normal 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.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
|
@ -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 }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
942
devices/homie/modules/home-assistant/timer-sentences.nix
Normal file
942
devices/homie/modules/home-assistant/timer-sentences.nix
Normal 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 %}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
}
|
|
@ -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 }}'';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
BIN
flake.lock
BIN
flake.lock
Binary file not shown.
BIN
flake.nix
BIN
flake.nix
Binary file not shown.
|
@ -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";
|
||||||
|
|
|
@ -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 {};
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in a new issue