diff --git a/.gitignore b/.gitignore
index e71c717b57a0382931bd8b795e3b237582fd3abd..b539c117fcc142b4f55d30a75ce7b212ed68869f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,8 @@ dist/
 downloads/
 eggs/
 .eggs/
+lib/
+!client/client/lib
 lib64/
 parts/
 sdist/
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index 624052346167a882f66736a4bfe43c575afab67f..2e9982bce84aced5e2093c41f9d1f1cd75f16a3e 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -1,12 +1,12 @@
 {
-    "version": "0.1.0",
-    "tasks": [
-        {
-            "taskName": "clang-format-everything",
-            "command": "clang-format",
-            "args": ["-i", "*" ],
-            "isShellCommand": true,
-            "isBackground": true
-        }
-    ]
-}
\ No newline at end of file
+  "version": "0.1.0",
+  "tasks": [
+    {
+      "taskName": "clang-format-everything",
+      "command": "clang-format",
+      "args": ["-i", "*"],
+      "isShellCommand": true,
+      "isBackground": true
+    }
+  ]
+}
diff --git a/client/client/lib/caching/src/ram_caching.cpp b/client/client/lib/caching/src/ram_caching.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9325e7c7909473c998d2a113779d94480fa3589c
--- /dev/null
+++ b/client/client/lib/caching/src/ram_caching.cpp
@@ -0,0 +1,24 @@
+#include "ram_caching.hpp"
+
+RTC_DATA_ATTR int cachedAmount = -1;
+RTC_DATA_ATTR ClientDataPackage backup[NUM_SENSORS];
+
+ClientDataPackage ram_cache_pop()
+{
+	return backup[cachedAmount--];
+}
+
+void ram_cache_push(ClientDataPackage data)
+{
+	backup[++cachedAmount] = data;
+}
+
+bool ram_cache_is_empty()
+{
+	return cachedAmount == -1;
+}
+
+bool ram_cache_is_full()
+{
+	return cachedAmount == 9;
+}
\ No newline at end of file
diff --git a/client/client/lib/caching/src/ram_caching.hpp b/client/client/lib/caching/src/ram_caching.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..466668ba65578e0a9aa3f0af9bf20174889b0eb2
--- /dev/null
+++ b/client/client/lib/caching/src/ram_caching.hpp
@@ -0,0 +1,11 @@
+#ifndef _RAM_CACHE
+#define _RAM_CACHE
+#include "ClientDataPackage.hpp"
+#include <ESP32Time.h>
+
+bool ram_cache_is_empty();
+bool ram_cache_is_full();
+void ram_cache_push(ClientDataPackage data);
+ClientDataPackage ram_cache_pop();
+
+#endif
\ No newline at end of file
diff --git a/client/client/lib/espnow/README b/client/client/lib/espnow/README
new file mode 100644
index 0000000000000000000000000000000000000000..55f89c0b2141283b3dd2d94c882cdaccbe2064fe
--- /dev/null
+++ b/client/client/lib/espnow/README
@@ -0,0 +1,11 @@
+# basic usage
+
+To send data using espnow, create a new Message object,
+then use the add_data(value, identifier) method for every value
+to fill the message.
+when every value is added, use the send() method to send the data
+to the host (fipy). If the esp client has never recieved a config
+message from the host, it will instead broadcast the message.
+
+---
+right now, it is not possible to add more than 10 values.
diff --git a/client/client/lib/espnow/src/ClientDataPackage.hpp b/client/client/lib/espnow/src/ClientDataPackage.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..52f2be6032a190e6346bef71457cb78c983b0038
--- /dev/null
+++ b/client/client/lib/espnow/src/ClientDataPackage.hpp
@@ -0,0 +1,14 @@
+#pragma once
+
+#define NUM_SENSORS 10
+// packing the struct without padding, makes reading it on the fipy easier
+#pragma pack(1)
+
+// having the data be a struct of basic types makes sending easier,
+// otherwise we would have to serialize the data before sending
+struct ClientDataPackage {
+	int identifiers[NUM_SENSORS];
+	float values[NUM_SENSORS];
+	int amountData;
+	long timestamp; // maybe make this array
+};
diff --git a/client/client/lib/espnow/src/ESPNow.cpp b/client/client/lib/espnow/src/ESPNow.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..e52930604dace5db905876e9ffcdc12642e943bf
--- /dev/null
+++ b/client/client/lib/espnow/src/ESPNow.cpp
@@ -0,0 +1,61 @@
+#include "ESPNow.hpp"
+
+uint8_t BROADCAST_MAC[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+esp_now_peer_info_t hostInfo;
+Preferences preferences;
+
+void get_host_mac(uint8_t *destination)
+{
+	preferences.begin("config", true);
+	if (preferences.isKey("host")) {
+		preferences.getBytes("host", destination, sizeof(uint8_t) * 6);
+	} else {
+		memcpy(destination, BROADCAST_MAC, sizeof(BROADCAST_MAC));
+		Serial.println("backup mac used");
+	}
+	preferences.end();
+}
+void on_data_sent(const uint8_t *mac_addr, esp_now_send_status_t status)
+{
+	// go to sleep
+}
+
+void on_data_recv(const uint8_t *mac, const uint8_t *incomingData, int len)
+{
+	Serial.println("message recieved");
+	config new_config;
+	memcpy(&new_config, incomingData, sizeof(new_config)); // TODO: check for valid mac
+
+	// put the host address in flash mem
+	preferences.begin("config", false);
+	if (!preferences.isKey("host")) {
+		preferences.putBytes("host", new_config.host, sizeof(new_config.host));
+		Serial.println("host mac saved to flash");
+	} // host change shouldn't be an issue
+	preferences.end();
+	// sync time
+	esptime::rtc.setTime(
+	    new_config.time_millis); // see https://www.esp32.com/viewtopic.php?t=9965, maybe this needs an offset
+}
+
+esp_err_t espnow_setup()
+{
+	esp_err_t result;
+	WiFi.mode(WIFI_STA);
+	result = esp_now_init();
+	if (result != ESP_OK) {
+		// initialization failed
+		return result; // not sure about this
+	}
+
+	get_host_mac(hostInfo.peer_addr); // check if there is a host saved in flash mem, broadcast otherwise
+
+	hostInfo.channel = 0;
+	hostInfo.encrypt = 0;
+	esp_now_add_peer(&hostInfo);
+
+	esp_now_register_recv_cb(on_data_recv);
+	esp_now_register_send_cb(on_data_sent);
+
+	return ESP_OK;
+}
diff --git a/client/client/lib/espnow/src/ESPNow.hpp b/client/client/lib/espnow/src/ESPNow.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..1230290fca05d93f3c98bbd7c3374f364f5868bb
--- /dev/null
+++ b/client/client/lib/espnow/src/ESPNow.hpp
@@ -0,0 +1,24 @@
+#ifndef _ESPNOW
+#define _ESPNOW
+
+#include "Message.hpp"
+#include "Time.hpp"
+#include "ram_caching.hpp"
+#include <ClientDataPackage.hpp>
+#include <ESP32Time.h>
+#include <Preferences.h>
+#include <WiFi.h>
+#include <esp_now.h>
+
+typedef struct config {
+	uint8_t host[6];
+	long time_millis;
+} config;
+
+esp_err_t espnow_setup();
+bool is_host_defined();
+void get_host_mac(uint8_t *destination);
+void on_data_sent(const uint8_t *mac_addr, esp_now_send_status_t status);
+void on_data_recv(const uint8_t *mac, const uint8_t *incomingData, int len);
+
+#endif
\ No newline at end of file
diff --git a/client/client/lib/espnow/src/Message.cpp b/client/client/lib/espnow/src/Message.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c4bfb3f765350c6ad51aa28ad605a7a13ae9c2e4
--- /dev/null
+++ b/client/client/lib/espnow/src/Message.cpp
@@ -0,0 +1,47 @@
+#include "Message.hpp"
+
+void Message::add_data(float value, int identifier)
+{
+	if (data.amountData < NUM_SENSORS) {
+		data.values[data.amountData] = value;
+		data.identifiers[data.amountData] = identifier;
+		data.amountData++;
+	}
+}
+
+esp_err_t Message::send()
+{
+	Serial.println("sending Message");
+	esp_err_t success;
+	success = esp_now_send(recipient, (uint8_t *)&data, sizeof(data));
+	// if(success != ESP_OK){
+	//     if(!ram_cache_is_full()){
+	//         ram_cache_push(*data);
+	//     }
+	// }
+	for (int i = 0; i < data.amountData; i++) {
+		Serial.println(data.values[i]);
+	}
+	Serial.println((String) "time sent: " + data.timestamp);
+	Serial.println((String) "Send status: " + success);
+	Serial.println();
+	Serial.flush();
+	Serial.println("done");
+	return success;
+}
+
+Message ::Message()
+{
+	// check for existing host mac address, use broadcast otherwise
+	get_host_mac(recipient);
+
+	data.amountData = 0;
+	data.timestamp = esptime::rtc.getMillis(); // I am assuming we are not sending data from Unix Epoch
+}
+
+Message ::Message(ClientDataPackage old_data)
+{
+	data = old_data;
+	// memcpy(&data, &old_data, sizeof(data));
+	get_host_mac(recipient);
+}
\ No newline at end of file
diff --git a/client/client/lib/espnow/src/Message.hpp b/client/client/lib/espnow/src/Message.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..ee00f7fd7365a15c25a32d9ad81b575fb5edde3b
--- /dev/null
+++ b/client/client/lib/espnow/src/Message.hpp
@@ -0,0 +1,22 @@
+#pragma once
+
+#include "ClientDataPackage.hpp"
+#include "ESPNow.hpp"
+#include "Time.hpp"
+#include <Arduino.h>
+#include <ESP32Time.h>
+#include <esp_now.h>
+
+// Format of the message sent from host to client
+// if more things are sent from the host the name might not be accurate anymore
+class Message {
+  public:
+	Message();
+	Message(ClientDataPackage old_data);
+	void add_data(float value, int identifier);
+	esp_err_t send();
+
+  private:
+	ClientDataPackage data;
+	uint8_t recipient[6];
+};
\ No newline at end of file
diff --git a/client/client/lib/time/src/Time.hpp b/client/client/lib/time/src/Time.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..93dfc964f0bef45fb86ccba203868ea995df4031
--- /dev/null
+++ b/client/client/lib/time/src/Time.hpp
@@ -0,0 +1,9 @@
+#pragma once
+
+#include <ESP32Time.h>
+
+namespace esptime {
+// internal linkage only
+static ESP32Time rtc; // global variable for the RTC (i don't think this is good practice)
+} // namespace esptime
+// namespace esptime
diff --git a/client/client/src/main.cpp b/client/client/src/main.cpp
index 11f1e0aefd61c4df547b5dae177ecae4451595aa..54220bae97fb193cf0d830b9d04c57a49976f3a4 100644
--- a/client/client/src/main.cpp
+++ b/client/client/src/main.cpp
@@ -29,4 +29,3 @@ void loop() {
   //   }
   delay(5000);
 }
-
diff --git a/client/client/test/TestESPNow.cpp b/client/client/test/TestESPNow.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3a4c149bb8742e61c0a235691e7e0b8d9a3eda76
--- /dev/null
+++ b/client/client/test/TestESPNow.cpp
@@ -0,0 +1,12 @@
+#include "TestESPNow.hpp"
+
+void test_on_data_recv_valid_config()
+{
+	uint8_t mac_addr[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+	int len = 0;
+	config conf = {host : {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA}, time_millis : 0};
+
+	// preferences / hostinfo would need to be global for this to work
+
+	TEST_FAIL();
+}
diff --git a/client/client/test/TestESPNow.hpp b/client/client/test/TestESPNow.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..a2512b2ffd4ca48031415456d658302d4bae6b91
--- /dev/null
+++ b/client/client/test/TestESPNow.hpp
@@ -0,0 +1,6 @@
+#pragma once
+#include <Arduino.h>
+#include <ESPNow.hpp>
+#include <unity.h>
+
+void test_on_data_recv_valid_config();
\ No newline at end of file
diff --git a/client/client/test/TestMessage.cpp b/client/client/test/TestMessage.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..56b7ccc83ab80707afba68c9c33fbe1f6ad6f0b1
--- /dev/null
+++ b/client/client/test/TestMessage.cpp
@@ -0,0 +1,24 @@
+#include "TestMessage.hpp"
+
+void test_on_data_recv()
+{
+	Message message = Message{};
+
+	TEST_ASSERT_EQUAL(0, message.getData().amountData);
+}
+
+void test_new_message_filled()
+{
+	Message message = Message{};
+
+	message.add_data(1.1, 0);
+	message.add_data(1.2, 1);
+	message.add_data(1.3, 2);
+
+	float expectedValuesArray[] = {1.1, 1.2, 1.3};
+	int expectedIdentifiersArray[] = {0, 1, 2};
+
+	TEST_ASSERT_EQUAL(3, message.getData().amountData);
+	TEST_ASSERT_EQUAL_FLOAT_ARRAY(expectedValuesArray, message.getData().values, 3);
+	TEST_ASSERT_EQUAL_INT_ARRAY(expectedIdentifiersArray, message.getData().identifiers, 3);
+}
\ No newline at end of file
diff --git a/client/client/test/TestMessage.hpp b/client/client/test/TestMessage.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..80d5be09d9d13954d96d1b6ef0b366783b414398
--- /dev/null
+++ b/client/client/test/TestMessage.hpp
@@ -0,0 +1,8 @@
+#pragma once
+#include <Arduino.h>
+#include <ESPNow.hpp>
+#include <unity.h>
+
+void test_on_data_recv();
+
+void test_new_message_filled();
\ No newline at end of file
diff --git a/client/client/test/main.cpp b/client/client/test/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..82d68817015b01f036c346b18fa79601a5e842aa
--- /dev/null
+++ b/client/client/test/main.cpp
@@ -0,0 +1,17 @@
+#include "TestESPNow.hpp"
+#include "TestMessage.hpp"
+#include <Arduino.h>
+#include <unity.h>
+
+void setup()
+{
+	delay(2000); // service delay
+
+	UNITY_BEGIN();
+	RUN_TEST(test_on_data_recv_valid_config);
+	RUN_TEST(test_on_data_recv);
+	RUN_TEST(test_new_message_filled);
+	UNITY_END();
+}
+
+void loop() {}
\ No newline at end of file
diff --git a/code-snippets/espnow/espNowTest/.gitignore b/code-snippets/espnow/espNowTest/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..89cc49cbd652508924b868ea609fa8f6b758ec56
--- /dev/null
+++ b/code-snippets/espnow/espNowTest/.gitignore
@@ -0,0 +1,5 @@
+.pio
+.vscode/.browse.c_cpp.db*
+.vscode/c_cpp_properties.json
+.vscode/launch.json
+.vscode/ipch
diff --git a/code-snippets/espnow/espNowTest/.vscode/extensions.json b/code-snippets/espnow/espNowTest/.vscode/extensions.json
new file mode 100644
index 0000000000000000000000000000000000000000..080e70d08b9811fa743afe5094658dba0ed6b7c2
--- /dev/null
+++ b/code-snippets/espnow/espNowTest/.vscode/extensions.json
@@ -0,0 +1,10 @@
+{
+    // See http://go.microsoft.com/fwlink/?LinkId=827846
+    // for the documentation about the extensions.json format
+    "recommendations": [
+        "platformio.platformio-ide"
+    ],
+    "unwantedRecommendations": [
+        "ms-vscode.cpptools-extension-pack"
+    ]
+}
diff --git a/code-snippets/espnow/espNowTest/.vscode/settings.json b/code-snippets/espnow/espNowTest/.vscode/settings.json
new file mode 100644
index 0000000000000000000000000000000000000000..0db587396d5123f3b72a5a52adbb085a527fc04e
--- /dev/null
+++ b/code-snippets/espnow/espNowTest/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+    "cmake.configureOnOpen": true
+}
\ No newline at end of file
diff --git a/code-snippets/espnow/espNowTest/espnow.md b/code-snippets/espnow/espNowTest/espnow.md
new file mode 100644
index 0000000000000000000000000000000000000000..8928df7421cf79abdfb1a6402ca328aa93dfe6fb
--- /dev/null
+++ b/code-snippets/espnow/espNowTest/espnow.md
@@ -0,0 +1,20 @@
+# Esp Now Basic Steps
+
+- Define Mac address of receiving esp32
+- create a ```esp_now_peer_info_t```
+- define a function for sending/receiving
+  
+  ```
+    setup(){
+    Serial.begin(115200);
+    while(!Serial); //open serial connection and wait
+    WiFi.mode(WIFI_STA); //enable wifi and set it to the correct mode
+    esp_now_init();
+    esp_now_register_send_cb(onDataSent);
+    esp_now_register_recv_cb(onDataRecv);
+    // fill out your esp_now_peer_info_t
+    esp_now_add_peer(peerInfo);
+    }
+  ```
+
+- Now you can send in your ```loop()```, or leave ```loop()``` empty to only receive
\ No newline at end of file
diff --git a/code-snippets/espnow/espNowTest/include/README b/code-snippets/espnow/espNowTest/include/README
new file mode 100644
index 0000000000000000000000000000000000000000..194dcd43252dcbeb2044ee38510415041a0e7b47
--- /dev/null
+++ b/code-snippets/espnow/espNowTest/include/README
@@ -0,0 +1,39 @@
+
+This directory is intended for project header files.
+
+A header file is a file containing C declarations and macro definitions
+to be shared between several project source files. You request the use of a
+header file in your project source file (C, C++, etc) located in `src` folder
+by including it, with the C preprocessing directive `#include'.
+
+```src/main.c
+
+#include "header.h"
+
+int main (void)
+{
+ ...
+}
+```
+
+Including a header file produces the same results as copying the header file
+into each source file that needs it. Such copying would be time-consuming
+and error-prone. With a header file, the related declarations appear
+in only one place. If they need to be changed, they can be changed in one
+place, and programs that include the header file will automatically use the
+new version when next recompiled. The header file eliminates the labor of
+finding and changing all the copies as well as the risk that a failure to
+find one copy will result in inconsistencies within a program.
+
+In C, the usual convention is to give header files names that end with `.h'.
+It is most portable to use only letters, digits, dashes, and underscores in
+header file names, and at most one dot.
+
+Read more about using header files in official GCC documentation:
+
+* Include Syntax
+* Include Operation
+* Once-Only Headers
+* Computed Includes
+
+https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
diff --git a/code-snippets/espnow/espNowTest/platformio.ini b/code-snippets/espnow/espNowTest/platformio.ini
new file mode 100644
index 0000000000000000000000000000000000000000..65ef8ee58c3b62a32f64a0027c98dbd9d5e221d0
--- /dev/null
+++ b/code-snippets/espnow/espNowTest/platformio.ini
@@ -0,0 +1,16 @@
+; PlatformIO Project Configuration File
+;
+;   Build options: build flags, source filter
+;   Upload options: custom upload port, speed and extra flags
+;   Library options: dependencies, extra library storages
+;   Advanced options: extra scripting
+;
+; Please visit documentation for the other options and examples
+; https://docs.platformio.org/page/projectconf.html
+
+[env:esp32-c3-devkitm-1]
+platform = espressif32
+board = esp32-c3-devkitm-1
+framework = arduino
+monitor_speed = 115200
+lib_deps = makuna/NeoPixelBus@^2.7.0
diff --git a/code-snippets/espnow/espNowTest/src/main.cpp b/code-snippets/espnow/espNowTest/src/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..38792847f1d2040000514bbe3114368dcc608c1f
--- /dev/null
+++ b/code-snippets/espnow/espNowTest/src/main.cpp
@@ -0,0 +1,118 @@
+#include <Arduino.h>
+#include <NeoPixelBus.h>
+#include <esp_now.h>
+#include "WiFi.h"
+
+#define PIN 8
+#define NUMPIXELS 1
+#define LED 0
+
+// uint8_t peerMAC[] = {0x58, 0xCF, 0x79, 0x04, 0x45, 0x9C}; //battery
+// uint8_t peerMAC[] = {0x58, 0xCF, 0x79, 0x04, 0x3A, 0xF8}; //wired
+uint8_t peerMAC[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+typedef struct espMessage{
+  String macAddr;
+  int temp;
+  int co;
+} espMessage;
+
+espMessage lastMessage;
+
+esp_now_peer_info_t peerInfo;
+
+NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> led(NUMPIXELS, PIN);
+
+void blink()
+{
+  // RgbColor current = led.GetPixelColor(0);
+  // if(current == RgbColor(0,0,0)){
+  //   led.SetPixelColor(LED, RgbColor(55, 55, 55));
+  //   led.Show();
+  //   Serial.println("Led is on at peer" + WiFi.macAddress());
+  // }
+  // else{
+  //   led.SetPixelColor(LED, RgbColor(0,0,0));
+  //   led.Show();
+  //   Serial.println("led is off");
+  // }
+}
+
+void flash(RgbColor color){
+  led.SetPixelColor(LED, color);
+  led.Show();
+  delay(500);
+  led.SetPixelColor(LED, RgbColor(0,0,0));
+  led.Show();
+}
+
+void onDataSent(const uint8_t *mac_addr, esp_now_send_status_t status)
+{
+  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Message recieved" : "Message lost");
+  flash(RgbColor(255, 255, 255));
+}
+
+void onDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len)
+{
+  Serial.println("message recieved");
+  memcpy(&lastMessage, incomingData, sizeof(lastMessage));
+  Serial.println(lastMessage.macAddr);
+  Serial.println(lastMessage.co);
+  Serial.println(lastMessage.temp);
+  Serial.println("--------------");
+}
+
+void setup() {
+  // put your setup code here, to run once:
+  Serial.begin(115200);
+  while (!Serial);
+
+  //Led stuff
+  led.Begin();
+  led.SetPixelColor(LED, RgbColor(0,0,0));
+  led.Show();
+
+  //esp now
+  WiFi.mode(WIFI_STA);
+  if(esp_now_init() != ESP_OK){
+    Serial.println("Error initializing espnow");
+    flash(RgbColor(0, 0, 55));
+    return;
+  }
+
+  //comment out whichever you don't need
+  esp_now_register_send_cb(onDataSent);
+  // esp_now_register_recv_cb(onDataRecv);
+
+  //register peer
+  memcpy(peerInfo.peer_addr, peerMAC, sizeof(peerMAC));
+  peerInfo.channel = 0;
+  peerInfo.encrypt = false;
+  if (esp_now_add_peer(&peerInfo) != ESP_OK){
+    flash(RgbColor(0, 55, 55));
+    return;
+  }
+
+
+}
+
+void loop() {
+  // put your main code here, to run repeatedly:
+  
+  //comment this out if you only want to recieve
+  espMessage data;
+  data.macAddr = WiFi.macAddress();
+  data.co = (int) random(5,30);
+  data.temp = (int) random(0,100);
+
+  esp_err_t result = esp_now_send(peerMAC, (uint8_t *) &data, sizeof(data));
+  if(result == ESP_OK){
+    flash(RgbColor(0, 55, 0));
+  }
+  else{
+    flash(RgbColor(55, 0, 0));
+    Serial.println(result);
+  }
+
+  delay(5000);
+}
\ No newline at end of file
diff --git a/code-snippets/espnow/espNowTest/test/README b/code-snippets/espnow/espNowTest/test/README
new file mode 100644
index 0000000000000000000000000000000000000000..9b1e87bc67c90e7f09a92a3e855444b085c655a6
--- /dev/null
+++ b/code-snippets/espnow/espNowTest/test/README
@@ -0,0 +1,11 @@
+
+This directory is intended for PlatformIO Test Runner and project tests.
+
+Unit Testing is a software testing method by which individual units of
+source code, sets of one or more MCU program modules together with associated
+control data, usage procedures, and operating procedures, are tested to
+determine whether they are fit for use. Unit testing finds problems early
+in the development cycle.
+
+More information about PlatformIO Unit Testing:
+- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html
diff --git a/host/fipy/LICENSES.md b/host/fipy/LICENSES.md
new file mode 100644
index 0000000000000000000000000000000000000000..ce547569361b650f90c105fc0a2e6009cfa885e9
--- /dev/null
+++ b/host/fipy/LICENSES.md
@@ -0,0 +1,279 @@
+# Micropython-lib
+
+micropython-lib consists of multiple modules from different sources and
+authors. Each module comes under its own licensing terms. The short name of
+a license can be found in a file within the module directory (usually
+metadata.txt or setup.py). The complete text of each license used is provided
+below. Files not belonging to a particular module are provided under the MIT
+license, unless explicitly stated otherwise.
+
+=============== MIT License ===============
+
+The MIT License (MIT)
+
+Copyright (c) 2013, 2014 micropython-lib contributors
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+=============== Python License ===============
+
+# A. HISTORY OF THE SOFTWARE
+
+Python was created in the early 1990s by Guido van Rossum at Stichting
+Mathematisch Centrum (CWI, see http://www.cwi.nl) in the Netherlands
+as a successor of a language called ABC. Guido remains Python's
+principal author, although it includes many contributions from others.
+
+In 1995, Guido continued his work on Python at the Corporation for
+National Research Initiatives (CNRI, see http://www.cnri.reston.va.us)
+in Reston, Virginia where he released several versions of the
+software.
+
+In May 2000, Guido and the Python core development team moved to
+BeOpen.com to form the BeOpen PythonLabs team. In October of the same
+year, the PythonLabs team moved to Digital Creations (now Zope
+Corporation, see http://www.zope.com). In 2001, the Python Software
+Foundation (PSF, see http://www.python.org/psf/) was formed, a
+non-profit organization created specifically to own Python-related
+Intellectual Property. Zope Corporation is a sponsoring member of
+the PSF.
+
+All Python releases are Open Source (see http://www.opensource.org for
+the Open Source Definition). Historically, most, but not all, Python
+releases have also been GPL-compatible; the table below summarizes
+the various releases.
+
+    Release         Derived     Year        Owner       GPL-
+                    from                                compatible? (1)
+
+    0.9.0 thru 1.2              1991-1995   CWI         yes
+    1.3 thru 1.5.2  1.2         1995-1999   CNRI        yes
+    1.6             1.5.2       2000        CNRI        no
+    2.0             1.6         2000        BeOpen.com  no
+    1.6.1           1.6         2001        CNRI        yes (2)
+    2.1             2.0+1.6.1   2001        PSF         no
+    2.0.1           2.0+1.6.1   2001        PSF         yes
+    2.1.1           2.1+2.0.1   2001        PSF         yes
+    2.1.2           2.1.1       2002        PSF         yes
+    2.1.3           2.1.2       2002        PSF         yes
+    2.2 and above   2.1.1       2001-now    PSF         yes
+
+Footnotes:
+
+(1) GPL-compatible doesn't mean that we're distributing Python under
+the GPL. All Python licenses, unlike the GPL, let you distribute
+a modified version without making your changes open source. The
+GPL-compatible licenses make it possible to combine Python with
+other software that is released under the GPL; the others don't.
+
+(2) According to Richard Stallman, 1.6.1 is not GPL-compatible,
+because its license has a choice of law clause. According to
+CNRI, however, Stallman's lawyer has told CNRI's lawyer that 1.6.1
+is "not incompatible" with the GPL.
+
+Thanks to the many outside volunteers who have worked under Guido's
+direction to make these releases possible.
+
+# B. TERMS AND CONDITIONS FOR ACCESSING OR OTHERWISE USING PYTHON
+
+## PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2
+
+1. This LICENSE AGREEMENT is between the Python Software Foundation
+   ("PSF"), and the Individual or Organization ("Licensee") accessing and
+   otherwise using this software ("Python") in source or binary form and
+   its associated documentation.
+
+2. Subject to the terms and conditions of this License Agreement, PSF hereby
+   grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce,
+   analyze, test, perform and/or display publicly, prepare derivative works,
+   distribute, and otherwise use Python alone or in any derivative version,
+   provided, however, that PSF's License Agreement and PSF's notice of copyright,
+   i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+   2011, 2012, 2013 Python Software Foundation; All Rights Reserved" are retained
+   in Python alone or in any derivative version prepared by Licensee.
+
+3. In the event Licensee prepares a derivative work that is based on
+   or incorporates Python or any part thereof, and wants to make
+   the derivative work available to others as provided herein, then
+   Licensee hereby agrees to include in any such work a brief summary of
+   the changes made to Python.
+
+4. PSF is making Python available to Licensee on an "AS IS"
+   basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+   IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND
+   DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+   FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT
+   INFRINGE ANY THIRD PARTY RIGHTS.
+
+5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+   FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+   A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON,
+   OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6. This License Agreement will automatically terminate upon a material
+   breach of its terms and conditions.
+
+7. Nothing in this License Agreement shall be deemed to create any
+   relationship of agency, partnership, or joint venture between PSF and
+   Licensee. This License Agreement does not grant permission to use PSF
+   trademarks or trade name in a trademark sense to endorse or promote
+   products or services of Licensee, or any third party.
+
+8. By copying, installing or otherwise using Python, Licensee
+   agrees to be bound by the terms and conditions of this License
+   Agreement.
+
+## BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0
+
+BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1
+
+1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an
+   office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the
+   Individual or Organization ("Licensee") accessing and otherwise using
+   this software in source or binary form and its associated
+   documentation ("the Software").
+
+2. Subject to the terms and conditions of this BeOpen Python License
+   Agreement, BeOpen hereby grants Licensee a non-exclusive,
+   royalty-free, world-wide license to reproduce, analyze, test, perform
+   and/or display publicly, prepare derivative works, distribute, and
+   otherwise use the Software alone or in any derivative version,
+   provided, however, that the BeOpen Python License is retained in the
+   Software, alone or in any derivative version prepared by Licensee.
+
+3. BeOpen is making the Software available to Licensee on an "AS IS"
+   basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+   IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND
+   DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+   FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT
+   INFRINGE ANY THIRD PARTY RIGHTS.
+
+4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE
+   SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS
+   AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY
+   DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+5. This License Agreement will automatically terminate upon a material
+   breach of its terms and conditions.
+
+6. This License Agreement shall be governed by and interpreted in all
+   respects by the law of the State of California, excluding conflict of
+   law provisions. Nothing in this License Agreement shall be deemed to
+   create any relationship of agency, partnership, or joint venture
+   between BeOpen and Licensee. This License Agreement does not grant
+   permission to use BeOpen trademarks or trade names in a trademark
+   sense to endorse or promote products or services of Licensee, or any
+   third party. As an exception, the "BeOpen Python" logos available at
+   http://www.pythonlabs.com/logos.html may be used according to the
+   permissions granted on that web page.
+
+7. By copying, installing or otherwise using the software, Licensee
+   agrees to be bound by the terms and conditions of this License
+   Agreement.
+
+## CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1
+
+1.  This LICENSE AGREEMENT is between the Corporation for National
+    Research Initiatives, having an office at 1895 Preston White Drive,
+    Reston, VA 20191 ("CNRI"), and the Individual or Organization
+    ("Licensee") accessing and otherwise using Python 1.6.1 software in
+    source or binary form and its associated documentation.
+
+2.  Subject to the terms and conditions of this License Agreement, CNRI
+    hereby grants Licensee a nonexclusive, royalty-free, world-wide
+    license to reproduce, analyze, test, perform and/or display publicly,
+    prepare derivative works, distribute, and otherwise use Python 1.6.1
+    alone or in any derivative version, provided, however, that CNRI's
+    License Agreement and CNRI's notice of copyright, i.e., "Copyright (c)
+    1995-2001 Corporation for National Research Initiatives; All Rights
+    Reserved" are retained in Python 1.6.1 alone or in any derivative
+    version prepared by Licensee. Alternately, in lieu of CNRI's License
+    Agreement, Licensee may substitute the following text (omitting the
+    quotes): "Python 1.6.1 is made available subject to the terms and
+    conditions in CNRI's License Agreement. This Agreement together with
+    Python 1.6.1 may be located on the Internet using the following
+    unique, persistent identifier (known as a handle): 1895.22/1013. This
+    Agreement may also be obtained from a proxy server on the Internet
+    using the following URL: http://hdl.handle.net/1895.22/1013".
+
+3.  In the event Licensee prepares a derivative work that is based on
+    or incorporates Python 1.6.1 or any part thereof, and wants to make
+    the derivative work available to others as provided herein, then
+    Licensee hereby agrees to include in any such work a brief summary of
+    the changes made to Python 1.6.1.
+
+4.  CNRI is making Python 1.6.1 available to Licensee on an "AS IS"
+    basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR
+    IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND
+    DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS
+    FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT
+    INFRINGE ANY THIRD PARTY RIGHTS.
+
+5.  CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON
+    1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS
+    A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1,
+    OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF.
+
+6.  This License Agreement will automatically terminate upon a material
+    breach of its terms and conditions.
+
+7.  This License Agreement shall be governed by the federal
+    intellectual property law of the United States, including without
+    limitation the federal copyright law, and, to the extent such
+    U.S. federal law does not apply, by the law of the Commonwealth of
+    Virginia, excluding Virginia's conflict of law provisions.
+    Notwithstanding the foregoing, with regard to derivative works based
+    on Python 1.6.1 that incorporate non-separable material that was
+    previously distributed under the GNU General Public License (GPL), the
+    law of the Commonwealth of Virginia shall govern this License
+    Agreement only as to issues arising under or with respect to
+    Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this
+    License Agreement shall be deemed to create any relationship of
+    agency, partnership, or joint venture between CNRI and Licensee. This
+    License Agreement does not grant permission to use CNRI trademarks or
+    trade name in a trademark sense to endorse or promote products or
+    services of Licensee, or any third party.
+
+8.  By clicking on the "ACCEPT" button where indicated, or by copying,
+    installing or otherwise using Python 1.6.1, Licensee agrees to be
+    bound by the terms and conditions of this License Agreement.
+
+            ACCEPT
+
+## CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2
+
+Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam,
+The Netherlands. All rights reserved.
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in
+supporting documentation, and that the name of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/host/fipy/boot.py b/host/fipy/boot.py
new file mode 100644
index 0000000000000000000000000000000000000000..b8e7bb0948e95d8d7e45ecd78640aa95d841f6d3
--- /dev/null
+++ b/host/fipy/boot.py
@@ -0,0 +1 @@
+# boot.py -- run on boot-up
diff --git a/host/fipy/lib/server_transfer.py b/host/fipy/lib/server_transfer.py
new file mode 100644
index 0000000000000000000000000000000000000000..00b7a53e6e3f20fa3c657c042a94ef21d0c55a9e
--- /dev/null
+++ b/host/fipy/lib/server_transfer.py
@@ -0,0 +1,38 @@
+class DataTransferInterface:
+    def connect(self):
+        pass
+
+    def disconnect(self):
+        pass
+
+    def send(self, data: str):
+        pass
+
+
+from network import WLAN
+import lib.urequests as requests
+
+
+class DataTransferWiFi(DataTransferInterface):
+    def connect(self, ssid: str, password: str):
+        self.wlan = WLAN(mode=WLAN.STA)
+        self.wlan.connect(ssid, auth=(WLAN.WPA2, password))
+        while not self.wlan.isconnected():
+            pass
+        print("Connected to Wifi")
+
+    def disconnect(self):
+        self.wlan.disconnect()
+
+    def send(self, data: str):
+        res = requests.post(
+            "http://influxdb.qe-forte.uibk.ac.at/api/v2/write?org=QE&bucket=fipy-tests&precision=s",
+            data=data,
+            headers={
+                "Authorization": "Token EML8-F4SfE6XiEAAcawwyA8cWzniCW7eYkCGnJ6hRnf1fyN4BrnxdBd3S56j4-MAZmi0FJu867YHvhflKeFmTw==",
+                "Content-Type": "text/plain; charset=utf-8",
+                "Accept": "application/json",
+            },
+        )
+        print(res.status_code)
+        print(res.reason)
diff --git a/host/fipy/lib/urequests.py b/host/fipy/lib/urequests.py
new file mode 100644
index 0000000000000000000000000000000000000000..a4488d1db2c5ed67970686839b01d2256505289d
--- /dev/null
+++ b/host/fipy/lib/urequests.py
@@ -0,0 +1,199 @@
+# MIT Licensed https://github.com/micropython/micropython-lib/blob/master/python-ecosys/urequests/urequests.py
+import usocket
+
+
+class Response:
+    def __init__(self, f):
+        self.raw = f
+        self.encoding = "utf-8"
+        self._cached = None
+
+    def close(self):
+        if self.raw:
+            self.raw.close()
+            self.raw = None
+        self._cached = None
+
+    @property
+    def content(self):
+        if self._cached is None:
+            try:
+                self._cached = self.raw.read()
+            finally:
+                self.raw.close()
+                self.raw = None
+        return self._cached
+
+    @property
+    def text(self):
+        return str(self.content, self.encoding)
+
+    def json(self):
+        import ujson
+
+        return ujson.loads(self.content)
+
+
+def request(
+    method,
+    url,
+    data=None,
+    json=None,
+    headers={},
+    stream=None,
+    auth=None,
+    timeout=None,
+    parse_headers=True,
+):
+    redirect = None  # redirection url, None means no redirection
+    chunked_data = (
+        data and getattr(data, "__iter__", None) and not getattr(data, "__len__", None)
+    )
+
+    if auth is not None:
+        import ubinascii
+
+        username, password = auth
+        formated = b"{}:{}".format(username, password)
+        formated = str(ubinascii.b2a_base64(formated)[:-1], "ascii")
+        headers["Authorization"] = "Basic {}".format(formated)
+
+    try:
+        proto, dummy, host, path = url.split("/", 3)
+    except ValueError:
+        proto, dummy, host = url.split("/", 2)
+        path = ""
+    if proto == "http:":
+        port = 80
+    elif proto == "https:":
+        import ussl
+
+        port = 443
+    else:
+        raise ValueError("Unsupported protocol: " + proto)
+
+    if ":" in host:
+        host, port = host.split(":", 1)
+        port = int(port)
+
+    ai = usocket.getaddrinfo(host, port, 0, usocket.SOCK_STREAM)
+    ai = ai[0]
+
+    resp_d = None
+    if parse_headers is not False:
+        resp_d = {}
+
+    s = usocket.socket(ai[0], usocket.SOCK_STREAM, ai[2])
+
+    if timeout is not None:
+        # Note: settimeout is not supported on all platforms, will raise
+        # an AttributeError if not available.
+        s.settimeout(timeout)
+
+    try:
+        s.connect(ai[-1])
+        if proto == "https:":
+            s = ussl.wrap_socket(s, server_hostname=host)
+        s.write(b"%s /%s HTTP/1.0\r\n" % (method, path))
+        if not "Host" in headers:
+            s.write(b"Host: %s\r\n" % host)
+        # Iterate over keys to avoid tuple alloc
+        for k in headers:
+            s.write(k)
+            s.write(b": ")
+            s.write(headers[k])
+            s.write(b"\r\n")
+        if json is not None:
+            assert data is None
+            import ujson
+
+            data = ujson.dumps(json)
+            s.write(b"Content-Type: application/json\r\n")
+        if data:
+            if chunked_data:
+                s.write(b"Transfer-Encoding: chunked\r\n")
+            else:
+                s.write(b"Content-Length: %d\r\n" % len(data))
+        s.write(b"Connection: close\r\n\r\n")
+        if data:
+            if chunked_data:
+                for chunk in data:
+                    s.write(b"%x\r\n" % len(chunk))
+                    s.write(chunk)
+                    s.write(b"\r\n")
+                s.write("0\r\n\r\n")
+            else:
+                s.write(data)
+
+        l = s.readline()
+        # print(l)
+        l = l.split(None, 2)
+        if len(l) < 2:
+            # Invalid response
+            raise ValueError("HTTP error: BadStatusLine:\n%s" % l)
+        status = int(l[1])
+        reason = ""
+        if len(l) > 2:
+            reason = l[2].rstrip()
+        while True:
+            l = s.readline()
+            if not l or l == b"\r\n":
+                break
+            # print(l)
+            if l.startswith(b"Transfer-Encoding:"):
+                if b"chunked" in l:
+                    raise ValueError("Unsupported " + str(l, "utf-8"))
+            elif l.startswith(b"Location:") and not 200 <= status <= 299:
+                if status in [301, 302, 303, 307, 308]:
+                    redirect = str(l[10:-2], "utf-8")
+                else:
+                    raise NotImplementedError("Redirect %d not yet supported" % status)
+            if parse_headers is False:
+                pass
+            elif parse_headers is True:
+                l = str(l, "utf-8")
+                k, v = l.split(":", 1)
+                resp_d[k] = v.strip()
+            else:
+                parse_headers(l, resp_d)
+    except OSError:
+        s.close()
+        raise
+
+    if redirect:
+        s.close()
+        if status in [301, 302, 303]:
+            return request("GET", redirect, None, None, headers, stream)
+        else:
+            return request(method, redirect, data, json, headers, stream)
+    else:
+        resp = Response(s)
+        resp.status_code = status
+        resp.reason = reason
+        if resp_d is not None:
+            resp.headers = resp_d
+        return resp
+
+
+def head(url, **kw):
+    return request("HEAD", url, **kw)
+
+
+def get(url, **kw):
+    return request("GET", url, **kw)
+
+
+def post(url, **kw):
+    return request("POST", url, **kw)
+
+
+def put(url, **kw):
+    return request("PUT", url, **kw)
+
+
+def patch(url, **kw):
+    return request("PATCH", url, **kw)
+
+
+def delete(url, **kw):
+    return request("DELETE", url, **kw)
diff --git a/host/fipy/main.py b/host/fipy/main.py
new file mode 100644
index 0000000000000000000000000000000000000000..1735bdbadcc6e0bcfa8649fc1ee81eecab71aceb
--- /dev/null
+++ b/host/fipy/main.py
@@ -0,0 +1,55 @@
+# main.py -- put your code here!
+from network import WLAN
+from network import ESPNOW
+import binascii
+import struct
+from time import sleep
+from lib.server_transfer import DataTransferWiFi
+
+
+def bytes_to_data(msg):
+    # turn bytes from message into 22-tuple of integers(identifiers), floats(values), integer(amount) and long(timestamp)
+    data = struct.unpack("<10i10fil", bytes(msg))
+    amountData = data[20]
+    timestamp = data[21]
+    identifiers = data[0:amountData]
+    values = data[10 : (10 + amountData)]
+    return {
+        "amountData": amountData,
+        "timestamp": timestamp,
+        "data": dict(zip(identifiers, values)),
+    }
+
+
+def espnow_recv(result):
+    mac, peer, msg = result
+
+    data = bytes_to_data(msg)
+    try:
+        print(data["amountData"])
+        print(data["timestamp"])
+        print(data["data"])
+        print(str(binascii.hexlify(mac), "ascii"))
+
+    except Exception as error:
+        print(error)
+
+
+# data = DataTransferWiFi()
+# data.connect("Z", "AbsoluteSandwich")
+# data.send(
+#     "airSensors,sensor_id=TLM0201 temperature=73.97038159354763,humidity=35.23103248356096,co=0.4844531056779361 1661175680\nairSensors,sensor_id=TLM0202 temperature=75.30007505999716,humidity=35.65192991869171,co=0.5141876544505826 1661175680\nairSensors,sensor_id=TLM0202 temperature=75.30007505999756,humidity=35.65192991869171,co=0.5141876544505826 1661175680"
+# )
+# data.disconnect()
+
+w = WLAN()
+
+ESPNOW.init()
+p = ESPNOW.add_peer("58cf79043c84")
+
+ESPNOW.on_recv(espnow_recv)
+
+while True:
+    print("...")
+    sleep(5)
+    pass
diff --git a/host/fipy/pymakr.conf b/host/fipy/pymakr.conf
new file mode 100644
index 0000000000000000000000000000000000000000..7f8e723b49b71b94f7fd6f092d9130d4af36050c
--- /dev/null
+++ b/host/fipy/pymakr.conf
@@ -0,0 +1,3 @@
+{
+    "name": "Host Fipy"
+}
\ No newline at end of file
diff --git a/host/fipy/pymakr.json b/host/fipy/pymakr.json
new file mode 100644
index 0000000000000000000000000000000000000000..4cfd21b33ba6faf6e052521bf37eab88befef466
--- /dev/null
+++ b/host/fipy/pymakr.json
@@ -0,0 +1,3 @@
+{
+    "onUpdate" : "restartScript"
+}
\ No newline at end of file