- BrainTools - https://www.braintools.ru -

Как посчитать, сколько людей в лаборатории

Как посчитать, сколько людей в лаборатории - 1

Почти всё время существования лаборатории студенческих проектов [1] Висконсинского университета в ней использовалась камера. Есть свидетельства наличия такой системы ещё в 1990-х: на древней версии сайта [2] университета о ней говорится следующее:

…на стену приклеена изолентой камера ценой $15, подключённая к видеомагнитофону, который соединён с видеоразъёмом Mac IIcx, где запущены Timed Video Grabber (TVG) и FTPd. Рабочая станция HP Dax выполняет скрипт, который каждые 60 секунд пытается сохранить на FTP последнее изображение. Из-за отсутствия синхронизации часов время от времени происходят коллизии доступа к файлам, и вся схема ломается.

Прочитав это, я ненароком с восхищением взглянул на камеру, которая теперь установлена наверху аркадного автомата. Система, для создания которой требовалось оборудование на многие тысячи долларов, сегодня реализуема (в бесконечно лучшем качестве) на основе веб-камеры за $50, подключённой к Raspberry Pi.

A grainy image featuring an interior view of the UPL, a triangular-shaped undergraduate lab at UW-Madison.

Зернистый кадр интерьера треугольной студенческой лаборатории Висконсинского университета в Мэдисоне
An image featuring the interior of the UPL, a lab at UW-Madison. Students sit at laptops.

Эти кадры разделяет примерно двадцать пять лет.

Можно написать отдельный пост (и, вероятно, я этим займусь) о сложной истории лаборатории студенческих проектов (Undergraduate Projects Lab, UPL) с упоминанием того, что старые версии веб-сайта [3] позволяли пользователям управлять поворотом и наклоном камеры при помощи четырёх прикреплённых к ней шаговых двигателей.

Однако в этой статье я расскажу о двух последних итерациях системы в UPL.

«Открыта ли сейчас UPL?»

Я уверен, что каждый член UPL может рассказать страшную историю о том, как он пришёл в лабораторию и увидел закрытую дверь. Если вы живёте не в кампусе, то печально осознавать, что сложный путь до здания computer science завершился неудачей.

Нет сомнений, что уже во времена IRC члены UPL спрашивали друг у друга, открыта ли лаборатория. С появлением мобильных телефонов напрягать друзей стало ещё проще; но они ведь могут и не находиться в кабинете!

Мы с другими членами UPL решили устранить эту проблему, вероятно, самым подходящим для студента CS способом: создать автоматизированную систему для определения того, занята ли лаборатория.

Считаем людей

В первой итерации системы подсчёта людей (разработанной Майклом Берки [4]) использовалась камера Logitech C920, смонтированная в точке с хорошим обзором на кабинет. Discord-бот каждые 15 минут (при помощи discord.py.ext @tasks.loop(minutes=15)) вызывал модель YOLOv7 с классом 0 (распознавание людей). Бот вызывал камеру, чтобы получить изображение, а затем получал инференс при помощи модели. Он возвращал количество людей в комнате (и с целью отладки аннотировал ограничивающими прямоугольниками те участки, где, по его мнению, находились люди).

The front side of a C920 webcam.
The back side of a C920 webcam.

…на скотч не обращайте внимания [5].

Затем он присваивал каналу имя, соответствующее результату (или 1-person-in-upl, или X-people-in-upl), которое могли видеть пользователи.

A channel in the UPL Discord reads '8 people in UPL'.

Пример того, как выглядел Discord в дни, когда в UPL было не так много людей

Переходим к датчикам на двери

Какое-то время это прекрасно работало — пользователи смотрели на имя канала Discord и понимали, сколько примерно людей находится в кабинете. Если там было написано «ноль людей», то можно было сделать вывод, что UPL закрыта.

Однако у этого решения начали появляться проблемы. Например, наличие людей в кабинете необязательно означает, что UPL открыта. Там может проходить совещание или отдельная встреча, когда двери закрываются и никого не впускают. Это сбивало с толку тех, кто видел имя канала «В UPL находится 8 человек» и лишь на месте узнавал, что у координаторов проходит совещание.

