В проекте по подсчету и публикации в сети показаний газового счетчика, я уже упоминал, что хорошо бы иметь возможность измерять не только температуру, но и содержание различных газов в воздухе. Тогда, в проекте, я пытался использоваться электрохимические датчики серии MQ. Один для измерения содержания природного газа в воздухе, второй для отслеживания концентрации CO. И если бы не полное фиаско с сенсорами MQ, вполне возможно, что данный проект и не появился бы.
Тем не менее понимать и вести статистику по содержанию CO2 в воздухе — очень важно. Ведь за счет удаления углекислого газа из нашего тела, собственно, мы и живем. Высокие показатели содержания CO2 в воздухе ведут к потере работоспособности, плохому самочувствию, а при очень высоком содержании углекислого газа в воздухе, увы, наступает досрочное завершение жизненного цикла.
Итак, цель настоящего мини-проекта в том, чтобы опробовать связку из Arduino-совместимой платы WeMos D1 Mini Pro, датчика содержания углекислого газа в воздухе и сервиса по хранению показаний ThingSpeak. На самом деле, данный мини-проект — проба пера, технологии определения содержания CO2 в воздухе, перед началом другого, немного более крупного проекта. Хотя результатами проекта можно пользоваться без каких-либо ограничений. Собранное устройство делает именно то, что от него требуется.
Почему я использую WeMos D1 Mini Pro для этого проекта? Плата мною уже изучена, подводные камни понятны. Кроме того, чип ESP8266 имеет встроенный Wi-Fi, а на самой плате распаяно, ни много ни мало, а целых 16 мегабайт памяти. Поэтому можно как угодно изгаляться, места для вашего скетча будет достаточно, нет необходимости экономить память.
640 килобайт хватит надолго!
Уильям Гейтс, 1981
Плата D1 Mini Pro поставляется вместе с набором шпыньков, включая сквозные, позволяющие не только устанавливать ее на макетную плату, но и одновременно использовать различные шишлды. Но, кроме неоспоримых достоинств у D1 Mini Pro есть и некоторый недостаток. На плате использована керамическая антенна, которая вроде бы должна обеспечивать вполне уверенное соединение с Wi-Fi. Однако, на практике связь хуже, чем у той же D1 R2 с антенной разведенной на плате. Видимо, по этой причине производитель добавил гнездо для подключения внешней антенных. Впрочем, разница все равно не слишком существенная.
Почему я использую сервис ThingSpeak? Да все по той же причине. Он бесплатен, позволяет передавать, агрегировать, хранить и обрабатывать данные со всех моих устройств. Что, согласитесь, удобно. Более того, доступность мощнейшего аппарата MatLab прямо онлайн, делает сервис ThingSpeak очень привлекательной средой для любых домашних проектов.
А вот на датчике MHZ-19 остановится подробнее.
MH-Z19
Датчики серии MH-Z выпускаются китайской компанией Winsen. Сама компания специализируется именно на разработке и производстве датчиков для определения газов. В активе компании имеются как электрохимические, так и датчики, выполненные по другим технологиям. Собственно, датчики MH-Z, а среди них MH-Z14A, MH-Z19B, MH-Z14 и MH-Z19, как раз и относятся к группе сенсоров, выполненных по другим технологиям.
В основе процесса измерения в сенсорах MH-Z лежит принцип оптического измерения содержания определенного газа. В английском языке подобная технология называется Nondispersive infrared, что на русский язык переводится примерно как «недисперсионная инфракрасная технология» или сокращенно NDIR. Наличие IR и то, что сам сенсор используется инфракрасное излучение для анализа воздуха наводит некоторых «специалистов» на то, что в датчике используется PIR (Passive Infrared) технология. Да, в PIR, как и в NDIR, используется инфракрасный свет, а в остальном это две отличных технологий.
В NDIR используется две камеры, одна заполнена азотом, а такой газ содержится и в атмосфере нашей планеты. Более того, азота в воздухе, которым мы дышим аж 78%. Кислорода 21%, а углекислого газа всего 1%. Так вот, одна из камер содержит азот, а вторая тот воздух, который подвергается исследованию. Через обе камеры, одновременно пропускается пучок инфракрасного света. Его источником может быть, все что угодно. В подобных устройствах обычно используется полупроводниковый диод, обеспечивающий требуемую длину волны. Если же источник инфракрасного света недостаточно стабилизирован по спектральной характеристике, то применяется оптический фильтр, отсекающий все остальные длины волн.
Проходя через обе камеры, световой импульс подвергается рассеиванию на молекулах газа. Во время дисперсии происходит рассеивание (преломление) направленного пучка света и его частичное поглощение молекулами или стенками сенсора. Как правило, в качестве базовой отправной точки используется камера с азотом, а результаты из второй камеры сравниваются с результатами в камере с азотом. В результате прошедший через камеры свет анализируется фотоприемником и вычисляется содержание искомого газа. Следует заметить, что метод весьма точен и мало затратен в плане энергетики, а сам сенсор будет служить, по крайней мере так заявляет производитель, верой и правдой своему хозяину на протяжении ну никак не менее пяти лет. Деградация датчика будет происходить из-за забивания пылью фильтров, изменения спектральных характеристик у излучающего светодиода и деградацией фотоприемника. Но эти процессы небыстрые, поэтому можно считать, что такой датчик будет служить лет десять без видимых ухудшений показаний.
Несмотря на то что измерения сенсорами с технологией NDIR точны, могут наблюдаться и некоторые погрешности, особенно при малых концентрациях искомого газа, связанные с наличием в воздухе других газов. Так, у датчиков, используемых для определения CO2 есть некоторые, совсем небольшие, проблемы с H2O (паром), SO2 и NO2. В бытовом применении эти погрешности можно с легкостью скинуть со счетов, но для промышленного применения, где требуется высокая точность, видимо надо изобретать какие-то дополнительные механизмы. И да, когда вы дышите на датчик, стараясь проверить насколько он здорово работает, учтите, что в выдыхаемом вами воздухе содержится изрядное количество водяного пара, который так же окажет влияние на показания.
Как отметил выше, в настоящее время Winsen выпускает два вида датчиков, серию Z14 и Z19. Отличаются одна серия от другой внешним видом. Z19 это параллелепипед с двумя фильтрами, а Z14 — усеченный цилиндр на плате с одним фильтром. Есть различия между моделями и внутри серий связанные с дополнительными настройками по диапазонам работы. В целом же обе серии можно считать идентичными, а различия несущественными.
Калибровка
Датчик Z19 имеет возможность калибровки. Причем возможна калибровка двумя способами. Первый и самый точный способ: калибровка абсолютного нуля. Для этого датчик необходимо поместить в атмосферу из чистого азота, подождать пока азот не вытеснит все остальные газы из корпуса датчика, примерно пять минут, и запустить калибровку командой. Результаты будут записаны в память микроконтроллера сенсора, и они будут использоваться для последующих определений значений измерений. Азот, кстати, можно приобрести на предприятиях занимающимися реализацией газов. Правда, самый маленький баллон будет стоить как два, а то и четыре датчика MH-Z19, но искусство требует жертв.
Второй способ, так называемый span calibration применяется для калибровки в бытовых условиях. Выполняется он точно так же, как и в первом способе, но датчик нет необходимости помещать в атмосферу азота. Достаточно вынести его на чистый и свежий воздух и произвести калибровку. Тут делается упор на то, что в атмосферном воздухе содержится порядка 400 ppm CO2. И значение это постоянно на протяжении длительного времени и более-менее однородно по всему земному шару. Но при подобной калибровке следует учитывать, что значение в 400 ppm весьма условно, поскольку концентрация углекислого газа колеблется, и в весьма ощутимых пределах, в зависимости от внешних факторов. В крупном городе концентрация будет выше, чем на селе. Летней ночью в лесу углекислого газа будет больше, чем в том же лесу, тем же летом, но в солнечную погоду днем.
Поэтому, если уж и заниматься калибровкой, то лучше разориться на литр другой азота и провести полноценную процедуру.
В конце статьи есть обновленная информация по калибровке. В любом случае, перед проведением процедуры, стоит ознакомиться и свериться со спецификацией.
Чем плох CO2?
Чем же плохо повышенное содержание углекислого газа в воздухе? А тем, что углекислый газ есть не что иное, как естественный результат нашей с вами жизнедеятельности. И не только нашей, кстати. Вдыхаем мы воздух, в котором преобладает азот и кислород, а выдыхаем все тот же азот, мало кислорода и много углекислого газа. Процесс миграции углекислого газа из крови, через альвеолы в легких происходит из-за парциального давления газов по разные стороны мембраны альвеолы. Суть парциального давления в том, что при одинаковом атмосферном давлении, если различается состав газов по разную сторону мембраны, то тот газ, которого больше с одной стороны и меньше с другой, будет пытаться проникнуть на другую сторону и уравновесить свою концентрацию. По такому же принципу работает и наполнение газом датчика MH-Z, где нет никакой принудительной вентиляции. Поэтому результаты он показывает с некоторой задержкой. Пока парциальное давление газов уравновесится.
Ну так вот, при дыхании, давление углекислого газа в капиллярах альвеолы, читай его процентное соотношение к другим газам, выше, чем во вдыхаемом воздухе, а содержание кислорода, наоборот, ниже. Углекислый газ старается выбраться из тела в атмосферу, а кислород наоборот, проникнуть в него. Для успешной работы этой системы обмена, во вдыхаемом воздухе должно быть много кислорода и мало углекислого газа. Иначе, вывод отработки из организма работать не будет. Собственно, этим и плохо высокое содержание CO2 в воздухе. Чем выше его содержание, тем хуже будет выводиться ненужный результат химических реакций наших тех. От переизбытка СО2 в воздухе и как следствие в самом теле, ухудшается самочувствие, страдает работоспособность, да и в целом идет интоксикация организма теми самыми шлаками. Именно по этой причине мамы стараются выгнать своих детей на улицу, подышать свежим воздухом, поиграть на морозце. Тем самым происходит очищение организма от ненужного ему СО2.
Во взрослом состоянии организма увещевание мам уже не действует и человек готов просидеть 12 часов в душном офисе имитируя бурную деятельность. Именно имитируя, ведь работать в атмосфере с повышенным содержанием углекислого газа нормально невозможно. Даже имитация работы будет жиденькой и вялой.
На подводных лодках и космических станция борются с повышенным содержанием СО2 в локальных атмосферах своих замкнутых миров при помощи химических фильтров, улавливающих и связывающих диоксид углерода. Но большинство людей дышат все же атмосферным воздухом планеты и для понижения концентрации углекислого газа достаточно только проветрить помещение. Строго говоря, проветривать нужно постоянно, хотя многие предпочитают жить в своих квартирах как в бетонных подводных лодках и ни под какими предлогами не открывают окна. В административных же зданиях, должна работать приточно-вытяжная вентиляция, обеспечивающая должный приток чистого и свежего воздуха.
Подключение
Подключаются датчики серии MH-Z к микроконтроллерам двумя способами. Доступно либо использование PWM (ШИМ), либо подключение по UART (последовательному порту). Мы уже знаем, что чипы ESP8266 не очень дружат с PWM под средой Android, поэтому для подключения будем использовать только и исключительно UART. Более того, подключение по последовательному порту еще и предпочтительнее, поскольку не только снижает нагрузку на сам микроконтроллер, но и позволяет использовать команды калибровки. Да и разве не здорово получать значения содержания CO2 сразу в ppm прямо с датчика, а не заниматься длительными и мучительными вычислениями? Вот именно, что стоит.
Во избежание ненужной гибели человеческих жертв, хочу обратить внимание воспитанного читателя на то, что для питания датчика MH-Z19 требуется напряжение от 4.5 и до 5.5 вольт, а для обмена данными по последовательному порту (равно как и для PWM) требуется 3.3 вольтовая логика. Поэтому при подключении датчика к оригинальным Arduino потребуется согласование уровней логики, иначе возможно повреждение устройства. Все эти параметры указаны в официальной спецификации на устройство, поэтому пренебрегать ими не стоит. Итак, подключаем питание, благо на плате WeMos есть выводы как для 5 вольт, так и для 3.3 вольт, а заодно подключаем линии передачи и приема на пины D1 и D2. И собственно после этого все должно заработать, в аппаратном понимании понятно.
Теперь, что касается программной стороны. Для того чтобы WeMos начал работать с UART необходимо использовать библиотеку для программного последовательного порта (SoftwareSerial). Библиотека позволяет организовывать UART порт на любых пинах устройства. В стандартной Arduino поставке уже есть такая библиотека, но для чипов ESP8266 нужна своя, особая библиотека (возможно, что в более свежих версиях Espressif SDK данная библиотека уже присутствует в поставке). Ее необходимо будет скачать и установить в систему, если ранее подобная операция не была произведена. Правда, после этого возможны коллизии с обычными Arduino скетчами. Нужно просто помнить по SoftwareSerial и отключать ее в случае проблем.
Для работы с MH-Z19 не требуется какая-то отдельная библиотека, весь требуемый код весьма и весьма компактен, и доступен для написания программистом самостоятельно.
Небольшое замечание по частоте опроса датчика. В спецификации не указывается максимальная частота опроса, но в некоторых обзорах упоминается, что дескать, не стоит дергать датчик чаще, чем раз в 10 секунд. Мол помрет раньше времени. Не могу согласиться с таким утверждением. Если в темноте присмотреться к датчику, то будут заметны световые импульсы, примерно каждые 3 секунды. Это сенсор проводит измерения уровня газа. Обработка показаний занимает тоже не космические величины, поэтому лично я не вижу никакой проблемы по считыванию значений не чаще чем 4-5 секунд. Тут важно попасть между вспышками, дабы получать каждый раз новый результат, а не копию старого. Хотя в моем скетче показания считываются вообще раз в 10 минут, мне важна статистика и динамика, а не моментальный результат.
В скетче, помимо всего прочего, осуществляется отправка показаний измерения CO2 и температуры на сервер ThingSpeak. Да-да, вы не должны не доверять своим глазам. Датчик MH-Z19 измеряет еще и температуру. Для получения более точного результата измерений содержания углекислого газа нужно проводить корректировку измерений по температуре самого датчика. Именно отсюда измеряемая температура слегка выше температуры окружающего воздуха и, пожалуй, может быть использована только в академических целях. Но как же получить измерения температуры? В официальной спецификации, полученной с сайта Winsen и многих других, действительно нет никакого упоминания по поводу температуры. А вот в спецификации на датчик MH-Z14 температура есть и передается она в ответе от сенсора вместе с остальными данными (байт 4).
При работе все это дело успешно подглюкивает. ThingSpeak может быть недоступен ввиду некоторого несовершенства передачи данных посредством керамической антенны, а данные, поступающие с сенсора, могут содержать ошибки. Во-первых, данные могут просто не передаваться между микроконтроллером и датчиком. Во-вторых, в данных могут быть ошибки контрольной суммы. В-третьих, значения измерений могут выходить за пределы: сильно меньше 400 или же больше или близко к границе 5000 ppm. Во всех этих случаях помогает повторная отправка или повторный запрос сенсора. Хотя в плане работы с сенсором отлично помогает отключение и повторное подключение контактов для передачи и получения данных. Возможно, что тут виноваты «сопли» в виде временных проводков.
#include <SoftwareSerial.h> #include <Wire.h> #include <ESP8266WiFi.h> #include <WiFiUdp.h> #include <ArduinoOTA.h> #include <ESP8266WebServer.h> #include <ESP8266HTTPClient.h> const char *ssid = "YourWiFiNetWork"; const char *password = "YourWiFiPasswird"; WiFiClient client; // All fucntions https://www.arduino.cc/en/Reference/WiFi & http://esp8266.github.io/Arduino/versions/2.0.0/doc/libraries.html#wifi-esp8266wifi-library #define ledPin D4 // the onboard LED unsigned long CO2Channel = ThingSpeakChannelNumber; const char *CO2WriteAPIKey = "ThingSpeakWriteAPIKey"; unsigned long CO2Millis = 600000; unsigned long MillisLast = 0; ESP8266WebServer server(80); // Simple web server String webArray[100]; // Keeps messages // CO2 sensor: SoftwareSerial mySerial(D1, D2); // RX,TX byte cmd[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79}; unsigned char response[9]; void setup() { pinMode(ledPin, OUTPUT); Serial.begin(115200); Serial.println(""); mySerial.begin(9600); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.waitForConnectResult() != WL_CONNECTED) { Serial.println("Connection Failed! Rebooting..."); delay(5000); ESP.restart(); } Serial.println("WiFi is ready..."); int lo = WiFi.RSSI(); Serial.print("WiFi signal: "); Serial.println(lo); { // Ota ArduinoOTA.onStart([]() { String type; if (ArduinoOTA.getCommand() == U_FLASH) type = "sketch"; else // U_SPIFFS type = "filesystem"; // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() Serial.println("Start updating " + type); }); ArduinoOTA.onEnd([]() { Serial.println("\nEnd"); }); ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); }); ArduinoOTA.onError([](ota_error_t error) { Serial.printf("Error[%u]: ", error); if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); else if (error == OTA_END_ERROR) Serial.println("End Failed"); }); ArduinoOTA.begin(); Serial.println("OTA is ready"); } { // Web-server init server.on("/", EhternetWebServer); server.begin(); // Starts Web-Server Serial.println("Web-server is Ready..."); } digitalWrite(ledPin, HIGH); Serial.println("Let us go...."); delay(3000); } void getCO2Data() { mySerial.write(cmd, 9); memset(response, 0, 9); mySerial.readBytes(response, 9); // CRC check int i; byte crc = 0; for (i = 1; i < 8; i++) crc += response[i]; crc = 255 - crc; crc++; // End of CRC check if (!(response[0] == 0xFF && response[1] == 0x86 && response[8] == crc)) { // Serial.println("CRC error: " + String(crc) + " / " + String(response[8])); char raw[32]; sprintf(raw, "RAW: %02X %02X %02X %02X %02X %02X %02X %02X %02X", response[0], response[1], response[2], response[3], response[4], response[5], response[6], response[7], response[8]); // Serial.println(raw); printWeb(raw); printWeb("CRC error: " + String(crc) + " / " + String(response[8])); MillisLast = CO2Millis - 10000; } else { unsigned int responseHigh = (unsigned int)response[2]; unsigned int responseLow = (unsigned int)response[3]; int ppm = (256 * responseHigh) + responseLow; int temp = response[4] - 20; Serial.println(String("-=-")); char raw[32]; sprintf(raw, "RAW: %02X %02X %02X %02X %02X %02X %02X %02X %02X", response[0], response[1], response[2], response[3], response[4], response[5], response[6], response[7], response[8]); printWeb(raw); if (ppm <= 400 || ppm > 4900) { // Serial.println("CO2: no valid data"); printWeb("CO2: no valid data"); MillisLast = CO2Millis; } else { printWeb("CO2 PPM:" + String(ppm) + "; Temp:" + String(temp)); digitalWrite(ledPin, LOW); String sURL = "http://api.thingspeak.com/update?api_key="; sURL += CO2WriteAPIKey; sURL += "&field1=" + String(ppm) + "&field2=" + String(temp); printWeb(sURL); HTTPClient http; http.begin(sURL); int httpCode = http.GET(); if (httpCode == HTTP_CODE_OK) { // Serial.printf("ThingSpeak responce code: %d\n", httpCode); printWeb("ThingSpeak responce code: " + String(httpCode)); } else { printWeb("ThingSpeak failed, error: " + String(http.errorToString(httpCode).c_str())); MillisLast = CO2Millis - 10000; } digitalWrite(ledPin, HIGH); } } } void loop() { unsigned long CurrentMillis = millis(); if (CurrentMillis - MillisLast > CO2Millis || MillisLast == 0) { MillisLast = CurrentMillis; getCO2Data(); } server.handleClient(); // Check Web-Server requests ArduinoOTA.handle(); // Handle Over The Air update delay(1000); } void EhternetWebServer() { Serial.println("WebServer responce request"); String responce = "<!DOCTYPE HTML>"; responce += "<html>"; for (int i = 0; i < 100; i++) { responce += i + 1; responce += ". "; responce += webArray[i]; responce += " "; } responce += " < hr > </ html> "; server.send(200, "text/html", responce); } void printWeb(String s) { Serial.println(s); for (int i = 99; i > 0; i--) { webArray[i] = webArray[i - 1]; } String sS = "" + String(MillisLast) + ": " + s; webArray[0] = sS; }
Помимо чтения значений датчика и отправки их в сеть к ThingSpeak, в скетче реализован механизм обновления прошивки по воздуху (OTA), и веб-сервер выводящий 100 последних сообщений, в целях отладки, разумеется.
ThingSpeak
Как видно из приведенного ниже графика, содержание диоксида углерода плавает в течение 12 часов. Датчик установлен в комнате с одним окном. В комнате периодически обитает двое взрослых и два мелких хищника. Окно постоянно приоткрыто для проветривания. Данные подаются на сервер каждые 10 минут, а затем происходит усреднение по 10 значениям. В какие-то периоды времени отправка данных невозможна, и линия графика выглядит как просто сплайн.
По графику хорошо видно, что в ночное время содержание CO2 колеблется на приемлемом уровне в районе 500 ppm, а около 8 утра наблюдается небольшой всплеск до 600. Ночью, когда любая активность минимальна, проветривания оказалось достаточно для поддержания оптимального уровня свежести воздуха. А вот в тот момент, когда все люди и звери становятся активными, содержание диоксида увеличивается. Хотя и в такой момент оно находится на вполне неплохом уровне. Затем же идет плавное снижение содержания вплоть до его номинального значения. Мелкие хищники днем спят, а их мощности метаболизма недостаточно для поддержания высокого уровня содержания CO2 в атмосфере комнаты.
Графики на ThingSpeak хороши, но не гибки. Но я не поленился и выгрузил данные сразу за несколько дней для анализа в Excel. Благо подобная функция, функция выгрузки, присутствует в ThingSpeak. Несколько несложных манипуляций и готов весьма подробный график готов. Поскольку значений выгружено много, то без дополнительных манипуляций провести усреднение непросто, но, с другой стороны, так даже интереснее. При анализе графика следует учитывать временный сдвиг в 3 часа из-за выгруженных данных в часовом поясе UTC+0.
Как видно, после начала сбора данных значения CO2 весьма и весьма высоки. Я и сам был удивлен столь неоднозначным показаниям. Но ответ нашелся быстро: в те дни на улице стояла прохладная температура с сильным ветром. И чтобы не понижать температуру в помещении до некомфортных значений, пластиковые окошки прикрыли. В результате домашние сумели надышать высокую концентрацию углекислого газа. В целом после анализа все пики были, так или иначе, связаны с постоянным пребыванием людей в помещении с датчиком и прикрытое окно. Но в общем, заметно постепенное понижение концентрации, что отображается линией тренда в виде зеленой точечной линии.
Выводы
В целом я могу заметить, что применение датчика MH-Z19 вполне оправдано в домашних проектах в качестве одного из действенных инструментов по контролю качества воздуха. Вторым по значимости будет датчик влажности, которой так не хватает в зимние периоды, когда отопление иссушивает воздух в помещении. Ну и третий из необходимых датчиков — датчик температуры. А как их соединить все в месте в одном проекте — поговорим в одной из последующих статей.
Update. Все течет, все меняется. И вот производитель данного сенсора, переехал на новый сайт и как оказалось в его ассортименте присутствует сразу три датчика MH-Z19: MH-Z19, MH-Z14A, MH-Z19B. Разнообразие датчиков меня удивило и я решил слегка разобраться в чем, собственно, разница между ними.
Похоже, что сенсор MH-Z19 без каких-либо букв появился самым первым на рынке и его дизайн можно считать оригинальным.
С виду MH-Z19B мало чем отличается от MH-Z19. Однако, различия во внешнем виде все же есть. Так, у датчика MH-Z19B отсутствуют пины SR и AOT. Вернее такие пины физически присутствуют на плате корпуса, но они не подписаны и вероятно никуда не подведены. У MH-Z19 эти пины подписаны, но производитель указывает, что они зарезервированы для каких-то производственных целей.
Распиновка оригинального датчика MH-Z19 дана в начале статьи, а MH-Z19B приведена выше. Хорошо заметно, что две ножки не подписаны. Физически они присутствуют, но есть ли там что-то непонятно.
Датчик MH-Z14A по внешнему виду отличается от своих собратьев и весьма существенно. Сперва может, конечно, показаться, что на нем просто отсутствует верхний кожух, но это не так. Форма самого "чувствительного" элемента другая, отличается даже окошко для газообмена с внешней средой. Но это еще не все. MH-Z14A способен измерять CO2 с концентрацией до 10000 ppm (или до 10% от объема газа). Плюс, как и имеет автоматическую калибровку на 0 (т.е. 400 ppm) каждые 24 часа. По причине автоматической калибровки данный датчик не рекомендуется использовать в теплицах и на рефрижераторных установках.
Вообще, с функцией автоматической калибровки присутствует какая-то неразбериха в спецификациях датчиков. Если в MH-Z14A явно указано, что такая функция присутствует и включена по-умолчанию. То в спецификации на MH-Z19B только дан способ включения и отключения калибровки.
Кстати, как оказалось, для получения более-менее достоверных результатов, необходимо датчик как следует прогреть. Вероятно, что ИК-светодиод должен выйти на какой-то особый режим свечения, чтоб результаты получались как можно ближе к true. Производитель дает время прогрева в 3 минуты. Ничего особого делать не надо, достаточно только подать рекомендуемое питание на сенсор и он сделает свое нагревательное дело самостоятельно.
Спецификация на MH-Z19
Спецификация на MH-Z19B
Спецификация на MH-Z14A
Update: Замечания по калибровке.
Датчики MHZ могут калиброваться. Как запустить данный процесс указано четко в документации. Ниже приведу пример того, как сработала автоматическая калибровка в датчике MH-Z19B.
Данный датчик пролежал у меня в загашнике года четыре как минимум, после чего он был извлечен на свет и прикручен к плате WeMos D1 R2 исправно работающей несколько лет в качестве мониторинга температуры и влажности на даче. Для работы с сенсором я использовал готовую библиотеку от Tobias Schürg MH-Z-CO2-Sensors. Библиотека позволяет работать с датчиками как по последовательному протоколу (лучший способ), так и посредством PWM (точность получается меньше, т.к. результат сильно зависит от того, чем занята Wi-Fi часть WeMos в момент измерения результатов).
После первого подключения датчик показал излишне высокий и местами подозрительный уровень CO2 в атмосфере дачной комнаты. Значения колебались в районе 1500-1600 ppm, что не просто много для загородного строения летом, когда все окна открыты, а слишком много и нереалистично. Однако, помятуя о том, что в MH-Z19B встроена автоматическая калибровка, которая включается раз в 24 часа непрерывной работы сенсора, я включил его в сеть и уехал в город.
На приведенном выше графике видно, что первоначально значения выдаваемые датчиком весьма и весьма высокие, затем, после суток прогона, значения резко понижаются до величины в 400 ppm. И на таком значении они и остаются некоторое время. Линия тут прямая по той причине, что при получении значения от датчика на уровне ниже 400 ppm данные не принимаются, т.к. явно не соответствуют среднему содержанию CO2 в атмосфере и тем более в комнате быть меньше просто не может. Затем, спустя еще несколько часов пошли реальные значения и наметилось некоторое колебание в диапазоне чуть больше 400 ppm. Колебания объясняются не соседом, который прильнул к окошку моего дома и активно дышит в помещение, а точностью определения значений самим датчиком. Точность в нижнем диапазоне, до 2000 ppm, составляет ±50 ppm + 3% от значения, что в общем-то не мало для колебаний, которые мы и наблюдаем.
Как именно работает алгоритм автоматической калибровки никто толком не знает. Но пользователь может провести самостоятельную калибровку, а затем отключить ее в сенсоре (и тут опять же вопрос, сохранятся ли значения калибровки или нет, хочется надеяться, что сохраняется). В MH-Z19B есть два варианта калибровки. Вариант Zero-Point и Span.
Zero-Point калибровка
Это рекомендуемый вариант калибровки, который необходимо провести даже если будет проводится калибровка методом Span. Запуск калибровки можно провести двумя способами, либо командой через последовательный порт, либо замкнув контакт HD на землю на время не менее 7 секунд. За это время датчик проведет несколько измерений и откалибруется. Калибровка в этом варианте происходит по общемировому значению CO2 в атмосфере которая примерно составляет 400 ppm. Для проведения калибровки высовываем датчик за окошко на время не менее 20 минут, потом запускаем калибровку. Здесь необходимо учитывать, что в городе значение CO2 будет выше, чем в деревне, а днем в деревне он будет ниже, чем там же, но ночью (про ночное дыхание растений не забываем). Похоже, что нечто похожее применяется и при автоматической калибровке.
Span калибровка
Данный вариант рекомендуется запускать после прохождения Zero-Point калибровки и выполнить ее можно только посредством команды через последовательный порт. В этом варианте подразумевается, что вы точно знаете уровень CO2 в атмосфере, в которой находится датчик. Спецификация рекомендует проводить Span-калибровку при значении 2000 ppm, но можно использовать и другое значение, т.к. оно передается вместе с командой на проведение калибровки. И да, сам датчик стоит выдержать в калибруемой атмосфере не менее 20 минут.