diff --git a/client/ESPcam/.idea/misc.xml b/client/ESPcam/.idea/misc.xml
index 79b3c94830bab93d40d0770f2765540fe24ed423..6e1c9f37b93d78b6c09407d34dc9e55175665cd7 100644
--- a/client/ESPcam/.idea/misc.xml
+++ b/client/ESPcam/.idea/misc.xml
@@ -1,4 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
-  <component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
+  <component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$">
+    <contentRoot DIR="$PROJECT_DIR$/.." />
+  </component>
 </project>
\ No newline at end of file
diff --git a/client/ESPcam/CMakeListsPrivate.txt b/client/ESPcam/CMakeListsPrivate.txt
index 1031c7cce53c3431dd7caa12d100c935a5bd749b..2c27268f2f0e34564668c2926a94775303a907e8 100644
--- a/client/ESPcam/CMakeListsPrivate.txt
+++ b/client/ESPcam/CMakeListsPrivate.txt
@@ -21,7 +21,7 @@ SET(CMAKE_C_STANDARD 99)
 set(CMAKE_CXX_STANDARD 17)
 
 if (CMAKE_BUILD_TYPE MATCHES "esp32cam")
-    add_definitions(-DPLATFORMIO=60104)
+    add_definitions(-DPLATFORMIO=60105)
     add_definitions(-DARDUINO_ESP32_DEV)
     add_definitions(-DBOARD_HAS_PSRAM)
     add_definitions(-DCORE_DEBUG_LEVEL=5)
@@ -247,10 +247,14 @@ if (CMAKE_BUILD_TYPE MATCHES "esp32cam")
     include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/dio_qspi/include")
     include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/cores/esp32")
     include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/variants/esp32")
+    include_directories("$ENV{HOME}/GitRepos/sensor-system/client/libs/.idea")
+    include_directories("$ENV{HOME}/GitRepos/sensor-system/client/libs/LC7090203F")
+    include_directories("$ENV{HOME}/GitRepos/sensor-system/client/libs/SentecSensors")
     include_directories("$ENV{HOME}/GitRepos/sensor-system/client/libs/deep_sleep")
     include_directories("$ENV{HOME}/GitRepos/sensor-system/client/libs/dr26_analogue")
     include_directories("$ENV{HOME}/GitRepos/sensor-system/client/libs/drs26_digital")
     include_directories("$ENV{HOME}/GitRepos/sensor-system/client/libs/ina219")
+    include_directories("$ENV{HOME}/GitRepos/sensor-system/client/libs/mock_sensor")
     include_directories("$ENV{HOME}/GitRepos/sensor-system/client/libs/rs485")
     include_directories("$ENV{HOME}/GitRepos/sensor-system/client/libs/scd30")
     include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/ArduinoOTA/src")
diff --git a/client/ESPcam/platformio.ini b/client/ESPcam/platformio.ini
index 0573bea475a110f93b65a2554d555f39a127b16c..835183a1a921563ea8720791c13a22e3cdafd9dd 100644
--- a/client/ESPcam/platformio.ini
+++ b/client/ESPcam/platformio.ini
@@ -15,11 +15,12 @@ framework = arduino
 monitor_speed = 115200
 lib_ldf_mode = deep
 lib_extra_dirs =
-    ../libs
+  ../libs
+  ../../shared-libs
 build_flags =
-    -I include
-    -DCORE_DEBUG_LEVEL=5
-    -std=gnu++17
+  -I include
+  -DCORE_DEBUG_LEVEL=5
+  -std=gnu++17
 build_unflags = -std=gnu++11
 lib_deps = sensirion/arduino-sht@^1.2.2
            adafruit/RTClib @^2.1.1
diff --git a/client/client_central_mast/platformio.ini b/client/client_central_mast/platformio.ini
index 0f778714c620418858a06af712025c04d4221c05..a75dccb356b65c764d38b5ff2a0c795fb0d42045 100644
--- a/client/client_central_mast/platformio.ini
+++ b/client/client_central_mast/platformio.ini
@@ -15,28 +15,29 @@ framework = arduino
 monitor_speed = 115200
 lib_ldf_mode = deep
 lib_extra_dirs =
-    ../libs
+  ../libs
+  ../../shared-libs
 ; 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
+  -I include
+  -DCORE_DEBUG_LEVEL=5
+  -std=gnu++17
 build_unflags = -std=gnu++11
 monitor_port = /dev/ttyUSB0
 upload_port = /dev/ttyUSB0
 lib_deps =
-    Wire
-    adafruit/Adafruit ADS1X15@^2.4.0
-    wollewald/INA219_WE@^1.3.1
-    adafruit/Adafruit BusIO@^1.13.2
-    Adafruit_I2CDevice
-    SPI
-    fbiego/ESP32Time@^2.0.0
-    bblanchon/ArduinoJson@^6.19.4
-    4-20ma/ModbusMaster@^2.0.1
-    adafruit/RTClib@^2.1.1
-    sensirion/arduino-sht@^1.2.2
-    robtillaart/SHT85@^0.3.2
-    fbiego/ESP32Time@^2.0.0
-    bblanchon/ArduinoJson@^6.19.4
+  Wire
+  adafruit/Adafruit ADS1X15@^2.4.0
+  wollewald/INA219_WE@^1.3.1
+  adafruit/Adafruit BusIO@^1.13.2
+  Adafruit_I2CDevice
+  SPI
+  fbiego/ESP32Time@^2.0.0
+  bblanchon/ArduinoJson@^6.19.4
+  4-20ma/ModbusMaster@^2.0.1
+  adafruit/RTClib@^2.1.1
+  sensirion/arduino-sht@^1.2.2
+  robtillaart/SHT85@^0.3.2
+  fbiego/ESP32Time@^2.0.0
+  bblanchon/ArduinoJson@^6.19.4
diff --git a/client/client_central_mast/test/TestClientDataPackage.cpp b/client/client_central_mast/test/TestClientDataPackage.cpp
index eea536cfbc63f7c6dc9797d8288a5887c384aa0c..694eec4dc26fab1041fa9c083963b694ee83cfe7 100644
--- a/client/client_central_mast/test/TestClientDataPackage.cpp
+++ b/client/client_central_mast/test/TestClientDataPackage.cpp
@@ -3,7 +3,7 @@
 //
 
 #include "TestClientDataPackage.hpp"
-#include "MeasurementData.hpp"
+#include "Measurement.hpp"
 #include "Protocol.hpp"
 #include <vector>
 
diff --git a/client/client_mock/platformio.ini b/client/client_mock/platformio.ini
index b7c388a5d2b4fd93dd5ddb27969ebd259d807847..817104fcf3a217a02f4eb028b7387da79fd71548 100644
--- a/client/client_mock/platformio.ini
+++ b/client/client_mock/platformio.ini
@@ -4,8 +4,10 @@ board = esp32dev
 framework = arduino
 monitor_speed = 115200
 lib_ldf_mode = deep
+upload_port = /dev/ttyUSB0
 lib_extra_dirs =
     ../libs
+    ../../shared-libs
 ; 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 =
diff --git a/client/client_mock/src/main.cpp b/client/client_mock/src/main.cpp
index 4e322c5fd2aa7baf9d260b3d8a8f760327b17038..bf5af15f103b2311f1f352fd526302cc24610a26 100644
--- a/client/client_mock/src/main.cpp
+++ b/client/client_mock/src/main.cpp
@@ -3,6 +3,8 @@
 #include "NoDataAvailableException.hpp"
 #include "f_deep_sleep.hpp"
 #include <Arduino.h>
+#include <ClientDataPackage.hpp>
+#include <soc/rtc_cntl_reg.h>
 
 
 static const char *TAG = "MAIN";
