Софтовый датчик присутствия на Linux AP + ESP8266

от автора

TL;DR

Наблюдение за изменением уровня Wi-Fi сигнала от стационарно расположенных по дому IoT устройств позволяет сделать полностью программный (выделенное железо отсутствует) обьемный датчик движения в квартире, достаточно точно показывающий наличие активно перемещающихся (фактически, не спящих) людей.

Предыстория

Есть обычная «квартира айтишника» с системой «умный дом» на базе Home Assistant:

  • Самодельные выключатели освещения на базе ESP8266 + MSP430

  • Несколько датчиков температуры/влажности, СО2 и качества воздуха.

  • Контроллер вентиляторов в ванной/туалете

  • пара Sonoff Mini для остального.

Общение девайсов между собой — по Wi-Fi + MQTT. Для минимизации влияния низкоскоростных ESP на «рабочую» Wi-Fi сеть — на отдельном Raspberry Pi 3 запущена отдельная Wi-Fi сеть для IoT, на базе стандартного hostapd. В сумме в IoT Wi-Fi сети — 12 устройств.

Там же на RPi запущен MQTT брокер, рядом на «домашнем сервере» — Home Assistant.

Идея

Уровень сигнала Wi-Fi достаточно зависим от наличия и расположения препятствий между точкой доступа и клиентами. Даже открытая/закрытая деревянная межкомнатная дверь может вызвать заметные изменения в RSSI, не говоря уже о прошедшем человеке. При этом, так как сами wi-fi клиенты стационарны — изменения сигнала от других факторов достаточно минимальны.

Если собрать данные о всех подключенных клиентах — скорее всего, их изменение будет достаточно заметным при перемещении людей в помещении, что и позволит реализовать обьемный датчик движения «просто так» — без установки дополнительного железа.

Реализация

Запустив команду iw dev wlan0 station dump, можно получить достаточно детальную информацию по подключенным клиентам:

Station 60:01:94:21:f8:4c (on wlan0)         inactive time:  8000 ms         rx bytes:       11269629         rx packets:     91423         tx bytes:       6159821         tx packets:     70707         tx failed:      0         signal:         -53 [-53] dBm         tx bitrate:     1.0 MBit/s         rx bitrate:     54.0 MBit/s         ...         connected time: 763375 seconds Station 18:fe:34:98:dc:81 (on wlan0)         inactive time:  4000 ms         rx bytes:       11388688         rx packets:     92101         tx bytes:       6143200         tx packets:     70205         tx failed:      39         signal:         -40 [-40] dBm         tx bitrate:     1.0 MBit/s         rx bitrate:     18.0 MBit/s         ...         connected time: 763378 seconds

Значение RSSI («signal: -40 [-40] dBm») обновляется в реальном времени, и вызывая iw достаточно часто — можно собрать статистику уровня сигнала.

Запуская iw два раза в секунду и усреднив RSSI за минуту — можно получить значения с более высокой точностью:

Уже по этому графику видно что ночью сигнал остается стабильным, а днем отдельные клиенты отклоняются от «спокойного» состояния на +/- 10 dBm. Однако представление результата можно улучшить, посчитав среднеквадратичное отклонения сигнала для всех клиентов от «спокойного» уровня.

Средние значения

Первым вариантом алгоритма было:

  • Собрать статистику по уровням сигналов в отсутствие людей («базовый уровень»)

  • Сохранить базовый уровень в файле конфигурации

  • Посчитать среднеквадратическое отклонение от базового уровня, которое и будет сигналом «обнаружено движение»

После имплементации такого алгоритма оказалось, что базового уровня не существует. После прохода человека по квартире и возврата в первоначальную точку — сигналы стабилизируются, но на других значениях.
Рассмотрим например тот же график в окресностях 4 утра:

Можно заметить ночной поход в ванную в ~4:30. После него сигналы вернулись к стабильности, но некоторые из них — сместились от предыдущих значений. Отсюда можно сделать вывод, что система в целом — метастабильна, и одного фиксированного «состяния покоя» не существует.

Для решения этой проблемы «состояние покоя» тоже нужно считать как среднее — но за значительно более продолжительный промежуток времени.

Финальный алгоритм

  • Раз в 500мс собираем значения RSSI из вывода iw dev wlan0 station dump.
    Сама команда достаточно легковесна, чтобы не нагружать Raspberry Pi выполнением с такой частотой.

  • Для каждого из клиентов считаем скользящее среднее за последние 1024 сэмпла в качестве «базового уровня»:

$RSSI = -65; # Значение из iw dev dump $baseline = ($RSSI + 1023 * $baseline) / 1024;
  • Опять же для каждого считаем скользящее среднее за 256 сэмплов по аналогичной формуле в качестве «текущего значения».

  • Итоговый показатель «активность движения в доме» считается как корень из суммы квадратов отклонений «текущего» от «базового» для каждого из wi-fi клиентов.

Результат уже намного более нагляден:

Здесь синий график («IW Signal Distance») и является среднеквадратическим отклонением. Остальное — индивидуальные отклонения от скользящего среднего.

Эмпирическим путем можно предположить, что значения IW Signal Distance >1 (зеленая горизонталь) соответствуют активности людей в помещении. Но эта граница, скорее всего, будет отличаться для других конфигураций помещения и количества устройств.

Результаты

Система работает в таком виде уже более двух лет, и достаточно надежно показывает активность внутри квартиры, с минимальным влиянием соседей.

Моя реализация алгоритма доступна на гитхабе (https://github.com/k-korn/misc-scripts/tree/main/iwmon), но она достаточно специфична (Perl + Zabbix + визуализация в Grafana) — и потому готовым решением «plug and play» все же служить не может.

ссылка на оригинал статьи https://habr.com/ru/post/536992/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *