Изначально была мысль повысить доступность openHAB средствами виртуализации. Ставим два гипервизора, настраиваем High availability, при отказе хоста виртуалка с openHAB перезапустится на соседнем сервере. И все бы ничего, но для работы HA нужно общее хранилище. Какой-то NAS допустим у меня есть, но выход его из строя даже более вероятен, чем отказ хоста. А городить что-то на DRBD или подобном не хотелось. Поэтому было решено кластеризовать openHAB другим способом, см. рисунок ниже. 

Идея

Разворачиваются две виртуалки. Также можно использовать физические машины, разные малинки и т.п. В качестве дистрибутива я использовал CentOS 9 Stream, но это не принципиально. Настраиваем keepalived для перекидывания IP-адреса с одной машины на другую.  Настраиваем lsyncd для синхронизации данных openHAB, поднимаем mosquitto и, кажется, все. Теперь подробнее.

Установка openHAB

Процесс установки описан тут - https://www.openhab.org/docs/installation/linux.html.

Если вкратце, то для CentOS 9 Stream создаем файл /etc/yum.repos.d/openhab.repo 
С таким содержимым: 


[openHAB-Stable]  
name=openHAB Stable  
baseurl=https://openhab.jfrog.io/artifactory/openhab-linuxpkg-rpm/stable  
gpgcheck=1  
gpgkey="https://openhab.jfrog.io/artifactory/api/gpg/key/public"  
enabled=1

Затем делаем:

# dnf update

# dnf install openhab

# dnf install openhab‑addons

# dnf install java-17-openjdk

Если есть другие инсталляции java, то их нужно удалить, например: 
# dnf remove java-11-openjdk 

Либо запустить команду: 

# alternatives --config java 
И выбрать 17ю версию. 
Запускаем и добавляем в автозагрузку:

#dnf systemctl start openhab 

#dnf systemctl enable openhab 

Интерфейс будет доступен по адресу http://IP:8080 

При первом запуске нужно создать учетную запись администратора и пройти небольшой мастер установки. 

Установка и настройка keepalived 

На обоих серверах пропишем имена и адреса в файл /etc/hosts 

10.20.10.41 srv-oh-01
10.20.10.42 srv-oh-02

Теперь нужно установить и настроить VRRP на обоих нодах: 

# dnf install keepalived  

Вот такой конфигурационный файл получился/etc/keepalived/keepalived.conf:

Hidden text

vrrp_instance failover_oh {  
state BACKUP  
interface ens192  
virtual_router_id 10  
priority 100  
advert_int 1  
preempt_delay 30  
authentication {  
auth_type AH  
auth_pass active-pass  
}  
notify /etc/keepalived/oh.sh  
 
unicast_peer {  
   10.20.10.42  
}  
  virtual_ipaddress {  
       10.20.10.40 dev ens192 label ens192:vip   
  }  
}
 

На обоих нодах конфигурация одинакова, за исключением unicast_peer, на втором сервере, он будет 10.20.10.41. 

Прошу заметить, что на обоих серверах прописано “state BACKUP”, а приоритет тоже одинаков. Это делает ноды равнозначными и какой сервер раньше загрузился, тот и будет мастером, до момента отказа. 

Кроме переключения IP-адреса мы так же выполняем notify-скрипт, который на самом деле запускает и останавливает openHAB, чтобы он не обращался ко всяким внешним биндингам (например Telegram) с двух нод одновременно, вот этот файл: 

#!/bin/bash  
TYPE=$1  
NAME=$2  
STATE=$3  
 
case $STATE in  
       "MASTER") systemctl start openhab  
                 ;;  
       "BACKUP") systemctl stop openhab  
                 ;;  
       "FAULT")  systemctl stop openhab  
                 exit 0  
                 ;;  
       *)        /usr/bin/logger "oh unknown state"  
                 exit 1  
                 ;;  
esac
  

Запускаем и добавляем в автозапуск keepalived 

# systemctl start keepalived
# systemctl enable keepalived

Можно запустить на обоих нодах: 

# journalctl -af 
И посмотреть, что будет в логах при start/stop keepalived на каждой ноде: 

Hidden text

