Merge pull request #360 from CHE77/ver4dev

добавил модуль для газовых анализаторов серии MQ
This commit is contained in:
2023-12-05 13:23:58 +03:00
committed by GitHub
4 changed files with 1152 additions and 0 deletions

View File

@@ -0,0 +1,570 @@
#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;
float aLimit;
float 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;
unsigned long lastCalibrationMillis;
float highRs = 0;
bool enableTempHumCorrection = false;
float k1;
float k2;
float b1;
float b2;
float Hum;
float 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<IoTValue> &param)
{
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;
if (lastCalibration == "00.00.00 00:00:00")
{
unsigned long miliSeconds = millis() - lastCalibrationMillis;
unsigned long seconds = miliSeconds / 1000;
unsigned long minutes = seconds / 60;
unsigned long hours = minutes / 60;
unsigned long days = hours / 24;
// miliSeconds %= 1000;
seconds %= 60;
minutes %= 60;
hours %= 24;
lastCalibration = String(days) + "d " + String(hours) + ":" + String(minutes) + ":" + String(seconds);
}
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();
lastCalibrationMillis = millis();
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();
lastCalibrationMillis = millis();
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;
}
}

View File

@@ -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": []
}
}

View File

@@ -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;
}

View File

@@ -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);