diff --git a/code/espurna/config/sensors.h b/code/espurna/config/sensors.h index 595c6d2a..3ce23a69 100644 --- a/code/espurna/config/sensors.h +++ b/code/espurna/config/sensors.h @@ -430,6 +430,23 @@ #define MHZ19_TX_PIN 15 #endif +//------------------------------------------------------------------------------ +// SDS011 particulates sensor +// Enable support by passing SDS011_SUPPORT=1 build flag +//------------------------------------------------------------------------------ + +#ifndef SDS011_SUPPORT +#define SDS011_SUPPORT 0 +#endif + +#ifndef SDS011_RX_PIN +#define SDS011_RX_PIN 14 +#endif + +#ifndef SDS011_TX_PIN +#define SDS011_TX_PIN 12 +#endif + //------------------------------------------------------------------------------ // NTC sensor // Enable support by passing NTC_SUPPORT=1 build flag @@ -657,6 +674,7 @@ GUVAS12SD_SUPPORT || \ HLW8012_SUPPORT || \ MHZ19_SUPPORT || \ + SDS011_SUPPORT || \ NTC_SUPPORT || \ SENSEAIR_SUPPORT || \ PMSX003_SUPPORT || \ @@ -785,6 +803,11 @@ #include "../sensors/MHZ19Sensor.h" #endif +#if SDS011_SUPPORT + #include + #include "../sensors/SDS011Sensor.h" +#endif + #if NTC_SUPPORT #include "../sensors/AnalogSensor.h" #include "../sensors/NTCSensor.h" diff --git a/code/espurna/config/types.h b/code/espurna/config/types.h index 880b6dd2..f953d16a 100644 --- a/code/espurna/config/types.h +++ b/code/espurna/config/types.h @@ -276,6 +276,7 @@ #define SENSOR_SENSEAIR_ID 0x24 #define SENSOR_GEIGER_ID 0x25 #define SENSOR_NTC_ID 0x26 +#define SENSOR_SDS011_ID 0x27 //-------------------------------------------------------------------------------- // Magnitudes diff --git a/code/espurna/sensor.ino b/code/espurna/sensor.ino index ab1dfe49..8ef683a7 100644 --- a/code/espurna/sensor.ino +++ b/code/espurna/sensor.ino @@ -330,13 +330,13 @@ void _sensorLoad() { */ - #if AM2320_SUPPORT - { - AM2320Sensor * sensor = new AM2320Sensor(); - sensor->setAddress(AM2320_ADDRESS); - _sensors.push_back(sensor); - } - #endif + #if AM2320_SUPPORT + { + AM2320Sensor * sensor = new AM2320Sensor(); + sensor->setAddress(AM2320_ADDRESS); + _sensors.push_back(sensor); + } + #endif #if ANALOG_SUPPORT { @@ -522,6 +522,15 @@ void _sensorLoad() { } #endif + #if SDS011_SUPPORT + { + SDS011Sensor * sensor = new SDS011Sensor(); + sensor->setRX(SDS011_RX_PIN); + sensor->setTX(SDS011_TX_PIN); + _sensors.push_back(sensor); + } + #endif + #if NTC_SUPPORT { NTCSensor * sensor = new NTCSensor(); diff --git a/code/espurna/sensors/SDS011Sensor.h b/code/espurna/sensors/SDS011Sensor.h new file mode 100644 index 00000000..18f496a1 --- /dev/null +++ b/code/espurna/sensors/SDS011Sensor.h @@ -0,0 +1,173 @@ +// ----------------------------------------------------------------------------- +// SDS011 particulates sensor +// Based on: https://github.com/ricki-z/SDS011 +// +// Uses SoftwareSerial library +// Copyright (C) 2018 by Lucas Pleß +// ----------------------------------------------------------------------------- + +#if SENSOR_SUPPORT && SDS011_SUPPORT + +#pragma once + +#include "Arduino.h" +#include "BaseSensor.h" +#include + + +class SDS011Sensor : public BaseSensor { + + public: + + // --------------------------------------------------------------------- + // Public + // --------------------------------------------------------------------- + + SDS011Sensor(): BaseSensor() { + _count = 2; + _sensor_id = SENSOR_SDS011_ID; + } + + ~SDS011Sensor() { + if (_serial) delete _serial; + } + + // --------------------------------------------------------------------- + + void setRX(unsigned char pin_rx) { + if (_pin_rx == pin_rx) return; + _pin_rx = pin_rx; + _dirty = true; + } + + void setTX(unsigned char pin_tx) { + if (_pin_tx == pin_tx) return; + _pin_tx = pin_tx; + _dirty = true; + } + + // --------------------------------------------------------------------- + + unsigned char getRX() { + return _pin_rx; + } + + unsigned char getTX() { + return _pin_tx; + } + + // --------------------------------------------------------------------- + // Sensor API + // --------------------------------------------------------------------- + + // Initialization method, must be idempotent + void begin() { + + if (!_dirty) return; + + if (_serial) delete _serial; + + _serial = new SoftwareSerial(_pin_rx, _pin_tx); + _serial->begin(9600); + + _ready = true; + _dirty = false; + } + + // Descriptive name of the sensor + String description() { + char buffer[28]; + snprintf(buffer, sizeof(buffer), "SDS011 @ SwSerial(%u,%u)", _pin_rx, _pin_tx); + return String(buffer); + } + + // Descriptive name of the slot # index + String slot(unsigned char index) { + return description(); + }; + + // Address of the sensor (it could be the GPIO or I2C address) + String address(unsigned char index) { + char buffer[6]; + snprintf(buffer, sizeof(buffer), "%u:%u", _pin_rx, _pin_tx); + return String(buffer); + } + + // Type for slot # index + unsigned char type(unsigned char index) { + if (index == 0) return MAGNITUDE_PM2dot5; + if (index == 1) return MAGNITUDE_PM10; + return MAGNITUDE_NONE; + } + + void pre() { + _read(); + } + + // Current value for slot # index + double value(unsigned char index) { + if (index == 0) return _p2dot5; + if (index == 1) return _p10; + return 0; + } + + + + protected: + + // --------------------------------------------------------------------- + // Protected + // --------------------------------------------------------------------- + + void _read() { + byte buffer; + int value; + int len = 0; + int pm10_serial = 0; + int pm25_serial = 0; + int checksum_is; + int checksum_ok = 0; + + while ((_serial->available() > 0) && (_serial->available() >= (10-len))) { + buffer = _serial->read(); + value = int(buffer); + switch (len) { + case (0): if (value != 170) { len = -1; }; break; + case (1): if (value != 192) { len = -1; }; break; + case (2): pm25_serial = value; checksum_is = value; break; + case (3): pm25_serial += (value << 8); checksum_is += value; break; + case (4): pm10_serial = value; checksum_is += value; break; + case (5): pm10_serial += (value << 8); checksum_is += value; break; + case (6): checksum_is += value; break; + case (7): checksum_is += value; break; + case (8): if (value == (checksum_is % 256)) { checksum_ok = 1; } else { len = -1; }; break; + case (9): if (value != 171) { len = -1; }; break; + } + + len++; + + if (len == 10) { + if(checksum_ok == 1) { + _p10 = (float)pm10_serial/10.0; + _p2dot5 = (float)pm25_serial/10.0; + len = 0; checksum_ok = 0; pm10_serial = 0.0; pm25_serial = 0.0; checksum_is = 0; + _error = SENSOR_ERROR_OK; + } else { + _error = SENSOR_ERROR_CRC; + } + } + + yield(); + } + + } + + double _p2dot5 = 0; + double _p10 = 0; + unsigned int _pin_rx; + unsigned int _pin_tx; + SoftwareSerial * _serial = NULL; + +}; + +#endif // SENSOR_SUPPORT && SDS011_SUPPORT