From 361b092d4e63cdcf7480e243e5e4d77b92fdf4ef Mon Sep 17 00:00:00 2001 From: Clemens-Dautermann Date: Wed, 9 Feb 2022 20:22:55 +0100 Subject: [PATCH 1/8] implemented make discoverable button --- firmware/src/ble/BluetoothServer.cpp | 23 +++++++++++++++++++++++ firmware/src/ble/BluetoothServer.h | 2 ++ firmware/src/main.cpp | 20 +++++++++++++++++++- 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/firmware/src/ble/BluetoothServer.cpp b/firmware/src/ble/BluetoothServer.cpp index 4586e42..5c67cae 100644 --- a/firmware/src/ble/BluetoothServer.cpp +++ b/firmware/src/ble/BluetoothServer.cpp @@ -8,6 +8,8 @@ #define SERVICE_UUID "2150123c-af53-4038-bc92-ba3d0870a9e4" #define TEMPERATURE_CHARACTERISTIC_UUID "cba1d466-344c-4be3-ab3f-189f80dd7518" #define PRESSURE_CHARACTERISTIC_UUID "ca73b3ba-39f6-4ab3-91ae-186dc9577d99" +#define BLINK_TIME_DELAY_MS 500 +#define BLINK_TIMES 5 //Setup callbacks onConnect and onDisconnect class ServerCallbacks : public BLEServerCallbacks { @@ -51,6 +53,9 @@ BluetoothServer::BluetoothServer() { //set initial values temperatureCharacteristic->setValue("NA"); pressureCharacteristic->setValue("NA"); + + //allow advertiser function to be called + this->advertiserLock = false; } /** @@ -89,4 +94,22 @@ void BluetoothServer::setPressure(float pressure) { ->setValue(pressure); } +/** + * This method will start advertising via Bluetooth and blink the LED + */ +void BluetoothServer::startAdvertising() { + if (!this->advertiserLock) { + this->advertiserLock = true; + this->bleServer->getAdvertising()->start(); + Serial.println("Starting Bluetooth advertising..."); + for (int i = 0; i < BLINK_TIMES; ++i) { + digitalWrite(INTERNAL_LED_PIN, HIGH); + delay(BLINK_TIME_DELAY_MS); + digitalWrite(INTERNAL_LED_PIN, LOW); + delay(BLINK_TIME_DELAY_MS); + } + this->advertiserLock = false; + } +} + diff --git a/firmware/src/ble/BluetoothServer.h b/firmware/src/ble/BluetoothServer.h index 4afd1ec..ecbe38f 100644 --- a/firmware/src/ble/BluetoothServer.h +++ b/firmware/src/ble/BluetoothServer.h @@ -13,9 +13,11 @@ class BluetoothServer { private: BLEService *sensorService; BLEServer *bleServer; + bool advertiserLock; public: BluetoothServer(); + void startAdvertising(); void startServer(); void setTemperature(float temperature); void setPressure(float pressure); diff --git a/firmware/src/main.cpp b/firmware/src/main.cpp index 38b5852..fe9f32d 100644 --- a/firmware/src/main.cpp +++ b/firmware/src/main.cpp @@ -2,13 +2,20 @@ #include #include -#define SLEEP_TIME 2 +#define SLEEP_TIME 1 #define BAUD_RATE 112500 #define INTERNAL_LED_PIN 2 +#define INTERRUPT_MAKE_DISCOVERABLE_PIN 15 Sensor *bmpSensor; BluetoothServer *server; +bool makeDiscoverable = false; + + +void IRAM_ATTR startBleServerAdvertising() { + makeDiscoverable = true; +} void setup() { Serial.begin(BAUD_RATE); @@ -18,9 +25,20 @@ void setup() { server = new BluetoothServer(); server->startServer(); + + //set up Interrupt to enable make discoverable button + pinMode(INTERRUPT_MAKE_DISCOVERABLE_PIN, INPUT_PULLDOWN); + attachInterrupt(digitalPinToInterrupt(INTERRUPT_MAKE_DISCOVERABLE_PIN), + startBleServerAdvertising, + RISING); } void loop() { + if (makeDiscoverable) { + server->startAdvertising(); + makeDiscoverable = false; + } + sensor_data_t sample = ((BmpSensor *) bmpSensor)->sampleLowEnergy(); server->setPressure(sample.pressure); server->setTemperature(sample.temperature); From 9225cb3d51e74c8ef31976389e3abf6d83cfc99b Mon Sep 17 00:00:00 2001 From: Clemens-Dautermann Date: Wed, 9 Feb 2022 21:38:43 +0100 Subject: [PATCH 2/8] excluded app dev directory --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 5dcc104..50b7945 100644 --- a/.gitignore +++ b/.gitignore @@ -444,3 +444,6 @@ obj/ # End of https://www.toptal.com/developers/gitignore/api/platformio,c,cmake,c++,intellij,android,androidstudio,clion+all,java + +###only in firmware_dev +ClimateGoApp/ From 8097446a16dc2ca472416d6e91b870953c4db5e3 Mon Sep 17 00:00:00 2001 From: Clemens-Dautermann Date: Wed, 9 Feb 2022 21:40:09 +0100 Subject: [PATCH 3/8] some weird line ending change... --- firmware/CMakeListsPrivate.txt | 150 +++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 firmware/CMakeListsPrivate.txt diff --git a/firmware/CMakeListsPrivate.txt b/firmware/CMakeListsPrivate.txt new file mode 100644 index 0000000..3de7299 --- /dev/null +++ b/firmware/CMakeListsPrivate.txt @@ -0,0 +1,150 @@ +# !!! WARNING !!! AUTO-GENERATED FILE, PLEASE DO NOT MODIFY IT AND USE +# https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags +# +# If you need to override existing CMake configuration or add extra, +# please create `CMakeListsUser.txt` in the root of project. +# The `CMakeListsUser.txt` will not be overwritten by PlatformIO. + + + +set(CMAKE_CONFIGURATION_TYPES "esp32dev" CACHE STRING "Build Types reflect PlatformIO Environments" FORCE) + +# Convert "Home Directory" that may contain unescaped backslashes on Windows + + +SET(CMAKE_C_COMPILER "$ENV{HOME}/.platformio/packages/toolchain-xtensa32/bin/xtensa-esp32-elf-gcc") +SET(CMAKE_CXX_COMPILER "$ENV{HOME}/.platformio/packages/toolchain-xtensa32/bin/xtensa-esp32-elf-g++") +SET(CMAKE_CXX_FLAGS "-fno-rtti -fno-exceptions -std=gnu++11 -Os -g3 -Wall -nostdlib -Wpointer-arith -Wno-error=unused-but-set-variable -Wno-error=unused-variable -mlongcalls -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -Wno-error=deprecated-declarations -Wno-error=unused-function -Wno-unused-parameter -Wno-sign-compare -fstack-protector -fexceptions -Werror=reorder") +SET(CMAKE_C_FLAGS "-std=gnu99 -Wno-old-style-declaration -Os -g3 -Wall -nostdlib -Wpointer-arith -Wno-error=unused-but-set-variable -Wno-error=unused-variable -mlongcalls -ffunction-sections -fdata-sections -fstrict-volatile-bitfields -Wno-error=deprecated-declarations -Wno-error=unused-function -Wno-unused-parameter -Wno-sign-compare -fstack-protector -fexceptions -Werror=reorder") + +SET(CMAKE_C_STANDARD 99) +set(CMAKE_CXX_STANDARD 11) + +if (CMAKE_BUILD_TYPE MATCHES "esp32dev") + add_definitions(-DPLATFORMIO=50204) + add_definitions(-DARDUINO_ESP32_DEV) + add_definitions(-DESP32) + add_definitions(-DESP_PLATFORM) + add_definitions(-DF_CPU=240000000L) + add_definitions(-DHAVE_CONFIG_H) + add_definitions(-DMBEDTLS_CONFIG_FILE=\"mbedtls/esp_config.h\") + add_definitions(-DARDUINO=10805) + add_definitions(-DARDUINO_ARCH_ESP32) + add_definitions(-DARDUINO_VARIANT=\"esp32\") + add_definitions(-DARDUINO_BOARD=\"Espressif\ ESP32\ Dev\ Module\") + + 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/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") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/Wire/src") + include_directories("${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/esp32dev/Adafruit Unified Sensor") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/config") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/app_trace") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/app_update") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/asio") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/bootloader_support") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/bt") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/coap") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/console") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/driver") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/efuse") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp-tls") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp32") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_adc_cal") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_event") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_http_client") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_http_server") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_https_ota") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_https_server") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_ringbuf") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp_websocket_client") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/espcoredump") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/ethernet") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/expat") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/fatfs") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/freemodbus") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/freertos") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/heap") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/idf_test") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/jsmn") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/json") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/libsodium") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/log") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/lwip") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/mbedtls") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/mdns") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/micro-ecc") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/mqtt") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/newlib") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/nghttp") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/nvs_flash") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/openssl") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/protobuf-c") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/protocomm") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/pthread") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/sdmmc") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/smartconfig_ack") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/soc") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/spi_flash") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/spiffs") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/tcp_transport") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/tcpip_adapter") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/ulp") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/unity") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/vfs") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/wear_levelling") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/wifi_provisioning") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/wpa_supplicant") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/xtensa-debug-module") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp-face") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/esp32-camera") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/include/fb_gfx") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/cores/esp32") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/variants/esp32") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/ArduinoOTA/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/AsyncUDP/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/AzureIoT/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/BluetoothSerial/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/DNSServer/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/EEPROM/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/ESP32/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/ESPmDNS/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/FFat/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/FS/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/HTTPClient/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/HTTPUpdate/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/HTTPUpdateServer/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/NetBIOS/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/Preferences/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/SD/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/SD_MMC/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/SPIFFS/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/SimpleBLE/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/Ticker/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/Update/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/WiFi/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/WiFiClientSecure/src") + include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/WiFiProv/src") + include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa32/xtensa-esp32-elf/include/c++/5.2.0") + include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa32/xtensa-esp32-elf/include/c++/5.2.0/xtensa-esp32-elf") + include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa32/lib/gcc/xtensa-esp32-elf/5.2.0/include-fixed") + include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa32/lib/gcc/xtensa-esp32-elf/5.2.0/include") + include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa32/xtensa-esp32-elf/include") + + FILE(GLOB_RECURSE EXTRA_LIB_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/esp32dev/*.* + ) +endif() + + +FILE(GLOB_RECURSE SRC_LIST + ${CMAKE_CURRENT_LIST_DIR}/src/*.* + ${CMAKE_CURRENT_LIST_DIR}/lib/*.* + ${CMAKE_CURRENT_LIST_DIR}/test/*.* +) + +list(APPEND SRC_LIST ${EXTRA_LIB_SOURCES}) From 74686e9b85905f4da92c3e553eaa1da748a75492 Mon Sep 17 00:00:00 2001 From: CDautermann Date: Wed, 9 Feb 2022 21:43:19 +0100 Subject: [PATCH 4/8] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f1c2bd9..4a71f26 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Climate GO -Climate GO is a fully open source open hardware Sensor pack, to track and analyze personal air quality data. It's goal is to provide a way to monitor ones own air quality and motivate people to avoid polluted places and protect the environment. +Climate GO is a fully open source open hardware Sensor pack, to track and analyze personal air quality data. Its goal is to provide a way to monitor ones own air quality and motivate people to avoid polluted places and protect the environment. ## Paradigms This project is intended to be open source, open hardware and open data oriented. It is of central importance to make this available to anyone who whishes to build a climate go device and to ensure no personal data is collected and stored. This is especially important because the climate data collected will be correlated with GPS information and could thus be used to construct a movement profile if not handled with uttermost care. @@ -17,4 +17,4 @@ A custom PCB/housing is yet to be designed and manufactured. Data collection is ## Outlook It might be interesting to add more types of sensors, to collect more information and provide a broader picture of personal air quality. However this will increase cost and power consumption of the sensor and must thus be considered carefully. -It would also be interesting to "gamify" the idea, by providing users the opportunity to collect awards and complete quests related to personal air quality, increasing the motivation to protect the environment and b healthy even more. \ No newline at end of file +It would also be interesting to "gamify" the idea, by providing users the opportunity to collect awards and complete quests related to personal air quality, increasing the motivation to protect the environment and b healthy even more. From 89d6acf1812036a9c0900bc39530023c191f27f2 Mon Sep 17 00:00:00 2001 From: Clemens-Dautermann Date: Mon, 14 Feb 2022 18:39:31 +0100 Subject: [PATCH 5/8] started implementing PM sensor --- firmware/CMakeListsPrivate.txt | 4 +- firmware/platformio.ini | 1 + firmware/src/main.cpp | 21 ++++++ firmware/src/sensors/BmpSensor.cpp | 4 +- firmware/src/sensors/BmpSensor.h | 1 + firmware/src/sensors/PmSensor.cpp | 95 ++++++++++++++++++++++++++++ firmware/src/sensors/PmSensor.h | 35 ++++++++++ firmware/src/sensors/Sensor.h | 4 +- firmware/src/sensors/sensor_data_t.h | 8 +-- 9 files changed, 165 insertions(+), 8 deletions(-) create mode 100644 firmware/src/sensors/PmSensor.cpp create mode 100644 firmware/src/sensors/PmSensor.h 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 From fe18044edd176c45a78a79311eb2c3bf89e24740 Mon Sep 17 00:00:00 2001 From: CDaut Date: Mon, 14 Feb 2022 20:09:10 +0100 Subject: [PATCH 6/8] implemented async PM sensor sampling --- firmware/src/main.cpp | 24 +++++++++++---- firmware/src/sensors/PmSensor.cpp | 50 +++++++++++++++++-------------- firmware/src/sensors/PmSensor.h | 2 +- 3 files changed, 48 insertions(+), 28 deletions(-) diff --git a/firmware/src/main.cpp b/firmware/src/main.cpp index f9fc036..51b119b 100644 --- a/firmware/src/main.cpp +++ b/firmware/src/main.cpp @@ -14,11 +14,16 @@ Sensor *pmSensor; BluetoothServer *server; bool makeDiscoverable = false; - +//interrupt handler for sensor being pressed void IRAM_ATTR startBleServerAdvertising() { makeDiscoverable = true; } +//helper function to create task for PM measurement +void startPmAsyncSampling(void * param){ + ((PmSensor *) pmSensor)->startAsyncSampling(); +} + void setup() { //initialize a Serial Connection Serial.begin(BAUD_RATE); @@ -38,17 +43,25 @@ void setup() { attachInterrupt(digitalPinToInterrupt(INTERRUPT_MAKE_DISCOVERABLE_PIN), startBleServerAdvertising, RISING); + + //start an async task for measuring PM so the sensor won't block the whole system + xTaskCreate( + startPmAsyncSampling, + "Async PM sampling", + 1024, + nullptr, + 1, + nullptr + ); } void loop() { + //check if the button has been pressed and handle appropriately if (makeDiscoverable) { server->startAdvertising(); 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); @@ -57,11 +70,12 @@ void loop() { 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", + 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/PmSensor.cpp b/firmware/src/sensors/PmSensor.cpp index 7e0fc03..b43a7bd 100644 --- a/firmware/src/sensors/PmSensor.cpp +++ b/firmware/src/sensors/PmSensor.cpp @@ -21,19 +21,35 @@ PmSensor::PmSensor() { this->PmSensor::sensor_setup(); } -void PmSensor::startAsyncSampling() { +[[noreturn]] void PmSensor::startAsyncSampling() { - this->enableStandbyMode(); - PmSensor::sensorWait(SLEEP_TIME); + Serial.println("Started async task for PM sensor sampling."); - this->wakeUp(); - sds011.perform_work(); + while (true) { + this->wakeUp(); - if (!sds011.query_data_auto_async(pm_tablesize, pm25_table, pm10_table)) { - Serial.println("measurement capture start failed"); + //attach a callback on what to do when data sampling is complete + sds011.on_query_data_auto_completed([this](int n) { + Serial.println("Sampled new PM data."); + 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; + } + }); + + if (!sds011.query_data_auto_async(pm_tablesize, pm25_table, pm10_table)) { + Serial.println("measurement capture start failed"); + } + + PmSensor::sensorWait(MEASURE_TIME); + + this->enableStandbyMode(); + PmSensor::sensorWait(SLEEP_TIME); } - - PmSensor::sensorWait(MEASURE_TIME); } /** @@ -41,6 +57,7 @@ void PmSensor::startAsyncSampling() { */ void PmSensor::enableStandbyMode() { if (sds011.set_sleep(true)) { this->state = SensorState::ASLEEP; } + Serial.println("PM sensor went to sleep mode."); } /** @@ -48,6 +65,7 @@ void PmSensor::enableStandbyMode() { */ void PmSensor::wakeUp() { if (sds011.set_sleep(false)) { this->state = SensorState::AWAKE; } + Serial.println("PM sensor woke up."); } /** @@ -64,18 +82,6 @@ void PmSensor::sensor_setup() { //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; - } - }); } /** @@ -85,7 +91,7 @@ void PmSensor::sensor_setup() { void PmSensor::sensorWait(int time) { uint32_t deadline = millis() + time * 1000; while (static_cast(deadline - millis()) > 0) { - delay(1000); + vTaskDelay(1000 / portTICK_PERIOD_MS); sds011.perform_work(); } } diff --git a/firmware/src/sensors/PmSensor.h b/firmware/src/sensors/PmSensor.h index 3a3bd84..626b586 100644 --- a/firmware/src/sensors/PmSensor.h +++ b/firmware/src/sensors/PmSensor.h @@ -17,7 +17,7 @@ public: sensor_data_t sample() override; - void startAsyncSampling(); + [[noreturn]] void startAsyncSampling(); void enableStandbyMode() override; From 3eb1a3eb4078a5578ec5c03133e44b3587f203a6 Mon Sep 17 00:00:00 2001 From: CDaut Date: Thu, 17 Feb 2022 10:41:27 +0100 Subject: [PATCH 7/8] added details about 2 sensors --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4a71f26..d636e83 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ -# Climate GO +# Climate GO Climate GO is a fully open source open hardware Sensor pack, to track and analyze personal air quality data. Its goal is to provide a way to monitor ones own air quality and motivate people to avoid polluted places and protect the environment. ## Paradigms This project is intended to be open source, open hardware and open data oriented. It is of central importance to make this available to anyone who whishes to build a climate go device and to ensure no personal data is collected and stored. This is especially important because the climate data collected will be correlated with GPS information and could thus be used to construct a movement profile if not handled with uttermost care. -## Technical information +## Technical information ### Stack The sensor pack itself is based around the ESP32 microprocessor and contains several sensors: - BMP280 air pressure and temperature monitoring sensor -- [name] particulate matter sensor +- Nova SDS011 particulate matter sensor - [name] CO2 sensor -- [name] NO2 sensor +- MISC 2714 NO2 sensor A custom PCB/housing is yet to be designed and manufactured. Data collection is made possible by an Android App, that will connect to the sensor pack via Bluetooth low energy. It is imperative to design the sensor pack to be lightweight and consume as little as possible energy to ensure comfort in transporting the sensor pack (it is intended to be clipped to e.g. a backpack) and long battery life. From 80863be65e4d19f2f7a1ba700473b92a660f26d5 Mon Sep 17 00:00:00 2001 From: Clara Dautermann Date: Wed, 2 Jul 2025 15:03:49 +0200 Subject: [PATCH 8/8] nix setup --- .envrc | 1 + .gitignore | 1 + .vscode/settings.json | 3 +++ firmware/.gitignore | 5 +++++ firmware/.vscode/extensions.json | 10 ++++++++++ flake.lock | 27 +++++++++++++++++++++++++++ flake.nix | 25 +++++++++++++++++++++++++ 7 files changed, 72 insertions(+) create mode 100644 .envrc create mode 100644 .vscode/settings.json create mode 100644 firmware/.gitignore create mode 100644 firmware/.vscode/extensions.json create mode 100644 flake.lock create mode 100644 flake.nix diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..8f390c3 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use_flake \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5dcc104..91555ba 100644 --- a/.gitignore +++ b/.gitignore @@ -444,3 +444,4 @@ obj/ # End of https://www.toptal.com/developers/gitignore/api/platformio,c,cmake,c++,intellij,android,androidstudio,clion+all,java +.direnv \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..c9594a6 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "cmake.sourceDirectory": "/home/clara/repositorys/climate-go/firmware" +} \ No newline at end of file diff --git a/firmware/.gitignore b/firmware/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/firmware/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/firmware/.vscode/extensions.json b/firmware/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/firmware/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..1796f3c --- /dev/null +++ b/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1728241625, + "narHash": "sha256-yumd4fBc/hi8a9QgA9IT8vlQuLZ2oqhkJXHPKxH/tRw=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "c31898adf5a8ed202ce5bea9f347b1c6871f32d1", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..8d9655b --- /dev/null +++ b/flake.nix @@ -0,0 +1,25 @@ +{ + description = "A Nix-flake-based PlatformIO development environment"; + + inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + + outputs = { self, nixpkgs }: + let + supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; + forEachSupportedSystem = f: nixpkgs.lib.genAttrs supportedSystems (system: f { + pkgs = import nixpkgs { inherit system; }; + }); + in + { + devShells = forEachSupportedSystem ({ pkgs }: { + default = pkgs.mkShell { + packages = with pkgs; [ + platformio-core + openocd + python3 + platformio + ]; + }; + }); + }; +}