From f05e1dd552b81d7cfcbbd37d70ed0004e4bf333c Mon Sep 17 00:00:00 2001
From: Zoe Pfister <zoe.pfister@student.uibk.ac.at>
Date: Thu, 6 Oct 2022 17:40:19 +0200
Subject: [PATCH] move to c++17, change message building, refactored
 SensorInformation and MeasurementData - messages are now built using the
 constructor - messages now only contain a single measurement value, even if a
 sensor might include more than one measurement - buildMessage has been
 changed to buildMessages and now returns a list of messages depending on how
 many measurements a sensor contains - ClientDataPackage now builds from
 SensorInformation and MeasurementData - minor naming refactors

---
 client/client/include/ForteSensor.hpp         | 10 +--
 client/client/include/MeasurementData.hpp     | 40 ++++++++++
 .../include/NoDataAvailableException.hpp      |  2 +-
 .../client/include/{pinout.hpp => Pinout.hpp} |  4 +-
 client/client/include/Protocol.hpp            |  5 +-
 client/client/include/SensorInformation.hpp   | 25 ++++++
 .../lib/dr26_analogue/{src => }/dr26.cpp      | 25 +++---
 client/client/lib/dr26_analogue/dr26.hpp      | 24 ++++++
 client/client/lib/dr26_analogue/src/dr26.hpp  | 22 ------
 client/client/lib/drs26_digital/drs26.cpp     | 26 ++++---
 client/client/lib/drs26_digital/drs26.hpp     |  9 ++-
 .../lib/espnow/src/ClientDataPackage.hpp      | 45 ++++++-----
 client/client/lib/espnow/src/Message.cpp      | 78 ++++---------------
 client/client/lib/espnow/src/Message.hpp      | 15 ++--
 client/client/lib/ina219/ina219.cpp           | 14 ++--
 client/client/lib/ina219/ina219.hpp           |  9 ++-
 client/client/lib/scd30/scd30.cpp             | 15 ++--
 client/client/lib/scd30/scd30.hpp             |  9 ++-
 client/client/platformio.ini                  |  6 +-
 client/client/src/main.cpp                    | 16 ++--
 client/client/test/TestClientDataPackage.cpp  | 31 +++++++-
 client/client/test/TestClientDataPackage.hpp  |  2 +
 client/client/test/main.cpp                   |  2 +
 23 files changed, 247 insertions(+), 187 deletions(-)
 create mode 100644 client/client/include/MeasurementData.hpp
 rename client/client/include/{pinout.hpp => Pinout.hpp} (77%)
 create mode 100644 client/client/include/SensorInformation.hpp
 rename client/client/lib/dr26_analogue/{src => }/dr26.cpp (74%)
 create mode 100644 client/client/lib/dr26_analogue/dr26.hpp
 delete mode 100644 client/client/lib/dr26_analogue/src/dr26.hpp

diff --git a/client/client/include/ForteSensor.hpp b/client/client/include/ForteSensor.hpp
index 1db845d..add5a01 100644
--- a/client/client/include/ForteSensor.hpp
+++ b/client/client/include/ForteSensor.hpp
@@ -3,15 +3,15 @@
 
 #include "Message.hpp"
 #include "Protocol.hpp"
+#include "SensorInformation.hpp"
 template <class T>