Также модель иногда интерпретировала стул в углу, как человека1:

An image of the empty lab. An annotation on a brown armchair reads 'Person 0', despite no human on the chair.

Или модель слишком чувствительная, или в UPL поселилось привидение!

Примерно в то же время я наткнулся на домашнюю страницу хакспейса Массачусетского технологического института MITERS [6]. Она сообщала, открыта ли дверь, при помощи геркона, соединённого с Raspberry Pi. Герконы — это маленькие физические детали, способные обнаруживать магнитное поле. Если установить геркон в дверную раму и прикрепить крошечный магнит к самой двери, то можно определять, открыта ли дверь! Мне удалось найти статью [7] бывшего члена хакспейса о реализации системы, но не гарантирую, что она совпадает с тем, что используется в хакспейсе сейчас.

Примечание

После публикации моей статьи я получил кучу вопросов о том, почему мы отслеживаем состояние двери, а не другие атрибуты кабинета. Большую часть этих вопросов задали в моём посте на Hacker News [8], а также под статьёй, опубликованной на Hackaday [9]. Особенно мне понравился комментарий о том, что я «не смотрю на проект с системной точки зрения». Ниже представлены мои ответы на некоторые из вопросов.

Почему бы не…

  • …направить на двери камеры?

    • Это бы тоже сработало! Но это было бы намного сложнее, чем прикрепить два датчика Zigbee на двери; мне бы пришлось обучать модель понимать разницу между интерьером UPL и коридором здания.

  • …направить камеру на источники освещения в кабинете?

    • Похоже, читатели больше всего путали отслеживание состояния кабинета и его занятости. Различие заключается в том, что наличие в лаборатории людей необязательно означает, что она открыта. Например, там могут проводить совещание координаторы (или прийти уборщица и так далее). Да, можно и другими способами понимать, есть ли люди в кабинете, но ни один из них не указывает на состояние так же хорошо, как двери (или же когда кто-то пишет в Discord, что кабинет закрыт для посещения).

  • …использовать технологическое решение, обнаруживающее устройства в лаборатории?

    • Таких предложений было несколько: например, для проверки того, кто вошёл в сеть, zdw [10] советовал команду finger, а zimpenfish [11] — применение rlogin. Дело в том, что в UPL больше нет десктопных компьютеров, которыми могли бы пользоваться студенты. Большинство студентов просто приносит свои ноутбуки, потому что купить компьютер сегодня уже не так сложно! У нас нет инфраструктуры (по крайней мере, пока), позволяющей студентам подключаться по ssh к нашим серверам, но если бы она и была, то мы бы не смогли определить, происходит ли это изнутри лаборатории. Что касается использования WiFi/DHCP для обнаружения устройств (как это рекомендовал сделать q3k [12]), то члены UPL пользуются UWNet или eduroam, а не WiFi-сетью лаборатории. Также есть тонкие моменты, связанные с конфиденциальностью при отслеживании пользователей, пусть и анонимизированных, поэтому нам крайне не хотелось бы создавать нечто подобное.

  • …использовать онлайн-систему резервации?

    • UPL [1] — это не конференц-зал. Хотя в ней существует список индивидуальных часов координаторов, кабинет не всегда занят согласно этому графику. Иногда координаторы пропускают свои часы, а иногда кабинет остаётся открытым до пяти утра [13]. К чему это я: невозможно просто заглянуть в расписание для определения состояния кабинета, а указанное времени занятости довольно часто будет оказываться неточным.

  • …использовать WiFi-сигналы [14] для определения точного количества людей в кабинете?

    • Ого! Это безумно круто. Но таким образом всё равно нельзя определить состояние использования кабинета. Однако всё равно было бы здорово иметь возможность подсчёта количества людей вместе с состоянием кабинета, так что эту мысль я запомню.

Надеюсь, это примечание ответило на самые частые вопросы о проекте.

Я подумывал использовать похожие компоненты для определения состояния двери UPL — было не так уж сложно купить модули ESP32 с поддержкой WiFi и герконы для монтажа не двери. Тогда чипы бы просто отправляли POST-запрос с состоянием каждый раз, когда дверь открывается или закрывается.

