Добавляем WiFi к монитору качества воздуха: измеритель CO2 для умного дома
Измерители CO₂ от Даджет уже снискали некоторую популярность из-за своей доступности и достаточно низкой цены(да, до десяти тысяч за NDIR-измеритель это еще бюджетно).
И вот когда я в один прекрасный момент задумался о мониторинге в своем доме не только температуры и влажности, но еще и количества углекислого газа, я сразу же вспомнил об этой компании и ее приборах.
Как известно, датчиков у Даджет два — один подключаемый проводом к компьютеру, а к другому можно подключить контроллер(как было сделано тут) для считывания показаний. Меня больше интересовал второй вариант котроллера, так как я хотел, чтобы датчик не был привязан к компьютеру проводом, и его можно было разместить в любом месте квартиры.
Итак, решено: берем монитор CO₂ и прикручиваем к нему WiFi в виде ESP8266.
► WiFi Inside
Для вскрытия надо вытащить 4 резиновых заглушки:
И выкрутить винты, скрывающиеся под ними. После этого можно осторожно разъединить две части корпуса(например пластиковой карточкой):
Осторожно — потому что внутри они соединены трубкой, которую надо аккуратно отцепить и засунуть внутрь корпуса, чтобы не мешалась:
На нижней части платы расположены 4 контактных отверстия:
Люди, знакомые с электроникой, поймут их назначение по буквам рядом с ним. Остальные поймут это из моего объяснения: V (voltage) — питание, D(data) — данные, С(clock) — синхронизация, G(ground) — земля.
G, он же GND, он же «земля» — нулевая точка, от которой отсчитывается напряжение питание(то, которое V) и уровни сигналов данных. В обывательской практике можно сказать, что G — это «минус», а V — это «плюс», как в батарейках. Оно даже будет правдой… пока не появится еще одно напряжение, после чего условности вроде «минуса» полетят в тартарары.
С, он же clock, он же тактовый, он же синхросигнал — специальный сигнал, который указывает принимающей стороне, когда надо считывать сигнал с линии данных(которая D).
В отличии асинхронных протоколов(типа UART/RS-232), где такого сигнала нет, и синхронизация строится на точном указании одинаковой частоты(=скорости) на передающей и принимающей стороне(все эти 1200, 9600, 115200 бод), в синхронном протоколе есть отдельная линия, смена уровня на которой означает, что приемник должен измерить состояние линии данных поняв, какой бит передается в текущий момент.
Плюсом синхронного протокола является нечувствительность к разнице тактирования устройств(можно хоть ручками набирать байты, если не ограничений по времени), минусом — необходимость отдельного провода. В принципе, при одинаковой частоте передачи, можно разбирать синхронную передачу и без тактового сигнала, но такими извращениями мы страдать не будем.
Цепляемся осциллографом на контакты и видим посылки с данными:
Приближаем, и вот уже можем разглядеть отдельные биты:
Можем даже расшифровать сообщение, но не будем. Нам важно понять, что он действительно что-то отправляет, чтобы потом не думать «а почему у меня данные не приходят» по причине их отсутствия.
Вместо осциллографа припаиваем и клеим термоклеем платку с ESP8266:
Подключаем ее по UART к компьютеру(на фото два провода, без земли, потому что измеритель питается от того же ноута) и начинаем писать код.
► Исходники
Пишется код в среде Arduino c включенной поддержкой ESP8266(как ее включить, можно прочитать вот тут). Как нажимать кнопочку для прошивки, думаю, разберетесь сами, или с помощью esp8266.ru.
Сам проект состоит из трех файлов: файла проекта, и подключенной библиотеки за авторством fedorro, который в свою очередь, использовал наработки отсюда.
Файл первый, CO2_meter.ino:
#define PIN_CLOCK 14 // Пин, к которому подключен контакт "С" — тактовый сигнал #define PIN_DATA 12 // Пин, к которому подключен контакт "D" — данные #include #include #include "mt8060_decoder.h" const char* ssid = "MikroTik-951"; //Имя сети const char* password = "FAKEPASSWORD"; //Пароль сети String co2_value = ""; //Значение содержания углекислоты в ppm String tmp_value = ""; //Значение температуры в градусах цельсия String hum_value = ""; //Значение влажности воздуха в процентах int error_count = 0; //Счетчик ошибок контрольной суммы(кстати, можно не считать, неделями работает без ошибок) ESP8266WebServer server(80); //Создаем обьект сервера void setup() < Serial.begin(115200); //Настраиваем UART WiFi.begin(ssid, password); //Подключаемся к WiFi while (WiFi.status() != WL_CONNECTED) < delay(500); Serial.print("."); // Усердно показываем в UART, что мы заняты делом >Serial.println(""); Serial.print("WiFi connected, IP "); Serial.println(WiFi.localIP()); server.on("/co2", co2_show); // Устанавливаем адреса страниц и функции, этим адресам соотвествующие server.on("/tmp", tmp_show); server.on("/hum", hum_show); server.on("/json", json_show); server.onNotFound(NotFound_show); // Главная страница server.begin(); pinMode(PIN_CLOCK, INPUT); //Настраиваем порты на вход pinMode(PIN_DATA, INPUT); //Настраиваем порты на вход attachInterrupt(digitalPinToInterrupt(PIN_CLOCK), interrupt, FALLING); //Включаем прерывание на пине с тактовым сигналом > void interrupt() // По каждому прерыванию начинаем собирать данные < bool dataBit = (digitalRead(PIN_DATA) == HIGH); unsigned long ms = millis(); mt8060_message* message = mt8060_process(ms, dataBit); //Отправляем текущее время и текущий бит в функцию, взамен получаем восхитительное ничего, если битов еще не набралось до полного сообщение, и расшифрованный пакет, если битов достаточно. if (message) < //если в ответ получен пакет if (!message->checksumIsValid) //то проверяем, правильно ли рассчитана контрольная сумма < error_count++; >else // и если правильно. < switch (message->type) //. то в зависимости от типа пакета. < case HUMIDITY: hum_value = String((double)message->value / 100, 0); // сохраняем значение влажности Serial.print("HUM:"); Serial.println(hum_value); // Выводим в UART break; case TEMPERATURE: tmp_value = String((double)message->value / 16 - 273.15, 1); // конвертируем и сохраняем значение температуры Serial.print("TMP:"); // Смотрите-ка! Сиськи! -> (. )(. ) Serial.println(tmp_value); // Выводим в UART break; case CO2_PPM: co2_value = String(message->value, DEC); // сохраняем значение количества CO₂ Serial.print("CO2:"); Serial.println(co2_value); // Выводим в UART break; default: break; > > > > void co2_show() < //Функция, выводящая CO₂ простым текстом server.send(200, "text/plain", co2_value); >void tmp_show() < //Функция, выводящая температуру простым текстом server.send(200, "text/plain", tmp_value); >void hum_show() < //Функция, выводящая влажность простым текстом server.send(200, "text/plain", hum_value); >void NotFound_show() < //Функция, выводящая красивую стартовую страницу с кнопочками String form en\">Dadget МТ8060 CO₂ monitor