diff --git a/Tests/Mieming/client_esp32C3/client/.gitignore b/Tests/Mieming/client_esp32C3/client/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..89cc49cbd652508924b868ea609fa8f6b758ec56 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/Tests/Mieming/client_esp32C3/client/.gitkeep b/Tests/Mieming/client_esp32C3/client/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/Tests/Mieming/client_esp32C3/client/.vscode/extensions.json b/Tests/Mieming/client_esp32C3/client/.vscode/extensions.json new file mode 100644 index 0000000000000000000000000000000000000000..080e70d08b9811fa743afe5094658dba0ed6b7c2 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/.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/Tests/Mieming/client_esp32C3/client/.vscode/settings.json b/Tests/Mieming/client_esp32C3/client/.vscode/settings.json new file mode 100644 index 0000000000000000000000000000000000000000..85c4d1b958928f8e741f91d4b9a8a6453eb0570d --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/.vscode/settings.json @@ -0,0 +1,54 @@ +{ + "files.associations": { + "optional": "cpp", + "array": "cpp", + "atomic": "cpp", + "*.tcc": "cpp", + "cctype": "cpp", + "clocale": "cpp", + "cmath": "cpp", + "cstdarg": "cpp", + "cstddef": "cpp", + "cstdint": "cpp", + "cstdio": "cpp", + "cstdlib": "cpp", + "cstring": "cpp", + "ctime": "cpp", + "cwchar": "cpp", + "cwctype": "cpp", + "deque": "cpp", + "list": "cpp", + "unordered_map": "cpp", + "unordered_set": "cpp", + "vector": "cpp", + "exception": "cpp", + "algorithm": "cpp", + "functional": "cpp", + "iterator": "cpp", + "map": "cpp", + "memory": "cpp", + "memory_resource": "cpp", + "numeric": "cpp", + "random": "cpp", + "string": "cpp", + "string_view": "cpp", + "system_error": "cpp", + "tuple": "cpp", + "type_traits": "cpp", + "utility": "cpp", + "fstream": "cpp", + "initializer_list": "cpp", + "iomanip": "cpp", + "iosfwd": "cpp", + "iostream": "cpp", + "istream": "cpp", + "limits": "cpp", + "new": "cpp", + "ostream": "cpp", + "sstream": "cpp", + "stdexcept": "cpp", + "streambuf": "cpp", + "cinttypes": "cpp", + "typeinfo": "cpp" + } +} \ No newline at end of file diff --git a/Tests/Mieming/client_esp32C3/client/include/ForteSensor.hpp b/Tests/Mieming/client_esp32C3/client/include/ForteSensor.hpp new file mode 100644 index 0000000000000000000000000000000000000000..add5a01d566ef5977eef3e0286d908c4b49fcb0b --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/include/ForteSensor.hpp @@ -0,0 +1,17 @@ +#ifndef _FORTE_SENSOR +#define _FORTE_SENSOR + +#include "Message.hpp" +#include "Protocol.hpp" +#include "SensorInformation.hpp" +template <class T> +class ForteSensor { + public: + virtual T readData() = 0; + virtual void setup() = 0; + virtual std::list<Message> buildMessages() = 0; + [[nodiscard]] virtual SensorInformation getSensorInformation() const = 0; + virtual ~ForteSensor() = default; +}; + +#endif \ No newline at end of file diff --git a/Tests/Mieming/client_esp32C3/client/include/MeasurementData.hpp b/Tests/Mieming/client_esp32C3/client/include/MeasurementData.hpp new file mode 100644 index 0000000000000000000000000000000000000000..36bd5db75fbdb714dad723d67b92affd4d4fd189 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/include/MeasurementData.hpp @@ -0,0 +1,39 @@ +// +// Created by cynthya on 10/6/22. +// + +#ifndef CLIENT_MEASUREMENTDATA_HPP +#define CLIENT_MEASUREMENTDATA_HPP + +#include "ArduinoJson.h" +#include "Protocol.hpp" +#include "SensorInformation.hpp" +#include <list> +#include <optional> +#include <string> +#include <utility> +class MeasurementData { + public: + MeasurementData(double value, std::optional<int> channel, std::optional<int> i2cAddress, + std::string measurementType) + : value(value), measurementType(std::move(measurementType)), channel(channel), i2cAddress(i2cAddress) + { + } + + MeasurementData(double value, std::string measurementType) + : value(value), measurementType(std::move(measurementType)) + { + } + + [[nodiscard]] double getValue() const { return value; } + [[nodiscard]] const std::string &getMeasurementType() const { return measurementType; } + [[nodiscard]] const std::optional<int> &getChannel() const { return channel; } + [[nodiscard]] const std::optional<int> &getI2CAddress() const { return i2cAddress; } + + private: + double value; + std::string measurementType; // TODO: consider using an enum + std::optional<int> channel; + std::optional<int> i2cAddress; +}; +#endif // CLIENT_MEASUREMENTDATA_HPP diff --git a/Tests/Mieming/client_esp32C3/client/include/NoDataAvailableException.hpp b/Tests/Mieming/client_esp32C3/client/include/NoDataAvailableException.hpp new file mode 100644 index 0000000000000000000000000000000000000000..83c56973868a76a1dca7f49487bcdb6fd33e86d8 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/include/NoDataAvailableException.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include <exception> +#include <iostream> + +struct NoDataAvailableException : public std::exception { + const char *what() const noexcept override { return "Sensor could not read data"; } +}; \ No newline at end of file diff --git a/Tests/Mieming/client_esp32C3/client/include/Pinout.hpp b/Tests/Mieming/client_esp32C3/client/include/Pinout.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f277fd91b274caa1de127f0380ba75164dd9b707 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/include/Pinout.hpp @@ -0,0 +1,10 @@ +#ifndef _FORTE_PINOUT +#define _FORTE_PINOUT + +// Pins for I2C +constexpr int I2C_SDA = 18; +constexpr int I2C_SCL = 19; + +// TODO: IF THE BOARD CHANGES (I.E. ESPCAM MODULE), THESE HAVE TO BE CHANGED (EITHER COMPILE TIME FLAG OR IFDEF OR SMTH) + +#endif diff --git a/Tests/Mieming/client_esp32C3/client/include/Protocol.hpp b/Tests/Mieming/client_esp32C3/client/include/Protocol.hpp new file mode 100644 index 0000000000000000000000000000000000000000..92270db81e4a54e525f2cd054a15a03e7ebade15 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/include/Protocol.hpp @@ -0,0 +1,15 @@ +// +// Created by zoe on 10/5/22. +// + +#ifndef CLIENT_PROTOCOL_HPP +#define CLIENT_PROTOCOL_HPP + +#include <map> +enum class Protocol { I2C, RS485, Analog }; + +// protocol to string +const static std::map<Protocol, const char *> protocolToString = { + {Protocol::I2C, "I2C"}, {Protocol::RS485, "RS485"}, {Protocol::Analog, "ANALOG"}}; + +#endif // CLIENT_PROTOCOL_HPP diff --git a/Tests/Mieming/client_esp32C3/client/include/README b/Tests/Mieming/client_esp32C3/client/include/README new file mode 100644 index 0000000000000000000000000000000000000000..194dcd43252dcbeb2044ee38510415041a0e7b47 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/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/Tests/Mieming/client_esp32C3/client/include/SensorInformation.hpp b/Tests/Mieming/client_esp32C3/client/include/SensorInformation.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4b8af5d357534be81670b503790960a2781bc282 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/include/SensorInformation.hpp @@ -0,0 +1,25 @@ +// +// Created by cynthya on 10/6/22. +// + +#ifndef CLIENT_SENSORINFORMATION_HPP +#define CLIENT_SENSORINFORMATION_HPP + +#include "Protocol.hpp" +#include <string> + +class SensorInformation { + public: + SensorInformation(std::string sensorName, Protocol protocol) : sensorName(std::move(sensorName)), protocol(protocol) + { + } + + [[nodiscard]] const std::string &getSensorName() const { return sensorName; } + [[nodiscard]] Protocol getProtocol() const { return protocol; } + + private: + std::string sensorName; + Protocol protocol; +}; + +#endif // CLIENT_SENSORINFORMATION_HPP diff --git a/Tests/Mieming/client_esp32C3/client/lib/README b/Tests/Mieming/client_esp32C3/client/lib/README new file mode 100644 index 0000000000000000000000000000000000000000..6debab1e8b4c3faa0d06f4ff44bce343ce2cdcbf --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/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 <Foo.h> +#include <Bar.h> + +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/Tests/Mieming/client_esp32C3/client/lib/caching/src/ram_caching.cpp b/Tests/Mieming/client_esp32C3/client/lib/caching/src/ram_caching.cpp new file mode 100644 index 0000000000000000000000000000000000000000..641f9744f12e4b7755ea78e786fcf06448f627f6 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/lib/caching/src/ram_caching.cpp @@ -0,0 +1,56 @@ +#include "ram_caching.hpp" + +namespace RtcMemory{ + // 2D array of 20 Strings with maxLength of 251 + RTC_DATA_ATTR char storage[maxLength_][maxSize_]; + RTC_DATA_ATTR int storedElements; + RTC_DATA_ATTR int headElement = 0; + RTC_DATA_ATTR int tailElement = 0; + + static const char* TAG = "CACHING"; + + + void store(std::string message){ + + // turn data into char array + const char* jsonString = message.c_str(); + + // move head to new element + headElement = (headElement + 1) % maxSize_; + // apparently I am not allowed to copy to rtc mem + for(int i=0; i<maxLength_; i++){ + storage[i][headElement] = jsonString[i]; + if(jsonString[i] == '\0'){ + break; + } + } + storedElements++; + ESP_LOGE(TAG, "Moved message to storage."); + } + + String get_from_storage(){ + // remove element pointed at by tail + String buf = ""; + char current = '\0'; + for(int i = 0; i<maxLength_; i++){ + current = storage[i][tailElement]; + buf += current; + if(current == '\0'){ + break; + } + } + // move tail to next element + tailElement = (tailElement + 1) % maxSize_; + storedElements--; + ESP_LOGE(TAG, "Retrieved message from storage"); + return buf; + } + + bool is_full(){ + return headElement == tailElement; + } + + int stored_amount(){ + return storedElements; + } +} diff --git a/Tests/Mieming/client_esp32C3/client/lib/caching/src/ram_caching.hpp b/Tests/Mieming/client_esp32C3/client/lib/caching/src/ram_caching.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c1a4ac57312afe9505b565b0ccfb1cf73f9175e9 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/lib/caching/src/ram_caching.hpp @@ -0,0 +1,16 @@ +#ifndef _RAM_CACHE +#define _RAM_CACHE +#include "esp_log.h" +#include <ESP32Time.h> + +#define maxSize_ 20 +#define maxLength_ 251 + +namespace RtcMemory { + void store(std::string message); + String get_from_storage(); + bool is_full(); + int stored_amount(); +} + +#endif \ No newline at end of file diff --git a/Tests/Mieming/client_esp32C3/client/lib/deep_sleep/f_deep_sleep.cpp b/Tests/Mieming/client_esp32C3/client/lib/deep_sleep/f_deep_sleep.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c434f53c5728c4bb840c8ec19087f802f9c63ffe --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/lib/deep_sleep/f_deep_sleep.cpp @@ -0,0 +1,43 @@ +#include "f_deep_sleep.hpp" +#include "esp32-hal-log.h" +#include "esp_log.h" + +namespace DeepSleep { +static const std::string TAG = "DEEP_SLEEP"; + + +void print_wakeup_reason() +{ + esp_sleep_wakeup_cause_t wakeup_reason; + + wakeup_reason = esp_sleep_get_wakeup_cause(); + + switch (wakeup_reason) { + case ESP_SLEEP_WAKEUP_EXT0: + ESP_LOGD(TAG.c_str(), "Wakeup caused by external signal using RTC_IO"); + break; + case ESP_SLEEP_WAKEUP_EXT1: + ESP_LOGD(TAG.c_str(), "Wakeup caused by external signal using RTC_CNTL"); + break; + case ESP_SLEEP_WAKEUP_TIMER: + ESP_LOGD(TAG.c_str(), "Wakeup caused by timer"); + break; + case ESP_SLEEP_WAKEUP_TOUCHPAD: + ESP_LOGD(TAG.c_str(), "Wakeup caused by touchpad"); + break; + case ESP_SLEEP_WAKEUP_ULP: + ESP_LOGD(TAG.c_str(), "Wakeup caused by ULP program"); + break; + default: + ESP_LOGD(TAG.c_str(), "Wakeup was not caused by deep sleep: %d\n", wakeup_reason); + break; + } +} + +void deep_sleep(int time_in_sec) +{ + esp_sleep_enable_timer_wakeup(time_in_sec * 1000000); + esp_deep_sleep_start(); +} + +}; // namespace DeepSleep diff --git a/Tests/Mieming/client_esp32C3/client/lib/deep_sleep/f_deep_sleep.hpp b/Tests/Mieming/client_esp32C3/client/lib/deep_sleep/f_deep_sleep.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7a528c840b8dab363a1f1b65a917f007294317c7 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/lib/deep_sleep/f_deep_sleep.hpp @@ -0,0 +1,18 @@ +#ifndef F_DEEP_SLEEP_H +#define F_DEEP_SLEEP_H + +#include <Arduino.h> + +namespace DeepSleep { +// https://en.cppreference.com/w/cpp/language/storage_duration +// When used in a declaration at namespace scope, it specifies internal linkage. +// internal linkage. The variable can be referred to from all scopes in the current translation unit. All variables +// which are declared at file scope have this linkage, including variables declared static at file scope. +static RTC_DATA_ATTR int bootCount = 0; + +void deep_sleep(int time_to_sleep_in_seconds); +void print_wakeup_reason(); + +} // namespace DeepSleep + +#endif diff --git a/Tests/Mieming/client_esp32C3/client/lib/dr26_analogue/dr26.cpp b/Tests/Mieming/client_esp32C3/client/lib/dr26_analogue/dr26.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f41a4458a943d9aaf9845e4e4e2e44b1271868a2 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/lib/dr26_analogue/dr26.cpp @@ -0,0 +1,85 @@ +#include "dr26.hpp" + +void ForteDR26 ::setup() +{ + Wire.begin(6, 7); + // ads.setGain(GAIN_ONE); + // ads.begin() ? Serial.println("ADS initialized") : Serial.println("failed to initialize ADS"); + + + ads1.setGain(GAIN_ONE); + ads1.begin() ? Serial.println("ADS initialized") : Serial.println("failed to initialize ADS"); + delay(100); + channel=0; +} + +float ForteDR26 ::readData() +{ + float volts=0; + for(int i=0; i<10; i++){ + int16_t adc = 0; + float volt = 0; + try + { + adc = ads1.readADC_SingleEnded(channel); + volt = ads1.computeVolts(adc); + } + catch(NoDataAvailableException& e) + { + throw NoDataAvailableException(); //propagate exception + } + volts += volt; + } + + volts /= 10; + return volts; +} + +// The following functions change the ADC input range: be careful +// to never to exceed VDD +0.3V max, or to exceed the upper and +// lower limits if you adjust the input range. +// SETTING THE GAIN VALUE INCORRECTLY MAY DESTROY THE ADC! +// The maximum output of the dendrometer is 2.5V, and so a gain of +// one (max 4.096V) or two (max 2.048V) is optimal. Changing the gain +// changes the accuracy of the sensor: higher gain gives a higher +// precision but a smaller range. +// +// GAIN_TWOTHIRDS // 2/3x gain +/- 6.144V 1 bit = 0.1875mV (default) +// GAIN_ONE // 1x gain +/- 4.096V 1 bit = 0.125mV +// GAIN_TWO // 2x gain +/- 2.048V 1 bit = 0.0625mV +// GAIN_FOUR // 4x gain +/- 1.024V 1 bit = 0.03125mV +// GAIN_EIGHT // 8x gain +/- 0.512V 1 bit = 0.015625mV +// GAIN_SIXTEEN // 16x gain +/- 0.256V 1 bit = 0.0078125mV +void ForteDR26 ::changeGain(adsGain_t gain) +{ + ads1.setGain(gain); +} + +void ForteDR26 ::setChannel(int c) +{ + channel=c; +} +std::list<Message> ForteDR26::buildMessages() +{ + std::list<Message> messages; + float data = readData(); + MeasurementData IncrementData{data, 0, {}, "CIRCUMFERENCE_INCREMENT"}; + messages.emplace_back(IncrementData, sensorInformation, Time::getInstance().getEpochSeconds()); + return messages; +} + +std::list<Message> ForteDR26::buildMessages(int channel,std::string measurementType) +{ + std::list<Message> messages; + float data = readData(); + MeasurementData IncrementData{data, channel, {}, measurementType}; + messages.emplace_back(IncrementData, sensorInformation, Time::getInstance().getEpochSeconds()); + return messages; +} +SensorInformation ForteDR26::getSensorInformation() const +{ + return sensorInformation; +} + + +Adafruit_ADS1115 ForteDR26::ads1=ads1; \ No newline at end of file diff --git a/Tests/Mieming/client_esp32C3/client/lib/dr26_analogue/dr26.hpp b/Tests/Mieming/client_esp32C3/client/lib/dr26_analogue/dr26.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b60c0997ec0180bc9e145d2588387022f9999f2a --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/lib/dr26_analogue/dr26.hpp @@ -0,0 +1,29 @@ +#ifndef _DR26 +#define _DR26 + +#include "Adafruit_ADS1X15.h" +#include "ForteSensor.hpp" +#include "Message.hpp" +#include "Pinout.hpp" +#include "esp_log.h" +#include <Wire.h> +#include "NoDataAvailableException.hpp" + +class ForteDR26 : public ForteSensor<float> { + public: + void setup() override; + float readData() override; + void changeGain(adsGain_t gain); + void setChannel(int channel); + std::list<Message> buildMessages() override; + std::list<Message> buildMessages(int channel,std::string mesurment_type); + [[nodiscard]] SensorInformation getSensorInformation() const override; + static Adafruit_ADS1115 ads1; + + private: + Adafruit_ADS1115 ads; + const SensorInformation sensorInformation{"DR26", Protocol::Analog}; + int channel; +}; + +#endif \ No newline at end of file diff --git a/Tests/Mieming/client_esp32C3/client/lib/drs26_digital/drs26.cpp b/Tests/Mieming/client_esp32C3/client/lib/drs26_digital/drs26.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5c21f3a98e01d665c38a879fb23f37217b39e8f4 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/lib/drs26_digital/drs26.cpp @@ -0,0 +1,61 @@ +#include <drs26.hpp> + +/* +It happens for some reason that the sensor cant get reached every 2 time +Because the sensor use sdi12 protocoll we have to wait aproxemettly 1 secound between the commands +It is not known how lond the response takes so we use a while loop which can be a risk wehre the programm can get stuck +*/ + +void ForteDRS26 ::setup() +{ + drs26.begin(4); +} + +out_data_drs26 ForteDRS26 ::readData() +{ + String sdiResponse = ""; + String measurement_command = + "1M!"; // The drs26 sensor uses the sdi12 protocoll , in the sdi12 protocoll is the measurement command is + // specified as 1M!=Sebsir measurement request at adress 1 + String data_command = "1D0!"; // and the followed data command 1D0! = Sensor data request at adress 1 + + drs26.sendCommand(measurement_command); + delay(1000); + drs26.sendCommand(data_command); + + data = {-1, -1, -1}; + + while (drs26.available()) { + char next_character = drs26.read(); + if ((next_character != '\n') && (next_character != '\r')) { + sdiResponse += next_character; + delay(10); // 1 character ~ 7.5ms + } + } + + if (sdiResponse.length() > 1) { + data.id = sdiResponse.substring(0, 8).toInt(); + data.circumferenceIncrement = sdiResponse.substring(9, 15).toFloat(); + data.temperature = sdiResponse.substring(16, 22).toFloat(); + } + return data; +} + +std::list<Message> ForteDRS26 ::buildMessages() +{ + std::list<Message> messages; + MeasurementData circumferenceIncrementMeasurementData{ + data.circumferenceIncrement, 0, {}, measurementTypeToString.at(MeasurementType::CIRCUMFERENCE_INCREMENT)}; + MeasurementData temperatureMeasurementData{ + data.temperature, 0, {}, measurementTypeToString.at(MeasurementType::TEMPERATURE)}; + + messages.emplace_back(Message{circumferenceIncrementMeasurementData, sensorInformation, 0}); + messages.emplace_back(Message{temperatureMeasurementData, sensorInformation, 0}); + + ESP_LOGE(sensorInformation.getSensorName().c_str(), "test"); + return messages; +} +SensorInformation ForteDRS26::getSensorInformation() const +{ + return sensorInformation; +} diff --git a/Tests/Mieming/client_esp32C3/client/lib/drs26_digital/drs26.hpp b/Tests/Mieming/client_esp32C3/client/lib/drs26_digital/drs26.hpp new file mode 100644 index 0000000000000000000000000000000000000000..0d713ca66260895f63cdc1e2137ec4027294e8bd --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/lib/drs26_digital/drs26.hpp @@ -0,0 +1,37 @@ +#ifndef _DRS26 +#define _DRS26 + +#include "ForteSensor.hpp" +#include "Message.hpp" +#include "Pinout.hpp" +#include "Wire.h" +#include "esp_log.h" +#include <SDI12.h> +#include <map> + +struct out_data_drs26 { + int id; + float circumferenceIncrement; + float temperature; +}; + +class ForteDRS26 : public ForteSensor<out_data_drs26> { + public: + void setup() override; + out_data_drs26 readData() override; + std::list<Message> buildMessages() override; + [[nodiscard]] SensorInformation getSensorInformation() const override; + + private: + SDI12 drs26; + out_data_drs26 data; + const SensorInformation sensorInformation{"DRS26", Protocol::I2C}; + enum class MeasurementType { TEMPERATURE, CIRCUMFERENCE_INCREMENT }; + + // enum to string + std::map<MeasurementType, const char *> measurementTypeToString = { + {MeasurementType::TEMPERATURE, "TEMPERATURE"}, + {MeasurementType::CIRCUMFERENCE_INCREMENT, "CIRCUMFERENCE_INCREMENT"}}; +}; + +#endif \ No newline at end of file diff --git a/Tests/Mieming/client_esp32C3/client/lib/espnow/README b/Tests/Mieming/client_esp32C3/client/lib/espnow/README new file mode 100644 index 0000000000000000000000000000000000000000..bbf1db0c44bf4b375af8aefcd9f6649864d64677 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/lib/espnow/README @@ -0,0 +1,11 @@ +# basic usage + +To send data using espnow, create a new Message object, +then use the addData(value, identifier) method for every value +to fill the message. +when every value is added, use the send() method to send the data +to the host (fipy). If the esp client has never recieved a config +message from the host, it will instead broadcast the message. + +--- +right now, it is not possible to add more than 10 values. diff --git a/Tests/Mieming/client_esp32C3/client/lib/espnow/src/ClientDataPackage.hpp b/Tests/Mieming/client_esp32C3/client/lib/espnow/src/ClientDataPackage.hpp new file mode 100644 index 0000000000000000000000000000000000000000..f08e6bba4ea43308e606f06f7870735d7f4820bc --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/lib/espnow/src/ClientDataPackage.hpp @@ -0,0 +1,54 @@ +#pragma once + +#include <ArduinoJson.h> +#include "MeasurementData.hpp" +#include "Protocol.hpp" +#include "SensorInformation.hpp" +#include <list> +#include <optional> +#include <string> +#include <utility> + +// having the data be a struct of basic types makes sending easier, +// otherwise we would have to serialize the data before sending +class ClientDataPackage { + private: + MeasurementData measurementData; + SensorInformation sensorInformation; + unsigned long timestamp; // maybe make this array + + public: + ClientDataPackage(MeasurementData value, SensorInformation sensorInformation, unsigned long timestamp) + : measurementData(std::move(value)), sensorInformation(std::move(sensorInformation)), timestamp(timestamp) + { + } + + [[nodiscard]] const MeasurementData &getMeasurementData() const { return measurementData; } + [[nodiscard]] const SensorInformation &getSensorInformation() const { return sensorInformation; } + [[nodiscard]] unsigned long getTimestamp() const { return timestamp; } + + [[nodiscard]] std::string getDataPackageAsMinifiedJsonString() const + { + StaticJsonDocument<250> document; // 250 byte is the max send size of espnow + + document["sensorName"] = sensorInformation.getSensorName(); + document["timestamp"] = timestamp; + document["protocol"] = protocolToString.at(sensorInformation.getProtocol()); + document["value"] = measurementData.getValue(); + + if (measurementData.getChannel().has_value()) { + document["channel"] = measurementData.getChannel().value(); + } + + if (measurementData.getI2CAddress().has_value()) { + document["i2cAddress"] = measurementData.getI2CAddress().value(); + } + + document["measurementType"] = measurementData.getMeasurementType(); + + std::string jsonString; + serializeJson(document, jsonString); + return jsonString; + } + +}; diff --git a/Tests/Mieming/client_esp32C3/client/lib/espnow/src/ESPNow.cpp b/Tests/Mieming/client_esp32C3/client/lib/espnow/src/ESPNow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..28eedfb4ca218230fba60d353e867261bc46a8c3 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/lib/espnow/src/ESPNow.cpp @@ -0,0 +1,118 @@ +#include "ESPNow.hpp" + +static const char *TAG = "ESPNOW"; + +uint8_t BROADCAST_MAC[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; +esp_now_peer_info_t hostInfo; +Preferences preferences; +bool msg_recv = false; + +bool was_msg_received(){ + if(msg_recv){ + msg_recv = false; + return true; + } + return false; +} + +void get_host_mac(uint8_t *destination) +{ + preferences.begin("config", true); + if (preferences.isKey("host")) { + preferences.getBytes("host", destination, sizeof(uint8_t) * 6); + } else { + memcpy(destination, BROADCAST_MAC, sizeof(BROADCAST_MAC)); + ESP_LOGE(TAG, "Backup MAC address used"); + } + preferences.end(); +} + +esp_err_t add_host_to_peers(config received){ + esp_now_peer_info_t host; + memset(&host, 0, sizeof(host)); + memcpy(host.peer_addr, received.host, sizeof(received.host)); + host.encrypt = false; + host.channel = 0; + return esp_now_add_peer(&host); +} + +void on_data_sent(const uint8_t *mac_addr, esp_now_send_status_t status) +{ + ESP_LOGE(TAG, "Message sent to"); + for(int i=0; i<6; i++){ + Serial.print(mac_addr[i], HEX); + Serial.print(":"); + } + Serial.println(); + // go to sleep +} + +void on_data_recv(const uint8_t *mac, const uint8_t *incomingData, int len) +{ + // is msg host -> yes -> set bool + // assume host change not happening, rare event + // => on host change, broadcast + ESP_LOGE(TAG, "Message recieved"); + preferences.begin("config", false); + config received_msg; + memcpy(&received_msg, incomingData, sizeof(received_msg)); // TODO: check for valid mac + // all the esp32 macs so far use the same first 3(?) bytes so maybe use that + switch (received_msg.type){ + case dataAck:{ + msg_recv = true; + Time::getInstance().setTime( + received_msg.epoch_seconds); // see https://www.esp32.com/viewtopic.php?t=9965, maybe this needs an offset + Serial.println(Time::getInstance().getEpochSeconds()); + if (!preferences.isKey("host")) { + preferences.putBytes("host", received_msg.host, sizeof(received_msg.host)); + ESP_LOGI(TAG, "host MAC address saved to flash"); + + // add host to peers + add_host_to_peers(received_msg); + } + } + case hostChange:{ + Time::getInstance().setTime(received_msg.epoch_seconds); + // delete old host + if(preferences.isKey("host")){ + uint8_t old[6]; + get_host_mac(old); + esp_now_del_peer(old); + } + // add new host + add_host_to_peers(received_msg); + } + default:{ + return; + } + } + preferences.end(); +} + + +esp_err_t espnow_setup() +{ + esp_err_t result; + WiFi.mode(WIFI_STA); + result = esp_now_init(); + if (result != ESP_OK) { + // initialization failed + return result; // not sure about this + } + + get_host_mac(hostInfo.peer_addr); // check if there is a host saved in flash mem, broadcast otherwise + + hostInfo.channel = 0; + + // TODO: PMK is used to encrypt LMK with the AES-128 algorithm. Call esp_now_set_pmk() to set PMK. If PMK is not + // set, a default PMK will be used. + // https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/network/esp_now.html + hostInfo.encrypt = false; + esp_now_add_peer(&hostInfo); + + preferences.clear(); + esp_now_register_recv_cb(on_data_recv); + esp_now_register_send_cb(on_data_sent); + + return ESP_OK; +} diff --git a/Tests/Mieming/client_esp32C3/client/lib/espnow/src/ESPNow.hpp b/Tests/Mieming/client_esp32C3/client/lib/espnow/src/ESPNow.hpp new file mode 100644 index 0000000000000000000000000000000000000000..266b139b46c184d91ddf0b7e741b6a70a3adf72a --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/lib/espnow/src/ESPNow.hpp @@ -0,0 +1,32 @@ +#ifndef _ESPNOW +#define _ESPNOW + +#include "Message.hpp" +#include "Time.hpp" +#include "esp_log.h" +#include "ram_caching.hpp" +#include <ClientDataPackage.hpp> +#include <ESP32Time.h> +#include <Preferences.h> +#include <WiFi.h> +#include <esp_now.h> + +enum MessageType{ + dataAck, + hostChange +}; +typedef struct config { + MessageType type; + uint8_t host[6]; + long epoch_seconds; +} config; + +esp_err_t espnow_setup(); +//esp_err_t espnow_send_message(const Message& message); +bool is_host_defined(); +bool was_msg_received(); +void get_host_mac(uint8_t *destination); +void on_data_sent(const uint8_t *mac_addr, esp_now_send_status_t status); +void on_data_recv(const uint8_t *mac, const uint8_t *incomingData, int len); + +#endif \ No newline at end of file diff --git a/Tests/Mieming/client_esp32C3/client/lib/espnow/src/Message.cpp b/Tests/Mieming/client_esp32C3/client/lib/espnow/src/Message.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7f7f8e2326e86ba647971170dbf3a43a83227c90 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/lib/espnow/src/Message.cpp @@ -0,0 +1,43 @@ +#include "Message.hpp" + +#include <utility> + +static const char *TAG = "MESSAGE"; + +esp_err_t Message::send() const +{ + ESP_LOGI(TAG, "Sending message"); + esp_err_t success; + auto messageData = getMessageAsMinifiedJsonString(); + + // conversion from std::string to c_str adds null terminator, which is why we add 1 to message length + success = esp_now_send(recipient, (uint8_t *)messageData.c_str(), (messageData.length() + 1) * sizeof(char)); + if (success != ESP_OK) { + ESP_LOGE(TAG, "Error sending the data"); + Serial.println(success, HEX); + // Removed caching from here, better do this in main + } + ESP_LOGE(TAG, "Sent data: %s", messageData.c_str()); + + ESP_LOGD(TAG, "time sent: %l", clientDataPackage.getTimestamp()); + ESP_LOGD(TAG, "send status: %d", success); + + return success; +} + +std::string Message::getMessageAsMinifiedJsonString() const +{ + return clientDataPackage.getDataPackageAsMinifiedJsonString(); +} + +Message::Message(ClientDataPackage data) : clientDataPackage(std::move(data)) +{ + // check for existing host mac address, use broadcast otherwise + get_host_mac(recipient); +} +Message::Message(MeasurementData const &data, const SensorInformation &information, unsigned long timestamp) + : clientDataPackage(data, information, timestamp) +{ + // check for existing host mac address, use broadcast otherwise + get_host_mac(recipient); +} diff --git a/Tests/Mieming/client_esp32C3/client/lib/espnow/src/Message.hpp b/Tests/Mieming/client_esp32C3/client/lib/espnow/src/Message.hpp new file mode 100644 index 0000000000000000000000000000000000000000..5a6ca8185393ababd2b3c83005a30cf8fd6052ab --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/lib/espnow/src/Message.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include "ClientDataPackage.hpp" +#include "ESPNow.hpp" +#include "Time.hpp" +#include "esp_log.h" +#include <Arduino.h> +#include <ArduinoJson.h> +#include <ESP32Time.h> +#include <esp_now.h> + +// Format of the message sent from host to client +// if more things are sent from the host the name might not be accurate anymore +class Message { + public: + + explicit Message(ClientDataPackage data); + + Message(MeasurementData const &data, const SensorInformation &information, unsigned long timestamp); + esp_err_t send() const; + [[nodiscard]] std::string getMessageAsMinifiedJsonString() const; + + private: + ClientDataPackage clientDataPackage; + uint8_t recipient[6]{}; +}; + diff --git a/Tests/Mieming/client_esp32C3/client/lib/ina219/ina219.cpp b/Tests/Mieming/client_esp32C3/client/lib/ina219/ina219.cpp new file mode 100644 index 0000000000000000000000000000000000000000..def6a9d73acefe00e1a160a1c3fc2ba64ab2099d --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/lib/ina219/ina219.cpp @@ -0,0 +1,35 @@ +#include "ina219.hpp" + +void ForteINA219 ::setup() +{ + Wire.begin(I2C_SDA, I2C_SCL); + if (!ina219.init()) { + // Sensor init went wrong + ESP_LOGW(sensorInformation.getSensorName().c_str(), "Initialization failed"); + return; + } +} + +out_data_ina219 ForteINA219 ::readData() +{ + if (!ina219.getOverflow()) { + data.shuntVoltage_mV = ina219.getShuntVoltage_mV(); + data.busVoltage_V = ina219.getBusVoltage_V(); + data.current_mA = ina219.getCurrent_mA(); + data.power_mW = ina219.getBusPower(); + data.loadVoltage_V = data.busVoltage_V + (data.shuntVoltage_mV / 1000); + data.ina219_overflow = ina219.getOverflow(); + + return data; + } else + return data; +} + +std::list<Message> ForteINA219::buildMessages() +{ + throw "Not yet implemented"; +} +SensorInformation ForteINA219::getSensorInformation() const +{ + return sensorInformation; +} diff --git a/Tests/Mieming/client_esp32C3/client/lib/ina219/ina219.hpp b/Tests/Mieming/client_esp32C3/client/lib/ina219/ina219.hpp new file mode 100644 index 0000000000000000000000000000000000000000..4a34d9591a325f9232f90ef61b4a74077fe1cf51 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/lib/ina219/ina219.hpp @@ -0,0 +1,33 @@ +#ifndef _INA219 +#define _INA219 + +#include "ForteSensor.hpp" +#include "Message.hpp" +#include "Pinout.hpp" +#include "Wire.h" +#include "esp_log.h" +#include <INA219_WE.h> + +struct out_data_ina219 { + float shuntVoltage_mV = 0.0; + float loadVoltage_V = 0.0; + float busVoltage_V = 0.0; + float current_mA = 0.0; + float power_mW = 0.0; + bool ina219_overflow = false; +}; + +class ForteINA219 : public ForteSensor<out_data_ina219> { + public: + void setup() override; + out_data_ina219 readData() override; + std::list<Message> buildMessages() override; + [[nodiscard]] SensorInformation getSensorInformation() const override; + + private: + INA219_WE ina219; + out_data_ina219 data; + const SensorInformation sensorInformation{"INA219", Protocol::I2C}; +}; + +#endif \ No newline at end of file diff --git a/Tests/Mieming/client_esp32C3/client/lib/scd30/scd30.cpp b/Tests/Mieming/client_esp32C3/client/lib/scd30/scd30.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7cff381af4ac4034d955366bf571a89b7e551ddf --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/lib/scd30/scd30.cpp @@ -0,0 +1,44 @@ +#include "scd30.hpp" + +void ForteSCD30 ::setup() +{ + Wire.begin(I2C_SDA, I2C_SCL); + if (!airSensor.begin()) { + // Sensor init went wrong + ESP_LOGW(sensorInformation.getSensorName().c_str(), "Initialization failed."); + return; + } +} + +out_data_scd30 ForteSCD30 ::readData() +{ + if (airSensor.dataAvailable()) { + data.C02 = airSensor.getCO2(); + data.Temperature = airSensor.getTemperature(); + data.Humidity = airSensor.getHumidity(); + + return data; + } + throw NoDataAvailableException(); +} + +std::list<Message> ForteSCD30::buildMessages() +{ + std::list<Message> messages; + + out_data_scd30 data = readData(); + MeasurementData CO2Data{data.C02, 0, {}, "CO2"}; + MeasurementData TempData{data.Temperature, 0, {}, "Temperature"}; + MeasurementData HumidData{data.Humidity, 0, {}, "Humidity"}; + + messages.emplace_back(Message(CO2Data, sensorInformation, Time::getInstance().getEpochSeconds())); + messages.emplace_back(Message(TempData, sensorInformation, Time::getInstance().getEpochSeconds())); + messages.emplace_back(Message(HumidData, sensorInformation, Time::getInstance().getEpochSeconds())); + + return messages; +} + +SensorInformation ForteSCD30::getSensorInformation() const +{ + return sensorInformation; +} diff --git a/Tests/Mieming/client_esp32C3/client/lib/scd30/scd30.hpp b/Tests/Mieming/client_esp32C3/client/lib/scd30/scd30.hpp new file mode 100644 index 0000000000000000000000000000000000000000..db3e85500924db80ac3c0b5cd3698314564f6fd6 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/lib/scd30/scd30.hpp @@ -0,0 +1,31 @@ +#ifndef _SCD30 +#define _SCD30 + +#include "ForteSensor.hpp" +#include "Message.hpp" +#include "NoDataAvailableException.hpp" +#include "Pinout.hpp" +#include "esp_log.h" +#include <SparkFun_SCD30_Arduino_Library.h> +#include <Wire.h> + +struct out_data_scd30 { + float C02; + float Temperature; + float Humidity; +}; + +class ForteSCD30 : public ForteSensor<out_data_scd30> { + public: + void setup() override; + out_data_scd30 readData() override; + std::list<Message> buildMessages() override; + [[nodiscard]] SensorInformation getSensorInformation() const override; + + private: + SCD30 airSensor; + out_data_scd30 data; + const SensorInformation sensorInformation{"SCD30", Protocol::I2C}; +}; + +#endif \ No newline at end of file diff --git a/Tests/Mieming/client_esp32C3/client/lib/time/src/Time.cpp b/Tests/Mieming/client_esp32C3/client/lib/time/src/Time.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5cc3dbcdb7086eb1a27bcf98dccef1e49e78beaf --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/lib/time/src/Time.cpp @@ -0,0 +1,28 @@ +#include "Time.hpp" + +#include <utility> +void Time::setTime(long epoch, int ms) +{ + this->rtc.setTime(epoch, ms); +} +tm Time::getTimeStruct() +{ + return this->rtc.getTimeStruct(); +} +String Time::getDateTime(bool mode) +{ + return this->rtc.getDateTime(mode); +} +String Time::getTime(String format) +{ + return this->rtc.getTime(std::move(format)); +} +unsigned long Time::getEpochSeconds() +{ + return this->rtc.getEpoch(); +} + +long Time::getMillis() +{ + return this->rtc.getMillis(); +} diff --git a/Tests/Mieming/client_esp32C3/client/lib/time/src/Time.hpp b/Tests/Mieming/client_esp32C3/client/lib/time/src/Time.hpp new file mode 100644 index 0000000000000000000000000000000000000000..783bdef40ead148d61271c7cf92aeabb8f3242d7 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/lib/time/src/Time.hpp @@ -0,0 +1,75 @@ +#ifndef ESPTIME +#define ESPTIME + +#include <ESP32Time.h> + +class Time { + public: + static Time &getInstance() + { + static Time instance; // Guaranteed to be destroyed. + // Instantiated on first use. + return instance; + } + + /*! + @brief set the internal RTC time + @param epoch + epoch time in seconds + @param ms + microseconds (optional) + */ + void setTime(long epoch, int ms = 0); + + /*! + @brief get the internal RTC time as a tm struct + */ + tm getTimeStruct(); + + /*! + @brief get the time and date as an Arduino String object + @param mode + true = Long date format + false = Short date format + */ + String getDateTime(bool mode); + + /*! + @brief get the time as an Arduino String object with the specified format + @param format + time format + http://www.cplusplus.com/reference/ctime/strftime/ + */ + String getTime(String format = "%H:%M:%S"); + + /*! + @brief get the current epoch seconds as long + */ + unsigned long getEpochSeconds(); + + /*! + @brief get the current milliseconds as long + */ + long getMillis(); + + private: + Time() {} // Constructor? (the {} brackets) are needed here. + + ESP32Time rtc = ESP32Time{}; + + // C++ 11 + // ======= + // We can use the better technique of deleting the methods + // we don't want. + public: + Time(Time const &) = delete; + void operator=(Time const &) = delete; + + // Note: Scott Meyers mentions in his Effective Modern + // C++ book, that deleted functions should generally + // be public as it results in better error messages + // due to the compilers behavior to check accessibility + // before deleted status +}; + +#endif \ No newline at end of file diff --git a/Tests/Mieming/client_esp32C3/client/platformio.ini b/Tests/Mieming/client_esp32C3/client/platformio.ini new file mode 100644 index 0000000000000000000000000000000000000000..19ee957dceb9496815c39ad024625a57d06ce6d1 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/platformio.ini @@ -0,0 +1,35 @@ +; 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:esp32-c3-devkitm-1] +platform = espressif32 +board = esp32-c3-devkitm-1 +framework = arduino +monitor_speed = 115200 +; C++17 https://community.platformio.org/t/esp32-c-17-toolchain-missing-std-optional/25850/6 +; we use c++17 features (i.e. optionals in ClientDataPackage.hpp) +build_flags = + -I include + -DCORE_DEBUG_LEVEL=5 + -std=gnu++17 +build_unflags = -std=gnu++11 +monitor_port = /dev/ttyUSB0 +upload_port = /dev/ttyUSB0 +lib_deps = + sparkfun/SparkFun SCD30 Arduino Library@^1.0.18 + Wire + adafruit/Adafruit ADS1X15@^2.4.0 + wollewald/INA219_WE@^1.3.1 + adafruit/Adafruit BusIO@^1.13.2 + Adafruit_I2CDevice + SPI + envirodiy/SDI-12@^2.1.4 + fbiego/ESP32Time@^2.0.0 + bblanchon/ArduinoJson@^6.19.4 diff --git a/Tests/Mieming/client_esp32C3/client/src/main.cpp b/Tests/Mieming/client_esp32C3/client/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9cfb9c85cdf088fa477dadccf4ecb95fee09d906 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/src/main.cpp @@ -0,0 +1,114 @@ +#include "../lib/dr26_analogue/dr26.hpp" +#include "NoDataAvailableException.hpp" +#include "esp_log.h" +#include "f_deep_sleep.hpp" +#include <Arduino.h> +#include <drs26.hpp> +#include <ina219.hpp> +#include <scd30.hpp> +#include "ESPNow.hpp" +// #include "esp32-hal-log.h" +static const std::string TAG = "MAIN"; + + +ForteDR26 dr26_channel3; +ForteDR26 dr26_channel1; +ForteDR26 dr26_channel2; +ForteDR26 dr26_channel0_power; + +void setup() +{ + Serial.begin(115200); + //Set the GPIO which conrtols the step up to OUTPUT + gpio_set_direction(GPIO_NUM_3, GPIO_MODE_OUTPUT); + + + + + DeepSleep::print_wakeup_reason(); + DeepSleep::bootCount++; + ESP_LOGD(TAG.c_str(), "Boot number: %d", DeepSleep::bootCount); + +gpio_set_level(GPIO_NUM_3, 1); + dr26_channel1.setup(); + dr26_channel3.setChannel(3); + dr26_channel1.setChannel(1); + dr26_channel2.setChannel(2); + dr26_channel0_power.setChannel(0); +gpio_set_level(GPIO_NUM_3, 0); + + espnow_setup(); + // log_e("Setup complete."); +} + +void loop() +{ +gpio_set_level(GPIO_NUM_3, 1); +Serial.println("***********************1-DRS26 NOT YET CONNECTED**********************************"); +Serial.println(dr26_channel1.readData(),5); +Serial.println("***********************2-DRS26**********************************"); +Serial.println(dr26_channel2.readData(),5); +Serial.println("***********************3-DRS26 *********************************"); +Serial.println(dr26_channel3.readData(),5); + + +Serial.println("***********************0-Voltage-Battery**********************************"); +dr26_channel3.changeGain(GAIN_TWOTHIRDS); +Serial.println(dr26_channel0_power.readData(),5); + + + + try { + + auto messages = dr26_channel0_power.buildMessages(0,"Voltage-Battery"); + + + for (const Message &message : messages) { + if(message.send() != ESP_OK){ + RtcMemory::store(message.getMessageAsMinifiedJsonString()); + } + delay(5000); + if(!was_msg_received()){ + RtcMemory::store(message.getMessageAsMinifiedJsonString()); + } + } + + dr26_channel3.changeGain(GAIN_ONE); + auto messages2=dr26_channel2.buildMessages(2,"CIRCUMFERENCE_INCREMENT"); + + for (const Message &message2 : messages2) { + if(message2.send() != ESP_OK){ + RtcMemory::store(message2.getMessageAsMinifiedJsonString()); + } + delay(5000); + if(!was_msg_received()){ + RtcMemory::store(message2.getMessageAsMinifiedJsonString()); + } + } + + auto messages3=dr26_channel3.buildMessages(3,"CIRCUMFERENCE_INCREMENT"); + + for (const Message &message3 : messages3) { + if(message3.send() != ESP_OK){ + RtcMemory::store(message3.getMessageAsMinifiedJsonString()); + } + delay(5000); + if(!was_msg_received()){ + RtcMemory::store(message3.getMessageAsMinifiedJsonString()); + } + } + + + } catch (const NoDataAvailableException &e) { + std::cerr << e.what() << '\n'; + } + + + + Serial.print("This device: "); + Serial.println("\n"); + +gpio_set_level(GPIO_NUM_3, 0); +delay(5); + DeepSleep::deep_sleep(600); +} diff --git a/Tests/Mieming/client_esp32C3/client/test/README b/Tests/Mieming/client_esp32C3/client/test/README new file mode 100644 index 0000000000000000000000000000000000000000..9b1e87bc67c90e7f09a92a3e855444b085c655a6 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner 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/en/latest/advanced/unit-testing/index.html diff --git a/Tests/Mieming/client_esp32C3/client/test/TestClientDataPackage.cpp b/Tests/Mieming/client_esp32C3/client/test/TestClientDataPackage.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eea536cfbc63f7c6dc9797d8288a5887c384aa0c --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/test/TestClientDataPackage.cpp @@ -0,0 +1,46 @@ +// +// Created by zoe on 10/6/22. +// + +#include "TestClientDataPackage.hpp" +#include "MeasurementData.hpp" +#include "Protocol.hpp" +#include <vector> + +void test_export_to_json() +{ + auto dataPackage = + ClientDataPackage(MeasurementData{1.1, 0, {}, "TEMPERATURE"}, SensorInformation{"DRS26", Protocol::Analog}, 0); + + std::string json = dataPackage.getDataPackageAsMinifiedJsonString(); + // expected + std::string expected = + R"({"sensorName":"DRS26","timestamp":0,"protocol":"ANALOG","value":1.1,"channel":0,"measurementType":"TEMPERATURE"})"; + + TEST_ASSERT_EQUAL_STRING(expected.c_str(), json.c_str()); +} +void test_export_to_json_no_analog() +{ + auto dataPackage = + ClientDataPackage(MeasurementData{1.1, {}, {}, "TEMPERATURE"}, SensorInformation{"DRS26_DIGITAL", Protocol::I2C}, 0); + + std::string json = dataPackage.getDataPackageAsMinifiedJsonString(); + // expected + std::string expected = + R"({"sensorName":"DRS26_DIGITAL","timestamp":0,"protocol":"I2C","value":1.1,"measurementType":"TEMPERATURE"})"; + + TEST_ASSERT_EQUAL_STRING(expected.c_str(), json.c_str()); +} + +void test_export_to_json_no_channel_no_address() +{ + auto dataPackage = + ClientDataPackage(MeasurementData{1.1,"TEMPERATURE"}, SensorInformation{"DRS26_DIGITAL", Protocol::I2C}, 0); + + std::string json = dataPackage.getDataPackageAsMinifiedJsonString(); + // expected + std::string expected = + R"({"sensorName":"DRS26_DIGITAL","timestamp":0,"protocol":"I2C","value":1.1,"measurementType":"TEMPERATURE"})"; + + TEST_ASSERT_EQUAL_STRING(expected.c_str(), json.c_str()); +} \ No newline at end of file diff --git a/Tests/Mieming/client_esp32C3/client/test/TestClientDataPackage.hpp b/Tests/Mieming/client_esp32C3/client/test/TestClientDataPackage.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fa5f20396c423714daff914dfd16b24c8cd6cff5 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/test/TestClientDataPackage.hpp @@ -0,0 +1,16 @@ +// +// Created by zoe on 10/6/22. +// + +#ifndef CLIENT_TESTCLIENTDATAPACKAGE_HPP +#define CLIENT_TESTCLIENTDATAPACKAGE_HPP + +#include <unity.h> +#include <Arduino.h> +#include <ClientDataPackage.hpp> + +void test_export_to_json(); +void test_export_to_json_no_analog(); +void test_export_to_json_no_channel_no_address(); + +#endif // CLIENT_TESTCLIENTDATAPACKAGE_HPP diff --git a/Tests/Mieming/client_esp32C3/client/test/TestESPNow.cpp b/Tests/Mieming/client_esp32C3/client/test/TestESPNow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3a4c149bb8742e61c0a235691e7e0b8d9a3eda76 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/test/TestESPNow.cpp @@ -0,0 +1,12 @@ +#include "TestESPNow.hpp" + +void test_on_data_recv_valid_config() +{ + uint8_t mac_addr[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + int len = 0; + config conf = {host : {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}, time_millis : 0}; + + // preferences / hostinfo would need to be global for this to work + + TEST_FAIL(); +} diff --git a/Tests/Mieming/client_esp32C3/client/test/TestESPNow.hpp b/Tests/Mieming/client_esp32C3/client/test/TestESPNow.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a2512b2ffd4ca48031415456d658302d4bae6b91 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/test/TestESPNow.hpp @@ -0,0 +1,6 @@ +#pragma once +#include <Arduino.h> +#include <ESPNow.hpp> +#include <unity.h> + +void test_on_data_recv_valid_config(); \ No newline at end of file diff --git a/Tests/Mieming/client_esp32C3/client/test/main.cpp b/Tests/Mieming/client_esp32C3/client/test/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5ad5f3f7a0c3626689b5093cfbec886b6afa4e96 --- /dev/null +++ b/Tests/Mieming/client_esp32C3/client/test/main.cpp @@ -0,0 +1,18 @@ +#include "TestESPNow.hpp" +#include <Arduino.h> +#include <unity.h> +#include "TestClientDataPackage.hpp" + +void setup() +{ + delay(2000); // service delay + + UNITY_BEGIN(); + RUN_TEST(test_on_data_recv_valid_config); + RUN_TEST(test_export_to_json); + RUN_TEST(test_export_to_json_no_analog); + RUN_TEST(test_export_to_json_no_channel_no_address); + UNITY_END(); +} + +void loop() {} \ No newline at end of file