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 = {
|
||||
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 {
|
||||
inherit
|
||||
(self.legacyPackages.${pkgs.system}.hass-components)
|
||||
extended-ollama-conversation
|
||||
ha-fallback-conversation
|
||||
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
|
||||
let
|
||||
inherit (import ../../../../../lib {}) lib;
|
||||
inherit (lib) concatStrings concatStringsSep splitString;
|
||||
in [
|
||||
[
|
||||
{
|
||||
spec = {
|
||||
name = "get_attributes";
|
||||
|
@ -26,283 +23,4 @@ in [
|
|||
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.
|
||||
Do not ask for confirmation to execute a service.
|
||||
Do not restate or appreciate what user says, rather make a quick inquiry.
|
||||
|
|
|
@ -77,6 +77,14 @@ in {
|
|||
"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
|
||||
inherit (lib) getExe;
|
||||
inherit (pkgs.writers) writeYAML;
|
||||
in {
|
||||
systemd.services.home-assistant.preStart = let
|
||||
WorkingDirectory = "/var/lib/hass";
|
||||
creds = config.sops.secrets.spotifyd.path;
|
||||
spotify = writeYAML "assist_spotify.yaml" (import ./spotify-sentences.nix);
|
||||
in
|
||||
getExe (pkgs.writeShellApplication {
|
||||
name = "spotify-plus-creds";
|
||||
name = "spotify-files";
|
||||
text = ''
|
||||
mkdir -p ${WorkingDirectory}/custom_sentences/en
|
||||
cp -f ${spotify} ${WorkingDirectory}/custom_sentences/en
|
||||
cp -f ${creds} ${WorkingDirectory}/.storage/SpotifyWebApiPython_librespot_credentials.json
|
||||
'';
|
||||
});
|
||||
|
||||
services.home-assistant = {
|
||||
# Needed for spotifyplus
|
||||
package = pkgs.home-assistant.override {
|
||||
packageOverrides = _: super: {
|
||||
inherit (self.packages.${pkgs.system}) urllib3;
|
||||
};
|
||||
};
|
||||
|
||||
customComponents = builtins.attrValues {
|
||||
inherit
|
||||
(self.legacyPackages.${pkgs.system}.hass-components)
|
||||
|
@ -36,5 +33,17 @@ in {
|
|||
extraComponents = [
|
||||
"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
|
||||
{lib, ...}: let
|
||||
inherit (lib) concatStrings concatStringsSep;
|
||||
{
|
||||
lib,
|
||||
pkgs,
|
||||
...
|
||||
}: let
|
||||
inherit (lib) concatStrings concatStringsSep getExe;
|
||||
inherit (pkgs.writers) writeYAML;
|
||||
|
||||
mkTimer = id: {
|
||||
"assist_timer${toString id}" = {
|
||||
|
@ -38,6 +43,19 @@
|
|||
timer_media_location = "/path/to/file.mp3";
|
||||
};
|
||||
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 = {
|
||||
config = {
|
||||
homeassistant.customize."script.assist_timerstart" = {inherit settings;};
|
||||
|
@ -48,6 +66,43 @@ in {
|
|||
# Makes location of a timer customizable from the UI
|
||||
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
|
||||
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";
|
||||
|
||||
|
@ -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";
|
||||
repo = "extended_ollama_conversation";
|
||||
}
|
||||
|
||||
{
|
||||
owner = "m50";
|
||||
repo = "ha-fallback-conversation";
|
||||
}
|
||||
{
|
||||
owner = "make-all";
|
||||
repo = "tuya-local";
|
||||
|
@ -222,6 +227,10 @@ let
|
|||
owner = "fwartner";
|
||||
repo = "home-assistant-wakewords-collection";
|
||||
}
|
||||
{
|
||||
owner = "don86nl";
|
||||
repo = "ha_intents";
|
||||
}
|
||||
{
|
||||
owner = "berti24";
|
||||
repo = "dracul-ha";
|
||||
|
|
|
@ -4,6 +4,7 @@ pkgs.lib.makeScope pkgs.newScope (hass: let
|
|||
hass.callPackage file (inputs // extraArgs // {});
|
||||
in {
|
||||
extended-ollama-conversation = buildHassComponent ./extended-ollama-conversation {};
|
||||
ha-fallback-conversation = buildHassComponent ./ha-fallback-conversation {};
|
||||
netdaemon = buildHassComponent ./netdaemon {};
|
||||
spotifyplus = import ./spotifyplus ({inherit buildHassComponent;} // inputs);
|
||||
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