diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino
index e8eb00501..79b1693d2 100644
--- a/sonoff/_releasenotes.ino
+++ b/sonoff/_releasenotes.ino
@@ -4,12 +4,10 @@
* Change Wemo SetBinaryState to distinguish from GetBinaryState (#1357)
* Change output of HTTP command to valid JSON only (#1363)
* Change output to valid JSON Array if needed (#1363)
+ * Add support for sensor MH-Z19(B) to be enabled with define USE_MHZ19 in user_config.h (#561, #1248)
*
* 5.10.0a
* Add (experimental) support for sensor SHT3x
- * Add support for sensor MH-Z19(B) using serial interface to be enabled with define USE_MHZ19_HARD_SERIAL in user_config.h (#561, #1248)
- * Add (experimental) support for sensor MH-Z19(B) using SoftwareSerial to be enabled with define USE_MHZ19_SOFT_SERIAL_OBSOLETE in user_config.h (#561, #1248)
- * Add (experimental) support for sensor MH-Z19(B) using stripped SoftwareSerial to be enabled with define USE_MHZ19_SOFT_SERIAL in user_config.h (#561, #1248)
* Add support for iTead SI7021 temperature and humidity sensor by consolidating DHT22 into AM2301 and using former DHT22 as SI7021 (#735)
* Fix BME280 calculation (#1051)
* Add support for BME680 using adafruit libraries (#1212)
diff --git a/sonoff/user_config.h b/sonoff/user_config.h
index bb73b3943..ebc248699 100644
--- a/sonoff/user_config.h
+++ b/sonoff/user_config.h
@@ -192,9 +192,7 @@
#define USE_WS2812_CTYPE 1 // WS2812 Color type (0 - RGB, 1 - GRB, 2 - RGBW, 3 - GRBW)
// #define USE_WS2812_DMA // DMA supports only GPIO03 (= Serial RXD) (+1k mem). When USE_WS2812_DMA is enabled expect Exceptions on Pow
-//#define USE_MHZ19_HARD_SERIAL // Add support for MH-Z19 CO2 sensor using hardware serial interface at 9600 bps on GPIO1/3 only (+1k1 code)
-//#define USE_MHZ19_SOFT_SERIAL // Add support for MH-Z19 CO2 sensor using software serial interface at 9600 bps (+2k3 code, 215 iram)
-//#define USE_MHZ19_SOFT_SERIAL_OBSOLETE // Add support for MH-Z19 CO2 sensor using software serial interface at 9600 bps (+2k3 code, 420 iram)
+//#define USE_MHZ19 // Add support for MH-Z19 CO2 sensor (+1k8 code)
#define USE_ARILUX_RF // Add support for Arilux RF remote controller (+0k8 code)
diff --git a/sonoff/xsns_15_mhz_softserial.ino b/sonoff/xsns_15_mhz19.ino
similarity index 74%
rename from sonoff/xsns_15_mhz_softserial.ino
rename to sonoff/xsns_15_mhz19.ino
index 2e9c5ae0c..4eb35fbf3 100644
--- a/sonoff/xsns_15_mhz_softserial.ino
+++ b/sonoff/xsns_15_mhz19.ino
@@ -1,7 +1,7 @@
/*
- xsns_15_mhz.ino - MH-Z19 CO2 sensor support for Sonoff-Tasmota
+ xsns_15_mhz.ino - MH-Z19(B) CO2 sensor support for Sonoff-Tasmota
- Copyright (C) 2017 Theo Arends
+ Copyright (C) 2018 Theo Arends
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,11 +17,11 @@
along with this program. If not, see .
*/
-#ifdef USE_MHZ19_SOFT_SERIAL
+#ifdef USE_MHZ19
/*********************************************************************************************\
* MH-Z19 - CO2 sensor
*
- * Based on EspEasy plugin P049 by Dmitry (rel22 ___ inbox.ru)
+ * Adapted from EspEasy plugin P049 by Dmitry (rel22 ___ inbox.ru)
**********************************************************************************************
* Filter usage
*
@@ -53,7 +53,7 @@ enum Mhz19FilterOptions {MHZ19_FILTER_OFF, MHZ19_FILTER_OFF_ALLSAMPLES, MHZ19_FI
/*********************************************************************************************/
#define MHZ19_BAUDRATE 9600
-#define MHZ19_READ_TIMEOUT 600 // Must be way less than 1000
+#define MHZ19_READ_TIMEOUT 500 // Must be way less than 1000
const char kMhz19Types[] PROGMEM = "MHZ19|MHZ19B";
@@ -61,14 +61,17 @@ const uint8_t mhz19_cmnd_read_ppm[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0
const uint8_t mhz19_cmnd_abc_enable[9] = {0xFF, 0x01, 0x79, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xE6};
const uint8_t mhz19_cmnd_abc_disable[9] = {0xFF, 0x01, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86};
-uint8_t mhz19_type = 0;
+uint8_t mhz19_type = 1;
uint16_t mhz19_last_ppm = 0;
uint8_t mhz19_filter = MHZ19_FILTER_OPTION;
-uint8_t mhz19_response[9];
bool mhz19_abc_enable = MHZ19_ABC_ENABLE;
bool mhz19_abc_must_apply = false;
char mhz19_types[7];
+float mhz19_temperature = 0;
+uint8_t mhz19_timer = 0;
+Ticker mhz19_ticker;
+
/*********************************************************************************************\
* Subset SoftwareSerial
\*********************************************************************************************/
@@ -85,7 +88,7 @@ unsigned long mhz19_serial_bit_time;
unsigned long mhz19_serial_bit_time_start;
bool Mhz19SerialValidGpioPin(uint8_t pin) {
- return (pin >= 0 && pin <= 5) || (pin >= 12 && pin <= 15);
+ return (pin >= 0 && pin <= 5) || (pin >= 9 && pin <= 10) || (pin >= 12 && pin <= 15);
}
bool Mhz19Serial(uint8_t receive_pin, uint8_t transmit_pin)
@@ -158,7 +161,7 @@ size_t Mhz19SerialWrite(const uint8_t *buffer, size_t size = 1) {
return n;
}
-void Mhz19SerialRxRead() ICACHE_RAM_ATTR; // Add 215 bytes to iram usage
+//void Mhz19SerialRxRead() ICACHE_RAM_ATTR; // Add 215 bytes to iram usage
void Mhz19SerialRxRead() {
// Advance the starting point for the samples but compensate for the
// initial delay which occurs before the interrupt is delivered
@@ -222,31 +225,29 @@ bool Mhz19CheckAndApplyFilter(uint16_t ppm, uint8_t s)
return true;
}
-bool Mhz19Read(uint16_t &p, float &t)
+void Mhz19222ms()
{
- bool status = false;
+ uint8_t mhz19_response[9];
- p = 0;
- t = NAN;
+ mhz19_timer++;
+ if (6 == mhz19_timer) { // MH-Z19 measuring cycle takes 1005 +5% ms
+ mhz19_timer = 0;
- if (mhz19_type)
- {
Mhz19SerialFlush();
- if (Mhz19SerialWrite(mhz19_cmnd_read_ppm, 9) != 9) {
- return false; // Unable to send 9 bytes
- }
- memset(mhz19_response, 0, sizeof(mhz19_response));
- uint32_t start = millis();
+ Mhz19SerialWrite(mhz19_cmnd_read_ppm, 9);
+ }
+
+ if (1 == mhz19_timer) {
+ unsigned long start = millis();
uint8_t counter = 0;
while (((millis() - start) < MHZ19_READ_TIMEOUT) && (counter < 9)) {
if (Mhz19SerialAvailable() > 0) {
mhz19_response[counter++] = Mhz19SerialRead();
- } else {
- delay(10);
}
}
- if (counter < 9){
- return false; // Timeout while trying to read
+ if (counter < 9) {
+// AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "MH-Z19 comms timeout"));
+ return;
}
byte crc = 0;
@@ -255,61 +256,55 @@ bool Mhz19Read(uint16_t &p, float &t)
}
crc = 255 - crc;
crc++;
+ if (mhz19_response[8] != crc) {
+// AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "MH-Z19 crc error"));
+ return;
+ }
+ if (0xFF != mhz19_response[0] || 0x86 != mhz19_response[1]) {
+// AddLog_P(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "MH-Z19 bad response"));
+ return;
+ }
-/*
- // Test data
- mhz19_response[0] = 0xFF;
- mhz19_response[1] = 0x86;
- mhz19_response[2] = 0x12;
- mhz19_response[3] = 0x86;
- mhz19_response[4] = 64;
-// mhz19_response[5] = 32;
- mhz19_response[8] = crc;
-*/
+ uint16_t u = (mhz19_response[6] << 8) | mhz19_response[7];
+ if (15000 == u) { // During (and only ever at) sensor boot, 'u' is reported as 15000
+ if (!mhz19_abc_enable) {
+ // After bootup of the sensor the ABC will be enabled.
+ // Thus only actively disable after bootup.
+ mhz19_abc_must_apply = true;
+ }
+ } else {
+ uint16_t ppm = (mhz19_response[2] << 8) | mhz19_response[3];
+ mhz19_temperature = ConvertTemp((float)mhz19_response[4] - 40);
+ uint8_t s = mhz19_response[5];
+ mhz19_type = (s) ? 1 : 2;
+ if (Mhz19CheckAndApplyFilter(ppm, s)) {
- if (0xFF == mhz19_response[0] && 0x86 == mhz19_response[1] && mhz19_response[8] == crc) {
- uint16_t u = (mhz19_response[6] << 8) | mhz19_response[7];
- if (15000 == u) { // During (and only ever at) sensor boot, 'u' is reported as 15000
- if (!mhz19_abc_enable) {
- // After bootup of the sensor the ABC will be enabled.
- // Thus only actively disable after bootup.
- mhz19_abc_must_apply = true;
- }
- } else {
- uint16_t ppm = (mhz19_response[2] << 8) | mhz19_response[3];
- t = ConvertTemp((float)mhz19_response[4] - 40);
- uint8_t s = mhz19_response[5];
- if (s) {
- mhz19_type = 1;
- } else {
- mhz19_type = 2;
- }
- if (Mhz19CheckAndApplyFilter(ppm, s)) {
- p = mhz19_last_ppm;
-
- if (0 == s || 64 == s) { // Reading is stable.
- if (mhz19_abc_must_apply) {
- mhz19_abc_must_apply = false;
- if (mhz19_abc_enable) {
- Mhz19SerialWrite(mhz19_cmnd_abc_enable, 9); // Sent sensor ABC Enable
- } else {
- Mhz19SerialWrite(mhz19_cmnd_abc_disable, 9); // Sent sensor ABC Disable
- }
+ if (0 == s || 64 == s) { // Reading is stable.
+ if (mhz19_abc_must_apply) {
+ mhz19_abc_must_apply = false;
+ if (mhz19_abc_enable) {
+ Mhz19SerialWrite(mhz19_cmnd_abc_enable, 9); // Sent sensor ABC Enable
+ } else {
+ Mhz19SerialWrite(mhz19_cmnd_abc_disable, 9); // Sent sensor ABC Disable
}
}
-
- status = true;
}
+
}
}
}
- return status;
}
+/*********************************************************************************************/
+
void Mhz19Init()
{
- if (Mhz19Serial(pin[GPIO_MHZ_RXD], pin[GPIO_MHZ_TXD])) {
- mhz19_type = 1;
+ mhz19_type = 0;
+ if ((pin[GPIO_MHZ_RXD] < 99) && (pin[GPIO_MHZ_TXD] < 99)) {
+ if (Mhz19Serial(pin[GPIO_MHZ_RXD], pin[GPIO_MHZ_TXD])) {
+ mhz19_type = 1;
+ mhz19_ticker.attach_ms(222, Mhz19222ms);
+ }
}
}
@@ -320,25 +315,20 @@ const char HTTP_SNS_CO2[] PROGMEM =
void Mhz19Show(boolean json)
{
- uint16_t co2;
- float t;
+ char temperature[10];
+ dtostrfd(mhz19_temperature, Settings.flag2.temperature_resolution, temperature);
+ GetTextIndexed(mhz19_types, sizeof(mhz19_types), mhz19_type -1, kMhz19Types);
- if (Mhz19Read(co2, t)) {
- char temperature[10];
- dtostrfd(t, Settings.flag2.temperature_resolution, temperature);
- GetTextIndexed(mhz19_types, sizeof(mhz19_types), mhz19_type -1, kMhz19Types);
-
- if (json) {
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_CO2 "\":%d,\"" D_TEMPERATURE "\":%s}"), mqtt_data, mhz19_types, co2, temperature);
+ if (json) {
+ snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_CO2 "\":%d,\"" D_TEMPERATURE "\":%s}"), mqtt_data, mhz19_types, mhz19_last_ppm, temperature);
#ifdef USE_DOMOTICZ
- DomoticzSensor(DZ_COUNT, co2);
+ DomoticzSensor(DZ_COUNT, mhz19_last_ppm);
#endif // USE_DOMOTICZ
#ifdef USE_WEBSERVER
- } else {
- snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_CO2, mqtt_data, mhz19_types, co2);
- snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, mhz19_types, temperature, TempUnit());
+ } else {
+ snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_CO2, mqtt_data, mhz19_types, mhz19_last_ppm);
+ snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, mhz19_types, temperature, TempUnit());
#endif // USE_WEBSERVER
- }
}
}
@@ -352,21 +342,17 @@ boolean Xsns15(byte function)
{
boolean result = false;
- if ((pin[GPIO_MHZ_RXD] < 99) && (pin[GPIO_MHZ_TXD] < 99)) {
+ if (mhz19_type) {
switch (function) {
case FUNC_XSNS_INIT:
Mhz19Init();
break;
- case FUNC_XSNS_PREP_BEFORE_TELEPERIOD:
-// Mhz19Prep();
- break;
case FUNC_XSNS_JSON_APPEND:
Mhz19Show(1);
break;
#ifdef USE_WEBSERVER
case FUNC_XSNS_WEB_APPEND:
Mhz19Show(0);
-// Mhz19Prep();
break;
#endif // USE_WEBSERVER
}
@@ -374,4 +360,4 @@ boolean Xsns15(byte function)
return result;
}
-#endif // USE_MHZ19_SOFT_SERIAL
+#endif // USE_MHZ19
diff --git a/sonoff/xsns_15_mhz_hardserial.ino b/sonoff/xsns_15_mhz_hardserial.ino
deleted file mode 100644
index 3f635436d..000000000
--- a/sonoff/xsns_15_mhz_hardserial.ino
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- xsns_15_mhz.ino - MH-Z19 CO2 sensor support for Sonoff-Tasmota
-
- Copyright (C) 2017 Theo Arends
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#ifdef USE_MHZ19_HARD_SERIAL
-/*********************************************************************************************\
- * MH-Z19 - CO2 sensor
- *
- * Supported on hardware serial interface only due to lack of iram needed by SoftwareSerial
- *
- * Based on EspEasy plugin P049 by Dmitry (rel22 ___ inbox.ru)
- *
- **********************************************************************************************
- * Filter usage
- *
- * Select filter usage on low stability readings
-\*********************************************************************************************/
-
-enum Mhz19FilterOptions {MHZ19_FILTER_OFF, MHZ19_FILTER_OFF_ALLSAMPLES, MHZ19_FILTER_FAST, MHZ19_FILTER_MEDIUM, MHZ19_FILTER_SLOW};
-
-#define MHZ19_FILTER_OPTION MHZ19_FILTER_FAST
-
-/*********************************************************************************************\
- * Source: http://www.winsen-sensor.com/d/files/infrared-gas-sensor/mh-z19b-co2-ver1_0.pdf
- *
- * Automatic Baseline Correction (ABC logic function)
- *
- * ABC logic function refers to that sensor itself do zero point judgment and automatic calibration procedure
- * intelligently after a continuous operation period. The automatic calibration cycle is every 24 hours after powered on.
- *
- * The zero point of automatic calibration is 400ppm.
- *
- * This function is usually suitable for indoor air quality monitor such as offices, schools and homes,
- * not suitable for greenhouse, farm and refrigeratory where this function should be off.
- *
- * Please do zero calibration timely, such as manual or commend calibration.
-\*********************************************************************************************/
-
-#define MHZ19_ABC_ENABLE 1 // Automatic Baseline Correction (0 = off, 1 = on (default))
-
-/*********************************************************************************************/
-
-#define MHZ19_BAUDRATE 9600
-#define MHZ19_READ_TIMEOUT 600 // Must be way less than 1000
-
-const char kMhz19Types[] PROGMEM = "MHZ19|MHZ19B";
-
-const byte mhz19_cmnd_read_ppm[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};
-const byte mhz19_cmnd_abc_enable[9] = {0xFF, 0x01, 0x79, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xE6};
-const byte mhz19_cmnd_abc_disable[9] = {0xFF, 0x01, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86};
-
-uint8_t mhz19_type = 0;
-uint16_t mhz19_last_ppm = 0;
-uint8_t mhz19_filter = MHZ19_FILTER_OPTION;
-byte mhz19_response[9];
-bool mhz19_abc_enable = MHZ19_ABC_ENABLE;
-bool mhz19_abc_must_apply = false;
-char mhz19_types[7];
-
-bool Mhz19CheckAndApplyFilter(uint16_t ppm, uint8_t s)
-{
- if (1 == s) {
- return false; // S==1 => "A" version sensor bootup, do not use values.
- }
- if (mhz19_last_ppm < 400 || mhz19_last_ppm > 5000) {
- // Prevent unrealistic values during start-up with filtering enabled.
- // Just assume the entered value is correct.
- mhz19_last_ppm = ppm;
- return true;
- }
- int32_t difference = ppm - mhz19_last_ppm;
- if (s > 0 && s < 64 && mhz19_filter != MHZ19_FILTER_OFF) {
- // Not the "B" version of the sensor, S value is used.
- // S==0 => "B" version, else "A" version
- // The S value is an indication of the stability of the reading.
- // S == 64 represents a stable reading and any lower value indicates (unusual) fast change.
- // Now we increase the delay filter for low values of S and increase response time when the
- // value is more stable.
- // This will make the reading useful in more turbulent environments,
- // where the sensor would report more rapid change of measured values.
- difference = difference * s;
- difference /= 64;
- }
- switch (mhz19_filter) {
- case MHZ19_FILTER_OFF: {
- if (s != 0 && s != 64) {
- return false;
- }
- break;
- }
- // #Samples to reach >= 75% of step response
- case MHZ19_FILTER_OFF_ALLSAMPLES:
- break; // No Delay
- case MHZ19_FILTER_FAST:
- difference /= 2;
- break; // Delay: 2 samples
- case MHZ19_FILTER_MEDIUM:
- difference /= 4;
- break; // Delay: 5 samples
- case MHZ19_FILTER_SLOW:
- difference /= 8;
- break; // Delay: 11 samples
- }
- mhz19_last_ppm = static_cast(mhz19_last_ppm + difference);
- return true;
-}
-
-bool Mhz19Read(uint16_t &p, float &t)
-{
- bool status = false;
-
- p = 0;
- t = NAN;
-
- if (mhz19_type)
- {
- Serial.flush();
- if (Serial.write(mhz19_cmnd_read_ppm, 9) != 9) {
- return false; // Unable to send 9 bytes
- }
- memset(mhz19_response, 0, sizeof(mhz19_response));
- uint32_t start = millis();
- uint8_t counter = 0;
- while (((millis() - start) < MHZ19_READ_TIMEOUT) && (counter < 9)) {
- if (Serial.available() > 0) {
- mhz19_response[counter++] = Serial.read();
- } else {
- delay(10);
- }
- }
- if (counter < 9){
- return false; // Timeout while trying to read
- }
-
- byte crc = 0;
- for (uint8_t i = 1; i < 8; i++) {
- crc += mhz19_response[i];
- }
- crc = 255 - crc;
- crc++;
-
-/*
- // Test data
- mhz19_response[0] = 0xFF;
- mhz19_response[1] = 0x86;
- mhz19_response[2] = 0x12;
- mhz19_response[3] = 0x86;
- mhz19_response[4] = 64;
-// mhz19_response[5] = 32;
- mhz19_response[8] = crc;
-*/
-
- if (0xFF == mhz19_response[0] && 0x86 == mhz19_response[1] && mhz19_response[8] == crc) {
- uint16_t u = (mhz19_response[6] << 8) | mhz19_response[7];
- if (15000 == u) { // During (and only ever at) sensor boot, 'u' is reported as 15000
- if (!mhz19_abc_enable) {
- // After bootup of the sensor the ABC will be enabled.
- // Thus only actively disable after bootup.
- mhz19_abc_must_apply = true;
- }
- } else {
- uint16_t ppm = (mhz19_response[2] << 8) | mhz19_response[3];
- t = ConvertTemp((float)mhz19_response[4] - 40);
- uint8_t s = mhz19_response[5];
- if (s) {
- mhz19_type = 1;
- } else {
- mhz19_type = 2;
- }
- if (Mhz19CheckAndApplyFilter(ppm, s)) {
- p = mhz19_last_ppm;
-
- if (0 == s || 64 == s) { // Reading is stable.
- if (mhz19_abc_must_apply) {
- mhz19_abc_must_apply = false;
- if (mhz19_abc_enable) {
- Serial.write(mhz19_cmnd_abc_enable, 9); // Sent sensor ABC Enable
- } else {
- Serial.write(mhz19_cmnd_abc_disable, 9); // Sent sensor ABC Disable
- }
- }
- }
-
- status = true;
- }
- }
- }
- }
- return status;
-}
-
-void Mhz19Init()
-{
- SetSerialBaudrate(MHZ19_BAUDRATE);
- Serial.flush();
-
- seriallog_level = 0;
- mhz19_type = 1;
-}
-
-#ifdef USE_WEBSERVER
-const char HTTP_SNS_CO2[] PROGMEM =
- "%s{s}%s " D_CO2 "{m}%d " D_UNIT_PPM "{e}"; // {s} = , {m} = | , {e} = |
-#endif // USE_WEBSERVER
-
-void Mhz19Show(boolean json)
-{
- uint16_t co2;
- float t;
-
- if (Mhz19Read(co2, t)) {
- char temperature[10];
- dtostrfd(t, Settings.flag2.temperature_resolution, temperature);
- GetTextIndexed(mhz19_types, sizeof(mhz19_types), mhz19_type -1, kMhz19Types);
-
- if (json) {
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_CO2 "\":%d,\"" D_TEMPERATURE "\":%s}"), mqtt_data, mhz19_types, co2, temperature);
-#ifdef USE_DOMOTICZ
- DomoticzSensor(DZ_COUNT, co2);
-#endif // USE_DOMOTICZ
-#ifdef USE_WEBSERVER
- } else {
- snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_CO2, mqtt_data, mhz19_types, co2);
- snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, mhz19_types, temperature, TempUnit());
-#endif // USE_WEBSERVER
- }
- }
-}
-
-/*********************************************************************************************\
- * Interface
-\*********************************************************************************************/
-
-#define XSNS_15
-
-boolean Xsns15(byte function)
-{
- boolean result = false;
-
- if ((pin[GPIO_MHZ_RXD] < 99) && (pin[GPIO_MHZ_TXD] < 99)) {
- switch (function) {
- case FUNC_XSNS_INIT:
- Mhz19Init();
- break;
- case FUNC_XSNS_PREP_BEFORE_TELEPERIOD:
-// Mhz19Prep();
- break;
- case FUNC_XSNS_JSON_APPEND:
- Mhz19Show(1);
- break;
-#ifdef USE_WEBSERVER
- case FUNC_XSNS_WEB_APPEND:
- Mhz19Show(0);
-// Mhz19Prep();
- break;
-#endif // USE_WEBSERVER
- }
- }
- return result;
-}
-
-#endif // USE_MHZ19_HARD_SERIAL
diff --git a/sonoff/xsns_15_mhz_softserial_obsolete.ino b/sonoff/xsns_15_mhz_softserial_obsolete.ino
deleted file mode 100644
index be307e467..000000000
--- a/sonoff/xsns_15_mhz_softserial_obsolete.ino
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- xsns_15_mhz.ino - MH-Z19 CO2 sensor support for Sonoff-Tasmota
-
- Copyright (C) 2017 Theo Arends
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-*/
-
-#ifdef USE_MHZ19_SOFT_SERIAL_OBSOLETE
-/*********************************************************************************************\
- * MH-Z19 - CO2 sensor
- *
- * Based on EspEasy plugin P049 by Dmitry (rel22 ___ inbox.ru)
- **********************************************************************************************
- * Filter usage
- *
- * Select filter usage on low stability readings
-\*********************************************************************************************/
-
-#include
-SoftwareSerial *SoftSerial;
-
-enum Mhz19FilterOptions {MHZ19_FILTER_OFF, MHZ19_FILTER_OFF_ALLSAMPLES, MHZ19_FILTER_FAST, MHZ19_FILTER_MEDIUM, MHZ19_FILTER_SLOW};
-
-#define MHZ19_FILTER_OPTION MHZ19_FILTER_FAST
-
-/*********************************************************************************************\
- * Source: http://www.winsen-sensor.com/d/files/infrared-gas-sensor/mh-z19b-co2-ver1_0.pdf
- *
- * Automatic Baseline Correction (ABC logic function)
- *
- * ABC logic function refers to that sensor itself do zero point judgment and automatic calibration procedure
- * intelligently after a continuous operation period. The automatic calibration cycle is every 24 hours after powered on.
- *
- * The zero point of automatic calibration is 400ppm.
- *
- * This function is usually suitable for indoor air quality monitor such as offices, schools and homes,
- * not suitable for greenhouse, farm and refrigeratory where this function should be off.
- *
- * Please do zero calibration timely, such as manual or commend calibration.
-\*********************************************************************************************/
-
-#define MHZ19_ABC_ENABLE 1 // Automatic Baseline Correction (0 = off, 1 = on (default))
-
-/*********************************************************************************************/
-
-#define MHZ19_BAUDRATE 9600
-#define MHZ19_READ_TIMEOUT 600 // Must be way less than 1000
-
-const char kMhz19Types[] PROGMEM = "MHZ19|MHZ19B";
-
-const byte mhz19_cmnd_read_ppm[9] = {0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79};
-const byte mhz19_cmnd_abc_enable[9] = {0xFF, 0x01, 0x79, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xE6};
-const byte mhz19_cmnd_abc_disable[9] = {0xFF, 0x01, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86};
-
-uint8_t mhz19_type = 0;
-uint16_t mhz19_last_ppm = 0;
-uint8_t mhz19_filter = MHZ19_FILTER_OPTION;
-byte mhz19_response[9];
-bool mhz19_abc_enable = MHZ19_ABC_ENABLE;
-bool mhz19_abc_must_apply = false;
-char mhz19_types[7];
-
-bool Mhz19CheckAndApplyFilter(uint16_t ppm, uint8_t s)
-{
- if (1 == s) {
- return false; // S==1 => "A" version sensor bootup, do not use values.
- }
- if (mhz19_last_ppm < 400 || mhz19_last_ppm > 5000) {
- // Prevent unrealistic values during start-up with filtering enabled.
- // Just assume the entered value is correct.
- mhz19_last_ppm = ppm;
- return true;
- }
- int32_t difference = ppm - mhz19_last_ppm;
- if (s > 0 && s < 64 && mhz19_filter != MHZ19_FILTER_OFF) {
- // Not the "B" version of the sensor, S value is used.
- // S==0 => "B" version, else "A" version
- // The S value is an indication of the stability of the reading.
- // S == 64 represents a stable reading and any lower value indicates (unusual) fast change.
- // Now we increase the delay filter for low values of S and increase response time when the
- // value is more stable.
- // This will make the reading useful in more turbulent environments,
- // where the sensor would report more rapid change of measured values.
- difference = difference * s;
- difference /= 64;
- }
- switch (mhz19_filter) {
- case MHZ19_FILTER_OFF: {
- if (s != 0 && s != 64) {
- return false;
- }
- break;
- }
- // #Samples to reach >= 75% of step response
- case MHZ19_FILTER_OFF_ALLSAMPLES:
- break; // No Delay
- case MHZ19_FILTER_FAST:
- difference /= 2;
- break; // Delay: 2 samples
- case MHZ19_FILTER_MEDIUM:
- difference /= 4;
- break; // Delay: 5 samples
- case MHZ19_FILTER_SLOW:
- difference /= 8;
- break; // Delay: 11 samples
- }
- mhz19_last_ppm = static_cast(mhz19_last_ppm + difference);
- return true;
-}
-
-bool Mhz19Read(uint16_t &p, float &t)
-{
- bool status = false;
-
- p = 0;
- t = NAN;
-
- if (mhz19_type)
- {
- SoftSerial->flush();
- if (SoftSerial->write(mhz19_cmnd_read_ppm, 9) != 9) {
- return false; // Unable to send 9 bytes
- }
- memset(mhz19_response, 0, sizeof(mhz19_response));
- uint32_t start = millis();
- uint8_t counter = 0;
- while (((millis() - start) < MHZ19_READ_TIMEOUT) && (counter < 9)) {
- if (SoftSerial->available() > 0) {
- mhz19_response[counter++] = SoftSerial->read();
- } else {
- delay(10);
- }
- }
- if (counter < 9){
- return false; // Timeout while trying to read
- }
-
- byte crc = 0;
- for (uint8_t i = 1; i < 8; i++) {
- crc += mhz19_response[i];
- }
- crc = 255 - crc;
- crc++;
-
-/*
- // Test data
- mhz19_response[0] = 0xFF;
- mhz19_response[1] = 0x86;
- mhz19_response[2] = 0x12;
- mhz19_response[3] = 0x86;
- mhz19_response[4] = 64;
-// mhz19_response[5] = 32;
- mhz19_response[8] = crc;
-*/
-
- if (0xFF == mhz19_response[0] && 0x86 == mhz19_response[1] && mhz19_response[8] == crc) {
- uint16_t u = (mhz19_response[6] << 8) | mhz19_response[7];
- if (15000 == u) { // During (and only ever at) sensor boot, 'u' is reported as 15000
- if (!mhz19_abc_enable) {
- // After bootup of the sensor the ABC will be enabled.
- // Thus only actively disable after bootup.
- mhz19_abc_must_apply = true;
- }
- } else {
- uint16_t ppm = (mhz19_response[2] << 8) | mhz19_response[3];
- t = ConvertTemp((float)mhz19_response[4] - 40);
- uint8_t s = mhz19_response[5];
- if (s) {
- mhz19_type = 1;
- } else {
- mhz19_type = 2;
- }
- if (Mhz19CheckAndApplyFilter(ppm, s)) {
- p = mhz19_last_ppm;
-
- if (0 == s || 64 == s) { // Reading is stable.
- if (mhz19_abc_must_apply) {
- mhz19_abc_must_apply = false;
- if (mhz19_abc_enable) {
- SoftSerial->write(mhz19_cmnd_abc_enable, 9); // Sent sensor ABC Enable
- } else {
- SoftSerial->write(mhz19_cmnd_abc_disable, 9); // Sent sensor ABC Disable
- }
- }
- }
-
- status = true;
- }
- }
- }
- }
- return status;
-}
-
-void Mhz19Init()
-{
- SoftSerial = new SoftwareSerial(pin[GPIO_MHZ_RXD], pin[GPIO_MHZ_TXD]);
- SoftSerial->begin(9600);
-
-
- mhz19_type = 1;
-}
-
-#ifdef USE_WEBSERVER
-const char HTTP_SNS_CO2[] PROGMEM =
- "%s{s}%s " D_CO2 "{m}%d " D_UNIT_PPM "{e}"; // {s} = , {m} = | , {e} = |
-#endif // USE_WEBSERVER
-
-void Mhz19Show(boolean json)
-{
- uint16_t co2;
- float t;
-
- if (Mhz19Read(co2, t)) {
- char temperature[10];
- dtostrfd(t, Settings.flag2.temperature_resolution, temperature);
- GetTextIndexed(mhz19_types, sizeof(mhz19_types), mhz19_type -1, kMhz19Types);
-
- if (json) {
- snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_CO2 "\":%d,\"" D_TEMPERATURE "\":%s}"), mqtt_data, mhz19_types, co2, temperature);
-#ifdef USE_DOMOTICZ
- DomoticzSensor(DZ_COUNT, co2);
-#endif // USE_DOMOTICZ
-#ifdef USE_WEBSERVER
- } else {
- snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_CO2, mqtt_data, mhz19_types, co2);
- snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, mhz19_types, temperature, TempUnit());
-#endif // USE_WEBSERVER
- }
- }
-}
-
-/*********************************************************************************************\
- * Interface
-\*********************************************************************************************/
-
-#define XSNS_15
-
-boolean Xsns15(byte function)
-{
- boolean result = false;
-
- if ((pin[GPIO_MHZ_RXD] < 99) && (pin[GPIO_MHZ_TXD] < 99)) {
- switch (function) {
- case FUNC_XSNS_INIT:
- Mhz19Init();
- break;
- case FUNC_XSNS_PREP_BEFORE_TELEPERIOD:
-// Mhz19Prep();
- break;
- case FUNC_XSNS_JSON_APPEND:
- Mhz19Show(1);
- break;
-#ifdef USE_WEBSERVER
- case FUNC_XSNS_WEB_APPEND:
- Mhz19Show(0);
-// Mhz19Prep();
- break;
-#endif // USE_WEBSERVER
- }
- }
- return result;
-}
-
-#endif // USE_MHZ19_SOFT_SERIAL_OBSOLETE