Skip to content
Snippets Groups Projects
Unverified Commit 14619889 authored by Zoe Pfister's avatar Zoe Pfister :speech_balloon:
Browse files

WIP: replace pack solution of Message transfer to JSON solution using ArduinoJson.

parent cf45fde7
No related branches found
No related tags found
6 merge requests!39Merge Develop into Main,!19development into master,!17Inital Host, initial Client,!10merge serial comm and sd write into espnow,!8merge sensor_readout into develop,!7move to c++17, change message building, refactored SensorInformation and MeasurementData
Showing
with 266 additions and 111 deletions
...@@ -2,12 +2,14 @@ ...@@ -2,12 +2,14 @@
#define _FORTE_SENSOR #define _FORTE_SENSOR
#include "Message.hpp" #include "Message.hpp"
#include "Protocol.hpp"
template <class T> template <class T>
class Forte_Sensor { class Forte_Sensor {
public: public:
virtual T read_data() = 0; virtual T readData() = 0;
virtual void setup() = 0; virtual void setup() = 0;
virtual Message build_message() = 0; virtual Message buildMessage() = 0;
virtual Protocol getProtocol() = 0;
private: private:
}; };
......
//
// Created by zoe on 10/5/22.
//
#ifndef CLIENT_PROTOCOL_HPP
#define CLIENT_PROTOCOL_HPP
#include <map>
enum Protocol { I2C, RS485, Analog };
// protocol to string
static std::map<Protocol, const char *> protocolToString = {{I2C, "I2C"}, {RS485, "RS485"}, {Analog, "Analog"}};
#endif // CLIENT_PROTOCOL_HPP
#include "ram_caching.hpp" #include "ram_caching.hpp"
static const char* TAG = "CACHING"; static const char* TAG = "CACHING";
const int NUM_SENSORS = 10;
RTC_DATA_ATTR int cachedAmount = -1; //RTC_DATA_ATTR int cachedAmount = -1;
RTC_DATA_ATTR ClientDataPackage backup[NUM_SENSORS]; //RTC_DATA_ATTR ClientDataPackage backup[NUM_SENSORS];
//
ClientDataPackage ram_cache_pop() //ClientDataPackage ram_cache_pop()
{ //{
return backup[cachedAmount--]; // return backup[cachedAmount--];
} //}
//
void ram_cache_push(ClientDataPackage data) //void ram_cache_push(ClientDataPackage data)
{ //{
backup[++cachedAmount] = data; // backup[++cachedAmount] = data;
ESP_LOGI(TAG, "ClientDataPackage saved"); // ESP_LOGI(TAG, "ClientDataPackage saved");
} //}
//
bool ram_cache_is_empty() //bool ram_cache_is_empty()
{ //{
return cachedAmount == -1; // return cachedAmount == -1;
} //}
//
bool ram_cache_is_full() //bool ram_cache_is_full()
{ //{
return cachedAmount == 9; // return cachedAmount == 9;
} //}
\ No newline at end of file \ No newline at end of file
#ifndef _RAM_CACHE #ifndef _RAM_CACHE
#define _RAM_CACHE #define _RAM_CACHE
#include "ClientDataPackage.hpp" //#include "ClientDataPackage.hpp"
#include "esp_log.h" #include "esp_log.h"
#include <ESP32Time.h> #include <ESP32Time.h>
bool ram_cache_is_empty(); bool ram_cache_is_empty();
bool ram_cache_is_full(); bool ram_cache_is_full();
void ram_cache_push(ClientDataPackage data); //void ram_cache_push(ClientDataPackage data);
ClientDataPackage ram_cache_pop(); //ClientDataPackage ram_cache_pop();
#endif #endif
\ No newline at end of file
...@@ -17,7 +17,7 @@ void Forte_DR26 ::setup() ...@@ -17,7 +17,7 @@ void Forte_DR26 ::setup()
delay(100); delay(100);
} }
float Forte_DR26 ::read_data() float Forte_DR26 ::readData()
{ {
float volts = 0; float volts = 0;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
...@@ -44,12 +44,16 @@ float Forte_DR26 ::read_data() ...@@ -44,12 +44,16 @@ float Forte_DR26 ::read_data()
// GAIN_FOUR // 4x gain +/- 1.024V 1 bit = 0.03125mV // GAIN_FOUR // 4x gain +/- 1.024V 1 bit = 0.03125mV
// GAIN_EIGHT // 8x gain +/- 0.512V 1 bit = 0.015625mV // GAIN_EIGHT // 8x gain +/- 0.512V 1 bit = 0.015625mV
// GAIN_SIXTEEN // 16x gain +/- 0.256V 1 bit = 0.0078125mV // GAIN_SIXTEEN // 16x gain +/- 0.256V 1 bit = 0.0078125mV
void Forte_DR26 ::change_Gain(adsGain_t gain) void Forte_DR26 ::changeGain(adsGain_t gain)
{ {
ads.setGain(gain); ads.setGain(gain);
} }
Message Forte_DR26::build_message() Message Forte_DR26::buildMessage()
{ {
throw "Not implemented"; throw "Not implemented";
} }
\ No newline at end of file Protocol Forte_DR26::getProtocol()
{
return Analog;
}
...@@ -11,9 +11,10 @@ ...@@ -11,9 +11,10 @@
class Forte_DR26 : public Forte_Sensor<float> { class Forte_DR26 : public Forte_Sensor<float> {
public: public:
void setup() override; void setup() override;
float read_data() override; float readData() override;
void change_Gain(adsGain_t gain); void changeGain(adsGain_t gain);
Message build_message() override; Message buildMessage() override;
Protocol getProtocol() override;
private: private:
}; };
......
#include <drs26.hpp> #include <drs26.hpp>
static const char* TAG = "DRS26"; static const std::string TAG = "DRS26";
/* /*
It happens for some reason that the sensor cant get reached every 2 time 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 Because the sensor use sdi12 protocoll we have to wait aproxemettly 1 secound between the commands
...@@ -12,7 +12,7 @@ void Forte_DRS26 ::setup() ...@@ -12,7 +12,7 @@ void Forte_DRS26 ::setup()
drs26.begin(4); drs26.begin(4);
} }
out_data_drs26 Forte_DRS26 ::read_data() out_data_drs26 Forte_DRS26 ::readData()
{ {
String sdiResponse = ""; String sdiResponse = "";
String measurement_command = String measurement_command =
...@@ -36,16 +36,20 @@ out_data_drs26 Forte_DRS26 ::read_data() ...@@ -36,16 +36,20 @@ out_data_drs26 Forte_DRS26 ::read_data()
if (sdiResponse.length() > 1) { if (sdiResponse.length() > 1) {
data.id = sdiResponse.substring(0, 8).toInt(); data.id = sdiResponse.substring(0, 8).toInt();
data.circumference = sdiResponse.substring(9, 15).toFloat(); data.circumferenceIncrement = sdiResponse.substring(9, 15).toFloat();
data.temperatur = sdiResponse.substring(16, 22).toFloat(); data.temperature = sdiResponse.substring(16, 22).toFloat();
} }
return data; return data;
} }
Message Forte_DRS26 ::build_message() Message Forte_DRS26 ::buildMessage()
{ {
auto message = Message(); auto message = Message();
message.add_data(12.12, 1); message.addData(12.12, measurementTypeToString[MeasurementType::TEMPERATURE], TAG, 4);
ESP_LOGE(TAG, "test"); ESP_LOGE(TAG.c_str(), "test");
return message; return message;
} }
\ No newline at end of file Protocol Forte_DRS26::getProtocol()
{
return I2C;
}
...@@ -7,22 +7,30 @@ ...@@ -7,22 +7,30 @@
#include "esp_log.h" #include "esp_log.h"
#include "pinout.hpp" #include "pinout.hpp"
#include <SDI12.h> #include <SDI12.h>
#include <map>
struct out_data_drs26 { struct out_data_drs26 {
int id; int id;
float circumference; float circumferenceIncrement;
float temperatur; float temperature;
}; };
class Forte_DRS26 : public Forte_Sensor<out_data_drs26> { class Forte_DRS26 : public Forte_Sensor<out_data_drs26> {
public: public:
void setup() override; void setup() override;
out_data_drs26 read_data() override; out_data_drs26 readData() override;
Message build_message() override; Message buildMessage() override;
Protocol getProtocol() override;
private: private:
SDI12 drs26; SDI12 drs26;
out_data_drs26 data; out_data_drs26 data;
enum class MeasurementType { TEMPERATURE, CIRCUMFERENCE_INCREMENT };
// enum to string
std::map<MeasurementType, const char *> measurementTypeToString = {
{MeasurementType::TEMPERATURE, "TEMPERATURE"},
{MeasurementType::CIRCUMFERENCE_INCREMENT, "CIRCUMFERENCE_INCREMENT"}};
}; };
#endif #endif
\ No newline at end of file
# basic usage # basic usage
To send data using espnow, create a new Message object, To send data using espnow, create a new Message object,
then use the add_data(value, identifier) method for every value then use the addData(value, identifier) method for every value
to fill the message. to fill the message.
when every value is added, use the send() method to send the data 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 to the host (fipy). If the esp client has never recieved a config
......
#pragma once #pragma once
#define NUM_SENSORS 10 #include "ArduinoJson.h"
// packing the struct without padding, makes reading it on the fipy easier #include "Protocol.hpp"
#pragma pack(1) #include <list>
#include <string>
#include <utility>
struct MeasurementData {
double value;
int channel;
std::string measurementType; // TODO: consider using an enum
};
// having the data be a struct of basic types makes sending easier, // having the data be a struct of basic types makes sending easier,
// otherwise we would have to serialize the data before sending // otherwise we would have to serialize the data before sending
struct ClientDataPackage { class ClientDataPackage {
int identifiers[NUM_SENSORS]; private:
float values[NUM_SENSORS]; MeasurementData value;
int amountData; std::string sensorName;
std::string protocol;
long timestamp; // maybe make this array long timestamp; // maybe make this array
public:
ClientDataPackage(MeasurementData value, std::string sensorName, long timestamp, Protocol protocol)
: value(std::move(std::move(value))), sensorName(std::move(sensorName)), timestamp(timestamp),
protocol(protocolToString[protocol])
{
}
std::string getDataPackageAsMinifiedJsonString()
{
StaticJsonDocument<250> document; // 250 byte is the max send size of espnow
document["sensorName"] = sensorName;
document["timestamp"] = timestamp;
document["protocol"] = protocol;
document["value"] = value.value;
document["channel"] = value.channel;
document["measurementType"] = value.measurementType;
std::string jsonString;
serializeJson(document, jsonString);
return jsonString;
}
}; };
...@@ -2,51 +2,89 @@ ...@@ -2,51 +2,89 @@
static const char *TAG = "MESSAGE"; static const char *TAG = "MESSAGE";
void Message::add_data(float value, int identifier) void Message::addData(float value, int identifier)
{ {
if (data.amountData < NUM_SENSORS) { StaticJsonDocument<100> document;
data.values[data.amountData] = value; document["value"] = value;
data.identifiers[data.amountData] = identifier; document["identifier"] = identifier;
data.amountData++; data["values"].add(document);
} ESP_LOGD(TAG, "Added data: %s", getMessageAsMinifiedJsonString().c_str());
}
void Message::addData(float value, const std::string &measurementType, const std::string &sensorName)
{
StaticJsonDocument<100> document;
document["sensorName"] = sensorName;
document["measurementType"] = measurementType;
data["values"].add(document);
ESP_LOGD(TAG, "Added data: %s", getMessageAsMinifiedJsonString().c_str());
}
/**
* Add data to a message that originates from an analog sensor with multiple channels
* @param value Value of the measurement
* @param measurementType Type of the measurement
* @param sensorName Name of the sensor
* @param channel Connected analog channel
*/
void Message::addData(float value, const std::string &measurementType, const std::string &sensorName, int channel)
{
StaticJsonDocument<100> document;
document["sensorName"] = sensorName;
document["channel"] = channel;
document["measurementType"] = measurementType;
document["value"] = value;
data["values"].add(document);
ESP_LOGD(TAG, "Added data: %s", getMessageAsMinifiedJsonString().c_str());
} }
esp_err_t Message::send() esp_err_t Message::send()
{ {
ESP_LOGI(TAG, "Sending message"); ESP_LOGI(TAG, "Sending message");
esp_err_t success; esp_err_t success;
success = esp_now_send(recipient, (uint8_t *)&data, sizeof(data)); auto messageData = getMessageAsMinifiedJsonString();
// if(success != ESP_OK){ success = esp_now_send(recipient, (uint8_t *)&messageData, sizeof(data));
// if(!ram_cache_is_full()){ if (success != ESP_OK) {
// ram_cache_push(*data); // TODO REWRITE FOR JSON
// } // if (!ram_cache_is_full()) {
// } // // ram_cache_push(messageData);
for (int i = 0; i < data.amountData; i++) { // }
ESP_LOGD(TAG, "Sent data: %i", data.values[i]);
} }
ESP_LOGD(TAG, "Sent data: %s", messageData.c_str());
ESP_LOGD(TAG, "time sent: %l", data.timestamp); std::string timestampString = data["timestamp"];
ESP_LOGD(TAG, "time sent: %s", timestampString.c_str());
ESP_LOGD(TAG, "send status: %d", success); ESP_LOGD(TAG, "send status: %d", success);
return success; return success;
} }
StaticJsonDocument<256> Message::getData()
{
return data;
}
Message ::Message() Message ::Message()
{ {
// check for existing host mac address, use broadcast otherwise // check for existing host mac address, use broadcast otherwise
get_host_mac(recipient); get_host_mac(recipient);
data["values"] = JsonArray();
data.amountData = 0; addTimestamp();
data.timestamp = esptime::rtc.getMillis(); // I am assuming we are not sending data from Unix Epoch
} }
Message ::Message(ClientDataPackage old_data) std::string Message::getMessageAsMinifiedJsonString()
{ {
data = old_data; std::string minimizedJson;
// memcpy(&data, &old_data, sizeof(data)); serializeJson(data, minimizedJson);
get_host_mac(recipient); return minimizedJson;
} }
ClientDataPackage Message::getData() void Message::addTimestamp()
{ {
return data; // TODO: if we are not time synced (i.e. didn't reach the host for current time, use another value like number of
// reboots of the ESP)
data["timestamp"] = esptime::rtc.getMillis();
} }
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "Time.hpp" #include "Time.hpp"
#include "esp_log.h" #include "esp_log.h"
#include <Arduino.h> #include <Arduino.h>
#include <ArduinoJson.h>
#include <ESP32Time.h> #include <ESP32Time.h>
#include <esp_now.h> #include <esp_now.h>
...@@ -12,13 +13,19 @@ ...@@ -12,13 +13,19 @@
// if more things are sent from the host the name might not be accurate anymore // if more things are sent from the host the name might not be accurate anymore
class Message { class Message {
public: public:
void addData(float value, int identifier);
void addData(float value, const std::string &measurementType, const std::string &sensorName);
void addData(float value, const std::string &measurementType, const std::string &sensorName, int channel);
Message(); Message();
explicit Message(ClientDataPackage old_data);
void add_data(float value, int identifier);
esp_err_t send(); esp_err_t send();
ClientDataPackage getData(); StaticJsonDocument<256> getData();
std::string getMessageAsMinifiedJsonString();
private: private:
ClientDataPackage data; StaticJsonDocument<256> data;
uint8_t recipient[6]; void addTimestamp();
// ClientDataPackage data;
uint8_t recipient[6]{};
}; };
\ No newline at end of file
...@@ -12,7 +12,7 @@ void Forte_INA219 ::setup() ...@@ -12,7 +12,7 @@ void Forte_INA219 ::setup()
} }
} }
out_data_ina219 Forte_INA219 ::read_data() out_data_ina219 Forte_INA219 ::readData()
{ {
if (!ina219.getOverflow()) { if (!ina219.getOverflow()) {
data.shuntVoltage_mV = ina219.getShuntVoltage_mV(); data.shuntVoltage_mV = ina219.getShuntVoltage_mV();
...@@ -27,7 +27,11 @@ out_data_ina219 Forte_INA219 ::read_data() ...@@ -27,7 +27,11 @@ out_data_ina219 Forte_INA219 ::read_data()
return data; return data;
} }
Message Forte_INA219::build_message() Message Forte_INA219::buildMessage()
{ {
throw "Not yet implemented"; throw "Not yet implemented";
} }
\ No newline at end of file Protocol Forte_INA219::getProtocol()
{
return I2C;
}
...@@ -20,8 +20,9 @@ struct out_data_ina219 { ...@@ -20,8 +20,9 @@ struct out_data_ina219 {
class Forte_INA219 : public Forte_Sensor<out_data_ina219> { class Forte_INA219 : public Forte_Sensor<out_data_ina219> {
public: public:
void setup() override; void setup() override;
out_data_ina219 read_data() override; out_data_ina219 readData() override;
Message build_message() override; Message buildMessage() override;
Protocol getProtocol() override;
private: private:
INA219_WE ina219; INA219_WE ina219;
......
...@@ -12,7 +12,7 @@ void Forte_SCD30 ::setup() ...@@ -12,7 +12,7 @@ void Forte_SCD30 ::setup()
} }
} }
out_data_scd30 Forte_SCD30 ::read_data() out_data_scd30 Forte_SCD30 ::readData()
{ {
if (airSensor.dataAvailable()) { if (airSensor.dataAvailable()) {
data.C02 = airSensor.getCO2(); data.C02 = airSensor.getCO2();
...@@ -25,7 +25,11 @@ out_data_scd30 Forte_SCD30 ::read_data() ...@@ -25,7 +25,11 @@ out_data_scd30 Forte_SCD30 ::read_data()
// return out_data_scd30{-1, -1, -1}; // return out_data_scd30{-1, -1, -1};
} }
Message Forte_SCD30::build_message() Message Forte_SCD30::buildMessage()
{ {
throw "Not yet implemented"; throw "Not yet implemented";
} }
\ No newline at end of file Protocol Forte_SCD30::getProtocol()
{
return I2C;
}
...@@ -18,8 +18,9 @@ struct out_data_scd30 { ...@@ -18,8 +18,9 @@ struct out_data_scd30 {
class Forte_SCD30 : public Forte_Sensor<out_data_scd30> { class Forte_SCD30 : public Forte_Sensor<out_data_scd30> {
public: public:
void setup() override; void setup() override;
out_data_scd30 read_data() override; out_data_scd30 readData() override;
Message build_message() override; Message buildMessage() override;
Protocol getProtocol() override;
private: private:
SCD30 airSensor; SCD30 airSensor;
......
...@@ -13,16 +13,17 @@ platform = espressif32 ...@@ -13,16 +13,17 @@ platform = espressif32
board = esp32-c3-devkitm-1 board = esp32-c3-devkitm-1
framework = arduino framework = arduino
monitor_speed = 115200 monitor_speed = 115200
build_flags = build_flags =
-I include -I include
-DCORE_DEBUG_LEVEL=5 -DCORE_DEBUG_LEVEL=5
lib_deps = lib_deps =
sparkfun/SparkFun SCD30 Arduino Library@^1.0.18 sparkfun/SparkFun SCD30 Arduino Library@^1.0.18
Wire Wire
adafruit/Adafruit ADS1X15@^2.4.0 adafruit/Adafruit ADS1X15@^2.4.0
wollewald/INA219_WE@^1.3.1 wollewald/INA219_WE@^1.3.1
adafruit/Adafruit BusIO@^1.13.2 adafruit/Adafruit BusIO@^1.13.2
Adafruit_I2CDevice Adafruit_I2CDevice
SPI SPI
envirodiy/SDI-12@^2.1.4 envirodiy/SDI-12@^2.1.4
fbiego/ESP32Time@^2.0.0 fbiego/ESP32Time@^2.0.0
bblanchon/ArduinoJson@^6.19.4
...@@ -24,8 +24,8 @@ void loop() ...@@ -24,8 +24,8 @@ void loop()
try { try {
espnow_setup(); espnow_setup();
// data = drs26.read_data(); // data = drs26.readData();
auto message = drs26.build_message(); auto message = drs26.buildMessage();
message.send(); message.send();
} catch (const NoDataAvailableException &e) { } catch (const NoDataAvailableException &e) {
std::cerr << e.what() << '\n'; std::cerr << e.what() << '\n';
......
//
// Created by zoe on 10/6/22.
//
#include "TestClientDataPackage.hpp"
#include "Protocol.hpp"
#include <vector>
void test_export_to_json()
{
ClientDataPackage dataPackage = ClientDataPackage(MeasurementData{1.1, 0, "TEMPERATURE"}, "DRS26", 0, Analog);
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());
}
\ No newline at end of file
//
// 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();
#endif // CLIENT_TESTCLIENTDATAPACKAGE_HPP
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment