SNMP в Home Assistant для определения дома/не дома

SNMP в Home Assistant для определения дома/не дома

Приветствую тебя, путник. Сегодня я поведаю о том, как настроить отслеживание присутствия средствами роутера.

Представь себе: ты возвращаешься домой после долгого путешествия, а твой умный дом уже знает, что ты здесь. Он включает свет в прихожей, подогревает чайник и ставит любимую музыку. Разве это не волшебство?

Но чтобы это всё заработало, тебе придётся приручить древнего и загадочного зверя — SNMP.

А если ты не хочешь связываться с этим таинственным существом и просто желаешь настроить определение дома/не дома, то рекомендую ознакомиться с этим обзорным видео:

Отслеживание местоположения телефона — обзор разных способов в Home Assistant
Отслеживание местоположения и присутствия в Home Assistant: трекинг телефона по Wi-Fi, определение дома/не дома, Home Assistant device_tracker, геолокация.Вк…

Либо можешь сразу переходить к настройке вот этой интеграции, если у тебя роутер под OpenWrt. Либо вот еще есть интеграция для Keenetic.

Предыстория

Но если без шуток, то в моём умном доме есть много решений, которые вызывают у людей вопрос: «Зачем ты сделал X, если проще было сделать Y?». Так обычно происходит потому, что:

  • Я предпочитаю гибкие конструкторы узкоспециализированным решениям;
  • Так исторически сложилось и переделывание не принесёт пользы.

И вот именно из-за этих причин я использую SNMP. У меня роутер на OpenWrt, и в Home Assistant для него есть аж две интеграции, которые могут отслеживать дома мой смартфон или нет (и, соответственно, дома ли я). Но эти интеграции мне не подходят. Вместо этого я настроил snmpd с кастомным скриптом, который определяет устройства, подключённые к Wi-Fi.

Вообще SNMP есть не только на OpenWrt, но и на многих других железках. Однако, прежде чем рассказывать про SNMP и настройку роутера, я хочу оправдаться пояснить, почему я использую своё решение, а не «стандартное» и «простое».

Так уж сложилось, что у моего первого роутера было всего 4 МБ флеш-памяти и мне приходилось пересобирать прошивку, избавляя её от ненужных пакетов. Первыми под нож я тогда пустил пакеты с веб-интерфейсом (LuCI). С тех пор я сменил несколько роутеров, но продолжаю пересобирать прошивку без LuCI и настраиваю OpenWrt исключительно через консоль по SSH.

Но загвоздка в том, что в Home Assistant одна из интеграций зависит от LuCI, а вторая требует установки веб-сервера uhttpd с модулем ubus.

Вот и получается, что «простое» решение предполагает установку дополнительных компонентов, которые потом нужно обновлять, мониторить, чинить и всячески обслуживать. И вот это «простое» решение уже не кажется таким уж простым. Ладно, хорошо, в случае с LuCI стоимость обслуживания практически нулевая, но я всегда стараюсь сначала прикинуть, сколько времени и сил уйдёт на поддержку, прежде чем что-то ставить. В контексте домашней инфраструктуры, для меня гораздо важнее простота обслуживания, а не простота внедрения. Я не хочу потом часами что-то чинить и исправлять.

Поэтому я воспользовался более гибким вариантом и настроил отслеживание присутствия по SNMP. Тем более, что SNMP я уже и так использовал для мониторинга некоторых своих железок:

snmpd неплохо так кастомизуруется, поэтому его можно легко переиспользовать и для других задач кроме мониторинга.

man smart-home
Раз уж я снова поднял тему отслеживания местоположения, то чтобы не было путаницы, хочу теперь всё структурировать и обобщить. А то у меня уже много постов по теме отслеживания, но даже я уже не всеми этими методами пользуюсь. А чем пользуюсь сейчас? Для отслеживания местоположения у меня настроен…

Я комбинирую отслеживание по SNMP с другими методами. Почитать про них можно в Telegram.

SNMP — что же это за зверь такой?

SNMP — это протокол для мониторинга роутеров, коммутаторов, принтеров, бесперебойников и прочего такого. В обычных домашних устройствах SNMP встречается редко, зато часто встроен в энтерпрайзное железо. Но если надо, то SNMP можно добавить практически к любому серверу или роутеру, просто установив на них mini-snmpd или snmpd.

Если мы говорим про мониторинг, то обычно нужно 2 компонента: агент (роутер) и какой-то центральный сервер, который подключается к агентам и собирает с них нужные метрики.

У каждой метрики есть свой идентификатор — OID. Например, чтобы получить load average, нужно прочитать метрику 1.3.6.1.4.1.2021.10.1.3.1 (или UCD-SNMP-MIB::laLoad.1), а 1.3.6.1.2.1.31.1.1.1.10.10 и 1.3.6.1.2.1.31.1.1.1.6.10 отвечают за количество байтов, которые были приняты и переданы через сетевой интерфейс роутера (10 в конце зависит от конкретного интерфейса).

Как это все можно применить в Home Assistant? Благодаря интеграции с SNMP можно собирать телеметрию и выводить её на панели мониторинга:

А ещё SNMP это не только про мониторинг, но и про управление устройствами. Например, через SNMP можно включать и выключать питание (PoE) на отдельных портах. Либо можно написать кастомный скрипт для snmpd, который, скажем, будет управлять VPN — запускать или останавливать его по запросу.

Короче говоря, SNMP можно использовать для самых разных задач, но в этой статье я сосредоточусь только на отслеживании присутствия в Home Assistant. Здесь есть два основных подхода:

  1. Мониторинг устройств в локальной сети, которые недавно были активны;
  2. Отслеживание смартфонов, подключённых к Wi-Fi.

Первый способ – самый простой, достаточно включить SNMP или поставить snmpd, но есть нюансы. Второй способ лучше, но провернуть такое получится далеко не с каждым роутером. Давайте разберём оба варианта по порядку.

Узнаем, кто дома, используя ARP

ARP-кэш — это внутренняя таблица роутера, куда он сохраняет пары IP ⭤ MAC, чтобы быстро находить устройства в локальной сети без лишних запросов. Кэш не резиновый, поэтому в нём хранятся записи только о тех устройствах, которые недавно были активны в сети. Эту особенность можно использовать для отслеживания того, дома ваш смартфон или нет.

Но прежде чем что-то настраивать, нужно предварительно включить SNMP на роутере. На разных роутерах это делается по-разному, но поищите в админке что-нибудь по ключевому слову «SNMP Agent» 🙂

Плюс нужно выключить рандомизацию MAC-адресов на смартфоне, чтобы потом его можно было однозначно идентифицировать. На разных телефонах эта фича называется по-разному, поищите в настройках что-нибудь из этого: «Использование частного адреса Wi-Fi», «Случайный MAC-адрес устройства», «Случайные аппаратные адреса».

Затем нужно настроить Home Assistant и добавить в configuration.yaml следующее:

device_tracker:
  - platform: snmp
    host: 192.168.1.1 # IP роутера
    community: public # по умолчанию обычно public
    baseoid: 1.3.6.1.2.1.4.22.1.2 # OID для получения ARP-таблицы

OID на разных роутерах тоже разный. Вот тут можно подсмотреть OID для своего роутера.

На этом, по сути, всё. После рестарта Home Assistant для каждого устройства в сети создастся объект device_tracker.<MAC-адрес>. Если устройство активно и находится в сети, его статус будет home, иначе — not_home.

Установка snmpd на OpenWrt

На роутерах с OpenWrt поддержка SNMP по умолчанию отсутствует. Но это не проблема — snmpd можно установить парой команд:

opgk update
opkg install snmpd

Чтобы запустить:

/etc/init.d/snmpd start
/etc/init.d/snmpd enable

Если хотите проверить, что все работает, то можете попробовать выполнить на домашнем сервере следующую команду:

snmpwalk -v2c -c public 192.168.1.1 1.3.6.1.2.1.4.22.1.2

Если snmpwalk отсутствует, то: apt install snmp или dnf install net-snmp-utils-1.

По умолчанию snmpd предоставляет доступ ко всем метрикам, что не выглядит безопасно. Хотя фаервол и закрывает порт SNMP от внешнего мира, мне такая вольность всё равно не по душе. Поэтому я отредактировал /etc/config/snmpd, ограничив доступ только к необходимым метрикам, а также заменил стандартный community public на свой — hass.

config agent
	option agentaddress UDP:161,UDP6:161

config com2sec hass
	option secname hasssec
	option source default # замените default на IPv4-адрес домашнего сервера, если хотите ограничить доступ по IP
	option community hass

config com2sec6 hass6
	option secname hasssec
	option source default # замените default на IPv6-адрес домашнего сервера, если хотите ограничить доступ по IP
	option community hass

config group hass_v1
	option group hassgroup
	option version v1
	option secname hasssec

config group hass_v2c
	option group hassgroup
	option version v2c
	option secname hasssec

config view hassview_arpcache
	option viewname hassview
	option type included
	option oid .1.3.6.1.2.1.4.22 # доступ к ARP-кэшу

config view hassview_scripts
	option viewname hassview
	option type included
	option oid .1.3.6.1.4.1.8072.1.3.2 # доступ к кастомным скриптам — об этом чуть ниже

config access hassgroup_access_hassview
	option group hassgroup # для группы hass
	option context none
	option version any
	option level noauth
	option prefix exact
	option read hassview # доступ к перечисленным метрикам
	option write none
	option notify none

# строчки ниже я оставил как есть
config engineid
	option engineidtype '3'
	option engineidnic 'eth0'

config snmpd general
	option enabled '1'

После изменения конфига нужно перезапустить snmpd и настроить device tracker в Home Assistant:

device_tracker:
  - platform: snmp
    host: 192.168.1.1 # IP роутера
    community: hass # вместо public теперь hass
    baseoid: 1.3.6.1.2.1.4.22.1.2

Узнаём, кто дома, по смартфонам, подключенным к Wi-Fi