Jan 24 11:32:15 srv‑oh-01 Keepalived_vrrp[924]: (failover_oh) Backup received priority 0 advertisement
Jan 24 11:32:15 srv‑oh-01 Keepalived_vrrp[924]: (failover_oh) Receive advertisement timeout
Jan 24 11:32:15 srv‑oh-01 Keepalived_vrrp[924]: (failover_oh) Entering MASTER STATE
Jan 24 11:32:15 srv‑oh-01 Keepalived_vrrp[924]: (failover_oh) setting VIPs.
Jan 24 11:32:15 srv‑oh-01 Keepalived_vrrp[924]: (failover_oh) Sending/queueing gratuitous ARPs on ens192 for 10.20.10.40 
Jan 24 11:32:15 srv‑oh-01 Keepalived_vrrp[924]: Sending gratuitous ARP on ens192 for 10.20.10.40 
Jan 24 11:32:15 srv‑oh-01 Keepalived_vrrp[924]: Sending gratuitous ARP on ens192 for 10.20.10.40 
Jan 24 11:32:15 srv‑oh-01 Keepalived_vrrp[924]: Sending gratuitous ARP on ens192 for 10.20.10.40 
Jan 24 11:32:15 srv‑oh-01 Keepalived_vrrp[924]: Sending gratuitous ARP on ens192 for 10.20.10.40 
Jan 24 11:32:15 srv‑oh-01 Keepalived_vrrp[924]: Sending gratuitous ARP on ens192 for 10.20.10.40 
Jan 24 11:32:15 srv‑oh-01 systemd[1]: Started openHAB — empowering the smart home.
Jan 24 11:32:20 srv‑oh-01 Keepalived_vrrp[924]: (failover_oh) Sending/queueing gratuitous ARPs on ens192 for 10.20.10.40 
Jan 24 11:32:20 srv‑oh-01 Keepalived_vrrp[924]: Sending gratuitous ARP on ens192 for 10.20.10.40 
Jan 24 11:32:20 srv‑oh-01 Keepalived_vrrp[924]: Sending gratuitous ARP on ens192 for 10.20.10.40 
Jan 24 11:32:20 srv‑oh-01 Keepalived_vrrp[924]: Sending gratuitous ARP on ens192 for 10.20.10.40 
Jan 24 11:32:20 srv‑oh-01 Keepalived_vrrp[924]: Sending gratuitous ARP on ens192 for 10.20.10.40 
Jan 24 11:32:20 srv‑oh-01 Keepalived_vrrp[924]: Sending gratuitous ARP on ens192 for 10.20.10.40

Я остановил keepalived на srv-oh-02, теперь первый стал мастером, установился vIP (10.20.10.40), отправились ARP-пакеты, чтобы побыстрее обучить коммутатор и запустился openHAB. 

Итак половина задачи решена, IP переезжает, сервис запускается где нужно. Теперь надо синхронизировать данные. 

Установка и настройка lsyncd 

В openHAB конфиги лежат в /etc/openhab, а также две базы - rrd4 (где хранятся метрики) и jsondb (где хранятся так называемые семантические элементы). Для синхронизации этих данных будем использовать lsyncd, который позволяет (при помощи rsync) сихронизировать файлы сразу после их создания или изменения, причем в обе стороны, т.е. сервер где модификация произошла позже, считается источником. 

Для работы lsyncd надо сгенерировать ключи SSH, на одном из серверов, например на 1-м делаем: 

# ssh-keygen
# ssh-copy-id srv-oh-02

Первая команда сгенерирует закрытый и публичный ключ, вторая скопирует публичный ключ на удаленный сервер, теперь на него можно заходить без пароля. Такую же процедуру нужно провезти на 2-м сервере, я просто скопировал этот же ключ в .ssh/authorized_keys 

Теперь установим lsyncd на оба сервера: 

# dnf install lsync 

Напишем конфигурационный файл /etc/lsyncd.conf, на первом сервере он будет такой: 

Hidden text

