feat(hass): add voice command to set timers
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
623780d511
commit
57f8ce5803
11 changed files with 832 additions and 11 deletions
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
|
pkgs,
|
||||||
self,
|
self,
|
||||||
wakewords-src,
|
wakewords-src,
|
||||||
...
|
...
|
||||||
|
@ -10,10 +11,15 @@
|
||||||
|
|
||||||
services = {
|
services = {
|
||||||
home-assistant = {
|
home-assistant = {
|
||||||
|
customComponents = builtins.attrValues {
|
||||||
|
inherit (self.legacyPackages.${pkgs.system}.hass-components) extended-ollama-conversation;
|
||||||
|
};
|
||||||
|
|
||||||
extraComponents = [
|
extraComponents = [
|
||||||
"esphome"
|
"esphome"
|
||||||
"ollama"
|
"ollama"
|
||||||
"wyoming"
|
"wyoming"
|
||||||
|
"scrape"
|
||||||
];
|
];
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
|
|
|
@ -82,6 +82,7 @@
|
||||||
"ibeacon"
|
"ibeacon"
|
||||||
"led_ble"
|
"led_ble"
|
||||||
"kegtron"
|
"kegtron"
|
||||||
|
"xiaomi_ble"
|
||||||
];
|
];
|
||||||
services.mpd = {
|
services.mpd = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
./bluetooth.nix
|
./bluetooth.nix
|
||||||
./firmware.nix
|
./firmware.nix
|
||||||
./frontend.nix
|
./frontend.nix
|
||||||
|
./timer.nix
|
||||||
];
|
];
|
||||||
|
|
||||||
environment.systemPackages = [
|
environment.systemPackages = [
|
||||||
|
@ -23,6 +24,23 @@
|
||||||
fi
|
fi
|
||||||
'';
|
'';
|
||||||
})
|
})
|
||||||
|
|
||||||
|
(pkgs.writeShellApplication {
|
||||||
|
name = "nix2yaml";
|
||||||
|
runtimeInputs = with pkgs; [remarshal];
|
||||||
|
text = ''
|
||||||
|
input="$1"
|
||||||
|
output="''${2:-""}"
|
||||||
|
|
||||||
|
yamlCode="$(nix eval --json --file "$input" | remarshal --if json --of yaml)"
|
||||||
|
|
||||||
|
if [[ "$output" != "" ]]; then
|
||||||
|
echo "$yamlCode" > "$output"
|
||||||
|
else
|
||||||
|
echo "$yamlCode"
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
# TODO: some components / integrations / addons require manual interaction in the GUI, find way to make it all declarative
|
# TODO: some components / integrations / addons require manual interaction in the GUI, find way to make it all declarative
|
||||||
|
|
90
devices/homie/modules/home-assistant/docs/functions.nix
Normal file
90
devices/homie/modules/home-assistant/docs/functions.nix
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
# I use nix2yaml from ../default.nix to convert to to YAML and place it in the functions of extended_ollama_conversation
|
||||||
|
[
|
||||||
|
{
|
||||||
|
function = {
|
||||||
|
name = "execute_service";
|
||||||
|
type = "native";
|
||||||
|
};
|
||||||
|
|
||||||
|
spec = {
|
||||||
|
name = "execute_services";
|
||||||
|
description = "Use this function to execute service of devices in Home Assistant.";
|
||||||
|
|
||||||
|
parameters = {
|
||||||
|
type = "object";
|
||||||
|
|
||||||
|
properties.list = {
|
||||||
|
type = "array";
|
||||||
|
|
||||||
|
items = {
|
||||||
|
type = "object";
|
||||||
|
|
||||||
|
properties = {
|
||||||
|
entity_id = {
|
||||||
|
description = "The entity_id retrieved from available devices. It must start with domain, followed by dot character.";
|
||||||
|
type = "string";
|
||||||
|
};
|
||||||
|
|
||||||
|
service = {
|
||||||
|
description = "The service to be called";
|
||||||
|
type = "string";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
required = ["entity_id" "service"];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
function = {
|
||||||
|
type = "script";
|
||||||
|
|
||||||
|
sequence = [
|
||||||
|
{
|
||||||
|
service = "script.assist_TimerStart";
|
||||||
|
|
||||||
|
data.duration = builtins.concatStringsSep "" [
|
||||||
|
''{% 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) }}''
|
||||||
|
];
|
||||||
|
|
||||||
|
target.entity_id = "timer.assist_timer1";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
spec = {
|
||||||
|
name = "timer_start";
|
||||||
|
description = "Use this function to start a timer in Home Assistant.";
|
||||||
|
|
||||||
|
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 = [];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
]
|
54
devices/homie/modules/home-assistant/docs/prompt
Normal file
54
devices/homie/modules/home-assistant/docs/prompt
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
{%- set customize_glob_exposed_attributes = {
|
||||||
|
".*": {
|
||||||
|
"friendly_name": true,
|
||||||
|
"temperature": true,
|
||||||
|
"current_temperature": true,
|
||||||
|
"temperature_unit": true,
|
||||||
|
"brightness": true,
|
||||||
|
"humidity": true,
|
||||||
|
"unit_of_measurement": true,
|
||||||
|
"device_class": true,
|
||||||
|
"current_position": true,
|
||||||
|
"percentage": true,
|
||||||
|
"volume_level": true,
|
||||||
|
"media_title": true,
|
||||||
|
"media_artist": true,
|
||||||
|
"media_album_name": true,
|
||||||
|
},
|
||||||
|
} %}
|
||||||
|
|
||||||
|
{%- macro get_exposed_attributes(entity_id) -%}
|
||||||
|
{%- set ns = namespace(exposed_attributes = {}, result = {}) %}
|
||||||
|
{%- for pattern, attributes in customize_glob_exposed_attributes.items() -%}
|
||||||
|
{%- if entity_id | regex_match(pattern) -%}
|
||||||
|
{%- set ns.exposed_attributes = dict(ns.exposed_attributes, **attributes) -%}
|
||||||
|
{%- endif -%}
|
||||||
|
{%- endfor -%}
|
||||||
|
{%- for attribute_key, should_include in ns.exposed_attributes.items() -%}
|
||||||
|
{%- if should_include and state_attr(entity_id, attribute_key) != None -%}
|
||||||
|
{%- set temp = {attribute_key: state_attr(entity_id, attribute_key)} if should_include is boolean else {attribute_key: should_include} -%}
|
||||||
|
{%- set ns.result = dict(ns.result, **temp) -%}
|
||||||
|
{%- endif -%}
|
||||||
|
{%- endfor -%}
|
||||||
|
{%- set result = ns.result | to_json if ns.result!={} else None -%}
|
||||||
|
{{"'" + result + "'" if result != None else ''}}
|
||||||
|
{%- endmacro -%}
|
||||||
|
|
||||||
|
I want you to act as smart home manager of Home Assistant.
|
||||||
|
I will provide information of smart home along with a question, you will truthfully make correction or answer using information provided in one sentence in everyday language.
|
||||||
|
|
||||||
|
Current Time: {{now()}}
|
||||||
|
|
||||||
|
Available Devices:
|
||||||
|
```csv
|
||||||
|
entity_id,name,state,aliases,attributes
|
||||||
|
{% for entity in exposed_entities -%}
|
||||||
|
{{ entity.entity_id }},{{ entity.name }},{{ entity.state }},{{entity.aliases | join('/')}},{{get_exposed_attributes(entity.entity_id)}}
|
||||||
|
{% endfor -%}
|
||||||
|
```
|
||||||
|
|
||||||
|
The current state of devices is provided in available devices.
|
||||||
|
Use execute_services function to control devices.
|
||||||
|
If needed, you can infer the entity_id from the name and common variations.
|
||||||
|
Do not ask for confirmation to execute a service.
|
||||||
|
Do not restate or appreciate what user says, rather make a quick inquiry.
|
652
devices/homie/modules/home-assistant/timer.nix
Normal file
652
devices/homie/modules/home-assistant/timer.nix
Normal file
|
@ -0,0 +1,652 @@
|
||||||
|
# From https://github.com/don86nl/ha_intents/blob/main/config/packages/assist_timers.yaml
|
||||||
|
{...}: let
|
||||||
|
settings = {
|
||||||
|
timer_media_location = "/path/to/file.mp3";
|
||||||
|
timer_target = "kitchen";
|
||||||
|
timer_target_default = "media_player.music_player_daemon";
|
||||||
|
timer_tts = true;
|
||||||
|
timer_tts_message = "A set timer has finished.";
|
||||||
|
timer_tts_service = "tts.speak";
|
||||||
|
timer_tts_target = "tts.piper";
|
||||||
|
timer_volume = 0.4;
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
services.home-assistant = {
|
||||||
|
config = {
|
||||||
|
# TODO: format this properly
|
||||||
|
automation = [
|
||||||
|
{
|
||||||
|
action = [
|
||||||
|
{
|
||||||
|
alias = "Get generic variables from script";
|
||||||
|
variables = {
|
||||||
|
timer_media_location = "{{ settings.get('timer_media_location') }}";
|
||||||
|
timer_target = "{%- if settings.get('timer_target')[:13] == \"\" %} {{- settings.get('timer_target_default') }} {%- elif settings.get('timer_target')[:13] == \"media_player.\" %} {{- settings.get('timer_target') }} {%- elif (settings.get('timer_target')[:7] == \"sensor.\" or settings.get('timer_target')[:11] == \"input_text.\") and (states(settings.get('timer_target'))[:13] == \"media_player.\") %} {{- states(settings.get('timer_target')) }} {%- elif (settings.get('timer_target')[:7] == \"sensor.\" or settings.get('timer_target')[:11] == \"input_text.\") and (states(settings.get('timer_target')) == \"\") %} {{- settings.get('timer_target_default') }} {%- else %} {%- set media_player_list = states.media_player | map(attribute='entity_id') | list %} {%- if \"sensor.\" in settings.get('timer_target') or \"input_text.\" in target_area %} {%- set target_area = states(settings.get('timer_target')) %} {%- else %} {%- set target_area = settings.get('timer_target') %} {%- endif %} {%- for entity_id in media_player_list %} {%- if area_name(entity_id) | lower == target_area | lower %} {{ entity_id }} {%- endif %} {%- endfor %} {%- endif %} ";
|
||||||
|
timer_tts = "{{ settings.get('timer_tts') }}";
|
||||||
|
timer_tts_message = "{{ settings.get('timer_tts_message') }}";
|
||||||
|
timer_tts_service = "{{ settings.get('timer_tts_service') }}";
|
||||||
|
timer_tts_target = "{{ settings.get('timer_tts_target') }}";
|
||||||
|
timer_volume = "{{ settings.get('timer_volume') }}";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
alias = "Store current device volume";
|
||||||
|
variables = {device_volume = "{{ state_attr(timer_target, 'volume_level') }}";};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
alias = "Set volume for timer";
|
||||||
|
data = {volume_level = "{{ timer_volume }}";};
|
||||||
|
service = "media_player.volume_set";
|
||||||
|
target = {entity_id = "{{ timer_target }}";};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
alias = "Media file or TTS";
|
||||||
|
choose = [
|
||||||
|
{
|
||||||
|
alias = "Media file";
|
||||||
|
conditions = [
|
||||||
|
{
|
||||||
|
alias = "Timer is a media file";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ timer_tts == false }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
sequence = [
|
||||||
|
{
|
||||||
|
alias = "Play media";
|
||||||
|
data = {
|
||||||
|
announce = true;
|
||||||
|
media_content_id = "{{ timer_media_location }}";
|
||||||
|
media_content_type = "music";
|
||||||
|
};
|
||||||
|
enabled = true;
|
||||||
|
service = "media_player.play_media";
|
||||||
|
target = {entity_id = "{{ timer_target }}";};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
default = [
|
||||||
|
{delay = {seconds = 1;};}
|
||||||
|
{
|
||||||
|
alias = "Choose TTS service";
|
||||||
|
choose = [
|
||||||
|
{
|
||||||
|
conditions = [
|
||||||
|
{
|
||||||
|
alias = "tts.cloud_say";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ timer_tts_service != 'tts.speak' }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
sequence = [
|
||||||
|
{
|
||||||
|
data = {
|
||||||
|
cache = true;
|
||||||
|
entity_id = "{{ timer_target }}";
|
||||||
|
message = "{% if timer_tts_message[:7] == \"sensor.\" or timer_tts_message[:11] == \"input_text.\" %} {{ states(timer_tts_message) }} {% else %} {{ timer_tts_message }} {% endif %}";
|
||||||
|
};
|
||||||
|
service = "{{ timer_tts_service }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
default = [
|
||||||
|
{
|
||||||
|
data = {
|
||||||
|
cache = true;
|
||||||
|
media_player_entity_id = "{{ timer_target }}";
|
||||||
|
message = "{% if timer_tts_message[:7] == \"sensor.\" or timer_tts_message[:11] == \"input_text.\" %} {{ states(timer_tts_message) }} {% else %} {{ timer_tts_message }} {% endif %}";
|
||||||
|
};
|
||||||
|
service = "tts.speak";
|
||||||
|
target = {entity_id = "{{ timer_tts_target }}";};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
alias = "Restore device previous volume";
|
||||||
|
data = {volume_level = "{{ device_volume }}";};
|
||||||
|
service = "media_player.volume_set";
|
||||||
|
target = {entity_id = "{{ timer_target }}";};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
alias = "Assist - TimerReached";
|
||||||
|
condition = [
|
||||||
|
{
|
||||||
|
alias = "Finished timer is an assist timer";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ trigger.event.data.entity_id[:18] == 'timer.assist_timer' }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
description = "Assist automation when set timer time is reached.";
|
||||||
|
id = "assist_timerreached";
|
||||||
|
mode = "single";
|
||||||
|
trigger = [
|
||||||
|
{
|
||||||
|
alias = "Any timer reached";
|
||||||
|
event_type = "timer.finished";
|
||||||
|
id = "timer_finished";
|
||||||
|
platform = "event";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
variables = {
|
||||||
|
inherit settings;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
action = [
|
||||||
|
{
|
||||||
|
alias = "Delay for Timer Reached automation";
|
||||||
|
delay = {seconds = 3;};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
alias = "Reset timer location";
|
||||||
|
data = {value = "";};
|
||||||
|
service = "input_text.set_value";
|
||||||
|
target = {entity_id = "{{ 'input_text.' + trigger.entity_id[6:] + '_location' }}";};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
alias = "Assist - TimerFinished";
|
||||||
|
condition = [
|
||||||
|
{
|
||||||
|
alias = "Timer was active or paused";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ trigger.from_state != trigger.to_state }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
description = "Assist automation when set timer time is finished.";
|
||||||
|
id = "assist_timerfinished";
|
||||||
|
mode = "parallel";
|
||||||
|
trigger = [
|
||||||
|
{
|
||||||
|
alias = "Assist timer finished or cancelled";
|
||||||
|
entity_id = ["timer.assist_timer1" "timer.assist_timer2" "timer.assist_timer3"];
|
||||||
|
platform = "state";
|
||||||
|
to = "idle";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
homeassistant = {
|
||||||
|
customize = {
|
||||||
|
"script.assist_timerstart" = {
|
||||||
|
inherit settings;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
input_text = {
|
||||||
|
assist_timer1_location = {
|
||||||
|
icon = "mdi:assistant";
|
||||||
|
max = 255;
|
||||||
|
name = "Assist - Timer 1 Location";
|
||||||
|
};
|
||||||
|
assist_timer2_location = {
|
||||||
|
icon = "mdi:assistant";
|
||||||
|
max = 255;
|
||||||
|
name = "Assist - Timer 2 Location";
|
||||||
|
};
|
||||||
|
assist_timer3_location = {
|
||||||
|
icon = "mdi:assistant";
|
||||||
|
max = 255;
|
||||||
|
name = "Assist - Timer 3 Location";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
intent_script = {
|
||||||
|
TimerDuration = {
|
||||||
|
action = [{stop = "";}];
|
||||||
|
async_action = true;
|
||||||
|
};
|
||||||
|
TimerPause = {
|
||||||
|
action = [
|
||||||
|
{
|
||||||
|
data = {
|
||||||
|
entity_id = "{{ entity_id }}";
|
||||||
|
timer_action = "{{ timer_action }}";
|
||||||
|
};
|
||||||
|
service = "script.assist_TimerPause";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
async_action = true;
|
||||||
|
};
|
||||||
|
TimerStart = {
|
||||||
|
action = [
|
||||||
|
{
|
||||||
|
data = {duration = "{{hours | int(default=0)}}:{{ minutes | int(default=0) }}:{{ seconds | int(default=0) }}";};
|
||||||
|
service = "script.assist_TimerStart";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
async_action = false;
|
||||||
|
};
|
||||||
|
TimerStop = {
|
||||||
|
action = [
|
||||||
|
{
|
||||||
|
data = {entity_id = "{{ entity_id }}";};
|
||||||
|
service = "script.assist_TimerStop";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
async_action = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
script = {
|
||||||
|
assist_timerpause = {
|
||||||
|
alias = "Assist - TimerPause";
|
||||||
|
description = "Script for pausing a timer using HA Assist.";
|
||||||
|
icon = "mdi:assistant";
|
||||||
|
mode = "single";
|
||||||
|
sequence = [
|
||||||
|
{
|
||||||
|
choose = [
|
||||||
|
{
|
||||||
|
conditions = [
|
||||||
|
{
|
||||||
|
alias = "Single Timer";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ entity_id[:18] == 'timer.assist_timer' }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
sequence = [
|
||||||
|
{
|
||||||
|
alias = "Single timer: Idle or active";
|
||||||
|
choose = [
|
||||||
|
{
|
||||||
|
conditions = [
|
||||||
|
{
|
||||||
|
alias = "Timer not active";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ states(entity_id) == 'idle' }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
sequence = [{stop = "Timer is not active";}];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
default = [
|
||||||
|
{
|
||||||
|
alias = "Pause or resume";
|
||||||
|
choose = [
|
||||||
|
{
|
||||||
|
alias = "Pause";
|
||||||
|
conditions = [
|
||||||
|
{
|
||||||
|
alias = "Action = pause";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ timer_action == 'pause' }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
sequence = [
|
||||||
|
{
|
||||||
|
alias = "Pause timer";
|
||||||
|
service = "timer.pause";
|
||||||
|
target = {entity_id = "{{ entity_id }}";};
|
||||||
|
}
|
||||||
|
{stop = "Pause timer";}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
default = [
|
||||||
|
{
|
||||||
|
alias = "Resume timer";
|
||||||
|
service = "timer.start";
|
||||||
|
target = {entity_id = "{{ entity_id }}";};
|
||||||
|
}
|
||||||
|
{stop = "Resume timer";}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
alias = "No specific timer";
|
||||||
|
conditions = [
|
||||||
|
{
|
||||||
|
alias = "No specific Timer";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ entity_id == 'null' }}";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
alias = "Timer(s) are active";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ states.timer \n | rejectattr('state','eq','idle') \n | selectattr('entity_id','match','timer.assist_timer*')\n | map(attribute='entity_id') \n | list\n | length > 0 }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
sequence = [
|
||||||
|
{
|
||||||
|
alias = "No specific timer: # active?";
|
||||||
|
choose = [
|
||||||
|
{
|
||||||
|
conditions = [
|
||||||
|
{
|
||||||
|
alias = "No specific timer asked";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ entity_id == 'null' }}";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
alias = "Multiple timers active";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ states.timer \n | rejectattr('state','eq','idle') \n | selectattr('entity_id','match','timer.assist_timer*')\n | map(attribute='entity_id') \n | list\n | length > 1 }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
sequence = [{stop = "Multiple timers active, none specified";}];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
default = [
|
||||||
|
{
|
||||||
|
alias = "Pause or resume";
|
||||||
|
choose = [
|
||||||
|
{
|
||||||
|
alias = "Pause";
|
||||||
|
conditions = [
|
||||||
|
{
|
||||||
|
alias = "Action = pause";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ timer_action == 'pause' }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
sequence = [
|
||||||
|
{
|
||||||
|
alias = "Pause timer";
|
||||||
|
service = "timer.pause";
|
||||||
|
target = {entity_id = "{{ states.timer \n | rejectattr('state','eq','idle') \n | selectattr('entity_id','match','timer.assist_timer*')\n | map(attribute='entity_id') \n | join(', ') }}";};
|
||||||
|
}
|
||||||
|
{stop = "Pause timer";}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
default = [
|
||||||
|
{
|
||||||
|
alias = "Resume timer";
|
||||||
|
service = "timer.start";
|
||||||
|
target = {entity_id = "{{ states.timer \n | rejectattr('state','eq','idle') \n | selectattr('entity_id','match','timer.assist_timer*')\n | map(attribute='entity_id') \n | join(', ') }}";};
|
||||||
|
}
|
||||||
|
{stop = "Resume timer";}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
alias = "All timers";
|
||||||
|
conditions = [
|
||||||
|
{
|
||||||
|
alias = "All timers";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ entity_id == 'all' }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
sequence = [
|
||||||
|
{
|
||||||
|
alias = "Timers active?";
|
||||||
|
choose = [
|
||||||
|
{
|
||||||
|
alias = "No timers active";
|
||||||
|
conditions = [
|
||||||
|
{
|
||||||
|
alias = "No timers active";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ states.timer \n | rejectattr('state','eq','idle') \n | selectattr('entity_id','match','timer.assist_timer*')\n | map(attribute='entity_id') \n | list\n | length == 0 }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
sequence = [{stop = "No timers active";}];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
default = [
|
||||||
|
{
|
||||||
|
alias = "Pause or resume";
|
||||||
|
choose = [
|
||||||
|
{
|
||||||
|
alias = "Pause";
|
||||||
|
conditions = [
|
||||||
|
{
|
||||||
|
alias = "Action = pause";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ timer_action == 'pause' }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
sequence = [
|
||||||
|
{
|
||||||
|
alias = "Pause timer";
|
||||||
|
service = "timer.pause";
|
||||||
|
target = {entity_id = "{{ states.timer \n | rejectattr('state','eq','idle') \n | selectattr('entity_id','match','timer.assist_timer*')\n | map(attribute='entity_id') \n | join(', ') }}";};
|
||||||
|
}
|
||||||
|
{stop = "Pause timer";}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
default = [
|
||||||
|
{
|
||||||
|
alias = "Resume timer";
|
||||||
|
service = "timer.start";
|
||||||
|
target = {entity_id = "{{ states.timer \n | rejectattr('state','eq','idle') \n | selectattr('entity_id','match','timer.assist_timer*')\n | map(attribute='entity_id') \n | join(', ') }}";};
|
||||||
|
}
|
||||||
|
{stop = "Resume timer";}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
variables = {
|
||||||
|
entity_id = "{% if entity_id is set or entity_id != \"\" %} {{ entity_id }} {% else %} null {% endif %}";
|
||||||
|
timer_action = "{% if timer_action is set or timer_action != \"\" %} {{ timer_action }} {% else %} resume {% endif %}";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
assist_timerstart = {
|
||||||
|
alias = "Assist - TimerStart";
|
||||||
|
description = "Script for starting a timer using HA Assist.";
|
||||||
|
icon = "mdi:assistant";
|
||||||
|
mode = "single";
|
||||||
|
sequence = [
|
||||||
|
{
|
||||||
|
alias = "Set variables";
|
||||||
|
variables = {timer_location = "{%- if settings.get('timer_target')[:13] == \"media_player.\" %} {{ area_name(settings.get('timer_target')) | lower }} {% elif (settings.get('timer_target')[:7] == \"sensor.\" or settings.get('timer_target')[:11] == \"input_text.\") and states(settings.get('timer_target'))[:13] == \"media_player.\" %} {{- states(settings.get('timer_target')) }} {%- elif settings.get('timer_target')[:13] != \"media_player.\" and settings.get('timer_target')[:7] != \"sensor.\" and settings.get('timer_target')[:11] != \"input_text.\" %} {{- settings.get('timer_target') }} {%- elif (settings.get('timer_target')[:7] == \"sensor.\" or settings.get('timer_target')[:11] == \"input_text.\") and (states(settings.get('timer_target')) != \"\") and (states(settings.get('timer_target'))[:13] == \"media_player.\") %} {{ area_name(settings.get('timer_target_default')) }} {%- elif (settings.get('timer_target')[:7] == \"sensor.\" or settings.get('timer_target')[:11] == \"input_text.\") %} {% if states(settings.get('timer_target')) != \"\" and states(settings.get('timer_target')) != \"not_home\" and states(settings.get('timer_target')) != 0 %} {{ states(settings.get('timer_target')) }} {% else %} {{- area_name(settings.get('timer_target_default')) | lower }} {%- endif %} {%- else %} {{- area_name(settings.get('timer_target')) | lower }} {%- endif %}";};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
alias = "Set timer location";
|
||||||
|
data = {value = "{{ timer_location }}";};
|
||||||
|
service = "input_text.set_value";
|
||||||
|
target = {entity_id = "{% if states('timer.assist_timer1') != 'active' and states('timer.assist_timer1') != 'paused' %} input_text.assist_timer1_location {% elif states('timer.assist_timer2') != 'active' and states('timer.assist_timer2') != 'paused' %} input_text.assist_timer2_location {% else %} input_text.assist_timer3_location {% endif%}";};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
alias = "Start timer";
|
||||||
|
data_template = {duration = "{{ duration }}";};
|
||||||
|
service = "timer.start";
|
||||||
|
target = {entity_id = "{% if states('timer.assist_timer1') != 'active' and states('timer.assist_timer1') != 'paused' %} timer.assist_timer1 {% elif states('timer.assist_timer2') != 'active' and states('timer.assist_timer2') != 'paused' %} timer.assist_timer2 {% else %} timer.assist_timer3{% endif%}";};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
variables = {
|
||||||
|
inherit settings;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
assist_timerstop = {
|
||||||
|
alias = "Assist - TimerStop";
|
||||||
|
description = "Script for stopping a timer using HA Assist.";
|
||||||
|
icon = "mdi:assistant";
|
||||||
|
mode = "single";
|
||||||
|
sequence = [
|
||||||
|
{
|
||||||
|
alias = "Set variables";
|
||||||
|
variables = {entity_id = "{% if entity_id is set or entity_id != \"\" %} {{ entity_id }} {% else %} null {% endif %}";};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
choose = [
|
||||||
|
{
|
||||||
|
alias = "Stop Timer music";
|
||||||
|
conditions = [
|
||||||
|
{
|
||||||
|
alias = "Timer is a media file";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ timer_tts == false }}";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{% set mediaplayer = namespace(entity=[]) %}\n{% for player in states.media_player %}\n {%- 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' -%}\n {%- set mediaplayer.entity = player.entity_id -%}\n {% endif -%}\n{% endfor %}\n{{ mediaplayer.entity[:12] == 'media_player' }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
sequence = [
|
||||||
|
{
|
||||||
|
alias = "Stop timer music";
|
||||||
|
service = "media_player.media_stop";
|
||||||
|
target = {entity_id = "{% set mediaplayer = namespace(entity=[]) %} {% for player in states.media_player %}\n {% 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' %}\n {% set mediaplayer.entity = player.entity_id %}\n {% endif %}\n{% endfor %} {{ mediaplayer.entity }}";};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
conditions = [
|
||||||
|
{
|
||||||
|
alias = "Single Timer";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ entity_id[:18] == 'timer.assist_timer' }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
sequence = [
|
||||||
|
{
|
||||||
|
alias = "Single timer: Idle or active";
|
||||||
|
choose = [
|
||||||
|
{
|
||||||
|
conditions = [
|
||||||
|
{
|
||||||
|
alias = "Timer not active";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ states(entity_id) == 'idle' }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
sequence = [{stop = "Timer is not active";}];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
default = [
|
||||||
|
{
|
||||||
|
alias = "Cancel single timer";
|
||||||
|
service = "timer.cancel";
|
||||||
|
target = {entity_id = "{{ entity_id }}";};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
alias = "Reset timer location value";
|
||||||
|
data = {value = "0";};
|
||||||
|
service = "input_text.set_value";
|
||||||
|
target = {entity_id = "{{ states.timer \n | selectattr('state','eq','active') \n | selectattr('entity_id','match','timer.assist_timer*')\n | map(attribute='entity_id') \n | join('_location, ') | replace('timer.', 'input_text.') }}";};
|
||||||
|
}
|
||||||
|
{stop = "Timer cancelled";}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
alias = "No specific timer";
|
||||||
|
conditions = [
|
||||||
|
{
|
||||||
|
alias = "No specific Timer";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ entity_id == 'null' }}";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
alias = "Timer(s) are active";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ states.timer \n | rejectattr('state','eq','idle') \n | selectattr('entity_id','match','timer.assist_timer*')\n | map(attribute='entity_id') \n | list\n | length > 0 }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
sequence = [
|
||||||
|
{
|
||||||
|
alias = "No specific timer: # active?";
|
||||||
|
choose = [
|
||||||
|
{
|
||||||
|
conditions = [
|
||||||
|
{
|
||||||
|
alias = "No specific timer asked";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ entity_id == 'null' }}";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
alias = "Multiple timers active";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ states.timer \n | rejectattr('state','eq','idle') \n | selectattr('entity_id','match','timer.assist_timer*')\n | map(attribute='entity_id') \n | list\n | length > 1 }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
sequence = [{stop = "Multiple timers active, none specified";}];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
default = [
|
||||||
|
{
|
||||||
|
alias = "Cancel single timer";
|
||||||
|
service = "timer.cancel";
|
||||||
|
target = {entity_id = "{{ states.timer \n | rejectattr('state','eq','idle') \n | selectattr('entity_id','match','timer.assist_timer*')\n | map(attribute='entity_id') \n | join(', ') }}";};
|
||||||
|
}
|
||||||
|
{
|
||||||
|
alias = "Reset timer location value";
|
||||||
|
data = {value = "0";};
|
||||||
|
metadata = {};
|
||||||
|
service = "input_text.set_value";
|
||||||
|
target = {entity_id = "{{ states.timer \n | rejectattr('state','eq','idle') \n | selectattr('entity_id','match','timer.assist_timer*')\n | map(attribute='entity_id') \n | join('_location, ') | replace('timer.', 'input_text.') }}";};
|
||||||
|
}
|
||||||
|
{stop = "Timer cancelled";}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
{
|
||||||
|
alias = "All timers";
|
||||||
|
conditions = [
|
||||||
|
{
|
||||||
|
alias = "All timers";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ entity_id == 'all' }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
sequence = [
|
||||||
|
{
|
||||||
|
alias = "Timers active?";
|
||||||
|
choose = [
|
||||||
|
{
|
||||||
|
alias = "No timers active";
|
||||||
|
conditions = [
|
||||||
|
{
|
||||||
|
alias = "No timers active";
|
||||||
|
condition = "template";
|
||||||
|
value_template = "{{ states.timer \n | rejectattr('state','eq','idle') \n | selectattr('entity_id','match','timer.assist_timer*')\n | map(attribute='entity_id') \n | list\n | length == 0 }}";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
sequence = [{stop = "No timers active";}];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
default = [
|
||||||
|
{
|
||||||
|
alias = "Cancel all timers";
|
||||||
|
service = "timer.cancel";
|
||||||
|
target = {entity_id = "{{ states.timer \n | rejectattr('state','eq','idle') \n | selectattr('entity_id','match','timer.assist_timer*')\n | map(attribute='entity_id') \n | join(', ') }}";};
|
||||||
|
}
|
||||||
|
{stop = "Cancel all timers";}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
|
variables = {entity_id = "{% if entity_id is set or entity_id != \"\" %} {{ entity_id }} {% else %} null {% endif %}";};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
timer = {
|
||||||
|
assist_timer1 = {
|
||||||
|
icon = "mdi:assistant";
|
||||||
|
name = "Assist - Timer 1";
|
||||||
|
restore = true;
|
||||||
|
};
|
||||||
|
assist_timer2 = {
|
||||||
|
icon = "mdi:assistant";
|
||||||
|
name = "Assist - Timer 2";
|
||||||
|
restore = true;
|
||||||
|
};
|
||||||
|
assist_timer3 = {
|
||||||
|
icon = "mdi:assistant";
|
||||||
|
name = "Assist - Timer 3";
|
||||||
|
restore = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
BIN
flake.lock
BIN
flake.lock
Binary file not shown.
BIN
flake.nix
BIN
flake.nix
Binary file not shown.
|
@ -168,9 +168,9 @@ let
|
||||||
repo = "home-llm";
|
repo = "home-llm";
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name = "extended-openai-conversation-src";
|
name = "extended-ollama-conversation-src";
|
||||||
owner = "jekalmin";
|
owner = "TheNimaj";
|
||||||
repo = "extended_openai_conversation";
|
repo = "extended_ollama_conversation";
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,5 +4,5 @@ pkgs.lib.makeScope pkgs.newScope (hass: let
|
||||||
hass.callPackage file (inputs // {});
|
hass.callPackage file (inputs // {});
|
||||||
in {
|
in {
|
||||||
home-llm = buildHassComponent ./home-llm.nix;
|
home-llm = buildHassComponent ./home-llm.nix;
|
||||||
extended-openai-conversation = buildHassComponent ./extended-openai-conversation.nix;
|
extended-ollama-conversation = buildHassComponent ./extended-ollama-conversation.nix;
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
{
|
{
|
||||||
extended-openai-conversation-src,
|
extended-ollama-conversation-src,
|
||||||
buildHomeAssistantComponent,
|
buildHomeAssistantComponent,
|
||||||
fetchFromGitHub,
|
fetchFromGitHub,
|
||||||
python312Packages,
|
python3Packages,
|
||||||
...
|
...
|
||||||
}: let
|
}: let
|
||||||
inherit (builtins) fromJSON readFile;
|
inherit (builtins) fromJSON readFile;
|
||||||
|
|
||||||
manifest = fromJSON (readFile "${extended-openai-conversation-src}/custom_components/extended_openai_conversation/manifest.json");
|
manifest = fromJSON (readFile "${extended-ollama-conversation-src}/custom_components/extended_ollama_conversation/manifest.json");
|
||||||
|
|
||||||
openai = python312Packages.openai.overrideAttrs (o: rec {
|
openai = python3Packages.openai.overrideAttrs (o: rec {
|
||||||
version = "1.3.8";
|
version = "1.3.8";
|
||||||
|
|
||||||
src = fetchFromGitHub {
|
src = fetchFromGitHub {
|
||||||
|
@ -23,11 +23,11 @@
|
||||||
});
|
});
|
||||||
in
|
in
|
||||||
buildHomeAssistantComponent {
|
buildHomeAssistantComponent {
|
||||||
owner = "jekalmin";
|
owner = "TheNimaj";
|
||||||
|
|
||||||
inherit (manifest) domain version;
|
inherit (manifest) domain version;
|
||||||
|
|
||||||
src = extended-openai-conversation-src;
|
src = extended-ollama-conversation-src;
|
||||||
|
|
||||||
propagatedBuildInputs = [openai];
|
propagatedBuildInputs = [python3Packages.ollama openai];
|
||||||
}
|
}
|
Loading…
Reference in a new issue