Я решил отказаться от такой системы по нескольким причинам:

  • В UPL нет оборудования для поддержки такой системы. Я не умею паять, а приклеивание макетных плат к стенам — не особо удобное и красивое решение.

  • Если после моего ухода из университета система поломается, то будет сложно найти человека, способного её починить. В UPL по большей мере работают с ПО!

  • Для логина в WiFi университета (UWNet) необходимо зайти на портал авторизации [15], где можно зарегистрировать устройство. Без вмешательства время от времени требуется выполнять повторную регистрацию, чтобы восстановить подключение2. Хотя запросы, которые обычный браузер выполняет для аутентификации с NetID, можно эмулировать, для этого потребуются существенные постоянные усилия (а после выпуска студента логин необходимо будет менять)!

Поэтому я решил, что датчики должны работать автономно и просто передавать своё состояние какому-то устройству в кабинете. К счастью, Raspberry Pi, где выполнялся код счётчика людей, можно было с лёгкостью использовать и для этой цели. Я установил Home Assistant [16] — опенсорсную платформу для взаимодействия с различными сетевыми устройствами.

Существует множество устройств для отслеживания состояния дверей, производимых такими компаниями, как Ring и ADT, которые специализируются на безопасности дома. Однако для проверки их состояния обычно требуется проприетарный концентратор и у них нет удобных API для взаимодействия с устройством. К счастью, есть решение получше!

Zigbee!

Встречайте Zigbee — низкочастотный беспроводной протокол mesh-сетей, позволяющий умным устройствам общаться через персональную сеть. Преимущество протокола заключается в том, что можно было использовать один концентратор для общения с разнообразными устройствами, даже если они изготовлены разными производителями. Вместо того, чтобы искать определённый бренд контактных датчиков дверей, мне достаточно найти датчики, поддерживающие протокол Zigbee, после чего я смогу отображать их состояние в дэшборде Home Assistant.

Важно отметить, что радиооборудование Zigbee работает независимо от антенн WiFi и Bluetooth. Для взаимодействия с Zigbee-устройствами необходимо приобрести специальный приёмник, поддерживающий этот протокол. Для этого проекта я купил устройство [17] SONOFF. Интеграция Home Assistant с Zigbee называется Zigbee Home Automation [18], она поддерживает широкий спектр Zigbee-координаторов (USB-донглов, обеспечивающих возможность подключения). При использовании этой интеграции Home Assistant автоматически создаёт сеть Zigbee, к которой могут подключаться устройства.

Для этого проекта я решил использовать дверные и оконные датчики Aqara [19]. Из всех просмотренных мной дверных Zigbee-датчиков у них были лучше отзывы и они могут работать от батареек (CR1632) два года.

После получения координатора и датчиков я создал логин Home Assistant и установил интеграцию ZHA. Для сопряжения устройств достаточно было лишь удерживать на датчиках кнопку сброса, пока Home Assistant не распознал их и не добавил на дэшборд соответствующие элементы.

An image of a Raspberry Pi suspended from a wall with various cables plugged into it. There's a USB stick with an antenna sticking out.
An image featuring a door contact sensor. The door is cracked open, and the sensors are nearly making contact.

Используем состояние дверей

После настройки этой системы в дэшборде Home Assistant начало отображаться актуальное состояние дверей3! Честно говоря, было очень захватывающе открывать и закрывать двери, наблюдая за изменением дэшборда в реальном времени (хотя проходящие мимо кабинета, наверно, думали, что я сошёл с ума).

Здесь важно отметить, что UWNet обеспечивает полную изоляцию точки доступа. Ни одно из устройств в сети не может видеть другие (и это здорово, ведь иначе бы возникла огромная уязвимость устройств с открытыми портами). Если бы не это ограничение, я бы настроил систему так, чтобы веб-сайт напрямую отправлял запросы RPi.

Поначалу я решил использовать интеграцию RESTful Command [20] Home Assistant для отправки POST-запроса на веб-сервер при изменении состояния дверей. Для этого необходимо, чтобы каждая команда была подготовлена заранее в файле configuration.yml Home Assistant:

rest_command:
  door1_opened:
    url: "https://doors.amoses.dev/door1/open"
    method: POST
    headers:
      content-type: "application/json"
    payload: '{"door": "door1", "state": "open"}'
    content_type: "application/json; charset=utf-8"

  door1_closed:
    url: "https://doors.amoses.dev/door1/close"
    method: POST
    headers:
      content-type: "application/json"
    payload: '{"door": "door1", "state": "closed"}'
    content_type: "application/json; charset=utf-8"

  door2_opened:
    url: "https://doors.amoses.dev/door2/open"
    method: POST
    headers:
      content-type: "application/json"
    payload: '{"door": "door2", "state": "open"}'
    content_type: "application/json; charset=utf-8"

  door2_closed:
    url: "https://doors.amoses.dev/door2/close"
    method: POST
    headers:
      content-type: "application/json"
    payload: '{"door": "door2", "state": "closed"}'
    content_type: "application/json; charset=utf-8"

…но я вскоре осознал, что это решение неидеально. Во-первых, когда я опубликовал исходный код [21] в GitHub, какие-то весёлые студенты решили, что можно вручную симулировать POST-запросы, чтобы произвольно менять состояние дверей. Вот, что получается, если не защищать конечную точку!4

Позже я узнал, что у Home Assistant наряду с веб-дэшбордом есть RESTful API [22]. Если настроить его, то можно будет запрашивать у инстанса состояния подключённых устройств5. Для этого достаточно лишь добавить к HA URL маршрут /api/.

Все маршруты API аутентифицируются bearer-токеном (скорее всего, чтобы отзеркаливать разрешения фронтенда, требующего логина пользователя для отображения данных). Учитывая то, что я хотел отображать состояние дверей на странице UPL, мне стала понятна потенциальная опасность выпуска bearer-токена с сайтом. Любой хитроумный пользователь сможет взять его и получить доступ к любому другому маршруту Home Assistant API. Учитывая уровень информации и контроля инстансов HA, это может иметь катастрофические последствия.

Я создал небольшой веб-сервер на основе Express, проксирующий запрос с bearer-токеном и передающий только релевантную информацию о дверях. Так как она отображается отдельно, пользователь никак не сможет просмотреть или изменить ничего другого.

server.js

const express = require("express");
const axios = require("axios");
const cors = require("cors");

const app = express();
const PORT = 3500;

const apiUrl = "https://HOMEASSISTANT-URL-HERE/api/states";
const token = "Bearer TOKEN-GOES-HERE";

app.use(cors());

app.get("/door-status", async (req, res) => {
  try {
    const response = await axios.get(apiUrl, {
      headers: {
        Authorization: token,
      },
    });

    const data = response.data;

    // получаем элементы с соответствующими id сущностей HA 
    const doors = data.filter(
      (item) =>
        item.entity_id === "binary_sensor.back" ||
        item.entity_id === "binary_sensor.front"
    );

    // точная информация о состоянии и последнем обновлении
    const doorStatus = doors.map((door) => ({
      door: door.attributes.friendly_name,
      status: door.state,
      last_updated: door.last_updated,
    }));

    // отправляем отфильтрованные данные в виде json-ответа
    res.json(doorStatus);
  } catch (error) {
    res.status(500).send("Error fetching data");
  }
});

// :P
app.get("/", async (req, res) => {
  res
    .status(200)
    .send("<html><body><b>wow upl door status endpoint 443</b></body></html>");
});

app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

Сервер будет от нашего лица запрашивать Home Assistant API (с соответствующим bearer-токеном), а тот будет возвращать объект JSON с состоянием дверей и временем их последнего изменения:

response.json

[
  {
    "door": "back",
    "status": "on",
    "last_updated": "2024-10-12T20:01:54.353657+00:00"
  },
  {
    "door": "front",
    "status": "on",
    "last_updated": "2024-10-12T20:02:10.132178+00:00"
  }
]

…а Discord-бот/веб-сайт UPL может использовать эти данные, чтобы отображать состояние.

