diff --git a/include/cyclic.h b/include/cyclic.h index 4b402360..ccadbb65 100644 --- a/include/cyclic.h +++ b/include/cyclic.h @@ -18,6 +18,15 @@ #include "display.h" #endif +#if (HAS_SDS011) +#include "sds011read.h" +#endif + +#if (HAS_SDCARD) +#include "sdcard.h" +#endif + + extern Ticker housekeeper; void housekeeping(void); diff --git a/include/payload.h b/include/payload.h index b41bb113..719d59ec 100644 --- a/include/payload.h +++ b/include/payload.h @@ -3,6 +3,10 @@ #include "paxcounter.conf" +#if (HAS_SDS011) +#include "sds011read.h" +#endif + // MyDevices CayenneLPP 1.0 channels for Synamic sensor payload format // all payload goes out on LoRa FPort 1 #if (PAYLOAD_ENCODER == 3) @@ -55,6 +59,10 @@ public: void addButton(uint8_t value); void addSensor(uint8_t[]); void addTime(time_t value); + void addPM10(float value); + void addPM25(float value); +private: + void addChars( char* string, int len); #if (PAYLOAD_ENCODER == 1) // format plain @@ -95,4 +103,4 @@ private: extern PayloadConvert payload; -#endif // _PAYLOAD_H_ \ No newline at end of file +#endif // _PAYLOAD_H_ diff --git a/include/sdcard.h b/include/sdcard.h index 051baa19..99e784cb 100644 --- a/include/sdcard.h +++ b/include/sdcard.h @@ -10,7 +10,7 @@ #define SDCARD_FILE_NAME "paxcount.%02d" #define SDCARD_FILE_HEADER "date, time, wifi, bluet" -bool sdcardInit( void ); +bool sdcard_init( void ); void sdcardWriteData( uint16_t, uint16_t); -#endif \ No newline at end of file +#endif diff --git a/include/sds011read.h b/include/sds011read.h new file mode 100644 index 00000000..8c573c0d --- /dev/null +++ b/include/sds011read.h @@ -0,0 +1,13 @@ +#ifndef _SDS011READ_H +#define _SDS011READ_H + +#include + +#define SDCARD_FILE_HEADER_SDS011 ", PM10,PM25" + +bool sds011_init(); +void sds011_loop(); +void sds011_sleep(void); +void sds011_wakeup(void); + +#endif // _SDS011READ_H diff --git a/platformio.ini b/platformio.ini index df7e17c2..704ebdc7 100644 --- a/platformio.ini +++ b/platformio.ini @@ -73,6 +73,8 @@ lib_deps_sensors = Adafruit BME280 Library@>=2.0.0 Adafruit BMP085 Library@>=1.0.1 BSEC Software Library@1.5.1474 + ;SDS011 sensor Library + https://github.com/ricki-z/SDS011.git#33fd8b6 lib_deps_basic = ArduinoJson@^5.13.1 76@>=1.2.4 ; #76 Timezone by Jack Christensen diff --git a/src/cyclic.cpp b/src/cyclic.cpp index 89f8e3e2..b0223381 100644 --- a/src/cyclic.cpp +++ b/src/cyclic.cpp @@ -9,6 +9,10 @@ static const char TAG[] = __FILE__; Ticker housekeeper; +#if (HAS_SDS011) +extern boolean isSDS011Active; +#endif + void housekeeping() { xTaskNotifyFromISR(irqHandlerTask, CYCLIC_IRQ, eSetBits, NULL); } @@ -18,7 +22,6 @@ void doHousekeeping() { // update uptime counter uptime(); - // check if update mode trigger switch was set if (RTC_runmode == RUNMODE_UPDATE) { // check battery status if we can before doing ota @@ -112,6 +115,17 @@ void doHousekeeping() { } #endif +#if (HAS_SDS011) + if ( isSDS011Active ) { + ESP_LOGD(TAG, "SDS011: go to sleep"); + sds011_loop(); + } + else { + ESP_LOGD(TAG, "SDS011: wakeup"); + sds011_wakeup(); + } +#endif + } // doHousekeeping() // uptime counter 64bit to prevent millis() rollover after 49 days @@ -143,4 +157,4 @@ void reset_counters() { #endif #endif -} \ No newline at end of file +} diff --git a/src/hal/generic.h b/src/hal/generic.h index 5d56e591..fa1d14c7 100644 --- a/src/hal/generic.h +++ b/src/hal/generic.h @@ -100,4 +100,4 @@ #define MCP_24AA02E64_I2C_ADDRESS 0x50 // I2C address for the 24AA02E64 #define MCP_24AA02E64_MAC_ADDRESS 0xF8 // Memory adress of unique deveui 64 bits -#endif \ No newline at end of file +#endif diff --git a/src/hal/ttgov21new.h b/src/hal/ttgov21new.h index 90f93c7a..9fa665f2 100644 --- a/src/hal/ttgov21new.h +++ b/src/hal/ttgov21new.h @@ -12,6 +12,12 @@ // This settings are for boards labeled v1.6 on pcb, NOT for v1.5 or older */ +// SDS011 dust sensor settings +#define HAS_SDS011 1 // use SDS011 +// used pins on the ESP-side: +#define ESP_PIN_TX 19 // connect to RX on the SDS011 +#define ESP_PIN_RX 23 // connect to TX on the SDS011 + #define HAS_LORA 1 // comment out if device shall not send data via LoRa #define CFG_sx1276_radio 1 // HPD13A LoRa SoC @@ -48,4 +54,4 @@ #define LORA_IO1 (33) #define LORA_IO2 (32) -#endif \ No newline at end of file +#endif diff --git a/src/main.cpp b/src/main.cpp index 5e761b0e..c8f3af3d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -324,10 +324,16 @@ void setup() { #endif #ifdef HAS_SDCARD - if (sdcardInit()) + if (sdcard_init()) strcat_P(features, " SD"); #endif +#if (HAS_SDS011) + ESP_LOGI(TAG, "init fine-dust-sensor"); + if ( sds011_init() ) + strcat_P(features, " SDS"); +#endif + #if (VENDORFILTER) strcat_P(features, " FILTER"); #endif diff --git a/src/payload.cpp b/src/payload.cpp index 323e402b..57428234 100644 --- a/src/payload.cpp +++ b/src/payload.cpp @@ -489,5 +489,41 @@ void PayloadConvert::addTime(time_t value) { buffer[cursor++] = (byte)((tx_period & 0x000000FF)); #endif } +#endif // PAYLOAD_ENCODER -#endif \ No newline at end of file +void PayloadConvert::addPM10( float value) { +#if (HAS_SDS011) +#if (PAYLOAD_ENCODER == 1) // plain + char tempBuffer[10+1]; + sprintf( tempBuffer, ",%5.1f", value); + addChars(tempBuffer, strlen(tempBuffer)); +#elif (PAYLOAD_ENCODER == 2 ) // packed + writeUint16( (uint16_t) (value*10) ); +#elif (PAYLOAD_ENCODER == 3 ) // Cayenne LPP dynamic +#error not implemented yet +#elif (PAYLOAD_ENCODER == 4 ) // Cayenne LPP packed +#error not implemented yet +#endif +#endif // HAS_SDS011 +} + +void PayloadConvert::addPM25( float value) { +#if (HAS_SDS011) +#if (PAYLOAD_ENCODER == 1) // plain + char tempBuffer[10+1]; + sprintf( tempBuffer, ",%5.1f", value); + addChars(tempBuffer, strlen(tempBuffer)); +#elif (PAYLOAD_ENCODER == 2 ) // packed + writeUint16( (uint16_t) (value*10) ); +#elif (PAYLOAD_ENCODER == 3 ) // Cayenne LPP dynamic +#error not implemented yet +#elif (PAYLOAD_ENCODER == 4 ) // Cayenne LPP packed +#error not implemented yet +#endif +#endif // HAS_SDS011 +} + +void PayloadConvert::addChars( char * string, int len) { + for (int i=0; i < len; i++) + addByte(string[i]); +} diff --git a/src/sdcard.cpp b/src/sdcard.cpp index 0633151f..002cfdf8 100644 --- a/src/sdcard.cpp +++ b/src/sdcard.cpp @@ -6,6 +6,12 @@ static const char TAG[] = __FILE__; #include "sdcard.h" +#if (HAS_SDS011) +#include +// the results of the sensor: +extern float pm25; +extern float pm10; +#endif static bool useSDCard; @@ -13,11 +19,13 @@ static void createFile(void); File fileSDCard; -bool sdcardInit() { +bool sdcard_init() { ESP_LOGD(TAG, "looking for SD-card..."); useSDCard = SD.begin(SDCARD_CS, SDCARD_MOSI, SDCARD_MISO, SDCARD_SCLK); if (useSDCard) createFile(); + else + ESP_LOGD(TAG,"SD-card not found"); return useSDCard; } @@ -35,7 +43,12 @@ void sdcardWriteData(uint16_t noWifi, uint16_t noBle) { sprintf(tempBuffer, "%02d:%02d:%02d,", hour(t), minute(t), second(t)); fileSDCard.print(tempBuffer); sprintf(tempBuffer, "%d,%d", noWifi, noBle); - fileSDCard.println(tempBuffer); + fileSDCard.print( tempBuffer); +#if (HAS_SDS011) + sprintf(tempBuffer, ",%5.1f,%4.1f", pm10, pm25); + fileSDCard.print( tempBuffer); +#endif + fileSDCard.println( ); if (++counterWrites > 2) { // force writing to SD-card @@ -58,8 +71,12 @@ void createFile(void) { ESP_LOGD(TAG, "SD: file does not exist: opening"); fileSDCard = SD.open(bufferFilename, FILE_WRITE); if (fileSDCard) { - ESP_LOGD(TAG, "SD: name opended: <%s>", bufferFilename); - fileSDCard.println(SDCARD_FILE_HEADER); + ESP_LOGD(TAG, "SD: name opened: <%s>", bufferFilename); + fileSDCard.print( SDCARD_FILE_HEADER ); +#if (HAS_SDS011) + fileSDCard.print( SDCARD_FILE_HEADER_SDS011 ); +#endif + fileSDCard.println(); useSDCard = true; break; } @@ -68,4 +85,4 @@ void createFile(void) { return; } -#endif // (HAS_SDCARD) \ No newline at end of file +#endif // (HAS_SDCARD) diff --git a/src/sds011read.cpp b/src/sds011read.cpp new file mode 100644 index 00000000..f280fbe6 --- /dev/null +++ b/src/sds011read.cpp @@ -0,0 +1,58 @@ +// routines for fetching data from the SDS011-sensor + +// Local logging tag +static const char TAG[] = __FILE__; + +#include "sds011read.h" + +#if (HAS_IF482) +#error cannot use IF482 together with SDS011 (both use UART#2) +#endif +// UART(2) is unused in this project +static HardwareSerial sdsSerial(2); // so we use it here +static SDS011 sdsSensor; // fine dust sensor + +// the results of the sensor: +float pm25; +float pm10; +boolean isSDS011Active; + +// init +bool sds011_init() { + pm25 = pm10 = 0.0; +#if (HAS_SDS011) + sdsSensor.begin (&sdsSerial, ESP_PIN_RX, ESP_PIN_TX); +#endif + sds011_sleep(); // we do sleep/wakup by ourselves + return true; +} + +// reading data: +void sds011_loop() { + if (isSDS011Active) { + int sdsErrorCode = sdsSensor.read(&pm25, &pm10); + if (sdsErrorCode) { + pm25 = pm10 = 0.0; + ESP_LOGI(TAG, "SDS011 error: %d", sdsErrorCode); + } else { + ESP_LOGI(TAG, "fine-dust-values: %5.1f,%4.1f", pm10, pm25); + } + sds011_sleep(); + } + return; +} + +// putting the SDS-sensor to sleep +void sds011_sleep(void) { + sdsSensor.sleep(); + isSDS011Active = false; +} + +// start the SDS-sensor +// needs 30 seconds for warming up +void sds011_wakeup() { + if (!isSDS011Active) { + sdsSensor.wakeup(); + isSDS011Active = true; + } +} diff --git a/src/senddata.cpp b/src/senddata.cpp index f4f6b085..f5b867f6 100644 --- a/src/senddata.cpp +++ b/src/senddata.cpp @@ -3,6 +3,11 @@ Ticker sendcycler; +#if (HAS_SDS011) +extern float pm10; +extern float pm25; +#endif + void sendcycle() { xTaskNotifyFromISR(irqHandlerTask, SENDCYCLE_IRQ, eSetBits, NULL); } @@ -94,6 +99,10 @@ void sendData() { payload.addCount(macs_wifi, MAC_SNIFF_WIFI); if (cfg.blescan) payload.addCount(macs_ble, MAC_SNIFF_BLE); +#endif +#if (HAS_SDS011) + payload.addPM10(pm10); + payload.addPM25(pm25); #endif SendPayload(COUNTERPORT, prio_normal); // clear counter if not in cumulative counter mode @@ -172,4 +181,4 @@ void flushQueues() { #ifdef HAS_SPI spi_queuereset(); #endif -} \ No newline at end of file +} diff --git a/src/timekeeper.cpp b/src/timekeeper.cpp index 85f62864..f95a97ab 100644 --- a/src/timekeeper.cpp +++ b/src/timekeeper.cpp @@ -16,6 +16,9 @@ static const char TAG[] = __FILE__; const char timeSetSymbols[] = {'G', 'R', 'L', '?'}; #ifdef HAS_IF482 +#if (HAS_SDS011) +#error cannot use IF482 together with SDS011 (both use UART#2) +#endif HardwareSerial IF482(2); // use UART #2 (#1 may be in use for serial GPS) #endif