diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..355a40d --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.pio +CMakeListsPrivate.txt +cmake-build-*/ + + +# IDE +./.idea \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..80cd00a --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..aeb7613 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/untitled.iml b/.idea/untitled.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/.idea/untitled.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..ef6ea8d --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +#Climate GO \ No newline at end of file diff --git a/firmware/CMakeLists.txt b/firmware/CMakeLists.txt new file mode 100644 index 0000000..b6ad71a --- /dev/null +++ b/firmware/CMakeLists.txt @@ -0,0 +1,33 @@ +# !!! 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. + +cmake_minimum_required(VERSION 3.13) +set(CMAKE_SYSTEM_NAME Generic) +set(CMAKE_C_COMPILER_WORKS 1) +set(CMAKE_CXX_COMPILER_WORKS 1) + +project("new_climte_go" C CXX) + +include(CMakeListsPrivate.txt) + +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/CMakeListsUser.txt) +include(CMakeListsUser.txt) +endif() + +add_custom_target( + Production ALL + COMMAND platformio -c clion run "$<$>:-e${CMAKE_BUILD_TYPE}>" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) + +add_custom_target( + Debug ALL + COMMAND platformio -c clion debug "$<$>:-e${CMAKE_BUILD_TYPE}>" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} +) + +add_executable(Z_DUMMY_TARGET ${SRC_LIST}) diff --git a/firmware/include/README b/firmware/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/firmware/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/firmware/lib/README b/firmware/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/firmware/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/firmware/platformio.ini b/firmware/platformio.ini new file mode 100644 index 0000000..1a0090b --- /dev/null +++ b/firmware/platformio.ini @@ -0,0 +1,15 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:esp32dev] +platform = espressif32 +board = esp32dev +framework = arduino +lib_deps = adafruit/Adafruit BMP280 Library@^2.6.1 diff --git a/firmware/src/ble/BluetoothServer.cpp b/firmware/src/ble/BluetoothServer.cpp new file mode 100644 index 0000000..4586e42 --- /dev/null +++ b/firmware/src/ble/BluetoothServer.cpp @@ -0,0 +1,92 @@ +#include +#include +#include +#include "BluetoothServer.h" + +#define INTERNAL_LED_PIN 2 +#define BLE_SERVER_NAME "ClimateGO" +#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" + +//Setup callbacks onConnect and onDisconnect +class ServerCallbacks : public BLEServerCallbacks { + void onConnect(BLEServer *pServer) override { + Serial.println("New device connected."); + digitalWrite(INTERNAL_LED_PIN, HIGH); + }; + + void onDisconnect(BLEServer *pServer) override { + Serial.println("Device disconnected."); + digitalWrite(INTERNAL_LED_PIN, LOW); + //restart advertising on device disconnect + pServer->getAdvertising()->start(); + } +}; + +/** + * Represents the Bluetooth server that handles all interactions + */ +BluetoothServer::BluetoothServer() { + // Create the BLE Device + BLEDevice::init(BLE_SERVER_NAME); + + // Create the BLE Server + this->bleServer = BLEDevice::createServer(); + bleServer->setCallbacks(new ServerCallbacks()); + + // Create the BLE Service + this->sensorService = bleServer->createService(SERVICE_UUID); + + //create characteristics that will enable data sharing + BLECharacteristic *temperatureCharacteristic = sensorService->createCharacteristic( + TEMPERATURE_CHARACTERISTIC_UUID, + BLECharacteristic::PROPERTY_READ + ); + BLECharacteristic *pressureCharacteristic = sensorService->createCharacteristic( + PRESSURE_CHARACTERISTIC_UUID, + BLECharacteristic::PROPERTY_READ + ); + + //set initial values + temperatureCharacteristic->setValue("NA"); + pressureCharacteristic->setValue("NA"); +} + +/** + * Method to start the Bluetooth server and enable advertising to allow other devices to connect + */ +void BluetoothServer::startServer() { + // Start the service + this->sensorService->start(); + + // Start advertising + BLEAdvertising *pAdvertising = BLEDevice::getAdvertising(); + pAdvertising->addServiceUUID(SERVICE_UUID); + this->bleServer->getAdvertising()->start(); + Serial.println("Started BLE Server."); +} + +/** + * TODO: Convert temperature to string somehow + * Publish a new temperature to the appropriate characteristic + * @param temperature the new temperature + */ +void BluetoothServer::setTemperature(float temperature) { + sensorService + ->getCharacteristic(TEMPERATURE_CHARACTERISTIC_UUID) + ->setValue(temperature); +} + +/** + * TODO: Convert pressure to string somehow + * Publish a new pressure to the appropriate characteristic + * @param pressure the new pressure + */ +void BluetoothServer::setPressure(float pressure) { + sensorService + ->getCharacteristic(PRESSURE_CHARACTERISTIC_UUID) + ->setValue(pressure); +} + + diff --git a/firmware/src/ble/BluetoothServer.h b/firmware/src/ble/BluetoothServer.h new file mode 100644 index 0000000..4afd1ec --- /dev/null +++ b/firmware/src/ble/BluetoothServer.h @@ -0,0 +1,25 @@ +#ifndef NEW_CLIMTE_GO_BLUETOOTHSERVER_H +#define NEW_CLIMTE_GO_BLUETOOTHSERVER_H + +#include +#include +#include +#include +#include + +#define temperatureCelsius + +class BluetoothServer { +private: + BLEService *sensorService; + BLEServer *bleServer; +public: + BluetoothServer(); + + void startServer(); + void setTemperature(float temperature); + void setPressure(float pressure); +}; + + +#endif //NEW_CLIMTE_GO_BLUETOOTHSERVER_H diff --git a/firmware/src/main.cpp b/firmware/src/main.cpp new file mode 100644 index 0000000..38b5852 --- /dev/null +++ b/firmware/src/main.cpp @@ -0,0 +1,28 @@ +#include +#include +#include + +#define SLEEP_TIME 2 +#define BAUD_RATE 112500 +#define INTERNAL_LED_PIN 2 + + +Sensor *bmpSensor; +BluetoothServer *server; + +void setup() { + Serial.begin(BAUD_RATE); + pinMode(INTERNAL_LED_PIN, OUTPUT); + + bmpSensor = new BmpSensor(); + + server = new BluetoothServer(); + server->startServer(); +} + +void loop() { + sensor_data_t sample = ((BmpSensor *) bmpSensor)->sampleLowEnergy(); + server->setPressure(sample.pressure); + server->setTemperature(sample.temperature); + delay(SLEEP_TIME * 1000); +} \ No newline at end of file diff --git a/firmware/src/sensors/BmpSensor.cpp b/firmware/src/sensors/BmpSensor.cpp new file mode 100644 index 0000000..7f68a25 --- /dev/null +++ b/firmware/src/sensors/BmpSensor.cpp @@ -0,0 +1,89 @@ +#include +#include +#include +#include "BmpSensor.h" + +/** + * Creates a new BMP Sensor and initializes it + */ +BmpSensor::BmpSensor() { + this->BmpSensor::sensor_setup(); + this->state = SensorState::ASLEEP; +} + +/** + * Function responsible for setting up the sensor and the I2C connection + */ +void BmpSensor::sensor_setup() { + while (!Serial) delay(100); // wait for native usb + + unsigned status = this->bmp.begin(0x76); //set the correct I2C port + + //query status and reboot the board if no sensor is detected + if (!status) + ESP.restart(); + + //put sensor to standby mode + this->enableStandbyMode(); +} + +/** + * Function to wake sensor up from standby mode + */ +void BmpSensor::wakeUp() { + this->bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */ + Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */ + Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */ + Adafruit_BMP280::FILTER_X16, /* Filtering. */ + Adafruit_BMP280::STANDBY_MS_500 /* Standby time. */ + ); +} + +/** + * Function to put sensor to standby mode + */ +void BmpSensor::enableStandbyMode() { + this->bmp.setSampling(Adafruit_BMP280::MODE_SLEEP, /* Operating Mode. */ + Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */ + Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */ + Adafruit_BMP280::FILTER_X16, /* Filtering. */ + Adafruit_BMP280::STANDBY_MS_500 /* Standby time. */ + ); +} + +/** + * read a sample from the sensor + * @return a struct containing all necessary sensor data + */ +sensor_data_t BmpSensor::sample() { + //wake sensor up if it is in standby mode + if (this->state == SensorState::ASLEEP) + this->wakeUp(); + + //sample pressure and temperature + sensors_event_t temp_event, pressure_event; + this->bmp_temp->getEvent(&temp_event); + this->bmp_pressure->getEvent(&pressure_event); + + + return sensor_data_t + { + temp_event.temperature, + pressure_event.pressure + }; +} + +/** + * Read a sample and put sensor to standby mode. + * !!! Do not use this if sampling time is <= 500ms !!! + * @return the sample read + */ +sensor_data_t BmpSensor::sampleLowEnergy() { + //read sample + sensor_data_t sampledData = this->sample(); + //put sensor to standby + this->enableStandbyMode(); + return sampledData; +} + + diff --git a/firmware/src/sensors/BmpSensor.h b/firmware/src/sensors/BmpSensor.h new file mode 100644 index 0000000..f5949fc --- /dev/null +++ b/firmware/src/sensors/BmpSensor.h @@ -0,0 +1,29 @@ +#ifndef NEW_CLIMTE_GO_BMPSENSOR_H +#define NEW_CLIMTE_GO_BMPSENSOR_H + +#include "Sensor.h" +#include "Adafruit_BMP280.h" + +class BmpSensor : public Sensor { +private: + Adafruit_BMP280 bmp; // use I2C interface + Adafruit_Sensor *bmp_temp = bmp.getTemperatureSensor(); + Adafruit_Sensor *bmp_pressure = bmp.getPressureSensor(); + +public: + BmpSensor(); + + sensor_data_t sample() override; + sensor_data_t sampleLowEnergy(); + + void enableStandbyMode() override; + + void wakeUp() override; + +protected: + void sensor_setup() override; + +}; + +#endif //NEW_CLIMTE_GO_BMPSENSOR_H + diff --git a/firmware/src/sensors/Sensor.h b/firmware/src/sensors/Sensor.h new file mode 100644 index 0000000..7f3a1f8 --- /dev/null +++ b/firmware/src/sensors/Sensor.h @@ -0,0 +1,25 @@ +#ifndef NEW_CLIMTE_GO_SENSOR_H +#define NEW_CLIMTE_GO_SENSOR_H + +#include + +enum class SensorState : unsigned short { + AWAKE, ASLEEP +}; + +class Sensor { +public: + virtual sensor_data_t sample() = 0; + + virtual void wakeUp() = 0; + + virtual void enableStandbyMode() = 0; + +protected: + SensorState state = SensorState::ASLEEP; + + virtual void sensor_setup() = 0; + +}; + +#endif //NEW_CLIMTE_GO_SENSOR_H diff --git a/firmware/src/sensors/sensor_data_t.h b/firmware/src/sensors/sensor_data_t.h new file mode 100644 index 0000000..0d96e8d --- /dev/null +++ b/firmware/src/sensors/sensor_data_t.h @@ -0,0 +1,16 @@ +#ifndef NEW_CLIMTE_GO_SENSOR_DATA_T_H +#define NEW_CLIMTE_GO_SENSOR_DATA_T_H + +#include + +/** + * This struct represents data read from any sensor. + * This implies, reading temperature from e.g. the CO2 Sensor + * does not make any sense + */ +struct sensor_data_t { + float temperature; + float pressure; +}; + +#endif diff --git a/firmware/test/README b/firmware/test/README new file mode 100644 index 0000000..b94d089 --- /dev/null +++ b/firmware/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Unit Testing and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/page/plus/unit-testing.html