Home Assistant: различия между версиями
Sirmax (обсуждение | вклад) |
Sirmax (обсуждение | вклад) |
||
| (не показано 55 промежуточных версий этого же участника) | |||
| Строка 1: | Строка 1: | ||
[[Категория:Home Assistant]] |
[[Категория:Home Assistant]] |
||
[[Категория:zigbee]] |
[[Категория:zigbee]] |
||
| + | [[Категория:MQTT]] |
||
| + | [[Категория:Zigbee2MQTT]] |
||
| + | [[Категория:Draft]] |
||
=Home Assistant= |
=Home Assistant= |
||
Пока это заготовка статьи про домашнюю автоматизацию и реализацию некоторых фич |
Пока это заготовка статьи про домашнюю автоматизацию и реализацию некоторых фич |
||
| + | |||
| + | =Прежде чем начать= |
||
| + | Для удобства работы (что б меньше возиться c UI) удобно выпустить токен и читать данные через API |
||
| + | <BR> |
||
| + | # Профиль (снизу справа) |
||
| + | # Безопасность |
||
| + | # Долгосрочные токены доступа |
||
| + | |||
| + | [[Файл:HA-Create-Token-250926125120.png|400px]] |
||
| + | |||
| + | Токен выглядит как-то так |
||
| + | <PRE> |
||
| + | eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp <пропущенно-много-букав> sImlhdCI6MTcyMTkwNzUzNywiZXhwIjoyMDM3MjY3NTM3fQ.YDLTNoOFebK4BVHFo-V1q7a84Cs78Z0b3H2e-F5mBpk" |
||
| + | </PRE> |
||
| + | |||
| + | Сразу сохранить, в открытом виде он показывается один раз |
||
| + | |||
| + | =<code>Zigbee2Mqtt</code>= |
||
| + | Важнейший компонент |
||
| + | <BR> |
||
| + | * Служит бриджом между MQTT (откуда читает команды) и устройсвами ZigBee |
||
| + | * Для подключения к ZigBee нужен адаптер который может быть USB или в сети (у меня - в сети https://noname.com.ua/mediawiki/index.php/Zigbee_Sonoff_Zigbee_Bridge_pro) |
||
| + | <BR> |
||
| + | Первое что нужно сделать - мониторит подключенные устройства |
||
| + | <BR> |
||
| + | Очень неприятно если какая-то автоматизация отвалится когда устройство ушло в off-line |
||
| + | <BR> |
||
| + | |||
| + | {{caution|text= |
||
| + | * Конфиг исправлять '''ТОЛЬКО''' при выключенном процессе |
||
| + | * '''ВСЕГДА''' иметь бекап - изменение Network Key потребует перепривязывание всех устройств что здорово выбесит |
||
| + | }} |
||
| + | <PRE> |
||
| + | homeassistant: |
||
| + | enabled: true |
||
| + | legacy_action_sensor: false |
||
| + | <PRE> |
||
| + | Этот шаг нужен (как минимум на сегодня) что бы отправлять данные которые считаются диагностическими (по умолчанию это не делается) |
||
| + | <PRE> |
||
| + | device_options: |
||
| + | homeassistant: |
||
| + | linkquality: |
||
| + | enabled_by_default: true |
||
| + | last_seen: |
||
| + | enabled_by_default: true |
||
| + | voltage: |
||
| + | enabled_by_default: true |
||
| + | current: |
||
| + | enabled_by_default: true |
||
| + | power: |
||
| + | enabled_by_default: true |
||
| + | energy: |
||
| + | enabled_by_default: true |
||
| + | battery_low: |
||
| + | enabled_by_default: true |
||
| + | entity_category: diagnostic |
||
| + | </PRE> |
||
| + | <PRE> |
||
| + | timestamp_format: YYYY-MM-DD HH:mm:ss |
||
| + | </PRE> |
||
| + | Отправлять доступность устройств - иначе не ясно будет как давно устройство "пропало" |
||
| + | <PRE> |
||
| + | availability: |
||
| + | enabled: true |
||
| + | </PRE> |
||
| + | |||
| + | Можно еще так |
||
| + | <PRE> |
||
| + | device_options: |
||
| + | homeassistant: |
||
| + | linkquality: |
||
| + | expire_after: 3600 |
||
| + | </PRE> |
||
| + | |||
| + | ==Настройка в HA== |
||
| + | |||
| + | Далее через UI HA сделать панель |
||
| + | * настройка -> панели -> новая панель (синяя кнопка внизу справа). |
||
| + | |||
| + | Когда панель добавлена |
||
| + | * Перейти в панель |
||
| + | * Справа вверху - редактировать |
||
| + | * Три точки справа вверху - выбрать текстовый редактор |
||
| + | Код панели: |
||
| + | <PRE> |
||
| + | views: |
||
| + | - title: Статус Zigbee |
||
| + | sections: |
||
| + | - type: grid |
||
| + | cards: |
||
| + | - type: heading |
||
| + | heading: Статус Zigbee |
||
| + | - type: markdown |
||
| + | content: >- |
||
| + | {% set devs = states.sensor |
||
| + | | selectattr('entity_id','search','_linkquality$') | list %} |
||
| + | {% set off = devs | selectattr('state','eq','unavailable') | list |
||
| + | %} **Всего:** {{ devs | length }} | **Онлайн:** {{ (devs | length) |
||
| + | - (off | length) }} | **Офлайн:** {{ off | length }} |
||
| + | - type: custom:auto-entities |
||
| + | card: |
||
| + | type: entities |
||
| + | title: Zigbee — OFFLINE |
||
| + | show_header_toggle: false |
||
| + | filter: |
||
| + | include: |
||
| + | - entity_id: sensor.*_linkquality |
||
| + | state: unavailable |
||
| + | sort: |
||
| + | method: name |
||
| + | show_empty: false |
||
| + | - type: custom:auto-entities |
||
| + | card: |
||
| + | type: entities |
||
| + | title: Zigbee — все устройства |
||
| + | show_header_toggle: false |
||
| + | filter: |
||
| + | include: |
||
| + | - entity_id: sensor.*_linkquality |
||
| + | sort: |
||
| + | method: name |
||
| + | </PRE> |
||
| + | |||
| + | =Разделение на файлы= |
||
| + | |||
| + | что list, что mapping |
||
| + | |||
| + | ==<code>automation:</code>== |
||
| + | список <code>!include_dir_merge_list</code>\ |
||
| + | * <code>automation: !include_dir_merge_list automations/</code> |
||
| + | * Пример: <code>automations/kitchen/kitchen_dishwasher.yaml</code> |
||
| + | <PRE> |
||
| + | - id: kitchen_dishwasher_is_on |
||
| + | alias: "kitchen DishWasher is on" |
||
| + | description: Тостер на кухне включен |
||
| + | trigger: |
||
| + | - platform: state |
||
| + | entity_id: |
||
| + | - binary_sensor.kitchen_dishwahser_power_on_off_sensor |
||
| + | from: 'off' |
||
| + | to: 'on' |
||
| + | condition: |
||
| + | action: |
||
| + | - service: notify.chat |
||
| + | data: |
||
| + | message: | |
||
| + | 🟢 🍽 ️🫧 Посудомойка Включена {{ now().strftime('%H:%M:%S') }} |
||
| + | </PRE> |
||
| + | |||
| + | ==<code>scene:</code>== |
||
| + | список <code>!include_dir_merge_list</code> |
||
| + | ** Пример |
||
| + | каждая сцена — с - |
||
| + | ==<code>template:</code>== |
||
| + | список блоков <code>!include_dir_merge_list</code> |
||
| + | ** Пример |
||
| + | каждый блок — с -; внутри sensor:/binary_sensor: тоже списки с - |
||
| + | ==<code>sensor:</code>== |
||
| + | !include_dir_merge_list sensors/ |
||
| + | sensor: !include_dir_merge_list sensors/ |
||
| + | |||
| + | ==<code>script:</code>== |
||
| + | словарь <code>!include_dir_merge_named</code> |
||
| + | * Пример |
||
| + | ключи сценариев без - |
||
| + | ==<code>input_select:</code>== |
||
| + | словарь <code>!include_dir_merge_named</code> |
||
| + | * Пример |
||
| + | ключи без - |
||
| + | ==<code>input_boolean:</code>== |
||
| + | словарь <code>!include_dir_merge_named</code> |
||
| + | * Пример |
||
| + | ключи без - |
||
| + | ==<code>input_number:</code>== |
||
| + | словарь <code>!include_dir_merge_named</code> |
||
| + | * Пример |
||
| + | ключи без - |
||
| + | |||
| + | =Ссылки= |
||
<BR> |
<BR> |
||
Пока что тут в основном ссылки |
Пока что тут в основном ссылки |
||
| Строка 28: | Строка 210: | ||
=Термины и понятия= |
=Термины и понятия= |
||
| + | ==Когда что использовать== |
||
| − | ==Триггер== |
||
| − | Триггер — это событие, которое запускает автоматизацию само по себе: изменение состояния, время, нажатие кнопки input_button, приход webhook и т.д. |
||
| − | ==Скрипт== |
||
| − | Сценарий (script) триггера не имеет — он запускается вручную (кнопкой в UI, из другой автоматизации, по голосу и т.п.). |
||
| + | * Срабатывание по условию -> automation (с trigger описывающим условие) |
||
| − | ==Пример скрипта== |
||
| + | * Если automation сложный, то код можно разбить на несколько скриптов |
||
| + | |||
| + | automation = логика запуска + условия + действия; |
||
| + | |||
| + | ==automation== |
||
| + | Automation — правило “если-то”: |
||
| + | <PRE> |
||
| + | automation: |
||
| + | - alias: Door opened → notify |
||
| + | trigger: |
||
| + | - platform: state |
||
| + | entity_id: binary_sensor.external_door |
||
| + | from: 'off' |
||
| + | to: 'on' |
||
| + | condition: [] |
||
| + | action: |
||
| + | - service: notify.chat |
||
| + | data: {message: "Дверь открыта"} |
||
| + | </PRE> |
||
| + | ==script== |
||
| + | |||
| + | Script — именованная последовательность action (шагов). <BR> |
||
| + | Не имеет триггера, запускается вручную (кнопкой/сервисы) или из automation. <BR> |
||
| + | |||
| + | |||
| + | Скрипт можно так же рассматривть как процедуру (для группировки и переиспользования кода) |
||
| + | <PRE> |
||
| + | script: |
||
| + | send_door_alert: |
||
| + | alias: Send door alert |
||
| + | sequence: |
||
| + | - service: notify.chat |
||
| + | data: {message: "Дверь открыта"} |
||
| + | </PRE> |
||
| + | |||
| + | Вызов из automation: |
||
| + | <PRE> |
||
| + | action: |
||
| + | - service: script.send_door_alert |
||
| + | </PRE> |
||
| + | |||
| + | ===Пример скрипта=== |
||
Помещать в файл <code>scripts.yaml</code> или любой другой определенный в <code>script: !include scripts.yaml</code> |
Помещать в файл <code>scripts.yaml</code> или любой другой определенный в <code>script: !include scripts.yaml</code> |
||
<PRE> |
<PRE> |
||
| Строка 73: | Строка 294: | ||
show_state: false |
show_state: false |
||
</PRE> |
</PRE> |
||
| + | |||
| + | ==trigger== |
||
| + | |||
| + | Trigger — часть automation. Это событие, которое запускает automation: смена состояния, время, MQTT-сообщение, вебхук, нажатие кнопки и т.д. |
||
| + | Сам по себе trigger вне automation не существует. |
||
| + | |||
| + | Примеры триггеров: |
||
| + | |||
| + | state (изменение состояния сущности) |
||
| + | time / time_pattern |
||
| + | event / webhook |
||
| + | mqtt |
||
| + | device (из интеграций) |
||
| + | numeric_state (порог) |
||
| + | |||
| + | |||
| + | script = только действия; |
||
| + | |||
| + | trigger = причина старта automation. |
||
| + | |||
| + | =Разбор примера автоматизации= |
||
| + | <PRE> |
||
| + | - alias: external_door_open_logged |
||
| + | description: "Открытие Внешней Двери (с логированием)" |
||
| + | mode: parallel |
||
| + | trigger: |
||
| + | - platform: state |
||
| + | entity_id: binary_sensor.sonoff_external_door_sensor_contact # твоя сущность |
||
| + | from: 'off' |
||
| + | to: 'on' |
||
| + | variables: |
||
| + | from: "{{ trigger.from_state.state if trigger.from_state is not none else 'none' }}" |
||
| + | to: "{{ trigger.to_state.state if trigger.to_state is not none else 'none' }}" |
||
| + | action: |
||
| + | - choose: |
||
| + | - conditions: [] # сюда твои прежние условия (если были) |
||
| + | sequence: |
||
| + | - service: logbook.log |
||
| + | data: |
||
| + | name: "door_automation" |
||
| + | entity_id: binary_sensor.external_door |
||
| + | message: "TRIGGERED ({{ from }} → {{ to }})" |
||
| + | - service: system_log.write |
||
| + | data: |
||
| + | logger: automation.door |
||
| + | level: info |
||
| + | message: "[door] sending notify ({{ from }} → {{ to }})" |
||
| + | - service: system_log.write |
||
| + | data: |
||
| + | logger: automation.door |
||
| + | level: info |
||
| + | message: "[door] notify SENT" |
||
| + | default: |
||
| + | - service: system_log.write |
||
| + | data: |
||
| + | logger: automation.door |
||
| + | level: info |
||
| + | message: "[door] SKIPPED: conditions not met ({{ from }} → {{ to }})" |
||
| + | </PRE> |
||
| + | |||
| + | == mode == |
||
| + | * <code>alias: external_door_open_logged</code> По этом |
||
| + | * <code> description: "Открытие Внешней Двери (с логированием)"</code> |
||
| + | * <code> mode: parallel</code> Режим выполнения автоматики при повторном запуске до завершения предыдущего |
||
| + | ** single — новый запуск игнорируется. |
||
| + | ** restart — оборвать текущий, начать заново. |
||
| + | ** queued — поставить в очередь (можно max). |
||
| + | ** parallel — запустить ещё один экземпляр параллельно. |
||
| + | Тут я хочу запускать автоматизацию не зависимо от того есть ли уже запущенная -> <code> parallel</code> |
||
| + | |||
| + | == trigger == |
||
| + | * <code> trigger:</code> - начало секции триггеров |
||
| + | === platform === |
||
| + | * <code> - platform: state</code> |
||
| + | |||
| + | основные платформы триггеров |
||
| + | |||
| + | Состояния/шаблоны |
||
| + | |||
| + | * state — смена состояния сущности. |
||
| + | * numeric_state — пороги (above/below) для числовых значений/атрибутов. |
||
| + | * template — когда Jinja-шаблон стал true. |
||
| + | |||
| + | Время |
||
| + | |||
| + | * time — в заданный момент (at: "08:30:00"). |
||
| + | * time_pattern — по шаблону, типа cron (minutes: "/5"). |
||
| + | * calendar — начало/конец события календаря. |
||
| + | |||
| + | Астрономия |
||
| + | * sun — рассвет/закат (+ оффсеты). |
||
| + | * zone — вход/выход из зоны (для device_tracker/person). |
||
| + | * geo_location — объекты geo_location (например, оповещения о землетрясениях). |
||
| + | |||
| + | События/внешние источники |
||
| + | * event — любое событие шины HA (например, telegram_command). |
||
| + | * homeassistant — события ядра (start, shutdown, т.п.). |
||
| + | * webhook — входящий вебхук. |
||
| + | * mqtt — сообщение в топике MQTT. |
||
| + | * tag — скан NFC-тега. |
||
| + | * device — триггеры, определяемые конкретной интеграцией/устройством (кнопки, клики, движения и т.д.). |
||
| + | |||
| + | === entity_id === |
||
| + | |||
| + | * <code> entity_id: binary_sensor.sonoff_external_door_sensor_contact</code> Какой именно сенсор брать |
||
| + | * <code> from: 'off'</code> переход из состояния |
||
| + | * <code> to: 'on'</code> в состояние |
||
| + | <BR> |
||
| + | Тут можно указать только одно - тогда например будет срабатывать при переходе их unknown |
||
| + | |||
| + | === condition === |
||
| + | * <code> condition: </code> (на уровне с trigger) |
||
| + | Дополнительные условия ограничивающие срабатывания |
||
| + | <BR> |
||
| + | ** Временное окно: |
||
| + | <PRE> |
||
| + | condition: |
||
| + | - condition: time |
||
| + | after: "08:00:00" |
||
| + | before: "23:00:00" |
||
| + | </PRE> |
||
| + | |||
| + | ** Только когда нет дома |
||
| + | <PRE> |
||
| + | condition: |
||
| + | - condition: state |
||
| + | entity_id: person.max |
||
| + | state: not_home |
||
| + | </PRE> |
||
| + | ** Только в темноте (через 30 минут после захода солнца): |
||
| + | <PRE> |
||
| + | condition: |
||
| + | - condition: sun |
||
| + | after: sunset |
||
| + | after_offset: "-00:30:00" |
||
| + | </PRE> |
||
| + | |||
| + | ** Батарея датчика > 10% (если конечно такой датчик есть) |
||
| + | <PRE> |
||
| + | condition: |
||
| + | - condition: numeric_state |
||
| + | entity_id: sensor.sonoff_external_door_sensor_battery |
||
| + | above: 10 |
||
| + | </PRE> |
||
| + | Шаблон (кастомная логика): |
||
| + | <PRE> |
||
| + | condition: |
||
| + | - condition: template |
||
| + | value_template: "{{ states('alarm_control_panel.home') == 'armed_away' }}" |
||
| + | </PRE> |
||
| + | === variables === |
||
| + | * <code> variables:</code> |
||
| + | * <code> from: "{{ trigger.from_state.state if trigger.from_state is not none else 'none' }}}}"</code> |
||
| + | * <code> to: "{{{{ trigger.to_state.state if trigger.to_state is not none else 'none' }}}}"</code> |
||
| + | |||
| + | === actions === |
||
| + | * <code> action:</code> |
||
| + | ==== choose ==== |
||
| + | choose не обязателен. Это просто “ветвление” внутри action (как if / elif / else): |
||
| + | |||
| + | проверяет наборы conditions; |
||
| + | |||
| + | выполняет первую подходящую sequence; |
||
| + | |||
| + | если ни одна не подошла — выполняет default (если есть). |
||
| + | |||
| + | Когда нужен: |
||
| + | |||
| + | разные действия при разных условиях; |
||
| + | |||
| + | нужно сделать fallback (например, залогировать «пропущено»), даже если условия не прошли. |
||
| + | |||
| + | Когда не нужен: |
||
| + | |||
| + | одно действие без условий → вызывай сервис напрямую. |
||
| + | |||
| + | Примеры |
||
| + | |||
| + | 1) Без условий (тебе хватит этого): |
||
| + | |||
| + | action: |
||
| + | - service: notify.chat |
||
| + | data: |
||
| + | message: "Дверь открыта" |
||
| + | |||
| + | |||
| + | 2) Условие “сверху” (без choose): |
||
| + | |||
| + | condition: |
||
| + | - condition: time |
||
| + | after: "08:00:00" |
||
| + | before: "23:00:00" |
||
| + | action: |
||
| + | - service: notify.chat |
||
| + | data: |
||
| + | message: "Дверь открыта" |
||
| + | |||
| + | |||
| + | Минус: если условие не прошло — ничего не выполнится (и ты не залогируешь «пропущено»). |
||
| + | |||
| + | 3) Ветвление с choose (и default): |
||
| + | |||
| + | action: |
||
| + | - choose: |
||
| + | - conditions: |
||
| + | - condition: sun |
||
| + | after: sunset |
||
| + | sequence: |
||
| + | - service: notify.chat |
||
| + | data: {message: "Дверь открыта (ночью)"} |
||
| + | default: |
||
| + | - service: notify.chat |
||
| + | data: {message: "Дверь открыта (днём)"} |
||
| + | |||
| + | |||
| + | 4) Логировать “пропущено” (то, ради чего я предлагал choose): |
||
| + | |||
| + | action: |
||
| + | - choose: |
||
| + | - conditions: |
||
| + | - condition: time |
||
| + | after: "08:00:00" |
||
| + | before: "23:00:00" |
||
| + | sequence: |
||
| + | - service: notify.chat |
||
| + | data: {message: "Дверь открыта"} |
||
| + | default: |
||
| + | - service: system_log.write |
||
| + | data: |
||
| + | logger: automation.door |
||
| + | level: info |
||
| + | message: "[door] SKIPPED: conditions not met" |
||
| + | |||
| + | |||
| + | * <code> - choose:</code> |
||
| + | * <code> - conditions: []</code> |
||
| + | * <code> sequence:</code> |
||
| + | Запись в лог датчика |
||
| + | * <code> - service: logbook.log</code> |
||
| + | * <code> data:</code> |
||
| + | * <code> name: "door_automation"</code> |
||
| + | * <code> entity_id: sensor.sonoff_external_door_sensor_battery</code> |
||
| + | * <code> message: "TRIGGERED ({{ from }} → {{ to }})"</code> |
||
| + | |||
| + | Запись в системный лог |
||
| + | * <code> - service: system_log.write</code> Запись в системнвй лог |
||
| + | * <code> data:</code> |
||
| + | * <code> logger: automation.door</code> |
||
| + | * <code> level: info</code> Уровень логгирования |
||
| + | * <code> message: "[door] sending notify ({{ from }} → {{ to }})"</code> текст сообщения |
||
| + | |||
| + | * <code> - service: system_log.write</code> |
||
| + | * <code> data:</code> |
||
| + | * <code> logger: automation.door</code> |
||
| + | * <code> level: info</code> |
||
| + | * <code> message: "[door] notify SENT"</code> |
||
| + | |||
| + | * <code> default:</code> |
||
| + | * <code> - service: system_log.write</code> |
||
| + | * <code> data:</code> |
||
| + | * <code> logger: automation.door</code> |
||
| + | * <code> level: info</code> |
||
| + | * <code> message: "[door] SKIPPED: conditions not met ({{ from }} → {{ to }})"</code> |
||
| + | |||
| + | =Устранение дребезга= |
||
| + | |||
| + | * delay_on |
||
| + | * delay_off |
||
| + | |||
| + | |||
| + | в определении binary_sensor (например, template / mqtt / zha через template-обёртку). |
||
| + | |||
| + | Что делают: |
||
| + | |||
| + | delay_on — переводит сенсор в on только если условие держалось всё это время. |
||
| + | |||
| + | delay_off — аналогично для перехода в off. |
||
| + | |||
| + | Зачем: «приглушить» дребезг на уровне сущности — все автоматизации и UI увидят уже устоявшееся состояние (короткие всплески не попадут в историю/логбук). |
||
| + | |||
| + | Пример (template binary_sensor): |
||
| + | |||
| + | template: |
||
| + | - binary_sensor: |
||
| + | - name: tea_kettle_kitchen_on_off_sensor |
||
| + | device_class: power |
||
| + | state: "{{ (states('sensor.kettle_power')|float(0)) > 500 }}" |
||
| + | delay_on: "00:00:05" # нужно 5 с непрерывно >500 Вт |
||
| + | delay_off: "00:00:10" # и 10 с непрерывно ≤500 Вт, чтобы погасить |
||
| + | |||
| + | |||
| + | (Формат длительности: "HH:MM:SS" или блоком seconds: 5.) |
||
| + | |||
| + | for: — в триггере автоматизации |
||
| + | |||
| + | Где: в trigger конкретной automation. |
||
| + | |||
| + | Что делает: автоматизация сработает только если целевое состояние держится указанное время. На саму сущность/историю не влияет — только на эту автоматизацию. |
||
| + | |||
| + | Пример: |
||
| + | |||
| + | automation: |
||
| + | - alias: external_door_open_logged |
||
| + | trigger: |
||
| + | - platform: state |
||
| + | entity_id: binary_sensor.external_door |
||
| + | from: 'off' |
||
| + | to: 'on' |
||
| + | for: "00:00:02" # дверь должна быть открыта ≥2 с |
||
| + | action: |
||
| + | - service: notify.chat |
||
| + | data: {message: "Дверь открыта"} |
||
| + | |||
| + | |||
| + | for: также работает с numeric_state, template и др. триггерами. |
||
| + | |||
| + | Когда что использовать |
||
| + | |||
| + | Хотите «успокоить» сам сенсор для всего (UI, истории, всех автоматизаций) → delay_on/off в сущности. |
||
| + | |||
| + | Нужна задержка только для конкретной реакции → for: в триггере. |
||
| + | |||
| + | Можно комбинировать: небольшой delay_on/off для сглаживания + for: в важной автоматизации. |
||
| + | |||
| + | Если покажешь конкретный тип сенсора/конфиг (template/mqtt/… ) — дам точный вариант вставки. |
||
Текущая версия на 12:09, 3 октября 2025
Home Assistant
Пока это заготовка статьи про домашнюю автоматизацию и реализацию некоторых фич
Прежде чем начать
Для удобства работы (что б меньше возиться c UI) удобно выпустить токен и читать данные через API
- Профиль (снизу справа)
- Безопасность
- Долгосрочные токены доступа
Токен выглядит как-то так
eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp <пропущенно-много-букав> sImlhdCI6MTcyMTkwNzUzNywiZXhwIjoyMDM3MjY3NTM3fQ.YDLTNoOFebK4BVHFo-V1q7a84Cs78Z0b3H2e-F5mBpk"
Сразу сохранить, в открытом виде он показывается один раз
Zigbee2Mqtt
Важнейший компонент
- Служит бриджом между MQTT (откуда читает команды) и устройсвами ZigBee
- Для подключения к ZigBee нужен адаптер который может быть USB или в сети (у меня - в сети https://noname.com.ua/mediawiki/index.php/Zigbee_Sonoff_Zigbee_Bridge_pro)
Первое что нужно сделать - мониторит подключенные устройства
Очень неприятно если какая-то автоматизация отвалится когда устройство ушло в off-line
|
homeassistant:
enabled: true
legacy_action_sensor: false
<PRE>
Этот шаг нужен (как минимум на сегодня) что бы отправлять данные которые считаются диагностическими (по умолчанию это не делается)
<PRE>
device_options:
homeassistant:
linkquality:
enabled_by_default: true
last_seen:
enabled_by_default: true
voltage:
enabled_by_default: true
current:
enabled_by_default: true
power:
enabled_by_default: true
energy:
enabled_by_default: true
battery_low:
enabled_by_default: true
entity_category: diagnostic
timestamp_format: YYYY-MM-DD HH:mm:ss
Отправлять доступность устройств - иначе не ясно будет как давно устройство "пропало"
availability: enabled: true
Можно еще так
device_options:
homeassistant:
linkquality:
expire_after: 3600
Настройка в HA
Далее через UI HA сделать панель
- настройка -> панели -> новая панель (синяя кнопка внизу справа).
Когда панель добавлена
- Перейти в панель
- Справа вверху - редактировать
- Три точки справа вверху - выбрать текстовый редактор
Код панели:
views:
- title: Статус Zigbee
sections:
- type: grid
cards:
- type: heading
heading: Статус Zigbee
- type: markdown
content: >-
{% set devs = states.sensor
| selectattr('entity_id','search','_linkquality$') | list %}
{% set off = devs | selectattr('state','eq','unavailable') | list
%} **Всего:** {{ devs | length }} | **Онлайн:** {{ (devs | length)
- (off | length) }} | **Офлайн:** {{ off | length }}
- type: custom:auto-entities
card:
type: entities
title: Zigbee — OFFLINE
show_header_toggle: false
filter:
include:
- entity_id: sensor.*_linkquality
state: unavailable
sort:
method: name
show_empty: false
- type: custom:auto-entities
card:
type: entities
title: Zigbee — все устройства
show_header_toggle: false
filter:
include:
- entity_id: sensor.*_linkquality
sort:
method: name
Разделение на файлы
что list, что mapping
automation:
список !include_dir_merge_list\
automation: !include_dir_merge_list automations/- Пример:
automations/kitchen/kitchen_dishwasher.yaml
- id: kitchen_dishwasher_is_on
alias: "kitchen DishWasher is on"
description: Тостер на кухне включен
trigger:
- platform: state
entity_id:
- binary_sensor.kitchen_dishwahser_power_on_off_sensor
from: 'off'
to: 'on'
condition:
action:
- service: notify.chat
data:
message: |
🟢 🍽 ️🫧 Посудомойка Включена {{ now().strftime('%H:%M:%S') }}
scene:
список !include_dir_merge_list
- Пример
каждая сцена — с -
template:
список блоков !include_dir_merge_list
- Пример
каждый блок — с -; внутри sensor:/binary_sensor: тоже списки с -
sensor:
!include_dir_merge_list sensors/
sensor: !include_dir_merge_list sensors/
script:
словарь !include_dir_merge_named
- Пример
ключи сценариев без -
input_select:
словарь !include_dir_merge_named
- Пример
ключи без -
input_boolean:
словарь !include_dir_merge_named
- Пример
ключи без -
input_number:
словарь !include_dir_merge_named
- Пример
ключи без -
Ссылки
Пока что тут в основном ссылки
- WebOS : https://www.home-assistant.io/integrations/webostv/
- ModKam Реле https://www.youtube.com/watch?v=u3zDXNGVbgo
- (рус) Базовая установка в контейнерах https://habr.com/ru/articles/731110/
- (рус) Тут кой-какие примеры ручного добавления в конфиги - https://sprut.ai/article/home-assistant-statya-3-dobavlyaem-ustroystva (но качество статьи спорное)
- Прошивки
Zigbee2Tasmota
- Тут вроде бы должно быть описание как интегрироваться с ХА ноя ничего не понял https://thehelpfulidiot.com/how-to-use-zigbee2tasmota-with-home-assistant
Прошивки
- Tasmota https://zigbee.blakadder.com/Sonoff_ZBBridge-P.html
- Еще одна инструкция по прошивке бриджа https://dialedin.com.au/blog/sonoff-zbbridge-p-setup
- Ещ инструкция (по-моему самая полная и правильная) https://notenoughtech.com/home-automation/tasmota-on-sonoff-zb-bridge-pro/#flash
Термины и понятия
Когда что использовать
- Срабатывание по условию -> automation (с trigger описывающим условие)
- Если automation сложный, то код можно разбить на несколько скриптов
automation = логика запуска + условия + действия;
automation
Automation — правило “если-то”:
automation:
- alias: Door opened → notify
trigger:
- platform: state
entity_id: binary_sensor.external_door
from: 'off'
to: 'on'
condition: []
action:
- service: notify.chat
data: {message: "Дверь открыта"}
script
Script — именованная последовательность action (шагов).
Не имеет триггера, запускается вручную (кнопкой/сервисы) или из automation.
Скрипт можно так же рассматривть как процедуру (для группировки и переиспользования кода)
script:
send_door_alert:
alias: Send door alert
sequence:
- service: notify.chat
data: {message: "Дверь открыта"}
Вызов из automation:
action: - service: script.send_door_alert
Пример скрипта
Помещать в файл scripts.yaml или любой другой определенный в script: !include scripts.yaml
tv_living_room_wol:
alias: "TV Living Room: Power On (WOL)"
sequence:
- service: wake_on_lan.send_magic_packet
data:
mac: "38:8c:50:00:a3:14"
Что бы запустить скрипт можно добавить кнопку
Настройки панели --> добавить карточку (справа внизу) --> Объект (что бы вписать вкод вручную)
type: button
name: Включить ТВ
icon: mdi:television
tap_action:
action: call-service
service: script.turn_on
target:
entity_id: script.tv_living_room_wol
hold_action:
action: none
double_tap_action:
action: none
show_state: false
trigger
Trigger — часть automation. Это событие, которое запускает automation: смена состояния, время, MQTT-сообщение, вебхук, нажатие кнопки и т.д. Сам по себе trigger вне automation не существует.
Примеры триггеров:
state (изменение состояния сущности) time / time_pattern event / webhook mqtt device (из интеграций) numeric_state (порог)
script = только действия;
trigger = причина старта automation.
Разбор примера автоматизации
- alias: external_door_open_logged
description: "Открытие Внешней Двери (с логированием)"
mode: parallel
trigger:
- platform: state
entity_id: binary_sensor.sonoff_external_door_sensor_contact # твоя сущность
from: 'off'
to: 'on'
variables:
from: "{{ trigger.from_state.state if trigger.from_state is not none else 'none' }}"
to: "{{ trigger.to_state.state if trigger.to_state is not none else 'none' }}"
action:
- choose:
- conditions: [] # сюда твои прежние условия (если были)
sequence:
- service: logbook.log
data:
name: "door_automation"
entity_id: binary_sensor.external_door
message: "TRIGGERED ({{ from }} → {{ to }})"
- service: system_log.write
data:
logger: automation.door
level: info
message: "[door] sending notify ({{ from }} → {{ to }})"
- service: system_log.write
data:
logger: automation.door
level: info
message: "[door] notify SENT"
default:
- service: system_log.write
data:
logger: automation.door
level: info
message: "[door] SKIPPED: conditions not met ({{ from }} → {{ to }})"
mode
alias: external_door_open_loggedПо этомdescription: "Открытие Внешней Двери (с логированием)"mode: parallelРежим выполнения автоматики при повторном запуске до завершения предыдущего- single — новый запуск игнорируется.
- restart — оборвать текущий, начать заново.
- queued — поставить в очередь (можно max).
- parallel — запустить ещё один экземпляр параллельно.
Тут я хочу запускать автоматизацию не зависимо от того есть ли уже запущенная -> parallel
trigger
trigger:- начало секции триггеров
platform
- platform: state
основные платформы триггеров
Состояния/шаблоны
- state — смена состояния сущности.
- numeric_state — пороги (above/below) для числовых значений/атрибутов.
- template — когда Jinja-шаблон стал true.
Время
- time — в заданный момент (at: "08:30:00").
- time_pattern — по шаблону, типа cron (minutes: "/5").
- calendar — начало/конец события календаря.
Астрономия
- sun — рассвет/закат (+ оффсеты).
- zone — вход/выход из зоны (для device_tracker/person).
- geo_location — объекты geo_location (например, оповещения о землетрясениях).
События/внешние источники
- event — любое событие шины HA (например, telegram_command).
- homeassistant — события ядра (start, shutdown, т.п.).
- webhook — входящий вебхук.
- mqtt — сообщение в топике MQTT.
- tag — скан NFC-тега.
- device — триггеры, определяемые конкретной интеграцией/устройством (кнопки, клики, движения и т.д.).
entity_id
entity_id: binary_sensor.sonoff_external_door_sensor_contactКакой именно сенсор братьfrom: 'off'переход из состоянияto: 'on'в состояние
Тут можно указать только одно - тогда например будет срабатывать при переходе их unknown
condition
condition:(на уровне с trigger)
Дополнительные условия ограничивающие срабатывания
- Временное окно:
condition:
- condition: time
after: "08:00:00"
before: "23:00:00"
- Только когда нет дома
condition:
- condition: state
entity_id: person.max
state: not_home
- Только в темноте (через 30 минут после захода солнца):
condition:
- condition: sun
after: sunset
after_offset: "-00:30:00"
- Батарея датчика > 10% (если конечно такой датчик есть)
condition:
- condition: numeric_state
entity_id: sensor.sonoff_external_door_sensor_battery
above: 10
Шаблон (кастомная логика):
condition:
- condition: template
value_template: "{{ states('alarm_control_panel.home') == 'armed_away' }}"
variables
variables:from: "Шаблон:Trigger.from state.state if trigger.from state is not none else 'none'}}"to: "{{{{ trigger.to_state.state if trigger.to_state is not none else 'none' }}}}"
actions
action:
choose
choose не обязателен. Это просто “ветвление” внутри action (как if / elif / else):
проверяет наборы conditions;
выполняет первую подходящую sequence;
если ни одна не подошла — выполняет default (если есть).
Когда нужен:
разные действия при разных условиях;
нужно сделать fallback (например, залогировать «пропущено»), даже если условия не прошли.
Когда не нужен:
одно действие без условий → вызывай сервис напрямую.
Примеры
1) Без условий (тебе хватит этого):
action:
- service: notify.chat
data:
message: "Дверь открыта"
2) Условие “сверху” (без choose):
condition:
- condition: time after: "08:00:00" before: "23:00:00"
action:
- service: notify.chat
data:
message: "Дверь открыта"
Минус: если условие не прошло — ничего не выполнится (и ты не залогируешь «пропущено»).
3) Ветвление с choose (и default):
action:
- choose:
- conditions:
- condition: sun
after: sunset
sequence:
- service: notify.chat
data: {message: "Дверь открыта (ночью)"}
default:
- service: notify.chat
data: {message: "Дверь открыта (днём)"}
4) Логировать “пропущено” (то, ради чего я предлагал choose):
action:
- choose:
- conditions:
- condition: time
after: "08:00:00"
before: "23:00:00"
sequence:
- service: notify.chat
data: {message: "Дверь открыта"}
default:
- service: system_log.write
data:
logger: automation.door
level: info
message: "[door] SKIPPED: conditions not met"
- choose:- conditions: []sequence:
Запись в лог датчика
- service: logbook.logdata:name: "door_automation"entity_id: sensor.sonoff_external_door_sensor_batterymessage: "TRIGGERED (Шаблон:From → Шаблон:To)"
Запись в системный лог
- service: system_log.writeЗапись в системнвй логdata:logger: automation.doorlevel: infoУровень логгированияmessage: "[door] sending notify (Шаблон:From → Шаблон:To)"текст сообщения
- service: system_log.writedata:logger: automation.doorlevel: infomessage: "[door] notify SENT"
default:- service: system_log.writedata:logger: automation.doorlevel: infomessage: "[door] SKIPPED: conditions not met (Шаблон:From → Шаблон:To)"
Устранение дребезга
- delay_on
- delay_off
в определении binary_sensor (например, template / mqtt / zha через template-обёртку).
Что делают:
delay_on — переводит сенсор в on только если условие держалось всё это время.
delay_off — аналогично для перехода в off.
Зачем: «приглушить» дребезг на уровне сущности — все автоматизации и UI увидят уже устоявшееся состояние (короткие всплески не попадут в историю/логбук).
Пример (template binary_sensor):
template:
- binary_sensor:
- name: tea_kettle_kitchen_on_off_sensor
device_class: power
state: "Шаблон:(states('sensor.kettle power')"
delay_on: "00:00:05" # нужно 5 с непрерывно >500 Вт
delay_off: "00:00:10" # и 10 с непрерывно ≤500 Вт, чтобы погасить
(Формат длительности: "HH:MM:SS" или блоком seconds: 5.)
for: — в триггере автоматизации
Где: в trigger конкретной automation.
Что делает: автоматизация сработает только если целевое состояние держится указанное время. На саму сущность/историю не влияет — только на эту автоматизацию.
Пример:
automation:
- alias: external_door_open_logged
trigger:
- platform: state
entity_id: binary_sensor.external_door
from: 'off'
to: 'on'
for: "00:00:02" # дверь должна быть открыта ≥2 с
action:
- service: notify.chat
data: {message: "Дверь открыта"}
for: также работает с numeric_state, template и др. триггерами.
Когда что использовать
Хотите «успокоить» сам сенсор для всего (UI, истории, всех автоматизаций) → delay_on/off в сущности.
Нужна задержка только для конкретной реакции → for: в триггере.
Можно комбинировать: небольшой delay_on/off для сглаживания + for: в важной автоматизации.
Если покажешь конкретный тип сенсора/конфиг (template/mqtt/… ) — дам точный вариант вставки.