@@ -34,20 +36,15 @@ void send_msgs(const std::__cxx11::list<Message> msgs) {
 
 // one loop takes ~2200 ms
 void setup() {
+    // disable brownout
+//    WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
     unsigned long ts = millis();
     Serial.begin(115200);
-    // Set the GPIO which conrtols the step up to OUTPUT
-    gpio_set_direction(GPIO_NUM_32, GPIO_MODE_OUTPUT);
-
-    // blinking led for debug
-    // gpio_set_direction(GPIO_NUM_17, GPIO_MODE_OUTPUT);
-    // gpio_set_level(GPIO_NUM_17, 1);
 
     DeepSleep::print_wakeup_reason();
     DeepSleep::bootCount++;
     ESP_LOGD(TAG, "Boot number: %d", DeepSleep::bootCount);
 
-    gpio_set_level(GPIO_NUM_32, 1);
     // delay(100);
     mock_channel0.setup();
     mock_channel1.setup();
@@ -59,42 +56,86 @@ void setup() {
     mock_channel2.setChannel(2);
     mock_channel3.setChannel(3);
 
-    ESP_LOGD(TAG, "Setup took %ld ms", millis() - ts);
+  // disable led
+  gpio_set_direction(GPIO_NUM_32, GPIO_MODE_OUTPUT);
 
-    try {
-        // FIXME: put me into seperate trys? No data will be sent when 1 exception occurs
+  ESP_LOGD(TAG, "Setup took %ld ms", millis() - ts);
 
+  try {
+      // FIXME: put me into seperate trys? No data will be sent when 1 exception occurs
         ts = millis();
         auto messages0 = mock_channel0.buildMessages();
         auto messages1 = mock_channel1.buildMessages();
         auto messages2 = mock_channel2.buildMessages();
         auto messages3 = mock_channel3.buildMessages();
+
         // roughly takes 500ms, ~120ms for each adc channel, barely anything for battery monitor
-        ESP_LOGD(TAG, "Reading data and building messages took %ld ms", millis() - ts);
+        ESP_LOGD(TAG,
+                 "Reading data and building messages took %ld ms",
+                 millis() - ts);
         gpio_set_level(GPIO_NUM_32, 0);
 
+        ESP_LOGD(TAG, "Size of message to be sent: %d", sizeof(messages0.front()));
+        ESP_LOGD(TAG, "Size of Message class: %d", sizeof(Message));
+        ESP_LOGD(TAG,
+                 "Size of ClientDataPackage class: %d",
+                 sizeof(ClientDataPackage));
+        // sizeof string
+        ESP_LOGD(TAG, "Size of string: %d", sizeof(std::string));
+        // sizeof string with 5 char
+        ESP_LOGD(TAG, "Size of string with 5 char: %d", sizeof(char[5]));
+        // sizeof optional int
+        ESP_LOGD(TAG, "Size of optional int: %d", sizeof(std::optional<int>));
+        // sizeof int
+        ESP_LOGD(TAG, "Size of int: %d", sizeof(int));
+        // sizeof short
+        ESP_LOGD(TAG, "Size of short: %d", sizeof(short));
+        // sizeof double
+        ESP_LOGD(TAG, "Size of double: %d", sizeof(double));
+        // sizeof float
+        ESP_LOGD(TAG, "Size of float: %d", sizeof(float));
+        // list of 5 compresseddatapackage
+        ClientDataPackage compresseddatapackage{};
+        ESP_LOGD(TAG,
+                 "Size of list of 4 ClientDataPackage: %d",
+                 sizeof(std::list<ClientDataPackage>)
+                 + (sizeof(ClientDataPackage) * 4));
+        // sizeof compresseddatapackage
+        ESP_LOGD(TAG,
+                 "Size of ClientDataPackage: %d",
+                 sizeof(ClientDataPackage));
+        // sizeof list
+        ESP_LOGD(TAG, "Size of list: %d", sizeof(std::list<ClientDataPackage>));
+        // sizeof vector
+        ESP_LOGD(TAG,
+                 "Size of vector: %d",
+                 sizeof(std::vector<ClientDataPackage>));
+
         // FIXME: put this outside the try loop?
         ts = millis();
         espnow_setup();
         ESP_LOGD(TAG, "EPSNow setup took %ld ms", millis() - ts);
+        // make a list of messages
+        std::array<Message, 6> messages =
+                {messages0.front(), messages1.front(), messages2.front(),
+                 Message::nullMessage(), Message::nullMessage(),
+                 Message::nullMessage()};
+
+        // print messages
+        for (const Message &msg: messages) {
+            ESP_LOGD(TAG, "Message: %s", msg.getMessageAsMinifiedJsonString().c_str());
+        }
+
         ts = millis();
-        send_msgs(messages0);
-        send_msgs(messages1);
-        send_msgs(messages2);
-        send_msgs(messages3);
-        // roughly takes 3s in ideal conditions
+        Message::sendMessages(messages);
         ESP_LOGD(TAG, "Sending messages took %ld ms", millis() - ts);
 
     } catch (const NoDataAvailableException &e) {
         std::cerr << e.what() << '\n';
     }
-    // just to be safe in case exception happens above
-    gpio_set_level(GPIO_NUM_32, 0);
-    // keep it in deep sleep
-    gpio_hold_en((gpio_num_t) GPIO_NUM_32);
 
     // battery protection: go to deep sleep for unlimited time when voltage less than 3.2V
-    DeepSleep::deep_sleep(20);
+    DeepSleep::deep_sleep(5);
 
 }
 
diff --git a/client/client_satellite/platformio.ini b/client/client_satellite/platformio.ini
index b7c388a5d2b4fd93dd5ddb27969ebd259d807847..1a9a18984b3f34f3cba2b6d992ddf9eb49f61e74 100644
--- a/client/client_satellite/platformio.ini
+++ b/client/client_satellite/platformio.ini
@@ -6,6 +6,7 @@ monitor_speed = 115200
 lib_ldf_mode = deep
 lib_extra_dirs =
     ../libs
+    ../../shared-libs
 ; 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 =
diff --git a/client/client_satellite/test/TestClientDataPackage.cpp b/client/client_satellite/test/TestClientDataPackage.cpp
index eea536cfbc63f7c6dc9797d8288a5887c384aa0c..694eec4dc26fab1041fa9c083963b694ee83cfe7 100644
--- a/client/client_satellite/test/TestClientDataPackage.cpp
+++ b/client/client_satellite/test/TestClientDataPackage.cpp
@@ -3,7 +3,7 @@
 //
 
 #include "TestClientDataPackage.hpp"
-#include "MeasurementData.hpp"
+#include "Measurement.hpp"
 #include "Protocol.hpp"
 #include <vector>
 
diff --git a/client/libs/LC7090203F/LC709203F.cpp b/client/libs/LC7090203F/LC709203F.cpp
index 037130060b547c019b1ba30e8769f9d52c3f51e0..b182f1378cc7fecc15369c716322d3c732093d23 100644
--- a/client/libs/LC7090203F/LC709203F.cpp
+++ b/client/libs/LC7090203F/LC709203F.cpp
@@ -39,13 +39,13 @@ uint8_t i2c_address = LC709203F_I2C_ADDR;
  *    @return True if initialization was successful, otherwise false.
  */
 bool LC709203F::begin(void) {
-    Wire.begin();
-    setPowerMode(LC709203F_POWER_OPERATE);
-    setCellCapacity(LC709203F_APA_1000MAH);
-    setTemperatureMode(LC709203F_TEMPERATURE_I2C);
-    setCellProfile(LC709203_NOM3p7_Charge4p2);
+  Wire.begin();
+  setPowerMode(LC709203F_POWER_OPERATE);
+  setCellCapacity(LC709203F_APA_1000MAH);
+  setTemperatureMode(LC709203F_TEMPERATURE_I2C);
+  setCellProfile(LC709203_NOM3p7_Charge4p2);
 
-    return true;
+  return true;
 }
 
 
@@ -54,9 +54,9 @@ bool LC709203F::begin(void) {
  *    @return 16-bit value read from LC709203F_RO_ICVERSION registers
  */
 uint16_t LC709203F::getICversion(void) {
-    uint16_t vers = 0;
-    vers = read16(LC709203F_RO_ICVERSION);
-    return vers;
+  uint16_t vers = 0;
+  vers = read16(LC709203F_RO_ICVERSION);
+  return vers;
 }
 
 
@@ -65,7 +65,7 @@ uint16_t LC709203F::getICversion(void) {
  *    @return
  */
 void LC709203F::initRSOC(void) {
-    write16(LC709203F_WO_INITRSOC, 0xAA55);
+  write16(LC709203F_WO_INITRSOC, 0xAA55);
 }
 
 
@@ -74,9 +74,9 @@ void LC709203F::initRSOC(void) {
  *    @return Cell voltage in milliVolt
  */
 uint16_t LC709203F::cellVoltage_mV(void) {
-    uint16_t mV = 0;
-    mV = read16(LC709203F_RO_CELLVOLTAGE);
-    return 1000 * (mV / 1000.0);
+  uint16_t mV = 0;
+  mV = read16(LC709203F_RO_CELLVOLTAGE);
+  return 1000 * (mV / 1000.0);
 }
 
 
@@ -85,9 +85,9 @@ uint16_t LC709203F::cellVoltage_mV(void) {
  *    @return point value from 0 to 1000
  */
 uint16_t LC709203F::cellRemainingPercent10(void) {
-    uint16_t percent = 0;
-    percent = read16(LC709203F_RO_ITE);
-    return percent;
+  uint16_t percent = 0;
+  percent = read16(LC709203F_RO_ITE);
+  return percent;
 }
 
 /*!
@@ -95,9 +95,9 @@ uint16_t LC709203F::cellRemainingPercent10(void) {
  *    @return point value from 0 to 100
  */
 uint16_t LC709203F::cellStateOfCharge(void) {
-    uint16_t percent = 0;
-    percent = read16(LC709203F_RW_RSOC);
-    return percent;
+  uint16_t percent = 0;
+  percent = read16(LC709203F_RW_RSOC);
+  return percent;
 }
 
 
@@ -106,9 +106,9 @@ uint16_t LC709203F::cellStateOfCharge(void) {
  *    @return value from -20 to 60 *C  // CdB Needs testing, no thermistor on ESP32_Bat_R2 board
  */
 uint16_t LC709203F::getCellTemperature(void) {
-    uint16_t temp = 0;
-    temp = read16(LC709203F_RW_CELLTEMPERATURE);
-    return temp;
+  uint16_t temp = 0;
+  temp = read16(LC709203F_RW_CELLTEMPERATURE);
+  return temp;
 }
 
 
@@ -118,7 +118,7 @@ uint16_t LC709203F::getCellTemperature(void) {
  * LC709203F_TEMPERATURE_THERMISTOR
  */
 void LC709203F::setTemperatureMode(lc709203_tempmode_t t) {
-    return write16(LC709203F_RW_STATUSBIT, (uint16_t) t);
+  return write16(LC709203F_RW_STATUSBIT, (uint16_t) t);
 }
 
 
@@ -127,7 +127,7 @@ void LC709203F::setTemperatureMode(lc709203_tempmode_t t) {
  *    @param apa The lc709203_adjustment_t enumerated approximate cell capacity
  */
 void LC709203F::setCellCapacity(lc709203_adjustment_t apa) {
-    write16(LC709203F_RW_APA, (uint16_t) apa);
+  write16(LC709203F_RW_APA, (uint16_t) apa);
 }
 
 
@@ -136,7 +136,7 @@ void LC709203F::setCellCapacity(lc709203_adjustment_t apa) {
  *    @param percent The threshold value, set to 0 to disable alarm
  */
 void LC709203F::setAlarmRSOC(uint8_t percent) {
-    write16(LC709203F_RW_ALARMRSOC, percent);
+  write16(LC709203F_RW_ALARMRSOC, percent);
 }
 
 
@@ -145,7 +145,7 @@ void LC709203F::setAlarmRSOC(uint8_t percent) {
  *    @param voltage The threshold value, set to 0 to disable alarm
  */
 void LC709203F::setAlarmVoltage(float voltage) {
-    write16(LC709203F_RW_ALARMVOLT, voltage * 1000);
+  write16(LC709203F_RW_ALARMVOLT, voltage * 1000);
 }
 
 
@@ -156,7 +156,7 @@ void LC709203F::setAlarmVoltage(float voltage) {
  *    @return 
  */
 void LC709203F::setPowerMode(lc709203_powermode_t t) {
-    write16(LC709203F_RW_POWERMODE, (uint16_t) t);
+  write16(LC709203F_RW_POWERMODE, (uint16_t) t);
 }
 
 /*!
@@ -165,7 +165,7 @@ void LC709203F::setPowerMode(lc709203_powermode_t t) {
  *    @return
  */
 void LC709203F::setCellProfile(lc709203_cell_profile_t t) {
-    write16(LC709203F_RW_PROFILE, (uint16_t) t);
+  write16(LC709203F_RW_PROFILE, (uint16_t) t);
 }
 
 /*!
@@ -173,9 +173,9 @@ void LC709203F::setCellProfile(lc709203_cell_profile_t t) {
  *    @return The uint16_t Beta value
  */
 uint16_t LC709203F::getThermistorBeta(void) {
-    uint16_t val = 0;
-    val = read16(LC709203F_RW_THERMISTORB);
-    return val;
+  uint16_t val = 0;
+  val = read16(LC709203F_RW_THERMISTORB);
+  return val;
 }
 
 
@@ -185,17 +185,19 @@ uint16_t LC709203F::getThermistorBeta(void) {
  *    @return 
  */
 void LC709203F::setThermistorB(uint16_t beta) {
-    write16(LC709203F_RW_THERMISTORB, beta);
+  write16(LC709203F_RW_THERMISTORB, beta);
 }
 
 
 std::list<Message> LC709203F::buildMessages() {
-    std::list<Message> messages;
-    float data = cellVoltage_mV() / 1000.0;
-    MeasurementData IncrementData{data, 0, {},
-                                  measurementTypeToString.at(MeasurementType::BATTERY_VOLTAGE)};
-    messages.emplace_back(IncrementData, sensorInformation, Time::getInstance().getEpochSeconds());
-    return messages;
+  std::list<Message> messages;
+  float data = cellVoltage_mV() / 1000.0;
+  Measurement IncrementData{data, 0, NO_I2C_ADDRESS, MeasurementType::BATTERY_VOLTAGE,
+                            ErrorType::DATA_OK};
+  messages.emplace_back(IncrementData,
+                        sensorInformation,
+                        Time::getInstance().getEpochSeconds());
+  return messages;
 }
 
 
@@ -216,52 +218,52 @@ std::list<Message> LC709203F::buildMessages() {
  * @return The computed CRC8 value.
  */
 static uint8_t crc8(uint8_t *data, int len) {
-    const uint8_t POLYNOMIAL(0x07);
-    uint8_t crc(0x00);
+  const uint8_t POLYNOMIAL(0x07);
+  uint8_t crc(0x00);
 
-    for (int j = len; j; --j) {
-        crc ^= *data++;
+  for (int j = len; j; --j) {
+    crc ^= *data++;
 
-        for (int i = 8; i; --i) {
-            crc = (crc & 0x80) ? (crc << 1) ^ POLYNOMIAL : (crc << 1);
-        }
+    for (int i = 8; i; --i) {
+      crc = (crc & 0x80) ? (crc << 1) ^ POLYNOMIAL : (crc << 1);
     }
-    return crc;
+  }
+  return crc;
 }
 
 
 // writes a 16-bit word (d) to register pointer regAddress
 // when selecting a register pointer to read from, data = 0
 void LC709203F::write16(uint8_t regAddress, uint16_t data) {
-    // Setup array to hold bytes to send including CRC-8
-    uint8_t crcArray[5];
-    crcArray[0] = 0x16;
-    crcArray[1] = regAddress;
-    crcArray[2] = lowByte(data);
-    crcArray[3] = highByte(data);
-    // Calculate crc of preceding four bytes and place in crcArray[4]
-    crcArray[4] = crc8(crcArray, 4);
-    // Device address
-    Wire.beginTransmission(i2c_address);
-    // Register address
-    Wire.write(regAddress);
-    // low byte
-    Wire.write(crcArray[2]);
-    // high byte
-    Wire.write(crcArray[3]);
-    // Send crc8
-    Wire.write(crcArray[4]);
-    Wire.endTransmission();
+  // Setup array to hold bytes to send including CRC-8
+  uint8_t crcArray[5];
+  crcArray[0] = 0x16;
+  crcArray[1] = regAddress;
+  crcArray[2] = lowByte(data);
+  crcArray[3] = highByte(data);
+  // Calculate crc of preceding four bytes and place in crcArray[4]
+  crcArray[4] = crc8(crcArray, 4);
+  // Device address
+  Wire.beginTransmission(i2c_address);
+  // Register address
+  Wire.write(regAddress);
+  // low byte
+  Wire.write(crcArray[2]);
+  // high byte
+  Wire.write(crcArray[3]);
+  // Send crc8
+  Wire.write(crcArray[4]);
+  Wire.endTransmission();
 }
 
 int16_t LC709203F::read16(uint8_t regAddress) {
-    int16_t data = 0;
-    Wire.beginTransmission(i2c_address);
-    Wire.write(regAddress);
-    Wire.endTransmission(false);
-    Wire.requestFrom(i2c_address, static_cast<uint8_t>(2));
-    uint8_t lowByteData = Wire.read();
-    uint8_t highByteData = Wire.read();
-    data = word(highByteData, lowByteData);
-    return (data);
+  int16_t data = 0;
+  Wire.beginTransmission(i2c_address);
+  Wire.write(regAddress);
+  Wire.endTransmission(false);
+  Wire.requestFrom(i2c_address, static_cast<uint8_t>(2));
+  uint8_t lowByteData = Wire.read();
+  uint8_t highByteData = Wire.read();
+  data = word(highByteData, lowByteData);
+  return (data);
 }
diff --git a/client/libs/LC7090203F/LC709203F.h b/client/libs/LC7090203F/LC709203F.h
index 75ed26c319f43810ea13e331a9b28854d3611081..d2624df882e6d55bbd50ac9543232ff6af54883c 100644
--- a/client/libs/LC7090203F/LC709203F.h
+++ b/client/libs/LC7090203F/LC709203F.h
@@ -40,33 +40,33 @@ static uint8_t crc8(uint8_t *data, int len);
 
 /*!  Approx cell capacity Table 7 */
 typedef enum {
-    LC709203F_APA_100MAH = 0x08,
-    LC709203F_APA_200MAH = 0x0B,
-    LC709203F_APA_500MAH = 0x10,
-    LC709203F_APA_1000MAH = 0x19,
-    LC709203F_APA_2000MAH = 0x2D,
-    LC709203F_APA_3000MAH = 0x36,
+  LC709203F_APA_100MAH = 0x08,
+  LC709203F_APA_200MAH = 0x0B,
+  LC709203F_APA_500MAH = 0x10,
+  LC709203F_APA_1000MAH = 0x19,
+  LC709203F_APA_2000MAH = 0x2D,
+  LC709203F_APA_3000MAH = 0x36,
 } lc709203_adjustment_t;
 
 /*!  Cell profile */
 typedef enum {
-    LC709203_NOM3p7_Charge4p2 = 1,
-    LC709203_NOM3p8_Charge4p35 = 3,
-    LC709203_NOM3p8_Charge4p35_Less500mAh = 6,
-    LC709203_ICR18650_SAMSUNG = 5,
-    LC709203_ICR18650_PANASONIC = 4
+  LC709203_NOM3p7_Charge4p2 = 1,
+  LC709203_NOM3p8_Charge4p35 = 3,
+  LC709203_NOM3p8_Charge4p35_Less500mAh = 6,
+  LC709203_ICR18650_SAMSUNG = 5,
+  LC709203_ICR18650_PANASONIC = 4
 } lc709203_cell_profile_t;
 
 /*!  Cell temperature source */
 typedef enum {
-    LC709203F_TEMPERATURE_I2C = 0x0000,
-    LC709203F_TEMPERATURE_THERMISTOR = 0x0001,
+  LC709203F_TEMPERATURE_I2C = 0x0000,
+  LC709203F_TEMPERATURE_THERMISTOR = 0x0001,
 } lc709203_tempmode_t;
 
 /*!  Chip power state */
 typedef enum {
-    LC709203F_POWER_OPERATE = 0x0001,
-    LC709203F_POWER_SLEEP = 0x0002,
+  LC709203F_POWER_OPERATE = 0x0001,
+  LC709203F_POWER_SLEEP = 0x0002,
 } lc709203_powermode_t;
 
 /*!
@@ -74,57 +74,55 @@ typedef enum {
  *            the LC709203F I2C LiPo monitor
  */
 class LC709203F {
-public:
-    LC709203F();
+    // FIXME: This does not conform to FORTE's interface
 
-    ~LC709203F();
+ public:
+  LC709203F();
 
-    bool begin(void);
+  ~LC709203F();
 
-    void initRSOC(void);
+  bool begin(void);
 
-    void setPowerMode(lc709203_powermode_t t);
+  void initRSOC(void);
 
-    void setCellCapacity(lc709203_adjustment_t apa);
+  void setPowerMode(lc709203_powermode_t t);
 
-    void setCellProfile(lc709203_cell_profile_t t);
+  void setCellCapacity(lc709203_adjustment_t apa);
 
-    uint16_t getICversion(void);
+  void setCellProfile(lc709203_cell_profile_t t);
 
-    uint16_t cellVoltage_mV(void);
+  uint16_t getICversion(void);
 
-    uint16_t cellRemainingPercent10(void);    // Remaining capacity in increments of 0.1% as integer
-    uint16_t cellStateOfCharge(void);                // In increments of 1% as integer
+  uint16_t cellVoltage_mV(void);
 
+  uint16_t
+  cellRemainingPercent10(void);    // Remaining capacity in increments of 0.1% as integer
+  uint16_t
+  cellStateOfCharge(void);                // In increments of 1% as integer
 
-    uint16_t getThermistorBeta(void);
 
-    void setThermistorB(uint16_t beta);
+  uint16_t getThermistorBeta(void);
 
-    void setTemperatureMode(lc709203_tempmode_t t);
+  void setThermistorB(uint16_t beta);
 
-    uint16_t getCellTemperature(void);
+  void setTemperatureMode(lc709203_tempmode_t t);
 
-    void setAlarmRSOC(uint8_t percent);
+  uint16_t getCellTemperature(void);
 
-    void setAlarmVoltage(float voltage);
+  void setAlarmRSOC(uint8_t percent);
 
-    std::list<Message> buildMessages();
+  void setAlarmVoltage(float voltage);
 
-protected:
-    void write16(uint8_t regAddress, uint16_t data);
+  std::list<Message> buildMessages();
 
-    int16_t read16(uint8_t regAddress);
+ protected:
+  void write16(uint8_t regAddress, uint16_t data);
 
-private:
-    const SensorInformation sensorInformation{"LC709203", Protocol::I2C};
+  int16_t read16(uint8_t regAddress);
 
-    enum class MeasurementType {
-        BATTERY_VOLTAGE,
-    };
-
-    std::map<MeasurementType, const char *> measurementTypeToString = {
-            {MeasurementType::BATTERY_VOLTAGE, "BATTERY_VOLTAGE"}};
+ private:
+  const SensorInformation
+      sensorInformation{HardwareName::LC709203, SensorProtocol::I2C};
 };
 
 #endif
diff --git a/client/libs/SentecSensors/SentecSensors.cpp b/client/libs/SentecSensors/SentecSensors.cpp
index 91c60c148c88cdaa612857e426ef9d611e8ebcc0..4029f3dcd049c916a852f92f2cc6ca279d015e59 100644
--- a/client/libs/SentecSensors/SentecSensors.cpp
+++ b/client/libs/SentecSensors/SentecSensors.cpp
@@ -1,345 +1,324 @@
 #include "NoDataAvailableException.hpp"
 #include <SentecSensors.h>
+
 /***************************************
  *          RS485 SENSOR READOUT
  ****************************************/
 static const char *TAG = "SENTEC";
-SentecSensorRS485::SentecSensorRS485(HardwareSerial *ser, byte add)
-{
-	address = add;
-	RS485 = ser;
+
+SentecSensorRS485::SentecSensorRS485(HardwareSerial *ser, byte add) {
+    address = add;
+    RS485 = ser;
 }
-SentecSensorRS485::SentecSensorRS485(HardwareSerial *ser, byte add, uint8_t serialControlPin)
-{
-	address = add;
-	RS485 = ser;
-	serialCommunicationControlPin = serialControlPin;
+
+SentecSensorRS485::SentecSensorRS485(HardwareSerial *ser, byte add, uint8_t serialControlPin) {
+    address = add;
+    RS485 = ser;
+    serialCommunicationControlPin = serialControlPin;
 }
 
-void SentecSensorRS485::write(byte queryFrame[], int length)
-{
-	// sends a message (bytes) to the sensor
-
-	// Initialize the transmitter
-	digitalWrite(serialCommunicationControlPin, HIGH);
-	// Send message: request a reading from the sensor
-	RS485->write(queryFrame, length);
-	RS485->flush();
-	// Initialize the receiver
-	digitalWrite(serialCommunicationControlPin, LOW);
+void SentecSensorRS485::write(byte queryFrame[], int length) {
+    // sends a message (bytes) to the sensor
+
+    // Initialize the transmitter
+    digitalWrite(serialCommunicationControlPin, HIGH);
+    // Send message: request a reading from the sensor
+    RS485->write(queryFrame, length);
+    RS485->flush();
+    // Initialize the receiver
+    digitalWrite(serialCommunicationControlPin, LOW);
 }
 
-String SentecSensorRS485::getValueStr(float value)
-{
-	if (valid) {
-		return String(value, 1);
-	} else {
-		return String("null");
-	}
+String SentecSensorRS485::getValueStr(float value) {
+    if (valid) {
+        return String(value, 1);
+    } else {
+        return String("null");
+    }
 }
 
-String SentecSensorRS485::getValueStr(int value)
-{
-	if (valid) {
-		return String(value);
-	} else {
-		return String("null");
-	}
+String SentecSensorRS485::getValueStr(int value) {
+    if (valid) {
+        return String(value);
+    } else {
+        return String("null");
+    }
 }
 
-SentecSensorRS485::ReturnCode SentecSensorRS485::queryAddress()
-{
-	// request the address of the sensor with ONLY ONE SENSOR ON THE BUS
+ErrorType SentecSensorRS485::queryAddress() {
+    // request the address of the sensor with ONLY ONE SENSOR ON THE BUS
 
-	byte tmp_addr = address; // store the address in a temporary byte
-	address = 0xFF;          // change the address to FF (0) for address check
-	SentecSensorRS485::ReturnCode tmp = readRegister(word(0x07, 0xD0), 2);
-	address = tmp_addr; // set the original address back
-	return tmp;
+    byte tmp_addr = address; // store the address in a temporary byte
+    address = 0xFF;          // change the address to FF (0) for address check
+    ErrorType tmp = readRegister(word(0x07, 0xD0), 2);
+    address = tmp_addr; // set the original address back
+    return tmp;
 }
 
-SentecSensorRS485::ReturnCode SentecSensorRS485::readRegister(int registerStartAddress)
-{
-	return readRegister(registerStartAddress, 1);
+ErrorType SentecSensorRS485::readRegister(int registerStartAddress) {
+    return readRegister(registerStartAddress, 1);
 }
 
-SentecSensorRS485::ReturnCode SentecSensorRS485::readRegister(int registerStartAddress, int registerLength)
-{
-	// function code 0x03: get data measured by the sensor
-	byte query[8];
-	query[0] = address;
-	// function code
-	query[1] = 0x03;
-	// register start address
-	query[2] = registerStartAddress >> 8;
-	query[3] = registerStartAddress & 0xFF;
-	// register length
-	query[4] = registerLength >> 8;
-	query[5] = registerLength & 0xFF;
-	// calculate last two bytes (CRC check)
-	calculateCRC(query, sizeof(query) - 2);
-	// #   Serial.print("Query (get data): 0x");                    #Print bytes
-	// #   printBytes(query, 8);
-	//  write the data request to the modbus line
-	write(query, sizeof(query));
-	// get response from sensor
-	return getResponse();
+ErrorType SentecSensorRS485::readRegister(int registerStartAddress, int registerLength) {
+    // function code 0x03: get data measured by the sensor
+    byte query[8];
+    query[0] = address;
+    // function code
+    query[1] = 0x03;
+    // register start address
+    query[2] = registerStartAddress >> 8;
+    query[3] = registerStartAddress & 0xFF;
+    // register length
+    query[4] = registerLength >> 8;
+    query[5] = registerLength & 0xFF;
+    // calculate last two bytes (CRC check)
+    calculateCRC(query, sizeof(query) - 2);
+    // #   Serial.print("Query (get data): 0x");                    #Print bytes
+    // #   printBytes(query, 8);
+    //  write the data request to the modbus line
+    write(query, sizeof(query));
+    // get response from sensor
+    return getResponse();
 }
 
-SentecSensorRS485::ReturnCode SentecSensorRS485::writeRegister(int registerAddress, int value)
-{
-	// function code 0x06: change sensor settings
-	// e.g. a new address, reset rainfal data...
-
-	byte query[8];
-	query[0] = address;
-	// function code
-	query[1] = 0x06;
-	// register start address
-	query[2] = registerAddress >> 8;
-	query[3] = registerAddress & 0xFF;
-	// register length
-	query[4] = value >> 8;
-	query[5] = value & 0xFF;
-	calculateCRC(query, sizeof(query) - 2);
-	ESP_LOGD(TAG, "Query (settings):    ");
-	printBytes(query, 8);
-	write(query, sizeof(query));
-	return getResponse();
+ErrorType SentecSensorRS485::writeRegister(int registerAddress, int value) {
+    // function code 0x06: change sensor settings
+    // e.g. a new address, reset rainfal data...
+
+    byte query[8];
+    query[0] = address;
+    // function code
+    query[1] = 0x06;
+    // register start address
+    query[2] = registerAddress >> 8;
+    query[3] = registerAddress & 0xFF;
+    // register length
+    query[4] = value >> 8;
+    query[5] = value & 0xFF;
+    calculateCRC(query, sizeof(query) - 2);
+    ESP_LOGD(TAG, "Query (settings):    ");
+    printBytes(query, 8);
+    write(query, sizeof(query));
+    return getResponse();
 }
 
-SentecSensorRS485::ReturnCode SentecSensorRS485::setAddress(byte add)
-{
-	// change the address of a sensor
-	SentecSensorRS485::ReturnCode tmp = writeRegister(word(0x07, 0xD0), add);
-	if (tmp == SentecSensorRS485::ReturnCode::OK)
-		address = add;
-	// TODO check response: matches the sent message exactly
-	return tmp;
+ErrorType SentecSensorRS485::setAddress(byte add) {
+    // change the address of a sensor
+    ErrorType tmp = writeRegister(word(0x07, 0xD0), add);
+    if (tmp == ErrorType::DATA_OK)
+        address = add;
+    // TODO check response: matches the sent message exactly
+    return tmp;
 }
 
-void SentecSensorRS485::resetAnswerFrame()
-{
-	for (int i = 0; i < 10; i++) {
-		answerFrame[i] = 0;
-	}
+void SentecSensorRS485::resetAnswerFrame() {
+    for (int i = 0; i < 10; i++) {
+        answerFrame[i] = 0;
+    }
 }
 
-SentecSensorRS485::ReturnCode SentecSensorRS485::getResponse()
-{
-	// reads the response of a sensor
-	SentecSensorRS485::ReturnCode returnCode = SentecSensorRS485::ReturnCode::OK;
-	valid = true;
-	int idx = 0;
-	int byteReceived;
-	// usual response length: changed in the while loop to match the response,
-	//   changed only when reading data (then it's 7 or 9  bytes, sensor dpendent)
-	int responseLength = 8;
-	// reading an answer takes up to 39 milliseconds for 2 byte readRegister
-	const int timeout = 200;
-	const int retries = 1; // #editet to q
-	size_t tries = 1;
-	// it doesn't seem to help to request multiple times if first time goes wrong
-	for (tries; tries <= retries; tries++) {
-		// if we lose connection with the sensor, we get an array of zeros back
-		resetAnswerFrame();
-
-		unsigned long time = millis();
-		while (idx < responseLength && (millis() - time) < timeout) {
-			if (RS485->available()) {
-				byteReceived = RS485->read();
-				// Serial.println(byteReceived, HEX);
-				// check for first byte. It has to be the device address unless for broadcasts with address = 0xFF
-				if (idx == 0 && address != 0xFF && byteReceived != address) {
-					ESP_LOGE(TAG, "Invalid byte. First byte needs to be address 0x%02X but got 0x%02Xinstead");
-				} else {
-					answerFrame[idx] = byteReceived;
-					// for reading register: third received byte is data length, read number of bytes accordingly
-					if (idx == 2 && answerFrame[1] == 0x03) {
-						// 5 bytes for address, function code, data length, CRC_H, CRC_L
-						responseLength = 5 + byteReceived;
-					}
-					idx++;
-				}
-			}
-		}
-		ESP_LOGD(TAG, "-----------------------------------------------------------------------------------------");
-		ESP_LOGD(TAG, "Response: 0x%s", formatBytes(answerFrame, responseLength).c_str());
-		// ESP_LOGD(TAG, "Tries: %d", tries);
-		// ESP_LOGD(TAG, "Bytes received: %d", idx);
-		if (answerFrame[0] == 0) {
-			ESP_LOGE(TAG, "Check sensor connection. First byte is 0x00.");
-			valid = false;
-			returnCode = SentecSensorRS485::ReturnCode::NO_CONNECTION;
-		} else if (idx < responseLength) {
-			ESP_LOGE(TAG, "Response too short: %d bytes < %d bytes. Unfinished transmission.", idx, responseLength);
-			valid = false;
-			returnCode = SentecSensorRS485::ReturnCode::SHORT_RESPONSE;
-		}
-		word crc_received = word(answerFrame[responseLength - 2], answerFrame[responseLength - 1]);
-		word crc = calculateCRC(answerFrame, responseLength - 2);
-		if (valid && crc_received != word(crc)) {
-			ESP_LOGE(TAG, "CRC wrong: Expected 0x%s got 0x%s", formatBytes(crc).c_str(),
-			         formatBytes(crc_received).c_str());
-			valid = false;
-			resetAnswerFrame();
-			returnCode = SentecSensorRS485::ReturnCode::WRONG_CRC;
-		}
-		// breaking after first successfull try
-		if (returnCode == SentecSensorRS485::ReturnCode::OK) {
-			break;
-		}
-	}
-
-	// ESP_LOGE(TAG, "Returncode: %d", returnCode);
-	return returnCode;
+ErrorType SentecSensorRS485::getResponse() {
+    // reads the response of a sensor
+    ErrorType returnCode = ErrorType::DATA_OK;
+    valid = true;
+    int idx = 0;
+    int byteReceived;
+    // usual response length: changed in the while loop to match the response,
+    //   changed only when reading data (then it's 7 or 9  bytes, sensor dpendent)
+    int responseLength = 8;
+    // reading an answer takes up to 39 milliseconds for 2 byte readRegister
+    const int timeout = 200;
+    const int retries = 1; // #editet to q
+    size_t tries = 1;
+    // it doesn't seem to help to request multiple times if first time goes wrong
+    for (tries; tries <= retries; tries++) {
+        // if we lose connection with the sensor, we get an array of zeros back
+        resetAnswerFrame();
+
+        unsigned long time = millis();
+        while (idx < responseLength && (millis() - time) < timeout) {
+            if (RS485->available()) {
+                byteReceived = RS485->read();
+                // Serial.println(byteReceived, HEX);
+                // check for first byte. It has to be the device address unless for broadcasts with address = 0xFF
+                if (idx == 0 && address != 0xFF && byteReceived != address) {
+                    ESP_LOGE(TAG,
+                             "Invalid byte. First byte needs to be address 0x%02X but got 0x%02Xinstead");
+                } else {
+                    answerFrame[idx] = byteReceived;
+                    // for reading register: third received byte is data length, read number of bytes accordingly
+                    if (idx == 2 && answerFrame[1] == 0x03) {
+                        // 5 bytes for address, function code, data length, CRC_H, CRC_L
+                        responseLength = 5 + byteReceived;
+                    }
+                    idx++;
+                }
+            }
+        }
+        ESP_LOGD(TAG,
+                 "-----------------------------------------------------------------------------------------");
+        ESP_LOGD(TAG, "Response: 0x%s", formatBytes(answerFrame, responseLength).c_str());
+        // ESP_LOGD(TAG, "Tries: %d", tries);
+        // ESP_LOGD(TAG, "Bytes received: %d", idx);
+        if (answerFrame[0] == 0) {
+            ESP_LOGE(TAG, "Check sensor connection. First byte is 0x00.");
+            valid = false;
+            returnCode = ErrorType::SENSOR_NOT_CONNECTED;
+        } else if (idx < responseLength) {
+            ESP_LOGE(TAG, "Response too short: %d bytes < %d bytes. Unfinished transmission.", idx,
+                     responseLength);
+            valid = false;
+            returnCode = ErrorType::CONNECTION_ENDED_PREMATURELY;
+        }
+        word crc_received = word(answerFrame[responseLength - 2], answerFrame[responseLength - 1]);
+        word crc = calculateCRC(answerFrame, responseLength - 2);
+        if (valid && crc_received != word(crc)) {
+            ESP_LOGE(TAG, "CRC wrong: Expected 0x%s got 0x%s", formatBytes(crc).c_str(),
+                     formatBytes(crc_received).c_str());
+            valid = false;
+            resetAnswerFrame();
+            returnCode = ErrorType::WRONG_CRC;
+        }
+        // breaking after first successfull try
+        if (returnCode == ErrorType::DATA_OK) {
+            break;
+        }
+    }
+
+    // ESP_LOGE(TAG, "Returncode: %d", returnCode);
+    return returnCode;
 }
 
-unsigned int SentecSensorRS485::calculateCRC(byte query[], int length)
-{
-	// Change the last two bytes of the queryFrame to conform to a CRC check
-	// Yes, this is necessary. No, I don't know exactly what it does.
-	unsigned int tmp1, tmp2, flag;
-	tmp1 = 0xFFFF;
-	for (unsigned char i = 0; i < length; i++) {
-		tmp1 = tmp1 ^ query[i];
-		for (unsigned char j = 1; j <= 8; j++) {
-			flag = tmp1 & 0x0001;
-			tmp1 >>= 1;
-			if (flag)
-				tmp1 ^= 0xA001;
-		}
-	}
-	// Reverse byte order.
-	tmp2 = tmp1 >> 8;
-	tmp1 = (tmp1 << 8) | tmp2;
-	tmp1 &= 0xFFFF;
-	// change last two query bytes
-	query[length + 1] = tmp1;
-	query[length] = tmp1 >> 8;
-
-	return tmp1; // the returned value is already swapped - CRC_L byte is first & CRC_H byte is last
+unsigned int SentecSensorRS485::calculateCRC(byte query[], int length) {
+    // Change the last two bytes of the queryFrame to conform to a CRC check
+    // Yes, this is necessary. No, I don't know exactly what it does.
+    unsigned int tmp1, tmp2, flag;
+    tmp1 = 0xFFFF;
+    for (unsigned char i = 0; i < length; i++) {
+        tmp1 = tmp1 ^ query[i];
+        for (unsigned char j = 1; j <= 8; j++) {
+            flag = tmp1 & 0x0001;
+            tmp1 >>= 1;
+            if (flag)
+                tmp1 ^= 0xA001;
+        }
+    }
+    // Reverse byte order.
+    tmp2 = tmp1 >> 8;
+    tmp1 = (tmp1 << 8) | tmp2;
+    tmp1 &= 0xFFFF;
+    // change last two query bytes
+    query[length + 1] = tmp1;
+    query[length] = tmp1 >> 8;
+
+    return tmp1; // the returned value is already swapped - CRC_L byte is first & CRC_H byte is last
 }
 
-void SentecSensorRS485::printBytes(byte *data, int length)
-{
-	// prints 8-bit data in hex with leading zeroes
-	char tmp[16];
-	for (int i = 0; i < length; i++) {
-		sprintf(tmp, "%.2X", data[i]);
-		// sprintf(tmp, "0x%.2X",data[i]);
-		Serial.print(tmp);
-		Serial.print(" ");
-	}
-	Serial.println();
+void SentecSensorRS485::printBytes(byte *data, int length) {
+    // prints 8-bit data in hex with leading zeroes
+    char tmp[16];
+    for (int i = 0; i < length; i++) {
+        sprintf(tmp, "%.2X", data[i]);
+        // sprintf(tmp, "0x%.2X",data[i]);
+        Serial.print(tmp);
+        Serial.print(" ");
+    }
+    Serial.println();
 }
 
-void SentecSensorRS485::printBytes(word data)
-{
-	char tmp[10];
-	sprintf(tmp, "0x%.2X", data >> 8);
-	Serial.print(tmp);
-	sprintf(tmp, "%.2X", data & 0xFF);
-	// sprintf(tmp, "0x%.2X",data[i]);
-	Serial.print(tmp);
+void SentecSensorRS485::printBytes(word data) {
+    char tmp[10];
+    sprintf(tmp, "0x%.2X", data >> 8);
+    Serial.print(tmp);
+    sprintf(tmp, "%.2X", data & 0xFF);
+    // sprintf(tmp, "0x%.2X",data[i]);
+    Serial.print(tmp);
 }
 
-std::string SentecSensorRS485::formatBytes(byte *data, int length)
-{
-	// pls don't hate me for building strings like that.
-	// I also wish that I would be good at programming
-	std::string tmp;
-	// prints 8-bit data in hex with leading zeroes
-	char buff[4];
-	for (int i = 0; i < length; i++) {
-		snprintf(buff, sizeof(buff), "%02X ", data[i]);
-		tmp += buff;
-	}
-	return tmp;
+std::string SentecSensorRS485::formatBytes(byte *data, int length) {
+    // pls don't hate me for building strings like that.
+    // I also wish that I would be good at programming
+    std::string tmp;
+    // prints 8-bit data in hex with leading zeroes
+    char buff[4];
+    for (int i = 0; i < length; i++) {
+        snprintf(buff, sizeof(buff), "%02X ", data[i]);
+        tmp += buff;
+    }
+    return tmp;
 }
 
-std::string SentecSensorRS485::formatBytes(word data)
-{
-	byte arr[2] = {data >> 8, data & 0xFF};
-	return formatBytes(arr, 2);
+std::string SentecSensorRS485::formatBytes(word data) {
+    byte arr[2] = {data >> 8, data & 0xFF};
+    return formatBytes(arr, 2);
 }
 
-word SolarRadiationSensor::getSolarRadiation()
-{
-	readRegister(0, 1);
-	glob = word(answerFrame[3], answerFrame[4]);
-	ESP_LOGI(TAG, "Global solar radiation: %d W/m^2", glob);
-	return glob;
+word SolarRadiationSensor::getSolarRadiation() {
+    readRegister(0, 1);
+    glob = word(answerFrame[3], answerFrame[4]);
+    ESP_LOGI(TAG, "Global solar radiation: %d W/m^2", glob);
+    return glob;
 }
 
-String SolarRadiationSensor::getSolarRadiationStr()
-{
-	return getValueStr((int)glob);
+String SolarRadiationSensor::getSolarRadiationStr() {
+    return getValueStr((int) glob);
 }
 
-void RainGaugeSensor::resetPrecipitation()
-{
-	// clears rainfall rata from the rain gauge
-	// delay resetting after the last register reading
-	delay(100);
-	Serial.println("Resetting precipitation sum");
-	writeRegister(0x00, 0x5A);
-	// TODO check response: matches the sent message exactly
+void RainGaugeSensor::resetPrecipitation() {
+    // clears rainfall rata from the rain gauge
+    // delay resetting after the last register reading
+    delay(100);
+    Serial.println("Resetting precipitation sum");
+    writeRegister(0x00, 0x5A);
+    // TODO check response: matches the sent message exactly
 }
 
-void RainGaugeSensor::resetSensor()
-{
-	// no clue what the difference between this one and the previous one is...
-	//   and the manual is not helpful, of course
-	delay(100);
-	Serial.println("Resetting precipitation sum");
-	writeRegister(0x37, 0x03);
-	// TODO check response: matches the sent message exactly
+void RainGaugeSensor::resetSensor() {
+    // no clue what the difference between this one and the previous one is...
+    //   and the manual is not helpful, of course
+    delay(100);
+    Serial.println("Resetting precipitation sum");
+    writeRegister(0x37, 0x03);
+    // TODO check response: matches the sent message exactly
 }
 
-word RainGaugeSensor::getInstantaneousPrecipitation()
-{
-	// gets tips of scale since the last reset, i.e. total precipitation (I THINK)
-	//   manual says this is current precipitation - is it?
-	readRegister(0, 0x01);
-	precipitation = word(answerFrame[3], answerFrame[4]);
+word RainGaugeSensor::getInstantaneousPrecipitation() {
+    // gets tips of scale since the last reset, i.e. total precipitation (I THINK)
+    //   manual says this is current precipitation - is it?
+    readRegister(0, 0x01);
+    precipitation = word(answerFrame[3], answerFrame[4]);
 
-	ESP_LOGI(TAG, "Precipitation: %.1f mm", precipitation / 10.0);
-	// resetPrecipitation();
-	return precipitation;
+    ESP_LOGI(TAG, "Precipitation: %.1f mm", precipitation / 10.0);
+    // resetPrecipitation();
+    return precipitation;
 }
 
-String RainGaugeSensor::getPrecipitationStr()
-{
-	return getValueStr((float)(precipitation / 10.0));
+String RainGaugeSensor::getPrecipitationStr() {
+    return getValueStr((float) (precipitation / 10.0));
 }
 
-float SoilMoistureSensor::getMoistureTemp()
-{
-	readRegister(0, 2); // start register at 0, read 2 variables (vwc, soil temp)
-	moistureRaw = (answerFrame[3] << 8) + answerFrame[4];
-	// TODO: neg. temp check
-	if (answerFrame[5] < 0x80) {
-		temperatureRaw = (answerFrame[5] << 8) + answerFrame[6];
-	} else {
-		temperatureRaw = (answerFrame[5] << 8) + answerFrame[6] - 65536;
-	}
-	ESP_LOGI(TAG, "Soil moisture:    %.1f  %", (moistureRaw - moistureOffset) / 10.0);
-	ESP_LOGI(TAG, "Soil temperature: %.1f °C", (temperatureRaw - temperatureOffset) / 10.0);
-	return (temperatureRaw - temperatureOffset) / 10.0;
+float SoilMoistureSensor::getMoistureTemp() {
+    readRegister(0, 2); // start register at 0, read 2 variables (vwc, soil temp)
+    moistureRaw = (answerFrame[3] << 8) + answerFrame[4];
+    // TODO: neg. temp check
+    if (answerFrame[5] < 0x80) {
+        temperatureRaw = (answerFrame[5] << 8) + answerFrame[6];
+    } else {
+        temperatureRaw = (answerFrame[5] << 8) + answerFrame[6] - 65536;
+    }
+    ESP_LOGI(TAG, "Soil moisture:    %.1f  %", (moistureRaw - moistureOffset) / 10.0);
+    ESP_LOGI(TAG, "Soil temperature: %.1f °C", (temperatureRaw - temperatureOffset) / 10.0);
+    return (temperatureRaw - temperatureOffset) / 10.0;
 }
 
-float SoilMoistureSensor::getMoisture()
-{
-	return (moistureRaw - moistureOffset) / 10.0;
+float SoilMoistureSensor::getMoisture() {
+    return (moistureRaw - moistureOffset) / 10.0;
 }
 
-String SoilMoistureSensor::getMoistureStr()
-{
-	return getValueStr((float)((moistureRaw - moistureOffset) / 10.0));
+String SoilMoistureSensor::getMoistureStr() {
+    return getValueStr((float) ((moistureRaw - moistureOffset) / 10.0));
 }
 
-String SoilMoistureSensor::getTemperatureStr()
-{
-	return getValueStr((float)((temperatureRaw - temperatureOffset) / 10.0));
+String SoilMoistureSensor::getTemperatureStr() {
+    return getValueStr((float) ((temperatureRaw - temperatureOffset) / 10.0));
 }
diff --git a/client/libs/SentecSensors/SentecSensors.h b/client/libs/SentecSensors/SentecSensors.h
index 336011134eb736a5265f5aa2b0ae86919b41d1c0..55fb834cdc770fd43edfff579a1f3f5ce08d5af1 100644
--- a/client/libs/SentecSensors/SentecSensors.h
+++ b/client/libs/SentecSensors/SentecSensors.h
@@ -2,79 +2,96 @@
 #define SENTECSENSORS_H
 
 #include <Arduino.h>
+#include <ErrorTypes.h>
 
 class SentecSensorRS485 {
-  public:
-	byte address;
-	uint8_t serialCommunicationControlPin = 19;
-	HardwareSerial *RS485;
-	byte answerFrame[10];
-	// TODO use valid flag to log None
-	bool valid = false;
-	SentecSensorRS485(HardwareSerial *ser, byte add);
-	SentecSensorRS485(HardwareSerial *ser, byte add, uint8_t serialControlPin);
-
-	enum class ReturnCode { 
-        OK,
-		NO_CONNECTION,
-		SHORT_RESPONSE, // connection ended prematurely
-		WRONG_CRC // corrupted data package
-      };
-
-	void write(byte queryFrame[], int length);
-	String getValueStr(float value);
-	String getValueStr(int value);
-	SentecSensorRS485::ReturnCode queryAddress();
-	SentecSensorRS485::ReturnCode readRegister(int registerStartAddress);
-	SentecSensorRS485::ReturnCode readRegister(int registerStartAddress, int registerLength);
-	SentecSensorRS485::ReturnCode writeRegister(int registerAddress, int value);
-	SentecSensorRS485::ReturnCode setAddress(byte add);
-	void resetAnswerFrame();
-	SentecSensorRS485::ReturnCode getResponse();
-	unsigned int calculateCRC(byte query[], int length);
-	void printBytes(byte *data, int length);
-	void printBytes(word data);
-	std::string formatBytes(byte *data, int length);
-	std::string formatBytes(word data);
+public:
+    byte address;
+    uint8_t serialCommunicationControlPin = 19;
+    HardwareSerial *RS485;
+    byte answerFrame[10];
+    // TODO use valid flag to log None
+    bool valid = false;
+
+    SentecSensorRS485(HardwareSerial *ser, byte add);
+
+    SentecSensorRS485(HardwareSerial *ser, byte add, uint8_t serialControlPin);
+
+    void write(byte queryFrame[], int length);
+
+    String getValueStr(float value);
+
+    String getValueStr(int value);
+
+    ErrorType queryAddress();
+
+    ErrorType readRegister(int registerStartAddress);
+
+    ErrorType readRegister(int registerStartAddress, int registerLength);
+
+    ErrorType writeRegister(int registerAddress, int value);
+
+    ErrorType setAddress(byte add);
+
+    void resetAnswerFrame();
+
+    ErrorType getResponse();
+
+    unsigned int calculateCRC(byte query[], int length);
+
+    void printBytes(byte *data, int length);
+
+    void printBytes(word data);
+
+    std::string formatBytes(byte *data, int length);
+
+    std::string formatBytes(word data);
 
 };
 
 class SolarRadiationSensor : public SentecSensorRS485 {
-  public:
-	using SentecSensorRS485::SentecSensorRS485;
-	// global radiation [W/m^2]
-	word glob = 0;
+public:
+    using SentecSensorRS485::SentecSensorRS485;
+    // global radiation [W/m^2]
+    word glob = 0;
 
-	word getSolarRadiation();
-	String getSolarRadiationStr();
+    word getSolarRadiation();
+
+    String getSolarRadiationStr();
 };
 
 class RainGaugeSensor : public SentecSensorRS485 {
-  public:
-	using SentecSensorRS485::SentecSensorRS485;
-	// precipitation values [mm]
-	word precipitation = 0; // prcp since reset? (I THINK!!!)
-
-	void resetPrecipitation();
-	void resetSensor();
-	word getInstantaneousPrecipitation();
-	String getPrecipitationStr();
+public:
+    using SentecSensorRS485::SentecSensorRS485;
+    // precipitation values [mm]
+    word precipitation = 0; // prcp since reset? (I THINK!!!)
+
+    void resetPrecipitation();
+
+    void resetSensor();
+
+    word getInstantaneousPrecipitation();
+
+    String getPrecipitationStr();
 };
 
 class SoilMoistureSensor : public SentecSensorRS485 {
-  public:
-	using SentecSensorRS485::SentecSensorRS485;
-	// vwc: volumetric water content [%]
-	uint16_t moistureRaw = 0;
-	int moistureOffset = 0;
-	// soil temperature [deg C]
-	int temperatureRaw = 0;
-	int temperatureOffset = 0;
-
-	float getMoistureTemp();
-	float getMoisture();
-	String getMoistureStr();
-	String getTemperatureStr();
+public:
+    using SentecSensorRS485::SentecSensorRS485;
+    // vwc: volumetric water content [%]
+    uint16_t moistureRaw = 0;
+    int moistureOffset = 0;
+    // soil temperature [deg C]
+    int temperatureRaw = 0;
+    int temperatureOffset = 0;
+
+    float getMoistureTemp();
+
+    float getMoisture();
+
+    String getMoistureStr();
+
+    String getTemperatureStr();
 };
 
 #endif
diff --git a/client/libs/dr26_analogue/dr26.cpp b/client/libs/dr26_analogue/dr26.cpp
index 1f01f0820e05d25db819606361626869352e3851..c0e7d0ee4959ea87d04043672a35fc82d59e4c2b 100644
--- a/client/libs/dr26_analogue/dr26.cpp
+++ b/client/libs/dr26_analogue/dr26.cpp
@@ -1,46 +1,47 @@
 #include "dr26.hpp"
 
 static const char *TAG = "DR26";
+
 void ForteDR26::setup() {
     Wire.begin();
 
-    ads1.setGain(GAIN_ONE);
-    ads1.setDataRate(RATE_ADS1115_8SPS);
-    ads1.begin() ? ESP_LOGD(TAG, "ADS initialized") : ESP_LOGE(TAG, "failed to initialize ADS");
+    ads.setGain(GAIN_ONE);
+    ads.setDataRate(RATE_ADS1115_8SPS);
+    if (ads.begin()) {
+        ESP_LOGD(TAG, "ADS initialized");
+        sensorConnected = true;
+    } else {
+        ESP_LOGE(TAG, "failed to initialize ADS");
+        sensorConnected = false;
+    }
+
     delay(100);
     channel = 0;
 }
 
-float ForteDR26::readData() {
+Measurement ForteDR26::readData() {
     float volts = 0;
-
-    // adjust data rate instead of yourself. ADC averages on its on with low data rate
-    // FIXME: Test which datarate gets most stable result. If it still is not good enough consider adding a small capacitor or averaging again
-    // 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;
-
-    
     int16_t adc = 0;
+
     try {
-        adc = ads1.readADC_SingleEnded(channel);
-        volts = ads1.computeVolts(adc);
+        // TODO: This function might never return if conversionComplete is never true. Check if this is the case
+        // FIXME: How to notice from the dr if a value is incorrect?
+        adc = ads.readADC_SingleEnded(channel);
+        volts = ads.computeVolts(adc);
     }
     catch (NoDataAvailableException &e) {
-        throw NoDataAvailableException();  //propagate exception
+        // FIXME: This catch block will never be called since we aint throwing any exceptions
+        return {ERROR_VALUE, channel, NO_I2C_ADDRESS, MeasurementType::CIRCUMFERENCE_INCREMENT,
+                ErrorType::NO_DATA};
     }
-    return volts;
+
+    if (!sensorConnected) {
+        return {ERROR_VALUE, channel, NO_I2C_ADDRESS, MeasurementType::CIRCUMFERENCE_INCREMENT,
+                ErrorType::SENSOR_INIT_FAILED};
+    }
+
+    return {volts, channel, NO_I2C_ADDRESS, MeasurementType::CIRCUMFERENCE_INCREMENT,
+            ErrorType::DATA_OK};
 }
 
 // The following functions change the ADC input range: be careful
@@ -59,7 +60,7 @@ float ForteDR26::readData() {
 // 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);
+    ads.setGain(gain);
 }
 
 void ForteDR26::setChannel(int c) {
@@ -68,18 +69,10 @@ void ForteDR26::setChannel(int c) {
 
 std::list<Message> ForteDR26::buildMessages() {
     std::list<Message> messages;
-    float data = readData();
-    MeasurementData IncrementData{data, channel, {}, "CIRCUMFERENCE_INCREMENT"};
-    messages.emplace_back(IncrementData, sensorInformation, Time::getInstance().getEpochSeconds());
-    return messages;
-}
-
-// FIXME: passing the measurementType as a string is not a good idea, we should use an enum like we do for other sensors
-std::list<Message> ForteDR26::buildMessages(std::string measurementType) {
-    std::list<Message> messages;
-    float data = readData();
-    MeasurementData IncrementData{data, channel, {}, measurementType};
-    messages.emplace_back(IncrementData, sensorInformation, Time::getInstance().getEpochSeconds());
+    auto data = readData();
+    messages.emplace_back(data,
+                          sensorInformation,
+                          Time::getInstance().getEpochSeconds());
     return messages;
 }
 
@@ -88,4 +81,6 @@ SensorInformation ForteDR26::getSensorInformation() const {
 }
 
 
-Adafruit_ADS1115 ForteDR26::ads1 = ads1; // TODO: What is this?
\ No newline at end of file
+// TODO: What is this?
+Adafruit_ADS1115 ForteDR26::ads = ads;
+
diff --git a/client/libs/dr26_analogue/dr26.hpp b/client/libs/dr26_analogue/dr26.hpp
index e1bc6b3e6c1857716a4e0fc6a0870ffd48774fbb..ea209f597917e3aee4a0dd0f2e89394e4833e499 100644
--- a/client/libs/dr26_analogue/dr26.hpp
+++ b/client/libs/dr26_analogue/dr26.hpp
@@ -9,21 +9,21 @@
 #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(std::string mesurment_type);
-	[[nodiscard]] SensorInformation getSensorInformation() const override;
-	static Adafruit_ADS1115 ads1;
+class ForteDR26: public ForteSensor<Measurement> {
+ public:
+  void setup() override;
+  Measurement readData() override;
+  void changeGain(adsGain_t gain);
+  void setChannel(int channel);
+  std::list<Message> buildMessages() override;
+  [[nodiscard]] SensorInformation getSensorInformation() const override;
+  static Adafruit_ADS1115 ads;
 
-  private:
-	Adafruit_ADS1115 ads;
-	const SensorInformation sensorInformation{"DR26", Protocol::Analog};
-	int channel;
+ private:
+  const SensorInformation
+      sensorInformation{HardwareName::DRS26, SensorProtocol::Analog};
+  int channel;
+  bool sensorConnected = true;
 };
 
 #endif
\ No newline at end of file
diff --git a/client/libs/drs26_digital/drs26.cpp b/client/libs/drs26_digital/drs26.cpp
index 5c21f3a98e01d665c38a879fb23f37217b39e8f4..a674964785a78476fa9783b0968bca161605e6b4 100644
--- a/client/libs/drs26_digital/drs26.cpp
+++ b/client/libs/drs26_digital/drs26.cpp
@@ -6,56 +6,56 @@ Because the sensor use sdi12 protocoll we have to wait aproxemettly 1 secound be
 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);
+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;
+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;
+std::list<Message> ForteDRS26::buildMessages() {
+  std::list<Message> messages;
+  Measurement circumferenceIncrementMeasurementData{data.circumferenceIncrement, 0,
+                                                    NO_I2C_ADDRESS,
+                                                    MeasurementType::CIRCUMFERENCE_INCREMENT,
+                                                    ErrorType::DATA_OK};
+  Measurement temperatureMeasurementData{data.temperature, 0, NO_I2C_ADDRESS,
+                                         MeasurementType::TEMPERATURE, ErrorType::DATA_OK};
+
+  messages.emplace_back(circumferenceIncrementMeasurementData,
+                        sensorInformation,
+                        0);
+  messages.emplace_back(temperatureMeasurementData, sensorInformation, 0);
+
+  return messages;
 }
-SensorInformation ForteDRS26::getSensorInformation() const
-{
-	return sensorInformation;
+SensorInformation ForteDRS26::getSensorInformation() const {
+  return sensorInformation;
 }
diff --git a/client/libs/drs26_digital/drs26.hpp b/client/libs/drs26_digital/drs26.hpp
index 0d713ca66260895f63cdc1e2137ec4027294e8bd..c02f0d23ebd4ae8e6e89dac952015f6f146c1415 100644
--- a/client/libs/drs26_digital/drs26.hpp
+++ b/client/libs/drs26_digital/drs26.hpp
@@ -10,28 +10,24 @@
 #include <map>
 
 struct out_data_drs26 {
-	int id;
-	float circumferenceIncrement;
-	float temperature;
+  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;
+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 };
+ private:
+  SDI12 drs26;
+  out_data_drs26 data;
+  const SensorInformation
+      sensorInformation{HardwareName::DRS26, SensorProtocol::I2C};
 
-	// 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/client/libs/espnow/src/ClientDataPackage.hpp b/client/libs/espnow/src/ClientDataPackage.hpp
deleted file mode 100644
index f08e6bba4ea43308e606f06f7870735d7f4820bc..0000000000000000000000000000000000000000
--- a/client/libs/espnow/src/ClientDataPackage.hpp
+++ /dev/null
@@ -1,54 +0,0 @@
-#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/client/libs/espnow/src/ESPNow.cpp b/client/libs/espnow/src/ESPNow.cpp
index b5627716f2101f11bb91e24d65b08baedae090b2..6ef9054a64321ec0318602b66b738fd7ccc4f3f9 100644
--- a/client/libs/espnow/src/ESPNow.cpp
+++ b/client/libs/espnow/src/ESPNow.cpp
@@ -7,98 +7,141 @@ 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;
+bool was_msg_received() {
+  if (msg_recv) {
+    msg_recv = false;
+    return true;
+  }
+  return false;
 }
 
-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 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_LOGI(TAG, "Backup MAC address used");
+  }
+  preferences.end();
 }
 
-void on_data_sent(const uint8_t *mac_addr, esp_now_send_status_t status)
-{
-	ESP_LOGE(TAG, "Message sent to %02X:%02X:%02X:%02X:%02X:%02X", mac_addr[0],
-			mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
+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_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_LOGD(TAG, "Message received");
-	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	
-														  // First three bytes of MACs are always vendor specific. But vendors have a range of them. 
-														  // all Espressif registered MAC starting bytes: https://maclookup.app/vendors/espressif-inc
-														  // you can also set your own MAC https://randomnerdtutorials.com/get-change-esp32-esp8266-mac-address-arduino/
-	switch (received_msg.type){
-		case hostChange:{
-			msg_recv = true;
-			ESP_LOGI(TAG, "hostChange received");
-			Time::getInstance().setTime(received_msg.epoch_seconds);
-			
-			// delete old host
-			uint8_t old[6];
-			RtcMemory::getInstance().get_host_mac(old);
-			if(memcmp(received_msg.host, old, 6) == 0){
-				ESP_LOGI(TAG, "removing old host");
-				esp_now_del_peer(old);
-			}
-			// add new host
-			RtcMemory::getInstance().store_mac_address(received_msg.host);
-			add_host_to_peers(received_msg);
-		}
-		case dataAck:{
-			msg_recv = true;
-			ESP_LOGI(TAG, "dataAck received.");
-			Time::getInstance().setTime(
-			received_msg.epoch_seconds); // see https://www.esp32.com/viewtopic.php?t=9965, maybe this needs an offset
-			ESP_LOGI(TAG, "Timestamp received: %ld", Time::getInstance().getEpochSeconds());
-		}
-			// delay(50);
-		
-		default:{
-			break;
-		}
-	}
+void on_data_sent(const uint8_t *mac_addr, esp_now_send_status_t status) {
+  ESP_LOGE(TAG, "Message sent to %02X:%02X:%02X:%02X:%02X:%02X", mac_addr[0],
+           mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
 }
 
+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_LOGD(TAG, "Message received");
+// time this
+  auto start = millis();
+  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
+  // First three bytes of MACs are always vendor specific. But vendors have a range of them.
+  // all Espressif registered MAC starting bytes: https://maclookup.app/vendors/espressif-inc
+  // you can also set your own MAC https://randomnerdtutorials.com/get-change-esp32-esp8266-mac-address-arduino/
+  switch (received_msg.type) {
+    case hostChange: {
+      ESP_LOGI(TAG, "hostChange received");
+      Time::getInstance().setTime(received_msg.epoch_seconds);
+      // delete old host
+      preferences.begin("config", false);
+      if (preferences.isKey("host")) {
+        ESP_LOGI(TAG, "removing old host");
+        uint8_t old[6];
+        preferences.end();
+        get_host_mac(old); // maybe problem here, re-opening preferences
+        esp_now_del_peer(old);
+      }
+      // add new host
+      preferences.begin("config", false);
+      if (preferences.putBytes("host",
+                               received_msg.host,
+                               sizeof(received_msg.host)) > 0) {
+        ESP_LOGI(TAG,
+                 "Host MAC address saved to flash %02X:%02X:%02X:%02X:%02X:%02X",
+                 received_msg.host[0],
+                 received_msg.host[1],
+                 received_msg.host[2],
+                 received_msg.host[3],
+                 received_msg.host[4],
+                 received_msg.host[5]);
+      } else {
+        ESP_LOGI(TAG, "Couldn't save Host Mac to flash");
+      }
+      preferences.end();
+      add_host_to_peers(received_msg);
+    }
+    case dataAck: {
+//			ESP_LOGI(TAG, "dataAck received.");
+      Time::getInstance().setTime(
+          received_msg.epoch_seconds); // see https://www.esp32.com/viewtopic.php?t=9965, maybe this needs an offset
 
-esp_err_t espnow_setup()
-{
-	esp_err_t result;
-	WiFi.mode(WIFI_STA);
-	result = esp_now_init();
-	if (result != ESP_OK) {
-		// initialization failed
-		ESP_LOGE(TAG, "ESPNow setup failed");
-		return result; // not sure about this
-	}
+//			ESP_LOGI(TAG, "Timestamp received: %ld", Time::getInstance().getEpochSeconds());
+      preferences.begin("config", false);
+      if (!preferences.isKey("host")) {
+        if (preferences.putBytes("host",
+                                 received_msg.host,
+                                 sizeof(received_msg.host)) > 0) {
+//			ESP_LOGI(TAG, "host MAC address saved to flash %02X:%02X:%02X:%02X:%02X:%02X", received_msg.host[0],
+//			received_msg.host[1],received_msg.host[2],received_msg.host[3],received_msg.host[4],received_msg.host[5]);
+//				}
 
-	RtcMemory::getInstance().get_host_mac(hostInfo.peer_addr); // check if there is a host saved in flash mem, broadcast otherwise
+          // add host to peers
+          add_host_to_peers(received_msg);
+        }
+      }
+      preferences.end();
+      // delay(50);
+      msg_recv = true;
+    }
+    default: {
+      break;
+    }
+  }
+  auto end = millis();
 
-	hostInfo.channel = 0;
+}
+
+
+esp_err_t espnow_setup() {
+  esp_err_t result;
+  WiFi.mode(WIFI_STA);
+  result = esp_now_init();
+  if (result != ESP_OK) {
+    // initialization failed
+    ESP_LOGE(TAG, "ESPNow setup 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);
+  // 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);
 
-	esp_now_register_recv_cb(on_data_recv);
-	esp_now_register_send_cb(on_data_sent);
+  esp_now_register_recv_cb(on_data_recv);
+  esp_now_register_send_cb(on_data_sent);
 
-	ESP_LOGI(TAG, "ESPNow started. MAC: %s", WiFi.macAddress().c_str());
-	return ESP_OK;
+  ESP_LOGI(TAG, "ESPNow started. MAC: %s", WiFi.macAddress().c_str());
+  return ESP_OK;
 }
diff --git a/client/libs/espnow/src/Message.cpp b/client/libs/espnow/src/Message.cpp
index fb5960e7ce182691e0da83daeb774e65320b592f..0df90ac3056149208dd7038e08f3ed52641822d3 100644
--- a/client/libs/espnow/src/Message.cpp
+++ b/client/libs/espnow/src/Message.cpp
@@ -2,39 +2,88 @@
 
 static const char *TAG = "MESSAGE";
 
-esp_err_t Message::send() const
-{
-	ESP_LOGD(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");
-		// Removed caching from here, better do this in main
-	}
-	ESP_LOGD(TAG, "Sent data: %s", messageData.c_str());
-
-	ESP_LOGD(TAG, "Timestamp sent: %ld", clientDataPackage.getTimestamp());
-	ESP_LOGD(TAG, "send status: %d", success);
-
-	return success;
+esp_err_t Message::send() const {
+  ESP_LOGD(TAG, "Sending message");
+  esp_err_t success;
+
+  // 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 *) &clientDataPackage,
+                         sizeof(ClientDataPackage));
+  if (success != ESP_OK) {
+    ESP_LOGE(TAG, "Error sending the data");
+    // Removed caching from here, better do this in main
+  }
+//    ESP_LOGD(TAG, "Sent data: %s", messageData.c_str());
+
+  ESP_LOGD(TAG, "Timestamp sent: %ld", clientDataPackage.getTimestamp());
+  ESP_LOGD(TAG, "send status: %d", success);
+
+  return success;
+}
+
+esp_err_t Message::sendMessages(const std::array<Message, 6> &messages) {
+  // recipient
+  uint8_t rec[6]{};
+  get_host_mac(rec);
+  ESP_LOGD(TAG, "Sending messages");
+  esp_err_t success;
+  // list of compressed data. Sending 6 at a time
+  std::array<ClientDataPackage, 6> clientDataPackages{};
+  // max 6 messages
+  int i = 0;
+  for (const auto &message: messages) {
+    if (i >= 6) {
+      ESP_LOGE(TAG, "Too many messages to send");
+      break;
+    }
+    clientDataPackages[i] = message.getClientDataPackage();
+
+    i++;
+  }
+
+  // conversion from std::string to c_str adds null terminator, which is why we add 1 to message length
+  success = esp_now_send(rec, (uint8_t *) &clientDataPackages,
+                         sizeof(std::array<ClientDataPackage, 6>));
+  if (success != ESP_OK) {
+    ESP_LOGE(TAG, "Error sending the data");
+    // Removed caching from here, better do this in main
+  }
+  unsigned long ts = millis();
+  // it takes ~110ms for receiving an acknowledgement by the host in perfect conditions
+  uint16_t message_timeout = 2000;
+  while (!was_msg_received()) {
+    if ((millis() - ts) > message_timeout) {
+      ESP_LOGE(TAG, "Timeout: Host not available\n");
+      break;
+    }
+  }
+  ESP_LOGD(TAG, "Time until acknowledgement: %ld", millis() - ts);
+//    ESP_LOGD(TAG, "Sent data: %s", messageData.c_str());
+
+//    ESP_LOGD(TAG, "Timestamp sent: %ld", clientDataPackage.getTimestamp());
+  ESP_LOGD(TAG, "send status: %d", success);
+
+  return success;
 }
 
-std::string Message::getMessageAsMinifiedJsonString() const
-{
-	return clientDataPackage.getDataPackageAsMinifiedJsonString();
+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
-	RtcMemory::getInstance().get_host_mac(recipient);
+Message::Message(ClientDataPackage data) : clientDataPackage(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
-	RtcMemory::getInstance().get_host_mac(recipient);
+
+Message::Message(Measurement 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);
+}
+const ClientDataPackage &Message::getClientDataPackage() const {
+  return clientDataPackage;
 }
+
diff --git a/client/libs/espnow/src/Message.hpp b/client/libs/espnow/src/Message.hpp
index ba2724deaf3e01ffcc56d146ca75909d20c69446..3dc83bf24274e19424d43d22187287651e927253 100644
--- a/client/libs/espnow/src/Message.hpp
+++ b/client/libs/espnow/src/Message.hpp
@@ -4,6 +4,7 @@
 #include "ESPNow.hpp"
 #include "Time.hpp"
 #include "esp_log.h"
+#include "GlobalDefinitions.hpp"
 #include <Arduino.h>
 #include <ArduinoJson.h>
 #include <ESP32Time.h>
@@ -13,14 +14,34 @@
 // Format of the message sent from host to client_satellite
 // if more things are sent from the host the name might not be accurate anymore
 class Message {
-  public:
-	explicit Message(ClientDataPackage data);
+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;
+    Message(Measurement const &data,
+            const SensorInformation &information,
+            unsigned long timestamp);
+
+    esp_err_t send() const;
+
+    [[nodiscard]] std::string getMessageAsMinifiedJsonString() const;
+
+    static Message nullMessage() {
+        return Message{Measurement(ERROR_VALUE,
+                                   NO_CHANNEL,
+                                   NO_I2C_ADDRESS,
+                                   MeasurementType::NULL_MEASUREMENT, ErrorType::NULL_MESSAGE),
+                       SensorInformation(HardwareName::NONE,
+                                         SensorProtocol::NULL_PROTOCOL),
+                       NULL_TIMESTAMP};
+    }
+
+    static esp_err_t sendMessages(const std::array<Message, 6> &messages);
+
+    [[nodiscard]] const ClientDataPackage &getClientDataPackage() const;
+
+private:
+    ClientDataPackage clientDataPackage;
+
+    uint8_t recipient[6]{};
 
-  private:
-	ClientDataPackage clientDataPackage;
-	uint8_t recipient[6]{};
 };
diff --git a/client/libs/ina219/ina219.cpp b/client/libs/ina219/ina219.cpp
index 930885f2d99e6ccd1571b778441dfd39668c2108..6253c034074687a7919f0b7f66afde1415bf37b5 100644
--- a/client/libs/ina219/ina219.cpp
+++ b/client/libs/ina219/ina219.cpp
@@ -1,63 +1,61 @@
 #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;
-	}
+void ForteINA219::setup() {
+    Wire.begin(I2C_SDA, I2C_SCL);
+    if (!ina219.init()) {
+        // Sensor init went wrong
+        ESP_LOGW(sensorInformation.getHardwareNameString().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;
+out_data_ina219 ForteINA219::readData() {
+    data.shuntVoltage_mV = Measurement{ina219.getShuntVoltage_mV(), NO_CHANNEL,
+                                       INA219_BASE_ADDRESS,
+                                       MeasurementType::SHUNT_VOLTAGE, ErrorType::DATA_OK};
+    data.busVoltage_V = Measurement{ina219.getBusVoltage_V(), NO_CHANNEL, INA219_BASE_ADDRESS,
+                                    MeasurementType::BUS_VOLTAGE, ErrorType::DATA_OK};
+    data.current_mA = Measurement{ina219.getCurrent_mA(), NO_CHANNEL, INA219_BASE_ADDRESS,
+                                  MeasurementType::CURRENT_mA, ErrorType::DATA_OK};
+    data.power_mW = Measurement{ina219.getBusPower(), NO_CHANNEL, INA219_BASE_ADDRESS,
+                                MeasurementType::POWER_mW, ErrorType::DATA_OK};
+    auto loadVoltage_V_value =
+            data.busVoltage_V.getValue() + (data.shuntVoltage_mV.getValue() / 1000);
+    data.loadVoltage_V = Measurement{
+            loadVoltage_V_value, NO_CHANNEL,
+            INA219_BASE_ADDRESS, MeasurementType::LOAD_VOLTAGE_V,
+            ErrorType::DATA_OK};
+
+    data.ina219_overflow = ina219.getOverflow();
+    if (data.ina219_overflow) {
+        // set all measurements to overflow
+        data.shuntVoltage_mV.setErrorType(ErrorType::INA219_OVERFLOW);
+        data.busVoltage_V.setErrorType(ErrorType::INA219_OVERFLOW);
+        data.current_mA.setErrorType(ErrorType::INA219_OVERFLOW);
+        data.power_mW.setErrorType(ErrorType::INA219_OVERFLOW);
+        data.loadVoltage_V.setErrorType(ErrorType::INA219_OVERFLOW);
+        return data;
+    } else {
+        return data;
+    }
 }
 
-std::list<Message> ForteINA219::buildMessages()
-{
-	std::list<Message> messages;
-	out_data_ina219 data = readData();
-	MeasurementData shuntVoltageData{
-		data.shuntVoltage_mV, 0, {}, measurementTypeToString.at(MeasurementType::SHUNT_VOLTAGE)
-	};
-	MeasurementData busVoltageData{
-		data.busVoltage_V, 0, {}, measurementTypeToString.at(MeasurementType::BUS_VOLTAGE)
-	};
-	MeasurementData currentMilliAmpData{
-		data.current_mA, 0, {}, measurementTypeToString.at(MeasurementType::CURRENT_mA)
-	};
-	MeasurementData powerMilliWattData{
-		data.power_mW, 0, {}, measurementTypeToString.at(MeasurementType::POWER_mA)
-	};
-	MeasurementData loadVoltageData{
-		data.loadVoltage_V, 0, {}, measurementTypeToString.at(MeasurementType::LOAD_VOLTAGE_V)
-	};
-	MeasurementData ina219OverflowData{
-		data.ina219_overflow, 0, {}, measurementTypeToString.at(MeasurementType::INA219_OVERFLOW)
-	};
-
-	messages.emplace_back(Message(shuntVoltageData, sensorInformation, 0));
-	messages.emplace_back(Message(busVoltageData, sensorInformation,0));
-	messages.emplace_back(Message(currentMilliAmpData, sensorInformation, 0));
-	messages.emplace_back(Message(powerMilliWattData, sensorInformation, 0));
-	messages.emplace_back(Message(loadVoltageData, sensorInformation, 0));
-	messages.emplace_back(Message(ina219OverflowData, sensorInformation, 0));
-
-	return messages;
+std::list<Message> ForteINA219::buildMessages() {
+    std::list<Message> messages;
+    out_data_ina219 measurements = readData();
+
+
+    messages.emplace_back(measurements.shuntVoltage_mV, sensorInformation, 0);
+    messages.emplace_back(measurements.busVoltage_V, sensorInformation, 0);
+    messages.emplace_back(measurements.current_mA, sensorInformation, 0);
+    messages.emplace_back(measurements.power_mW, sensorInformation, 0);
+    messages.emplace_back(measurements.loadVoltage_V, sensorInformation, 0);
+//    messages.emplace_back(ina219OverflowData, sensorInformation, 0); TODO: Do we need this as an extra message?
+
+    return messages;
 }
-SensorInformation ForteINA219::getSensorInformation() const
-{
-	return sensorInformation;
+
+SensorInformation ForteINA219::getSensorInformation() const {
+    return sensorInformation;
 }
diff --git a/client/libs/ina219/ina219.hpp b/client/libs/ina219/ina219.hpp
index 1985b996820f696290be13bc776a5f238fcd466a..a360948d0d98ab0b5030bb5aa8b8c4c38419cec8 100644
--- a/client/libs/ina219/ina219.hpp
+++ b/client/libs/ina219/ina219.hpp
@@ -7,36 +7,32 @@
 #include "Wire.h"
 #include "esp_log.h"
 #include <INA219_WE.h>
+#include <MeasurementTypes.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;
+  Measurement shuntVoltage_mV;
+  Measurement loadVoltage_V;
+  Measurement busVoltage_V;
+  Measurement current_mA;
+  Measurement power_mW;
+  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;
+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};
-	enum class MeasurementType {SHUNT_VOLTAGE, BUS_VOLTAGE, CURRENT_mA, POWER_mA, LOAD_VOLTAGE_V, INA219_OVERFLOW};
+ private:
+  INA219_WE ina219;
+  out_data_ina219 data;
+  const SensorInformation
+      sensorInformation{HardwareName::INA219, SensorProtocol::I2C};
+  const uint8_t INA219_BASE_ADDRESS = 0x40;
 
-	std::map<MeasurementType, const char*> measurementTypeToString = {
-		{MeasurementType::SHUNT_VOLTAGE, "SHUNT_VOLTAGE"},
-		{MeasurementType::BUS_VOLTAGE, "BUS_VOLTAGE"},
-		{MeasurementType::CURRENT_mA, "CURRENT_mA"},
-		{MeasurementType::POWER_mA, "POWER_mA"},
-		{MeasurementType::LOAD_VOLTAGE_V, "LOAD_VOLTAGE_V"},
-		{MeasurementType::INA219_OVERFLOW, "INA219_OVERFLOW"}};
 };
 
 #endif
\ No newline at end of file
diff --git a/client/libs/includes/ForteSensor.hpp b/client/libs/includes/ForteSensor.hpp
index add5a01d566ef5977eef3e0286d908c4b49fcb0b..1da7c49716cdf7c0bfc133babfc83cd834fc1216 100644
--- a/client/libs/includes/ForteSensor.hpp
+++ b/client/libs/includes/ForteSensor.hpp
@@ -2,7 +2,7 @@
 #define _FORTE_SENSOR
 
 #include "Message.hpp"
-#include "Protocol.hpp"
+#include "SensorProtocol.hpp"
 #include "SensorInformation.hpp"
 template <class T>
 class ForteSensor {
diff --git a/client/libs/includes/MeasurementData.hpp b/client/libs/includes/MeasurementData.hpp
deleted file mode 100644
index 36bd5db75fbdb714dad723d67b92affd4d4fd189..0000000000000000000000000000000000000000
--- a/client/libs/includes/MeasurementData.hpp
+++ /dev/null
@@ -1,39 +0,0 @@
-//
-// 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/libs/includes/Protocol.hpp b/client/libs/includes/Protocol.hpp
deleted file mode 100644
index f9a124978a42626fd128e579adc497bd23257678..0000000000000000000000000000000000000000
--- a/client/libs/includes/Protocol.hpp
+++ /dev/null
@@ -1,15 +0,0 @@
-//
-// Created by zoe on 10/5/22.
-//
-
-#ifndef CLIENT_PROTOCOL_HPP
-#define CLIENT_PROTOCOL_HPP
-
-#include <map>
-enum class Protocol { I2C, RS485, Analog, Mock };
-
-// protocol to string
-const static std::map<Protocol, const char *> protocolToString = {
-    {Protocol::I2C, "I2C"}, {Protocol::RS485, "RS485"}, {Protocol::Analog, "ANALOG"}, {Protocol::Mock, "MOCK"}};
-
-#endif // CLIENT_PROTOCOL_HPP
diff --git a/client/libs/includes/SensorInformation.hpp b/client/libs/includes/SensorInformation.hpp
deleted file mode 100644
index 4b8af5d357534be81670b503790960a2781bc282..0000000000000000000000000000000000000000
--- a/client/libs/includes/SensorInformation.hpp
+++ /dev/null
@@ -1,25 +0,0 @@
-//
-// 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/libs/mock_sensor/MockSensor.cpp b/client/libs/mock_sensor/MockSensor.cpp
index 4833773e9b7e26da8ff00842e1fcee47fb613635..bc1deaf1a62b868fd91ec3755732b1eb3f115068 100644
--- a/client/libs/mock_sensor/MockSensor.cpp
+++ b/client/libs/mock_sensor/MockSensor.cpp
@@ -1,34 +1,40 @@
 #include "MockSensor.hpp"
+#include "MeasurementTypes.h"
 
 static const char *TAG = "MOCK";
 
 void MockSensor::setup() {
 
-    ESP_LOGD(TAG, "MOCK Sensor initialized");
-    delay(100);
-    channel = 0;
+  ESP_LOGD(TAG, "MOCK Sensor initialized");
+  delay(100);
+  channel = 0;
 }
 
-float MockSensor::readData() {
-    // generate a random float value between 0 and 100
-    float randomValue = (float)rand() / (float)RAND_MAX * 100.0;
-    ESP_LOGD(TAG, "MOCK Sensor read value: %f", randomValue);
-    return randomValue;
+Measurement MockSensor::readData() {
+  // generate a random float value between 0 and 100
+  float randomValue = DeepSleep::bootCount * 10 + channel;
+  ESP_LOGD(TAG, "MOCK Sensor read value: %f", randomValue);
+  return {randomValue, channel, NO_I2C_ADDRESS, MeasurementType::MOCK,
+          ErrorType::DATA_OK};
+
 }
 
 
 void MockSensor::setChannel(int c) {
-    channel = c;
+  channel = c;
 }
 
 std::list<Message> MockSensor::buildMessages() {
-    std::list<Message> messages;
-    float data = readData();
-    MeasurementData MockData{data, channel, {}, "MOCK"};
-    messages.emplace_back(MockData, sensorInformation, Time::getInstance().getEpochSeconds());
-    return messages;
+  std::list<Message> messages;
+  auto measurement = readData();
+//  Measurement
+//          MockData{data, channel, NO_I2C_ADDRESS, MeasurementType::MOCK, ErrorType::DATA_OK};
+  messages.emplace_back(measurement,
+                        sensorInformation,
+                        Time::getInstance().getEpochSeconds());
+  return messages;
 }
 
 SensorInformation MockSensor::getSensorInformation() const {
-    return sensorInformation;
+  return sensorInformation;
 }
diff --git a/client/libs/mock_sensor/MockSensor.hpp b/client/libs/mock_sensor/MockSensor.hpp
index 20df4d1d2c66b954949a5fbce9a7e074293d28b2..aa39578f58b2ae0bb8bb651340bf02fa82c01426 100644
--- a/client/libs/mock_sensor/MockSensor.hpp
+++ b/client/libs/mock_sensor/MockSensor.hpp
@@ -7,18 +7,20 @@
 #include "Pinout.hpp"
 #include "esp_log.h"
 #include <Wire.h>
+#include <f_deep_sleep.hpp>
 
-class MockSensor : public ForteSensor<float> {
-  public:
-	void setup() override;
-	float readData() override;
-	void setChannel(int channel);
-	std::list<Message> buildMessages() override;
-	[[nodiscard]] SensorInformation getSensorInformation() const override;
 
-  private:
-	const SensorInformation sensorInformation{"MOCK", Protocol::Mock};
-	int channel;
+class MockSensor: public ForteSensor<Measurement> {
+ public:
+  void setup() override;
+  Measurement readData() override;
+  void setChannel(int channel);
+  std::list<Message> buildMessages() override;
+  [[nodiscard]] SensorInformation getSensorInformation() const override;
+
+ private:
+  const SensorInformation sensorInformation{HardwareName::MOCK, SensorProtocol::Mock};
+  int channel;
 };
 
 #endif
\ No newline at end of file
diff --git a/client/libs/rs485/rs485.cpp b/client/libs/rs485/rs485.cpp
index 269c7f37a0c6cb685adda7dc599edbea185d5f8e..55f18b6ba21b55729ba6e36f677770f7298135ce 100644
--- a/client/libs/rs485/rs485.cpp
+++ b/client/libs/rs485/rs485.cpp
@@ -13,72 +13,88 @@ static const char *TAG = "RS485";
 
 // Configure sensors
 SolarRadiationSensor solarSensor(&RS485Serial, 1, RE_DE_PIN);
-RainGaugeSensor rainGauge = RainGaugeSensor(&RS485Serial, 2, RE_DE_PIN);         // Give 2 Sensor Adress 2
-SoilMoistureSensor soilSensor3 = SoilMoistureSensor(&RS485Serial, 3, RE_DE_PIN); //.....
+RainGaugeSensor rainGauge = RainGaugeSensor(&RS485Serial,
+                                            2,
+                                            RE_DE_PIN);         // Give 2 Sensor Adress 2
+SoilMoistureSensor
+    soilSensor3 = SoilMoistureSensor(&RS485Serial, 3, RE_DE_PIN); //.....
 SoilMoistureSensor soilSensor4 = SoilMoistureSensor(&RS485Serial, 4, RE_DE_PIN);
 SoilMoistureSensor soilSensor5 = SoilMoistureSensor(&RS485Serial, 5, RE_DE_PIN);
 
-void Forte_RS485::setup()
-{
-	// configure the pins to be output only
-	pinMode(RE_DE_PIN, OUTPUT);
-	pinMode(POWER_SWITCH_PIN_12V, OUTPUT);
-	pinMode(POWER_SWITCH_PIN_5V, OUTPUT);
-	RS485Serial.begin(4800, SERIAL_8N1, TXPin, RXPin);
+void Forte_RS485::setup() {
+  // configure the pins to be output only
+  pinMode(RE_DE_PIN, OUTPUT);
+  pinMode(POWER_SWITCH_PIN_12V, OUTPUT);
+  pinMode(POWER_SWITCH_PIN_5V, OUTPUT);
+  RS485Serial.begin(4800, SERIAL_8N1, TXPin, RXPin);
 }
 
-out_data_rs485 Forte_RS485::readData()
-{
-	// Power on sensor
-	digitalWrite(POWER_SWITCH_PIN_12V, HIGH);
-	digitalWrite(POWER_SWITCH_PIN_5V, HIGH);
-	// Wait for sensors to power up
-	// TODO minimize delay
-	delay(300);
-	out_data_rs485 output;
-	unsigned long ts = millis();
-	output.solarRadiation = solarSensor.getSolarRadiation();
-	output.soilTemperature3 = soilSensor3.getMoistureTemp();
-	output.soilTemperature4 = soilSensor4.getMoistureTemp();
-	output.soilTemperature5 = soilSensor5.getMoistureTemp();
-	output.soilMoisture3 = soilSensor3.getMoisture();
-	output.soilMoisture4 = soilSensor4.getMoisture();
-	output.soilMoisture5 = soilSensor5.getMoisture();
-	output.precipitation = rainGauge.getInstantaneousPrecipitation();
-	digitalWrite(POWER_SWITCH_PIN_12V, LOW);
-	digitalWrite(POWER_SWITCH_PIN_5V, LOW);
+out_data_rs485 Forte_RS485::readData() {
+  // Power on sensor
+  digitalWrite(POWER_SWITCH_PIN_12V, HIGH);
+  digitalWrite(POWER_SWITCH_PIN_5V, HIGH);
+  // Wait for sensors to power up
+  // TODO minimize delay
+  delay(300);
+  out_data_rs485 output;
+  unsigned long ts = millis();
+  output.solarRadiation = solarSensor.getSolarRadiation();
+  output.soilTemperature3 = soilSensor3.getMoistureTemp();
+  output.soilTemperature4 = soilSensor4.getMoistureTemp();
+  output.soilTemperature5 = soilSensor5.getMoistureTemp();
+  output.soilMoisture3 = soilSensor3.getMoisture();
+  output.soilMoisture4 = soilSensor4.getMoisture();
+  output.soilMoisture5 = soilSensor5.getMoisture();
+  output.precipitation = rainGauge.getInstantaneousPrecipitation();
+  digitalWrite(POWER_SWITCH_PIN_12V, LOW);
+  digitalWrite(POWER_SWITCH_PIN_5V, LOW);
 
-	gpio_hold_en((gpio_num_t)POWER_SWITCH_PIN_12V);
-	gpio_hold_en((gpio_num_t)POWER_SWITCH_PIN_5V);
-	return output;
+  gpio_hold_en((gpio_num_t) POWER_SWITCH_PIN_12V);
+  gpio_hold_en((gpio_num_t) POWER_SWITCH_PIN_5V);
+  return output;
 }
 
-std::list<Message> Forte_RS485::buildMessages()
-{
-	std::list<Message> messages;
-	out_data_rs485 output = readData();
-	MeasurementData solarRadiation {output.solarRadiation, measurementTypeToString.at(MeasurementType::SOLAR_RADIATION)};
-	MeasurementData soilTemp3{output.soilTemperature3, measurementTypeToString.at(MeasurementType::SOIL_TEMPERATURE_3)};
-	MeasurementData soilTemp4 {output.soilTemperature4, measurementTypeToString.at(MeasurementType::SOIL_TEMPERATURE_4)};
-	MeasurementData soilTemp5 {output.soilTemperature5, measurementTypeToString.at(MeasurementType::SOIL_TEMPERATURE_5)};
-	MeasurementData soilMoisture3 {output.soilMoisture3, measurementTypeToString.at(MeasurementType::SOIL_MOISTURE_3)};
-	MeasurementData soilMoisture4 {output.soilMoisture4, measurementTypeToString.at(MeasurementType::SOIL_MOISTURE_4)};
-	MeasurementData soilMoisture5 {output.soilMoisture5, measurementTypeToString.at(MeasurementType::SOIL_MOISTURE_5)};
-	MeasurementData precipitation {output.precipitation, measurementTypeToString.at(MeasurementType::PRECIPITATION)};
+std::list<Message> Forte_RS485::buildMessages() {
+  std::list<Message> messages;
+  out_data_rs485 output = readData();
+  Measurement
+      solarRadiation{output.solarRadiation, MeasurementType::SOLAR_RADIATION};
+  Measurement
+      soilTemp3{output.soilTemperature3, MeasurementType::SOIL_TEMPERATURE_3};
+  Measurement
+      soilTemp4{output.soilTemperature4, MeasurementType::SOIL_TEMPERATURE_4};
+  Measurement
+      soilTemp5{output.soilTemperature5, MeasurementType::SOIL_TEMPERATURE_5};
+  Measurement
+      soilMoisture3{output.soilMoisture3, MeasurementType::SOIL_MOISTURE_3};
+  Measurement
+      soilMoisture4{output.soilMoisture4, MeasurementType::SOIL_MOISTURE_4};
+  Measurement
+      soilMoisture5{output.soilMoisture5, MeasurementType::SOIL_MOISTURE_5};
+  Measurement
+      precipitation{output.precipitation, MeasurementType::PRECIPITATION};
 
-	messages.emplace_back(Message{solarRadiation,sensorInformation, Time::getInstance().getEpochSeconds()});
-	messages.emplace_back(Message{soilTemp3,sensorInformation, Time::getInstance().getEpochSeconds()});
-	messages.emplace_back(Message{soilTemp4,sensorInformation, Time::getInstance().getEpochSeconds()});
-	messages.emplace_back(Message{soilTemp5,sensorInformation, Time::getInstance().getEpochSeconds()});
-	messages.emplace_back(Message{soilMoisture3,sensorInformation, Time::getInstance().getEpochSeconds()});
-	messages.emplace_back(Message{soilMoisture4,sensorInformation, Time::getInstance().getEpochSeconds()});
-	messages.emplace_back(Message{soilMoisture5,sensorInformation, Time::getInstance().getEpochSeconds()});
-	messages.emplace_back(Message(precipitation, sensorInformation, Time::getInstance().getEpochSeconds()));
+  messages.emplace_back(solarRadiation, sensorInformation,
+                        Time::getInstance().getEpochSeconds());
+  messages.emplace_back(soilTemp3, sensorInformation,
+                        Time::getInstance().getEpochSeconds());
+  messages.emplace_back(soilTemp4, sensorInformation,
+                        Time::getInstance().getEpochSeconds());
+  messages.emplace_back(soilTemp5, sensorInformation,
+                        Time::getInstance().getEpochSeconds());
+  messages.emplace_back(soilMoisture3, sensorInformation,
+                        Time::getInstance().getEpochSeconds());
+  messages.emplace_back(soilMoisture4, sensorInformation,
+                        Time::getInstance().getEpochSeconds());
+  messages.emplace_back(soilMoisture5, sensorInformation,
+                        Time::getInstance().getEpochSeconds());
+  messages.emplace_back(precipitation,
+                        sensorInformation,
+                        Time::getInstance().getEpochSeconds());
 
-	return messages;
+  return messages;
 }
 
-SensorInformation Forte_RS485::getSensorInformation() const
-{
-	return sensorInformation;
+SensorInformation Forte_RS485::getSensorInformation() const {
+  return sensorInformation;
 }
\ No newline at end of file
diff --git a/client/libs/rs485/rs485.hpp b/client/libs/rs485/rs485.hpp
index 4fc4f5e3d5b9e49f2748bc72406f1091625b7aa4..7ae7c9287f12f4af6370398495bfa083e9a88a5a 100644
--- a/client/libs/rs485/rs485.hpp
+++ b/client/libs/rs485/rs485.hpp
@@ -1,51 +1,32 @@
 #ifndef _RS485
 #define _RS485
 
+#include <MeasurementTypes.h>
 #include "Message.hpp"
 #include "ForteSensor.hpp"
 #include "SentecSensors.h"
 
-struct out_data_rs485{
-    float solarRadiation;
-    float soilMoisture3;
-    float soilTemperature3;
-    float soilMoisture4;
-    float soilTemperature4;
-    float soilMoisture5;
-    float soilTemperature5;
-    float precipitation;
+struct out_data_rs485 {
+  float solarRadiation;
+  float soilMoisture3;
+  float soilTemperature3;
+  float soilMoisture4;
+  float soilTemperature4;
+  float soilMoisture5;
+  float soilTemperature5;
+  float precipitation;
 };
 
-class Forte_RS485 : public ForteSensor <out_data_rs485> {
-  public:
-	void setup() override;
-	out_data_rs485 readData() override;
-	std::list<Message> buildMessages() override;
-	[[nodiscard]] SensorInformation getSensorInformation() const override;
+class Forte_RS485: public ForteSensor<out_data_rs485> {
+ public:
+  void setup() override;
+  out_data_rs485 readData() override;
+  std::list<Message> buildMessages() override;
+  [[nodiscard]] SensorInformation getSensorInformation() const override;
 
-  private:
-    const SensorInformation sensorInformation{"RS485", Protocol::RS485};
+ private:
+  const SensorInformation
+      sensorInformation{HardwareName::RS485, SensorProtocol::RS485};
 
-    enum class MeasurementType { 
-        SOLAR_RADIATION,
-        SOIL_MOISTURE_3,
-        SOIL_TEMPERATURE_3,
-        SOIL_MOISTURE_4,
-        SOIL_TEMPERATURE_4,
-        SOIL_MOISTURE_5,
-        SOIL_TEMPERATURE_5,
-        PRECIPITATION
-      };
-
-    std::map<MeasurementType, const char *> measurementTypeToString = {
-	    {MeasurementType::SOLAR_RADIATION, "SOLAR_RADIATION"},
-	    {MeasurementType::SOIL_MOISTURE_3, "SOIL_MOISTURE_3"},
-      {MeasurementType::SOIL_TEMPERATURE_3, "SOIL_TEMPERATURE_3"},
-      {MeasurementType::SOIL_MOISTURE_4, "SOIL_MOISTURE_4"},
-      {MeasurementType::SOIL_TEMPERATURE_4, "SOIL_TEMPERATURE_4"},
-	    {MeasurementType::SOIL_MOISTURE_5, "SOIL_MOISTURE_5"},
-      {MeasurementType::SOIL_TEMPERATURE_5, "SOIL_TEMPERATURE_5"},
-      {MeasurementType::PRECIPITATION, "PRECIPATION"}
-        };
 };
 #endif 
\ No newline at end of file
diff --git a/client/libs/scd30/scd30.cpp b/client/libs/scd30/scd30.cpp
index 7cff381af4ac4034d955366bf571a89b7e551ddf..6d830203bf58d3c14f03e5cc4a5c5d31c725b5a4 100644
--- a/client/libs/scd30/scd30.cpp
+++ b/client/libs/scd30/scd30.cpp
@@ -1,44 +1,63 @@
 #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;
-	}
+void ForteSCD30::setup() {
+    Wire.begin(I2C_SDA, I2C_SCL);
+    if (!airSensor.begin()) {
+        // Sensor init went wrong
+        ESP_LOGW(sensorInformation.getHardwareNameString().c_str(),
+                 "Initialization failed.");
+        sensorInit = false;
+    } else
+        sensorInit = true;
 }
 
-out_data_scd30 ForteSCD30 ::readData()
-{
-	if (airSensor.dataAvailable()) {
-		data.C02 = airSensor.getCO2();
-		data.Temperature = airSensor.getTemperature();
-		data.Humidity = airSensor.getHumidity();
+out_data_scd30 ForteSCD30::readData() {
+    if (airSensor.dataAvailable()) {
+        data.C02 = Measurement{static_cast<double>(airSensor.getCO2()), NO_CHANNEL,
+                               SCD30_BASE_ADDRESS,
+                               MeasurementType::CO2, ErrorType::DATA_OK};
 
-		return data;
-	}
-	throw NoDataAvailableException();
+        data.Temperature = Measurement{airSensor.getTemperature(), NO_CHANNEL, SCD30_BASE_ADDRESS,
+                                       MeasurementType::TEMPERATURE, ErrorType::DATA_OK};
+        data.Humidity = Measurement{airSensor.getHumidity(), NO_CHANNEL, SCD30_BASE_ADDRESS,
+                                    MeasurementType::HUMIDITY, ErrorType::DATA_OK};
+    } else {
+        data.C02 = Measurement{ERROR_VALUE, NO_CHANNEL, SCD30_BASE_ADDRESS,
+                               MeasurementType::CO2, ErrorType::NO_DATA};
+        data.Temperature = Measurement{ERROR_VALUE, NO_CHANNEL, SCD30_BASE_ADDRESS,
+                                       MeasurementType::TEMPERATURE, ErrorType::NO_DATA};
+        data.Humidity = Measurement{ERROR_VALUE, NO_CHANNEL, SCD30_BASE_ADDRESS,
+                                    MeasurementType::HUMIDITY, ErrorType::NO_DATA};
+    }
+
+    if (!sensorInit) {
+        data.C02.setErrorType(ErrorType::SENSOR_INIT_FAILED);
+        data.Temperature.setErrorType(ErrorType::SENSOR_INIT_FAILED);
+        data.Humidity.setErrorType(ErrorType::SENSOR_INIT_FAILED);
+    }
+
+    return data;
 }
 
-std::list<Message> ForteSCD30::buildMessages()
-{
-	std::list<Message> messages;
+std::list<Message> ForteSCD30::buildMessages() {
+    std::list<Message> messages;
+
+    auto measurements = readData();
+
 
-	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(measurements.C02,
+                          sensorInformation,
+                          Time::getInstance().getEpochSeconds());
+    messages.emplace_back(measurements.Temperature,
+                          sensorInformation,
+                          Time::getInstance().getEpochSeconds());
+    messages.emplace_back(measurements.Humidity,
+                          sensorInformation,
+                          Time::getInstance().getEpochSeconds());
 
-	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;
+    return messages;
 }
 
-SensorInformation ForteSCD30::getSensorInformation() const
-{
-	return sensorInformation;
+SensorInformation ForteSCD30::getSensorInformation() const {
+    return sensorInformation;
 }
diff --git a/client/libs/scd30/scd30.hpp b/client/libs/scd30/scd30.hpp
index db3e85500924db80ac3c0b5cd3698314564f6fd6..00ea13198e336b3afadde75e3ed265afbcec6fdf 100644
--- a/client/libs/scd30/scd30.hpp
+++ b/client/libs/scd30/scd30.hpp
@@ -10,22 +10,28 @@
 #include <Wire.h>
 
 struct out_data_scd30 {
-	float C02;
-	float Temperature;
-	float Humidity;
+    Measurement C02;
+    Measurement Temperature;
+    Measurement 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};
+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{HardwareName::SCD30, SensorProtocol::I2C};
+    const uint8_t SCD30_BASE_ADDRESS = 0x61;
+    bool sensorInit = true;
 };
 
 #endif
\ No newline at end of file
diff --git a/client/libs/sht85/Sht85.cpp b/client/libs/sht85/Sht85.cpp
index f9c1ee0e1089b6c2cc63abe9430cc0ec7ca002d9..f645944fdd4d1247bdfbdf7c587e2a623d6ec4fa 100644
--- a/client/libs/sht85/Sht85.cpp
+++ b/client/libs/sht85/Sht85.cpp
@@ -3,70 +3,68 @@
 //
 
 #include "Sht85.hpp"
-void Sht85::setup()
-{
-
-	this->sht = SHTSensor(SHTSensor::SHT85);
-	readData();
+void Sht85::setup() {
+  this->sht = SHTSensor(SHTSensor::SHT85);
+  readData();
 }
 
-void Sht85::readSHT()
-{
-	// Read data from the initialized SHT85
-	// TODO send via esp now instead of printing
-	if (sht.readSample()) {
-		Serial.print("T:  ");
-		Serial.println(sht.getTemperature(), 2);
-		Serial.print("RH: ");
-		Serial.println(sht.getHumidity(), 2);
-	} else {
-		Serial.print("Error in readSample()\n");
-	}
+void Sht85::readSHT() {
+  // Read data from the initialized SHT85
+  // TODO send via esp now instead of printing
+  if (sht.readSample()) {
+    Serial.print("T:  ");
+    Serial.println(sht.getTemperature(), 2);
+    Serial.print("RH: ");
+    Serial.println(sht.getHumidity(), 2);
+  } else {
+    Serial.print("Error in readSample()\n");
+  }
 }
 
-out_data_sht85 Sht85::readData()
-{
-	// Start the I2C bus
-	Wire.begin(SDA, SCL);
-	delay(100); // let serial console settle
+out_data_sht85 Sht85::readData() {
+  // Start the I2C bus
+  Wire.begin(SDA, SCL);
+  delay(100); // let serial console settle
 
-	// initiate the SHT85 sensor
-	Serial.println("");
-	if (sht.init(Wire)) {
-		Serial.println("SHT initialization successful");
-	} else {
-		Serial.println("SHT initialization failed");
-	}
+  // initiate the SHT85 sensor
+  Serial.println("");
+  if (sht.init(Wire)) {
+    Serial.println("SHT initialization successful");
+  } else {
+    Serial.println("SHT initialization failed");
+  }
 
-	// T + RH reading
-	readSHT();
+  // T + RH reading
+  readSHT();
 
-	delay(100);
+  delay(100);
 
-	// end I2C to free the pins to be used by the SD card
-	Wire.end();
+  // end I2C to free the pins to be used by the SD card
+  Wire.end();
 
-	out_data_sht85 sht85Data;
-	sht85Data.temperature = sht.getTemperature();
-	sht85Data.humidity = sht.getHumidity();
-	return sht85Data;
+  out_data_sht85 sht85Data;
+  sht85Data.temperature = sht.getTemperature();
+  sht85Data.humidity = sht.getHumidity();
+  return sht85Data;
 }
-std::list<Message> Sht85::buildMessages()
-{
-	std::list<Message> messages;
-	auto data = readData();
-	MeasurementData temperatureMeasurementData{
-	    data.temperature, {}, 0x44, measurementTypeToString.at(MeasurementType::TEMPERATURE)};
-	MeasurementData humidityMeasurementData{
-	    data.humidity, {}, 0x44, measurementTypeToString.at(MeasurementType::HUMIDITY)};
+std::list<Message> Sht85::buildMessages() {
+  std::list<Message> messages;
+  auto data = readData();
+  Measurement temperatureMeasurementData{data.temperature, NO_CHANNEL, 0x44,
+                                         MeasurementType::TEMPERATURE, ErrorType::DATA_OK};
+  Measurement humidityMeasurementData{data.humidity, NO_CHANNEL, 0x44,
+                                      MeasurementType::HUMIDITY, ErrorType::DATA_OK};
 
-	messages.emplace_back(
-	    Message{temperatureMeasurementData, sensorInformation, Time::getInstance().getEpochSeconds()});
-	messages.emplace_back(Message{humidityMeasurementData, sensorInformation, Time::getInstance().getEpochSeconds()});
+  messages.emplace_back(
+      temperatureMeasurementData,
+      sensorInformation,
+      Time::getInstance().getEpochSeconds());
+  messages.emplace_back(humidityMeasurementData,
+                        sensorInformation,
+                        Time::getInstance().getEpochSeconds());
 
-	return messages;
+  return messages;
 }
-SensorInformation Sht85::getSensorInformation() const
-{
-	return sensorInformation;
+SensorInformation Sht85::getSensorInformation() const {
+  return sensorInformation;
 }
diff --git a/client/libs/sht85/Sht85.hpp b/client/libs/sht85/Sht85.hpp
index 00c7114f27a7ab0382bc09e765d2728fd7d1b219..c9e86383ef5d60261fd993653c348f0b48c08261 100644
--- a/client/libs/sht85/Sht85.hpp
+++ b/client/libs/sht85/Sht85.hpp
@@ -6,7 +6,7 @@
 #define ESPCAM_SHT85_HPP
 
 #include "ForteSensor.hpp"
-#include "MeasurementData.hpp"
+#include "Measurement.hpp"
 #include "Message.hpp"
 #include "Pinout.hpp"
 #include "RTClib.h"    // adafruit/RTClib @^2.1.1
@@ -23,28 +23,24 @@
 #define SCL 12
 
 struct out_data_sht85 {
-	float temperature = 0.0;
-	float humidity = 0.0;
+  float temperature = 0.0;
+  float humidity = 0.0;
 };
 
-class Sht85 : public ForteSensor<out_data_sht85> {
-  public:
-	void setup() override;
-	out_data_sht85 readData() override;
-	std::list<Message> buildMessages() override;
-	[[nodiscard]] SensorInformation getSensorInformation() const override;
+class Sht85: public ForteSensor<out_data_sht85> {
+ public:
+  void setup() override;
+  out_data_sht85 readData() override;
+  std::list<Message> buildMessages() override;
+  [[nodiscard]] SensorInformation getSensorInformation() const override;
 
-  private:
-	SHTSensor sht; // I2C address: 0x44
-	out_data_sht85 data;
-	const SensorInformation sensorInformation{"SHT85", Protocol::I2C};
-	void readSHT();
+ private:
+  SHTSensor sht; // I2C address: 0x44
+  out_data_sht85 data;
+  const SensorInformation
+      sensorInformation{HardwareName::SHT85, SensorProtocol::I2C};
+  void readSHT();
 
-	enum class MeasurementType { TEMPERATURE, HUMIDITY };
-
-	// enum to string
-	std::map<MeasurementType, const char *> measurementTypeToString = {{MeasurementType::TEMPERATURE, "TEMPERATURE"},
-	                                                                   {MeasurementType::HUMIDITY, "HUMIDITY"}};
 };
 
 #endif // ESPCAM_SHT85_HPP
diff --git a/code-snippets/espnow_satellite/src/ClientDataPackage.hpp b/code-snippets/espnow_satellite/src/ClientDataPackage.hpp
index f08e6bba4ea43308e606f06f7870735d7f4820bc..2f80c5647490a42597f9f36aa1bba8fff8b26941 100644
--- a/code-snippets/espnow_satellite/src/ClientDataPackage.hpp
+++ b/code-snippets/espnow_satellite/src/ClientDataPackage.hpp
@@ -1,7 +1,7 @@
 #pragma once
 
 #include <ArduinoJson.h>
-#include "MeasurementData.hpp"
+#include "Measurement.hpp"
 #include "Protocol.hpp"
 #include "SensorInformation.hpp"
 #include <list>
diff --git a/host/host_central_mast/include/QueueStruct.h b/host/host_central_mast/include/QueueStruct.h
new file mode 100644
index 0000000000000000000000000000000000000000..15607ea353f5b0fc52b5f4385132deb2fa761595
--- /dev/null
+++ b/host/host_central_mast/include/QueueStruct.h
@@ -0,0 +1,13 @@
+//
+// Created by zoe on 2/7/23.
+//
+
+#ifndef HOST_CENTRAL_MAST_QUEUESTRUCT_H
+#define HOST_CENTRAL_MAST_QUEUESTRUCT_H
+
+struct QueueStruct {
+    std::array<ClientDataPackage, 6> data;
+    uint8_t mac[6]{};
+};
+
+#endif // HOST_CENTRAL_MAST_QUEUESTRUCT_H
diff --git a/host/host_central_mast/lib/Utilities/SDCardLogger.cpp b/host/host_central_mast/lib/Utilities/SDCardLogger.cpp
index b7fe7c7dcd2ef8b075cd67faae9ae187f01922b0..e35196503a0b10e858b8f32916ae4b2acaef24a3 100644
--- a/host/host_central_mast/lib/Utilities/SDCardLogger.cpp
+++ b/host/host_central_mast/lib/Utilities/SDCardLogger.cpp
@@ -15,10 +15,14 @@ namespace SDCardLogger {
     int vprintf_into_sd(const char *szFormat, va_list args) {
         String logstring = "[" + rtc.getDateTime() + "] ";
         logstring += szFormat;
-
+        // print current core
+        logstring += "Core: ";
+        logstring += xPortGetCoreID();
+        logstring += ". ";
         if (!SDUtilities::isSDAvailable()) {
             if (printToSerial) {
                 logstring += " (SD card not available)\n";
+
                 vprintf(logstring.c_str(), args);
             }
             return 1;
diff --git a/host/host_central_mast/lib/Utilities/Utilities.cpp b/host/host_central_mast/lib/Utilities/Utilities.cpp
index 316d33c95d27260f7b3c0ca299ed049db6305bce..50e18e0adbb892bd01ceeac66dde1a77eb57f5f1 100644
--- a/host/host_central_mast/lib/Utilities/Utilities.cpp
+++ b/host/host_central_mast/lib/Utilities/Utilities.cpp
@@ -237,6 +237,40 @@ namespace SDUtilities {
     }
 } // namespace SDUtilities
 
+namespace ESPUtilities {
+
+    String getMacAddressAsString(const uint8_t *mac) {
+        String macAddress;
+        for (int i = 0; i < 6; i++) {
+            macAddress += String(mac[i], HEX);
+        }
+        esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW, "MAC: %s\n", macAddress.c_str());
+        return macAddress;
+    }
+
+    void checkPeerExistence(const uint8_t *mac) {
+        if (!esp_now_is_peer_exist(mac)) {
+            esp_now_peer_info_t client = {};
+            memcpy(client.peer_addr, mac, sizeof(uint8_t) * 6);
+            client.encrypt = false;
+            client.channel = 0;
+
+            esp_err_t status = esp_now_add_peer(&client);
+            if (status != ESP_OK) {
+                esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW, "Failed to add new Peer: %d", status);
+            }
+        }
+    }
+
+    void sendResponse(const uint8_t *mac) {
+        response response = {};
+        response.type = dataAck;
+        esp_read_mac(response.mac, ESP_MAC_WIFI_STA);
+        response.time = rtc.getEpoch();
+        esp_err_t success = esp_now_send(mac, (uint8_t *)&response, sizeof(response));
+    }
+} // namespace ESPUtilities
+
 // I don't think this does anything. Copied from the example
 void turnOffLEDs() { // Set LED OFF
     pinMode(LED_PIN, OUTPUT);
@@ -248,15 +282,6 @@ void turnOffLEDs() { // Set LED OFF
     digitalWrite(PWR_PIN, LOW);
 }
 
-String getMacAddressAsString(const uint8_t *mac) {
-    String macAddress;
-    for (int i = 0; i < 6; i++) {
-        macAddress += String(mac[i], HEX);
-    }
-    esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW, "MAC: %s\n", macAddress.c_str());
-    return macAddress;
-}
-
 String documentToLineProtocolString(const DynamicJsonDocument &doc) {
     String measurementType = doc["measurementType"].as<String>();
     String sensorName = doc["sensorName"].as<String>();
@@ -288,16 +313,42 @@ String documentToServerReadableString(const DynamicJsonDocument &doc) {
 
     serverDoc["host"] = hostMacAddressString;
     serverDoc["client"] = doc["clientMac"].as<String>();
-    serverDoc["sensorProtocol"] = doc["protocol"].as<String>();
+    serverDoc["sensorProtocol"] = doc["sensorProtocol"].as<String>();
     serverDoc["protocolAddress"] = doc["channel"].as<String>();
-    serverDoc["hardwareName"] = doc["sensorName"].as<String>();
+    serverDoc["i2cAddress"] = doc["i2cAddress"].as<String>();
+    serverDoc["hardwareName"] = doc["hardwareName"].as<String>();
     // each value is a element in the readigs array
     JsonArray readings = serverDoc.createNestedArray("readings");
     JsonObject reading = readings.createNestedObject();
     reading["name"] = doc["measurementType"].as<String>();
-    reading["value"] = doc["value"].as<float>();
+    reading["value"] = doc["value"].as<double>();
     serverDoc["time"] = doc["timestamp"].as<uint32_t>();
 
+    String serverString;
+    serializeJson(serverDoc, serverString);
+    esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW, "Server readable data: %s\n", serverString.c_str());
+    return serverString;
+}
+
+String dataPackageToServerReadableString(ClientDataPackage clientDataPackage, const String &clientMacAddress) {
+    StaticJsonDocument<300> serverDoc;
+    String hostMacAddressString = WiFi.macAddress();
+    hostMacAddressString.replace(":", "");
+    hostMacAddressString.toLowerCase();
+
+    serverDoc["host"] = hostMacAddressString;
+    serverDoc["client"] = clientMacAddress;
+    serverDoc["sensorProtocol"] = clientDataPackage.getSensorInformation().getProtocolString();
+    serverDoc["protocolAddress"] = clientDataPackage.getMeasurementData().getChannel();
+    serverDoc["i2cAddress"] = clientDataPackage.getMeasurementData().getI2CAddress();
+    serverDoc["hardwareName"] = clientDataPackage.getSensorInformation().getHardwareNameString();
+    // each value is a element in the readigs array
+    JsonArray readings = serverDoc.createNestedArray("readings");
+    JsonObject reading = readings.createNestedObject();
+    reading["name"] = clientDataPackage.getMeasurementData().getMeasurementTypeString();
+    reading["value"] = clientDataPackage.getMeasurementData().getValue();
+    serverDoc["time"] = clientDataPackage.getTimestamp();
+
     String serverString;
     serializeJson(serverDoc, serverString);
     esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW, "Server readable data: %s\n", serverString.c_str());
diff --git a/host/host_central_mast/lib/Utilities/Utilities.h b/host/host_central_mast/lib/Utilities/Utilities.h
index dc18e3459e0fabe83c64f2e09a4a9ae3bf8c45f6..a196ea8c18fbf854aa482b5b84f673bec7d260e9 100644
--- a/host/host_central_mast/lib/Utilities/Utilities.h
+++ b/host/host_central_mast/lib/Utilities/Utilities.h
@@ -6,13 +6,16 @@
 #define HOST_CENTRAL_MAST_UTILITIES_H
 
 #include "ArduinoJson.h"
+#include "MessageType.h"
 #include "SD.h"
 #include "SDCardException.h"
 #include "SDSetupException.h"
 #include "WiFi.h"
 #include <Arduino.h>
+#include <ClientDataPackage.hpp>
 #include <Definitions.h>
 #include <WString.h>
+#include <esp_now.h>
 #include <list>
 
 namespace SDUtilities {
@@ -29,10 +32,18 @@ namespace SDUtilities {
     bool isSDAvailable();
 } // namespace SDUtilities
 
+namespace ESPUtilities {
+
+    String getMacAddressAsString(const uint8_t *mac);
+    void checkPeerExistence(const uint8_t *mac);
+    void sendResponse(const uint8_t *mac);
+} // namespace ESPUtilities
+
 void turnOffLEDs();
 String getMacAddressAsString(const uint8_t *mac);
 String documentToLineProtocolString(const DynamicJsonDocument &doc);
 DynamicJsonDocument parseReceivedJsonData(char *data);
 String documentToServerReadableString(const DynamicJsonDocument &doc);
+String dataPackageToServerReadableString(ClientDataPackage clientDataPackage, const String &clientMacAddress);
 
 #endif // HOST_CENTRAL_MAST_UTILITIES_H
diff --git a/host/host_central_mast/platformio.ini b/host/host_central_mast/platformio.ini
index f935fa80544f7810f4d3d5e7d9712f08d8551bde..5cd5785ab457376b7c5a95f86002031764cad269 100644
--- a/host/host_central_mast/platformio.ini
+++ b/host/host_central_mast/platformio.ini
@@ -14,8 +14,10 @@ board = esp-wrover-kit
 framework = arduino
 monitor_speed = 115200
 lib_ldf_mode = deep
-monitor_port = /dev/ttyACM0
-upload_port = /dev/ttyACM0
+monitor_port = /dev/ttyACM1
+upload_port = /dev/ttyACM1
+lib_extra_dirs =
+    ../../shared-libs
 build_flags =
     -I include
     -DCORE_DEBUG_LEVEL=5
diff --git a/host/host_central_mast/src/main.cpp b/host/host_central_mast/src/main.cpp
index af25396fb4e9f4d82cd8169b914373894ec541f9..68b7710938fde3cf3f3d74f7c4d25001394a7fe8 100644
--- a/host/host_central_mast/src/main.cpp
+++ b/host/host_central_mast/src/main.cpp
@@ -5,8 +5,10 @@
 
 #define TINY_GSM_MODEM_SIM7000
 
+#include "ClientDataPackage.hpp"
 #include "ConnectionManager.h"
 #include "MessageType.h"
+#include "QueueStruct.h"
 #include "SDCardLogger.h"
 #include "SPI.h"
 #include "Utilities.h"
@@ -14,13 +16,12 @@
 #include <Definitions.h>
 #include <ESP32Time.h>
 #include <NTPManager.h>
-#include <ResendManager.h>
 #include <TinyGsmClient.h>
 #include <WiFi.h>
 #include <esp_log.h>
 #include <esp_now.h>
-#include <map>
 #include <queue>
+#include <soc/rtc_cntl_reg.h>
 #include <sys/unistd.h>
 
 ESP32Time rtc;
@@ -51,68 +52,26 @@ SemaphoreHandle_t xMutex;
 
 TaskHandle_t ESPNOWTask;
 
-static std::queue<String> queue;
-
-ResendManager resendManager;
+void handleDataReceive(const uint8_t *mac, const uint8_t *incomingData);
+static std::queue<QueueStruct> queue;
 
 void on_data_sent(const uint8_t *mac_addr, esp_now_send_status_t status) {
     // go to sleep
 }
 
+/**
+ * @brief ESPNOW callback function that is called when data is received
+ * @param mac
+ * @param incomingData
+ * @param len length of the incoming data in bytes
+ */
 void on_data_recv(const uint8_t *mac, const uint8_t *incomingData, int len) {
+    ESPUtilities::checkPeerExistence(mac);
 
-    response response = {};
-    // send a host change msg if client is new, simplifies client
-    response.type = esp_now_is_peer_exist(mac) ? dataAck : hostChange;
-    esp_read_mac(response.mac, ESP_MAC_WIFI_STA);
-    response.time = rtc.getEpoch();
-
-    // this block needs to happen before we send the message, as it's not possible to
-    // send a message to an unregistered peer (i.e. new client)
-    if (!esp_now_is_peer_exist(mac)) {
-        esp_now_peer_info_t client = {};
-        memcpy(client.peer_addr, mac, sizeof(uint8_t) * 6);
-        client.encrypt = false;
-        client.channel = 0;
-
-        esp_err_t status = esp_now_add_peer(&client);
-        if (status != ESP_OK) {
-            esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW, "Failed to add new Peer: %d", status);
-        }
-    }
-
-    esp_err_t success = esp_now_send(mac, (uint8_t *)&response, sizeof(response));
-    esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW, (success == ESP_OK) ? "Response sent\n" : "Failed to respond\n");
-
-    char data[len];
-    memcpy(data, incomingData, len);
-    esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW, "Raw received Data: %s\n", data);
-
-    DynamicJsonDocument doc = parseReceivedJsonData(data);
+    ESPUtilities::sendResponse(mac);
 
-    String macAddress = getMacAddressAsString(mac);
-
-    // add timestamp and mac address
-    // doc["timestamp"] = rtc.getEpoch();
-    doc["clientMac"] = macAddress;
-
-    // serialize json document again
-    std::string dataString{};
-    serializeJson(doc, dataString);
-
-    try {
-        SDUtilities::saveStringToSDCard(dataString);
-    } catch (const std::exception &e) {
-        esp_log_write(ESP_LOG_ERROR, TAG_ESPNOW, "Failed to save data to SD card: %s", e.what());
-    }
-
-    String serverData = documentToServerReadableString(doc);
-
-    esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW, "Data to be sent: %s\n", serverData.c_str());
-
-    xSemaphoreTake(xMutex, portMAX_DELAY);
-    queue.push(serverData);
-    xSemaphoreGive(xMutex);
+    // requires queue and I am too lazy to extern declare the queue
+    handleDataReceive(mac, incomingData);
 }
 
 [[noreturn]] void esp_loop() {
@@ -121,7 +80,7 @@ void on_data_recv(const uint8_t *mac, const uint8_t *incomingData, int len) {
 }
 
 [[noreturn]] void ESPNOWReceiveTask(void *parameter) {
-    esp_log_write(ESP_LOG_DEBUG, TAG_ESPNOW, "ESPNOWReceiveTask started on core %d\n", xPortGetCoreID());
+    esp_log_write(ESP_LOG_INFO, TAG_ESPNOW, "ESPNOWReceiveTask started on core %d\n", xPortGetCoreID());
 
     WiFi.mode(WIFI_STA);
 
@@ -160,6 +119,7 @@ void setup() {
     // Set console baud rate
     Serial.begin(115200);
     delay(10);
+    WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); // disable detector
     try {
         SDUtilities::setupSDCard(SD_MISO, SD_MOSI, SD_SCLK, SD_CS);
     } catch (const SDSetupException &e) {
@@ -167,14 +127,13 @@ void setup() {
         esp_log_write(ESP_LOG_ERROR, TAG_MAIN, "SD Card setup failed: %s\n", e.what());
     }
 
-    SDCardLogger::printDebugToSerial(PRINT_TO_SERIAL);
+    SDCardLogger::printDebugToSerial(true);
 
     //	https://stackoverflow.com/questions/60442350/arduinos-esp-log-set-vprintf-does-not-work-on-esp32
     esp_log_set_vprintf(&SDCardLogger::vprintf_into_sd);
     esp_log_level_set("*", ESP_LOG_VERBOSE);
     esp_log_write(ESP_LOG_DEBUG, TAG_MAIN, "%s", WiFi.macAddress().c_str());
 
-    resendManager.init();
     turnOffLEDs();
 
     xMutex = xSemaphoreCreateMutex();
@@ -192,10 +151,57 @@ void setup() {
                             0);                  /* Core where the task should run */
 
     SerialAT.begin(UART_BAUD, SERIAL_8N1, PIN_RX, PIN_TX);
+
+    // Restart takes quite some time
+    // To skip it, call init() instead of restart()
+}
+
+bool isQueueEmpty() {
+    bool emptyQueue;
+    xSemaphoreTake(xMutex, portMAX_DELAY);
+    emptyQueue = queue.empty();
+    xSemaphoreGive(xMutex);
+    return emptyQueue;
 }
 
 void loop() {
 
+    // exit after 10 retries
+    int earlyExitCounter = 0;
+
+    // do while loop that takes one element of the queue each until the queue is empty
+    while (!isQueueEmpty()) {
+        xSemaphoreTake(xMutex, portMAX_DELAY);
+        auto data = queue.front();
+        queue.pop();
+        xSemaphoreGive(xMutex);
+
+        // get mac address as string
+        String macAddress = ESPUtilities::getMacAddressAsString(data.mac);
+
+        for (const auto &dataPackage : data.data) {
+            // ignore padding messages
+            if (dataPackage.getMeasurementData().getErrorType() == ErrorType::NULL_MESSAGE) {
+                continue;
+            }
+
+            auto serverReadableString = dataPackageToServerReadableString(dataPackage, macAddress);
+
+            try {
+                SDUtilities::saveStringToSDCard(serverReadableString.c_str());
+            } catch (const std::exception &e) {
+                esp_log_write(ESP_LOG_ERROR, TAG_ESPNOW, "Failed to save data to SD card: %s", e.what());
+            }
+
+            // TODO: Try send or add to queue
+        }
+
+        if (earlyExitCounter > 10) {
+            break;
+        }
+        earlyExitCounter++;
+    }
+
     connectionManager.modemPowerOn();
     delay(5000L);
 
@@ -253,29 +259,9 @@ void loop() {
         esp_log_write(ESP_LOG_ERROR, TAG_GSM, "Error writing time to rtc: %s\n", e.what());
     }
 
-    if (connectionManager.isGprsConnected()) {
-        esp_log_write(ESP_LOG_DEBUG, TAG_GSM, "GPRS connected\n");
-        // make list of map of headers
-        std::map<String, String> headers;
-        headers["Content-Type"] = "application/json";
-        headers["Accept"] = "application/json";
-
-        xSemaphoreTake(xMutex, portMAX_DELAY);
-        String data = queue.front();
-        queue.pop();
-        xSemaphoreGive(xMutex);
-
-        RequestInformation requestInformation{POST, "influxdb.qe-forte.uibk.ac.at",
-                                              80,   "/api/v2/write?org=QE&bucket=esp32test&precision=s",
-                                              data, headers};
-
-        try {
-            connectionManager.connect(requestInformation);
-        } catch (const std::exception &e) {
-            esp_log_write(ESP_LOG_ERROR, TAG_GSM, "Error sending data: %s\n", e.what());
-        }
-        esp_log_write(ESP_LOG_DEBUG, TAG_GSM, "Data sent: %s\n", data.c_str());
-    }
+    //    RequestInformation requestInformation("GET", "vsh.pp.ua", "/TinyGSM/logo.txt", "");
+    //    auto s = connectionManager.connect(80, requestInformation);
+    //    esp_log_write(ESP_LOG_DEBUG, TAG_GSM, "Response: %s\n", s.c_str());
 
     connectionManager.gprsDisconnect();
     delay(5000L);
@@ -290,3 +276,10 @@ void loop() {
 
     delay(10000);
 }
+void handleDataReceive(const uint8_t *mac, const uint8_t *incomingData) {
+    std::array<ClientDataPackage, 6> compressedDataPackage{};
+    memcpy(&compressedDataPackage, incomingData, sizeof(ClientDataPackage) * 6);
+    xSemaphoreTake(xMutex, portMAX_DELAY);
+    queue.emplace(QueueStruct{compressedDataPackage, {mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]}});
+    xSemaphoreGive(xMutex);
+}
\ No newline at end of file
diff --git a/shared-libs/DataTransfer/ClientDataPackage.hpp b/shared-libs/DataTransfer/ClientDataPackage.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..3f1413cc21e9e13c6428973166eaf817650dbcfe
--- /dev/null
+++ b/shared-libs/DataTransfer/ClientDataPackage.hpp
@@ -0,0 +1,68 @@
+#pragma once
+
+#include <ArduinoJson.h>
+#include "Measurement.hpp"
+#include "SensorProtocol.hpp"
+#include "SensorInformation.hpp"
+#include <list>
+#include <optional>
+#include <string>
+#include <utility>
+#include <ErrorTypes.h>
+
+// 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:
+    Measurement measurementData;
+    SensorInformation sensorInformation;
+    unsigned long timestamp; // maybe make this array
+
+public:
+    ClientDataPackage(Measurement value,
+                      SensorInformation sensorInformation,
+
+                      unsigned long timestamp)
+            : measurementData(value),
+              sensorInformation(sensorInformation),
+              timestamp(timestamp) {
+    }
+
+
+    [[nodiscard]] const Measurement &
+    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["hardwareName"] = sensorInformation.getHardwareNameString();
+        document["timestamp"] = timestamp;
+        document["sensorProtocol"] = sensorInformation.getProtocolString();
+        document["value"] = measurementData.getValue();
+
+
+        document["channel"] = measurementData.getChannel();
+
+
+        document["i2cAddress"] = measurementData.getI2CAddress();
+
+        document["measurementType"] = measurementData.getMeasurementTypeString();
+        document["errorType"] = measurementData.getErrorTypeString();
+
+        std::string jsonString;
+        serializeJson(document, jsonString);
+        return jsonString;
+    }
+
+    ClientDataPackage() : measurementData(Measurement(ERROR_VALUE, NO_CHANNEL, NO_I2C_ADDRESS,
+                                                      MeasurementType::TEMPERATURE,
+                                                      ErrorType::NULL_MESSAGE)),
+                          sensorInformation(SensorInformation(HardwareName::NONE,
+                                                              SensorProtocol::NULL_PROTOCOL)),
+                          timestamp(0) {}
+};
diff --git a/shared-libs/DataTransfer/ErrorTypes.cpp b/shared-libs/DataTransfer/ErrorTypes.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2babe9db1275a12c7b1a61e74ca16011cadca18f
--- /dev/null
+++ b/shared-libs/DataTransfer/ErrorTypes.cpp
@@ -0,0 +1,41 @@
+//
+// Created by zoe on 2/2/23.
+//
+
+#include "ErrorTypes.h"
+
+namespace ErrorTypes {
+
+    std::string errorTypeToString(ErrorType errorType) {
+        switch (errorType) {
+            case ErrorType::SENSOR_NOT_FOUND:
+                return "SENSOR_NOT_FOUND";
+            case ErrorType::SENSOR_NOT_CONNECTED:
+                return "SENSOR_NOT_CONNECTED";
+            case ErrorType::NO_DATA:
+                return "NO_DATA";
+            case ErrorType::DATA_OK:
+                return "DATA_OK";
+            case ErrorType::NULL_MESSAGE:
+                return "NULL_MESSAGE";
+            case ErrorType::SENSOR_DOES_NOT_RETURN_DATA:
+                return "SENSOR_DOES_NOT_RETURN_DATA";
+            case ErrorType::BATTERY_VOLTAGE_TOO_LOW:
+                return "BATTERY_VOLTAGE_TOO_LOW";
+            case ErrorType::INVALID_VALUE:
+                return "INVALID_VALUE";
+            case ErrorType::SENSOR_INIT_FAILED:
+                return "SENSOR_INIT_FAILED";
+            case ErrorType::INA219_OVERFLOW:
+                return "INA219_OVERFLOW";
+            case ErrorType::CONNECTION_ENDED_PREMATURELY:
+                return "CONNECTION_ENDED_PREMATURELY";
+            case ErrorType::WRONG_CRC:
+                return "WRONG_CRC";
+            case ErrorType::UNKNOWN:
+            default:
+                return "UNKNOWN_ERROR_TYPE";
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/shared-libs/DataTransfer/ErrorTypes.h b/shared-libs/DataTransfer/ErrorTypes.h
new file mode 100644
index 0000000000000000000000000000000000000000..3d12cbd8bbdc923154322960ed984ef9e734334a
--- /dev/null
+++ b/shared-libs/DataTransfer/ErrorTypes.h
@@ -0,0 +1,31 @@
+//
+// Created by zoe on 2/2/23.
+//
+
+#ifndef CLIENT_MOCK_ERRORTYPES_H
+#define CLIENT_MOCK_ERRORTYPES_H
+
+#include <string>
+
+enum class ErrorType : char {
+    SENSOR_NOT_FOUND,
+    SENSOR_INIT_FAILED,
+    SENSOR_NOT_CONNECTED,
+    NO_DATA,
+    DATA_OK,
+    NULL_MESSAGE, // message that is sent as padding, should be thrown away
+    SENSOR_DOES_NOT_RETURN_DATA,
+    BATTERY_VOLTAGE_TOO_LOW,
+    INVALID_VALUE,
+    INA219_OVERFLOW,
+    CONNECTION_ENDED_PREMATURELY, // connection ended prematurely
+    WRONG_CRC, // corrupted data package
+    UNKNOWN,
+};
+
+namespace ErrorTypes {
+    std::string errorTypeToString(ErrorType errorType);
+}
+
+
+#endif //CLIENT_MOCK_ERRORTYPES_H
diff --git a/shared-libs/DataTransfer/GlobalDefinitions.hpp b/shared-libs/DataTransfer/GlobalDefinitions.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..b4863dcd8950c5cf430eaf30c236cb56bce58345
--- /dev/null
+++ b/shared-libs/DataTransfer/GlobalDefinitions.hpp
@@ -0,0 +1,14 @@
+//
+// Created by zoe on 2/2/23.
+//
+
+#ifndef CLIENT_MOCK_GLOBALDEFINITIONS_HPP
+#define CLIENT_MOCK_GLOBALDEFINITIONS_HPP
+
+
+constexpr unsigned long NULL_TIMESTAMP = 0;
+constexpr int NO_I2C_ADDRESS = -1;
+constexpr int NO_CHANNEL = -1;
+constexpr double ERROR_VALUE = -999.99;
+
+#endif //CLIENT_MOCK_GLOBALDEFINITIONS_HPP
diff --git a/shared-libs/DataTransfer/HardwareNames.cpp b/shared-libs/DataTransfer/HardwareNames.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0150aaf61a6286ff03a93844d7124058c2aac741
--- /dev/null
+++ b/shared-libs/DataTransfer/HardwareNames.cpp
@@ -0,0 +1,39 @@
+//
+// Created by zoe on 2/2/23.
+//
+
+#include "HardwareNames.h"
+namespace HardwareNames {
+std::string hardwareNameToString(HardwareName hardwareName) {
+  // switch
+  switch (hardwareName) {
+    case HardwareName::RS485:
+      return "RS485";
+    case HardwareName::INA219:
+      return "INA219";
+    case HardwareName::SCD30:
+      return "SCD30";
+    case HardwareName::RAIN_GAUGE:
+      return "RAIN_GAUGE";
+    case HardwareName::SOIL_MOISTURE_SENSOR:
+      return "SOIL_MOISTURE_SENSOR";
+    case HardwareName::SOIL_TEMPERATURE_SENSOR:
+      return "SOIL_TEMPERATURE_SENSOR";
+    case HardwareName::SOLAR_RADIATION_SENSOR:
+      return "SOLAR_RADIATION_SENSOR";
+    case HardwareName::SHT85:
+      return "SHT85";
+    case HardwareName::DRS26:
+      return "DRS26";
+    case HardwareName::DR26:
+      return "DR26";
+    case HardwareName::MOCK:
+      return "MOCK";
+    case HardwareName::NONE:
+      return "NONE";
+    case HardwareName::LC709203:
+      break;
+  }
+  return "UNKNOWN HARDWARE NAME";
+}
+}
\ No newline at end of file
diff --git a/shared-libs/DataTransfer/HardwareNames.h b/shared-libs/DataTransfer/HardwareNames.h
new file mode 100644
index 0000000000000000000000000000000000000000..5bf6930379ab6069940cd6763eb022db8d511287
--- /dev/null
+++ b/shared-libs/DataTransfer/HardwareNames.h
@@ -0,0 +1,34 @@
+//
+// Created by zoe on 2/2/23.
+//
+
+#ifndef CLIENT_MOCK_HARDWARENAMES_H
+#define CLIENT_MOCK_HARDWARENAMES_H
+
+#include <map>
+
+// 32,767 possible values
+enum class HardwareName : short {
+  RS485, // TODO: THIS IS THE PROTOCOL NAME NOT THE HARDWARE NAME
+  INA219,
+  SCD30,
+  RAIN_GAUGE,
+  SOIL_MOISTURE_SENSOR,
+  SOIL_TEMPERATURE_SENSOR,
+  SOLAR_RADIATION_SENSOR,
+  SHT85,
+  DRS26,
+  DR26,
+  MOCK,
+  NONE,
+  LC709203,
+};
+
+// hardware name to string function
+
+namespace HardwareNames {
+std::string hardwareNameToString(HardwareName hardwareName);
+}
+
+
+#endif //CLIENT_MOCK_HARDWARENAMES_H
diff --git a/shared-libs/DataTransfer/Measurement.hpp b/shared-libs/DataTransfer/Measurement.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..49bcd4956e151bc1f4ec910970fceba51cd80df2
--- /dev/null
+++ b/shared-libs/DataTransfer/Measurement.hpp
@@ -0,0 +1,68 @@
+//
+// Created by cynthya on 10/6/22.
+//
+
+#ifndef CLIENT_MEASUREMENTDATA_HPP
+#define CLIENT_MEASUREMENTDATA_HPP
+
+#include "ArduinoJson.h"
+#include "SensorProtocol.hpp"
+#include "SensorInformation.hpp"
+#include <list>
+#include <optional>
+#include <string>
+#include <utility>
+#include <MeasurementTypes.h>
+#include <GlobalDefinitions.hpp>
+#include "ErrorTypes.h"
+
+class Measurement {
+public:
+    Measurement(double value, int channel, int i2cAddress, MeasurementType measurementType,
+                ErrorType errorType)
+            : value(value), measurementType(measurementType), channel(channel),
+              i2cAddress(i2cAddress), errorType(errorType) {
+    }
+
+    Measurement(double value, MeasurementType measurementType)
+            : value(value), measurementType(measurementType) {
+        channel = NO_CHANNEL;
+        i2cAddress = NO_I2C_ADDRESS;
+        errorType = ErrorType::DATA_OK;
+    }
+
+    [[nodiscard]] double getValue() const { return value; }
+
+    [[nodiscard]] const MeasurementType &
+    getMeasurementType() const { return measurementType; }
+
+    [[nodiscard]] std::string getMeasurementTypeString() const {
+        return MeasurementTypes::measurementTypeToString(measurementType);
+    }
+
+    [[nodiscard]] const int &getChannel() const { return channel; }
+
+    [[nodiscard]] const ErrorType &getErrorType() const { return errorType; }
+
+    [[nodiscard]] std::string getErrorTypeString() const {
+        return ErrorTypes::errorTypeToString(errorType);
+    }
+
+    void setErrorType(ErrorType type) {
+        errorType = type;
+    }
+
+    [[nodiscard]] const int &
+    getI2CAddress() const { return i2cAddress; }
+
+
+private:
+    double value;
+    MeasurementType measurementType;
+    ErrorType errorType;
+    // TODO: is it possible for a sensor to have both a channel and an i2cAddress?
+    int channel = NO_CHANNEL;
+    int i2cAddress = NO_I2C_ADDRESS;
+};
+
+#endif // CLIENT_MEASUREMENTDATA_HPP
diff --git a/shared-libs/DataTransfer/MeasurementTypes.cpp b/shared-libs/DataTransfer/MeasurementTypes.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..220da6e1879f570b4faacd47372aea5974bdee7b
--- /dev/null
+++ b/shared-libs/DataTransfer/MeasurementTypes.cpp
@@ -0,0 +1,54 @@
+//
+// Created by zoe on 2/2/23.
+//
+# include "MeasurementTypes.h"
+namespace MeasurementTypes {
+std::string measurementTypeToString(MeasurementType measurementType) {
+  switch (measurementType) {
+    case MeasurementType::CIRCUMFERENCE_INCREMENT:
+      return "CIRCUMFERENCE_INCREMENT";
+    case MeasurementType::TEMPERATURE:
+      return "TEMPERATURE";
+    case MeasurementType::HUMIDITY:
+      return "HUMIDITY";
+    case MeasurementType::SHUNT_VOLTAGE:
+      return "SHUNT_VOLTAGE";
+    case MeasurementType::BUS_VOLTAGE:
+      return "BUS_VOLTAGE";
+    case MeasurementType::CURRENT_mA:
+      return "CURRENT_mA";
+    case MeasurementType::POWER_mW:
+      return "POWER_mW";
+    case MeasurementType::LOAD_VOLTAGE_V:
+      return "LOAD_VOLTAGE_V";
+    case MeasurementType::INA219_OVERFLOW:
+      return "INA219_OVERFLOW";
+    case MeasurementType::BATTERY_VOLTAGE:
+      return "BATTERY_VOLTAGE";
+    case MeasurementType::MOCK:
+      return "MOCK";
+    case MeasurementType::SOLAR_RADIATION:
+      return "SOLAR_RADIATION";
+    case MeasurementType::SOIL_MOISTURE_3:
+      return "SOIL_MOISTURE_3";
+    case MeasurementType::SOIL_TEMPERATURE_3:
+      return "SOIL_TEMPERATURE_3";
+    case MeasurementType::SOIL_MOISTURE_4:
+      return "SOIL_MOISTURE_4";
+    case MeasurementType::SOIL_TEMPERATURE_4:
+      return "SOIL_TEMPERATURE_4";
+    case MeasurementType::SOIL_MOISTURE_5:
+      return "SOIL_MOISTURE_5";
+    case MeasurementType::SOIL_TEMPERATURE_5:
+      return "SOIL_TEMPERATURE_5";
+    case MeasurementType::PRECIPITATION:
+      return "PRECIPITATION";
+    case MeasurementType::CO2:
+      return "CO2";
+    case MeasurementType::NULL_MEASUREMENT:
+      return "NULL_MEASUREMENT";
+  }
+  return "UNKNOWN";
+}
+
+}
\ No newline at end of file
diff --git a/shared-libs/DataTransfer/MeasurementTypes.h b/shared-libs/DataTransfer/MeasurementTypes.h
new file mode 100644
index 0000000000000000000000000000000000000000..0818bba5453a7223c9f84025bd9608343a6a0672
--- /dev/null
+++ b/shared-libs/DataTransfer/MeasurementTypes.h
@@ -0,0 +1,40 @@
+//
+// Created by zoe on 2/2/23.
+//
+
+#ifndef CLIENT_MOCK_MEASUREMENTTYPES_H
+#define CLIENT_MOCK_MEASUREMENTTYPES_H
+
+#include <map>
+
+enum class MeasurementType {
+  CIRCUMFERENCE_INCREMENT,
+  TEMPERATURE,
+  HUMIDITY,
+  SHUNT_VOLTAGE,
+  BUS_VOLTAGE,
+  CURRENT_mA,
+  POWER_mW,
+  LOAD_VOLTAGE_V,
+  INA219_OVERFLOW,
+  BATTERY_VOLTAGE,
+  MOCK,
+  SOLAR_RADIATION,
+  SOIL_MOISTURE_3,
+  SOIL_TEMPERATURE_3,
+  SOIL_MOISTURE_4,
+  SOIL_TEMPERATURE_4,
+  SOIL_MOISTURE_5,
+  SOIL_TEMPERATURE_5,
+  PRECIPITATION,
+  CO2,
+  NULL_MEASUREMENT,
+};
+
+// convert below to a function
+// measurement type to string function
+namespace MeasurementTypes {
+std::string measurementTypeToString(MeasurementType measurementType);
+}
+
+#endif //CLIENT_MOCK_MEASUREMENTTYPES_H
diff --git a/shared-libs/DataTransfer/SensorInformation.hpp b/shared-libs/DataTransfer/SensorInformation.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..c95d99107fb54b138c77990a92ad2dba1ad37021
--- /dev/null
+++ b/shared-libs/DataTransfer/SensorInformation.hpp
@@ -0,0 +1,33 @@
+//
+// Created by cynthya on 10/6/22.
+//
+
+#ifndef CLIENT_SENSORINFORMATION_HPP
+#define CLIENT_SENSORINFORMATION_HPP
+
+#include "SensorProtocol.hpp"
+#include <string>
+#include <HardwareNames.h>
+
+class SensorInformation {
+ public:
+  SensorInformation(HardwareName hardwareName, SensorProtocol sensorProtocol)
+      : hardwareName(hardwareName), sensorProtocol(sensorProtocol) {
+  }
+
+  [[nodiscard]] const HardwareName &
+  getHardwareName() const { return hardwareName; }
+  [[nodiscard]] std::string getHardwareNameString() const {
+    return HardwareNames::hardwareNameToString(hardwareName);
+  }
+  [[nodiscard]] SensorProtocol getProtocol() const { return sensorProtocol; }
+  [[nodiscard]] std::string getProtocolString() const {
+    return SensorProtocols::sensorProtocolToString(sensorProtocol);
+  }
+
+ private:
+  HardwareName hardwareName;
+  SensorProtocol sensorProtocol;
+};
+
+#endif // CLIENT_SENSORINFORMATION_HPP
diff --git a/shared-libs/DataTransfer/SensorProtocol.cpp b/shared-libs/DataTransfer/SensorProtocol.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f2aa02da070bf93f3cdee9ca2682b792a6ee62cf
--- /dev/null
+++ b/shared-libs/DataTransfer/SensorProtocol.cpp
@@ -0,0 +1,22 @@
+//
+// Created by zoe on 2/2/23.
+//
+
+#include "SensorProtocol.hpp"
+namespace SensorProtocols {
+std::string sensorProtocolToString(SensorProtocol sensorProtocol) {
+  switch (sensorProtocol) {
+    case SensorProtocol::I2C:
+      return "I2C";
+    case SensorProtocol::RS485:
+      return "RS485";
+    case SensorProtocol::Analog:
+      return "Analog";
+    case SensorProtocol::Mock:
+      return "Mock";
+    case SensorProtocol::NULL_PROTOCOL:
+      return "NULL_PROTOCOL";
+  }
+  return "UNKNOWN";
+}
+}
\ No newline at end of file
diff --git a/shared-libs/DataTransfer/SensorProtocol.hpp b/shared-libs/DataTransfer/SensorProtocol.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..fb4d0b0f114cb2e10decb6a263044bc05ade7c3d
--- /dev/null
+++ b/shared-libs/DataTransfer/SensorProtocol.hpp
@@ -0,0 +1,15 @@
+//
+// Created by zoe on 10/5/22.
+//
+
+#ifndef CLIENT_PROTOCOL_HPP
+#define CLIENT_PROTOCOL_HPP
+
+#include <map>
+enum class SensorProtocol : short { I2C, RS485, Analog, Mock, NULL_PROTOCOL };
+
+namespace SensorProtocols {
+std::string sensorProtocolToString(SensorProtocol sensorProtocol);
+}
+
+#endif // CLIENT_PROTOCOL_HPP