sensoresp/include/sensor_mhz19b.cpp

159 lines
4.6 KiB
C++

#ifdef SENSOR_MHZ19B
#include "sensor_mhz19b.h"
Sensor_MHZ19B::Sensor_MHZ19B(int prx,int ptx)
{
pin_rx=prx;
pin_tx=ptx;
mhz19 = new MHZ19();
mhz19_swSerial = new SoftwareSerial();
/*
* 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;
}
//Called during setup
void Sensor_MHZ19B::advertise(HomieNode& p_sensorNode)
{
sensorNode = &p_sensorNode;
sensorNode->advertise("co2");
#ifdef MHZ19CALIBRATIONTOPIC
sensorNode->advertise("mhz19calibration").settable(mhz19calibrationHandler);
#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;
}
void Sensor_MHZ19B::calibrateZero() {
mhz19->calibrateZero();
}
#endif