Home Assistant: различия между версиями

Материал из noname.com.ua
Перейти к навигацииПерейти к поиску
 
(не показаны 23 промежуточные версии этого же участника)
Строка 3: Строка 3:
 
[[Категория:MQTT]]
 
[[Категория:MQTT]]
 
[[Категория:Zigbee2MQTT]]
 
[[Категория:Zigbee2MQTT]]
  +
[[Категория:Draft]]
 
=Home Assistant=
 
=Home Assistant=
 
Пока это заготовка статьи про домашнюю автоматизацию и реализацию некоторых фич
 
Пока это заготовка статьи про домашнюю автоматизацию и реализацию некоторых фич
Строка 21: Строка 22:
   
 
Сразу сохранить, в открытом виде он показывается один раз
 
Сразу сохранить, в открытом виде он показывается один раз
  +
  +
=<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>
  +
* Пример
  +
ключи без -
   
 
=Ссылки=
 
=Ссылки=
Строка 282: Строка 444:
 
value_template: "{{ states('alarm_control_panel.home') == 'armed_away' }}"
 
value_template: "{{ states('alarm_control_panel.home') == 'armed_away' }}"
 
</PRE>
 
</PRE>
=== variables ==
+
=== variables ===
 
* <code> variables:</code>
 
* <code> variables:</code>
 
* <code> from: "{{ trigger.from_state.state if trigger.from_state is not none else 'none' }}}}"</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>
 
* <code> to: "{{{{ trigger.to_state.state if trigger.to_state is not none else 'none' }}}}"</code>
  +
=== actions ==
 
  +
=== actions ===
 
* <code> action:</code>
 
* <code> action:</code>
 
==== choose ====
 
==== choose ====
Строка 394: Строка 557:
 
* <code> level: info</code>
 
* <code> level: info</code>
 
* <code> message: "[door] SKIPPED: conditions not met ({{ from }} → {{ to }})"</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

  1. Профиль (снизу справа)
  2. Безопасность
  3. Долгосрочные токены доступа

HA-Create-Token-250926125120.png

Токен выглядит как-то так

eyJhbGciOiJIUzI1NiIsInR5cCI6Ikp <пропущенно-много-букав> sImlhdCI6MTcyMTkwNzUzNywiZXhwIjoyMDM3MjY3NTM3fQ.YDLTNoOFebK4BVHFo-V1q7a84Cs78Z0b3H2e-F5mBpk"

Сразу сохранить, в открытом виде он показывается один раз

Zigbee2Mqtt

Важнейший компонент


Первое что нужно сделать - мониторит подключенные устройства
Очень неприятно если какая-то автоматизация отвалится когда устройство ушло в off-line

Icon-caution.gif

  • Конфиг исправлять ТОЛЬКО при выключенном процессе
  • ВСЕГДА иметь бекап - изменение Network Key потребует перепривязывание всех устройств что здорово выбесит
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

  • Пример

ключи без -

Ссылки


Пока что тут в основном ссылки


  • Прошивки

Zigbee2Tasmota

Прошивки

Термины и понятия

Когда что использовать

  • Срабатывание по условию -> 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"

Что бы запустить скрипт можно добавить кнопку

Настройки панели --> добавить карточку (справа внизу) --> Объект (что бы вписать вкод вручную)

HA-add-button-250923154324.png

HA-add-button- 250923154402.png

HA-button-250923154153.png

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

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.log
  • data:
  • name: "door_automation"
  • entity_id: sensor.sonoff_external_door_sensor_battery
  • 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)"

Устранение дребезга

  • 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/… ) — дам точный вариант вставки.