mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-23 18:56:38 +00:00
Support of Winsum ZH03B sensor Dust particle sensor in xsns_18_pms5003.ino (#19850)
* Update xsns_18_pms5003.ino The Winsum ZH03B sensor is quite similar to the Plantower PMS3003 sensor. The main difference is the response in passive mode. With these changes xsns_18_pms5003.ino can support the ZH03B sensor when PMS_MODEL_ZH03X is defined in the configuration file. * Update xsns_18_pms5003.ino
This commit is contained in:
parent
f45b55a18b
commit
0130ce972a
@ -27,6 +27,8 @@
|
||||
* You can either support PMS3003 or PMS5003-7003 at one time. To enable the PMS3003 support
|
||||
* you must enable the define PMS_MODEL_PMS3003 on your configuration file.
|
||||
* For PMSx003T models that report temperature and humidity define PMS_MODEL_PMS5003T
|
||||
* This module can also support de Winsen ZH03x series of dust particle sensors,
|
||||
* To support those sensors, you must define PMS_MODEL_ZH03X in the confuguration file.
|
||||
\*********************************************************************************************/
|
||||
|
||||
#define XSNS_18 18
|
||||
@ -61,6 +63,15 @@ enum PmsCommands
|
||||
CMD_READ_DATA
|
||||
};
|
||||
|
||||
#ifdef PMS_MODEL_ZH03X
|
||||
const uint8_t kPmsCommands[][9] PROGMEM = {
|
||||
// 0 1 2 3 4 5 6 7 8
|
||||
{0xFF, 0x01, 0x78, 0x40, 0x00, 0x00, 0x00, 0x00, 0x47}, // pms_set_active_mode
|
||||
{0xFF, 0x01, 0xA7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x57}, // pms_sleep
|
||||
{0xFF, 0x01, 0xA7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58}, // pms_wake
|
||||
{0xFF, 0x01, 0x78, 0x41, 0x00, 0x00, 0x00, 0x00, 0x46}, // pms_set_passive_mode
|
||||
{0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79}}; // pms_passive_mode_read
|
||||
#else
|
||||
const uint8_t kPmsCommands[][7] PROGMEM = {
|
||||
// 0 1 2 3 4 5 6
|
||||
{0x42, 0x4D, 0xE1, 0x00, 0x01, 0x01, 0x71}, // pms_set_active_mode
|
||||
@ -68,12 +79,13 @@ const uint8_t kPmsCommands[][7] PROGMEM = {
|
||||
{0x42, 0x4D, 0xE4, 0x00, 0x01, 0x01, 0x74}, // pms_wake
|
||||
{0x42, 0x4D, 0xE1, 0x00, 0x00, 0x01, 0x70}, // pms_set_passive_mode
|
||||
{0x42, 0x4D, 0xE2, 0x00, 0x00, 0x01, 0x71}}; // pms_passive_mode_read
|
||||
#endif // PMS_MODEL_ZH03X
|
||||
|
||||
struct pmsX003data {
|
||||
uint16_t framelen;
|
||||
uint16_t pm10_standard, pm25_standard, pm100_standard;
|
||||
uint16_t pm10_env, pm25_env, pm100_env;
|
||||
#ifdef PMS_MODEL_PMS3003
|
||||
#if defined(PMS_MODEL_PMS3003) || defined(PMS_MODEL_ZH03X)
|
||||
uint16_t reserved1, reserved2, reserved3;
|
||||
#else
|
||||
uint16_t particles_03um, particles_05um, particles_10um, particles_25um;
|
||||
@ -104,7 +116,7 @@ bool PmsReadData(void)
|
||||
while ((PmsSerial->peek() != 0x42) && PmsSerial->available()) {
|
||||
PmsSerial->read();
|
||||
}
|
||||
#ifdef PMS_MODEL_PMS3003
|
||||
#if defined(PMS_MODEL_PMS3003) || defined(PMS_MODEL_ZH03X)
|
||||
if (PmsSerial->available() < 24) {
|
||||
#else
|
||||
if (PmsSerial->available() < 32) {
|
||||
@ -112,7 +124,7 @@ bool PmsReadData(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef PMS_MODEL_PMS3003
|
||||
#if defined(PMS_MODEL_PMS3003) || defined(PMS_MODEL_ZH03X)
|
||||
uint8_t buffer[24];
|
||||
PmsSerial->readBytes(buffer, 24);
|
||||
#else
|
||||
@ -122,14 +134,14 @@ bool PmsReadData(void)
|
||||
uint16_t sum = 0;
|
||||
PmsSerial->flush(); // Make room for another burst
|
||||
|
||||
#ifdef PMS_MODEL_PMS3003
|
||||
#if defined(PMS_MODEL_PMS3003) || defined(PMS_MODEL_ZH03X)
|
||||
AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, 24);
|
||||
#else
|
||||
AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, 32);
|
||||
#endif // PMS_MODEL_PMS3003
|
||||
|
||||
// get checksum ready
|
||||
#ifdef PMS_MODEL_PMS3003
|
||||
#if defined(PMS_MODEL_PMS3003) || defined(PMS_MODEL_ZH03X)
|
||||
for (uint32_t i = 0; i < 22; i++) {
|
||||
#else
|
||||
for (uint32_t i = 0; i < 30; i++) {
|
||||
@ -137,7 +149,7 @@ bool PmsReadData(void)
|
||||
sum += buffer[i];
|
||||
}
|
||||
// The data comes in endian'd, this solves it so it works on all platforms
|
||||
#ifdef PMS_MODEL_PMS3003
|
||||
#if defined(PMS_MODEL_PMS3003) || defined(PMS_MODEL_ZH03X)
|
||||
uint16_t buffer_u16[12];
|
||||
for (uint32_t i = 0; i < 12; i++) {
|
||||
#else
|
||||
@ -147,7 +159,8 @@ bool PmsReadData(void)
|
||||
buffer_u16[i] = buffer[2 + i*2 + 1];
|
||||
buffer_u16[i] += (buffer[2 + i*2] << 8);
|
||||
}
|
||||
#ifdef PMS_MODEL_PMS3003
|
||||
|
||||
#if defined(PMS_MODEL_PMS3003) || defined(PMS_MODEL_ZH03X)
|
||||
if (sum != buffer_u16[10]) {
|
||||
#else
|
||||
if (sum != buffer_u16[14]) {
|
||||
@ -156,7 +169,7 @@ bool PmsReadData(void)
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef PMS_MODEL_PMS3003
|
||||
#if defined(PMS_MODEL_PMS3003) || defined(PMS_MODEL_ZH03X)
|
||||
memcpy((void *)&pms_data, (void *)buffer_u16, 22);
|
||||
#else
|
||||
memcpy((void *)&pms_data, (void *)buffer_u16, 30);
|
||||
@ -170,6 +183,60 @@ bool PmsReadData(void)
|
||||
|
||||
return true;
|
||||
}
|
||||
#ifdef PMS_MODEL_ZH03X
|
||||
bool ZH03ReadDataPassive() // process the passive mode response of the ZH03x sensor
|
||||
{
|
||||
if (! PmsSerial->available()) {
|
||||
return false;
|
||||
}
|
||||
while ((PmsSerial->peek() != 0xFF) && PmsSerial->available()) {
|
||||
PmsSerial->read();
|
||||
}
|
||||
if (PmsSerial->available() < 9) {
|
||||
return false;
|
||||
}
|
||||
uint8_t buffer[9];
|
||||
PmsSerial->readBytes(buffer, 9);
|
||||
if (buffer[1] != 0x86) {
|
||||
return false;
|
||||
}
|
||||
PmsSerial->flush(); // Make room for another burst
|
||||
|
||||
AddLogBuffer(LOG_LEVEL_DEBUG_MORE, buffer, 9);
|
||||
|
||||
uint8_t sum = 0;
|
||||
for (uint32_t i = 1; i < 7; i++) {
|
||||
sum += buffer[i];
|
||||
}
|
||||
sum=(~sum)+1;
|
||||
if (sum != buffer[8]) {
|
||||
AddLog(LOG_LEVEL_DEBUG, PSTR("ZH03x: " D_CHECKSUM_FAILURE));
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t buffer_u16[12];
|
||||
for (uint32_t i = 1; i < 4; i++) {
|
||||
buffer_u16[i] = buffer[i*2 + 1];
|
||||
buffer_u16[i] += (buffer[i*2] << 8);
|
||||
buffer_u16[i+3] = buffer[i*2 + 1]; // Direct and Environment values identical
|
||||
buffer_u16[i+3] += (buffer[i*2] << 8); // Direct and Environment values identical
|
||||
buffer_u16[0] = 20; // set dummy framelength
|
||||
buffer_u16[11] = buffer[8]; // copy checksum
|
||||
}
|
||||
|
||||
memcpy((void *)&pms_data, (void *)buffer_u16, 22);
|
||||
|
||||
Pms.valid = 10;
|
||||
|
||||
if (!Pms.discovery_triggered) {
|
||||
TasmotaGlobal.discovery_counter = 1; // Force discovery
|
||||
Pms.discovery_triggered = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
#endif // PMS_MODEL_ZH03X
|
||||
|
||||
/*********************************************************************************************\
|
||||
* Command Sensor18
|
||||
@ -227,7 +294,18 @@ void PmsSecond(void) // Every second
|
||||
}
|
||||
|
||||
if (Pms.ready) {
|
||||
#ifdef PMS_MODEL_ZH03X
|
||||
bool validread;
|
||||
if (Settings->pms_wake_interval >= MIN_INTERVAL_PERIOD) {
|
||||
validread = ZH03ReadDataPassive(); // in passive mode, the response is different from the PMS sensors
|
||||
}
|
||||
else {
|
||||
validread = PmsReadData(); // In active mode the rsponse is identical to the PMS sensors
|
||||
}
|
||||
if (validread) {
|
||||
#else
|
||||
if (PmsReadData()) {
|
||||
#endif // PMS_MODEL_ZH03X
|
||||
Pms.valid = 10;
|
||||
if (Settings->pms_wake_interval >= MIN_INTERVAL_PERIOD) {
|
||||
PmsSendCmd(CMD_SLEEP);
|
||||
@ -276,7 +354,10 @@ void PmsInit(void) {
|
||||
void PmsShow(bool json) {
|
||||
if (Pms.valid) {
|
||||
char types[10];
|
||||
#ifdef PMS_MODEL_PMS3003
|
||||
|
||||
#ifdef PMS_MODEL_ZH03X
|
||||
strcpy_P(types, PSTR("ZH03x"));
|
||||
#elif defined(PMS_MODEL_PMS3003)
|
||||
strcpy_P(types, PSTR("PMS3003"));
|
||||
#elif defined(PMS_MODEL_PMS5003T)
|
||||
strcpy_P(types, PSTR("PMS5003T"));
|
||||
@ -294,7 +375,7 @@ void PmsShow(bool json) {
|
||||
types,
|
||||
pms_data.pm10_standard, pms_data.pm25_standard, pms_data.pm100_standard,
|
||||
pms_data.pm10_env, pms_data.pm25_env, pms_data.pm100_env);
|
||||
#ifndef PMS_MODEL_PMS3003
|
||||
#if !(defined(PMS_MODEL_PMS3003) || defined(PMS_MODEL_ZH03X))
|
||||
ResponseAppend_P(PSTR(",\"PB0.3\":%d,\"PB0.5\":%d,\"PB1\":%d,\"PB2.5\":%d,"),
|
||||
pms_data.particles_03um, pms_data.particles_05um, pms_data.particles_10um, pms_data.particles_25um);
|
||||
#ifdef PMS_MODEL_PMS5003T
|
||||
@ -321,7 +402,7 @@ void PmsShow(bool json) {
|
||||
WSContentSend_PD(HTTP_SNS_ENVIRONMENTAL_CONCENTRATION, types, "1", pms_data.pm10_env);
|
||||
WSContentSend_PD(HTTP_SNS_ENVIRONMENTAL_CONCENTRATION, types, "2.5", pms_data.pm25_env);
|
||||
WSContentSend_PD(HTTP_SNS_ENVIRONMENTAL_CONCENTRATION, types, "10", pms_data.pm100_env);
|
||||
#ifndef PMS_MODEL_PMS3003
|
||||
#if !(defined(PMS_MODEL_PMS3003) || defined(PMS_MODEL_ZH03X))
|
||||
WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "0.3", pms_data.particles_03um);
|
||||
WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "0.5", pms_data.particles_05um);
|
||||
WSContentSend_PD(HTTP_SNS_PARTICALS_BEYOND, types, "1", pms_data.particles_10um);
|
||||
|
Loading…
x
Reference in New Issue
Block a user