Last active
December 16, 2025 13:53
-
-
Save smirnowegor/4756a2a63bace39aa2ae163094d4ecaa to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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