diff --git a/.gitignore b/.gitignore index b539c117fcc142b4f55d30a75ce7b212ed68869f..c3aed1a6ffb12f32c68d7d0e2c7cf1220c3adde9 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ downloads/ eggs/ .eggs/ lib/ +!host/fipy/lib !client/client/lib lib64/ parts/ diff --git a/client/client/lib/deep_sleep/f_deep_sleep.cpp b/client/client/lib/deep_sleep/f_deep_sleep.cpp new file mode 100644 index 0000000000000000000000000000000000000000..60d1ac0b44d850f809d44be2b2fd609536fb54a0 --- /dev/null +++ b/client/client/lib/deep_sleep/f_deep_sleep.cpp @@ -0,0 +1,23 @@ +#include "f_deep_sleep.hpp" + +void print_wakeup_reason(){ + esp_sleep_wakeup_cause_t wakeup_reason; + + wakeup_reason = esp_sleep_get_wakeup_cause(); + + switch(wakeup_reason) + { + case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break; + case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break; + case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break; + case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break; + case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break; + default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break; + } +} + + +void deep_sleep(int time_in_sec){ + esp_sleep_enable_timer_wakeup(time_in_sec * 1000000); + esp_deep_sleep_start(); +} diff --git a/client/client/lib/deep_sleep/f_deep_sleep.hpp b/client/client/lib/deep_sleep/f_deep_sleep.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b0c91129d025c7cd48f0350a269a765c7c8e0f5b --- /dev/null +++ b/client/client/lib/deep_sleep/f_deep_sleep.hpp @@ -0,0 +1,9 @@ +#ifndef F_DEEP_SLEEP_H +#define F_DEEP_SLEEP_H + +#include <Arduino.h> + +void deep_sleep(int time_to_sleep); +void print_wakeup_reason(); + +#endif diff --git a/client/client/lib/espnow/src/ESPNow.cpp b/client/client/lib/espnow/src/ESPNow.cpp index e52930604dace5db905876e9ffcdc12642e943bf..359b43c50b855b7f90d955995befe915a3846e3d 100644 --- a/client/client/lib/espnow/src/ESPNow.cpp +++ b/client/client/lib/espnow/src/ESPNow.cpp @@ -7,7 +7,7 @@ Preferences preferences; void get_host_mac(uint8_t *destination) { preferences.begin("config", true); - if (preferences.isKey("host")) { + if (!preferences.isKey("host")) { preferences.getBytes("host", destination, sizeof(uint8_t) * 6); } else { memcpy(destination, BROADCAST_MAC, sizeof(BROADCAST_MAC)); @@ -31,11 +31,15 @@ void on_data_recv(const uint8_t *mac, const uint8_t *incomingData, int len) 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 + } else{ + Serial.println("host mac already exists"); + }// host change shouldn't be an issue preferences.end(); // sync time - esptime::rtc.setTime( + Time::getInstance().setTime( new_config.time_millis); // see https://www.esp32.com/viewtopic.php?t=9965, maybe this needs an offset + Serial.println("Saved Time: " + (String) new_config.time_millis); + Serial.flush(); } esp_err_t espnow_setup() @@ -59,3 +63,29 @@ esp_err_t espnow_setup() return ESP_OK; } + +esp_err_t espnow_send_message(const Message& message){ + Serial.println("sending Message"); + esp_err_t success; + ClientDataPackage dataP = message.get_client_data_package(); + uint8_t recipient; + get_host_mac(&recipient); + + success = esp_now_send(&recipient, (uint8_t *) &dataP, sizeof(ClientDataPackage)); + // if(success != ESP_OK){ + // if(!ram_cache_is_full()){ + // ram_cache_push(*data); + // } + // } + + for (int i = 0; i < dataP.amountData; i++) { + Serial.println(dataP.values[i]); + } + + Serial.println((String) "time sent: " + dataP.timestamp); + Serial.println((String) "Send status: " + success); + Serial.println(); + Serial.println("done"); + Serial.flush(); + return success; +} diff --git a/client/client/lib/espnow/src/ESPNow.hpp b/client/client/lib/espnow/src/ESPNow.hpp index 1230290fca05d93f3c98bbd7c3374f364f5868bb..e4ac43b351c4431e8a1bd1b15740ae5fe085e2fe 100644 --- a/client/client/lib/espnow/src/ESPNow.hpp +++ b/client/client/lib/espnow/src/ESPNow.hpp @@ -16,6 +16,7 @@ typedef struct config { } config; esp_err_t espnow_setup(); +esp_err_t espnow_send_message(const Message& message); 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); diff --git a/client/client/lib/espnow/src/Message.cpp b/client/client/lib/espnow/src/Message.cpp index c4bfb3f765350c6ad51aa28ad605a7a13ae9c2e4..6975ab6cd228ab218df9759abddc498a082c288c 100644 --- a/client/client/lib/espnow/src/Message.cpp +++ b/client/client/lib/espnow/src/Message.cpp @@ -9,39 +9,21 @@ void Message::add_data(float value, int identifier) } } -esp_err_t Message::send() +ClientDataPackage Message ::get_client_data_package() const { - 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; + return data; } 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 + data.timestamp = Time::getInstance().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 index ee00f7fd7365a15c25a32d9ad81b575fb5edde3b..397ca6f707105be90fb76add8200b8edef93c8ed 100644 --- a/client/client/lib/espnow/src/Message.hpp +++ b/client/client/lib/espnow/src/Message.hpp @@ -1,7 +1,6 @@ #pragma once #include "ClientDataPackage.hpp" -#include "ESPNow.hpp" #include "Time.hpp" #include <Arduino.h> #include <ESP32Time.h> @@ -14,9 +13,8 @@ class Message { Message(); Message(ClientDataPackage old_data); void add_data(float value, int identifier); - esp_err_t send(); + ClientDataPackage get_client_data_package() const; private: ClientDataPackage data; - uint8_t recipient[6]; }; \ No newline at end of file diff --git a/client/client/lib/time/src/Time.cpp b/client/client/lib/time/src/Time.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8fdf4b4decd253a197cda680a6613529daa2b127 --- /dev/null +++ b/client/client/lib/time/src/Time.cpp @@ -0,0 +1,28 @@ +#include "Time.hpp" + +#include <utility> +void Time::setTime(long epoch, int ms) +{ + this->rtc.setTime(epoch, ms); +} +tm Time::getTimeStruct() +{ + return this->rtc.getTimeStruct(); +} +String Time::getDateTime(bool mode) +{ + return this->rtc.getDateTime(mode); +} +String Time::getTime(String format) +{ + return this->rtc.getTime(std::move(format)); +} +long Time::getEpochSeconds() +{ + return this->rtc.getEpoch(); +} + +long Time::getMillis() +{ + return this->rtc.getMillis(); +} diff --git a/client/client/lib/time/src/Time.hpp b/client/client/lib/time/src/Time.hpp index 93dfc964f0bef45fb86ccba203868ea995df4031..d53adb159f8f5deb092bcffa3977f550f59fcd1d 100644 --- a/client/client/lib/time/src/Time.hpp +++ b/client/client/lib/time/src/Time.hpp @@ -1,9 +1,75 @@ -#pragma once +#ifndef ESPTIME +#define ESPTIME #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 +class Time { + public: + static Time &getInstance() + { + static Time instance; // Guaranteed to be destroyed. + // Instantiated on first use. + return instance; + } + + /*! + @brief set the internal RTC time + @param epoch + epoch time in seconds + @param ms + microseconds (optional) + */ + void setTime(long epoch, int ms = 0); + + /*! + @brief get the internal RTC time as a tm struct + */ + tm getTimeStruct(); + + /*! + @brief get the time and date as an Arduino String object + @param mode + true = Long date format + false = Short date format + */ + String getDateTime(bool mode); + + /*! + @brief get the time as an Arduino String object with the specified format + @param format + time format + http://www.cplusplus.com/reference/ctime/strftime/ + */ + String getTime(String format = "%H:%M:%S"); + + /*! + @brief get the current epoch seconds as long + */ + long getEpochSeconds(); + + /*! + @brief get the current milliseconds as long + */ + long getMillis(); + + private: + Time() {} // Constructor? (the {} brackets) are needed here. + + ESP32Time rtc = ESP32Time{}; + + // C++ 11 + // ======= + // We can use the better technique of deleting the methods + // we don't want. + public: + Time(Time const &) = delete; + void operator=(Time 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 \ No newline at end of file diff --git a/client/client/src/main.cpp b/client/client/src/main.cpp index 54220bae97fb193cf0d830b9d04c57a49976f3a4..1c549ba722451f99037e2fb54643cdb5dfc91636 100644 --- a/client/client/src/main.cpp +++ b/client/client/src/main.cpp @@ -1,31 +1,44 @@ +#include "ESPNow.hpp" +#include "ram_caching.hpp" #include <Arduino.h> -#include <scd30.hpp> -#include <dr26.hpp> -#include <drs26.hpp> -#include <ina219.hpp> +#include <ArduinoJson.h> +#include "Time.hpp" +#include "f_deep_sleep.hpp" -// Forte_SCD30 scd30; -void setup() { - Serial.begin(9600); - // scd30.setup(); -} +void setup() +{ + + // put your setup code here, to run once: + Serial.begin(115200); + while (!Serial) + ; + Serial.flush(); -void loop() { - - void* data; - // data = scd30.read_data(); - - if(data==0) - { - Serial.println("Waiting for data !"); - Serial.println(); - } - // else{ - // Serial.print("Sensor CO2 "); Serial.println(data->C02); - // Serial.print("Humidity "); Serial.println(data->Humidity); - // Serial.print("Temperature "); Serial.println(data->Temperature); - // Serial.println(); - // } - delay(5000); + esp_err_t result = espnow_setup(); } + +int counter = 0; + +void loop() +{ + // put your main code here, to run repeatedly: + Message new_data = Message{}; + new_data.add_data(++counter * 1.1, 0); + new_data.add_data(counter * 1.2, 1); + new_data.add_data(counter * 1.3, 2); + espnow_send_message(new_data); + + // if(!ram_cache_is_empty()){ + // ClientDataPackage old_data = ram_cache_pop(); + // Message* resend_message = new Message(old_data); + // resend_message->send(); + // delete resend_message;u + // } + Serial.println("Saved Time Loop: " + Time::getInstance().getTime("%c")); + + Serial.println("delaying..."); + Serial.flush(); + delay(5000); // 5 second receive window + // deep_sleep(900); // go to sleep for 15 mins (900s) +} \ No newline at end of file diff --git a/host/fipy/lib/espnow.py b/host/fipy/lib/espnow.py new file mode 100644 index 0000000000000000000000000000000000000000..6afe2a8b0c2d766e626dd864c493e6a3dd8ab6e7 --- /dev/null +++ b/host/fipy/lib/espnow.py @@ -0,0 +1,57 @@ +import network +from network import ESPNOW +import time +from lib.rtc_time import RTCTime +import struct + +w = network.WLAN() +self_mac, sta = w.mac() +peer_list = [] + +class Forte_ESPNOW: + def __init__(self): + ESPNOW.init() + ESPNOW.on_recv(espnow_recv) + + def add_peer(mac): + peer_list.append(ESPNOW.add_peer(mac)) + +def espnow_respond(mac): + msg = struct.pack("<6sl", self_mac, time.time()) + print(int(time.time())) + + ESPNOW.send(mac, msg) + print("response sent") + +def espnow_recv(result): + print("message recv") + mac, peer, msg = result + + data = bytes_to_data(msg) + try: + print("amount data: " + str(data["amountData"])) + # print(data["timestamp"]) + # print(data["data"]) + + except Exception as error: + print(error) + + if(peer not in peer_list): + Forte_ESPNOW.add_peer(mac) + + espnow_respond(mac) + +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)), + } + + diff --git a/host/fipy/lib/rtc_time.py b/host/fipy/lib/rtc_time.py new file mode 100644 index 0000000000000000000000000000000000000000..d57b3944d0e00847266b988349464009d3e0a971 --- /dev/null +++ b/host/fipy/lib/rtc_time.py @@ -0,0 +1,35 @@ +from time import sleep +from machine import RTC + + +class RTCTime: + # def __init__( + # self, + # main_ntp_server: str = "pool.ntp.org", + # backup_ntp_server: str = "time.nist.gov", + # update_interval_seconds: int = 3600, + # ): + # self.rtc = RTC() + # self._setup_ntp(main_ntp_server, backup_ntp_server, update_interval_seconds) + + + def __init__(self, datetime): + self.rtc = RTC() + self.rtc.init(datetime) + + def _setup_ntp( + self, main_ntp_server: str, backup_ntp_server: str, update_interval_seconds: int + ): + print("Setting up NTP") + self.rtc.ntp_sync(main_ntp_server, update_interval_seconds, backup_ntp_server) + while not self.rtc.synced(): + print(self.rtc.synced()) + sleep(1) + + + + def get_time(self): + return self.rtc.now() + + def is_synchronized(self): + return self.rtc.synced() diff --git a/host/fipy/main.py b/host/fipy/main.py index 1735bdbadcc6e0bcfa8649fc1ee81eecab71aceb..020d027e0345c701725c418eade7e55179d05551 100644 --- a/host/fipy/main.py +++ b/host/fipy/main.py @@ -1,39 +1,9 @@ # main.py -- put your code here! -from network import WLAN -from network import ESPNOW -import binascii -import struct +# from network import ESPNOW 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) - +from lib.espnow import Forte_ESPNOW +from lib.rtc_time import RTCTime # data = DataTransferWiFi() # data.connect("Z", "AbsoluteSandwich") @@ -41,15 +11,9 @@ def espnow_recv(result): # "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) - +# +rtc_time = RTCTime((2014, 5, 1, 4, 13, 0, 0, 0)) +espnow = Forte_ESPNOW() while True: - print("...") sleep(5) pass