diff --git a/client/ESPcam/.idea/misc.xml b/client/ESPcam/.idea/misc.xml
index 6e1c9f37b93d78b6c09407d34dc9e55175665cd7..79b3c94830bab93d40d0770f2765540fe24ed423 100644
--- a/client/ESPcam/.idea/misc.xml
+++ b/client/ESPcam/.idea/misc.xml
@@ -1,6 +1,4 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
-  <component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$">
-    <contentRoot DIR="$PROJECT_DIR$/.." />
-  </component>
+  <component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
 </project>
\ No newline at end of file
diff --git a/client/ESPcam/CMakeLists.txt b/client/ESPcam/CMakeLists.txt
deleted file mode 100644
index 09129ea1d8cb31d661b5f0903019ed910e3d1483..0000000000000000000000000000000000000000
--- a/client/ESPcam/CMakeLists.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-# !!! WARNING !!! AUTO-GENERATED FILE, PLEASE DO NOT MODIFY IT AND USE
-# https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags
-#
-# If you need to override existing CMake configuration or add extra,
-# please create `CMakeListsUser.txt` in the root of project.
-# The `CMakeListsUser.txt` will not be overwritten by PlatformIO.
-
-cmake_minimum_required(VERSION 3.13)
-set(CMAKE_SYSTEM_NAME Generic)
-set(CMAKE_C_COMPILER_WORKS 1)
-set(CMAKE_CXX_COMPILER_WORKS 1)
-
-project("ESPcam" C CXX)
-
-include(CMakeListsPrivate.txt)
-
-if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/CMakeListsUser.txt)
-include(CMakeListsUser.txt)
-endif()
-
-add_custom_target(
-    Production ALL
-    COMMAND platformio -c clion run "$<$<NOT:$<CONFIG:All>>:-e${CMAKE_BUILD_TYPE}>"
-    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
-)
-
-add_custom_target(
-    Debug ALL
-    COMMAND platformio -c clion debug "$<$<NOT:$<CONFIG:All>>:-e${CMAKE_BUILD_TYPE}>"
-    WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
-)
-
-add_executable(Z_DUMMY_TARGET ${SRC_LIST})
diff --git a/client/ESPcam/CMakeListsPrivate.txt b/client/ESPcam/CMakeListsPrivate.txt
deleted file mode 100644
index 2c27268f2f0e34564668c2926a94775303a907e8..0000000000000000000000000000000000000000
--- a/client/ESPcam/CMakeListsPrivate.txt
+++ /dev/null
@@ -1,305 +0,0 @@
-# !!! WARNING !!! AUTO-GENERATED FILE, PLEASE DO NOT MODIFY IT AND USE
-# https://docs.platformio.org/page/projectconf/section_env_build.html#build-flags
-#
-# If you need to override existing CMake configuration or add extra,
-# please create `CMakeListsUser.txt` in the root of project.
-# The `CMakeListsUser.txt` will not be overwritten by PlatformIO.
-
-
-
-set(CMAKE_CONFIGURATION_TYPES "esp32cam" CACHE STRING "Build Types reflect PlatformIO Environments" FORCE)
-
-# Convert "Home Directory" that may contain unescaped backslashes on Windows
-
-
-SET(CMAKE_C_COMPILER "$ENV{HOME}/.platformio/packages/toolchain-xtensa-esp32/bin/xtensa-esp32-elf-gcc")
-SET(CMAKE_CXX_COMPILER "$ENV{HOME}/.platformio/packages/toolchain-xtensa-esp32/bin/xtensa-esp32-elf-g++")
-SET(CMAKE_CXX_FLAGS "-std=gnu++17 -Wno-frame-address -fexceptions -fno-rtti -mfix-esp32-psram-cache-issue -mlongcalls -ffunction-sections -fdata-sections -Wno-error=unused-function -Wno-error=unused-variable -Wno-error=deprecated-declarations -Wno-unused-parameter -Wno-sign-compare -ggdb -Os -freorder-blocks -Wwrite-strings -fstack-protector -fstrict-volatile-bitfields -Wno-error=unused-but-set-variable -fno-jump-tables -fno-tree-switch-conversion -MMD")
-SET(CMAKE_C_FLAGS "-Wno-frame-address -std=gnu99 -Wno-old-style-declaration -mfix-esp32-psram-cache-issue -mlongcalls -ffunction-sections -fdata-sections -Wno-error=unused-function -Wno-error=unused-variable -Wno-error=deprecated-declarations -Wno-unused-parameter -Wno-sign-compare -ggdb -Os -freorder-blocks -Wwrite-strings -fstack-protector -fstrict-volatile-bitfields -Wno-error=unused-but-set-variable -fno-jump-tables -fno-tree-switch-conversion -MMD")
-
-SET(CMAKE_C_STANDARD 99)
-set(CMAKE_CXX_STANDARD 17)
-
-if (CMAKE_BUILD_TYPE MATCHES "esp32cam")
-    add_definitions(-DPLATFORMIO=60105)
-    add_definitions(-DARDUINO_ESP32_DEV)
-    add_definitions(-DBOARD_HAS_PSRAM)
-    add_definitions(-DCORE_DEBUG_LEVEL=5)
-    add_definitions(-DHAVE_CONFIG_H)
-    add_definitions(-DMBEDTLS_CONFIG_FILE=\"mbedtls/esp_config.h\")
-    add_definitions(-DUNITY_INCLUDE_CONFIG_H)
-    add_definitions(-DWITH_POSIX)
-    add_definitions(-D_GNU_SOURCE)
-    add_definitions(-DIDF_VER=\"v4.4.2\")
-    add_definitions(-DESP_PLATFORM)
-    add_definitions(-D_POSIX_READER_WRITER_LOCKS)
-    add_definitions(-DARDUINO_ARCH_ESP32)
-    add_definitions(-DESP32)
-    add_definitions(-DF_CPU=240000000L)
-    add_definitions(-DARDUINO=10812)
-    add_definitions(-DARDUINO_VARIANT=\"esp32\")
-    add_definitions(-DARDUINO_BOARD=\"AI\ Thinker\ ESP32-CAM\")
-    add_definitions(-DARDUINO_PARTITION_default)
-
-    include_directories("${CMAKE_CURRENT_LIST_DIR}/include")
-    include_directories("${CMAKE_CURRENT_LIST_DIR}/src")
-    include_directories("$ENV{HOME}/GitRepos/sensor-system/client/libs/sht85")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/SD_MMC/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/FS/src")
-    include_directories("$ENV{HOME}/GitRepos/sensor-system/client/libs/espnow/src")
-    include_directories("$ENV{HOME}/GitRepos/sensor-system/client/libs/includes")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/WiFi/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/Preferences/src")
-    include_directories("$ENV{HOME}/GitRepos/sensor-system/client/libs/caching/src")
-    include_directories("$ENV{HOME}/GitRepos/sensor-system/client/libs/time/src")
-    include_directories("${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/esp32cam/ArduinoJson/src")
-    include_directories("${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/esp32cam/ESP32Time")
-    include_directories("${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/esp32cam/RTClib/src")
-    include_directories("${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/esp32cam/Adafruit BusIO")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/SPI/src")
-    include_directories("${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/esp32cam/arduino-sht")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/Wire/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/newlib/platform_include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freertos/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freertos/include/esp_additions/freertos")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freertos/port/xtensa/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freertos/include/esp_additions")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/include/soc")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/include/soc/esp32")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/port/esp32")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hw_support/port/esp32/private_include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/heap/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/log/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/include/apps")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/include/apps/sntp")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/lwip/src/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/port/esp32/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/lwip/port/esp32/include/arch")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/soc/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/soc/esp32")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/soc/esp32/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/hal/esp32/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/hal/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/hal/platform_port/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_rom/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_rom/include/esp32")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_rom/esp32")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_common/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_system/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_system/port/soc")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_system/port/public_compat")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp32/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/xtensa/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/xtensa/esp32/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/driver/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/driver/esp32/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_pm/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_ringbuf/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/efuse/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/efuse/esp32/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/vfs/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_wifi/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_event/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_netif/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_eth/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/tcpip_adapter/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_phy/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_phy/esp32/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_ipc/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/app_trace/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_timer/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mbedtls/port/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mbedtls/mbedtls/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mbedtls/esp_crt_bundle/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/app_update/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/spi_flash/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bootloader_support/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nvs_flash/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/pthread/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_gdbstub/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_gdbstub/xtensa")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_gdbstub/esp32")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espcoredump/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/espcoredump/include/port/xtensa")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wpa_supplicant/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wpa_supplicant/port/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wpa_supplicant/esp_supplicant/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/ieee802154/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/console")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/asio/asio/asio/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/asio/port/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/common/osi/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/include/esp32/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/common/api/include/api")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/common/btc/profile/esp/blufi/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/common/btc/profile/esp/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/host/bluedroid/api/include/api")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_common/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_common/tinycrypt/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_core")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_core/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_core/storage")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/btc/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_models/common/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_models/client/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/mesh_models/server/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/api/core/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/api/models/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/bt/esp_ble_mesh/api")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/cbor/port/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/unity/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/unity/unity/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/cmock/CMock/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/coap/port/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/coap/libcoap/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/port/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/nghttp/nghttp2/lib/includes")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-tls")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-tls/esp-tls-crypto")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_adc_cal/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_hid/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/tcp_transport/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_http_client/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_http_server/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_https_ota/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_https_server/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_lcd/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_lcd/interface")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/protobuf-c/protobuf-c")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/protocomm/include/common")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/protocomm/include/security")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/protocomm/include/transports")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mdns/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_local_ctrl/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/sdmmc/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_serial_slave_link/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_websocket_client/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/expat/expat/expat/lib")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/expat/port/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wear_levelling/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/fatfs/diskio")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/fatfs/vfs")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/fatfs/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/freemodbus/common/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/idf_test/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/idf_test/include/esp32")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/jsmn/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/json/cJSON")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/libsodium/libsodium/src/libsodium/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/libsodium/port_include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/mqtt/esp-mqtt/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/openssl/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/perfmon/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/spiffs/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/ulp/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/wifi_provisioning/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/rmaker_common/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/json_parser/upstream/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/json_parser/upstream")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/json_generator/upstream")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_schedule/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_rainmaker/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/gpio_button/button/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/qrcode/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/ws2812_led")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/dotprod/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/support/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/windows/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/windows/hann/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/windows/blackman/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/windows/blackman_harris/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/windows/blackman_nuttall/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/windows/nuttall/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/windows/flat_top/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/iir/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/fir/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/math/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/math/add/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/math/sub/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/math/mul/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/math/addc/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/math/mulc/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/math/sqrt/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/matrix/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/fft/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/dct/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/conv/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/common/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/kalman/ekf/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dsp/modules/kalman/ekf_imu13states/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp_littlefs/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/tool")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/typedef")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/image")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/math")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/nn")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/layer")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/detect")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-dl/include/model_zoo")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-sr/src/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-sr/esp-tts/esp_tts_chinese/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp-sr/include/esp32")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp32-camera/driver/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp32-camera/conversions/include")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/fb_gfx/include")
-    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")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/AsyncUDP/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/BLE/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/BluetoothSerial/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/DNSServer/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/EEPROM/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/ESP32/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/ESPmDNS/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/Ethernet/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/FFat/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/HTTPClient/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/HTTPUpdate/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/HTTPUpdateServer/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/I2S/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/LittleFS/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/NetBIOS/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/RainMaker/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/SD/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/SPIFFS/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/SimpleBLE/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/Ticker/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/USB/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/Update/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/WebServer/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/WiFiClientSecure/src")
-    include_directories("$ENV{HOME}/.platformio/packages/framework-arduinoespressif32/libraries/WiFiProv/src")
-    include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/include/c++/8.4.0")
-    include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/include/c++/8.4.0/xtensa-esp32-elf")
-    include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa-esp32/lib/gcc/xtensa-esp32-elf/8.4.0/include-fixed")
-    include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa-esp32/lib/gcc/xtensa-esp32-elf/8.4.0/include")
-    include_directories("$ENV{HOME}/.platformio/packages/toolchain-xtensa-esp32/xtensa-esp32-elf/include")
-
-    FILE(GLOB_RECURSE EXTRA_LIB_SOURCES
-        ${CMAKE_CURRENT_LIST_DIR}/.pio/libdeps/esp32cam/*.*
-        $ENV{HOME}/GitRepos/sensor-system/client/libs/*.*
-    )
-endif()
-
-
-FILE(GLOB_RECURSE SRC_LIST
-    ${CMAKE_CURRENT_LIST_DIR}/src/*.*
-    ${CMAKE_CURRENT_LIST_DIR}/lib/*.*
-    ${CMAKE_CURRENT_LIST_DIR}/test/*.*
-)
-
-list(APPEND SRC_LIST ${EXTRA_LIB_SOURCES})
diff --git a/client/ESPcam/platformio.ini b/client/ESPcam/platformio.ini
index 835183a1a921563ea8720791c13a22e3cdafd9dd..6a98c59f1074e53cfe8f80b9c0efe782cd5f6ceb 100644
--- a/client/ESPcam/platformio.ini
+++ b/client/ESPcam/platformio.ini
@@ -14,6 +14,7 @@ board = esp32cam
 framework = arduino
 monitor_speed = 115200
 lib_ldf_mode = deep
+monitor_port = /dev/ttyACM1
 lib_extra_dirs =
   ../libs
   ../../shared-libs
diff --git a/client/client_central_mast/src/main.cpp b/client/client_central_mast/src/main.cpp
index c1cdd98da0cee65b8520472999c78d70ec7d442a..310ce035e0d930161b79110cc86968c281851b24 100644
--- a/client/client_central_mast/src/main.cpp
+++ b/client/client_central_mast/src/main.cpp
@@ -1,134 +1,118 @@
 #include "Arduino.h"
 #include "ESPNow.hpp"
 #include "NoDataAvailableException.hpp"
+#include "SentecRainGaugeSensor.h"
 #include "rs485.hpp"
-#include <list>
 #include <ina219.hpp>
 
 static const char *TAG = "MAIN";
 
 #define uS_TO_S_FACTOR 1000000 /* Conversion factor for micro seconds to seconds */
-#define TIME_TO_SLEEP 5 * 1   /* Time ESP32 will go to sleep (in seconds) */
+#define TIME_TO_SLEEP 0 * 1    /* Time ESP32 will go to sleep (in seconds) */
 
-Forte_RS485 rs485;
+ForteRS485 rs485;
 ForteINA219 ina219;
+SEM404 rainGaugeSensor = SEM404(2, 19);
 
 float getBatteryVoltage() {
-  //************ Measuring Battery Voltage ***********
-  // reference voltage of microcontroller 3.3v for esp32
-  const float reference_vcc = 3.3;
-  // value of R2 resistor [kOhm]
-  const float bat_res_gnd = 20;
-  // value of R1 resistor [kOhm]
-  const float bat_res_vcc = 68;
-  // max ADC value
-  const int adc = 4095;
-  float sample = 0;
-  // Get 100 analog read to prevent unusefully read
-  for (int i = 0; i < 100; i++) {
-    sample =
-        sample + analogRead(35); // read the voltage from the divider circuit
-    delay(2);
-  }
-  sample = sample / 100;
-  float battery_voltage =
-      (sample / 4095 * reference_vcc * (bat_res_vcc + bat_res_gnd)
-          / bat_res_gnd);
-  ESP_LOGI(TAG, "Battery Voltage: %4.2f V", battery_voltage);
-  ESP_LOGD(TAG, "ADC mean Value:  %4.2f", sample);
-  return battery_voltage;
-}
-
-// FIXME: put this in ESPNow.hpp and let stupid Markus Rampp know how you did it. After years of Python he moved past
-// the idea of types and declarations
-void send_msgs(const std::__cxx11::list<Message> msgs) {
-  for (const Message &msg: msgs) {
-
-    if (msg.send() != ESP_OK) {
-      RtcMemory::store_data(msg.getMessageAsMinifiedJsonString());
+    //************ Measuring Battery Voltage ***********
+    // reference voltage of microcontroller 3.3v for esp32
+    const float reference_vcc = 3.3;
+    // value of R2 resistor [kOhm]
+    const float bat_res_gnd = 20;
+    // value of R1 resistor [kOhm]
+    const float bat_res_vcc = 68;
+    // max ADC value
+    const int adc = 4095;
+    float sample = 0;
+    // Get 100 analog read to prevent unusefully read
+    for (int i = 0; i < 100; i++) {
+        sample = sample + analogRead(35); // read the voltage from the divider circuit
+        delay(2);
     }
-    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) {
-        RtcMemory::store_data(msg.getMessageAsMinifiedJsonString());
-        ESP_LOGE(TAG, "Timeout: Host not available\n");
-        break;
-      }
-    }
-    ESP_LOGD(TAG, "Time until acknowledgement: %ld", millis() - ts);
-  }
+    sample = sample / 100;
+    float battery_voltage = (sample / 4095 * reference_vcc * (bat_res_vcc + bat_res_gnd) / bat_res_gnd);
+    ESP_LOGI(TAG, "Battery Voltage: %4.2f V", battery_voltage);
+    ESP_LOGD(TAG, "ADC mean Value:  %4.2f", sample);
+    return battery_voltage;
 }
 
 void setup() {
-  // whole loop should be around ~3000 ms
-  Serial.begin(115200);
-  rs485.setup();
-
-  getBatteryVoltage();
-
-
-  ina219.setup();
-  ina219.setPinSetup({21, 22});
-
-  // ~2100ms
-  try {
-    auto messages = rs485.buildMessages();
-    // split into arrays of 6 messages TODO: Make this cleaner with default constructor
-    std::array<Message, 6> messages_1 =
-        {Message::nullMessage(), Message::nullMessage(), Message::nullMessage(),
-         Message::nullMessage(), Message::nullMessage(),
-         Message::nullMessage()};
-    std::array<Message, 6> messages_2 =
-        {Message::nullMessage(), Message::nullMessage(), Message::nullMessage(),
-         Message::nullMessage(), Message::nullMessage(),
-         Message::nullMessage()};
-
-    auto ina219_messages = ina219.buildMessages();
-
-    std::array<Message, 6> ina_array =
-        {Message::nullMessage(), Message::nullMessage(), Message::nullMessage(),
-         Message::nullMessage(), Message::nullMessage(),
-         Message::nullMessage()};
-
-    // log ina messages
-    for (const auto &msg: ina219_messages) {
-      ESP_LOGI(TAG,
-               "INA219 Message: %s",
-               msg.getMessageAsMinifiedJsonString().c_str());
-    }
-
-
-    int i = 0;
-    for (const auto &msg: messages) {
-      if (i < 6) {
-        messages_1[i] = msg;
-      } else {
-        messages_2[i - 6] = msg;
-      }
-      i++;
+    // whole loop should be around ~3000 ms
+    Serial.begin(115200);
+    rs485.setup();
+
+    getBatteryVoltage();
+
+    ina219.setPinSetup({21, 22});
+    ina219.setup();
+
+    try {
+        ForteRS485::powerOnRS485Sensors();
+        auto messages = rainGaugeSensor.buildMessages();
+        ForteRS485::powerOffRS485Sensors();
+        // split into arrays of 6 messages TODO: Make this cleaner with default constructor
+        std::array<Message, 6> messages_1 = {Message::nullMessage(), Message::nullMessage(), Message::nullMessage(),
+                                             Message::nullMessage(), Message::nullMessage(), Message::nullMessage()};
+
+        auto ina219_messages = ina219.buildMessages();
+
+        std::array<Message, 6> ina_array = {Message::nullMessage(), Message::nullMessage(), Message::nullMessage(),
+                                            Message::nullMessage(), Message::nullMessage(), Message::nullMessage()};
+
+        // log ina messages
+        for (const auto &msg : ina219_messages) {
+            ESP_LOGI(TAG, "INA219 Message: %s", msg.getMessageAsMinifiedJsonString().c_str());
+        }
+
+        int i = 0;
+        for (const auto &msg : messages) {
+            if (i < 6) {
+                messages_1[i] = msg;
+            }
+            i++;
+        }
+
+        espnow_setup();
+
+        // demo of how to reset the rain gauge
+#ifdef RESET_RAIN_GAUGE
+        if (messages_1.front().getClientDataPackage().getMeasurementData().getValue() > 20) {
+            ForteRS485::powerOnRS485Sensors();
+            if (rainGaugeSensor.resetPrecipitation() == ErrorType::SEM404_COULD_NOT_RESET_PRECIPITATION) {
+                ESP_LOGE(TAG, "Could not reset precipitation");
+                auto precipitationErrorMessage = Message(
+                    Measurement(ERROR_VALUE, rainGaugeSensor.address, NO_I2C_ADDRESS, MeasurementType::PRECIPITATION,
+                                ErrorType::SEM404_COULD_NOT_RESET_PRECIPITATION),
+                    rainGaugeSensor.getSensorInformation(), Time::getInstance().getEpochSeconds());
+                std::array<Message, 6> messages_error = {precipitationErrorMessage, Message::nullMessage(),
+                                                         Message::nullMessage(),    Message::nullMessage(),
+                                                         Message::nullMessage(),    Message::nullMessage()};
+                Message::sendMessages(messages_error);
+            }
+            ForteRS485::powerOffRS485Sensors();
+        }
+#endif
+
+        i = 0;
+        for (const auto &msg : ina219_messages) {
+            ina_array[i] = msg;
+            i++;
+        }
+
+        Message::sendMessages(messages_1);
+        //    Message::sendMessages(ina_array);
+
+    } catch (const NoDataAvailableException &e) {
+        std::cerr << e.what() << '\n';
     }
 
-    i = 0;
-    for (const auto &msg: ina219_messages) {
-      ina_array[i] = msg;
-      i++;
-    }
-
-    espnow_setup();
-    Message::sendMessages(messages_1);
-    Message::sendMessages(messages_2);
-    Message::sendMessages(ina_array);
-
-  } catch (const NoDataAvailableException &e) {
-    std::cerr << e.what() << '\n';
-  }
+    rs485.teardown();
 
-  ESP_LOGD(TAG, "Going to sleep for %d seconds", TIME_TO_SLEEP);
+    ESP_LOGD(TAG, "Going to sleep for %d seconds", TIME_TO_SLEEP);
 
-  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
-  esp_deep_sleep_start();
+    esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
+    esp_deep_sleep_start();
 }
 
 void loop() {}
diff --git a/client/client_satellite/platformio.ini b/client/client_satellite/platformio.ini
index 1a9a18984b3f34f3cba2b6d992ddf9eb49f61e74..09b747efce058c0311c30e7a0a2468ced411e15a 100644
--- a/client/client_satellite/platformio.ini
+++ b/client/client_satellite/platformio.ini
@@ -4,6 +4,8 @@ board = esp32dev
 framework = arduino
 monitor_speed = 115200
 lib_ldf_mode = deep
+upload_port = /dev/ttyUSB0
+monitor_port = /dev/ttyUSB0
 lib_extra_dirs =
     ../libs
     ../../shared-libs
diff --git a/client/client_satellite/src/main.cpp b/client/client_satellite/src/main.cpp
index 7f729b96215a8e83b8860a8b902c071aac17f50f..770e9204dfdea6fcf01e18dc592d5722b0902315 100644
--- a/client/client_satellite/src/main.cpp
+++ b/client/client_satellite/src/main.cpp
@@ -4,14 +4,16 @@
 #include "dr26.hpp"
 #include "f_deep_sleep.hpp"
 #include <Arduino.h>
+#include <SentecRainGaugeSensor.h>
 #include <list>
+#include <rs485.hpp>
 
 // Execution time:
 // FIXME: Boot: needs to be optimised. should be around 300 ms, can be <100ms
 // https://github.com/makermoekoe/Picoclick-C3#speed-up-boot-process
 // Part				[ms]
 // Boot:			 300
-// First setup: 	 150 
+// First setup: 	 150
 // Data aquisition:  500	(4 Dendrometers)
 // ESPNow setup: 	 220
 // Sending 			 580
@@ -26,105 +28,118 @@ static const char *TAG = "MAIN";
 
 LC709203F battery_monitor;
 
+#define RS485Serial Serial2
+#define RE_DE_PIN 19 // Line to pull high or low to receive or send data from RS485
+
+#define RXPin 14 // Serial Receive pin
+#define TXPin 15 // Serial Transmit pin
+
+#define POWER_SWITCH_PIN_12V 12
+#define POWER_SWITCH_PIN_5V 13
+
+ForteRS485 rs485;
+SEM404 rainGaugeSensor{2, RE_DE_PIN};
+
 ForteDR26 dr26_channel0;
 ForteDR26 dr26_channel3;
 ForteDR26 dr26_channel1;
 ForteDR26 dr26_channel2;
 
-void send_msgs(const std::__cxx11::list<Message> msgs)
-{
-	for (const Message &msg : msgs) {
-
-		if (msg.send() != ESP_OK) {
-			RtcMemory::store_data(msg.getMessageAsMinifiedJsonString());
-		}
-		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) {
-				RtcMemory::store_data(msg.getMessageAsMinifiedJsonString());
-				ESP_LOGE(TAG, "Timeout: Host not available\n");
-				break;
-			}
-		}
-		ESP_LOGD(TAG, "Time until acknowledgement: %ld", millis() - ts);
-	}
-}
 // one loop takes ~2200 ms
-void setup()
-{
-	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);
-
-	battery_monitor.begin();
-
-	DeepSleep::print_wakeup_reason();
-	DeepSleep::bootCount++;
-	ESP_LOGD(TAG, "Boot number: %d", DeepSleep::bootCount);
-	// battery protection: go to deep sleep for unlimited time when voltage less than 3.2V
-	if (battery_monitor.cellVoltage_mV() < 3200) {
-		battery_monitor.setPowerMode(LC709203F_POWER_SLEEP);
-		esp_deep_sleep_start();
-	}
-
-	gpio_set_level(GPIO_NUM_32, 1);
-	// delay(100);
-	dr26_channel1.setup();
-	dr26_channel0.setChannel(0);
-	dr26_channel1.setChannel(1);
-	dr26_channel2.setChannel(2);
-	dr26_channel3.setChannel(3);
-
-	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 = dr26_channel0.buildMessages();
-		auto messages1 = dr26_channel1.buildMessages();
-		auto messages2 = dr26_channel2.buildMessages();
-		auto messages3 = dr26_channel3.buildMessages();
-		auto messages4 = battery_monitor.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);
-		gpio_set_level(GPIO_NUM_32, 0);
-
-		// FIXME: put this outside the try loop?
-		ts = millis();
-		espnow_setup();
-		ESP_LOGD(TAG, "EPSNow setup took %ld ms", millis() - ts);
-		ts = millis();
-		send_msgs(messages0);
-		send_msgs(messages1);
-		send_msgs(messages2);
-		send_msgs(messages3);
-		send_msgs(messages4);
-		// roughly takes 3s in ideal conditions
-		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_monitor.setPowerMode(LC709203F_POWER_SLEEP);
-	// battery protection: go to deep sleep for unlimited time when voltage less than 3.2V
-	if (battery_monitor.cellVoltage_mV() > 3200) {
-		DeepSleep::deep_sleep(10 * 60);
-	} else {
-		esp_deep_sleep_start();
-	}
+void setup() {
+    unsigned long ts = millis();
+    Serial.begin(115200);
+    rs485.setup();
+    // 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);
+
+    battery_monitor.begin();
+
+    DeepSleep::print_wakeup_reason();
+    DeepSleep::bootCount++;
+    ESP_LOGD(TAG, "Boot number: %d", DeepSleep::bootCount);
+    // battery protection: go to deep sleep for unlimited time when voltage less than 3.2V
+    if (battery_monitor.cellVoltage_mV() < 3200) {
+        battery_monitor.setPowerMode(LC709203F_POWER_SLEEP);
+        esp_deep_sleep_start();
+    }
+
+    gpio_set_level(GPIO_NUM_32, 1);
+    // delay(100);
+    dr26_channel1.setup();
+    dr26_channel0.setChannel(0);
+    dr26_channel1.setChannel(1);
+    dr26_channel2.setChannel(2);
+    dr26_channel3.setChannel(3);
+
+    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 = dr26_channel0.buildMessages();
+        //    auto messages1 = dr26_channel1.buildMessages();
+        //    auto messages2 = dr26_channel2.buildMessages();
+        //    auto messages3 = dr26_channel3.buildMessages();
+        //    auto messages4 = battery_monitor.buildMessages();
+        ForteRS485::powerOnRS485Sensors();
+        auto rainMessage = rainGaugeSensor.buildMessages();
+        ForteRS485::powerOffRS485Sensors();
+        // 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);
+        gpio_set_level(GPIO_NUM_32, 0);
+
+        //    std::array<Message, 6> messages =
+        //        {messages0.front(), messages1.front(), messages2.front(),
+        //         messages3.front(), messages4.front(), rainMessage.front()};
+        std::array<Message, 6> messages = {Message::nullMessage(), Message::nullMessage(), Message::nullMessage(),
+                                           Message::nullMessage(), Message::nullMessage(), rainMessage.front()};
+
+        ts = millis();
+        espnow_setup();
+        ESP_LOGD(TAG, "EPSNow setup took %ld ms", millis() - ts);
+
+        if (messages.back().getClientDataPackage().getMeasurementData().getValue() > 20) {
+            ForteRS485::powerOnRS485Sensors();
+            if (rainGaugeSensor.resetPrecipitation() == ErrorType::SEM404_COULD_NOT_RESET_PRECIPITATION) {
+                ESP_LOGE(TAG, "Could not reset precipitation");
+                auto precipitationErrorMessage = Message(
+                    Measurement(ERROR_VALUE, rainGaugeSensor.address, NO_I2C_ADDRESS, MeasurementType::PRECIPITATION,
+                                ErrorType::SEM404_COULD_NOT_RESET_PRECIPITATION),
+                    rainGaugeSensor.getSensorInformation(), Time::getInstance().getEpochSeconds());
+                std::array<Message, 6> messages_error = {precipitationErrorMessage, Message::nullMessage(),
+                                                         Message::nullMessage(),    Message::nullMessage(),
+                                                         Message::nullMessage(),    Message::nullMessage()};
+                Message::sendMessages(messages_error);
+            }
+            ForteRS485::powerOffRS485Sensors();
+        }
+
+        ts = millis();
+        Message::sendMessages(messages);
+        // roughly takes 3s in ideal conditions
+        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_monitor.setPowerMode(LC709203F_POWER_SLEEP);
+    // battery protection: go to deep sleep for unlimited time when voltage less than 3.2V
+    if (battery_monitor.cellVoltage_mV() > 3200) {
+        DeepSleep::deep_sleep(2);
+    } else {
+        esp_deep_sleep_start();
+    }
 }
 
 void loop() {}
\ No newline at end of file
diff --git a/client/libs/SentecSensors/SentecRainGaugeSensor.cpp b/client/libs/SentecSensors/SentecRainGaugeSensor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..716c129743f2c68002b277c90b5af82ee505751c
--- /dev/null
+++ b/client/libs/SentecSensors/SentecRainGaugeSensor.cpp
@@ -0,0 +1,61 @@
+//
+// Created by zoe on 2/20/23.
+//
+
+#include "SentecRainGaugeSensor.h"
+
+static const char *TAG = "SEM404";
+
+ErrorType SEM404::resetPrecipitation() {
+    // clears rainfall rata from the rain gauge
+    // delay resetting after the last register reading
+    delay(100);
+    Serial.println("Resetting precipitation sum");
+    auto writeRegisterReturn = writeRegister(0x00, 0x5A);
+
+    // other errors like not connected will be shared when reading out the sensor
+    if (!isAnswerFrameEqualToQueryFrame(answerFrame, writeRegisterReturn.writtenQuery)) {
+        ESP_LOGE(TAG, "Could not reset precipitation");
+        return ErrorType::SEM404_COULD_NOT_RESET_PRECIPITATION;
+    }
+
+    return writeRegisterReturn.errorType;
+}
+
+void SEM404::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
+}
+out_data_rain_gauge SEM404::getInstantaneousPrecipitation() {
+    // gets tips of scale since the last reset, i.e. total precipitation (I THINK)
+    //   manual says this is current precipitation - is it?
+    auto error = readRegister(0, 0x01);
+    precipitation = word(answerFrame[3], answerFrame[4]);
+
+    ESP_LOGI("RainGauge", "Precipitation: %s mm", getPrecipitationStr().c_str());
+    // resetPrecipitation();
+    return {static_cast<float>(precipitation), error};
+}
+String SEM404::getPrecipitationStr() {
+    return getValueStr((float)(precipitation / 10.0));
+}
+
+SensorInformation SEM404::getSensorInformation() const {
+    return {HardwareName::SEM404, SensorProtocol::RS485};
+}
+std::list<Message> SEM404::buildMessages() {
+    auto messages = std::list<Message>();
+    auto data = getInstantaneousPrecipitation();
+    Measurement precipitationMeasurement{data.precipitation, address, NO_I2C_ADDRESS, MeasurementType::PRECIPITATION,
+                                         data.precipitationError};
+    messages.emplace_back(precipitationMeasurement, getSensorInformation(), Time::getInstance().getEpochSeconds());
+    return messages;
+}
+out_data_rain_gauge SEM404::readData() {
+    return getInstantaneousPrecipitation();
+}
+void SEM404::setup() {}
diff --git a/client/libs/SentecSensors/SentecRainGaugeSensor.h b/client/libs/SentecSensors/SentecRainGaugeSensor.h
new file mode 100644
index 0000000000000000000000000000000000000000..521459d1219209f30caa2c8bd0266a917ba0b328
--- /dev/null
+++ b/client/libs/SentecSensors/SentecRainGaugeSensor.h
@@ -0,0 +1,51 @@
+//
+// Created by zoe on 2/20/23.
+//
+
+#ifndef CLIENT_CENTRAL_MAST_SENTECRAINGAUGESENSOR_H
+#define CLIENT_CENTRAL_MAST_SENTECRAINGAUGESENSOR_H
+
+#include "SentecSensorsRS485.h"
+#include <ForteSensor.hpp>
+#include <Message.hpp>
+
+struct out_data_rain_gauge {
+    float precipitation;
+    ErrorType precipitationError;
+};
+
+/**
+ * @brief Class to read data from the Sentec rain gauge sensor (SEM404)
+ * @implements ForteSensor<out_data_rain_gauge>
+ * @extends SentecSensorRS485
+ */
+class SEM404 : public SentecSensorRS485, ForteSensor<out_data_rain_gauge> {
+  public:
+    using SentecSensorRS485::SentecSensorRS485;
+    SEM404() : SentecSensorRS485(0) {}
+    // precipitation values [mm]
+    unsigned int precipitation = 0; // prcp since reset? (I THINK!!!)
+
+    /**
+     * @brief Reset the precipitation value
+     * @return ErrorType. If the reset was unsuccessful, this will return ErrorType::SEM404_RESET_PRECIPITATION_ERROR.
+     * Otherwise it returns the error given from the device
+     */
+    ErrorType resetPrecipitation();
+
+    void resetSensor();
+
+    /**
+     * @brief Get the instantaneous precipitation value
+     * @return out_data_rain_gauge
+     */
+    out_data_rain_gauge getInstantaneousPrecipitation();
+
+    String getPrecipitationStr();
+
+    void setup() override;
+    out_data_rain_gauge readData() override;
+    std::list<Message> buildMessages() override;
+    [[nodiscard]] SensorInformation getSensorInformation() const override;
+};
+#endif // CLIENT_CENTRAL_MAST_SENTECRAINGAUGESENSOR_H
diff --git a/client/libs/SentecSensors/SentecSensors.h b/client/libs/SentecSensors/SentecSensors.h
deleted file mode 100644
index 55fb834cdc770fd43edfff579a1f3f5ce08d5af1..0000000000000000000000000000000000000000
--- a/client/libs/SentecSensors/SentecSensors.h
+++ /dev/null
@@ -1,97 +0,0 @@
-#ifndef SENTECSENSORS_H
-#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);
-
-    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;
-
-    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();
-};
-
-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();
-};
-
-#endif
diff --git a/client/libs/SentecSensors/SentecSensors.cpp b/client/libs/SentecSensors/SentecSensorsRS485.cpp
similarity index 50%
rename from client/libs/SentecSensors/SentecSensors.cpp
rename to client/libs/SentecSensors/SentecSensorsRS485.cpp
index 4029f3dcd049c916a852f92f2cc6ca279d015e59..a3a090321c22b5ea04f7d7ff607725768936385f 100644
--- a/client/libs/SentecSensors/SentecSensors.cpp
+++ b/client/libs/SentecSensors/SentecSensorsRS485.cpp
@@ -1,19 +1,18 @@
 #include "NoDataAvailableException.hpp"
-#include <SentecSensors.h>
+#include "SentecRainGaugeSensor.h"
+#include <SentecSensorsRS485.h>
 
 /***************************************
  *          RS485 SENSOR READOUT
  ****************************************/
 static const char *TAG = "SENTEC";
 
-SentecSensorRS485::SentecSensorRS485(HardwareSerial *ser, byte add) {
+SentecSensorRS485::SentecSensorRS485(byte add) {
     address = add;
-    RS485 = ser;
 }
 
-SentecSensorRS485::SentecSensorRS485(HardwareSerial *ser, byte add, uint8_t serialControlPin) {
+SentecSensorRS485::SentecSensorRS485(byte add, uint8_t serialControlPin) {
     address = add;
-    RS485 = ser;
     serialCommunicationControlPin = serialControlPin;
 }
 
@@ -30,19 +29,11 @@ void SentecSensorRS485::write(byte queryFrame[], int length) {
 }
 
 String SentecSensorRS485::getValueStr(float value) {
-    if (valid) {
-        return String(value, 1);
-    } else {
-        return String("null");
-    }
+    return String(value, 1);
 }
 
 String SentecSensorRS485::getValueStr(int value) {
-    if (valid) {
-        return String(value);
-    } else {
-        return String("null");
-    }
+    return String(value);
 }
 
 ErrorType SentecSensorRS485::queryAddress() {
@@ -81,7 +72,7 @@ ErrorType SentecSensorRS485::readRegister(int registerStartAddress, int register
     return getResponse();
 }
 
-ErrorType SentecSensorRS485::writeRegister(int registerAddress, int value) {
+WriteRegisterReturnType SentecSensorRS485::writeRegister(int registerAddress, int value) {
     // function code 0x06: change sensor settings
     // e.g. a new address, reset rainfal data...
 
@@ -99,96 +90,123 @@ ErrorType SentecSensorRS485::writeRegister(int registerAddress, int value) {
     ESP_LOGD(TAG, "Query (settings):    ");
     printBytes(query, 8);
     write(query, sizeof(query));
-    return getResponse();
+    return {getResponse(), {query[0], query[1], query[2], query[3], query[4], query[5], query[6], query[7]}};
 }
 
 ErrorType SentecSensorRS485::setAddress(byte add) {
     // change the address of a sensor
-    ErrorType tmp = writeRegister(word(0x07, 0xD0), add);
-    if (tmp == ErrorType::DATA_OK)
+    WriteRegisterReturnType tmp = writeRegister(word(0x07, 0xD0), add);
+    if (tmp.errorType == ErrorType::DATA_OK)
         address = add;
-    // TODO check response: matches the sent message exactly
-    return tmp;
+
+    if (!isAnswerFrameEqualToQueryFrame(answerFrame, tmp.writtenQuery)) {
+        return ErrorType::COULD_NOT_SET_ADDRESS;
+    }
+
+    return tmp.errorType;
 }
 
 void SentecSensorRS485::resetAnswerFrame() {
-    for (int i = 0; i < 10; i++) {
-        answerFrame[i] = 0;
+    for (unsigned char &i : answerFrame) {
+        i = 0;
     }
 }
 
 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++) {
+    for (size_t tries = 1; 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,
-                 "-----------------------------------------------------------------------------------------");
+        readRS485(idx, responseLength);
+
         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;
-        }
+
+        // TODO: Test this @future_zoe
+        returnCode = checkForErrors(idx, responseLength);
+
         // breaking after first successfull try
         if (returnCode == ErrorType::DATA_OK) {
             break;
         }
     }
 
-    // ESP_LOGE(TAG, "Returncode: %d", returnCode);
     return returnCode;
 }
 
+ErrorType SentecSensorRS485::checkForErrors(int idx, int responseLength) {
+    // TODO: Not optimal, has precedence
+    auto connectionEndedPrematurelyReturnCode = checkConnectionEndedPrematurely(idx, responseLength);
+    auto sensorConnectedReturnCode = checkSensorConnected();
+    auto crcReturnCode = checkCRC(responseLength);
+
+    if (sensorConnectedReturnCode != ErrorType::DATA_OK) {
+        return sensorConnectedReturnCode;
+    } else if (connectionEndedPrematurelyReturnCode != ErrorType::DATA_OK) {
+        return connectionEndedPrematurelyReturnCode;
+    } else if (crcReturnCode != ErrorType::DATA_OK) {
+        return crcReturnCode;
+    }
+    return ErrorType::DATA_OK;
+}
+
+ErrorType SentecSensorRS485::checkCRC(int responseLength) {
+    word crc_received = word(answerFrame[responseLength - 2], answerFrame[responseLength - 1]);
+    word crc = calculateCRC(answerFrame, responseLength - 2);
+    if (crc_received != word(crc)) {
+        ESP_LOGE(TAG, "CRC wrong: Expected 0x%s got 0x%s", formatBytes(crc).c_str(), formatBytes(crc_received).c_str());
+        return ErrorType::WRONG_CRC;
+    }
+    return ErrorType::DATA_OK;
+}
+
+ErrorType SentecSensorRS485::checkConnectionEndedPrematurely(int idx, int responseLength) const {
+    if (idx < responseLength) {
+        ESP_LOGE(TAG, "Response too short: %d bytes < %d bytes. Unfinished transmission.", idx, responseLength);
+        return ErrorType::CONNECTION_ENDED_PREMATURELY;
+    }
+    return ErrorType::DATA_OK;
+}
+
+ErrorType SentecSensorRS485::checkSensorConnected() const {
+    if (answerFrame[0] == 0) {
+        ESP_LOGE(TAG, "Check sensor connection. First byte is 0x00.");
+        return ErrorType::SENSOR_NOT_CONNECTED;
+    }
+    return ErrorType::DATA_OK;
+}
+
+void SentecSensorRS485::readRS485(int &idx, int &responseLength, const int timeout) {
+    int byteReceived = 0;
+    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++;
+            }
+        }
+    }
+}
+
 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.
@@ -249,76 +267,18 @@ std::string SentecSensorRS485::formatBytes(byte *data, int length) {
 }
 
 std::string SentecSensorRS485::formatBytes(word data) {
-    byte arr[2] = {data >> 8, data & 0xFF};
+    byte arr[2] = {static_cast<byte>(data >> 8), static_cast<byte>(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;
-}
-
-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::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]);
-
-    ESP_LOGI(TAG, "Precipitation: %.1f mm", precipitation / 10.0);
-    // resetPrecipitation();
-    return precipitation;
-}
-
-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;
+bool SentecSensorRS485::isAnswerFrameEqualToQueryFrame(byte returnedFrame[8], byte queryFrame[8]) {
+    for (int i = 0; i < 8; i++) {
+        if (returnedFrame[i] != queryFrame[i]) {
+            ESP_LOGD(TAG, "Response: 0x%s", formatBytes(returnedFrame, 8).c_str());
+            ESP_LOGD(TAG, "Response: 0x%s", formatBytes(queryFrame, 8).c_str());
+            ESP_LOGE("TEST", "Error: returnedFrame[%d] != ret.writtenQuery[%d]", i, i);
+            return false;
+        }
     }
-    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;
-}
-
-String SoilMoistureSensor::getMoistureStr() {
-    return getValueStr((float) ((moistureRaw - moistureOffset) / 10.0));
-}
-
-String SoilMoistureSensor::getTemperatureStr() {
-    return getValueStr((float) ((temperatureRaw - temperatureOffset) / 10.0));
-}
+    return true;
+}
\ No newline at end of file
diff --git a/client/libs/SentecSensors/SentecSensorsRS485.h b/client/libs/SentecSensors/SentecSensorsRS485.h
new file mode 100644
index 0000000000000000000000000000000000000000..cab2500853625f2763b296e73d75d9f106d6b236
--- /dev/null
+++ b/client/libs/SentecSensors/SentecSensorsRS485.h
@@ -0,0 +1,86 @@
+#ifndef SENTECSENSORS_H
+#define SENTECSENSORS_H
+
+#include <Arduino.h>
+#include <ErrorTypes.h>
+#include <HardwareNames.h>
+#include <RS485HardwareSerial.h>
+#include <SensorInformation.hpp>
+#include <memory>
+
+struct WriteRegisterReturnType {
+    ErrorType errorType;
+    byte writtenQuery[8];
+};
+
+class SentecSensorRS485 {
+  public:
+    byte address;
+    uint8_t serialCommunicationControlPin = 19;
+    std::shared_ptr<HardwareSerial> RS485 = RS485HardwareSerial::getInstance().getRS485Serial();
+    byte answerFrame[10] = {0};
+
+    SentecSensorRS485(byte add);
+
+    SentecSensorRS485(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);
+
+    WriteRegisterReturnType writeRegister(int registerAddress, int value);
+
+    /**
+     * @brief Set the address of the sensor
+     * @param add The new address of the sensor
+     * @return ErrorType. If the address was not set correctly, the error type is set to
+     * ErrorType::COULD_NOT_SET_ADDRESS
+     */
+    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);
+
+  protected:
+    /**
+     * @brief Check if the answer frame is equal to the query frame. ONLY CHECKS THE FIRST 8 BYTES
+     * @param returnedFrame The frame returned from the device
+     * @param queryFrame The frame sent to the device
+     * @return true if the answer frame is equal to the query frame
+     */
+    bool isAnswerFrameEqualToQueryFrame(byte *returnedFrame, byte *queryFrame);
+
+  private:
+    /**
+     * @brief Read the response from the RS485 bus
+     * @param[in, out] idx The index of the response
+     * @param[in, out] responseLength The length of the response
+     * @param timeout The timeout in ms. Default is 2000ms
+     */
+    void readRS485(int &idx, int &responseLength, const int timeout = 2000);
+    ErrorType checkSensorConnected() const;
+    ErrorType checkConnectionEndedPrematurely(int idx, int responseLength) const;
+    ErrorType checkCRC(int responseLength);
+    ErrorType checkForErrors(int idx, int responseLength);
+};
+
+#endif
diff --git a/client/libs/SentecSensors/SentecSolarRadiationSensor.cpp b/client/libs/SentecSensors/SentecSolarRadiationSensor.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7082a2c43430da171980d37023fd1275815361fc
--- /dev/null
+++ b/client/libs/SentecSensors/SentecSolarRadiationSensor.cpp
@@ -0,0 +1,32 @@
+//
+// Created by zoe on 3/06/23.
+//
+
+#include "SentecSolarRadiationSensor.h"
+
+String SEM228A::getSolarRadiationStr() {
+    return getValueStr((int)glob);
+}
+
+void SEM228A::setup() {
+    // TODO: check if rs485 serial is active
+}
+
+out_data_solar_radiation SEM228A::readData() {
+    auto error = readRegister(0, 1);
+    glob = word(answerFrame[3], answerFrame[4]);
+    ESP_LOGI("SolarRadiation", "Global solar radiation: %d W/m^2", glob);
+    return {static_cast<float>(glob), error};
+}
+std::list<Message> SEM228A::buildMessages() {
+    auto messages = std::list<Message>();
+    auto data = readData();
+    Measurement solarRadiation{data.solarRadiation, address, NO_I2C_ADDRESS, MeasurementType::SOLAR_RADIATION,
+                               data.solarError};
+    messages.emplace_back(Message{solarRadiation, getSensorInformation(), Time::getInstance().getEpochSeconds()});
+    return messages;
+}
+
+SensorInformation SEM228A::getSensorInformation() const {
+    return SensorInformation(HardwareName::SEM228A, SensorProtocol::RS485);
+}
diff --git a/client/libs/SentecSensors/SentecSolarRadiationSensor.h b/client/libs/SentecSensors/SentecSolarRadiationSensor.h
new file mode 100644
index 0000000000000000000000000000000000000000..3c1edc99a424c89a0f2f28fc863e027e2fa13782
--- /dev/null
+++ b/client/libs/SentecSensors/SentecSolarRadiationSensor.h
@@ -0,0 +1,37 @@
+//
+// Created by zoe on 2/20/23.
+//
+
+#ifndef CLIENT_CENTRAL_MAST_SENTECSOLARRADIATIONSENSOR_H
+#define CLIENT_CENTRAL_MAST_SENTECSOLARRADIATIONSENSOR_H
+
+#include "SentecSensorsRS485.h"
+#include <ForteSensor.hpp>
+
+struct out_data_solar_radiation {
+    float solarRadiation;
+    ErrorType solarError;
+};
+
+/**
+ * @brief Class to read data from the Sentec solar radiation sensor (SEM228A)
+ * @implements ForteSensor<out_data_solar_radiation>
+ * @extends SentecSensorRS485
+ */
+class SEM228A : public SentecSensorRS485, public ForteSensor<out_data_solar_radiation> {
+  public:
+    using SentecSensorRS485::SentecSensorRS485;
+
+    SEM228A() : SentecSensorRS485(0) {}
+    // global radiation [W/m^2]
+    word glob = 0;
+
+    void setup() override;
+    out_data_solar_radiation readData() override;
+    std::list<Message> buildMessages() override;
+    [[nodiscard]] SensorInformation getSensorInformation() const override;
+
+    String getSolarRadiationStr();
+};
+
+#endif // CLIENT_CENTRAL_MAST_SENTECSOLARRADIATIONSENSOR_H
diff --git a/client/libs/dr26_analogue/dr26.cpp b/client/libs/dr26_analogue/dr26.cpp
index c0e7d0ee4959ea87d04043672a35fc82d59e4c2b..ea7f1fb639341812f1ed499a298b67efb7ce2b04 100644
--- a/client/libs/dr26_analogue/dr26.cpp
+++ b/client/libs/dr26_analogue/dr26.cpp
@@ -3,8 +3,11 @@
 static const char *TAG = "DR26";
 
 void ForteDR26::setup() {
+    if (sensorConnected) {
+        ESP_LOGD(TAG, "ADS already initialized");
+        return;
+    }
     Wire.begin();
-
     ads.setGain(GAIN_ONE);
     ads.setDataRate(RATE_ADS1115_8SPS);
     if (ads.begin()) {
@@ -14,8 +17,6 @@ void ForteDR26::setup() {
         ESP_LOGE(TAG, "failed to initialize ADS");
         sensorConnected = false;
     }
-
-    delay(100);
     channel = 0;
 }
 
@@ -23,25 +24,22 @@ Measurement ForteDR26::readData() {
     float volts = 0;
     int16_t adc = 0;
 
+    if (!sensorConnected) {
+        return {ERROR_VALUE, channel, NO_I2C_ADDRESS, MeasurementType::CIRCUMFERENCE_INCREMENT,
+                ErrorType::SENSOR_INIT_FAILED};
+    }
+
     try {
         // 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) {
+    } catch (NoDataAvailableException &e) {
         // 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};
-    }
-
-    if (!sensorConnected) {
-        return {ERROR_VALUE, channel, NO_I2C_ADDRESS, MeasurementType::CIRCUMFERENCE_INCREMENT,
-                ErrorType::SENSOR_INIT_FAILED};
+        return {ERROR_VALUE, channel, NO_I2C_ADDRESS, MeasurementType::CIRCUMFERENCE_INCREMENT, ErrorType::NO_DATA};
     }
 
-    return {volts, channel, NO_I2C_ADDRESS, MeasurementType::CIRCUMFERENCE_INCREMENT,
-            ErrorType::DATA_OK};
+    return {volts, channel, NO_I2C_ADDRESS, MeasurementType::CIRCUMFERENCE_INCREMENT, ErrorType::DATA_OK};
 }
 
 // The following functions change the ADC input range: be careful
@@ -70,9 +68,7 @@ void ForteDR26::setChannel(int c) {
 std::list<Message> ForteDR26::buildMessages() {
     std::list<Message> messages;
     auto data = readData();
-    messages.emplace_back(data,
-                          sensorInformation,
-                          Time::getInstance().getEpochSeconds());
+    messages.emplace_back(data, sensorInformation, Time::getInstance().getEpochSeconds());
     return messages;
 }
 
@@ -80,7 +76,5 @@ SensorInformation ForteDR26::getSensorInformation() const {
     return sensorInformation;
 }
 
-
 // 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 ea209f597917e3aee4a0dd0f2e89394e4833e499..b84b61254a75342681a0c8c890c830d35f631866 100644
--- a/client/libs/dr26_analogue/dr26.hpp
+++ b/client/libs/dr26_analogue/dr26.hpp
@@ -23,7 +23,7 @@ class ForteDR26: public ForteSensor<Measurement> {
   const SensorInformation
       sensorInformation{HardwareName::DRS26, SensorProtocol::Analog};
   int channel;
-  bool sensorConnected = true;
+  bool sensorConnected = false;
 };
 
 #endif
\ No newline at end of file
diff --git a/client/libs/ina219/ina219.cpp b/client/libs/ina219/ina219.cpp
index 1a39ff58e7c28aa573cf864159c5efe18e93ac03..4a0227ad4c51bc9b79e42a25dc96a2866aacfed8 100644
--- a/client/libs/ina219/ina219.cpp
+++ b/client/libs/ina219/ina219.cpp
@@ -46,11 +46,11 @@ std::list<Message> ForteINA219::buildMessages() {
     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(measurements.shuntVoltage_mV, sensorInformation, Time::getInstance().getEpochSeconds());
+    messages.emplace_back(measurements.busVoltage_V, sensorInformation, Time::getInstance().getEpochSeconds());
+    messages.emplace_back(measurements.current_mA, sensorInformation, Time::getInstance().getEpochSeconds());
+    messages.emplace_back(measurements.power_mW, sensorInformation, Time::getInstance().getEpochSeconds());
+    messages.emplace_back(measurements.loadVoltage_V, sensorInformation, Time::getInstance().getEpochSeconds());
 //    messages.emplace_back(ina219OverflowData, sensorInformation, 0); TODO: Do we need this as an extra message?
 
     return messages;
diff --git a/client/libs/rs485/RS485HardwareSerial.h b/client/libs/rs485/RS485HardwareSerial.h
new file mode 100644
index 0000000000000000000000000000000000000000..b5c688c3c4b9fcd6f542b37b98842466fac16656
--- /dev/null
+++ b/client/libs/rs485/RS485HardwareSerial.h
@@ -0,0 +1,53 @@
+//
+// Created by zoe on 3/8/23.
+//
+
+#ifndef CLIENT_CENTRAL_MAST_RS485HARDWARESERIAL_H
+#define CLIENT_CENTRAL_MAST_RS485HARDWARESERIAL_H
+
+
+#include <HardwareSerial.h>
+#include <memory>
+
+/**
+ * @brief Singleton class to get the RS485 serial port
+ * @example std::shared_ptr<HardwareSerial> RS485 = RS485HardwareSerial::getInstance().getRS485Serial();
+
+ */
+class RS485HardwareSerial {
+ public:
+  static RS485HardwareSerial &getInstance()
+  {
+    static RS485HardwareSerial instance; // Guaranteed to be destroyed.
+    // Instantiated on first use.
+    return instance;
+  }
+
+    std::shared_ptr<HardwareSerial> getRS485Serial() {
+        return RS485Serial;
+    }
+
+ private:
+  RS485HardwareSerial() {} // Constructor? (the {} brackets) are needed here.
+
+  const std::shared_ptr<HardwareSerial> RS485Serial = std::make_shared<HardwareSerial>(Serial2);
+
+
+  // C++ 11
+  // =======
+  // We can use the better technique of deleting the methods
+  // we don't want.
+ public:
+  RS485HardwareSerial(RS485HardwareSerial const &) = delete;
+  void operator=(RS485HardwareSerial const &) = delete;
+
+  // Note: Scott Meyers mentions in his Effective Modern
+  //       C++ book, that deleted functions should generally
+  //       be public as it results in better error messages
+  //       due to the compilers behavior to check accessibility
+  //       before deleted status
+
+};
+
+
+#endif //CLIENT_CENTRAL_MAST_RS485HARDWARESERIAL_H
diff --git a/client/libs/rs485/rs485.cpp b/client/libs/rs485/rs485.cpp
index 55f18b6ba21b55729ba6e36f677770f7298135ce..62b749dc5e17f0c1dcc70007a47383dcb51d09ad 100644
--- a/client/libs/rs485/rs485.cpp
+++ b/client/libs/rs485/rs485.cpp
@@ -1,8 +1,11 @@
 #include "rs485.hpp"
+#include "SentecRainGaugeSensor.h"
+#include "SentecSolarRadiationSensor.h"
 // RS485 control
-#define RS485Serial Serial2
-#define RXPin 14 // Serial Receive pin
-#define TXPin 15 // Serial Transmit pin
+//#define RS485Serial Serial2
+
+#define RX_PIN 14 // Serial Receive pin
+#define TX_PIN 15 // Serial Transmit pin
 
 #define RE_DE_PIN 19 // Line to pull high or low to receive or send data from RS485
 
@@ -12,89 +15,61 @@
 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); //.....
-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);
+SEM228A solarSensor(1, RE_DE_PIN);
+SEM404 rainGauge = SEM404(2, RE_DE_PIN);
+
+void ForteRS485::setup() {
+    RS485Serial = RS485HardwareSerial::getInstance().getRS485Serial();
+    // 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, TX_PIN, RX_PIN);
+}
+
+void ForteRS485::teardown() {
+    RS485Serial->end();
+}
+
+out_data_rs485 ForteRS485::readData() {
+    powerOnRS485Sensors();
+
+    out_data_rs485 output{};
+    output.solar = solarSensor.readData();
+    output.precipitation = rainGauge.readData();
+
+    powerOffRS485Sensors();
+    return output;
 }
+void ForteRS485::powerOffRS485Sensors() {
+    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);
+}
+void ForteRS485::powerOnRS485Sensors() { // 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(100);
 }
 
-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(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;
+std::list<Message> ForteRS485::buildMessages() {
+    std::list<Message> messages;
+    out_data_rs485 output = readData();
+
+    Measurement solarRadiation{output.solar.solarRadiation, 1, NO_I2C_ADDRESS, MeasurementType::SOLAR_RADIATION,
+                               output.solar.solarError};
+    Measurement precipitation{output.precipitation.precipitation, 2, NO_I2C_ADDRESS, MeasurementType::PRECIPITATION,
+                              output.precipitation.precipitationError};
+
+    messages.emplace_back(solarRadiation, sensorInformation, Time::getInstance().getEpochSeconds());
+    messages.emplace_back(precipitation, sensorInformation, Time::getInstance().getEpochSeconds());
+
+    return messages;
 }
 
-SensorInformation Forte_RS485::getSensorInformation() const {
-  return sensorInformation;
+SensorInformation ForteRS485::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 7ae7c9287f12f4af6370398495bfa083e9a88a5a..823fecbafcd6a506605f66d02abea4888d231fee 100644
--- a/client/libs/rs485/rs485.hpp
+++ b/client/libs/rs485/rs485.hpp
@@ -1,32 +1,48 @@
 #ifndef _RS485
 #define _RS485
 
-#include <MeasurementTypes.h>
-#include "Message.hpp"
 #include "ForteSensor.hpp"
-#include "SentecSensors.h"
+#include "Message.hpp"
+#include "SentecSensorsRS485.h"
+#include <MeasurementTypes.h>
+#include <RS485HardwareSerial.h>
+#include <SentecRainGaugeSensor.h>
+#include <SentecSolarRadiationSensor.h>
+
+/**
+ * @brief Struct to hold all the data from the RS485 sensors
+ */
 
 struct out_data_rs485 {
-  float solarRadiation;
-  float soilMoisture3;
-  float soilTemperature3;
-  float soilMoisture4;
-  float soilTemperature4;
-  float soilMoisture5;
-  float soilTemperature5;
-  float precipitation;
+    out_data_solar_radiation solar;
+    out_data_rain_gauge 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;
+/**
+ * @brief Class to read data from both the Sentec solar radiation sensor and the Sentec rain gauge sensor at once
+ * This class is required to be instantiated and setup in order to use RS485 communication.
+ */
+class ForteRS485 : public ForteSensor<out_data_rs485> {
+  public:
+    void setup() override;
+    out_data_rs485 readData() override;
+    std::list<Message> buildMessages() override;
+    [[nodiscard]] SensorInformation getSensorInformation() const override;
+    void teardown();
+
+    /**
+     * @brief Power on the RS485 sensors
+     */
+    static void powerOnRS485Sensors();
+
+    /**
+     * @brief Power off the RS485 sensors
+     */
+    static void powerOffRS485Sensors();
 
- private:
-  const SensorInformation
-      sensorInformation{HardwareName::RS485, SensorProtocol::RS485};
+  private:
+    std::shared_ptr<HardwareSerial> RS485Serial;
 
+    const SensorInformation sensorInformation{HardwareName::RS485, SensorProtocol::RS485};
 };
-#endif 
\ No newline at end of file
+#endif
\ No newline at end of file
diff --git a/host/host_central_mast/lib/Utilities/SDCardLogger.cpp b/host/host_central_mast/lib/Utilities/SDCardLogger.cpp
index e35196503a0b10e858b8f32916ae4b2acaef24a3..86735a0abb3396887422d0957024a801c2a5e358 100644
--- a/host/host_central_mast/lib/Utilities/SDCardLogger.cpp
+++ b/host/host_central_mast/lib/Utilities/SDCardLogger.cpp
@@ -13,12 +13,14 @@ namespace SDCardLogger {
         printToSerial = printToSerialAsWell;
     }
     int vprintf_into_sd(const char *szFormat, va_list args) {
-        String logstring = "[" + rtc.getDateTime() + "] ";
-        logstring += szFormat;
+        auto timeSinceBootMs = esp_timer_get_time() / 1000;
+        String logstring = String(timeSinceBootMs) + ", ";
         // print current core
         logstring += "Core: ";
         logstring += xPortGetCoreID();
-        logstring += ". ";
+        logstring += ", ";
+        logstring += "[" + rtc.getDateTime() + "] ";
+        logstring += szFormat;
         if (!SDUtilities::isSDAvailable()) {
             if (printToSerial) {
                 logstring += " (SD card not available)\n";
diff --git a/shared-libs/DataTransfer/ErrorTypes.cpp b/shared-libs/DataTransfer/ErrorTypes.cpp
index 8526b717b36e6328c8c08f5cab1af360112e557d..558d35f4a465320a9d1856eafcf9afaf4852192b 100644
--- a/shared-libs/DataTransfer/ErrorTypes.cpp
+++ b/shared-libs/DataTransfer/ErrorTypes.cpp
@@ -5,37 +5,42 @@
 #include "ErrorTypes.h"
 
 namespace ErrorTypes {
-    // INFO: If you add a new error type, add it here and to the documentation at https://git.uibk.ac.at/informatik/qe/forte/sensor-system/-/wikis/Error-Types as well
+    // INFO: If you add a new error type, add it here and to the documentation at
+    // https://git.uibk.ac.at/informatik/qe/forte/sensor-system/-/wikis/Error-Types as well
     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";
+        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::SEM404_COULD_NOT_RESET_PRECIPITATION:
+            return "SEM404_COULD_NOT_RESET_PRECIPITATION";
+        case ErrorType::COULD_NOT_SET_ADDRESS:
+            return "COULD_NOT_SET_ADDRESS";
+        case ErrorType::UNKNOWN:
+        default:
+            return "UNKNOWN_ERROR_TYPE";
         }
     }
 
-}
\ No newline at end of file
+} // namespace ErrorTypes
\ No newline at end of file
diff --git a/shared-libs/DataTransfer/ErrorTypes.h b/shared-libs/DataTransfer/ErrorTypes.h
index 3d12cbd8bbdc923154322960ed984ef9e734334a..c53c25f13d774540decaba83b2ae2a73741aab16 100644
--- a/shared-libs/DataTransfer/ErrorTypes.h
+++ b/shared-libs/DataTransfer/ErrorTypes.h
@@ -11,6 +11,8 @@ enum class ErrorType : char {
     SENSOR_NOT_FOUND,
     SENSOR_INIT_FAILED,
     SENSOR_NOT_CONNECTED,
+    SEM404_COULD_NOT_RESET_PRECIPITATION,
+    COULD_NOT_SET_ADDRESS,
     NO_DATA,
     DATA_OK,
     NULL_MESSAGE, // message that is sent as padding, should be thrown away
@@ -19,7 +21,7 @@ enum class ErrorType : char {
     INVALID_VALUE,
     INA219_OVERFLOW,
     CONNECTION_ENDED_PREMATURELY, // connection ended prematurely
-    WRONG_CRC, // corrupted data package
+    WRONG_CRC,                    // corrupted data package
     UNKNOWN,
 };
 
@@ -27,5 +29,4 @@ namespace ErrorTypes {
     std::string errorTypeToString(ErrorType errorType);
 }
 
-
-#endif //CLIENT_MOCK_ERRORTYPES_H
+#endif // CLIENT_MOCK_ERRORTYPES_H
diff --git a/shared-libs/DataTransfer/HardwareNames.cpp b/shared-libs/DataTransfer/HardwareNames.cpp
index 72c2256e8833d912ca02021593d71949679ada0f..94fbb405a8e7faf9fe22995f3720d12c9876b849 100644
--- a/shared-libs/DataTransfer/HardwareNames.cpp
+++ b/shared-libs/DataTransfer/HardwareNames.cpp
@@ -4,36 +4,42 @@
 
 #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";
-    }
+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:
+      return "LC709203";
+    case HardwareName::SEM228A:
+      return "SEM228A";
+    case HardwareName::SEM225:
+      return "SEM225";
+    case HardwareName::SEM404:
+      return "SEM404";
+  }
+  return "UNKNOWN_HARDWARE_NAME";
+}
 } // namespace HardwareNames
