diff --git a/firmware/CMakeListsPrivate.txt b/firmware/CMakeListsPrivate.txt index 3de7299..e39b280 100644 --- a/firmware/CMakeListsPrivate.txt +++ b/firmware/CMakeListsPrivate.txt @@ -21,7 +21,7 @@ SET(CMAKE_C_STANDARD 99) set(CMAKE_CXX_STANDARD 11) if (CMAKE_BUILD_TYPE MATCHES "esp32dev") - add_definitions(-DPLATFORMIO=50204) + add_definitions(-DPLATFORMIO=50205) add_definitions(-DARDUINO_ESP32_DEV) add_definitions(-DESP32) add_definitions(-DESP_PLATFORM) @@ -36,6 +36,8 @@ if (CMAKE_BUILD_TYPE MATCHES "esp32dev") include_directories("${CMAKE_CURRENT_LIST_DIR}/include") include_directories("${CMAKE_CURRENT_LIST_DIR}/src") include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/BLE/src") + include_directories("${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/esp32dev/esp_sds011/src") + include_directories("${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/esp32dev/EspSoftwareSerial/src") include_directories("${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/esp32dev/Adafruit BMP280 Library") include_directories("${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/esp32dev/Adafruit BusIO") include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/SPI/src") diff --git a/firmware/platformio.ini b/firmware/platformio.ini index 1a0090b..6db8dfe 100644 --- a/firmware/platformio.ini +++ b/firmware/platformio.ini @@ -13,3 +13,4 @@ platform = espressif32 board = esp32dev framework = arduino lib_deps = adafruit/Adafruit BMP280 Library@^2.6.1 + dok-net/esp_sds011@^1.0.0 diff --git a/firmware/src/main.cpp b/firmware/src/main.cpp index fe9f32d..f9fc036 100644 --- a/firmware/src/main.cpp +++ b/firmware/src/main.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #define SLEEP_TIME 1 #define BAUD_RATE 112500 @@ -9,6 +10,7 @@ Sensor *bmpSensor; +Sensor *pmSensor; BluetoothServer *server; bool makeDiscoverable = false; @@ -18,11 +20,16 @@ void IRAM_ATTR startBleServerAdvertising() { } void setup() { + //initialize a Serial Connection Serial.begin(BAUD_RATE); + //setup the internal LED pinMode(INTERNAL_LED_PIN, OUTPUT); + //create sensor objects bmpSensor = new BmpSensor(); + pmSensor = new PmSensor(); + //setup & start Bluetooth server server = new BluetoothServer(); server->startServer(); @@ -39,8 +46,22 @@ void loop() { makeDiscoverable = false; } + //setup PM sensor measurement TODO: This blocks for 120 seconds and needs to be executed asynchronously + //((PmSensor *) pmSensor)->startAsyncSampling(); + + //obtain measurement from BMP280 Sensor sensor_data_t sample = ((BmpSensor *) bmpSensor)->sampleLowEnergy(); server->setPressure(sample.pressure); server->setTemperature(sample.temperature); + //Obtain measurement from PM Sensor + sensor_data_t pmSample = pmSensor->sample(); + + //Print measured data + Serial.printf("Pressure: %f hPa | Temperature: %f °C | PM10: %f ppm| PM2.5: %f ppm\n", + sample.pressure, + sample.temperature, + pmSample.pm10, + pmSample.pm25); + //wait for one measurement cycle delay(SLEEP_TIME * 1000); } \ No newline at end of file diff --git a/firmware/src/sensors/BmpSensor.cpp b/firmware/src/sensors/BmpSensor.cpp index 7f68a25..b4a5724 100644 --- a/firmware/src/sensors/BmpSensor.cpp +++ b/firmware/src/sensors/BmpSensor.cpp @@ -69,7 +69,9 @@ sensor_data_t BmpSensor::sample() { return sensor_data_t { temp_event.temperature, - pressure_event.pressure + pressure_event.pressure, + 0.0, + 0.0 }; } diff --git a/firmware/src/sensors/BmpSensor.h b/firmware/src/sensors/BmpSensor.h index f5949fc..a7d9ffa 100644 --- a/firmware/src/sensors/BmpSensor.h +++ b/firmware/src/sensors/BmpSensor.h @@ -14,6 +14,7 @@ public: BmpSensor(); sensor_data_t sample() override; + sensor_data_t sampleLowEnergy(); void enableStandbyMode() override; diff --git a/firmware/src/sensors/PmSensor.cpp b/firmware/src/sensors/PmSensor.cpp new file mode 100644 index 0000000..7e0fc03 --- /dev/null +++ b/firmware/src/sensors/PmSensor.cpp @@ -0,0 +1,95 @@ +#include "PmSensor.h" +#include +#include + +#define SDS_PIN_RX 18 +#define SDS_PIN_TX 19 +#define SENSOR_BAUD_RATE 9600 +#define SLEEP_TIME 90 +#define MEASURE_TIME 30 + +#ifdef ESP32 +HardwareSerial &serialSDS(Serial2); +Sds011Async sds011(serialSDS); +#else +SoftwareSerial serialSDS; +Sds011Async< SoftwareSerial > sds011(serialSDS); +#endif + + +PmSensor::PmSensor() { + this->PmSensor::sensor_setup(); +} + +void PmSensor::startAsyncSampling() { + + this->enableStandbyMode(); + PmSensor::sensorWait(SLEEP_TIME); + + this->wakeUp(); + sds011.perform_work(); + + if (!sds011.query_data_auto_async(pm_tablesize, pm25_table, pm10_table)) { + Serial.println("measurement capture start failed"); + } + + PmSensor::sensorWait(MEASURE_TIME); +} + +/** + * Put the sensor to standby mode + */ +void PmSensor::enableStandbyMode() { + if (sds011.set_sleep(true)) { this->state = SensorState::ASLEEP; } +} + +/** + * Activate the sensor + */ +void PmSensor::wakeUp() { + if (sds011.set_sleep(false)) { this->state = SensorState::AWAKE; } +} + +/** + * Method to set up and initialize the sensor + */ +void PmSensor::sensor_setup() { +#ifdef ESP32 + serialSDS.begin(SENSOR_BAUD_RATE, SERIAL_8N1, SDS_PIN_RX, SDS_PIN_TX); + delay(100); +#else + serialSDS.begin(SENSOR_BAUD_RATE, SWSERIAL_8N1, SDS_PIN_RX, SDS_PIN_TX, false, 192); +#endif + + //put the sensor into standby mode initially + this->PmSensor::enableStandbyMode(); + Serial.println("SDS011 sensor initialized to standby mode."); + + //attach a callback on what to do when data sampling is complete + sds011.on_query_data_auto_completed([this](int n) { + int pm25; + int pm10; + if (sds011.filter_data(n, pm25_table, pm10_table, pm25, pm10) && + !isnan(pm10) && !isnan(pm25)) { + //set the right values + this->latestPM10 = float(pm10) / 10; + this->latestPM25 = float(pm25) / 10; + } + }); +} + +/** + * Method to wait for some time and perform the appropriate task + * @param time the time to wait for in seconds + */ +void PmSensor::sensorWait(int time) { + uint32_t deadline = millis() + time * 1000; + while (static_cast(deadline - millis()) > 0) { + delay(1000); + sds011.perform_work(); + } +} + +sensor_data_t PmSensor::sample() { + return {0.0, 0.0, this->latestPM10, this->latestPM25}; +} diff --git a/firmware/src/sensors/PmSensor.h b/firmware/src/sensors/PmSensor.h new file mode 100644 index 0000000..3a3bd84 --- /dev/null +++ b/firmware/src/sensors/PmSensor.h @@ -0,0 +1,35 @@ +#ifndef FIRMWARE_PMSENSOR_H +#define FIRMWARE_PMSENSOR_H + +#include "Sensor.h" +#include "sensor_data_t.h" + +class PmSensor : public Sensor { +public: + static const int pm_tablesize = 20; + int pm25_table[pm_tablesize]; + int pm10_table[pm_tablesize]; + + float latestPM10; + float latestPM25; + + PmSensor(); + + sensor_data_t sample() override; + + void startAsyncSampling(); + + + void enableStandbyMode() override; + + void wakeUp() override; + +protected: + void sensor_setup() override; + +private: + static void sensorWait(int time); +}; + + +#endif //FIRMWARE_PMSENSOR_H diff --git a/firmware/src/sensors/Sensor.h b/firmware/src/sensors/Sensor.h index 7f3a1f8..bba9e33 100644 --- a/firmware/src/sensors/Sensor.h +++ b/firmware/src/sensors/Sensor.h @@ -1,5 +1,5 @@ -#ifndef NEW_CLIMTE_GO_SENSOR_H -#define NEW_CLIMTE_GO_SENSOR_H +#ifndef FIRMWARE_SENSOR_H +#define FIRMWARE_SENSOR_H #include diff --git a/firmware/src/sensors/sensor_data_t.h b/firmware/src/sensors/sensor_data_t.h index 0d96e8d..cc76161 100644 --- a/firmware/src/sensors/sensor_data_t.h +++ b/firmware/src/sensors/sensor_data_t.h @@ -1,7 +1,5 @@ -#ifndef NEW_CLIMTE_GO_SENSOR_DATA_T_H -#define NEW_CLIMTE_GO_SENSOR_DATA_T_H - -#include +#ifndef FIRMWARE_SENSOR_DATA_T_H +#define FIRMWARE_SENSOR_DATA_T_H /** * This struct represents data read from any sensor. @@ -11,6 +9,8 @@ struct sensor_data_t { float temperature; float pressure; + float pm10; + float pm25; }; #endif