From 1693a84cf3290011a2990028a8c740b84ef9008e Mon Sep 17 00:00:00 2001 From: Fisch Date: Sat, 6 Nov 2021 19:38:54 +0100 Subject: [PATCH] move mhz19 to class (calibration topic missing) --- include/sensor_ldr.cpp | 3 +- include/sensor_ldr.h | 4 +- include/sensor_mhz19b.cpp | 169 +++++++++++++++++++++++++++++++ include/sensor_mhz19b.h | 52 ++++++++++ platformio.ini | 26 ++--- src/main.cpp | 204 ++++---------------------------------- 6 files changed, 257 insertions(+), 201 deletions(-) create mode 100644 include/sensor_mhz19b.cpp create mode 100644 include/sensor_mhz19b.h diff --git a/include/sensor_ldr.cpp b/include/sensor_ldr.cpp index a1e538e..2a30c48 100644 --- a/include/sensor_ldr.cpp +++ b/include/sensor_ldr.cpp @@ -18,8 +18,9 @@ void Sensor_LDR::init() //Things to be done during setup() } //Also called during setup() -void Sensor_LDR::setSettings(unsigned long senddelaymax, unsigned long readdelay) +void Sensor_LDR::setSettings(float minchange, unsigned long senddelaymax, unsigned long readdelay) { + data.minchange=minchange; data.senddelaymax=senddelaymax; data.readdelay=readdelay; } diff --git a/include/sensor_ldr.h b/include/sensor_ldr.h index a8f494c..ed3a0be 100644 --- a/include/sensor_ldr.h +++ b/include/sensor_ldr.h @@ -21,9 +21,11 @@ private: //wemos d1 mini, black wire of ldr connects to A0 with 10k to gnd. red wire connects with 1k to gnd and 2k2 to 3v3 + #ifdef SENSOR_LDR_CALIB_1 #define LDRARRAYSIZE 18 const unsigned int out_ldr[18] = {0, 30, 50, 60, 130, 170, 250, 420, 780, 1300,2600, 5000, 5350, 7700, 10900, 12000, 17000,20000}; // x10 (i.e. gets later divided by 10) const unsigned int in_ldr[18] = {0, 12, 100, 150, 350, 400, 450, 650, 730, 780, 840, 930, 948 , 970, 993, 1005, 1019, 1023}; // 0 - 1023 + #endif @@ -33,7 +35,7 @@ public: void init(); - void setSettings(unsigned long senddelaymax, unsigned long readdelay); + void setSettings(float minchange, unsigned long senddelaymax, unsigned long readdelay); void advertise(HomieNode& p_sensorNode); void sensorloop(); diff --git a/include/sensor_mhz19b.cpp b/include/sensor_mhz19b.cpp new file mode 100644 index 0000000..73abccc --- /dev/null +++ b/include/sensor_mhz19b.cpp @@ -0,0 +1,169 @@ +#include "sensor_mhz19b.h" + + + +Sensor_MHZ19B::Sensor_MHZ19B(int prx,int ptx) +{ + pin_rx=prx; + pin_tx=ptx; + + /* + * MHZ19 Library: https://platformio.org/lib/show/1620/SevSegSPI + * Software Serial Library: https://platformio.org/lib/show/168/EspSoftwareSerial + + */ + // SW Serial + //SW Serial RX: to mhz19 tx (green cable) + //SW Serial TX: to mhz19 rx (blue cable) + //co2 sensor needs 5v. Maybe better to Connect USB 5V directly (not through wemos d1 onboard diode which gives only 4.7V! at '5V' output) + + //if ABC is disabled (see in setup function) sensor should be calibrated manually. leave outdoors (=400ppm) with no direct sunlight for >20min, then connect HD pin to GND for at least 7 seconds. + /* Pinout (view from top, connector at the bottom) + * Vin, GND, NC, PWM + * | | | | + * /-----------------\ + * | | + * | | + * | | + * | | + * \-----------------/ + * | | | | | + * Vo Rx Tx NC HD + * + * [Connector] + */ + + //value will be in [ppm] +} + +void Sensor_MHZ19B::init() //Things to be done during setup() +{ + Serial.println("initializing MHZ19B"); + mhz19_swSerial->begin(BAUD_RATE_MHZ19, SWSERIAL_8N1, pin_rx, pin_tx, false, 256); + mhz19->setSerial(mhz19_swSerial); + + uint8_t mhz19abctries=10; + while(!mhz19->disableABC() && mhz19abctries>0) { //disable automatic baseline correction (abc does calibration every 24h -> needs to have 400ppm co2 level sometime during that time) + delay(500); //wait some time for mhz to be initialized + Serial.print("disableABC Failed! try="); Serial.println(mhz19abctries); + mhz19abctries--; + } + if (mhz19abctries>0) { + Serial.println("mhz19 abc disabled successfully"); + init_ok=true; + } +} + +//Also called during setup() +void Sensor_MHZ19B::setSettings(float minchange, unsigned long senddelaymax, unsigned long readdelay) +{ + data.minchange=minchange; + data.senddelaymax=senddelaymax; + data.readdelay=readdelay; +} + + +bool Sensor_MHZ19B::mhz19calibrationHandler(const HomieRange& range, const String& value) { + if (range.isRange) { + return false; //if range is given but index is not in allowed range + } + Homie.getLogger() << "mhz19 calibration " << ": " << value << endl; + + if (value=="zero") { + mhz19->calibrateZero(); + Homie.getLogger() << "mhz19 calibration " << ": " << value << endl; + #ifdef STATUSNODE + sensorNode->setProperty("status").send("MHZ19 Zero Calibration triggered"); + #endif + } else { + Homie.getLogger() << "Value outside range" << endl; + return false; + } + + return true; +} + +//Called during setup +void Sensor_MHZ19B::advertise(HomieNode& p_sensorNode) +{ + sensorNode = &p_sensorNode; + sensorNode->advertise("co2"); + #ifdef MHZ19CALIBRATIONTOPIC + sensorNode->advertise("mhz19calibration").settable(&Sensor_MHZ19B::mhz19calibrationHandler)); //not working!!! TODO: Fix it + #endif +} + +void Sensor_MHZ19B::sensorloop() +{ + if (init_ok) { + sensordata &d=data; + + bool _changed=false; + if (millis() >= (d.lastreadtime+d.readdelay)) { + mhz19_ready=mhz19->isReady(); + //d.value=mhz19->readValue(); //[ppm] + d.value=mhz19_readValue_reimplemented(mhz19_swSerial, mhz19); //[ppm] reimplemented function to fix no response issue + Homie.getLogger() << "read co2 " << ": " << d.value << " status=" << mhz19_ready << endl; + if (fabs(d.lastsentvalue-d.value)>=d.minchange){ + _changed=true; + } + d.lastreadtime=millis(); + } + + if (_changed || millis() >= (d.lastsent+d.senddelaymax)) { + Serial.print("Sending MHZ19. reason="); + if (_changed) Serial.println("change"); else Serial.println("time"); + + Homie.getLogger() << "co2 " << ": " << d.value << endl; + if (mhz19_ready){ //send no co2 values if not warmed up. can take several miniutes + sensorNode->setProperty("co2").send(String(d.value)); + }else{ + Homie.getLogger() << "co2 not ready. didnt sent" << endl; + } + + d.lastsentvalue=d.value; + + d.lastsent=millis(); + } + } +} + + +byte Sensor_MHZ19B::mhz19_getCheckSum(byte* packet) { + byte checksum = 0; + for(uint8_t i = 1; i < 8; i++) { + checksum += packet[i]; + } + checksum = 0xff - checksum; + checksum += 1; + return checksum; +} + +int Sensor_MHZ19B::mhz19_readValue_reimplemented(Stream *_streamRef, MHZ19 *_mhz19Ref) { //same function as in mhz19 library from klevytskyi, but with delay between cmd send and response check + byte CMD_READ[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79}; // Read command + unsigned int co2 = -1; + unsigned char response[9]; + _streamRef->write(CMD_READ, 9); + + unsigned long _startwait=millis(); + while (millis()-_startwait<100) { //wait for mhz19 to send response + //wait + } + + if (_streamRef->available()) { + _streamRef->readBytes(response, 9); + + byte crc = mhz19_getCheckSum(response); + + if (response[0] == 0xFF && response[1] == CMD_READ[2] && response[8] == crc) { + unsigned int responseHigh = (unsigned int) response[2]; + unsigned int responseLow = (unsigned int) response[3]; + unsigned int ppm = (256*responseHigh) + responseLow; + co2 = ppm; + } + } + + return co2; +} + + diff --git a/include/sensor_mhz19b.h b/include/sensor_mhz19b.h new file mode 100644 index 0000000..ea89a2a --- /dev/null +++ b/include/sensor_mhz19b.h @@ -0,0 +1,52 @@ +#ifndef SENSOR_MHZ19B_H +#define SENSOR_MHZ19B_H + +#include "sensordata.h" +#include + + +#include +#include + + +class Sensor_MHZ19B +{ + +private: + HomieNode *sensorNode; //reference to HomieNode + + struct sensordata data; //struct values are changed in setup() + + int pin_rx; + int pin_tx; + + bool init_ok; + + int mhz19_readValue_reimplemented(Stream *_streamRef, MHZ19 *_mhz19Ref); + byte mhz19_getCheckSum(byte* packet); + + + bool mhz19_ready; + + MHZ19 *mhz19; + SoftwareSerial *mhz19_swSerial; + #define BAUD_RATE_MHZ19 9600 + + + + //#define MHZ19CALIBRATIONTOPIC //TODO: fix it + +public: + Sensor_MHZ19B(int prx, int ptx); + + void init(); + void setSettings(float minchange, unsigned long senddelaymax, unsigned long readdelay); + void advertise(HomieNode& p_sensorNode); + void sensorloop(); + + bool mhz19calibrationHandler(const HomieRange& range, const String& value); + +}; + +#endif + diff --git a/platformio.ini b/platformio.ini index dbd352c..927668f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -91,6 +91,7 @@ build_flags = -D SENSOR_LDR -D SENSOR_LDR_PIN=A0 + -D SENSOR_LDR_CALIB_1 lib_deps = @@ -120,10 +121,9 @@ build_flags = -D SENSOR_HCSR501_PIN=D6 -D SENSOR_LDR - -D SENSOR_LDR_CALIB1 + -D SENSOR_LDR_CALIB_1 -D SENSOR_LDR_PIN=A0 -D SENSOR_LDR_minchange=10.0 - -D SENSOR_LDR_readdelay=1000*2 -D SENSOR_LDR_senddelaymax=1000*60*1 @@ -144,11 +144,11 @@ monitor_port = /dev/ttyUSB0 monitor_speed = 115200 build_flags = - -D SENSOR_MHZ19 - -D MHZ19_SERIAL_RX=D5 - -D MHZ19_SERIAL_TX=D6 - -D dataMHZ19_minchange=10 - -D dataMHZ19_readdelay=10*1000 + -D SENSOR_MHZ19B + -D SENSOR_MHZ19B_SERIAL_RX=D5 + -D SENSOR_MHZ19B_SERIAL_TX=D6 + -D SENSOR_MHZ19B_minchange=10 + -D SENSOR_MHZ19B_readdelay=10*1000 -D SENSOR_SDS018 -D SDS018_SERIAL_RX=D7 @@ -203,7 +203,7 @@ monitor_speed = 115200 build_flags = -D SENSOR_DHT22 - -D DHTPIN=D7 + -D SENSOR_DHT22_PIN=D7 -D dataDHT22_temperature_minchange=0.2 -D dataDHT22_humidity_minchange=1.0 @@ -214,11 +214,11 @@ build_flags = -D dataBH1750_minchange=10.0 -D dataBH1750_senddelaymax=1000*60*2 - -D SENSOR_MHZ19 - -D MHZ19_SERIAL_RX=D5 - -D MHZ19_SERIAL_TX=D6 - -D dataMHZ19_minchange=10 - -D dataMHZ19_readdelay=10*1000 + -D SENSOR_MHZ19B + -D SENSOR_MHZ19B_SERIAL_RX=D5 + -D SENSOR_MHZ19B_SERIAL_TX=D6 + -D SENSOR_MHZ19B_minchange=10 + -D SENSOR_MHZ19B_readdelay=10*1000 lib_deps = adafruit/DHT sensor library@1.3.10 diff --git a/src/main.cpp b/src/main.cpp index 13c69e5..be633d2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -188,54 +188,18 @@ #endif #endif -#ifdef SENSOR_MHZ19 - struct sensordata dataMHZ19; - /* - * MHZ19 Library: https://platformio.org/lib/show/1620/SevSegSPI - * Software Serial Library: https://platformio.org/lib/show/168/EspSoftwareSerial +#ifdef SENSOR_MHZ19B + #include "sensor_mhz19b.cpp" + Sensor_MHZ19B sensor_mhz19b(SENSOR_MHZ19B_SERIAL_RX,SENSOR_MHZ19B_SERIAL_TX); - */ - // SW Serial - //SW Serial RX: to mhz19 tx (green cable) - //SW Serial TX: to mhz19 rx (blue cable) - //co2 sensor needs 5v. Maybe better to Connect USB 5V directly (not through wemos d1 onboard diode which gives only 4.7V! at '5V' output) - - //if ABC is disabled (see in setup function) sensor should be calibrated manually. leave outdoors (=400ppm) with no direct sunlight for >20min, then connect HD pin to GND for at least 7 seconds. - /* Pinout (view from top, connector at the bottom) - * Vin, GND, NC, PWM - * | | | | - * /-----------------\ - * | | - * | | - * | | - * | | - * \-----------------/ - * | | | | | - * Vo Rx Tx NC HD - * - * [Connector] - */ - - - #ifndef SOFTWARESERIAL_H - #include - #define SOFTWARESERIAL_H + #ifndef SENSOR_MHZ19B_minchange + #define SENSOR_MHZ19B_minchange 10.0 #endif - - SoftwareSerial mhz19_swSerial; - #define BAUD_RATE_MHZ19 9600 - - #define MHZ19CALIBRATIONTOPIC - - #include - MHZ19 mhz19; - bool mhz19_ready=false; - int value_co2=-1; //[ppm] - - int mhz19_readValue_reimplemented(Stream *_streamRef, MHZ19 *_mhz19Ref); //declare function - - #ifdef MHZ19CALIBRATIONTOPIC - bool mhz19calibrationHandler(const HomieRange& range, const String& value); + #ifndef SENSOR_MHZ19B_senddelaymax + #define SENSOR_MHZ19B_senddelaymax 1000*60*10 + #endif + #ifndef SENSOR_MHZ19B_readdelay + #define SENSOR_MHZ19B_readdelay 1000*10 #endif #endif @@ -409,31 +373,12 @@ void setup() { #ifdef SENSOR_LDR sensor_ldr.init(); - sensor_ldr.setSettings(SENSOR_RADAR_senddelaymax,SENSOR_RADAR_readdelay); + sensor_ldr.setSettings(SENSOR_LDR_minchange,SENSOR_LDR_senddelaymax,SENSOR_LDR_readdelay); #endif - #ifdef SENSOR_MHZ19 - Serial.println("initializing mhz19"); - #ifdef dataMHZ19_minchange - dataMHZ19.minchange=dataMHZ19_minchange; - #endif - #ifdef dataMHZ19_readdelay - dataMHZ19.readdelay=dataMHZ19_readdelay; - #endif - - mhz19_swSerial.begin(BAUD_RATE_MHZ19, SWSERIAL_8N1, MHZ19_SERIAL_RX, MHZ19_SERIAL_TX, false, 256); - mhz19.setSerial(&mhz19_swSerial); - - uint8_t mhz19abctries=10; - while(!mhz19.disableABC() && mhz19abctries>0) { //disable automatic baseline correction (abc does calibration every 24h -> needs to have 400ppm co2 level sometime during that time) - delay(500); //wait some time for mhz to be initialized - Serial.print("disableABC Failed! try="); Serial.println(mhz19abctries); - mhz19abctries--; - } - if (mhz19abctries>0) { - Serial.println("mhz19 abc disabled successfully"); - } - + #ifdef SENSOR_MHZ19B + sensor_mhz19b.init(); + sensor_mhz19b.setSettings(SENSOR_MHZ19B_minchange,SENSOR_MHZ19B_senddelaymax,SENSOR_MHZ19B_readdelay); #endif @@ -566,17 +511,8 @@ void setup() { sensor_ldr.advertise(sensorNode); #endif - - - - - - - #ifdef SENSOR_MHZ19 - sensorNode.advertise("co2"); - #ifdef MHZ19CALIBRATIONTOPIC - sensorNode.advertise("mhz19calibration").settable(mhz19calibrationHandler); - #endif + #ifdef SENSOR_MHZ19B + sensor_mhz19b.advertise(sensorNode); #endif #ifdef SENSOR_SDS018 @@ -619,42 +555,6 @@ void loop() { Homie.loop(); } -#ifdef SENSOR_MHZ19 -void loop_MHZ19() -{ - sensordata &d=dataMHZ19; - - bool _changed=false; - if (millis() >= (d.lastreadtime+d.readdelay)) { - mhz19_ready=mhz19.isReady(); - //value_co2=mhz19.readValue(); //[ppm] - value_co2=mhz19_readValue_reimplemented(&mhz19_swSerial, &mhz19); //[ppm] reimplemented function to fix no response issue - Homie.getLogger() << "read co2 " << ": " << value_co2 << " status=" << mhz19_ready << endl; - if (fabs(d.lastsentvalue-value_co2)>=d.minchange){ - _changed=true; - } - d.lastreadtime=millis(); - } - - if (_changed || millis() >= (d.lastsent+d.senddelaymax)) { - Serial.print("Sending MHZ19. reason="); - if (_changed) Serial.println("change"); else Serial.println("time"); - checkESPStatus(); - - Homie.getLogger() << "co2 " << ": " << value_co2 << endl; - if (mhz19_ready){ //send no co2 values if not warmed up. can take several miniutes - sensorNode.setProperty("co2").send(String(value_co2)); - }else{ - Homie.getLogger() << "co2 not ready. didnt sent" << endl; - } - - d.lastsentvalue=value_co2; - - d.lastsent=millis(); - } -} -#endif - #ifdef SENSOR_SDS018 void loop_SDS018_pm25() { @@ -1010,11 +910,8 @@ void loopHandler() { sensor_ldr.sensorloop(); #endif - - - - #ifdef SENSOR_MHZ19 - loop_MHZ19(); + #ifdef SENSOR_MHZ19B + sensor_mhz19b.sensorloop(); #endif #ifdef SENSOR_SDS018 @@ -1055,46 +952,6 @@ void checkESPStatus() } - -#ifdef SENSOR_MHZ19 -byte mhz19_getCheckSum(byte* packet) { - byte checksum = 0; - for(uint8_t i = 1; i < 8; i++) { - checksum += packet[i]; - } - checksum = 0xff - checksum; - checksum += 1; - return checksum; -} - -int mhz19_readValue_reimplemented(Stream *_streamRef, MHZ19 *_mhz19Ref) { //same function as in mhz19 library from klevytskyi, but with delay between cmd send and response check - byte CMD_READ[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79}; // Read command - unsigned int co2 = -1; - unsigned char response[9]; - _streamRef->write(CMD_READ, 9); - - unsigned long _startwait=millis(); - while (millis()-_startwait<100) { //wait for mhz19 to send response - //wait - } - - if (_streamRef->available()) { - _streamRef->readBytes(response, 9); - - byte crc = mhz19_getCheckSum(response); - - if (response[0] == 0xFF && response[1] == CMD_READ[2] && response[8] == crc) { - unsigned int responseHigh = (unsigned int) response[2]; - unsigned int responseLow = (unsigned int) response[3]; - unsigned int ppm = (256*responseHigh) + responseLow; - co2 = ppm; - } - } - - return co2; -} -#endif - #ifdef SENSOR_SDS018 void readSDS018() { @@ -1164,31 +1021,6 @@ void ICACHE_RAM_ATTR interrupt_raingauge() #endif -/* ################################# -* ########### topic handler ####### -*/ - -#ifdef MHZ19CALIBRATIONTOPIC - bool mhz19calibrationHandler(const HomieRange& range, const String& value) { - if (range.isRange) { - return false; //if range is given but index is not in allowed range - } - Homie.getLogger() << "mhz19 calibration " << ": " << value << endl; - - if (value=="zero") { - mhz19.calibrateZero(); - Homie.getLogger() << "mhz19 calibration " << ": " << value << endl; - #ifdef STATUSNODE - sensorNode.setProperty("status").send("MHZ19 Zero Calibration triggered"); - #endif - } else { - Homie.getLogger() << "Value outside range" << endl; - return false; - } - - return true; -} -#endif /*##################################