Skip to content

Instantly share code, notes, and snippets.

@smirnowegor
Last active December 16, 2025 13:53
Show Gist options
  • Select an option

  • Save smirnowegor/4756a2a63bace39aa2ae163094d4ecaa to your computer and use it in GitHub Desktop.

Select an option

Save smirnowegor/4756a2a63bace39aa2ae163094d4ecaa to your computer and use it in GitHub Desktop.
blueprint:
name: Умный полив (Todoist Official) + Имя датчика
description: >
Управляет задачами через интеграцию Todo List.
Гарантирует отсутствие дублей за счет очистки имени от пробелов.
1. Сухо -> Создает задачу (если её еще нет).
2. Влажно -> Удаляет задачу (если она есть).
3. Изменение -> Обновляет описание существующей задачи.
domain: automation
input:
binary_sensor:
name: Бинарный сенсор (Требуется полив)
description: Сенсор должен быть ON, когда сухо.
selector:
entity:
domain: binary_sensor
humidity_sensor:
name: Датчик влажности (%)
description: Добавляет текущий % влажности в описание.
selector:
entity:
domain: sensor
last_watering_helper:
name: Helper даты последнего полива
description: Сущность input_datetime для записи времени полива.
selector:
entity:
domain: input_datetime
todo_list:
name: Список задач Todoist
description: Сущность todo.* (например, todo.todoist_tasks).
selector:
entity:
domain: todo
task_name:
name: Название задачи
description: Уникальное имя. (Пробелы в начале и конце будут удалены автоматически).
default: "Полить цветок"
force_remove_threshold:
name: Порог влажности для удаления (%)
description: Если влажность выше этого уровня — задача удаляется (страховка).
default: 95
selector:
number:
min: 0
max: 100
unit_of_measurement: "%"
mode: single
max_exceeded: silent
trigger:
- platform: state
entity_id: !input binary_sensor
to: null
- platform: state
entity_id: !input humidity_sensor
to: null
action:
# ------------------------------------------------------------------
# 1. ПОДГОТОВКА ПЕРЕМЕННЫХ
# ------------------------------------------------------------------
- variables:
binary_entity: !input binary_sensor
sensor_entity: !input humidity_sensor
helper_entity: !input last_watering_helper
todo_entity: !input todo_list
raw_name: !input task_name
threshold: !input force_remove_threshold
# --- ЗАЩИТА ОТ ДУБЛЕЙ ---
# Удаляем пробелы в начале и конце имени, чтобы сравнение было точным
name: "{{ raw_name | trim }}"
# Имя датчика
sensor_name: >-
{{ state_attr(sensor_entity, 'friendly_name')
| default('Цветочный датчик') }}
# Состояния
is_dry: "{{ is_state(binary_entity, 'on') }}"
hum_state: "{{ states(sensor_entity) }}"
# Округляем до целого (int), чтобы игнорировать мелкий шум (13.1% -> 13.2%)
hum_val: "{{ hum_state | float(0) | int if is_number(hum_state) else 0 }}"
tomorrow: "{{ (now() + timedelta(days=1)).strftime('%Y-%m-%d') }}"
last_watered_raw: "{{ states(helper_entity) }}"
last_watered_fmt: >-
{% if last_watered_raw in ['unknown', 'unavailable', 'None', ''] %}
Неизвестно
{% else %}
{{ as_timestamp(last_watered_raw) | timestamp_custom('%d.%m %H:%M', true) }}
{% endif %}
# Описание задачи
desc: "🌿 Датчик: {{ sensor_name }}\n💧 Влажность: {{ hum_val }}% | 🕒 Был полит: {{ last_watered_fmt }}"
# Условие "Полито": Бинарный выкл ИЛИ Влажность > порога
is_wet: "{{ not is_dry or hum_val > (threshold | float(95)) }}"
# ------------------------------------------------------------------
# 2. ПОЛУЧЕНИЕ ДАННЫХ ИЗ TODOIST
# ------------------------------------------------------------------
- delay: "00:00:02" # Ждем синхронизации
- service: todo.get_items
target:
entity_id: "{{ todo_entity }}"
data:
status: needs_action
response_variable: todo_response
- variables:
all_items: "{{ todo_response[todo_entity]['items'] }}"
# --- УЛУЧШЕННЫЙ ПОИСК ЗАДАЧИ ---
# Ищем задачу, сравнивая имена без учета пробелов
found_task: >-
{% set clean_target = name | trim %}
{% set ns = namespace(found=none) %}
{% for task in all_items %}
{% if task.summary | trim == clean_target %}
{% set ns.found = task %}
{% endif %}
{% endfor %}
{{ ns.found }}
found_uid: "{{ found_task.uid if found_task else none }}"
current_desc: "{{ found_task.description if found_task else '' }}"
task_exists: "{{ found_uid is not none }}"
# ------------------------------------------------------------------
# 3. ЛОГИКА (Choose)
# ------------------------------------------------------------------
- choose:
# А) УДАЛЕНИЕ (Влажно + Задача найдена)
- conditions:
- condition: template
value_template: "{{ is_wet }}"
- condition: template
value_template: "{{ task_exists }}"
sequence:
- service: todo.remove_item
target:
entity_id: "{{ todo_entity }}"
data:
item: "{{ found_uid }}"
- service: input_datetime.set_datetime
target:
entity_id: "{{ helper_entity }}"
data:
timestamp: "{{ now().timestamp() }}"
- service: logbook.log
data:
name: "Smart Irrigation"
message: "Полито ({{ sensor_name }}). Задача удалена."
# Б) СОЗДАНИЕ (Сухо + Задачи НЕТ)
- conditions:
- condition: template
value_template: "{{ is_dry }}"
- condition: template
value_template: "{{ not task_exists }}"
sequence:
- service: todo.add_item
target:
entity_id: "{{ todo_entity }}"
data:
item: "{{ name }}"
description: "{{ desc }}"
due_date: "{{ tomorrow }}"
# В) ОБНОВЛЕНИЕ (Сухо + Задача ЕСТЬ)
- conditions:
- condition: template
value_template: "{{ is_dry }}"
- condition: template
value_template: "{{ task_exists }}"
# Обновляем только если описание реально изменилось
- condition: template
value_template: "{{ current_desc != desc }}"
sequence:
- service: todo.update_item
target:
entity_id: "{{ todo_entity }}"
data:
item: "{{ found_uid }}"
description: "{{ desc }}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment