From 9dfcbf0484e03e1b20d4e443c1946947214971d5 Mon Sep 17 00:00:00 2001 From: Willem Oldemans Date: Mon, 26 Jul 2021 16:37:49 +0200 Subject: [PATCH] added CO2 and VOC sensor --- .vscode/c_cpp_properties.json | 14 ++++- CO2_sensor.cpp | 43 +++++++++---- VOC_sensor.cpp | 69 +++++++++++++++++++++ VOC_sensor.h | 11 ++++ lcd.cpp | 110 ++++++++++++++++++++++++++++++++-- lcd.h | 2 +- main.cpp | 11 +++- mqtt.cpp | 5 ++ particles.cpp | 40 +++++++------ platformio.ini | 4 +- sensor.cpp | 33 ++++++++-- sensor.h | 58 ++++++++++++++++-- 12 files changed, 347 insertions(+), 53 deletions(-) create mode 100644 VOC_sensor.cpp create mode 100644 VOC_sensor.h diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index d251ffd..5c74e25 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -10,10 +10,15 @@ "includePath": [ "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32/include", "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32", + "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32/.pio/libdeps/esp32/Adafruit SGP30 Sensor", + "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32/.pio/libdeps/esp32/Adafruit SCD30", + "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32/.pio/libdeps/esp32/Adafruit BusIO", + "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/Wire/src", "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32/.pio/libdeps/esp32/TJpg_Decoder/src", "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/SD/src", "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32/.pio/libdeps/esp32/RunningMedian", "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32/.pio/libdeps/esp32/PubSubClient/src", + "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32/.pio/libdeps/esp32/Adafruit Unified Sensor", "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32/.pio/libdeps/esp32/TFT_eSPI", "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/SPI/src", "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/SPIFFS/src", @@ -82,6 +87,7 @@ "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/fb_gfx", "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/cores/esp32", "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/variants/esp32", + "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32/.pio/libdeps/esp32/Adafruit GFX Library", "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/ArduinoOTA/src", "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/AsyncUDP/src", "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/AzureIoT/src", @@ -104,7 +110,6 @@ "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src", "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/WiFiClientSecure/src", "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/WiFiProv/src", - "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/Wire/src", "/Users/willemoldemans/.platformio/packages/tool-unity", "" ], @@ -113,10 +118,15 @@ "path": [ "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32/include", "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32", + "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32/.pio/libdeps/esp32/Adafruit SGP30 Sensor", + "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32/.pio/libdeps/esp32/Adafruit SCD30", + "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32/.pio/libdeps/esp32/Adafruit BusIO", + "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/Wire/src", "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32/.pio/libdeps/esp32/TJpg_Decoder/src", "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/SD/src", "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32/.pio/libdeps/esp32/RunningMedian", "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32/.pio/libdeps/esp32/PubSubClient/src", + "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32/.pio/libdeps/esp32/Adafruit Unified Sensor", "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32/.pio/libdeps/esp32/TFT_eSPI", "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/SPI/src", "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/SPIFFS/src", @@ -185,6 +195,7 @@ "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/fb_gfx", "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/cores/esp32", "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/variants/esp32", + "/Users/willemoldemans/Documents/PROJECTEN/AQS-main/Firmware/PM25SensorESP32/.pio/libdeps/esp32/Adafruit GFX Library", "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/ArduinoOTA/src", "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/AsyncUDP/src", "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/AzureIoT/src", @@ -207,7 +218,6 @@ "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src", "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/WiFiClientSecure/src", "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/WiFiProv/src", - "/Users/willemoldemans/.platformio/packages/framework-arduinoespressif32/libraries/Wire/src", "/Users/willemoldemans/.platformio/packages/tool-unity", "" ] diff --git a/CO2_sensor.cpp b/CO2_sensor.cpp index 8c4f4e1..94db54a 100644 --- a/CO2_sensor.cpp +++ b/CO2_sensor.cpp @@ -3,36 +3,53 @@ Adafruit_SCD30 scd30; #define CO2_INTERVAL 120000 //ms +#define SCD30TEMPMAX 50 +#define SDC30HUMMAX 100 +#define SCD30CO2MAX 20000 +#define SCD30MIN 0 uint8_t CO2_samples = 3600 / g_pms_report_period; -AQSSensor SCD30_temperature("Temperature", device_name, CO2_samples); -AQSSensor SCD30_Humidity("Humidity", device_name, CO2_samples); -AQSSensor SCD30_CO2("CO2", device_name, CO2_samples); +AQSSensor SCD30_temperature("Temperature", SCD30_temp, "degC", device_name, CO2_samples, SCD30MIN, SCD30TEMPMAX); +AQSSensor SCD30_Humidity("Humidity", SCD30_hum, "%RH", device_name, CO2_samples, SCD30MIN, SDC30HUMMAX); +AQSSensor SCD30_CO2("CO2", SCD30_co2, "PPM", device_name, CO2_samples, SCD30MIN, SCD30CO2MAX); uint32_t CO2_lastUpdate = 0; void initCO2sensor(void) { - Serial.print("Init SCD30:"); - if (!scd30.begin(true)) + Serial.println("SCD30: init"); + if (!scd30.begin()) { - Serial.println("Failed to find SCD30 device"); + Serial.println("SCD30: Failed to find sensor"); } + else + { + //configure sensor + scd30.setMeasurementInterval(g_pms_report_period); - addSensorToList(&SCD30_temperature); - addSensorToList(&SCD30_Humidity); - addSensorToList(&SCD30_CO2); + addSensorToList(&SCD30_temperature); + addSensorToList(&SCD30_Humidity); + addSensorToList(&SCD30_CO2); - Serial.println(" OK"); + //check callibration Mode + scd30.selfCalibrationEnabled(false); + scd30.read(); + Serial.println("SCD30: init OK"); + } } void handleCO2sensor(void) { uint32_t currentmillis = millis(); - - if (currentmillis - CO2_lastUpdate > CO2_INTERVAL) + if ((currentmillis - CO2_lastUpdate > (g_pms_report_period * 1000)) || (!CO2_lastUpdate) && (scd30.dataReady())) { + if (!scd30.read()) + { + Serial.println("SCD30: read error!"); + return; + } + SCD30_temperature.set(uint32_t(scd30.temperature)); SCD30_Humidity.set(uint32_t(scd30.relative_humidity)); SCD30_CO2.set(uint32_t(scd30.CO2)); @@ -40,5 +57,7 @@ void handleCO2sensor(void) SCD30_temperature.publish(); SCD30_Humidity.publish(); SCD30_CO2.publish(); + + CO2_lastUpdate = currentmillis; } } \ No newline at end of file diff --git a/VOC_sensor.cpp b/VOC_sensor.cpp new file mode 100644 index 0000000..dfc3b5f --- /dev/null +++ b/VOC_sensor.cpp @@ -0,0 +1,69 @@ +#include "VOC_sensor.h" + +Adafruit_SGP30 sgp; +uint8_t VOC_samples = 3600 / g_pms_report_period; +#define VOC_MIN 0 +#define VOC_MAX 10000 +#define VOC_INTERVAL 120000 //ms + +uint32_t lastVOCtime = 0; +//sensors +AQSSensor SGP30_tvoc("TVOC", SGP30_TVOC, "ppb", device_name, VOC_samples, VOC_MIN, VOC_MAX); +AQSSensor SGP30_eco2("eCO2", SGP30_eCO2, "ppm", device_name, VOC_samples, VOC_MIN, VOC_MAX); +AQSSensor SGP30_rawh2("Raw_H2", SGP30_rawH2, "#", device_name, VOC_samples, VOC_MIN, VOC_MAX); +AQSSensor SGP30_rawethanol("Raw_Ethanol", SGP30_rawEthanol, "#", device_name, VOC_samples, VOC_MIN, VOC_MAX); + +void initVOCsensor(void) +{ + Serial.println("VOCSensor: Init SGP30: "); + + if (!sgp.begin()) + { + Serial.println("VOCSensor: Init Failed (SGP30 not found)"); + } + else + { + Serial.printf("VOCSensor: serial =0x%X%X%X\n", sgp.serialnumber[0], sgp.serialnumber[1], sgp.serialnumber[2]); + addSensorToList(&SGP30_tvoc); + addSensorToList(&SGP30_eco2); + addSensorToList(&SGP30_rawh2); + addSensorToList(&SGP30_rawethanol); + + sgp.IAQmeasure(); + sgp.IAQmeasureRaw(); + + Serial.println("VOCSensor: Init OK"); + } +} + +void handleVOCsensor(void) +{ + uint32_t timenow = millis(); + if ((timenow - lastVOCtime > VOC_INTERVAL) || !lastVOCtime) + { + if (!sgp.IAQmeasure()) + { + Serial.println("VOCSensor: Measurement failed"); + return; + } + SGP30_tvoc.set(sgp.TVOC); + SGP30_eco2.set(sgp.eCO2); + + SGP30_tvoc.publish(); +SGP30_eco2.publish(); + + if (!sgp.IAQmeasureRaw()) + { + Serial.println("VOCSensor: Raw Measurement failed"); + return; + } + + SGP30_rawethanol.set(sgp.rawEthanol); + SGP30_rawh2.set(sgp.rawH2); + + SGP30_rawethanol.publish(); + SGP30_rawh2.publish(); + + lastVOCtime = timenow; + } +} \ No newline at end of file diff --git a/VOC_sensor.h b/VOC_sensor.h new file mode 100644 index 0000000..bbd9ff0 --- /dev/null +++ b/VOC_sensor.h @@ -0,0 +1,11 @@ +#pragma once + +#include "Arduino.h" +#include "config.h" +#include "sensor.h" + +#include "Adafruit_SGP30.h" + + +void initVOCsensor(void); +void handleVOCsensor(void); \ No newline at end of file diff --git a/lcd.cpp b/lcd.cpp index 4b02abc..fb2cce1 100644 --- a/lcd.cpp +++ b/lcd.cpp @@ -36,6 +36,8 @@ TFT_eSPI tft = TFT_eSPI(); TFT_eSprite needle = TFT_eSprite(&tft); // Sprite object for needle TFT_eSprite spr = TFT_eSprite(&tft); // Sprite for meter reading +TFT_eSprite nameSpr = TFT_eSprite(&tft); +TFT_eSprite unitSpr = TFT_eSprite(&tft); // Jpeg image array attached to this sketch #include "dial.h" @@ -46,6 +48,7 @@ TFT_eSprite spr = TFT_eSprite(&tft); // Sprite for meter reading uint16_t *tft_buffer; bool buffer_loaded = false; uint16_t spr_width = 0; +uint16_t name_spr_width = 0; void createNeedle(void); void plotNeedle(int16_t angle, uint16_t ms_delay); @@ -99,9 +102,16 @@ void initLCD() spr.pushSprite(DIAL_CENTRE_X - spr_width / 2, DIAL_CENTRE_Y - spr.fontHeight() / 2); // Plot the label text - tft.setTextColor(TFT_WHITE, bg_color); - tft.setTextDatum(MC_DATUM); - tft.drawString("(PM2.5 ug/m3)", DIAL_CENTRE_X, DIAL_CENTRE_Y + 48, 2); + nameSpr.setTextFont(3); + name_spr_width = nameSpr.textWidth("Temperature"); + nameSpr.createSprite(name_spr_width, nameSpr.fontHeight() * 2 + 2); + nameSpr.fillSprite(bg_color); + nameSpr.setTextColor(TFT_WHITE, bg_color); + nameSpr.setTextDatum(MC_DATUM); + nameSpr.setTextPadding(name_spr_width); + nameSpr.drawString("Sensor Name", name_spr_width / 2, nameSpr.fontHeight() / 2); + nameSpr.drawString("Unit", name_spr_width / 2, nameSpr.fontHeight() / 2 * 3 + 2); nameSpr.pushSprite(DIAL_CENTRE_X - name_spr_width / 2, DIAL_CENTRE_Y + 40, 2); + nameSpr.pushSprite(DIAL_CENTRE_X - name_spr_width / 2, DIAL_CENTRE_Y + 40, 2); // Define where the needle pivot point is on the TFT before // creating the needle so boundary calculation is correct @@ -120,11 +130,101 @@ void initLCD() // ======================================================================================= // Loop // ======================================================================================= +enum DISPLAY_STATE +{ + DISPLAY_PM1P0, + DISPLAY_PM2P5, + DISPLAY_PM10P0, + DISPLAY_TEMP, + DISPLAY_HUM, + DISPLAY_CO2, + DISPLAY_LAST +}; + +DISPLAY_STATE displaystate = DISPLAY_PM1P0; +uint32_t display_last_update = 0; + +#define MAXGUAGE 240 +#define MINGUAGE 0 +#define DISPLAY_ROTATE 10 //sec + void handleLCD() { + static uint32_t value; + static uint16_t angle; + DISPLAY_STATE displaystate_next = DISPLAY_PM1P0; + sensor_e nextSensor = AE_1P0; + + switch (displaystate) + { + case DISPLAY_PM1P0: + { + nextSensor = AE_1P0; + displaystate_next = DISPLAY_PM2P5; + } + break; + case DISPLAY_PM2P5: + { + nextSensor = AE_2P5; + displaystate_next = DISPLAY_PM10P0; + } + break; + case DISPLAY_PM10P0: + { + nextSensor = AE_10P0; + displaystate_next = DISPLAY_TEMP; + } + break; + case DISPLAY_TEMP: + { + nextSensor = SCD30_temp; + displaystate_next = DISPLAY_HUM; + } + break; + case DISPLAY_HUM: + { + nextSensor = SCD30_hum; + displaystate_next = DISPLAY_CO2; + } + break; + case DISPLAY_CO2: + { + nextSensor = SCD30_hum; + displaystate_next = DISPLAY_PM1P0; + } + break; + + case DISPLAY_LAST: + default: + { + displaystate_next = DISPLAY_PM1P0; + } + break; + } + //rotate display + uint32_t timenow = millis(); + if (timenow - display_last_update > (DISPLAY_ROTATE * 1000)) + { + displaystate = displaystate_next; + display_last_update = timenow; + Serial.println("LCD next State"); + } //calculate value to angle - uint16_t angle = map(getLCDvalue(),0,50,0,240); - plotNeedle(angle,15, getLCDvalue()); + + AQSSensor *sensor = getSensor(nextSensor); + if (sensor == NULL) + { + Serial.println("LCD: getSensor=NULL!"); + return; + } + + angle = map(value, sensor->getMin(), sensor->getMax(), MINGUAGE, MAXGUAGE); + + plotNeedle(angle, 15, value); + + nameSpr.drawString(sensor->getName().c_str(), name_spr_width / 2, nameSpr.fontHeight() / 2); + nameSpr.drawString(sensor->getUnit().c_str(), name_spr_width / 2, nameSpr.fontHeight() / 2 * 3 + 2); + nameSpr.pushSprite(DIAL_CENTRE_X - name_spr_width / 2, DIAL_CENTRE_Y + 40, 2); } // ======================================================================================= diff --git a/lcd.h b/lcd.h index 58d5253..d07e80c 100644 --- a/lcd.h +++ b/lcd.h @@ -1,7 +1,7 @@ #pragma once #include "Arduino.h" -#include "particles.h" +#include "sensor.h" void initLCD(); void handleLCD(); diff --git a/main.cpp b/main.cpp index 63968dc..f27e2a3 100644 --- a/main.cpp +++ b/main.cpp @@ -36,9 +36,10 @@ /*--------------------------- Modules ------------------------------------*/ #include "lcd.h" #include "mqtt.h" +#include "sensor.h" #include "particles.h" #include "CO2_sensor.h" -#include "sensor.h" +#include "VOC_sensor.h" #include "button.h" /*--------------------------- Program ---------------------------------------*/ @@ -52,12 +53,15 @@ void setup() Serial.print("Air Quality Sensor starting up, v"); Serial.println(VERSION); + digitalWrite(5, false); + initWifi(); initMQTT(); initSensor(); initParticles(); initCO2sensor(); - initLCD(); + initVOCsensor(); + //initLCD(); initButtons(); } @@ -68,8 +72,9 @@ void loop() { handleParticles(); handleCO2sensor(); + handleVOCsensor(); handleButtons(); handleSensor(); - handleLCD(); + //handleLCD(); handleMQTT(); } diff --git a/mqtt.cpp b/mqtt.cpp index c918cb8..f982126 100644 --- a/mqtt.cpp +++ b/mqtt.cpp @@ -137,6 +137,11 @@ void handleMQTT(void) if (!client.connected()) { reconnectMqtt(); + if(!client.connected()) + { + Serial.print("OK"); + } + Serial.println(""); } } client.loop(); // Process any outstanding MQTT messages diff --git a/particles.cpp b/particles.cpp index a0ee574..8924d4d 100644 --- a/particles.cpp +++ b/particles.cpp @@ -10,6 +10,9 @@ char g_command_topic[50]; // MQTT topic for receiving commands #define PMS_STATE_ASLEEP 0 // Low power mode, laser and fan off #define PMS_STATE_WAKING_UP 1 // Laser and fan on, not ready yet #define PMS_STATE_READY 2 // Warmed up, ready to give data +#define PMSMAX 50 +#define PSMMIN 0 +#define PPDMAX 2000 uint8_t g_pms_state = PMS_STATE_WAKING_UP; uint32_t g_pms_state_start = 0; // Timestamp when PMS state last changed @@ -18,20 +21,19 @@ uint8_t g_pms_ppd_readings_taken = 0; // 0/1: whether PPD readings have been tak uint8_t samples = 3600 / g_pms_report_period; -AQSSensor g_pm1p0_sp("SP_1P0", device_name, samples); -AQSSensor g_pm2p5_sp("SP_2P5", device_name, samples); -AQSSensor g_pm10p0_sp("SP_10P0", device_name, samples); - -AQSSensor g_pm1p0_ae("AE_1P0", device_name, samples); -AQSSensor g_pm2p5_ae("AE_2P5", device_name, samples); -AQSSensor g_pm10p0_ae("AE_10P0", device_name, samples); - -AQSSensor g_pm0p3_ppd("PPD_0P3", device_name, samples); -AQSSensor g_pm0p5_ppd("PPD_0P5", device_name, samples); -AQSSensor g_pm1p0_ppd("PPD_1P0", device_name, samples); -AQSSensor g_pm2p5_ppd("PPD_2P5", device_name, samples); -AQSSensor g_pm5p0_ppd("PPD_5P0", device_name, samples); -AQSSensor g_pm10p0_ppd("PPD_10P0", device_name, samples); +// name enum unit device name samples/h, min, max +AQSSensor g_pm1p0_sp("SP_1P0", SP_1P0, "", device_name, samples, PSMMIN, PMSMAX); +AQSSensor g_pm2p5_sp("SP_2P5", SP_2P5, "", device_name, samples, PSMMIN, PMSMAX); +AQSSensor g_pm10p0_sp("SP_10P0", SP_10P0, "", device_name, samples, PSMMIN, PMSMAX); +AQSSensor g_pm1p0_ae("AE_1P0", AE_1P0, "ug/m3", device_name, samples, PSMMIN, PMSMAX); +AQSSensor g_pm2p5_ae("AE_2P5", AE_2P5, "ug/m3", device_name, samples, PSMMIN, PMSMAX); +AQSSensor g_pm10p0_ae("AE_10P0", AE_10P0, "ug/m3", device_name, samples, PSMMIN, PMSMAX); +AQSSensor g_pm0p3_ppd("PPD_0P3", PPD_0P3, "", device_name, samples, PSMMIN, PPDMAX); +AQSSensor g_pm0p5_ppd("PPD_0P5", PPD_0P5, "", device_name, samples, PSMMIN, PPDMAX); +AQSSensor g_pm1p0_ppd("PPD_1P0", PPD_1P0, "", device_name, samples, PSMMIN, PPDMAX); +AQSSensor g_pm2p5_ppd("PPD_2P5", PPD_2P5, "", device_name, samples, PSMMIN, PPDMAX); +AQSSensor g_pm5p0_ppd("PPD_5P0", PPD_5P0, "", device_name, samples, PSMMIN, PPDMAX); +AQSSensor g_pm10p0_ppd("PPD_10P0",PPD_10P0, "", device_name, samples, PSMMIN, PPDMAX); void PMS_publishSensors(void ); @@ -62,7 +64,6 @@ uint32_t getLCDvalue(void) void PMS_publishSensors(void ) { - String message_string; /* Report PM1.0 AE value */ g_pm1p0_ae.publish(); @@ -87,7 +88,7 @@ void PMS_publishSensors(void ) void initParticles( void ) { - Serial.print("initPMS:"); + Serial.println("PMS: Init"); // Open a connection to the PMS and put it into passive mode Serial2.begin(PMS_BAUD_RATE, SERIAL_8N1, PMS_RX_PIN, PMS_TX_PIN); // Connection for PMS5003 pms.activeMode(); // Tell PMS to stop sending data automatically @@ -98,7 +99,7 @@ void initParticles( void ) PMS_AddSensors(); - Serial.println(" OK"); + Serial.println("PMS: Init OK"); } @@ -112,7 +113,7 @@ void handleParticles( void ) if (time_now - g_pms_state_start >= ((g_pms_report_period * 1000) - (g_pms_warmup_period * 1000))) { // It's time to wake up the sensor - Serial.println("Waking up sensor"); + Serial.println("PMS: Waking up sensor"); pms.wakeUp(); g_pms_state_start = time_now; g_pms_state = PMS_STATE_WAKING_UP; @@ -170,4 +171,5 @@ void handleParticles( void ) g_pms_state = PMS_STATE_ASLEEP; } } -} \ No newline at end of file +} + diff --git a/platformio.ini b/platformio.ini index 02450c5..04be749 100644 --- a/platformio.ini +++ b/platformio.ini @@ -22,7 +22,7 @@ lib_deps = robtillaart/RunningMedian bodmer/Tjpg_decoder adafruit/Adafruit SCD30 - adafruit/Adafruit BusIO + adafruit/Adafruit BusIO [env:esp32] platform = espressif32 @@ -32,4 +32,4 @@ monitor_speed = 115200 lib_deps = ${common.lib_deps_builtin} ${common.lib_deps} - + adafruit/Adafruit SGP30 Sensor@^2.0.0 diff --git a/sensor.cpp b/sensor.cpp index 76f4f32..52aed15 100644 --- a/sensor.cpp +++ b/sensor.cpp @@ -1,6 +1,5 @@ #include "sensor.h" - std::vector sensorList; void publishAll(void); @@ -17,7 +16,7 @@ void reportToSerial(void) void addSensorToList(AQSSensor* sensor) { sensorList.push_back(sensor); - Serial.printf("AQSSensor: added %s", sensor->getName().c_str()); + Serial.printf("sensor: added %s\n", sensor->getName().c_str()); } @@ -27,16 +26,40 @@ void publishAll(void) { sensor->print(); sensor->publishMQTT(); + sensor->published(); } } void initSensor(void) { - Serial.print("InitSensor:"); - Serial.println(" OK"); + Serial.println("Sensor: Init"); + Serial.println("Sensor: Init OK"); } void handleSensor(void) { publishAll(); -} \ No newline at end of file +} + +AQSSensor* getSensor(sensor_e sensor) +{ + for(auto && thissensor : sensorList) + { + if(thissensor->getSensor() == sensor) + { + return thissensor; + } + } + return NULL; +} + +uint32_t getSensorValue(sensor_e sensor) +{ + AQSSensor *thissensor = getSensor(sensor); + if(thissensor == NULL) + { + Serial.println("Sensor: failed to get sensor"); + return 999; + } + return thissensor->value(); +} diff --git a/sensor.h b/sensor.h index f42f07d..86615f2 100644 --- a/sensor.h +++ b/sensor.h @@ -3,21 +3,57 @@ #include "Arduino.h" #include "mqtt.h" +enum sensor_e +{ + //PMS sensors + SP_1P0, + SP_2P5, + SP_10P0, + AE_1P0, + AE_2P5, + AE_10P0, + PPD_0P3, + PPD_0P5, + PPD_1P0, + PPD_2P5, + PPD_5P0, + PPD_10P0, + SCD30_temp, + SCD30_hum, + SCD30_co2, + SGP30_TVOC, + SGP30_eCO2, + SGP30_rawH2, + SGP30_rawEthanol, + sensor_last +}; + class AQSSensor { char _topic[50]; char _topic_1h[50]; char _topic_24h[255]; const String _name; + const sensor_e _sensor; + const String _unit; uint32_t _value; RunningMedian _average1h; RunningMedian _average24h; bool _publish = false; + const uint32_t _scaleMin; + const uint32_t _scaleMax; public: - AQSSensor(String name, String deviceID, uint8_t avgSamples) : _name(name), - _average1h(avgSamples), - _average24h(avgSamples * 24) + AQSSensor(String name, sensor_e sensor, String unit, + String deviceID, uint8_t avgSamples, + uint32_t scaleMin, uint32_t scaleMax) + : _name(name), + _sensor(sensor), + _unit(unit), + _average1h(avgSamples), + _average24h(avgSamples * 24), + _scaleMin(scaleMin), + _scaleMax(scaleMax) { sprintf(_topic, "Sensors/%s/%s", deviceID.c_str(), name.c_str()); sprintf(_topic_1h, "Sensors/%s/%s/1h/", deviceID.c_str(), name.c_str()); @@ -34,6 +70,11 @@ public: return _name; } + void published(void) + { + _publish = false; + } + void publishMQTT(void) { if (_publish == true) @@ -58,13 +99,22 @@ public: { if (_publish) { - Serial.printf("sensor:%s = %d\n", _name.c_str(), _value); + Serial.printf("sensor: report: %s = %d\n", _name.c_str(), _value); } } + + sensor_e getSensor(void) { return _sensor; } + + String getUnit(void) { return _unit;} + + uint32_t getMin(void) { return _scaleMin; } + uint32_t getMax(void) { return _scaleMax; } }; void addSensorToList(AQSSensor *sensor); void reportToSerial(void); +AQSSensor *getSensor(sensor_e sensor); +uint32_t getSensorValue(sensor_e sensor); void initSensor(void); void handleSensor(void); \ No newline at end of file