mirror of
https://github.com/IoTManagerProject/IoTManager.git
synced 2026-03-26 22:22:16 +03:00
Added MQgas
This commit is contained in:
552
src/modules/sensors/MQgas/MQgas.cpp
Normal file
552
src/modules/sensors/MQgas/MQgas.cpp
Normal file
@@ -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<IoTValue> ¶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;
|
||||
}
|
||||
}
|
||||
271
src/modules/sensors/MQgas/modinfo.json
Normal file
271
src/modules/sensors/MQgas/modinfo.json
Normal 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": []
|
||||
}
|
||||
}
|
||||
135
src/modules/sensors/MQgas/mq135alone.json
Normal file
135
src/modules/sensors/MQgas/mq135alone.json
Normal 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;
|
||||
}
|
||||
|
||||
176
src/modules/sensors/MQgas/mq135withBME280.json
Normal file
176
src/modules/sensors/MQgas/mq135withBME280.json
Normal 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);
|
||||
Reference in New Issue
Block a user