Программная часть городской системы мониторинга воздуха
31 мая 2026 · Услуги: Данные · Legacy Perl
В середине 2010-х я работал над программной частью проекта, связанного с городской системой мониторинга атмосферного воздуха Санкт-Петербурга. Это была не обычная веб-разработка, а часть городской инфраструктуры: автоматические станции по районам города, газоанализаторы, регулярные измерения, передача данных в центр сбора и обработки, хранение показаний и публикация информации.
По сути, это была промышленная система с приборами и удалённым сбором данных до того, как термин «интернет вещей» стал массовым. В системе были реальные приборы, COM-порты, модемная связь, промежуточные файлы измерений, центральная обработка, отчётность и требования к надёжности. Моя работа относилась к одному из программных слоёв уже существующей городской инфраструктуры: не вся система создавалась с нуля, но станционную часть нужно было привести в более сопровождаемое состояние.
Рисунок 1. Карта с точками станций мониторинга воздуха, сфотографированная в офисе проекта. Такие физические точки наблюдения были главным источником данных для программной части.
Рисунок 2. Та же логика на публичной стороне: карта с сайта, где данные станций становились понятным городским интерфейсом.
Контекст системы
Городская система использовалась для экологического мониторинга атмосферного воздуха. Автоматические станции непрерывно измеряли загрязняющие вещества, а результаты с регулярным интервалом попадали в центральную базу и дальше использовались для обработки, отчётности и информирования.
В таких системах программный слой работает не с абстрактными заявками, а с потоком физических измерений. На одной стороне находятся приборы, датчики, порты, модемы, локальные файлы и инженеры, которые приезжают на станцию. На другой — центральная обработка, хранение, контроль качества данных и публикация результатов.
Система работала автоматизированно с измерением оксида углерода, оксида азота, диоксида азота, взвешенных частиц PM10 и диоксида серы. Неавтоматизированно наблюдались бензол, толуол, этилбензол, ксилолы, фенол. Часть таких измерений могла делаться через полуавтоматический отбор проб с последующим лабораторным анализом.
Исходное состояние
На момент моей работы основная проблема была не только в коде, а в способе эксплуатации. Программная часть уже работала в продакшене, но вокруг неё почти не было нормального инженерного контура: документации, воспроизводимого развёртывания, понятной истории изменений и аккуратного процесса поставки обновлений.
Такое состояние характерно для многих долгоживущих промышленных систем. Код живёт рядом с оборудованием, дорабатывается по мере появления проблем, часть знаний хранится у отдельных людей, а документация появляется позже, чем сама система. Пока всё работает, это кажется приемлемым. Но любая замена станции, поездка инженера на объект, подключение нового прибора или исправление ошибки превращаются в ручную операцию с высоким риском.
Что нужно было сделать
- Собрать рабочий код в репозиторий и сделать его основным источником.
- Описать процесс изменений: задачи, ветки, коммиты, проверка и попадание изменений в прод.
- Подготовить документацию по станционной части: установка ОС, окружение, конфигурация приборов, запуск сервисов, бекапы и обновление кода.
- Упростить обслуживание станций инженерами, которые приезжают на объект и должны быстро понять, что и как обновлять.
- Подключить стажёров и младших специалистов к работе так, чтобы они могли помогать с документацией, проверками и переносом знаний, не ломая продакшен.
- Сохранить работоспособность существующей системы: это была инфраструктурная история, а не зелёный проект с правом всё переписать.
Репозиторий, документация и поставка
Первый слой работы был организационно-инженерным: привести код и документацию в состояние, с которым можно жить. Для изменений был зафиксирован процесс через задачи и отдельные ветки. Коммиты привязывались к задачам, перед слиянием изменения тестировались, а ветка master рассматривалась как версия для продакшена, которую можно взять для установки на рабочую станцию.
Это не был современный облачный CI/CD в смысле контейнеров, staging-кластеров и автоматического деплоя на каждую станцию. У станций могли быть ограничения по связи, часть обновлений выполнялась на месте. Но это был важный для проекта шаг к управляемой поставке: код перестал быть набором файлов "где-то в проде", появилась история изменений, появились правила попадания в продакшен, появилась тестовая станция и появился понятный способ обновлять рабочие станции из репозитория.
Отдельно была сделана документация для практической эксплуатации: как всё подготовить, какие рабочие директории нужны, где лежат конфиги, как указать приборы и порты, как запускать мониторинг в реальном времени, как настроить backup данных измерений и автозагрузку станционных процессов.
Рисунок 3. Схема работы программного обеспечения станции мониторинга из рабочих материалов проекта.
Станционная часть
Станция была не абстрактным "клиентом API", а компьютером рядом с измерительным оборудованием. К нему подключались газоанализаторы, метеодатчики, радиационные датчики и служебное оборудование. Значительная часть обмена шла через последовательные порты, поэтому в документации отдельно описывались MOXA-платы для расширения количества COM-портов и привязка конкретных приборов к конкретным устройствам вроде /dev/ttyM0, /dev/ttyM3 или /dev/ttyS0.
Рисунок 4. Так станция мониторинга выглядела снаружи: отдельный объект городской инфраструктуры, куда приезжали инженеры для обслуживания оборудования и программной части.
Рисунок 5. Станция внутри: стойка с измерительным и служебным оборудованием, рядом с которым работала станционная программная часть.
В рабочих материалах были описаны разные классы приборов: ThermoElectron, Environnement, Horiba, Automet, WXT520, DKGRAD, FDS. Для них фиксировались измеряемые параметры и единицы: NO, NO2, SO2, CO, O3, PM10/PM2.5, температура, влажность, давление, скорость и направление ветра, радиационный фон. Это хорошо показывает природу задачи: программный слой должен был быть устойчивым посредником между физическими приборами и дальнейшей обработкой данных.
Данные читались не с красивого интерфейса на экране, а с порта — сырые значения, которые нужно было корректно прочитать, нормализовать, сохранить и передать дальше.
Рисунок 6. Показания прибора на станции: NO, NO2 и NOx в мг/м³.
Внутри станционной части были отдельные процессы для сбора и контроля данных. Результаты измерений складывались в рабочие каталоги, а центр мог забирать подготовленные файлы. Для инженера на станции важны были воспроизводимые команды: что запустить, где посмотреть живые показания, как проверить порт, как не потерять данные после перезагрузки.
Рисунок 7. Кроме стационарных объектов использовалась передвижная станция. Внутри у неё была похожая стойка с оборудованием, поэтому требования к обслуживанию программной части оставались такими же прикладными: порты, приборы, конфигурация, сбор данных и передача результатов.
Tiny Core Linux
Отдельной частью проекта была станционная операционная система на Tiny Core Linux. Это был прагматичный выбор для полевых условий: система загружалась с флешки, работала в оперативной памяти и позволяла сохранять нужную конфигурацию обратно на носитель. Такой подход упрощал обслуживание станции и снижал зависимость от состояния локального диска.
Рабочее окружение станции включало Perl, git, minicom, pppd, inetutils, Log::Log4perl, JSON и дополнительные пакеты для работы с последовательными портами. Часть зависимостей приходилось собирать и упаковывать отдельно в формат Tiny Core, например модули Perl для SerialPort и BufferedSelect, драйверы MOXA, mgetty и редактор Vim. Это была низкоуровневая эксплуатационная работа: не просто написать скрипт, а сделать так, чтобы он поднимался после перезагрузки станции и продолжал работать рядом с приборами.
Работа с командой
Ещё одна часть результата — подключение людей к проекту. Когда система существует только как код в продакшене и устные знания, стажёра или младшего разработчика невозможно безопасно включить в работу. Сначала нужно описать границы: где документация, где репозиторий, как создаются задачи, что можно менять, что проверяется на тестовой станции, как выглядит рабочее обновление.
После этого стажёры могли брать ограниченные задачи: приводить инструкции в порядок, проверять развёртывание, фиксировать шаги настройки, уточнять конфиги, помогать с переносом знаний в README. Для промышленной системы с унаследованным кодом это не второстепенная работа, а способ снизить зависимость от одного человека и сделать сопровождение более устойчивым.
Результат
- Код станционной части был собран в репозиторий и стал управляемым артефактом, а не набором файлов в продакшене.
- Был описан процесс изменений: задачи, ветки, коммиты, тестирование и попадание в продакшен-ветку.
- Появилась эксплуатационная документация по Tiny Core Linux, пакетам, автозагрузке, ssh, cron, backup и связи станции с центром.
- Были зафиксированы конфигурационные принципы для приборов, портов, исключения измерений и запуска станционных процессов.
- Проект стало проще передавать инженерам и младшим специалистам: часть знаний перестала быть устной.
- Система сохранила прикладной фокус: не переписывание ради переписывания, а повышение сопровождаемости работающей городской инфраструктуры.
Если нужен похожий результат: помогаю разбирать унаследованные системы вокруг данных, восстанавливать документацию, выстраивать репозиторий и процесс поставки, упаковывать эксплуатационные знания и снижать риски сопровождения.