Почему стоит заботиться о качестве воздуха (помимо лёгких)
Давайте будем честными — большинство из нас не думает о качестве воздуха, пока не начинает кашлять из-за сильного смога. Но дело в том, что данные о качестве воздуха повсюду, и их можно использовать. Правительствам они нужны для принятия политических решений, городским планировщикам — для развития городов, а обычным людям — чтобы решить, остаться ли сегодня дома или пойти на прогулку.
Проблема? Традиционный мониторинг качества воздуха дорог, требует специального оборудования и часто предоставляет данные только из нескольких фиксированных мест. А что, если я скажу вам, что можно построить сложную систему прогнозирования качества воздуха в реальном времени за долю стоимости, используя IoT-датчики и немного изобретательности?
В следующих нескольких тысячах слов мы как раз и построим такую систему. Мы разработаем систему, которая не просто измеряет качество воздуха — она его прогнозирует. И да, кода будет много.
Понимание архитектуры системы
Прежде чем углубляться в детали, давайте определимся, что мы на самом деле строим. Наша система состоит из трёх взаимосвязанных слоёв: сенсорного (аппаратное обеспечение, собирающее данные), сетевого (подключение и шлюзы) и аналитического (прогнозирование и визуализация).
PM2.5 | PM10 | CO2
NO2 | O3 | Температура"] -->|Wi-Fi/LTE| B["Шлюз IoT
Агрегация данных
Локальная обработка"] B -->|HTTPS| C[" облачная платформа
База данных временных рядов
Модели машинного обучения"] C -->|API| D["Веб-панель
Визуализация в реальном времени
Прогнозы"] C -->|WebSocket| E["Мобильное приложение
Пуш-уведомления
Рекомендации по здоровью"] F["Исторические данные
Погодные условия
Данные о трафике"] -.->|Обучение модели| C style A fill:#e1f5ff style B fill:#fff3e0 style C fill:#f3e5f5 style D fill:#e8f5e9 style E fill:#fce4ec
Эта архитектура позволяет нам масштабироваться от мониторинга одного района до целого мегаполиса. Каждый компонент слабо связан, что означает возможность обновления отдельных частей без перестройки всей системы.
Аппаратные компоненты: выбор датчиков
Сердцем любой системы мониторинга качества воздуха является набор датчиков. Теперь мы измеряем не только PM10 — мы охватываем весь спектр. Вот что мы будем использовать:
Датчики частиц измеряют концентрацию взвешенных частиц (PM2.5, PM10). Лазерные датчики пыли, такие как SDS011, обеспечивают отличную точность по разумной цене. Это как глаза вашей системы для обнаружения мельчайших проблем в воздухе.
Датчики газа — это то, где всё становится интереснее. Датчик MQ135 обнаруживает CO2, бензол, NH3 и NOx — всё, что может вызвать недовольство вашей дыхательной системы. Это не лабораторная точность, но удивительно надёжно для экологического мониторинга.
Датчики окружающей среды измеряют температуру, влажность и атмосферное давление. Почему? Потому что качество воздуха не существует в вакууме (буквально — воздух существует в вакууме, но вы понимаете, о чём я). Эти параметры влияют на поведение загрязнителей и имеют решающее значение для точного прогнозирования.
Для микроконтроллера мы будем использовать NodeMCU (ESP8266) или Arduino MKR WiFi 1010. NodeMCU предлагает отличный баланс между подключением, вычислительной мощностью и стоимостью. Он оснащён Wi-Fi, имеет контакты GPIO для подключения датчиков и достаточную память для буферизации локальных данных.
Настройка среды разработки
Прежде чем датчики увидят электроны, давайте подготовим среду разработки. Предполагается, что вы знакомы с Arduino IDE, но если нет, то кривая обучения будет пологой — представьте себе «инструкции IKEA, но понятные».
Сначала установите Arduino IDE, если ещё не сделали этого. Добавьте поддержку платы NodeMCU:
- Откройте Arduino IDE и перейдите в «Файл» > «Настройки».
- В разделе «Дополнительные URL-адреса менеджера плат» добавьте:
http://arduino.esp8266.com/stable/package_esp8266com_index.json. - Перейдите в «Инструменты» > «Плата» > «Менеджер плат» и найдите «ESP8266».
- Установите последнюю версию.
Теперь нам нужны библиотеки для наших датчиков. Перейдите в «Файл» > «Включить библиотеку» > «Управление библиотеками» и установите:
MQ135от bestfitme (для газового датчика);SDS011 dust sensor library;DHT sensor libraryот Adafruit (для измерения температуры и влажности);ArduinoJsonот Benoit Blanchon (для работы с JSON).
Сборка сенсорного узла: сборка оборудования
Пришло время физической сборки. Здесь теория встречается с макетной платой и иногда с разочарованием:
Соединения контактов NodeMCU:
- D1 (GPIO5) → контакт данных DHT22
- D2 (GPIO4) → выход MQ135 → A0
- D4 (GPIO2) → контакт RX SDS011
- D3 (GPIO0) → контакт TX SDS011
- GND → общее заземление (DHT, MQ135, SDS011)
- 3.3V → DHT22 VCC, MQ135 VCC, SDS011 VCC
- Vin → внешнее питание 5 В
Почему Vin вместо USB-подключения для питания? Потому что датчики — это энергоёмкие маленькие паразиты, а USB не может обеспечить стабильное напряжение под нагрузкой. Поверьте мне — я узнал это на собственном опыте через обожжённые резисторы и слёзы.
Прошивка: где происходит волшебство
Теперь код. Это прошивка, которая запускается на вашем NodeMCU, собирает данные и связывается с облаком:
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>
#include <DHT.h>
#include <SoftwareSerial.h>
// Конфигурация Wi-Fi
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";
const char* cloudServer = "your-cloud-endpoint.com";
// Конфигурация датчиков
#define DHT_PIN D1
#define MQ135_PIN A0
#define DHT_TYPE DHT22
DHT dht(DHT_PIN, DHT_TYPE);
SoftwareSerial sdsSerial(D3, D4); // RX, TX для SDS011
// Глобальные переменные
float temperature = 0;
float humidity = 0;
float pm25 = 0;
float pm10 = 0;
int mq135Value = 0;
unsigned long lastTransmission = 0;
const unsigned long TRANSMISSION_INTERVAL = 300000; // 5 минут
// Структура для показаний датчиков
struct SensorReading {
float temperature;
float humidity;
float pm25;
float pm10;
int mq135;
unsigned long timestamp;
};
void setup() {
Serial.begin(115200);
delay(100);
// Инициализация датчиков
dht.begin();
sdsSerial.begin(9600);
Serial.println("\n\nСистема инициализируется...");
// Подключение к Wi-Fi
connectToWiFi();
}
void loop() {
// Проверка подключения к Wi-Fi
if (WiFi.status() != WL_CONNECTED) {
connectToWiFi();
}
// Чтение датчиков
readDHTSensor();
readMQ135Sensor();
readSDS011Sensor();
// Передача данных, если интервал истёк
if (millis() - lastTransmission > TRANSMISSION_INTERVAL) {
transmitData();
lastTransmission = millis();
}
delay(2000);
}
void readDHTSensor() {
float h = dht.readHumidity();
float t = dht.readTemperature();
if (!isnan(h) && !isnan(t)) {
humidity = h;
temperature = t;
Serial.printf("DHT22 - Температура: %.1f°C, Влажность: %.1f%%\n", temperature, humidity);
}
}
void readMQ135Sensor() {
int rawValue = analogRead(MQ135_PIN);
mq135Value = rawValue;
// Преобразование в PPM (упрощённо; требуется калибровка для производства)
float ppm = (rawValue / 1024.0) * 500;
Serial.printf("MQ135 - Сырое значение: %d, Ожидаемый CO2: %.0f ppm\n", rawValue, ppm);
}
void readSDS0