У отслеживания через ARP-кэш есть один серьёзный минус — ложные срабатывания. Я столкнулся с проблемами на собственном опыте:

  • Если смартфон подключён к Wi-Fi, но не передаёт данные, то роутер может удалить его из кэша. А дальше начинается веселье: Home Assistant решает, что я ушёл из дома, автоматически выключает свет и блокирует компьютер. Однажды такая подстава случилась прямо посреди видеозвонка 😅
  • Иногда, наоборот, запись в ARP-кэше может висеть слишком долго. Бывало, что автоматизации срабатывали только через час после того, как я уже ушёл из дома вместе со своим смартфоном.

Поэтому я всё переделал и решил, что лучше напрямую отслеживать подключён ли телефон к Wi-Fi точке доступа. Кто-то может спросить: «А зачем ты пудрил мозги своим ARP? Почему нельзя было сразу дать OID для отслеживания подключенных Wi-Fi-устройств???». Ответ прост — такого OID нет. Может, какие-то роутеры и умеют такое, но snmpd из репозиториев OpenWrt такой возможности не предоставляет.

Зато в snmpd можно добавлять свои OID, которые будут возвращать результат выполнения произвольного скрипта. Но прежде чем лезть в конфиг snmpd, нужно написать сам скрипт.

На OpenWrt для получения списка подключённых Wi-Fi-устройств нужно выполнить:

ubus call hostapd.wlan0 get_clients
ubus call hostapd.wlan1 get_clients # для 5 ГГц

Только если у вас такой команды нет, то предварительно нужно поставить пакет ubus:

opkg install ubus

Команда ubus возвращает результат в формате JSON, а нам нужен только список MAC-адресов. Чтобы вычленить нужные данные, понадобится распарсить JSON с помощью grep. В итоге получается вот такой скрипт:

#!/bin/sh

ubus -S call hostapd.wlan1 get_clients | grep -oE "([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}"

В принципе, скрипт можно было бы сохранить в отдельный файл, но зачем нам лишние телодвижения? 🙂 Давайте добавим его целиком в /etc/config/snmpd:

config extend
	option name	clients
	option prog	'/bin/sh -c "ubus -S call hostapd.wlan1 get_clients | exec grep -oE \"([0-9A-Fa-f]{2}:){5}[0-9A-Fa-f]{2}\""'

Осталось перезапустить snmpd и убедиться, что всё работает. Для этого выполните на домашнем сервере следующую команду:

snmpwalk -v2c -c hass 192.168.1.1 'NET-SNMP-EXTEND-MIB::nsExtendOutLine'

Если всё в порядке, в stdout выведется список Wi-Fi-клиентов.

Правда, для Home Assistant нужен числовой OID. Его можно получить вот так:

snmptranslate -On 'NET-SNMP-EXTEND-MIB::nsExtendOutLine."clients"'

Но вам эту команду выполнять не обязательно — у нас с вами OID будет одинаковый:
.1.3.6.1.4.1.8072.1.3.2.4.1.2.7.99.108.105.101.110.116.115. Остаётся прописать его в конфиг Home Assistant:

device_tracker:
  - platform: snmp
    host: 192.168.1.1
    community: hass
    baseoid: 1.3.6.1.4.1.8072.1.3.2.4.1.2.7.99.108.105.101.110.116.115
    interval_seconds: 20
    consider_home: 120

В итоге для каждого устройства, подключённого к Wi-Fi, будет создан свой device_tracker.

Правда, в текущей реализации есть небольшой нюанс. Скрипты, добавленные через extend, отдают MAC-адреса в строковом виде, но Home Assistant ожидает другой формат. В результате вместо реальных MAC-адресов в именах трекеров получается вот такая «каша»:device_tracker.61_36_3a_65_62_3a_62_36_3a_30_35_3a_65_35_6a_61_23.

Поэтому придется отключать смартфон от Wi-Fi и подключать его снова, чтобы отследить, какой device tracker связан с вашим смартфоном.

🧠
Вместо extend правильнее было бы использовать pass, который позволяет указать корректный тип данных. Но сделать скрипт для pass сложнее: нужно предусмотреть обработку getnext, иначе snmpwalk будет обрываться на середине и работать некорректно.

Заключение

SNMP + Home Assistant = 🔥 Получается гибкий конструктор, который подходит не только для отслеживания присутствия. В документации также есть примеры сенсоров для мониторинга load average, аптайма и даже для включения и выключения PoE.

Я использую SNMP и по прямому назначению: мониторю состояние роутера через Icinga. А на файловом сервере, например, отслеживаю состояние дисков с помощью mini-snmpd и всё той же Icinga.

В общем, надеюсь, статья оказалась полезной или хотя бы интересной 🙂

Была ли статья полезна?

Хотите сказать спасибо? Кофе автору — ваша благодарность.

На кофе
Подписка на новые статьи

Уведомления, как только в блоге появится что-нибудь интересненькое.

Подписываясь, вы даете согласие на обработку персональных данных.