OK comming from TTGO esp32 lora boards . I am trying out the Solar cubcell . As at the moment November 2022. the links for github and arduino are a mess. So have put my big boy pants on and coded using visual studio code( actually easier in the end than arduino). However sleep is a pain on this board. Either it won’t sleep or it will sleep and never wake up.From what i can gather from here ,it’s something to do with the lowPowerHandler(); . The principle to my code, stolen mostly from the pingpong example is. i have cube cells that sync themselves together and sleep for 20 minutes and wake for 60 seconds to mesh repeat relay reading and then sleep. while i have a esp32 lora wifi board in constant receive. sending the messages to Thingspeak. If this mesh repeater thing has already been done and all i am doing is reinventing the wheel. Put me out my misery and show me the code. Else can anyone give reliable solutions to why the code in this form just locks up. I have honestly wasted days and nights getting this far and need a solution before the cubecells will be transmitting from the rubbish bin.
#include “LoRaWan_APP.h”
#include “Arduino.h”
#include “time.h”
#include <Wire.h>
#include <string.h>
#include “SHT3x.h”
SHT3x Sensor;
#ifndef LoraWan_RGB
#define LoraWan_RGB = 0 //set both to 1 for led to work
#endif
#define RF_FREQUENCY 868000000 // Hz
#define TX_OUTPUT_POWER 5 // dBm
#define LORA_BANDWIDTH 0 // [0: 125 kHz,
// 1: 250 kHz,
// 2: 500 kHz,
// 3: Reserved]
#define LORA_SPREADING_FACTOR 7 // [SF7…SF12]
#define LORA_CODINGRATE 1 // [1: 4/5,
// 2: 4/6,
// 3: 4/7,
// 4: 4/8]
#define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx
#define LORA_SYMBOL_TIMEOUT 0 // Symbols
#define LORA_FIX_LENGTH_PAYLOAD_ON false
#define LORA_IQ_INVERSION_ON false
#define RX_TIMEOUT_VALUE 900
#define BUFFER_SIZE 255 // Define the payload size here
byte RXcount=0;
uint64_t TxLastTimne ; // timestamp last TX
uint64_t TXinterval; // time until next TX
uint64_t ThisAwake; // time spent awake
byte txpacket[BUFFER_SIZE];
byte rxpacket[BUFFER_SIZE];
byte packetList[255]; // store packets
byte pointer;
float Temp=0;
float Humid=0;
byte TXsize=0;
uint64_t TXchipID=getID();
uint16_t volts;
int SleepTime =1; //minutes
int awakeTime =50; //second
byte RecieveSync=0; //
static TimerEvent_t sleep;
static TimerEvent_t wakeUp;
bool BatteryLow;
bool debug=false; ///**** debug with print statements
RadioEvents_t RadioEvents;
void OnTxDone( void );
void OnTxTimeout( void );
void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr );
typedef enum
{
LOWPOWER,
RX,
TX
}States_t;
int16_t txNumber;
States_t state;
bool sleepMode = false;
int16_t Rssi,rxSize;
void setup() {
boardInitMcu( );
Serial.begin(115200);
txNumber=0;
Rssi=0;
RadioEvents.TxDone = OnTxDone;
RadioEvents.TxTimeout = OnTxTimeout;
RadioEvents.RxDone = OnRxDone;
Radio.Init( &RadioEvents );
Radio.SetChannel( RF_FREQUENCY );
Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH,
LORA_SPREADING_FACTOR, LORA_CODINGRATE,
LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON,
true, 0, 0, LORA_IQ_INVERSION_ON, 3000 );
Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR,
LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH,
LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON,
0, true, 0, 0, LORA_IQ_INVERSION_ON, true );
Radio.SetSyncWord(0xF2);
volts = getBatteryVoltage();
TXpacketInsert();
state=RX;
TimerInit( &sleep, onSleep );
TimerInit( &wakeUp, onWakeUp );
SetAwakeTime();
TimerSetValue( &wakeUp, (SleepTime *60000));
TxLastTimne = millis(); // timestamp the message
TXinterval =2000; //between 2.5 and 7.5 seconds next T
}
void loop()
{
if (RecieveSync==0) { // not sycned so TX interval 20 seconds
TXinterval =20000;
}
if ((millis() - TxLastTimne> TXinterval)&&(state==RX)){
TxLastTimne = millis(); // timestamp the message
TXinterval =8000; //between 1 and 7 seconds next TX
state=TX;
}
switch(state)
{
case TX:
TXPacket();
state=RX;
break;
case RX:
Radio.Rx( 0 );
break;
case LOWPOWER:
//SetAwakeTime();
lowPowerHandler();
//StopTimers();
break;
default:
break;
}
Radio.IrqProcess( );
}
void TXPacket(){
if (debug==true){
Serial.println("Get a TX packet.");
}
TXpacketGet();
if (TXsize!=0){
TXPacketPrint();
if (debug==true){
turnOnRGB(0x000050,0);// blue help shine through case
}
//turnOnRGB(COLOR_SEND,0);
Radio.Send( (uint8_t *)txpacket,TXsize); // *** remember to change the packet length to send
}
}
void OnTxDone( void )
{
if (debug==true){
Serial.print(“TX done…\r\n”);
turnOnRGB(0,0);
}
//Radio.Sleep( );
//lowPowerHandler();
//StopTimers();
state=RX;
if (RecieveSync!=0){ // sycned with other devices so do exchanges and go to sleep in 10 seconds
awakeTime=30; // seconds
}
SetAwakeTime();
}
void OnTxTimeout( void )
{
Radio.Sleep( );
if (debug==true){
Serial.print("TX Timeout......");
}
state=TX;
}
void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
{
Rssi=rssi;
rxSize=size;
memcpy(rxpacket, payload, size );
//turnOnRGB(COLOR_RECEIVED,0);
if (rxSize==18){ // found another of my nodes
RXpacketApend();
Radio.Rx( 0 );
//lowPowerHandler();
//StopTimers();
RecieveSync=3; // reset sycn to keep trying for 2 attempts so could lose contact for 3 hours
SleepTime=20; // sycned so sleep and wake together every 20 minutes
awakeTime=20; // just stay awake for another 10 seconds to see if any other node joins or transmits
SetAwakeTime();
state=RX;
}
}
void TXpacketInsert(){
pointer=1; // start at position 1 to insert packet length at 0
volts = getBatteryVoltage();
if (debug==true){
Serial.printf("ChipID:%04X%08X\r\n",(uint32_t)(TXchipID>>32),(uint32_t)TXchipID);
Serial.printf("Battery:");
Serial.println((float)volts/1000);
}
SHT30();
byte *aStr = new byte[8];
byte *bStr = new byte[8];
byte *cStr = new byte[8];
packetList[pointer]=0; // transmit recieve counter
pointer++;
int64ToChar(aStr, TXchipID);
for (int i=0;i<8;++i) {
packetList[pointer]=aStr[i];
pointer++;
}
int16ToChar(bStr, volts);
for (int i=0;i<2;++i) {
packetList[pointer]=bStr[i];
pointer++;
}
floatToChar(cStr,Temp); // pack in temperature in packet
for (int i=0;i<4;++i) {
packetList[pointer]=cStr[i];
pointer++;
}
floatToChar(cStr,Humid);
for (int i=0;i<4;++i) {
packetList[pointer]=cStr[i];
pointer++;
}
packetList[pointer]=0; // End terminated ready for appending
packetList[0]=pointer; // put the packet length at the start.
}
void TXpacketGet(){
byte BasePoint=0;
pointer=0;
TXsize=0;
while (packetList[BasePoint+pointer]!=0) {
TXsize=packetList[BasePoint+pointer]-2;
pointer++;
if (packetList[BasePoint+pointer]<2){
packetList[BasePoint+pointer]++; // increment it as going to transmit this one
pointer++; // incement to point at packet data
for (int i=0;i<TXsize;++i) {
txpacket[i]=packetList[BasePoint+pointer];
pointer++;
}
return;
}
BasePoint+=20;
pointer=0;
}
TXsize=0;
if (debug==true){
Serial.println(“Nothing to send”);
}
if ((RecieveSync != 0)&& (RXcount>10)) {
awakeTime=1; // seconds
Radio.Sleep( );
state=LOWPOWER;
}
RXcount++;
Radio.Rx( 0 );
state=RX;
}
void RXpacketApend(){
byte BasePoint=0;
pointer=0;
while (packetList[BasePoint+pointer]!=0){ // look for end zero
bool match=true;
pointer++; // Now pointing at TX RX count
pointer++; // Now pointing at Data
for (int i=0;i<rxSize;++i) {
if (packetList[BasePoint+pointer]!=rxpacket[i]){
match=false;
}
pointer++;
}
if (match==true) { // packet already in list don’t append just add recieved count and return
if (debug==true){
Serial.println("RX-packet matched already");
}
packetList[BasePoint+1]++;
return;
}
//BasePoint+=packetList[BasePoint]; // point to start of next packet and test match again
BasePoint+=20;
pointer=0;
}
if (BasePoint+rxSize>254){
Serial.print("Append packet full");
return; // if buffer full do not append
}
packetList[BasePoint+pointer]= rxSize+2;
pointer++;
packetList[BasePoint+pointer]=0; // transmit recieve counter
pointer++;
for (int i=0;i<rxSize;++i) {// check for matching ID and payload
packetList[BasePoint+pointer]=rxpacket[i];
pointer++;
}
packetList[BasePoint+pointer]=0; // End terminated ready for appending
if (debug==true){
Serial.println(“New Packet appended at”);
Serial.println( BasePoint);
}
packetList[1]=1; // Send this Device again to confirm new recieved device has it.
}
void TXPacketPrint(){
byte *aStr = new byte[8];
byte *bStr = new byte[8];
byte *cStr = new byte[8];
int pointer =0;
for (int i=0;i<8;++i) { // get Chip ID
aStr[i]=txpacket[pointer];
pointer++;
}
int64_t RXchipID = charTo64bitNum(aStr);
if (debug==true){
Serial.printf(“TX-ChipID:%04X%08X\r\n”,(uint32_t)(RXchipID>>32),(uint32_t)RXchipID);
}
for (int i=0;i<2;++i) { // get battery voltage from packet
bStr[i]=txpacket[pointer];
pointer++;
}
volts=charTo16bitNum(bStr);
if (debug==true){
Serial.printf(“TX-Battery:”);
Serial.println((float)volts/1000);
}
for (int i=0;i<4;++i) { // get temperature from packet
cStr[i]=txpacket[pointer];
pointer++;
}
Temp= charTofloatNum(cStr);
if (debug==true){
Serial.print("TX-Temperature: ");
Serial.print(Temp);
Serial.write("\xC2\xB0"); //The Degree symbol
Serial.println(“C”);
}
for (int i=0;i<4;++i) { // get Humidity from packet
cStr[i]=txpacket[pointer];
pointer++;
}
Humid= charTofloatNum(cStr);
if (debug==true){
Serial.print("TX-Humidity : ");
Serial.print(Humid);
Serial.println("%");
Serial.println("------------------------");
}
}
void onSleep()
{
Radio.Sleep( );
turnOnRGB(0,0);
if (debug==true){
Serial.printf(“Going to sleep for %d Minutes…\r\n”,SleepTime);
Serial.println();
Serial.flush();
Serial.println();
Serial.flush();
}
//TimerStop(&wakeUp);
TimerSetValue( &wakeUp, (SleepTime *60000));
TimerStart( &wakeUp );
delay(50);
//lowPowerHandler();
}
void SetAwakeTime(){
if (debug==true){
Serial.printf(“Awake for %d Seconds…\r\n”,awakeTime);
delay(50);
Serial.flush();
}
//TimerStop(&sleep);
TimerSetValue( &sleep, awakeTime*1000);
TimerStart( &sleep );
}
void onWakeUp()
{
//TimerStop(&wakeUp);
ThisAwake=millis();
if (debug==true){
Serial.println(“Just Woke Up”);
}
//StopTimers();
if (RecieveSync==0){ // lost sync or no nodes so go into long listen short sleep mode.
SleepTime=constrain(map(volts,2900,2500,1,120),1,120); // sleep for longer to charge from solar
awakeTime=71;// awake time 71 seconds
}
else
{
SleepTime=20; // minutes
awakeTime=55; // seconds
}
if(RecieveSync>0){
RecieveSync–;
}
volts = getBatteryVoltage();
if ((volts)<2500){
BatteryLow=true;
}
if ((volts)>3100){
BatteryLow=false;
}
if (BatteryLow==true){
SleepTime=120; // 2hours do long sleep
awakeTime=1; // seconds
RecieveSync=0; // no chance we will wake from recharge with sync so wake as lost sync
onSleep(); // just sleep to recharge
}
SetAwakeTime();
TimerSetValue( &wakeUp, (SleepTime *60000));
TXpacketInsert();
Radio.Rx( 0 );
state=RX;
if (debug==true){
Serial.println("");
}
TxLastTimne = millis(); // timestamp the message
TXinterval =8000; //between 2.5 and 7.5 seconds next TX
}
void SHT30() {
// Vext ON
digitalWrite(Vext, LOW);
delay(50);
Sensor.UpdateData();
Temp=Sensor.GetTemperature();
if (debug==true){
Serial.print("Temperature: ");
Serial.print(Temp);
Serial.write("\xC2\xB0"); //The Degree symbol
Serial.println(“C”);
}
Humid=Sensor.GetRelHumidity();
if (debug==true){
Serial.print("Humidity : ");
Serial.print(Humid);
Serial.println("%");
}
// Vext OFF
digitalWrite(Vext, HIGH);
}
void StopTimers() {
TimerStop(&sleep);
TimerStop(&wakeUp);
}
void StartTimers() {
TimerSetValue( &sleep, awakeTime*1000);
TimerSetValue( &wakeUp, SleepTime *60000);
TimerStart(&sleep);
TimerStart(&wakeUp);
}
// Service routines…
void int64ToChar(byte a[], int64_t n) {
memcpy(a, &n, 8);
}
void int16ToChar(byte a[], int16_t n) {
memcpy(a, &n, 2);
}
void floatToChar(byte a[], float f) {
memcpy(a, &f, sizeof(float));
}
int64_t charTo64bitNum(byte a[]) {
int64_t n = 0;
memcpy(&n, a, 8);
return n;
}
int16_t charTo16bitNum(byte a[]) {
int16_t n = 0;
memcpy(&n, a, 2);
return n;
}
float charTofloatNum(byte a[]) {
float n = 0;
memcpy(&n, a, sizeof(float));
return n;
}