settings {  
       logfile = "/var/log/lsyncd/lsyncd.log",  
       statusFile = "/var/log/lsyncd/lsyncd.status",  
       statusInterval = 1,  
       nodaemon = true,  
       insist = true  
}  
sync {  
       default.rsync,  
       source = "/etc/openhab/",  
       target = "srv-oh-02:/etc/openhab",  
       delete = 'running',  
       --delay = 5,  
       rsync = {  
               -- timeout = 3000,  
               update = true,  
               _extra={"--temp-dir=/temp-lsync/"},  
               times = true,  
               archive = true,  
               compress = true,  
               perms = true,  
               acls = true,  
               owner = true,  
               verbose = true  
       }  
}  
sync {  
       default.rsync,  
       source = "/var/lib/openhab/persistence",  
       target = "srv-oh-02:/var/lib/openhab/persistence",  
       delete = 'running',  
       --delay = 5,  
       rsync = {  
               -- timeout = 3000,  
               update = true,  
               _extra={"--temp-dir=/temp-lsync/"},  
               times = true,  
               archive = true,  
               compress = true,  
               perms = true,  
               acls = true,  
               owner = true,  
               verbose = true  
       }  
}  
sync {  
       default.rsync,  
       source = "/var/lib/openhab/jsondb",  
       target = "srv-oh-02:/var/lib/openhab/jsondb",  
       delete = 'running',  
       --delay = 5,  
       rsync = {  
               -- timeout = 3000,  
               update = true,  
               _extra={"--temp-dir=/temp-lsync/"},  
               times = true,  
               archive = true,  
               compress = true,  
               perms = true,  
               acls = true,  
               owner = true,  
               verbose = true  
       }  

Каждая секция sync настраивается отдельно. 

На втором сервере конфигурация такая же, только в target’ах надо изменить имя сервера на srv-oh-01. Еще нужно на обоих нодах создать директорию /temp-lsync, для хранения временных данных. 

Запускаем его и добавляем в автозагрузку на обоих нодах: 

# systemctl start lsyncd
# systemctl enable lsyncd

Логи можно смотреть так:
# tail -f /var/log/lsyncd/lsyncd.log 

Hidden text

Jan 24 11:32:10 srv-oh-02 lsyncd[857]: 11:32:10 Normal: Calling rsync with filter-list of new/modified files/dirs  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_Kitchen_Gas.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/gGas.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/gTemperature.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_Kitchen_Motion.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_Kitchen_Button_1.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_Kitchen_Water_2.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_Kitchen_Shutter_3.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_Kitchen_Water_1.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_Kitchen_Shutter_2.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_Kitchen_Shutter_1.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_FamilyRoom_Temperature.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_FamilyRoom_Shutter_1.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/gWater.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_FamilyRoom_Humidity.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/Security.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/OU_Toilet_Light.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/gLight.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/OU_Temperature.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_Kitchen_Door_1.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_FamilyRoom_Light.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_Kitchen_Light_2.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_Kitchen_Light_1.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/gShutter.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_FamilyRoom_Gas.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/gMotion.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/gWindow.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_Kitchen_Window_1.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_FamilyRoom_Motion.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_Kitchen_Temperature.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_FamilyRoom_Shutter_4.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_FamilyRoom_Shutter_3.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/GF_FamilyRoom_Shutter_2.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/gHumidity.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/gDoor.rrd  
Jan 24 11:32:10 srv-oh-02 lsyncd[857]: /rrd4j/Day.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: sending incremental file list  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/Day.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_FamilyRoom_Gas.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_FamilyRoom_Humidity.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_FamilyRoom_Light.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_FamilyRoom_Motion.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_FamilyRoom_Shutter_1.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_FamilyRoom_Shutter_2.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_FamilyRoom_Shutter_3.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_FamilyRoom_Shutter_4.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_FamilyRoom_Temperature.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_Kitchen_Button_1.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_Kitchen_Door_1.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_Kitchen_Gas.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_Kitchen_Light_1.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_Kitchen_Light_2.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_Kitchen_Motion.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_Kitchen_Shutter_1.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_Kitchen_Shutter_2.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_Kitchen_Shutter_3.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_Kitchen_Temperature.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_Kitchen_Water_1.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_Kitchen_Water_2.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/GF_Kitchen_Window_1.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/OU_Temperature.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/OU_Toilet_Light.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/Security.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/gDoor.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/gGas.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/gHumidity.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/gLight.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/gMotion.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/gShutter.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/gTemperature.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/gWater.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: rrd4j/gWindow.rrd  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: sent 12,743 bytes  received 161,256 bytes  115,999.33 bytes/sec  
Jan 24 11:32:11 srv-oh-02 lsyncd[1753681]: total size is 20,477,492  speedup is 117.69  Jan 24 11:32:11 srv-oh-02 lsyncd[857]: 11:32:11 Normal: Finished a list after exitcode: 0

Установка и настройка MQTT-брокера

я выбрал один из популярных брокеров - Mosquitto.  

Установка: 

# dnf install epel-release
# dnf install mosquitto 

В конфигурационный файл (/etc/mosquitto/mosquitto.conf) нужно добавить password_file, чтобы получилось так:

listener 1883 
log_type all 
log_dest file /var/log/mosquitto/mosquitto.log
log_type all
password_file /etc/mosquitto/users.txt
 

Создаем пользователя openhab: 

# mosquitto_passwd -c /etc/mosquitto/users.txt openhab

Остальные пользователи добавляются так: 

# mosquitto_passwd -b /etc/mosquitto/users.txt user1 password 
установим права на файл: 

# chmod 644 /etc/mosquitto/users.txt 

Подробности по управлению пользователями тут - https://mosquitto.org/man/mosquitto_passwd-1.html 

Запускаем и добавляем его в автозапуск: 

# systemctl start mosquitto
# systemctl enable mosquitto

По аналогии устанавливаем mosquitto на второй сервер.

Устанавливаем MQTT Binding в openHAB

Заходим на веб-интерфейс и идем в Add-on Store->Bindings->MQTT Binding, жмем Install. Подключаем MQTT bridge сдедующим образом: Settings->Things-> жмем СИНИЙ ПЛЮС->MQTT Binding-> MQTT Broker.

Заполняем поля:

Unique ID (Должен сгенерироваться автоматически, но можно и самому придумать);
Label;
Location;
Broker Hostname/IP;

Устанавливаем галочку “Show advanced” и далее заполняем:
Username;
Password;
После чего жмем “Create Thing"

В списке Things должен появиться MQTT Broker и статус должен стать Online.

Жмем опять СИНИЙ ПЛЮС, выбираем MQTT Binding и затем Generic MQTT Thing.

Тут выбираем Bridge который добавили ранее и жмем “Create Thing”. Вот что должно получиться в результате. 

Добавим канал. Жмем на появившийся Generic MQTT Thing и переходим во вкладку Channels

Теперь нажимаем "Add Channel"

Например, нам надо добавить канал для температуры в кухне, заполняем Channel Identifier (надо придумать), Label, можно еще указать Description, теперь выбираем тип “Number”, откроются дополнительные поля: 

Тут заполняем “MQTT State Topic”, ставим галочку “Show advanced” 

Устанавливаем единицы измерения - градус Цельсия.

А также желаемый формат вывода, так будет выводиться точность до десятых градуса. Жмем “Create”

Предположим, у нас уже есть созданный Item такого плана: 

Number   GF_Kitchen_Temperature  "Температура [%.1f]%unit%"    <temperature>    (GF_Kitchen, gTemperature)    ["Temperature"] 

Тогда жмем на создавшейся канал, теперь на маленький зеленый плюсик “Add link to Item”, откроется такое окошко: 

Тут можно создать новый Item, но у нас он уже существует, поэтому жмем ”Item to Link”, выбираем из списка нужный и жмем “Link”

Все, теперь если кто-то отправил в канал oh/kitchen/temp значения температуры, то openHAB его оттуда возьмет. Получится вот такой график.

MQTT Explorer как инструмент отладки

Однако у нас пока нет настроенного оборудования, которое бы это делало, поэтому предлагаю проверить работу при помощи MQTT Explorer, устанавливаем отсюда - http://mqtt-explorer.com/ 

Подключаемся и можем читать/писать топики.

У меня была мысль поставить EMQX и настроить кластерный MQTT, или поднять mosquitto в режиме моста и как-то синхронизировать два сервера. Но оказалось, что данных репликации openHAB  через lsyncd достаточно. Топики быстро переписываются и хранить данные на обоих MQTT-брокерах не обязательно, но можно. 

Заключение

Вот таким образом удалось кластеризовать openHAB. В следующей статье мы соберем модуль умного дома на Arduino, подключим Ethernet, подключимся к MQTT-брокеру и сможем отправлять/получать данные, управлять реле и т.п.

Комментарии (9)


  1. GennPen
    02.04.2024 08:08

    И все бы ничего, но для работы HA нужно общее хранилище.

    Не обязательно, можно настроить например репликацию раз в N минут. Но лучше всего использовать Ceph Storage.


    1. Speccyfan Автор
      02.04.2024 08:08

      С реепликацией я игрался, работает, но не все так просто, надо понимать, что упал сервер на котором работала основная копия и что нужно запустить реплику на соседнем сервере. Т.е. все должно отработать автоматически. Ну а Ceph у меня негде развернуть, используются два гипервизора, по одному SSD-диску в каждом. Да и я бы его не выбрал для такой задачи никогда.


  1. t3hk0d3
    02.04.2024 08:08

    Спасибо за статью!

    Небольшая просьба - убрать дампы конфигов в спойлер или ссылкой на gist


    1. Speccyfan Автор
      02.04.2024 08:08

      убрал в спойлер


  1. vazir
    02.04.2024 08:08

    А почему он должен падать? Может неправильный выбор системы автоматизации просто?


    1. Speccyfan Автор
      02.04.2024 08:08

      Обычный физический отказ сервера.


    1. t3hk0d3
      02.04.2024 08:08
      +1

      На самом деле довольно неприятное явление. У меня умный дом на Home Assistant-e. Весь свет в доме контролируется через реле Shelly, либо через ZigBee контроллеры светодиодных лент.

      Некоторые переключатели "отвязаны" от реле, и просто являются триггером для автоматизации в Home Assistant.

      Плюс куча переключателей которые работают по Zigbee, и это работает только через HA.

      Однажды у меня сдохла малинка на которой это все крутится - по какой-то причине случился USB undervoltage (судя по логам), и система подвисла.

      Пока я был на работе, домашние не очень обрадовались что некоторые выключатели перестали работать, либо надо бегать и "вручную" выключать свет на этажах (на лестнице стоят ZB-кнопки которые выключают свет на всем этаже).

      Проблему я впоследствии решил с помощью USB-хаба с внешним питанием, но осадочек остался.


      1. vazir
        02.04.2024 08:08

        Ну, от этого никто не застрахован. Кстати, зигби временами (от поддержки в прошивке устройств зависит) позволяет привязать друг-к-другу - тогда будут работать и без ХА и без координатора, если слышат друг друга (например пары кнопка икея+лампа так связаны и продавались парами), но это усложняет сетап, и появляется резонное замечание - чем гибче тем больше зависимости от "ядра". У меня были похожие "моменты" - но как ИМХО - критического ничего нет. Простой потребитель - да будет говорить "фи". Малинка - постоянно ругается на undervolt - но работает без нареканий. Хотя запитана 5ти амперным БП. Мне не нравится малинка, потому воткнул в конце себе Beelink N100. Потому следуем универсальным правилам... Там где можно планируем провода, потом уже радио, где радио делим от простого к сложному, зигби в приоритете, где невозможно там уже wifi. Как говорится your mileage may vary. И... проще относиться главное. Чем сложнее система тем более вероятны неучтенчики


        1. t3hk0d3
          02.04.2024 08:08

          Я просто хотел подчеркнуть что фактор hardware-отказа для домашней автоматизации очень даже реальный и неприятный (но не критичный).

          У меня нет задачи построить пуленепробиваемую SLO=99.9999% систему.

          Тут скорее речь не про надежность, а про resilience системы.

          стати, зигби временами (от поддержки в прошивке устройств зависит) позволяет привязать друг-к-другу - тогда будут работать и без ХА и без координатора, если слышат друг друга (например пары кнопка икея+лампа так связаны и продавались парами)

          у меня настроен Touchlink для некоторых вещей, но обычно он работает нормально только в рамках одного производителя (IKEA). С китайским ZigBee-устройствами вероятность фейла стремится к единице.

          Малинка - постоянно ругается на undervolt - но работает без нареканий. Хотя запитана 5ти амперным БП.

          У меня тоже, и обычно ничего не происходит, либо устройство просто перезагружается с kernel-panic-ом. Но тут редкий случай - оно тупо зависло, и пришлось сделать power-reset. Возможно проблема была в чем-то другом, но ругань на undervoltage была последней записью в логах.

          Я решил проблему USB-хабом с внешним питанием + питанием по PoE (можно дернуть ресет через UI свича удаленно).

          Там где можно планируем провода, потом уже радио, где радио делим от простого к сложному, зигби в приоритете, где невозможно там уже wifi.

          Абсолютно согласен, придерживаюсь той-же идеологии.