mirror of https://github.com/arendst/Tasmota.git
Squashed commit of the following:
commit 5563b50abdd70806099248bea875be63b1a8acbb Author: Max <rekin.m@gmail.com> Date: Wed Jan 26 12:03:21 2022 +0300 Update xsns_95_cm1107.ino commit fbcfccb9732b3b47c7e5f2554e9d9f5765aad719 Merge: a7a792ff062458e367
Author: Max <rekin.m@gmail.com> Date: Wed Jan 26 09:44:09 2022 +0300 Merge pull request #3 from arendst/development Add command ``SspmEnergyTotal<relay>`` commit a7a792ff026872736aad991aa23702fc53e278a2 Merge: a4199127ad7664c02a
Author: Max <rekin.m@gmail.com> Date: Tue Jan 25 18:48:12 2022 +0300 Merge remote-tracking branch 'upstream/development' into CM11_sensor commit a4199127a178265c0eefc08a07c41716ce72f7d3 Author: Max <rekin.m@gmail.com> Date: Tue Jan 25 18:38:35 2022 +0300 CM11 commit ff0c88badc83ea789b217b5d400d0660573fe64c Author: Max <rekin.m@gmail.com> Date: Tue Jan 25 18:37:23 2022 +0300 Create xsns_95_cm1107.ino
This commit is contained in:
parent
62458e3676
commit
1ef08e15f1
|
@ -852,6 +852,8 @@
|
||||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||||
|
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||||
|
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||||
|
|
||||||
// Units
|
// Units
|
||||||
#define D_UNIT_AMPERE "A"
|
#define D_UNIT_AMPERE "A"
|
||||||
|
|
|
@ -852,6 +852,8 @@
|
||||||
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
#define D_GPIO_SHIFT595_RCLK "74x595 RCLK"
|
||||||
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
#define D_GPIO_SHIFT595_OE "74x595 OE"
|
||||||
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
#define D_GPIO_SHIFT595_SER "74x595 SER"
|
||||||
|
#define D_SENSOR_CM11_TX "CM110x TX"
|
||||||
|
#define D_SENSOR_CM11_RX "CM110x RX"
|
||||||
|
|
||||||
// Units
|
// Units
|
||||||
#define D_UNIT_AMPERE "A"
|
#define D_UNIT_AMPERE "A"
|
||||||
|
|
|
@ -788,6 +788,9 @@ void ResponseAppendFeatures(void)
|
||||||
#ifdef USE_SDM230
|
#ifdef USE_SDM230
|
||||||
feature8 |= 0x00100000; // xnrg_21_sdm230.ino
|
feature8 |= 0x00100000; // xnrg_21_sdm230.ino
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_CM1107
|
||||||
|
feature8 |= 0x00200000; // xsns_95_cm1107.ino
|
||||||
|
#endif
|
||||||
// feature8 |= 0x00200000;
|
// feature8 |= 0x00200000;
|
||||||
// feature8 |= 0x00400000;
|
// feature8 |= 0x00400000;
|
||||||
// feature8 |= 0x00800000;
|
// feature8 |= 0x00800000;
|
||||||
|
|
|
@ -181,6 +181,7 @@ enum UserSelectablePins {
|
||||||
GPIO_OPTION_E, // Emulated module
|
GPIO_OPTION_E, // Emulated module
|
||||||
GPIO_SDM230_TX, GPIO_SDM230_RX, // SDM230 Serial interface
|
GPIO_SDM230_TX, GPIO_SDM230_RX, // SDM230 Serial interface
|
||||||
GPIO_ADC_MQ, // Analog MQ Sensor
|
GPIO_ADC_MQ, // Analog MQ Sensor
|
||||||
|
GPIO_CM11_TXD, GPIO_CM11_RXD, // CM11 Serial interface
|
||||||
GPIO_SENSOR_END };
|
GPIO_SENSOR_END };
|
||||||
|
|
||||||
enum ProgramSelectablePins {
|
enum ProgramSelectablePins {
|
||||||
|
@ -400,7 +401,8 @@ const char kSensorNames[] PROGMEM =
|
||||||
D_SENSOR_SOLAXX1_RTS "|"
|
D_SENSOR_SOLAXX1_RTS "|"
|
||||||
D_SENSOR_OPTION " E|"
|
D_SENSOR_OPTION " E|"
|
||||||
D_SENSOR_SDM230_TX "|" D_SENSOR_SDM230_RX "|"
|
D_SENSOR_SDM230_TX "|" D_SENSOR_SDM230_RX "|"
|
||||||
D_SENSOR_ADC_MQ
|
D_SENSOR_ADC_MQ "|"
|
||||||
|
D_SENSOR_CM11_TX "|" D_SENSOR_CM11_RX "|"
|
||||||
;
|
;
|
||||||
|
|
||||||
const char kSensorNamesFixed[] PROGMEM =
|
const char kSensorNamesFixed[] PROGMEM =
|
||||||
|
@ -934,6 +936,10 @@ const uint16_t kGpioNiceList[] PROGMEM = {
|
||||||
AGPIO(GPIO_MAX7219CS),
|
AGPIO(GPIO_MAX7219CS),
|
||||||
#endif // USE_DISPLAY_MAX7219
|
#endif // USE_DISPLAY_MAX7219
|
||||||
|
|
||||||
|
#ifdef USE_CM1107
|
||||||
|
AGPIO(GPIO_CM11_TXD), // MH-Z19 Serial interface
|
||||||
|
AGPIO(GPIO_CM11_RXD), // MH-Z19 Serial interface
|
||||||
|
#endif
|
||||||
/*-------------------------------------------------------------------------------------------*\
|
/*-------------------------------------------------------------------------------------------*\
|
||||||
* ESP32 specifics
|
* ESP32 specifics
|
||||||
\*-------------------------------------------------------------------------------------------*/
|
\*-------------------------------------------------------------------------------------------*/
|
||||||
|
|
|
@ -87,6 +87,8 @@ enum LegacyUserSelectablePins {
|
||||||
GPI8_LED4_INV,
|
GPI8_LED4_INV,
|
||||||
GPI8_MHZ_TXD, // MH-Z19 Serial interface
|
GPI8_MHZ_TXD, // MH-Z19 Serial interface
|
||||||
GPI8_MHZ_RXD, // MH-Z19 Serial interface
|
GPI8_MHZ_RXD, // MH-Z19 Serial interface
|
||||||
|
GPI8_CM11_TXD, // MH-Z19 Serial interface
|
||||||
|
GPI8_CM11_RXD, // MH-Z19 Serial interface
|
||||||
GPI8_PZEM0XX_TX, // PZEM0XX Serial interface
|
GPI8_PZEM0XX_TX, // PZEM0XX Serial interface
|
||||||
GPI8_PZEM004_RX, // PZEM004T Serial interface
|
GPI8_PZEM004_RX, // PZEM004T Serial interface
|
||||||
GPI8_SAIR_TX, // SenseAir Serial interface
|
GPI8_SAIR_TX, // SenseAir Serial interface
|
||||||
|
@ -317,6 +319,8 @@ const uint16_t kGpioConvert[] PROGMEM = {
|
||||||
AGPIO(GPIO_LED1_INV) +3,
|
AGPIO(GPIO_LED1_INV) +3,
|
||||||
AGPIO(GPIO_MHZ_TXD), // MH-Z19 Serial interface
|
AGPIO(GPIO_MHZ_TXD), // MH-Z19 Serial interface
|
||||||
AGPIO(GPIO_MHZ_RXD),
|
AGPIO(GPIO_MHZ_RXD),
|
||||||
|
AGPIO(GPIO_CM11_TXD), // MH-Z19 Serial interface
|
||||||
|
AGPIO(GPIO_CM11_RXD),
|
||||||
AGPIO(GPIO_PZEM0XX_TX), // PZEM0XX Serial interface
|
AGPIO(GPIO_PZEM0XX_TX), // PZEM0XX Serial interface
|
||||||
AGPIO(GPIO_PZEM004_RX), // PZEM004T Serial interface
|
AGPIO(GPIO_PZEM004_RX), // PZEM004T Serial interface
|
||||||
AGPIO(GPIO_SAIR_TX), // SenseAir Serial interface
|
AGPIO(GPIO_SAIR_TX), // SenseAir Serial interface
|
||||||
|
|
|
@ -0,0 +1,465 @@
|
||||||
|
/*
|
||||||
|
XSNS_95_cm1107.ino - CM1107(B) CO2 sensor support for Tasmota
|
||||||
|
|
||||||
|
Copyright (C) 2021 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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_CM1107
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* CM11xx - CO2 sensor
|
||||||
|
* https://en.gassensor.com.cn/CO2Sensor/list.html
|
||||||
|
* Adapted from Mhz19 plugin by Maksim (rekin.m ___ gmail.com)
|
||||||
|
*
|
||||||
|
* Hardware Serial will be selected if GPIO1 = [CM11 Rx] and GPIO3 = [CM11 Tx]
|
||||||
|
**********************************************************************************************
|
||||||
|
* Filter usage
|
||||||
|
*
|
||||||
|
* Select filter usage on low stability readings
|
||||||
|
*
|
||||||
|
* *******************************************************************************************
|
||||||
|
* Some CM11 models has manual or continuos modes - this logic not implemented.
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
#define XSNS_95 95
|
||||||
|
|
||||||
|
enum CM11FilterOptions {CM1107_FILTER_OFF, CM1107_FILTER_FAST, CM1107_FILTER_MEDIUM, CM1107_FILTER_MEDIUM2, CM1107_FILTER_SLOW};
|
||||||
|
|
||||||
|
#ifndef CM1107_FILTER_OPTION
|
||||||
|
#define CM1107_FILTER_OPTION CM1107_FILTER_FAST
|
||||||
|
#endif
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Source: https://en.gassensor.com.cn/CO2Sensor/list.html (pdf for 1106/1107/1109 sensors)
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Automatic Baseline Correction (ABC logic function) is enabled by default but may be disabled with command
|
||||||
|
* Sensor95 0
|
||||||
|
* and enabled again with command
|
||||||
|
* Sensor95 1
|
||||||
|
*
|
||||||
|
* 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 first 24 hours and 7 days cycle 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 command calibration.
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
#include <TasmotaSerial.h>
|
||||||
|
|
||||||
|
#ifndef CO2_LOW
|
||||||
|
#define CO2_LOW 800 // Below this CO2 value show green light
|
||||||
|
#endif
|
||||||
|
#ifndef CO2_HIGH
|
||||||
|
#define CO2_HIGH 1200 // Above this CO2 value show red light
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CM1107_READ_TIMEOUT 400 // Must be way less than 1000 but enough to read 16 bytes at 9600 bps
|
||||||
|
#define CM1107_RETRY_COUNT 8
|
||||||
|
|
||||||
|
TasmotaSerial *CM11Serial;
|
||||||
|
|
||||||
|
|
||||||
|
const char CM11_ABC_ENABLED[] = "ABC is Enabled";
|
||||||
|
const char CM11_ABC_DISABLED[] = "ABC is Disabled";
|
||||||
|
|
||||||
|
//First [0] element - lenght of cmd and data
|
||||||
|
const uint8_t cmd_read[] = {0x01,0x01}; // cm11_cmnd_read_ppm
|
||||||
|
uint8_t cmd_abc_enable[] = {0x07,0x10,0x64,0x00,0x07,0x01,0x90,0x64}; // cm11_cmnd_abc_enable. Not const because can be modified
|
||||||
|
const uint8_t cmd_abc_disable[] = {0x07,0x10,0x64,0x02,0x07,0x01,0x90,0x64}; // cm11_cmnd_abc_disable
|
||||||
|
const uint8_t cmd_zeropoint[] = {0x03,0x03,0x01,0x90}; // cm11_cmnd_zeropoint_400
|
||||||
|
const uint8_t cmd_serial[] = {0x01,0x1F}; // cm11_cmnd_read_serial
|
||||||
|
const uint8_t cmd_sw_version[] = {0x01,0x1E}; // cm11_cmnd_read_sw_version
|
||||||
|
|
||||||
|
|
||||||
|
enum CM11Commands { CM11_CMND_READPPM, CM11_CMND_ABCENABLE, CM11_CMND_ABCDISABLE, CM11_CMND_ZEROPOINT, CM11_CMND_SERIAL,CM11_CMND_SW_VERSION };
|
||||||
|
const uint8_t* kCM11Commands[] PROGMEM = {
|
||||||
|
cmd_read,
|
||||||
|
cmd_abc_enable,
|
||||||
|
cmd_abc_disable,
|
||||||
|
cmd_zeropoint,
|
||||||
|
cmd_serial,
|
||||||
|
cmd_sw_version
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t cm11_type = 1;
|
||||||
|
uint16_t cm11_last_ppm = 0;
|
||||||
|
uint8_t cm11_filter = CM1107_FILTER_OPTION;
|
||||||
|
bool cm11_abc_must_apply = false;
|
||||||
|
|
||||||
|
float cm11_temperature = 0;
|
||||||
|
uint16_t cm11_humidity = 0;
|
||||||
|
char cm11_sw_version[30] = {0};
|
||||||
|
char cm11_serial_number[21] = {0};
|
||||||
|
uint8_t cm11_retry = CM1107_RETRY_COUNT;
|
||||||
|
uint8_t cm11_received = 0;
|
||||||
|
uint8_t cm11_state = 0;
|
||||||
|
uint16_t ppm_low_limit = 0;
|
||||||
|
uint16_t ppm_high_limit = 5000;
|
||||||
|
|
||||||
|
/*********************************************************************************************/
|
||||||
|
//256-(HEAD+LEN+CMD+DATA)%256
|
||||||
|
uint8_t CM11CalculateChecksum(uint8_t *array,uint8_t start, uint8_t len)
|
||||||
|
{
|
||||||
|
uint8_t checksum = 0;
|
||||||
|
for (uint8_t i = start; i < len; i++) {
|
||||||
|
checksum += array[i];
|
||||||
|
}
|
||||||
|
checksum = checksum%256;
|
||||||
|
checksum = 255 - checksum;
|
||||||
|
return (checksum +1);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t CM11SendCmd(uint8_t command_id)
|
||||||
|
{
|
||||||
|
uint8_t len =kCM11Commands[command_id][0];
|
||||||
|
uint8_t cm11_send[len+3];// = {0}; //Fix length
|
||||||
|
memset( cm11_send, 0, (len+3)*sizeof(uint8_t) );
|
||||||
|
|
||||||
|
cm11_send[0] = 0x11; // Start byte, fixed
|
||||||
|
|
||||||
|
memcpy_P(&cm11_send[1], kCM11Commands[command_id], (len+1) * sizeof(uint8_t));
|
||||||
|
|
||||||
|
cm11_send[len+2] = CM11CalculateChecksum(cm11_send,0, len+2);
|
||||||
|
|
||||||
|
#ifdef DEBUG_TASMOTA_SENSOR
|
||||||
|
char cmdFull[len+30];// = {0};
|
||||||
|
memset( cmdFull, 0, (len+3)*sizeof(char) );
|
||||||
|
for(int i=0, j=0;i<len+3;i=i+1, j=j+3)
|
||||||
|
{
|
||||||
|
sprintf(&cmdFull[j],"%02x ", cm11_send[i]);
|
||||||
|
}
|
||||||
|
AddLog(LOG_LEVEL_DEBUG, PSTR("Final CM11Command: %s"),cmdFull);
|
||||||
|
#endif // DEBUG_TASMOTA_SENSOR
|
||||||
|
cm11_received = 0;
|
||||||
|
cm11_state = 0;
|
||||||
|
return CM11Serial->write(cm11_send, sizeof(cm11_send));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************/
|
||||||
|
|
||||||
|
bool CM11CheckAndApplyFilter(uint16_t ppm, uint8_t drift)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG_TASMOTA_SENSOR
|
||||||
|
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "CM11 ppm: %u, last ppm: %u"),ppm, cm11_last_ppm);
|
||||||
|
#endif //DEBUG_TASMOTA_SENSOR
|
||||||
|
if (cm11_last_ppm < ppm_low_limit || cm11_last_ppm > ppm_high_limit) {
|
||||||
|
// Prevent unrealistic values during start-up with filtering enabled.
|
||||||
|
// Just assume the entered value is correct.
|
||||||
|
cm11_last_ppm = ppm;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
int32_t difference = ppm - cm11_last_ppm;
|
||||||
|
if (drift > 0 && cm11_filter != CM1107_FILTER_OFF) {
|
||||||
|
difference >>= CM1107_FILTER_SLOW; // If drifting values -> apply slow filter
|
||||||
|
}else if (CM1107_FILTER_OFF == cm11_filter) {
|
||||||
|
if (drift != 0 ) {
|
||||||
|
return false; //Do not alarm on such unstable values
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
difference >>=cm11_filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "CM11 diff: %d"),difference);
|
||||||
|
cm11_last_ppm = static_cast<uint16_t>(cm11_last_ppm + difference);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CM11EverySecond(void)
|
||||||
|
{
|
||||||
|
cm11_state++;
|
||||||
|
//If more than one command was send
|
||||||
|
//Reading preffered
|
||||||
|
if (CM11Serial->available() > 0){
|
||||||
|
cm11_received = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((8 == cm11_state && cm11_received) || 16 == cm11_state) { // Every 8 sec start a CM11 measuring cycle (which takes 1005 +5% ms)
|
||||||
|
cm11_state = 0;
|
||||||
|
|
||||||
|
if (cm11_retry) {
|
||||||
|
cm11_retry--;
|
||||||
|
if (!cm11_retry) {
|
||||||
|
cm11_last_ppm = 0;
|
||||||
|
cm11_temperature = 0;
|
||||||
|
cm11_humidity = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CM11Serial->flush(); // Sync reception
|
||||||
|
CM11SendCmd(CM11_CMND_READPPM);
|
||||||
|
cm11_received = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((cm11_state > 2) && !cm11_received) { // Start reading response after 3 seconds every second until received
|
||||||
|
uint8_t cm11_response[50];
|
||||||
|
unsigned long start = millis();
|
||||||
|
uint8_t counter = 0;
|
||||||
|
uint8_t resp_len = 50;
|
||||||
|
while (((millis() - start) < CM1107_READ_TIMEOUT) && (counter < resp_len)) {
|
||||||
|
if (CM11Serial->available() > 0) {
|
||||||
|
cm11_response[counter++] = CM11Serial->read();
|
||||||
|
if (counter ==2 && cm11_response[0] == 0x16) {
|
||||||
|
resp_len = cm11_response[1] +3 ;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
delay(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (counter < 5) {
|
||||||
|
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "CM1107 timeout (command sent, no responce"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t crc = CM11CalculateChecksum(cm11_response,0, cm11_response[1]+2);
|
||||||
|
if (cm11_response[cm11_response[1]+2] != crc) {
|
||||||
|
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "CM1107 crc error"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (0x16 != cm11_response[0]) {
|
||||||
|
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "CM1107 bad response"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cm11_received = 1;
|
||||||
|
|
||||||
|
if (cm11_response[2]==cmd_read[1]){ //0x01 - read command
|
||||||
|
uint16_t ppm = (cm11_response[3] << 8) | cm11_response[4];
|
||||||
|
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "CM11 PPM: %u"),ppm);
|
||||||
|
if (ppm ==550) { // Preheating mode, fixed value.
|
||||||
|
//DOCs says that preheating is cm11_response[5] & (1 << 0)) ==1 (first bit ==1), but mine sensor (CM1107, sw V1.07.0.02 )
|
||||||
|
// set first bit 0 when preheating at switch to 1 then finished.
|
||||||
|
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "CM11 preheating"));
|
||||||
|
if (Settings->SensorBits1.mhz19b_abc_disable) {
|
||||||
|
// After bootup of the sensor the ABC will be enabled.
|
||||||
|
// Thus only actively disable after bootup.
|
||||||
|
cm11_abc_must_apply = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(cm11_response[1] ==13) { // CM1107T with temperature and humidity
|
||||||
|
cm11_temperature = (float)(((cm11_response[7] << 8) | cm11_response[8]) - 4685)/100.0f;
|
||||||
|
cm11_humidity = (((cm11_response[9] << 8) | cm11_response[10]) - 600)/100;
|
||||||
|
cm11_type = 2;
|
||||||
|
}
|
||||||
|
uint8_t cm11_drift = (cm11_response[5] & (1 << 7)) ? 1:0;
|
||||||
|
AddLog(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "CM11 flags DF3: %02x"),cm11_response[5]);
|
||||||
|
|
||||||
|
if (CM11CheckAndApplyFilter(ppm,cm11_drift)) {
|
||||||
|
cm11_retry = CM1107_RETRY_COUNT;
|
||||||
|
#ifdef USE_LIGHT
|
||||||
|
LightSetSignal(CO2_LOW, CO2_HIGH, cm11_last_ppm);
|
||||||
|
#endif // USE_LIGHT
|
||||||
|
|
||||||
|
if (!cm11_drift) { // Measuring is stable.
|
||||||
|
if (cm11_abc_must_apply) {
|
||||||
|
cm11_abc_must_apply = false;
|
||||||
|
if (!Settings->SensorBits1.mhz19b_abc_disable) {
|
||||||
|
CM11SendCmd(CM11_CMND_ABCENABLE);
|
||||||
|
} else {
|
||||||
|
CM11SendCmd(CM11_CMND_ABCDISABLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cm11_response[2]==cmd_sw_version[1]){ //0x1E - read SW version
|
||||||
|
memcpy_P(cm11_sw_version, &cm11_response[3], cm11_response[1] * sizeof(uint8_t));
|
||||||
|
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_DEBUG "SW version: %s"),cm11_sw_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cm11_response[2]==cmd_serial[1]){ //0x1F - read serial
|
||||||
|
// Serial num coded as 5 integers 0..9999. Each integer is uint16_t size
|
||||||
|
for (uint8_t i=0; i<cm11_response[1]-1;i=i+2){ //for each 2 uint8_t
|
||||||
|
uint16_t v = (cm11_response[3+i] <<8) | cm11_response[3+i+1]; // get int value
|
||||||
|
sprintf_P(cm11_serial_number+i*2,"%04u", v); //print int value to result str
|
||||||
|
}
|
||||||
|
AddLog(LOG_LEVEL_INFO, PSTR(D_LOG_DEBUG "Serial number: %s"),cm11_serial_number);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Command Sensor15
|
||||||
|
*
|
||||||
|
* 0 - ABC Off
|
||||||
|
* 1 - ABC On (Default)
|
||||||
|
* 2 - Manual start = ABC Off (set zero point)
|
||||||
|
* 3 - Get SW version
|
||||||
|
* 4 - Get serial
|
||||||
|
* 5 - Set limits
|
||||||
|
* 6 - Set filter mode
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
bool CM11CommandSensor(void)
|
||||||
|
{
|
||||||
|
bool serviced = true;
|
||||||
|
|
||||||
|
switch (XdrvMailbox.payload) {
|
||||||
|
case 0:
|
||||||
|
Settings->SensorBits1.mhz19b_abc_disable = true;
|
||||||
|
CM11SendCmd(CM11_CMND_ABCDISABLE);
|
||||||
|
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_95, CM11_ABC_DISABLED);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Settings->SensorBits1.mhz19b_abc_disable = false;
|
||||||
|
CM11SendCmd(CM11_CMND_ABCENABLE);
|
||||||
|
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_95, CM11_ABC_ENABLED);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
CM11SendCmd(CM11_CMND_ZEROPOINT);
|
||||||
|
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_95, D_JSON_ZERO_POINT_CALIBRATION);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
CM11SendCmd(CM11_CMND_SW_VERSION);
|
||||||
|
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_95, "CM11 sw version");
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
CM11SendCmd(CM11_CMND_SERIAL);
|
||||||
|
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_95, "CM11 serial number");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Set ppm limits: 5,<low_limit>,<high_limit>
|
||||||
|
// ABS period cmd(with enabling ABS): 1,[1..30]
|
||||||
|
uint32_t parm[3] = { 0 };
|
||||||
|
ParseParameters(3, parm);
|
||||||
|
switch (parm[0]) {
|
||||||
|
case 1:
|
||||||
|
if (parm[1]>=1 && parm[1]<=30){
|
||||||
|
cmd_abc_enable[4] = parm[1]; //set uint8 from uint32 *o*, but value limited by 30
|
||||||
|
Settings->SensorBits1.mhz19b_abc_disable = false;
|
||||||
|
CM11SendCmd(CM11_CMND_ABCENABLE);
|
||||||
|
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_95, CM11_ABC_ENABLED);
|
||||||
|
} else {
|
||||||
|
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_95, "Valid period value: [1..30]");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// Set sensor ppm limit. Default 0..5000, but some sensors has another range.
|
||||||
|
case 5:
|
||||||
|
if(parm[1]>=0 && parm[1] <=10000 && parm[2]>=0 && parm[2] <=10000 && parm[1]<parm[2]) {
|
||||||
|
ppm_low_limit = parm[1];
|
||||||
|
ppm_high_limit = parm[2];
|
||||||
|
}else{
|
||||||
|
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_95, "Invalid PPM limits: [0..10000]");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
// Set filter mode
|
||||||
|
case 6:
|
||||||
|
if (parm[1] >=0 && parm[1]<=4) {
|
||||||
|
cm11_filter = parm[1];
|
||||||
|
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_95, "CM11 set filter mode");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_95, "Invalid filter mode: [0..4]. 0 - Off, 1 (Fast) -> 4 (Slow)");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Response_P(S_JSON_SENSOR_INDEX_SVALUE, XSNS_95, "Unknown command");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return serviced;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************/
|
||||||
|
|
||||||
|
void CM11Init(void)
|
||||||
|
{
|
||||||
|
cm11_type = 0;
|
||||||
|
if (PinUsed(GPIO_CM11_RXD) && PinUsed(GPIO_CM11_TXD)) {
|
||||||
|
CM11Serial = new TasmotaSerial(Pin(GPIO_CM11_RXD), Pin(GPIO_CM11_TXD), 1);
|
||||||
|
if (CM11Serial->begin(9600)) {
|
||||||
|
if (CM11Serial->hardwareSerial()) { ClaimSerial(); }
|
||||||
|
cm11_type = 1;
|
||||||
|
CM11SendCmd(CM11_CMND_SW_VERSION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CM11Show(bool json)
|
||||||
|
{
|
||||||
|
if (json) {
|
||||||
|
ResponseAppend_P(PSTR(",\"CM11\":{\"" D_JSON_CO2 "\":%d,\"" D_JSON_VERSION "\":\"%s\",\"Serial number\":\"%s\""),
|
||||||
|
cm11_last_ppm, cm11_sw_version, cm11_serial_number);
|
||||||
|
if(cm11_type == 2) { // With temp and humidity
|
||||||
|
ResponseAppend_P(PSTR(",\"" D_JSON_TEMPERATURE "\":%*_f"),
|
||||||
|
Settings->flag2.temperature_resolution, &cm11_temperature);
|
||||||
|
}
|
||||||
|
ResponseAppend_P(PSTR("}"));
|
||||||
|
#ifdef USE_DOMOTICZ
|
||||||
|
if (0 == TasmotaGlobal.tele_period) {
|
||||||
|
DomoticzSensor(DZ_AIRQUALITY, cm11_last_ppm);
|
||||||
|
if(cm11_type == 2) { // With temp and humidity
|
||||||
|
DomoticzFloatSensor(DZ_TEMP, cm11_temperature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // USE_DOMOTICZ
|
||||||
|
#ifdef USE_WEBSERVER
|
||||||
|
} else {
|
||||||
|
WSContentSend_PD(HTTP_SNS_CO2, "CM11", cm11_last_ppm);
|
||||||
|
if(cm11_type == 2) { // With temp and humidity
|
||||||
|
WSContentSend_Temp("CM11", cm11_temperature);
|
||||||
|
}
|
||||||
|
#endif // USE_WEBSERVER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************************************\
|
||||||
|
* Interface
|
||||||
|
\*********************************************************************************************/
|
||||||
|
|
||||||
|
bool Xsns95(uint8_t function)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
if (cm11_type) {
|
||||||
|
switch (function) {
|
||||||
|
case FUNC_INIT:
|
||||||
|
CM11Init();
|
||||||
|
break;
|
||||||
|
case FUNC_EVERY_SECOND:
|
||||||
|
CM11EverySecond();
|
||||||
|
break;
|
||||||
|
case FUNC_COMMAND_SENSOR:
|
||||||
|
if (XSNS_95 == XdrvMailbox.index) {
|
||||||
|
result = CM11CommandSensor();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FUNC_JSON_APPEND:
|
||||||
|
CM11Show(1);
|
||||||
|
break;
|
||||||
|
#ifdef USE_WEBSERVER
|
||||||
|
case FUNC_WEB_SENSOR:
|
||||||
|
CM11Show(0);
|
||||||
|
break;
|
||||||
|
#endif // USE_WEBSERVER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // USE_CM1107
|
|
@ -63,6 +63,8 @@ DSB_OUT = GPIO_DSB_OUT
|
||||||
WS2812 = GPIO_WS2812
|
WS2812 = GPIO_WS2812
|
||||||
MHZ_TXD = GPIO_MHZ_TXD
|
MHZ_TXD = GPIO_MHZ_TXD
|
||||||
MHZ_RXD = GPIO_MHZ_RXD
|
MHZ_RXD = GPIO_MHZ_RXD
|
||||||
|
CM11_TXD = GPIO_CM11_TXD
|
||||||
|
CM11_RXD = GPIO_CM11_RXD
|
||||||
PZEM0XX_TX = GPIO_PZEM0XX_TX
|
PZEM0XX_TX = GPIO_PZEM0XX_TX
|
||||||
PZEM004_RX = GPIO_PZEM004_RX
|
PZEM004_RX = GPIO_PZEM004_RX
|
||||||
PZEM016_RX = GPIO_PZEM016_RX
|
PZEM016_RX = GPIO_PZEM016_RX
|
||||||
|
|
Loading…
Reference in New Issue