diff --git a/src/modules/sensors/MQgas/MQgas.cpp b/src/modules/sensors/MQgas/MQgas.cpp new file mode 100644 index 00000000..1ac82aad --- /dev/null +++ b/src/modules/sensors/MQgas/MQgas.cpp @@ -0,0 +1,552 @@ +#include "Global.h" +#include "classes/IoTItem.h" +#include "NTP.h" + +extern IoTGpio IoTgpio; + +#ifdef ESP8266 +#define ADC_BIT 10 +#endif +#ifdef ESP32 +#define ADC_BIT 12 +// #define analogWrite ledcWrite +#endif + +#define ADC_VALUE_MAX pow(2, ADC_BIT) + +// Это файл сенсора, в нем осуществляется чтение сенсора. +// для добавления сенсора вам нужно скопировать этот файл и заменить в нем текст AnalogAdc на название вашего сенсора +// Название должно быть уникальным, коротким и отражать суть сенсора. + +// ребенок - родитель +class MQgas : public IoTItem +{ +private: + //======================================================================================================= + // Секция переменных. + // Это секция где Вы можете объявлять переменные и объекты arduino библиотек, что бы + // впоследствии использовать их в loop и setup + byte _pin; + int currentSensor; + float _ro = 0; // расчетное сопротивления датчика. переменная для текущих расчетов + float ro_TH = 0; + float rlBoard = 0; + float R0CleanAir; // расчетное сопротивления датчика, полученное из настроек элемента + float R0CleanAirDefault; + float RlR0CleanAir; + float RlR0CleanAirDefault; + float ppmCleanAir; + float ppmCleanAirDefault; + double aLimit; + double bLimit; + byte sampleTimes = 10; + byte sampleInterval = 20; + byte intensity = 5; + bool autoCalibrationEnable = true; + unsigned int autoCalibPeriod = 24; // часы + unsigned long autoCalibTimer = 0; // мс + unsigned int warmUpTime = 60; // сек + bool _stateCalibrate = false; + bool _stateCalibrateTH = false; + String lastCalibration; + float highRs = 0; + bool enableTempHumCorrection = false; + float k1; + float k2; + float b1; + float b2; + double Hum; + double Temp; + double tempHumCorrection; + String _idTempSensor; + String _idHumSensor; + float operatingVoltage = 3.3; + double ppmResult = 0; + bool debug = true; + +public: + //======================================================================================================= + // setup() + // это аналог setup из arduino. Здесь вы можете выполнять методы инициализации сенсора. + // Такие как ...begin и подставлять в них параметры полученные из web интерфейса. + // Все параметры хранятся в перемененной parameters, вы можете прочитать любой параметр используя jsonRead функции: + // jsonReadStr, jsonReadBool, jsonReadInt + MQgas(String parameters) : IoTItem(parameters) + { + +#ifdef ESP8266 + _pin = 0; +#endif +#ifdef ESP32 + _pin = jsonReadInt(parameters, "pin-Esp32"); + // adcAttachPin(_pin); +#endif + + currentSensor = jsonReadInt(parameters, "Series"); // пока не используется + jsonRead(parameters, F("Rl on board"), rlBoard, false); + jsonRead(parameters, F("aLimit"), aLimit, false); + jsonRead(parameters, F("bLimit"), bLimit, false); + jsonRead(parameters, F("Ro in clean air"), R0CleanAir, false); // + R0CleanAirDefault = R0CleanAir; + jsonRead(parameters, F("Rl/Ro in clean air"), RlR0CleanAir, false); // соотношение + RlR0CleanAirDefault = RlR0CleanAir; + jsonRead(parameters, F("PPM in clean air"), ppmCleanAir, false); // + ppmCleanAirDefault = ppmCleanAir; + warmUpTime = jsonReadInt(parameters, "Warm up time"); + sampleInterval = jsonReadInt(parameters, "Sample interval"); + sampleTimes = jsonReadInt(parameters, "Sample times"); + intensity = jsonReadInt(parameters, "Calibtation intensity"); + autoCalibrationEnable = jsonReadBool(parameters, "autoCalibration"); + autoCalibPeriod = jsonReadInt(parameters, "autoCalib.Period"); + + enableTempHumCorrection = jsonReadBool(parameters, "TempHum correction"); + jsonRead(parameters, F("k1"), k1, false); + jsonRead(parameters, F("k2"), k2, false); + jsonRead(parameters, F("b1"), b1, false); + jsonRead(parameters, F("b2"), b2, false); + jsonRead(parameters, F("temperature"), Temp, false); + jsonRead(parameters, F("humidity"), Hum, false); + jsonRead(parameters, "idTempSensor", _idTempSensor); + jsonRead(parameters, "idHumSensor", _idHumSensor); + + jsonRead(parameters, F("operating voltage"), operatingVoltage, false); + + debug = jsonReadBool(parameters, "Debug"); + if (debug) + { + Serial.print("ADC_VALUE_MAX ="); + Serial.println(ADC_VALUE_MAX); + Serial.print("R0CleanAir ="); + Serial.println(R0CleanAir); + Serial.print("Rl/R0CleanAir ="); + Serial.println(RlR0CleanAir); + Serial.print("ppmCleanAir ="); + Serial.println(ppmCleanAir); + } + + calibrate(); // быстрая калибровка, по холодному + warmUpTime = millis() / 1000 + warmUpTime; + _stateCalibrate = false; // чтобы сделать еще одну калибровку через warmUpTime + lastCalibration = NAN; + } + + //======================================================================================================= + // это аналог loop из arduino, но вызываемый каждые int секунд, заданные в настройках. Здесь вы должны выполнить чтение вашего сенсора + void doByInterval() + { + + if (!_stateCalibrate && millis() > warmUpTime * 1000) // повторная калибровка после минимального прогрева + { + calibrate(); + } + + if (((millis() - autoCalibTimer) > autoCalibPeriod * 3600 * 1000) && autoCalibrationEnable) // автомастическа калибровка + { + autoCalibration(); + } + + ppmResult = readSensor(); + + if (_stateCalibrate) // без калибровки не выводим ничего + { + value.valD = ppmResult; + + regEvent(value.valD, "MQgas"); + } + else + { + value.valD = NAN; + regEvent(value.valD, "MQgas"); + } + } + + // получаем Temp и Hum из других элементов + void onRegEvent(IoTItem *eventItem) + { + if (eventItem) + { + if (_idTempSensor != "") + { + if (_idTempSensor == eventItem->getID()) + { + String _idTempSensorString = eventItem->getValue(); + Temp = _idTempSensorString.toFloat(); + if (debug) + { + String output = " got via eventItem: Temp = " + String(Temp); + SerialPrint("I", "MQgas", output, _id); + } + } + } + + if (_idHumSensor != "") + { + if (_idHumSensor == eventItem->getID()) + { + String _idHumSensorSting = eventItem->getValue(); + Hum = _idHumSensorSting.toFloat(); + if (debug) + { + String output = " got via eventItem: Hum = " + String(Hum); + SerialPrint("I", "MQgas", output, _id); + } + } + } + } + } + + // получаем вызовы из сценария + IoTValue execute(String command, std::vector ¶m) + { + if (command == "calibrate") // калибровка значениями по умолчанию (из настроек) + { + R0CleanAir = R0CleanAirDefault; + RlR0CleanAir = RlR0CleanAirDefault; + ppmCleanAir = ppmCleanAirDefault; + calibrate(); + SerialPrint("I", "MQgas", "calibrate() with default values", _id); + } + else if (command == "calibrateR0") + { + R0CleanAir = param[0].valD; + calibrate(); + String output = "calibrateR0(), R0CleanAir = " + String(R0CleanAir); + SerialPrint("I", "MQgas", output, _id); + } + else if (command == "calibrateRlRo") + { + R0CleanAir = 0; + ppmCleanAir = 0; + RlR0CleanAir = param[0].valD; + calibrate(); + String output = "calibrateRlRo(), RlR0CleanAir = " + String(RlR0CleanAir); + SerialPrint("I", "MQgas", output, _id); + } + else if (command == "calibratePPM") + { + R0CleanAir = 0; + RlR0CleanAir = 0; + ppmCleanAir = param[0].valD; + calibrate(); + String output = "calibratePPM(), ppmCleanAir = " + String(ppmCleanAir); + SerialPrint("I", "MQgas", output, _id); + } + else if (command == "setAutoCalibration") + { + if (param[0].isDecimal) + { + autoCalibrationEnable = param[0].valD; + } + String output = "setAutoCalibration = " + String(autoCalibrationEnable); + SerialPrint("I", "MQgas", output, _id); + } + else if (command == "runAutoCalibration") + { + autoCalibration(); + } + else if (command == "lastCalibration") // оправляем время послежней калибровки в сценарий + { + IoTValue valTmp; + valTmp.isDecimal = false; + valTmp.valS = lastCalibration; + String output = "By request: lastCalibration = " + String(valTmp.valS); + SerialPrint("I", "MQgas", output, _id); + return valTmp; + } + /* + else if (command == "enabledAutoCalibration") // оправляем время послежней калибровки в сценарий + { + IoTValue valTmp; + valTmp.isDecimal = true; + valTmp.valD = autoCalibrationEnable; + String output = "By request: enabledAutoCalibration = " + String(valTmp.valD); + SerialPrint("I", "MQgas", output, _id); + return valTmp; + } + */ + else if (command == "TempHumCorrection") // получаем Temp и Hum из сценария + { + if (param[0].isDecimal) + Temp = param[0].valD; + if (param[1].isDecimal) + Hum = param[1].valD; + String output = "TempHumCorrection() temperature = " + String(Temp) + " humidity = " + String(Hum); + SerialPrint("I", "MQgas", output, _id); + } + + return {}; // команда поддерживает возвращаемое значения. Т.е. по итогу выполнения команды или общения с внешней системой, можно вернуть значение в сценарий для дальнейшей обработки + } + + // получиение соотношения Rl/Ro на чистом воздухе + float getRlRoInCleanAir() + { + float RlR0CleanAirCalc; + + if (ppmCleanAir) // или расчитываем по ppm + { + RlR0CleanAirCalc = exp((log(ppmCleanAir) * aLimit) + bLimit); + } + else // или берем готовое их настроек + { + RlR0CleanAirCalc = RlR0CleanAir; + } + + return RlR0CleanAirCalc; + } + + // калибровка датчика + void calibrate() + { + float ro = 0; + if (R0CleanAir) // при знании сопративления датчика на чистом воздухe + { // фиксированая калибровка датчика + ro = R0CleanAir; + RlR0CleanAir = rlBoard / R0CleanAir; // просто пересчитываем для вывода в дебаг + } + else // расчет ro через RlRoInCleanAir + { + float rs = readRs(sampleTimes * intensity); // считывания показаний сопративление датчика на чистом воздухе!! + ro = rs / getRlRoInCleanAir(); + } + + if (ro && ro == ro) // проверка что не NAN + { + _ro = ro; // значение сопративления сенсора на воздухе + _stateCalibrate = true; + lastCalibration = getDateTimeDotFormated(); + String output = "Calibration successful! Ro in Clean Air = " + String(_ro); + Serial.println(); + SerialPrint("I", "MQgas", output, _id); + calibrationTH(); + } + else + { + Serial.println(); + SerialPrint("E", "MQgas", " Calibration failed! Fill one of Setting 'in clean air', check wiring ", _id); + } + } + + // выполнение автоматической калибровки + void autoCalibration() + { + _ro = highRs / getRlRoInCleanAir(); // значение сопративления сенсора на воздухе + + if (_ro && _ro == _ro) + { + _stateCalibrate = true; + lastCalibration = getDateTimeDotFormated(); + String output = "autoCalibration successful!, R0 = " + String(_ro); + Serial.println(); + SerialPrint("I", "MQgas", output, _id); + calibrationTH(); + autoCalibTimer = millis(); + highRs = 0; + } + else + { + Serial.println(); + SerialPrint("E", "MQgas", " autoCalibration failed! Fill one of Setting 'in clean air', check wiring ", _id); + } + } + + // калибровка с учетом температуры и влажности + void calibrationTH() + { + if (enableTempHumCorrection && goodReadTH()) // нормализуем к текущей температуре и влажности + { + tempHumCorrection = TempHumCorrection(); + ro_TH = _ro * tempHumCorrection; + _stateCalibrateTH = true; + String output = "TH Calibration successful! Ro_TH in Clean Air = " + String(ro_TH); + Serial.println(); + SerialPrint("I", "MQgas", output, _id); + } + else + { + Serial.println(); + SerialPrint("E", "MQgas", "TH Calibration failed! Fill Temp and Hum at Settings or add Temp and Hum sensors!", _id); + } + } + + // расчет сопротивление датчика + float CalculateResistance(int sensorADC) + { + float sensorVoltage = sensorADC * (operatingVoltage / ADC_VALUE_MAX); + float sensorResistance = (operatingVoltage - sensorVoltage) / sensorVoltage * rlBoard; + return sensorResistance; + } + + // циклическое считывание сопративления датчика + float readRs(byte sampleTimes) + { + float rs = 0; + int sensorADC; + byte error0 = 0; + byte errorMax = 0; + + for (int i = 0; i < sampleTimes; i++) + { + sensorADC = analogRead(_pin); + if (sensorADC >= ADC_VALUE_MAX - 1) + { + errorMax = 1; + if (debug) + { + String output = "Check wiring, analogRead(_pin) = " + String(sensorADC); + SerialPrint("E", "MQgas", output, _id); + } + } + else if (sensorADC == 0) + { + error0 = 1; + if (debug) + SerialPrint("E", "MQgas", "Check sensor, analogRead(_pin) = 0", _id); + } + else + { + rs += CalculateResistance(sensorADC); + delay(sampleInterval); + } + } + + if (!error0 && !errorMax) + { + rs = rs / (sampleTimes); + + if (rs > highRs && millis() > warmUpTime * 1000) // запоминаем максимальное значение сопротивления сенсора для автокалибровки + highRs = rs; + } + else + { + rs = NAN; + if (errorMax) + { + String output = "Check wiring, analogRead(_pin) = " + String(sensorADC); + SerialPrint("E", "MQgas", output, _id); + } + if (error0) + SerialPrint("E", "MQgas", "Check sensor, analogRead(_pin) = 0", _id); + } + + if (debug) + { + Serial.print("Analog: "); + Serial.print(analogRead(_pin)); + Serial.print("\tRo: "); + Serial.print(_ro); + Serial.print("\treadRs: "); + Serial.print(rs); + Serial.print("\thighRs: "); + Serial.print(highRs); + } + return rs; + } + + // расчет соотношения Rs/Ro + float readRatio() + { + float readRatio = NAN; + if (_ro) + { + float rs = readRs(sampleTimes); + if (rs) + { + readRatio = rs / _ro; // getRo(); + } + } + if (debug) + { + Serial.print(" \tRs/RoRatio: "); + Serial.print(readRatio); + } + return readRatio; + } + + // расчет значения концентрации газа + double readSensor() + { + double readSensor = NAN; + double ratio = readRatio(); + + if (ratio != 0 && ratio == ratio) // also not NAN + { + readSensor = exp((log(ratio) - bLimit) / aLimit); + if (debug) + { + Serial.print("\tGas: "); + Serial.println(readSensor, 10); + } + + if (enableTempHumCorrection && _stateCalibrateTH && goodReadTH()) // поправка на температуру и влажность + { + tempHumCorrection = TempHumCorrection(); + + ratio = ratio * tempHumCorrection; + readSensor = exp((log(ratio * _ro / ro_TH) - bLimit) / aLimit); + if (debug) + { + Serial.print("\tTHCor: "); + Serial.print(tempHumCorrection, 10); + Serial.print("\tGasTHCorrected: "); + Serial.println(readSensor, 10); + } + } + } + + return readSensor; + } + + // расчет поправки на температуру и влажность + double TempHumCorrection() + { + double correction = 1; + + double k_hum = k1 * Hum / 100 + k2; + double b_hum = b1 * Hum / 100 + b2; + correction = k_hum * Temp + b_hum; + + if (debug) + { + Serial.print("\tk_hum: "); + Serial.print(k_hum, 10); + Serial.print("\tb_hum: "); + Serial.print(b_hum, 10); + Serial.print("\tcor: "); + Serial.print(correction, 10); + } + + return correction; + } + + // проверка значний температуры и влажности + bool goodReadTH() + { + if (Hum > 0 && Hum < 95 && Temp > 0 && Temp < 70) + { + return true; + } + else + { + if (debug) + { + Serial.println(); + SerialPrint("E", "MQgas", "Wrong data from Temperature and Humidity sensor or from Settings", _id); + } + return false; + } + } + + ~MQgas(){}; +}; + +void *getAPI_MQgas(String subtype, String param) +{ + if (subtype == F("MQgas")) + { + return new MQgas(param); + } + else + { + return nullptr; + } +} diff --git a/src/modules/sensors/MQgas/modinfo.json b/src/modules/sensors/MQgas/modinfo.json new file mode 100644 index 00000000..bcaa1fd6 --- /dev/null +++ b/src/modules/sensors/MQgas/modinfo.json @@ -0,0 +1,271 @@ +{ + "menuSection": "sensors", + "configItem": [ + { + "global": 0, + "name": "MQ газовые анализаторы", + "type": "Reading", + "subtype": "MQgas", + "id": "MQ", + "widget": "anydataPpm", + "page": "Сенсоры", + "descr": "MQ-135", + "Series": 135, + "Gas": "CO2", + "Rl on board": 10, + "Ro in clean air": 0, + "Rl/Ro in clean air": 0, + "PPM in clean air": 397.13, + "aLimit": -0.42, + "bLimit": 1.92, + "Warm up time": 60, + "Sample interval": 20, + "Sample times": 10, + "Calibtation intensity": 5, + "autoCalibration": 1, + "autoCalib.Period": 24, + "TempHum correction" : 1, + "temperature": 20, + "idTempSensor": "", + "humidity": 50, + "idHumSensor": "", + "k1": 0.00672096284322792, + "k2":-0.0159038179354688, + "b1":-0.741244323718154, + "b2":1.77535862501753, + "Debug": 1, + "plus": 0, + "multiply": 1, + "round": 1, + "pin-Esp32": 34, + "operating voltage": 3.3, + "int": 15 + } + ], + "about": { + "authorName": "Alex K", + "authorContact": "https://t.me/cmche", + "authorGit": "https://github.com/CHE77/MQ-sensors_IotManager", + "exampleURL": "https://iotmanager.org/wiki", + "specialThanks": "https://github.com/amperka/TroykaMQ", + "specialThanks2": "https://forum.amperka.ru/threads/%D0%94%D0%B0%D1%82%D1%87%D0%B8%D0%BA%D0%B8-%D1%81%D0%B5%D1%80%D0%B8%D0%B8-mq-%D0%B8-%D0%B1%D0%B8%D0%B1%D0%BB%D0%B8%D0%BE%D1%82%D0%B5%D0%BA%D0%B0-troykamq.16377/page-7#post-220009", + "moduleName": "MQgas", + "moduleVersion": "1.0", + "usedRam": { + "esp32_4mb": 15, + "esp8266_4mb": 15 + }, + "title": "MQ газовые анализаторы", + "moduleDesc": "Позволяет получить концентрации газов с сенсоров серии MQ, подключаемых на аналоговый вход. Заполните свойства элемента значениями для каждого сенсора и типа газа. ‘Rl on board’, ‘aLimit’, ‘bLimit’ – обязательные для заполнения. И как минимум одно из - ‘Ro in clean air’, ‘Rl/Ro in clean air’, ‘PPM in clean air’. При запуске будет сразу запущена предварительная калибровка для определения базовой характеристики сенсора - сопротивления в чистом воздухе - Ro. Через ‘Warm up time’ будет произведена повторная калибровка уже слегка прогретого сенсора. Полный прогрев занимает сутки. Дополнительную калибровку можно вызвать из сценария, либо с помощью автоматической калибровки.", + "propInfo": { + "Series": "Номер серии из линейки сенсоров MQ- (только для обозначения для себя)", + "Gas": "Тип исследуемого газа. (только для обозначения для себя) Один сенсор может регистировать концентрацию нескольких газов", + "Rl on board": "Фиксированое сопротивление резистора делителя напряжение на плате. [кОм]", + "Ro in clean air": "Известное номинальное сопротивление сенсора на чистом воздухе или референсной среде. [кОм]", + "Rl/Ro in clean air": "Известное соотношенее сопротивления сенсора делителя напряжения к номинальному на чистом воздухе.", + "PPM in clean air": "Известное значение концентрации газа в чистом воздухе. [ppm]", + "aLimit": "Табличный коэффициент нижнего предела диапзона", + "bLimit": "Табличный коэффициент верхнего предела диапзона", + "Warm up time": "Время прогрева для дополнительной калибровки. [сек]", + "Sample interval": "Задержка между замерами на аналоговом пине.[мс]", + "Sample times": "Количестов замеров в серии для поледующего усреднения", + "Calibtation intensity": "Во сколько раз увеличить количество замеров в серии для калибровки", + "autoCalibration": "1 - включить Автокалибровку. Для переодически проветриваемых помещений", + "autoCalib.Period": "Период Автоколибровки в часах. Будет выбиратся минимальное значение ppm для рачета Сопротивления датчика на чистом воздухе.[ч]", + "TempHum correction" : "Включить (1), выключить(0) коррекцию по темературе и влажности", + "temperature": "Температутра по умолчанию [*C]. Если нет сенсора, то можно откалибровать с одними значениями, потом использовать с другими", + "idTempSensor": "id сенсора Температуры. Значения сенсора в приоритете перед значением по умолчанию", + "humidity": "Влажность по умолчанию [%]. Если нет сенсора, то можно откалибровать с одними значениями, потом использовать с другими", + "idHumSensor": "id сенсора Влажности. Значения сенсора в приоритете перед значением по умолчанию", + "k1":"коэффициент для расчета k_hum = k1 * Hum / 100 + k2 и correction = k_hum * Temp + b_hum", + "k2":"коэффициент для расчета k_hum = k1 * Hum / 100 + k2 и correction = k_hum * Temp + b_hum", + "b1":"коэффициент для расчета b_hum = b1 * Hum / 100 + b2 и correction = k_hum * Temp + b_hum", + "b2":"коэффициент для расчета b_hum = b1 * Hum / 100 + b2 и correction = k_hum * Temp + b_hum", + "Debug": "1 - для вывода промежуточных рачетных значений в Лог", + "plus": "поправочный коэффиент +c", + "multiply": "поправочный коэффиент k*", + "round": "округление", + "pin-Esp32": "Esp32: Аналоговый GPIO номер, к которому подключен датчик:32, 33, 34, 35, 36, 39. Для Esp8266 указывать не надо.", + "operating voltage": "3.3 - если используете согласование уровней на аналоговый вход. 5 - если подключаете датчик напрямую. MQ датчики 5-вольтовые, но диапазон реальных измерений как павило не выходит за 3.3В И даже если и будет превышение (что конечно не рекомендуются) то из практики известно что аналоговый пин это выдерживает. Поэтому можно подкючать напрямую и при этом даже несколько повышается разрешающая способность датчика", + "int": "Количество секунд между опросами датчика" + }, + "settings": { + "MQ-2": { + "Rl on board": 5, + "Ro in clean air": 0, + "Rl/Ro in clean air": 9.83, + "PPM in clean air": 0, + "LPG": { + "aLimit": -0.45, + "bLimit": 2.95 + }, + "Methane": { + "aLimit": -0.38, + "bLimit": 3.21 + }, + "Smoke": { + "aLimit": -0.42, + "bLimit": 3.54 + }, + "Hydrogen": { + "aLimit": -0.48, + "bLimit": 3.32 + } + }, + "MQ-3": { + "Gas": "Alcohol", + "Rl on board": 200, + "Ro in clean air": 0, + "Rl/Ro in clean air": 60, + "PPM in clean air": 0, + "aLimit": -0.66, + "bLimit": -0.62, + "multiply": 2.2 + }, + "MQ-4": { + "Gas": "Methane", + "Rl on board": 20, + "Ro in clean air": 0, + "Rl/Ro in clean air": 4.4, + "PPM in clean air": 0, + "aLimit": -0.36, + "bLimit": 2.54 + }, + "MQ-5": { + "Rl on board": 20, + "Ro in clean air": 0, + "Rl/Ro in clean air": 6.5, + "PPM in clean air": 0, + "LPG": { + "aLimit": -0.39, + "bLimit": 1.73 + }, + "Methane": { + "aLimit": -0.38, + "bLimit": 1.79 + } + }, + "MQ-6": { + "Gas": "LPG", + "Rl on board": 20, + "Ro in clean air": 0, + "Rl/Ro in clean air": 10, + "PPM in clean air": 0, + "aLimit": -0.42, + "bLimit": 2.91 + }, + "MQ-7": { + "Gas": "CO", + "Rl on board": 10, + "Ro in clean air": 0, + "Rl/Ro in clean air": 27, + "PPM in clean air": 0, + "aLimit": -0.77, + "bLimit": 3.38 + }, + "MQ-8": { + "Gas": "H2", + "Rl on board": 10, + "Ro in clean air": 0, + "Rl/Ro in clean air": 27, + "PPM in clean air": 0, + "aLimit": -1.52, + "bLimit": 10.49 + }, + "MQ-9": { + "Rl on board": 10, + "Ro in clean air": 0, + "Rl/Ro in clean air": 9.8, + "PPM in clean air": 0, + "LPG": { + "aLimit": -0.48, + "bLimit": 3.33 + }, + "Methane": { + "aLimit": -0.38, + "bLimit": 3.21 + }, + "CO": { + "aLimit": -0.48, + "bLimit": 3.10 + } + }, + "MQ-135": { + "Gas": "CO2", + "Rl on board": 10, + "aLimit": -0.42, + "bLimit": 1.92, + "Ro in clean air": 0, + "Rl/Ro in clean air": 0, + "PPM in clean air": 397.13 + } + }, + "funcInfo": [ + { + "name": "calibrate", + "descr": "Калибровка с параметрами по умолчанию" + }, + { + "name": "calibrateR0", + "descr": "Калибровка с установкой номинального сопротивления сенсора на чистом воздухе ", + "params": [ + "Ro in clean air" + ] + }, + { + "name": "calibrateRlRo", + "descr": "Калибровка с установкой соотношения сопротивления делителя напряжения к номинальному на чистом воздухе.", + "params": [ + "Rl/Ro in clean air" + ] + }, + { + "name": "calibratePPM", + "descr": "Калибровка с установкой значения концентрации газа в чистом воздухе", + "params": [ + "PPM in clean air" + ] + }, + { + "name": "setAutoCalibration", + "descr": "Включение/Выключение автокалибровки", + "params": [ + "0 - Выкл. 1 - Вкл." + ] + }, + { + "name": "runAutoCalibration", + "descr": "Принудительная автоматическая калибровка (с обнулением максимального сопротивления сенсора и перезапуском счетчика автокалибровки)" + }, + { + "name": "lastCalibration", + "descr": "Возврат время последней калибровки" + }, + { + "name": "TempHumCorrection", + "descr": "Передача значений темературы и влажности для расчета поправки", + "params": [ + "Temperature", + "Humidity" + ] + } + + ] + }, + "defActive": true, + "usedLibs": { + "esp32_4mb": [], + "esp32_4mb3f": [], + "esp32cam_4mb": [], + "esp32_16mb": [], + "esp32s2_4mb": [], + "esp8266_4mb": [], + "esp8266_16mb": [], + "esp8266_1mb": [], + "esp8266_1mb_ota": [], + "esp8285_1mb": [], + "esp8285_1mb_ota": [], + "esp8266_2mb": [], + "esp8266_2mb_ota": [] + } +} diff --git a/src/modules/sensors/MQgas/mq135alone.json b/src/modules/sensors/MQgas/mq135alone.json new file mode 100644 index 00000000..76e9eaf2 --- /dev/null +++ b/src/modules/sensors/MQgas/mq135alone.json @@ -0,0 +1,135 @@ +{ + "mark": "iotm", + "config": [ + { + "global": 0, + "type": "Reading", + "subtype": "MQgas", + "id": "MQ135", + "widget": "anydataPpm", + "page": "Сенсоры", + "descr": "MQ-135", + "Series": 135, + "Gas": "CO2", + "Rl on board": "10", + "Ro in clean air": 0, + "Rl/Ro in clean air": "0", + "PPM in clean air": "397.13", + "aLimit": "-0.42", + "bLimit": "1.92", + "Warm up time": "60", + "Sample interval": 20, + "Sample times": "10", + "Calibtation intensity": 5, + "autoCalibration": 1, + "autoCalib.Period": 1, + "TempHum correction": 1, + "k1": 0.00672096284322792, + "k2": -0.0159038179354688, + "b1": -0.741244323718154, + "b2": 1.77535862501753, + "temperature": "20", + "idTempSensor": "Tmp", + "humidity": "50", + "idHumSensor": "Hum", + "Debug": 1, + "plus": 0, + "multiply": 1, + "round": 1, + "pin-Esp32": 34, + "operating voltage": 3.3, + "int": 15 + }, + { + "global": 0, + "type": "Writing", + "subtype": "Loging", + "id": "log", + "widget": "chart1", + "page": "Графики", + "descr": "CO2", + "int": "1", + "logid": "MQ135", + "points": 300 + }, + { + "global": 0, + "type": "Reading", + "subtype": "VButton", + "id": "vbtn", + "needSave": 0, + "widget": "toggle", + "page": "Калибровка", + "descr": "Быстрая Калибровка", + "int": "0", + "val": "0" + }, + { + "global": 0, + "type": "Reading", + "subtype": "Variable", + "id": "vout", + "needSave": 0, + "widget": "anydataDef", + "page": "Калибровка", + "descr": "Последняя калибровка", + "int": "0", + "val": "0.0", + "map": "1024,1024,1,100", + "plus": 0, + "multiply": 1, + "round": 0 + }, + { + "global": 0, + "type": "Reading", + "subtype": "VButton", + "id": "vbtn13", + "needSave": 0, + "widget": "toggle", + "page": "Калибровка", + "descr": "Автокалибровка выкл/вкл", + "int": "0", + "val": "1" + }, + { + "global": 0, + "type": "Reading", + "subtype": "VButton", + "id": "vbtn50", + "needSave": 0, + "widget": "toggle", + "page": "Калибровка", + "descr": "Накопительная Калибровка", + "int": "0", + "val": "0" + } + ] +} + +scenario=>#запускаем разово калибровку без параметрова или с ними +if vbtn then { +MQ135.calibrate(); +#MQ135.calibrateR0(42); +#MQ135.calibrateRlRo(0.60); +#MQ135.calibratePPM(400); +#MQ135.TempHumCorrection(20,55); + vbtn = 0;} + +#обновляем время последней калибровки +if MQ135 then { +vout = MQ135.lastCalibration(); +} + + +#влючаем/выключаем автокалибровку +if vbtn13 == 1 then MQ135.setAutoCalibration(1) +if vbtn13 == 0 then MQ135.setAutoCalibration(0) + + +#принудительно запускаем автокалибровку +if vbtn50 then { +MQ135.runAutoCalibration(); +vbtn50 = 0; +} + diff --git a/src/modules/sensors/MQgas/mq135withBME280.json b/src/modules/sensors/MQgas/mq135withBME280.json new file mode 100644 index 00000000..fc88e799 --- /dev/null +++ b/src/modules/sensors/MQgas/mq135withBME280.json @@ -0,0 +1,176 @@ +{ + "mark": "iotm", + "config": [ + { + "global": 0, + "type": "Reading", + "subtype": "MQgas", + "id": "MQ135", + "widget": "anydataPpm", + "page": "Сенсоры", + "descr": "MQ-135", + "Series": 135, + "Gas": "CO2", + "Rl on board": "10", + "Ro in clean air": 0, + "Rl/Ro in clean air": "0", + "PPM in clean air": "397.13", + "aLimit": "-0.42", + "bLimit": "1.92", + "Warm up time": "60", + "Sample interval": 20, + "Sample times": "10", + "Calibtation intensity": 5, + "autoCalibration": 1, + "autoCalib.Period": 1, + "TempHum correction": 1, + "k1": 0.00672096284322792, + "k2": -0.0159038179354688, + "b1": -0.741244323718154, + "b2": 1.77535862501753, + "temperature": "20", + "idTempSensor": "Tmp", + "humidity": "50", + "idHumSensor": "Hum", + "Debug": 1, + "plus": 0, + "multiply": 1, + "round": 1, + "pin-Esp32": 34, + "operating voltage": 3.3, + "int": 15 + }, + { + "global": 0, + "type": "Writing", + "subtype": "Loging", + "id": "log", + "widget": "chart1", + "page": "Графики", + "descr": "CO2", + "int": "1", + "logid": "MQ135", + "points": 300 + }, + { + "global": 0, + "type": "Reading", + "subtype": "VButton", + "id": "vbtn", + "needSave": 0, + "widget": "toggle", + "page": "Калибровка", + "descr": "Быстрая Калибровка", + "int": "0", + "val": "0" + }, + { + "global": 0, + "type": "Reading", + "subtype": "Bme280t", + "id": "Tmp", + "widget": "anydataTmp", + "page": "Сенсоры", + "descr": "Температура", + "int": 15, + "addr": "0x76", + "round": 1 + }, + { + "global": 0, + "type": "Reading", + "subtype": "Bme280h", + "id": "Hum", + "widget": "anydataHum", + "page": "Сенсоры", + "descr": "Влажность", + "int": 15, + "addr": "0x76", + "round": 1 + }, + { + "global": 0, + "type": "Writing", + "subtype": "Timer", + "id": "timer0", + "widget": "nil", + "page": "", + "descr": "Таймер", + "int": "1", + "countDown": 15, + "ticker": "0", + "repeat": "1", + "needSave": 0 + }, + { + "global": 0, + "type": "Reading", + "subtype": "Variable", + "id": "vout", + "needSave": 0, + "widget": "anydataDef", + "page": "Калибровка", + "descr": "Последняя калибровка", + "int": "0", + "val": "0.0", + "map": "1024,1024,1,100", + "plus": 0, + "multiply": 1, + "round": 0 + }, + { + "global": 0, + "type": "Reading", + "subtype": "VButton", + "id": "vbtn13", + "needSave": 0, + "widget": "toggle", + "page": "Калибровка", + "descr": "Автокалибровка выкл/вкл", + "int": "0", + "val": "1" + }, + { + "global": 0, + "type": "Reading", + "subtype": "VButton", + "id": "vbtn50", + "needSave": 0, + "widget": "toggle", + "page": "Калибровка", + "descr": "Накопительная Калибровка", + "int": "0", + "val": "0" + } + ] +} + +scenario=>#запускаем разово калибровку без параметрова или с ними +if vbtn then { +MQ135.calibrate(); +#MQ135.calibrateR0(42); +#MQ135.calibrateRlRo(0.60); +#MQ135.calibratePPM(400); +#MQ135.TempHumCorrection(20,55); +#MQ135.TempHumCorrection(Tmp,Hum); + vbtn = 0;} + +#обновляем время последней калибровки +if MQ135 then { +vout = MQ135.lastCalibration(); +} + + +#влючаем/выключаем автокалибровку +if vbtn13 == 1 then MQ135.setAutoCalibration(1) +if vbtn13 == 0 then MQ135.setAutoCalibration(0) + + +#принудительно запускаем автокалибровку +if vbtn50 then { +MQ135.runAutoCalibration(); +vbtn50 = 0; +} + +#можно по таймеру передавать температуру и влажность в модуль. Но проще сразу вписать id этих элементов в настройки MQ +#if timer0 == 0 then MQ135.TempHumCorrection(Tmp,Hum);