\ No newline at end of file
diff --git a/shared-libs/DataTransfer/HardwareNames.h b/shared-libs/DataTransfer/HardwareNames.h
index 5bf6930379ab6069940cd6763eb022db8d511287..ee689f81c5fc58f810fc99d83a2cfa6340fa3b34 100644
--- a/shared-libs/DataTransfer/HardwareNames.h
+++ b/shared-libs/DataTransfer/HardwareNames.h
@@ -16,6 +16,9 @@ enum class HardwareName : short {
   SOIL_MOISTURE_SENSOR,
   SOIL_TEMPERATURE_SENSOR,
   SOLAR_RADIATION_SENSOR,
+  SEM404,
+  SEM228A,
+  SEM225,
   SHT85,
   DRS26,
   DR26,
diff --git a/shared-libs/DataTransfer/MeasurementTypes.cpp b/shared-libs/DataTransfer/MeasurementTypes.cpp
index 220da6e1879f570b4faacd47372aea5974bdee7b..6144cc12a8338955307d71a59e7958fc274d92e4 100644
--- a/shared-libs/DataTransfer/MeasurementTypes.cpp
+++ b/shared-libs/DataTransfer/MeasurementTypes.cpp
@@ -47,6 +47,10 @@ std::string measurementTypeToString(MeasurementType measurementType) {
       return "CO2";
     case MeasurementType::NULL_MEASUREMENT:
       return "NULL_MEASUREMENT";
+    case MeasurementType::SOIL_MOISTURE:
+        return "SOIL_MOISTURE";
+    case MeasurementType::SOIL_TEMPERATURE:
+        return "SOIL_TEMPERATURE";
   }
   return "UNKNOWN";
 }
diff --git a/shared-libs/DataTransfer/MeasurementTypes.h b/shared-libs/DataTransfer/MeasurementTypes.h
index 0818bba5453a7223c9f84025bd9608343a6a0672..f642e3b6cca9372cc2d206cf7bd1d27072a33acf 100644
--- a/shared-libs/DataTransfer/MeasurementTypes.h
+++ b/shared-libs/DataTransfer/MeasurementTypes.h
@@ -20,6 +20,8 @@ enum class MeasurementType {
   BATTERY_VOLTAGE,
   MOCK,
   SOLAR_RADIATION,
+  SOIL_MOISTURE,
+  SOIL_TEMPERATURE,
   SOIL_MOISTURE_3,
   SOIL_TEMPERATURE_3,
   SOIL_MOISTURE_4,