The UPL website reads 'the doors are open!' with an icon of an open door.

Веб-сайт UPL использует компонент header, получающий состояние дверей каждые 15 секунд
A channel in the UPL Discord reads 'UPL doors open'.

Имя канала Discord — простой способ определения состояния без необходимости захода на сайт

Заключение

Я очень доволен результатами проекта. Было очень увлекательно разрабатывать систему, которой сам будешь пользоваться ежедневно, и испытывал приятное чувство каждый раз, когда я проверял, открыта ли UPL.


Примечания

  1. Я уверен, что есть способы преобразования изображения, чтобы замаскировать эту область от распознавания. Но иногда в ней сидят люди!

  2. Человек, живший в общежитиях Винсконсинского университета, знает, о чём я. Каждое устройство без браузерного доступа должно иметь MAC-адрес из белого списка сетевой системы. Срок этой авторизации истекает через шесть месяцев, поэтому через полгода ты теряешь доступ к Интернету и его нужно обновлять.

  3. В UPL есть передний и задний вход, поэтому и «двери», а не «дверь».

  4. Можете не пытаться, эти конечные точки больше не используются.

  5. Внимательные читатели могут задаться вопросом: «а что насчёт той проблемы с изоляцией точки доступа?». Я нашёл замечательный аддон для Home Assistant, позволяющий при помощи туннелей Cloudflare получать доступ к дэшборду (а значит, и к API), когда отсутствует подключение к LAN Raspberry Pi. У него есть репозиторий на GitHub [23].

Автор: interpres

Источник [24]


Сайт-источник BrainTools: https://www.braintools.ru

Путь до страницы источника: https://www.braintools.ru/article/20075

URLs in this post:

[1] лаборатории студенческих проектов: https://www.upl.cs.wisc.edu/

[2] древней версии сайта: https://web.archive.org/web/19981202092257/http://www.upl.cs.wisc.edu/cgi-bin/uplcam.html

[3] старые версии веб-сайта: https://web.archive.org/web/20001003051528/http://www.upl.cs.wisc.edu/uplcam/spincam.html

[4] Майклом Берки: https://github.com/mdberkey

[5] внимания: http://www.braintools.ru/article/7595

[6] MITERS: https://miters.mit.edu/

[7] статью: https://andrewbirkel.com/projects/MITERS_Door.html

[8] моём посте на Hacker News: https://news.ycombinator.com/item?id=41907360

[9] Hackaday: https://hackaday.com/2024/10/24/keeping-tabs-on-an-undergraduate-projects-labs-door-status/

[10] zdw: https://news.ycombinator.com/item?id=41908772

[11] zimpenfish: https://news.ycombinator.com/item?id=41912287

[12] q3k: https://news.ycombinator.com/item?id=41913831

[13] кабинет остаётся открытым до пяти утра: https://www.amoses.dev/images/upl-pc/five_am.jpg

[14] WiFi-сигналы: https://arxiv.org/pdf/2301.00250

[15] портал авторизации: https://en.wikipedia.org/wiki/Captive_portal

[16] Home Assistant: https://www.home-assistant.io/

[17] устройство: https://www.amazon.com/SONOFF-Universal-Assistant-Zigbee2MQTT-Wireless/dp/B0B6P22YJC/

[18] Zigbee Home Automation: https://www.home-assistant.io/integrations/zha/

[19] дверные и оконные датчики Aqara: https://www.amazon.com/Aqara-MCCGQ11LM-Window-Sensor-White/dp/B07D37VDM3/

[20] RESTful Command: https://www.home-assistant.io/integrations/rest_command/

[21] исходный код: https://github.com/UW-UPL/people-counter-v2/blob/main/home-assistant/configuration.yaml

[22] RESTful API: https://developers.home-assistant.io/docs/api/rest/

[23] репозиторий на GitHub: https://github.com/brenner-tobias/addon-cloudflared

[24] Источник: https://habr.com/ru/companies/ruvds/articles/950944/?utm_campaign=950944&utm_source=habrahabr&utm_medium=rss

www.BrainTools.ru

Rambler's Top100