-class Forte_Sensor {
+class ForteSensor {
   public:
 	virtual T readData() = 0;
 	virtual void setup() = 0;
-	virtual Message buildMessage() = 0;
-	virtual Protocol getProtocol() = 0;
-
-  private:
+	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/client/client/include/MeasurementData.hpp b/client/client/include/MeasurementData.hpp
new file mode 100644
index 0000000..9434e6a
--- /dev/null
+++ b/client/client/include/MeasurementData.hpp
@@ -0,0 +1,40 @@
+//
+// 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/client/client/include/NoDataAvailableException.hpp b/client/client/include/NoDataAvailableException.hpp
index a5de09a..83c5697 100644
--- a/client/client/include/NoDataAvailableException.hpp
+++ b/client/client/include/NoDataAvailableException.hpp
@@ -4,5 +4,5 @@
 #include <iostream>
 
 struct NoDataAvailableException : public std::exception {
-	const char *what() const throw() { return "Sensor could not read data"; }
+	const char *what() const noexcept override { return "Sensor could not read data"; }
 };
\ No newline at end of file
diff --git a/client/client/include/pinout.hpp b/client/client/include/Pinout.hpp
similarity index 77%
rename from client/client/include/pinout.hpp
rename to client/client/include/Pinout.hpp
index b80b32d..f277fd9 100644
--- a/client/client/include/pinout.hpp
+++ b/client/client/include/Pinout.hpp
@@ -2,8 +2,8 @@
 #define _FORTE_PINOUT
 
 // Pins for I2C
-#define I2C_SDA 18
-#define I2C_SCL 19
+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)
 
diff --git a/client/client/include/Protocol.hpp b/client/client/include/Protocol.hpp
index 2bcdab9..92270db 100644
--- a/client/client/include/Protocol.hpp
+++ b/client/client/include/Protocol.hpp
@@ -6,9 +6,10 @@
 #define CLIENT_PROTOCOL_HPP
 
 #include <map>
-enum Protocol { I2C, RS485, Analog };
+enum class Protocol { I2C, RS485, Analog };
 
 // protocol to string
-static std::map<Protocol, const char *> protocolToString = {{I2C, "I2C"}, {RS485, "RS485"}, {Analog, "Analog"}};
+const static std::map<Protocol, const char *> protocolToString = {
+    {Protocol::I2C, "I2C"}, {Protocol::RS485, "RS485"}, {Protocol::Analog, "ANALOG"}};
 
 #endif // CLIENT_PROTOCOL_HPP
diff --git a/client/client/include/SensorInformation.hpp b/client/client/include/SensorInformation.hpp
new file mode 100644
index 0000000..4b8af5d
--- /dev/null
+++ b/client/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/client/client/lib/dr26_analogue/src/dr26.cpp b/client/client/lib/dr26_analogue/dr26.cpp
similarity index 74%
rename from client/client/lib/dr26_analogue/src/dr26.cpp
rename to client/client/lib/dr26_analogue/dr26.cpp
index 626203d..e8d4555 100644
--- a/client/client/lib/dr26_analogue/src/dr26.cpp
+++ b/client/client/lib/dr26_analogue/dr26.cpp
@@ -1,23 +1,18 @@
 #include "dr26.hpp"
 
-static const char* TAG = "DR26";
-
-Adafruit_ADS1115 ads;
-
-void Forte_DR26 ::setup()
+void ForteDR26 ::setup()
 {
 	Wire.begin(I2C_SDA, I2C_SCL);
 	// ads.setGain(0);
-	if(ads.begin()){
-		ESP_LOGI(TAG, "ADS initialized.");
-	}
-	else{
-		ESP_LOGW(TAG, "ADS initialization failed.");
+	if (ads.begin()) {
+		ESP_LOGI(sensorInformation.getSensorName().c_str(), "ADS initialized.");
+	} else {
+		ESP_LOGW(sensorInformation.getSensorName().c_str(), "ADS initialization failed.");
 	}
 	delay(100);
 }
 
-float Forte_DR26 ::readData()
+float ForteDR26 ::readData()
 {
 	float volts = 0;
 	for (int i = 0; i < 10; i++) {
@@ -44,16 +39,16 @@ float Forte_DR26 ::readData()
 // 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 Forte_DR26 ::changeGain(adsGain_t gain)
+void ForteDR26 ::changeGain(adsGain_t gain)
 {
 	ads.setGain(gain);
 }
 
-Message Forte_DR26::buildMessage()
+std::list<Message> ForteDR26::buildMessages()
 {
 	throw "Not implemented";
 }
-Protocol Forte_DR26::getProtocol()
+SensorInformation ForteDR26::getSensorInformation() const
 {
-	return Analog;
+	return sensorInformation;
 }
diff --git a/client/client/lib/dr26_analogue/dr26.hpp b/client/client/lib/dr26_analogue/dr26.hpp
new file mode 100644
index 0000000..778f8fe
--- /dev/null
+++ b/client/client/lib/dr26_analogue/dr26.hpp
@@ -0,0 +1,24 @@
+#ifndef _DR26
+#define _DR26
+
+#include "Adafruit_ADS1X15.h"
+#include "ForteSensor.hpp"
+#include "Message.hpp"
+#include "Pinout.hpp"
+#include "esp_log.h"
+#include <Wire.h>
+
+class ForteDR26 : public ForteSensor<float> {
+  public:
+	void setup() override;
+	float readData() override;
+	void changeGain(adsGain_t gain);
+	std::list<Message> buildMessages() override;
+	[[nodiscard]] SensorInformation getSensorInformation() const override;
+
+  private:
+	Adafruit_ADS1115 ads;
+	const SensorInformation sensorInformation{"DR26", Protocol::Analog};
+};
+
+#endif
\ No newline at end of file
diff --git a/client/client/lib/dr26_analogue/src/dr26.hpp b/client/client/lib/dr26_analogue/src/dr26.hpp
deleted file mode 100644
index 9c9efa5..0000000
--- a/client/client/lib/dr26_analogue/src/dr26.hpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef _DR26
-#define _DR26
-
-#include "ForteSensor.hpp"
-#include "Message.hpp"
-#include "esp_log.h"
-#include "pinout.hpp"
-#include <Adafruit_ADS1X15.h>
-#include <Wire.h>
-
-class Forte_DR26 : public Forte_Sensor<float> {
-  public:
-	void setup() override;
-	float readData() override;
-	void changeGain(adsGain_t gain);
-	Message buildMessage() override;
-	Protocol getProtocol() override;
-
-  private:
-};
-
-#endif
\ No newline at end of file
diff --git a/client/client/lib/drs26_digital/drs26.cpp b/client/client/lib/drs26_digital/drs26.cpp
index 9e77230..5c21f3a 100644
--- a/client/client/lib/drs26_digital/drs26.cpp
+++ b/client/client/lib/drs26_digital/drs26.cpp
@@ -1,18 +1,17 @@
 #include <drs26.hpp>
 
-static const std::string TAG = "DRS26";
 /*
 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 Forte_DRS26 ::setup()
+void ForteDRS26 ::setup()
 {
 	drs26.begin(4);
 }
 
-out_data_drs26 Forte_DRS26 ::readData()
+out_data_drs26 ForteDRS26 ::readData()
 {
 	String sdiResponse = "";
 	String measurement_command =
@@ -42,14 +41,21 @@ out_data_drs26 Forte_DRS26 ::readData()
 	return data;
 }
 
-Message Forte_DRS26 ::buildMessage()
+std::list<Message> ForteDRS26 ::buildMessages()
 {
-	auto message = Message();
-	message.addData(12.12, measurementTypeToString[MeasurementType::TEMPERATURE], TAG, 4);
-	ESP_LOGE(TAG.c_str(), "test");
-	return message;
+	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;
 }
-Protocol Forte_DRS26::getProtocol()
+SensorInformation ForteDRS26::getSensorInformation() const
 {
-	return I2C;
+	return sensorInformation;
 }
diff --git a/client/client/lib/drs26_digital/drs26.hpp b/client/client/lib/drs26_digital/drs26.hpp
index 153371d..0d713ca 100644
--- a/client/client/lib/drs26_digital/drs26.hpp
+++ b/client/client/lib/drs26_digital/drs26.hpp
@@ -3,9 +3,9 @@
 
 #include "ForteSensor.hpp"
 #include "Message.hpp"
+#include "Pinout.hpp"
 #include "Wire.h"
 #include "esp_log.h"
-#include "pinout.hpp"
 #include <SDI12.h>
 #include <map>
 
@@ -15,16 +15,17 @@ struct out_data_drs26 {
 	float temperature;
 };
 
-class Forte_DRS26 : public Forte_Sensor<out_data_drs26> {
+class ForteDRS26 : public ForteSensor<out_data_drs26> {
   public:
 	void setup() override;
 	out_data_drs26 readData() override;
-	Message buildMessage() override;
-	Protocol getProtocol() 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
diff --git a/client/client/lib/espnow/src/ClientDataPackage.hpp b/client/client/lib/espnow/src/ClientDataPackage.hpp
index 727127d..2458ca6 100644
--- a/client/client/lib/espnow/src/ClientDataPackage.hpp
+++ b/client/client/lib/espnow/src/ClientDataPackage.hpp
@@ -1,43 +1,50 @@
 #pragma once
 
 #include "ArduinoJson.h"
+#include "MeasurementData.hpp"
 #include "Protocol.hpp"
+#include "SensorInformation.hpp"
 #include <list>
+#include <optional>
 #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,
 // otherwise we would have to serialize the data before sending
 class ClientDataPackage {
   private:
-	MeasurementData value;
-	std::string sensorName;
-	std::string protocol;
-	long timestamp; // maybe make this array
+	MeasurementData measurementData;
+	SensorInformation sensorInformation;
+	unsigned 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])
+	ClientDataPackage(MeasurementData value, SensorInformation sensorInformation, unsigned long timestamp)
+	    : measurementData(std::move(value)), sensorInformation(std::move(sensorInformation)), timestamp(timestamp)
 	{
 	}
 
-	std::string getDataPackageAsMinifiedJsonString()
+	[[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"] = sensorName;
+		document["sensorName"] = sensorInformation.getSensorName();
 		document["timestamp"] = timestamp;
-		document["protocol"] = protocol;
-		document["value"] = value.value;
-		document["channel"] = value.channel;
-		document["measurementType"] = value.measurementType;
+		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);
diff --git a/client/client/lib/espnow/src/Message.cpp b/client/client/lib/espnow/src/Message.cpp
index 4a23314..8c69a11 100644
--- a/client/client/lib/espnow/src/Message.cpp
+++ b/client/client/lib/espnow/src/Message.cpp
@@ -1,90 +1,42 @@
 #include "Message.hpp"
 
-static const char *TAG = "MESSAGE";
-
-void Message::addData(float value, int identifier)
-{
-	StaticJsonDocument<100> document;
-	document["value"] = value;
-	document["identifier"] = identifier;
-	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);
+#include <utility>
 
-	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());
-}
+static const char *TAG = "MESSAGE";
 
-esp_err_t Message::send()
+esp_err_t Message::send() const
 {
 	ESP_LOGI(TAG, "Sending message");
 	esp_err_t success;
 	auto messageData = getMessageAsMinifiedJsonString();
-	success = esp_now_send(recipient, (uint8_t *)&messageData, sizeof(data));
+	success = esp_now_send(recipient, (uint8_t *)&messageData, sizeof(clientDataPackage));
 	if (success != ESP_OK) {
 		// TODO REWRITE FOR JSON
-//		if (!ram_cache_is_full()) {
-//			//			ram_cache_push(messageData);
-//		}
+		//		if (!ram_cache_is_full()) {
+		//			//			ram_cache_push(messageData);
+		//		}
 	}
 	ESP_LOGD(TAG, "Sent data: %s", messageData.c_str());
 
-	std::string timestampString = data["timestamp"];
-	ESP_LOGD(TAG, "time sent: %s", timestampString.c_str());
+	ESP_LOGD(TAG, "time sent: %l", clientDataPackage.getTimestamp());
 	ESP_LOGD(TAG, "send status: %d", success);
 
 	return success;
 }
 
-StaticJsonDocument<256> Message::getData()
+std::string Message::getMessageAsMinifiedJsonString() const
 {
-	return data;
+	return clientDataPackage.getDataPackageAsMinifiedJsonString();
 }
 
-Message ::Message()
+Message::Message(ClientDataPackage data) : clientDataPackage(std::move(data))
 {
 	// check for existing host mac address, use broadcast otherwise
 	get_host_mac(recipient);
-	data["values"] = JsonArray();
-	addTimestamp();
 }
-
-std::string Message::getMessageAsMinifiedJsonString()
+Message::Message(MeasurementData const &data, const SensorInformation &information, unsigned long timestamp)
+    : clientDataPackage(data, information, timestamp)
 {
-	std::string minimizedJson;
-	serializeJson(data, minimizedJson);
-	return minimizedJson;
-}
-void Message::addTimestamp()
-{
-	// 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();
+	// check for existing host mac address, use broadcast otherwise
+	get_host_mac(recipient);
 }
diff --git a/client/client/lib/espnow/src/Message.hpp b/client/client/lib/espnow/src/Message.hpp
index 8a26ea7..3711df2 100644
--- a/client/client/lib/espnow/src/Message.hpp
+++ b/client/client/lib/espnow/src/Message.hpp
@@ -13,19 +13,14 @@
 // if more things are sent from the host the name might not be accurate anymore
 class Message {
   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();
+	explicit Message(ClientDataPackage data);
 
-	esp_err_t send();
-	StaticJsonDocument<256> getData();
-	std::string getMessageAsMinifiedJsonString();
+	Message(MeasurementData const &data, const SensorInformation &information, unsigned long timestamp);
+	esp_err_t send() const;
+	[[nodiscard]] std::string getMessageAsMinifiedJsonString() const;
 
   private:
-	StaticJsonDocument<256> data;
-	void addTimestamp();
-	//	ClientDataPackage data;
+	ClientDataPackage clientDataPackage;
 	uint8_t recipient[6]{};
 };
\ No newline at end of file
diff --git a/client/client/lib/ina219/ina219.cpp b/client/client/lib/ina219/ina219.cpp
index 5d1ff38..def6a9d 100644
--- a/client/client/lib/ina219/ina219.cpp
+++ b/client/client/lib/ina219/ina219.cpp
@@ -1,18 +1,16 @@
 #include "ina219.hpp"
 
-static const char* TAG = "INA219";
-
-void Forte_INA219 ::setup()
+void ForteINA219 ::setup()
 {
 	Wire.begin(I2C_SDA, I2C_SCL);
 	if (!ina219.init()) {
 		// Sensor init went wrong
-		ESP_LOGW(TAG, "Initialization failed");
+		ESP_LOGW(sensorInformation.getSensorName().c_str(), "Initialization failed");
 		return;
 	}
 }
 
-out_data_ina219 Forte_INA219 ::readData()
+out_data_ina219 ForteINA219 ::readData()
 {
 	if (!ina219.getOverflow()) {
 		data.shuntVoltage_mV = ina219.getShuntVoltage_mV();
@@ -27,11 +25,11 @@ out_data_ina219 Forte_INA219 ::readData()
 		return data;
 }
 
-Message Forte_INA219::buildMessage()
+std::list<Message> ForteINA219::buildMessages()
 {
 	throw "Not yet implemented";
 }
-Protocol Forte_INA219::getProtocol()
+SensorInformation ForteINA219::getSensorInformation() const
 {
-	return I2C;
+	return sensorInformation;
 }
diff --git a/client/client/lib/ina219/ina219.hpp b/client/client/lib/ina219/ina219.hpp
index cfcb01d..4a34d95 100644
--- a/client/client/lib/ina219/ina219.hpp
+++ b/client/client/lib/ina219/ina219.hpp
@@ -3,9 +3,9 @@
 
 #include "ForteSensor.hpp"
 #include "Message.hpp"
+#include "Pinout.hpp"
 #include "Wire.h"
 #include "esp_log.h"
-#include "pinout.hpp"
 #include <INA219_WE.h>
 
 struct out_data_ina219 {
@@ -17,16 +17,17 @@ struct out_data_ina219 {
 	bool ina219_overflow = false;
 };
 
-class Forte_INA219 : public Forte_Sensor<out_data_ina219> {
+class ForteINA219 : public ForteSensor<out_data_ina219> {
   public:
 	void setup() override;
 	out_data_ina219 readData() override;
-	Message buildMessage() override;
-	Protocol getProtocol() 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/client/client/lib/scd30/scd30.cpp b/client/client/lib/scd30/scd30.cpp
index eb7e743..507d815 100644
--- a/client/client/lib/scd30/scd30.cpp
+++ b/client/client/lib/scd30/scd30.cpp
@@ -1,18 +1,16 @@
 #include "scd30.hpp"
 
-static const char* TAG = "SCD30";
-
-void Forte_SCD30 ::setup()
+void ForteSCD30 ::setup()
 {
 	Wire.begin(I2C_SDA, I2C_SCL);
 	if (!airSensor.begin()) {
 		// Sensor init went wrong
-		ESP_LOGW(TAG, "Initialization failed.");
+		ESP_LOGW(sensorInformation.getSensorName().c_str(), "Initialization failed.");
 		return;
 	}
 }
 
-out_data_scd30 Forte_SCD30 ::readData()
+out_data_scd30 ForteSCD30 ::readData()
 {
 	if (airSensor.dataAvailable()) {
 		data.C02 = airSensor.getCO2();
@@ -22,14 +20,13 @@ out_data_scd30 Forte_SCD30 ::readData()
 		return data;
 	}
 	throw NoDataAvailableException();
-	// return out_data_scd30{-1, -1, -1};
 }
 
-Message Forte_SCD30::buildMessage()
+std::list<Message> ForteSCD30::buildMessages()
 {
 	throw "Not yet implemented";
 }
-Protocol Forte_SCD30::getProtocol()
+SensorInformation ForteSCD30::getSensorInformation() const
 {
-	return I2C;
+	return sensorInformation;
 }
diff --git a/client/client/lib/scd30/scd30.hpp b/client/client/lib/scd30/scd30.hpp
index a1fa290..db3e855 100644
--- a/client/client/lib/scd30/scd30.hpp
+++ b/client/client/lib/scd30/scd30.hpp
@@ -4,8 +4,8 @@
 #include "ForteSensor.hpp"
 #include "Message.hpp"
 #include "NoDataAvailableException.hpp"
+#include "Pinout.hpp"
 #include "esp_log.h"
-#include "pinout.hpp"
 #include <SparkFun_SCD30_Arduino_Library.h>
 #include <Wire.h>
 
@@ -15,16 +15,17 @@ struct out_data_scd30 {
 	float Humidity;
 };
 
-class Forte_SCD30 : public Forte_Sensor<out_data_scd30> {
+class ForteSCD30 : public ForteSensor<out_data_scd30> {
   public:
 	void setup() override;
 	out_data_scd30 readData() override;
-	Message buildMessage() override;
-	Protocol getProtocol() 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/client/client/platformio.ini b/client/client/platformio.ini
index a28a589..28cc58c 100644
--- a/client/client/platformio.ini
+++ b/client/client/platformio.ini
@@ -13,10 +13,14 @@ 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
-lib_deps = 
+	-std=gnu++17
+build_unflags = -std=gnu++11
+lib_deps =
 	sparkfun/SparkFun SCD30 Arduino Library@^1.0.18
 	Wire
 	adafruit/Adafruit ADS1X15@^2.4.0
diff --git a/client/client/src/main.cpp b/client/client/src/main.cpp
index fe98c19..77265a5 100644
--- a/client/client/src/main.cpp
+++ b/client/client/src/main.cpp
@@ -1,14 +1,14 @@
+#include "../lib/dr26_analogue/dr26.hpp"
 #include "NoDataAvailableException.hpp"
 #include "esp_log.h"
 #include <Arduino.h>
-#include <dr26.hpp>
 #include <drs26.hpp>
 #include <ina219.hpp>
 #include <scd30.hpp>
 // #include "esp32-hal-log.h"
-static const char *TAG = "MAIN";
+static const std::string TAG = "MAIN";
 
-Forte_DRS26 drs26;
+ForteDRS26 drs26;
 
 void setup()
 {
@@ -25,13 +25,17 @@ void loop()
 	try {
 		espnow_setup();
 		//			data = drs26.readData();
-		auto message = drs26.buildMessage();
-		message.send();
+		auto messages = drs26.buildMessages();
+
+		for (const Message &message : messages) {
+			message.send();
+		}
+
 	} catch (const NoDataAvailableException &e) {
 		std::cerr << e.what() << '\n';
 	}
 
-	ESP_LOGE(TAG, "Sensor Circumference: ");
+	ESP_LOGE(TAG.c_str(), "Sensor Circumference: ");
 	//	log_e("Temperature: ");
 	//	log_e("Id: ");
 
diff --git a/client/client/test/TestClientDataPackage.cpp b/client/client/test/TestClientDataPackage.cpp
index bae42a2..eea536c 100644
--- a/client/client/test/TestClientDataPackage.cpp
+++ b/client/client/test/TestClientDataPackage.cpp
@@ -3,17 +3,44 @@
 //
 
 #include "TestClientDataPackage.hpp"
+#include "MeasurementData.hpp"
 #include "Protocol.hpp"
 #include <vector>
 
 void test_export_to_json()
 {
-	ClientDataPackage dataPackage = ClientDataPackage(MeasurementData{1.1, 0, "TEMPERATURE"}, "DRS26", 0, Analog);
+	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"})";
+	    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/client/client/test/TestClientDataPackage.hpp b/client/client/test/TestClientDataPackage.hpp
index 74a7b90..fa5f203 100644
--- a/client/client/test/TestClientDataPackage.hpp
+++ b/client/client/test/TestClientDataPackage.hpp
@@ -10,5 +10,7 @@
 #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/client/client/test/main.cpp b/client/client/test/main.cpp
index b4aedce..5ad5f3f 100644
--- a/client/client/test/main.cpp
+++ b/client/client/test/main.cpp
@@ -10,6 +10,8 @@ void setup()
 	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();
 }
 
-- 
GitLab