From a6cb499ce1a35c8b9eca058eb74cd1017066cb87 Mon Sep 17 00:00:00 2001 From: "Samuel C. Auclair" Date: Thu, 25 Apr 2024 21:46:26 -0400 Subject: [PATCH] Deep sleep and example --- .../class_a_otaa_esp_deepsleep.ino | 205 ++++++++++++++++++ src/arduino-rfm/lorawan-arduino-rfm.h | 27 ++- 2 files changed, 218 insertions(+), 14 deletions(-) create mode 100644 examples/class_a_otaa_esp_deepsleep/class_a_otaa_esp_deepsleep.ino diff --git a/examples/class_a_otaa_esp_deepsleep/class_a_otaa_esp_deepsleep.ino b/examples/class_a_otaa_esp_deepsleep/class_a_otaa_esp_deepsleep.ino new file mode 100644 index 0000000..57171c9 --- /dev/null +++ b/examples/class_a_otaa_esp_deepsleep/class_a_otaa_esp_deepsleep.ino @@ -0,0 +1,205 @@ +/** + * Example of OTAA device with ESP8266 or ESP32 using deep sleep wihtout losing LoRaWAN settings. + * A minimum number of pin is also used in this example. For slighly faster processing, + * DIO0 and DIO1 should be used. + */ +#include +#include + +// OTAA credentials +const char *devEui = "0000000000000000"; +const char *appEui = "0000000000000000"; +const char *appKey = "00000000000000000000000000000000"; + +unsigned int counter = 0; // message counter + +char myStr[50]; +char outStr[255]; +byte recvStatus = 0; + +const sRFM_pins RFM_pins = { + .CS = 15, + .RST = 2, //Could be connected to the reset ESP pin of ESP8266, if so put -1 + .DIO0 = 0, + .DIO1 = 4, + .DIO2 = -1, + .DIO5 = -1, +}; + +struct RTCRAM +{ + unsigned char DevEUI[8]; + unsigned char AppEUI[8]; + unsigned char AppKey[16]; + unsigned char DevNonce[2]; + unsigned char AppNonce[3]; + unsigned char NetID[3]; + unsigned char Address_Tx[4]; + unsigned char NwkSKey[16]; + unsigned char AppSKey[16]; + unsigned int Frame_Counter_Tx; + sSettings LoRa_Settings; + unsigned int counter; +}; +#if defined(ESP32) +RTC_DATA_ATTR RTCRAM rtcRAM; +#else +RTCRAM rtcRAM; +#endif + +void deepsleep(uint64_t us) +{ + Serial.println("We go to deep sleep"); + delay(10); + lora.sleep(); +#if defined(ESP8266) + ESP.deepSleep(us, WAKE_RF_DISABLED); +#elif defined(ESP32) + esp_sleep_enable_timer_wakeup(us); + esp_deep_sleep_start(); +#else + Serial.print("Deep sleep not supported by this example"); +#endif +} + +void saveVariableRTC() +{ + memcpy(rtcRAM.DevEUI, lora.DevEUI, sizeof(rtcRAM.DevEUI)); + memcpy(rtcRAM.AppEUI, lora.AppEUI, sizeof(rtcRAM.AppEUI)); + memcpy(rtcRAM.AppKey, lora.AppKey, sizeof(rtcRAM.AppKey)); + memcpy(rtcRAM.DevNonce, lora.DevNonce, sizeof(rtcRAM.DevNonce)); + memcpy(rtcRAM.AppNonce, lora.AppNonce, sizeof(rtcRAM.AppNonce)); + memcpy(rtcRAM.NetID, lora.NetID, sizeof(rtcRAM.NetID)); + memcpy(rtcRAM.Address_Tx, lora.Address_Tx, sizeof(rtcRAM.Address_Tx)); + memcpy(rtcRAM.NwkSKey, lora.NwkSKey, sizeof(rtcRAM.NwkSKey)); + memcpy(rtcRAM.AppSKey, lora.AppSKey, sizeof(rtcRAM.AppSKey)); + memcpy(&rtcRAM.Frame_Counter_Tx, &lora.Frame_Counter_Tx, sizeof(rtcRAM.Frame_Counter_Tx)); + memcpy(&rtcRAM.LoRa_Settings, &lora.LoRa_Settings, sizeof(rtcRAM.LoRa_Settings)); + memcpy(&rtcRAM.counter, &counter, sizeof(rtcRAM.counter)); +#if defined(ESP8266) + ESP.rtcUserMemoryWrite(32, (uint32_t *)&rtcRAM, sizeof(rtcRAM)); +#endif +} + +void loadVariableRTC() +{ +#if defined(ESP8266) + ESP.rtcUserMemoryRead(32, (uint32_t *)&rtcRAM, sizeof(rtcRAM)); +#endif + memcpy(lora.DevEUI, rtcRAM.DevEUI, sizeof(rtcRAM.DevEUI)); + memcpy(lora.AppEUI, rtcRAM.AppEUI, sizeof(rtcRAM.AppEUI)); + memcpy(lora.AppKey, rtcRAM.AppKey, sizeof(rtcRAM.AppKey)); + memcpy(lora.DevNonce, rtcRAM.DevNonce, sizeof(rtcRAM.DevNonce)); + memcpy(lora.AppNonce, rtcRAM.AppNonce, sizeof(rtcRAM.AppNonce)); + memcpy(lora.NetID, rtcRAM.NetID, sizeof(rtcRAM.NetID)); + memcpy(lora.Address_Tx, rtcRAM.Address_Tx, sizeof(rtcRAM.Address_Tx)); + memcpy(lora.NwkSKey, rtcRAM.NwkSKey, sizeof(rtcRAM.NwkSKey)); + memcpy(lora.AppSKey, rtcRAM.AppSKey, sizeof(rtcRAM.AppSKey)); + memcpy(&lora.Frame_Counter_Tx, &rtcRAM.Frame_Counter_Tx, sizeof(rtcRAM.Frame_Counter_Tx)); + memcpy(&lora.LoRa_Settings, &rtcRAM.LoRa_Settings, sizeof(rtcRAM.LoRa_Settings)); + memcpy(&counter, &rtcRAM.counter, sizeof(rtcRAM.counter)); +} + +#if defined(ESP8266) +uint32_t magicBytes; // if previous data save on rtc, this equal 'magi' (183510009) +void loadMagicByte() +{ + ESP.rtcUserMemoryRead(127, &magicBytes, sizeof(magicBytes)); +} + +void saveMagicByte() +{ + magicBytes = 183510009; + ESP.rtcUserMemoryWrite(127, &magicBytes, 4); +} +#endif + +void setup() +{ + // Setup loraid access + Serial.begin(9600); + while (!Serial) + ; + if (!lora.init()) + { + Serial.println("RFM95 not detected"); + delay(5000); + deepsleep(10000000); + } + + // Join procedure + bool isJoined = true; +#if defined(ESP8266) + loadMagicByte(); + if (magicBytes != 183510009) +#else + if (rtcRAM.counter == 0) +#endif + { + Serial.println("Cold boot Join procedure needs to be performed"); + isJoined = false; + } + + if (!isJoined) + { + // Set LoRaWAN Class change CLASS_A or CLASS_C + lora.setDeviceClass(CLASS_A); + // Set Data Rate + lora.setDataRate(SF9BW125); + // set channel to random + lora.setChannel(MULTI); + + // Put OTAA Key and DevAddress here + lora.setDevEUI(devEui); + lora.setAppEUI(appEui); + lora.setAppKey(appKey); + while (!isJoined) + { + Serial.println("Joining..."); + isJoined = lora.join(); + + // wait for 10s to try again if not join + if (!isJoined) + delay(10000); + } + Serial.println("Joined to network!\nWe now save LoRaWAN information"); + delay(100); // Necessary for ESP32 in order to properly save data on RTC ram + saveVariableRTC(); +#if defined(ESP8266) + saveMagicByte(); +#endif + } + else + { + Serial.println("Previously joined network, we applied the save parameters"); + loadVariableRTC(); + } + + // Send a upling + sprintf(myStr, "Counter-%d", counter); + Serial.print("Sending: "); + Serial.println(myStr); + lora.sendUplink(myStr, strlen(myStr), 0, 1); + counter++; + + // cycle over send and receive data with LoRa update + lora.update(); + recvStatus = lora.readData(outStr); + if (recvStatus) + { + Serial.println(outStr); + } + delay(100); // Necessary for ESP32 in order to properly save data on RTC ram + // Save pertinent information on RTC ram + saveVariableRTC(); + + // Deep sleep for 10 s + deepsleep(10000000); +} + +void loop() +{ + // We never get here + Serial.print("Oups, you use this example without an ESP device"); + delay(10000); +} \ No newline at end of file diff --git a/src/arduino-rfm/lorawan-arduino-rfm.h b/src/arduino-rfm/lorawan-arduino-rfm.h index 2fcc25d..0d92054 100644 --- a/src/arduino-rfm/lorawan-arduino-rfm.h +++ b/src/arduino-rfm/lorawan-arduino-rfm.h @@ -91,6 +91,19 @@ class LoRaWANClass unsigned int getFrameCounter(); void setFrameCounter(unsigned int FrameCounter); + // Declare public instead of private so they can be save on RTC ram in the main script before deep sleep for ESP + unsigned char DevEUI[8]; + unsigned char AppEUI[8]; + unsigned char AppKey[16]; + unsigned char DevNonce[2]; + unsigned char AppNonce[3]; + unsigned char NetID[3]; + unsigned char Address_Tx[4]; + unsigned char NwkSKey[16]; + unsigned char AppSKey[16]; + unsigned int Frame_Counter_Tx; + sSettings LoRa_Settings; + private: void randomChannel(); @@ -106,25 +119,11 @@ class LoRaWANClass void(*messageCallback)(sBuffer *Data_Rx, bool isConfirmed, uint8_t fPort) = NULL; // Declare ABP session - unsigned char Address_Tx[4]; - unsigned char NwkSKey[16]; - unsigned char AppSKey[16]; - unsigned int Frame_Counter_Tx; sLoRa_Session Session_Data; // Declare OTAA data struct - unsigned char DevEUI[8]; - unsigned char AppEUI[8]; - unsigned char AppKey[16]; - unsigned char DevNonce[2]; - unsigned char AppNonce[3]; - unsigned char NetID[3]; sLoRa_OTAA OTAA_Data; - // Declare LoRA settings struct - sSettings LoRa_Settings; - sRFM_pins LoRa_Pins; - unsigned char drate_common; // Lora Setting Class