Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
# Unique Home Assistant Blueprints & Tutorials

**[ 🇺🇸 English | [🇻🇳 Tiếng Việt](README_vi.md) ]**
**🇺🇸 English | [🇻🇳 Tiếng Việt](README_vi.md)**

> [!TIP]
> **[Blueprints Updater](https://github.com/luuquangvu/blueprints-updater)**: A highly useful integration that automatically updates blueprints in this collection. When you have many blueprints from different sources, keeping track of updates can be challenging - this integration handles it for you automatically.

**Google has recently significantly cut back on the free Gemini API, making it almost impossible to meet the usage needs of Home Assistant. You can find [a completely free alternative solution here](https://github.com/luuquangvu/ha-addons).**
<!-- MD028/no-blanks-blockquote: Blank line inside blockquote -->

> [!NOTE]
> **Google has recently significantly cut back on the free Gemini API, making it almost impossible to meet the usage needs of Home Assistant. You can find [a completely free alternative solution here](https://github.com/luuquangvu/ha-addons).**

_All blueprints in this collection are fine-tuned to work best with **Gemini Flash** models. Other models may require minor adjustments to behave as expected._

Expand Down
7 changes: 5 additions & 2 deletions README_vi.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
# Bộ sưu tập Blueprint và Hướng dẫn độc đáo cho Home Assistant

**[ [🇺🇸 English](README.md) | 🇻🇳 Tiếng Việt ]**
**[🇺🇸 English](README.md) | 🇻🇳 Tiếng Việt**

> [!TIP]
> **[Blueprints Updater](https://github.com/luuquangvu/blueprints-updater)**: Một tích hợp cực kỳ hữu ích giúp tự động cập nhật các blueprint trong bộ sưu tập này. Khi bạn cài đặt nhiều blueprint từ nhiều nguồn khác nhau, việc theo dõi cập nhật từ các tác giả trở nên khó khăn - tích hợp này sẽ giải quyết vấn đề đó cho bạn hoàn toàn tự động.

**Gần đây, Google đã cắt giảm đáng kể API Gemini miễn phí, khiến nó gần như không thể đáp ứng nhu cầu sử dụng của Home Assistant. Các bạn có thể tham khảo [một giải pháp thay thế hoàn toàn miễn phí tại đây](https://github.com/luuquangvu/ha-addons).**
<!-- MD028/no-blanks-blockquote: Blank line inside blockquote -->

> [!NOTE]
> **Gần đây, Google đã cắt giảm đáng kể API Gemini miễn phí, khiến nó gần như không thể đáp ứng nhu cầu sử dụng của Home Assistant. Các bạn có thể tham khảo [một giải pháp thay thế hoàn toàn miễn phí tại đây](https://github.com/luuquangvu/ha-addons).**

_Tất cả blueprint trong bộ sưu tập này được tinh chỉnh để hoạt động tối ưu với các mô hình (model) **Gemini Flash**. Các mô hình ngôn ngữ khác có thể cần điều chỉnh nhỏ để đạt hiệu quả tương tự._

Expand Down
117 changes: 94 additions & 23 deletions calendar_events_lookup_full_llm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@ blueprint:
text:
multiline: true
default: |-
daily or hourly
daily or hourly. Default daily
time_period_length_prompt:
name: Time Period Length Prompt
description: The prompt used by the AI to identify the period length [Human-only]
selector:
text:
multiline: true
default: |-
Length in days (daily) or hours (hourly)
Length in days (daily) or hours (hourly). Default 1
date_prompt:
name: Date Prompt
description: The prompt used by the AI to identify the starting date [Human-only]
Expand All @@ -75,12 +75,12 @@ blueprint:
text:
multiline: true
default: |-
Start time (HH:MM:SS)
Start time (HH:MM:SS). Default 00:00:00 for daily, current time for hourly
mode: parallel
max_exceeded: silent
description: Retrieves upcoming or past calendar events for a specific period
variables:
version: 20260818
version: 20260821
fields:
time_period_type:
name: Time Period Type
Expand All @@ -90,39 +90,56 @@ fields:
options:
- daily
- hourly
required: true
default: daily
time_period_length:
name: Time Period Length
description: !input time_period_length_prompt
selector:
number:
min: 1
max: 120
required: true
default: 1
start_date:
name: Start Date
description: !input date_prompt
selector:
date:
required: true
start_time:
name: Start Time
description: !input time_prompt
selector:
time:
required: true
sequence:
- variables:
start_date: "{{ start_date | as_datetime(default='') }}"
start_time: "{{ start_time | default('00:00:00') | as_timedelta | default('00:00:00', true) }}"
_period_type: "{{ time_period_type if (time_period_type | default) in ['daily', 'hourly'] else 'daily' }}"
_add_length: "{{ (time_period_length | default(1) | float(1)) | abs }}"
_start_date_raw: "{{ start_date | default('', true) | trim }}"
_start_time_raw: "{{ start_time | default('', true) | trim }}"
_start_date_val: >-
{% if _start_date_raw != '' %}
{% set parsed = _start_date_raw | as_datetime(default=none) %}
{{ (parsed.date() | string) if parsed is not none else _start_date_raw }}
{% else %}
{{ now().strftime('%Y-%m-%d') }}
{% endif %}
_start_time_val: >-
{% if _start_time_raw != '' %}
{{ _start_time_raw }}
{% elif _period_type == 'hourly' and (_start_date_val == now().strftime('%Y-%m-%d')) %}
{{ now().strftime('%H:%M:%S') }}
{% else %}
00:00:00
{% endif %}
start: >-
{{ ((start_date | as_datetime + as_timedelta(start_time)) | as_local) if start_date else 'n/a' }}
{% set dt_str = _start_date_val ~ ' ' ~ _start_time_val %}
{% set dt = dt_str | as_datetime(default=none) %}
{{ (dt | as_local).isoformat() if dt is not none else 'n/a' }}
end: >-
{% if start != 'n/a' %}
{% set start = as_datetime(start) %}
{% set add = (time_period_length | default(1) | float(1)) | abs %}
{% set type = time_period_type if (time_period_type | default) in ['daily', 'hourly'] else 'daily' %}
{{ (start + timedelta(days = add if type == 'daily' else 0, hours = add if type == 'hourly' else 0)) | as_local }}
{% set start_dt = as_datetime(start) %}
{{ (start_dt + timedelta(days = _add_length if _period_type == 'daily' else 0, hours = _add_length if _period_type == 'hourly' else 0)) | as_local | string }}
{% else %}
n/a
{% endif %}
- alias: Check if variables were set correctly
if:
Expand All @@ -147,13 +164,67 @@ sequence:
start_date_time: "{{ start }}"
end_date_time: "{{ end }}"
- variables:
response:
events: >-
{{
response.values()
| map(attribute='events')
| sum(start=[])
| sort(attribute='start')
}}
response: >-
{% set raw_events = response.values() | map(attribute='events') | sum(start=[]) | sort(attribute='start') %}
{% set enriched = namespace(events=[]) %}
{% for ev in raw_events %}
{% set s_str = ev.start | string %}
{% set is_all_day = ('T' not in s_str) and (' ' not in s_str) %}
{% set s_dt = (ev.start | as_datetime | as_local) if (ev.start | as_datetime(default=none)) is not none else none %}
{% set e_dt = (ev.end | as_datetime | as_local) if (ev.end | as_datetime(default=none)) is not none else none %}
{% if s_dt is not none %}
{% set rel = ('in ' ~ time_until(s_dt)) if s_dt >= now() else (time_since(s_dt) ~ ' ago') %}
{% else %}
{% set rel = '' %}
{% endif %}
{% if is_all_day %}
{% if s_dt is not none and e_dt is not none %}
{% set d_days = (e_dt.date() - s_dt.date()).days %}
{% set dur = 'all day' if d_days <= 1 else (d_days ~ ' days') %}
{% else %}
{% set dur = 'all day' %}
{% endif %}
{% else %}
{% if s_dt is not none and e_dt is not none %}
{% set dur_sec = (e_dt - s_dt).total_seconds() | int(0) %}
{% set dur_h = dur_sec // 3600 %}
{% set dur_m = (dur_sec % 3600) // 60 %}
{% if dur_h > 0 and dur_m > 0 %}
{% set dur = dur_h ~ ' hr ' ~ dur_m ~ ' min' %}
{% elif dur_h > 0 %}
{% set dur = dur_h ~ (' hr' if dur_h == 1 else ' hrs') %}
{% elif dur_m > 0 %}
{% set dur = dur_m ~ ' min' %}
{% else %}
{% set dur = dur_sec ~ ' sec' %}
{% endif %}
{% else %}
{% set dur = '' %}
{% endif %}
{% endif %}
{% set item = dict(ev,
weekday=(s_dt.strftime('%A') if s_dt is not none else ''),
is_all_day=is_all_day,
relative_time=rel,
duration=dur
) %}
{% set enriched.events = enriched.events + [item] %}
{% endfor %}
{{
dict(
current_context=dict(
current_time=now().strftime('%A, %Y-%m-%d %H:%M:%S %z'),
timezone=now().tzinfo | string
),
queried_period=dict(
start=start,
end=end,
type=_period_type,
length=_add_length
),
events_count=enriched.events | length,
events=enriched.events
)
}}
- stop: ""
response_variable: response
5 changes: 4 additions & 1 deletion camera_snapshot_full_llm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ mode: parallel
max_exceeded: silent
description: Captures a camera snapshot or records a video and returns the local file path
variables:
version: 20260818
version: 20260821
fields:
camera_name:
name: Camera Name
Expand Down Expand Up @@ -278,5 +278,8 @@ sequence:
- variables:
response:
error: "Unsupported capture type: {{ capture_type }}"
- variables:
response: >-
{{ dict(response, captured_at=now().strftime('%Y-%m-%d %H:%M:%S %z')) if response is mapping else response }}
- stop: ""
response_variable: response
41 changes: 35 additions & 6 deletions create_calendar_event_full_llm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ blueprint:
text:
multiline: true
default: |-
End date/time (YYYY-MM-DD HH:MM:SS)
End date/time (YYYY-MM-DD HH:MM:SS). Optional, default start + 1h
start_date_prompt:
name: Start Date Prompt
description: The starting date for all-day events (YYYY-MM-DD), provided by the AI
Expand All @@ -103,13 +103,13 @@ blueprint:
text:
multiline: true
default: |-
End date (YYYY-MM-DD)
End date (YYYY-MM-DD). Optional, default start date
mode: queued
max: !input simultaneous
max_exceeded: silent
description: Adds a new event to a specified calendar
variables:
version: 20260409
version: 20260821
fields:
summary:
selector:
Expand Down Expand Up @@ -148,9 +148,31 @@ sequence:
summary: "{{ summary | default('') | trim }}"
description: "{{ description | default('') | trim }}"
start_date_time: "{{ start_date_time | default('') | trim }}"
end_date_time: "{{ end_date_time | default('') | trim }}"
start_date: "{{ start_date | default('') | trim }}"
end_date: "{{ end_date | default('') | trim }}"
end_date_time: >-
{% if end_date_time | default('') | trim != '' %}
{{ end_date_time | trim }}
{% elif start_date_time | default('') | trim != '' %}
{% set sdt = start_date_time | as_datetime(default=none) %}
{{ ((sdt + timedelta(hours=1)) | as_local).isoformat() if sdt is not none else '' }}
{% else %}
''
{% endif %}
end_date: >-
{% set sd = start_date | as_datetime(default=none) %}
{% set ed_raw = end_date | default('', true) | trim %}
{% if ed_raw != '' %}
{% set ed = ed_raw | as_datetime(default=none) %}
{% if sd is not none and ed is not none and sd.date() == ed.date() %}
{{ ((ed + timedelta(days=1)) | as_local).date() | string }}
{% else %}
{{ ed_raw }}
{% endif %}
{% elif sd is not none %}
{{ ((sd + timedelta(days=1)) | as_local).date() | string }}
{% else %}
''
{% endif %}
calendar: !input calendar
- alias: Check if variables were set correctly
if:
Expand Down Expand Up @@ -304,7 +326,14 @@ sequence:
variables:
response:
message: >-
Event created: {{ summary }} ({{ (start_date | as_datetime).date() }} to {{ (end_date | as_datetime).date() }}) in {{ state_attr(calendar, 'friendly_name') or calendar }}.
{% set s_date = (start_date | as_datetime).date() %}
{% set e_date = (end_date | as_datetime).date() %}
{% set diff_days = (e_date - s_date).days %}
{% if diff_days <= 1 %}
Event created: {{ summary }} (all day on {{ s_date }}) in {{ state_attr(calendar, 'friendly_name') or calendar }}.
{% else %}
Event created: {{ summary }} ({{ s_date }} to {{ (e_date - timedelta(days=1)) }}) in {{ state_attr(calendar, 'friendly_name') or calendar }}.
{% endif %}
- stop: ""
response_variable: response
default:
Expand Down
5 changes: 2 additions & 3 deletions date_lookup_and_conversion_full_llm.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ blueprint:
text:
multiline: true
default: |-
Date (YYYY-MM-DD). If no year, use current
Date (YYYY-MM-DD). Optional, defaults to today if omitted.
leap_month_prompt:
name: Leap Month Prompt
description: Indicates whether the Lunar date is in a leap month, determined by the AI
Expand All @@ -69,7 +69,7 @@ mode: parallel
max_exceeded: silent
description: Converts dates between Solar and Lunar calendars
variables:
version: 20260409
version: 20260821
fields:
conversion_type:
name: Conversion Type
Expand All @@ -85,7 +85,6 @@ fields:
description: !input date_prompt
selector:
date:
required: true
leap_month:
name: Leap Month
description: !input leap_month_prompt
Expand Down
Loading