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