From a16e2316b39f7e0295724ce113c92d9dac362eea Mon Sep 17 00:00:00 2001 From: Theo Arends Date: Sat, 3 Mar 2018 15:28:30 +0100 Subject: [PATCH] v5.12.0d - Add support for Nova Fitness SDS011 5.12.0d * Add support for Nova Fitness SDS011 and possibly SDS021 particle concentration sensor (#2070) --- sonoff/_releasenotes.ino | 1 + sonoff/language/de-DE.h | 1 + sonoff/language/en-GB.h | 1 + sonoff/language/es-AR.h | 1 + sonoff/language/fr-FR.h | 1 + sonoff/language/hu-HU.h | 1 + sonoff/language/it-IT.h | 1 + sonoff/language/nl-NL.h | 1 + sonoff/language/pl-PL.h | 1 + sonoff/language/pt-PT.h | 1 + sonoff/language/ru-RU.h | 1 + sonoff/language/zh-CN.h | 1 + sonoff/sonoff_post.h | 3 +- sonoff/sonoff_template.h | 3 +- sonoff/user_config.h | 1 + sonoff/xsns_20_novasds.ino | 143 +++++++++++++++++++++++++++++++++++++ 16 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 sonoff/xsns_20_novasds.ino diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index f18747ba0..51ebe785b 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -4,6 +4,7 @@ * Add compiler check for stable lwIP version v1.4 (#1940) * Add diacritics to Polish language file (#2005) * Add Hungarian language file (#2024) + * Add support for Nova Fitness SDS011 and possibly SDS021 particle concentration sensor (#2070) * Fix MQTT TLS fingerprint validation (#2033) * * 5.12.0c diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index 09877893c..f1eed0dac 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -407,6 +407,7 @@ #define D_SENSOR_SPI_DC "SPI DC" #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1 "SDS0X1" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index 77db37009..987d0ccda 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -407,6 +407,7 @@ #define D_SENSOR_SPI_DC "SPI DC" #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1 "SDS0X1" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/es-AR.h b/sonoff/language/es-AR.h index e54098edf..8386dd605 100644 --- a/sonoff/language/es-AR.h +++ b/sonoff/language/es-AR.h @@ -407,6 +407,7 @@ #define D_SENSOR_SPI_DC "SPI DC" #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1 "SDS0X1" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index 78afc0677..9364bc102 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.h @@ -407,6 +407,7 @@ #define D_SENSOR_SPI_DC "SPI DC" #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1 "SDS0X1" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/hu-HU.h b/sonoff/language/hu-HU.h index 3f283f7e5..f1fb99c61 100644 --- a/sonoff/language/hu-HU.h +++ b/sonoff/language/hu-HU.h @@ -407,6 +407,7 @@ #define D_SENSOR_SPI_DC "SPI DC" #define D_SENSOR_BACKLIGHT "Háttérvil" #define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1 "SDS0X1" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/it-IT.h b/sonoff/language/it-IT.h index 6ab442ca1..ea6ce9804 100644 --- a/sonoff/language/it-IT.h +++ b/sonoff/language/it-IT.h @@ -407,6 +407,7 @@ #define D_SENSOR_SPI_DC "SPI DC" #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1 "SDS0X1" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h index 6f9d39f72..c260553a0 100644 --- a/sonoff/language/nl-NL.h +++ b/sonoff/language/nl-NL.h @@ -407,6 +407,7 @@ #define D_SENSOR_SPI_DC "SPI DC" #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1 "SDS0X1" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/pl-PL.h b/sonoff/language/pl-PL.h index 12496e9a6..334934a12 100644 --- a/sonoff/language/pl-PL.h +++ b/sonoff/language/pl-PL.h @@ -407,6 +407,7 @@ #define D_SENSOR_SPI_DC "SPI DC" #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1 "SDS0X1" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/pt-PT.h b/sonoff/language/pt-PT.h index cf4b7ee09..7fd9bac23 100644 --- a/sonoff/language/pt-PT.h +++ b/sonoff/language/pt-PT.h @@ -407,6 +407,7 @@ #define D_SENSOR_SPI_DC "SPI DC" #define D_SENSOR_BACKLIGHT "Luz negra" #define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1 "SDS0X1" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/ru-RU.h b/sonoff/language/ru-RU.h index f6bab7d90..b0f5cd764 100644 --- a/sonoff/language/ru-RU.h +++ b/sonoff/language/ru-RU.h @@ -408,6 +408,7 @@ #define D_SENSOR_SPI_DC "SPI DC" #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1 "SDS0X1" // Units #define D_UNIT_AMPERE "А" diff --git a/sonoff/language/zh-CN.h b/sonoff/language/zh-CN.h index 76c271ee9..feff61a23 100644 --- a/sonoff/language/zh-CN.h +++ b/sonoff/language/zh-CN.h @@ -407,6 +407,7 @@ #define D_SENSOR_SPI_DC "SPI DC" #define D_SENSOR_BACKLIGHT "BkLight" #define D_SENSOR_PMS5003 "PMS5003" +#define D_SENSOR_SDS0X1 "SDS0X1" // Units #define D_UNIT_AMPERE "安" diff --git a/sonoff/sonoff_post.h b/sonoff/sonoff_post.h index d7b55030a..0a023ea6f 100644 --- a/sonoff/sonoff_post.h +++ b/sonoff/sonoff_post.h @@ -61,6 +61,7 @@ void WifiWpsStatusCallback(wps_cb_status status); #define CO2_HIGH 1200 // Above this CO2 value show red light (needs PWM or WS2812 RG(B) led and enable with SetOption18 1) #endif #define USE_PMS5003 // Add support for PMS5003 and PMS7003 particle concentration sensor (+1k3 code) +#define USE_NOVA_SDS // Add support for SDS011 and SDS021 particle concentration sensor (+0k7 code) #define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code) #define USE_IR_REMOTE // Send IR remote commands using library IRremoteESP8266 and ArduinoJson (+4k code, 0k3 mem, 48 iram) #define USE_IR_HVAC // Support for HVAC system using IR (+2k code) @@ -170,4 +171,4 @@ void WifiWpsStatusCallback(wps_cb_status status); #define ARDUINO_ESP8266_RELEASE "STAGE" #endif -#endif // _SONOFF_POST_H_ \ No newline at end of file +#endif // _SONOFF_POST_H_ diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 1a8206c08..6a0e2cd97 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -88,6 +88,7 @@ enum UserSelectablePins { GPIO_SPI_DC, // SPI Data Direction GPIO_BACKLIGHT, // Display backlight control GPIO_PMS5003, // Plantower PMS5003 Serial interface + GPIO_SDS0X1, // Nova Fitness SDS011 Serial interface GPIO_SENSOR_END }; // Programmer selectable GPIO functionality offset by user selectable GPIOs @@ -129,7 +130,7 @@ const char kSensorNames[] PROGMEM = D_SENSOR_PZEM_TX "|" D_SENSOR_PZEM_RX "|" D_SENSOR_SAIR_TX "|" D_SENSOR_SAIR_RX "|" D_SENSOR_SPI_CS "|" D_SENSOR_SPI_DC "|" D_SENSOR_BACKLIGHT "|" - D_SENSOR_PMS5003; + D_SENSOR_PMS5003 "|" D_SENSOR_SDS0X1; /********************************************************************************************/ diff --git a/sonoff/user_config.h b/sonoff/user_config.h index d2e8aa9e7..f5f7acdc7 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -215,6 +215,7 @@ #define CO2_LOW 800 // Below this CO2 value show green light (needs PWM or WS2812 RG(B) led and enable with SetOption18 1) #define CO2_HIGH 1200 // Above this CO2 value show red light (needs PWM or WS2812 RG(B) led and enable with SetOption18 1) #define USE_PMS5003 // Add support for PMS5003 and PMS7003 particle concentration sensor (+1k3 code) +#define USE_NOVA_SDS // Add support for SDS011 and SDS021 particle concentration sensor (+0k7 code) #define USE_PZEM004T // Add support for PZEM004T Energy monitor (+2k code) // -- Low level interface devices ----------------- diff --git a/sonoff/xsns_20_novasds.ino b/sonoff/xsns_20_novasds.ino new file mode 100644 index 000000000..ed877fd2f --- /dev/null +++ b/sonoff/xsns_20_novasds.ino @@ -0,0 +1,143 @@ +/* + xsns_20_novasds.ino - Nova SDS011/SDS021 particle concentration sensor support for Sonoff-Tasmota + + 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 + 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_NOVA_SDS +/*********************************************************************************************\ + * Nova Fitness SDS011 (and possibly SDS021) particle concentration sensor + * For background information see http://aqicn.org/sensor/sds011/ +\*********************************************************************************************/ + +#include + +TasmotaSerial *NovaSdsSerial; + +uint8_t novasds_type = 1; +uint8_t novasds_valid = 0; + +struct sds011data { + uint16_t pm100; + uint16_t pm25; +} novasds_data; + +bool NovaSdsReadData() +{ + if (! NovaSdsSerial->available()) return false; + + while ((NovaSdsSerial->peek() != 0xAA) && NovaSdsSerial->available()) { + NovaSdsSerial->read(); + } + + byte d[8] = { 0 }; + NovaSdsSerial->read(); // skip 0xAA + NovaSdsSerial->readBytes(d, 8); + NovaSdsSerial->flush(); + + AddLogSerial(LOG_LEVEL_DEBUG_MORE, d, 8); + + if (d[7] == ((d[1] + d[2] + d[3] + d[4] + d[5] + d[6]) & 0xFF)) { + novasds_data.pm25 = (d[1] + 256 * d[2]); + novasds_data.pm100 = (d[3] + 256 * d[4]); + } else { + AddLog_P(LOG_LEVEL_DEBUG, PSTR("SDS: " D_CHECKSUM_FAILURE)); + return false; + } + + novasds_valid = 10; + + return true; +} + +/*********************************************************************************************/ + +void NovaSdsSecond() // Every second +{ + if (NovaSdsReadData()) { + novasds_valid = 10; + } else { + if (novasds_valid) { + novasds_valid--; + } + } +} + +/*********************************************************************************************/ + +void NovaSdsInit() +{ + novasds_type = 0; + + if (pin[GPIO_SDS0X1] < 99) { + NovaSdsSerial = new TasmotaSerial(pin[GPIO_SDS0X1], -1); + if (NovaSdsSerial->begin()) { + novasds_type = 1; + } + } +} + +#ifdef USE_WEBSERVER +const char HTTP_SDS0X1_SNS[] PROGMEM = "%s" + "{s}SDS0X1 " D_ENVIRONMENTAL_CONCENTRATION " 2.5 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}" + "{s}SDS0X1 " D_ENVIRONMENTAL_CONCENTRATION " 10 " D_UNIT_MICROMETER "{m}%d " D_UNIT_MICROGRAM_PER_CUBIC_METER "{e}"; // {s} = , {m} = , {e} = +#endif // USE_WEBSERVER + +void NovaSdsShow(boolean json) +{ + if (novasds_valid) { + if (json) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"SDS0X1\":{\"PM2.5\":%d,\"PM10\":%d}"), mqtt_data, novasds_data.pm25, novasds_data.pm100); +#ifdef USE_WEBSERVER + } else { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SDS0X1_SNS, mqtt_data, novasds_data.pm25/10, novasds_data.pm100/10); +#endif // USE_WEBSERVER + } + } +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +#define XSNS_20 + +boolean Xsns20(byte function) +{ + boolean result = false; + + if (novasds_type) { + switch (function) { + case FUNC_INIT: + NovaSdsInit(); + break; + case FUNC_EVERY_SECOND: + NovaSdsSecond(); + break; + case FUNC_JSON_APPEND: + NovaSdsShow(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_APPEND: + NovaSdsShow(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_NOVA_SDS \ No newline at end of file