Hi,
I'm trying to do some flow control and have what's probably a very basic problem.
I'm syncing nodes on an esp-now network to sleep at 10 minute intervals. The master node determines the time needed to sleep and pushes this info to the nodes. I have had an issue where after sleeping, the master wakes slightly early. Rather than going back to sleep for a short period (less than a second usually) I want the master to wait until the coms window is open then contact nodes.
In the setup funciton, I'm tryng to write a while loop that will determine whether it's time to take action. If it's not, it should recalculate seconds since midnight and time to sleep untill there is 1 second left until the comms window is open, then continue.. The trouble I'm having is that the variables that are being declared in the while loop aren't available for downstream action after the loop exit, so the compiler is complaining with a "variable x not declared in scope" error. I wanted to avoid using globals for these so just wondering what the right approach is here or what I'm doing wrong.
Thanks in advance.
Code below..
#include <WiFi.h>
#include <esp_now.h>
#include <ThreeWire.h>
#include <RtcDS1302.h>
#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */
int TIME_TO_SLEEP ; /* Time ESP32 will go to sleep (in seconds) */
RTC_DATA_ATTR int bootCount = 0;
int poll_times[6] = {21600, 32400, 43200, 54000, 64800, 75600};
int poll_hrs[6] = {6, 9, 12, 15, 18, 21};
int poll_pos = 0;
int task; // node instruction
//RTC stuff
ThreeWire myWire(4, 5, 2); // IO, SCLK, CE
RtcDS1302<ThreeWire> Rtc(myWire);
#define countof(a) (sizeof(a) / sizeof(a[0]))
typedef struct dataOut_struct {
int x; // task: 0 = sleep, 1 = post
int y; // time2sleep
} dataOut_struct;
dataOut_struct dataOut;
typedef struct dataIn_struct {
int x; // ID of node
int y; // datapoint
int z; // battery
} dataIn_struct;
dataIn_struct dataIn;
void formatMacAddress(const uint8_t *macAddr, char *buffer, int maxLength) {
snprintf(buffer, maxLength, "%02x:%02x:%02x:%02x:%02x:%02x", macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]);
}
void receiveCallback(const uint8_t *macAddr, const uint8_t *data, int len) {
dataIn_struct* dataIn = (dataIn_struct*) data;
// format the mac address
char macStr[18];
formatMacAddress(macAddr, macStr, 18);
// debug log the message to the serial port
Serial.println(macStr);
Serial.println(dataIn->x);
Serial.println(dataIn->y);
Serial.println(dataIn->z);
}
// callback when data is sent
void sentCallback(const uint8_t *macAddr, esp_now_send_status_t status) {
char macStr[18];
formatMacAddress(macAddr, macStr, 18);
Serial.print("Last Packet Sent to: ");
Serial.println(macStr);
Serial.print("Last Packet Send Status: ");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
void broadcast() {
// this will broadcast a message to everyone in range
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
esp_now_peer_info_t peerInfo = {};
memcpy(&peerInfo.peer_addr, broadcastAddress, 6);
if (!esp_now_is_peer_exist(broadcastAddress)) {
esp_now_add_peer(&peerInfo);
}
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *) &dataOut, sizeof(dataOut_struct));
if (result == ESP_OK) {
Serial.println("Broadcast message success");
}
else if (result == ESP_ERR_ESPNOW_NOT_INIT) {
Serial.println("ESPNOW not Init.");
}
else if (result == ESP_ERR_ESPNOW_ARG) {
Serial.println("Invalid Argument");
}
else if (result == ESP_ERR_ESPNOW_INTERNAL) {
Serial.println("Internal Error");
}
else if (result == ESP_ERR_ESPNOW_NO_MEM) {
Serial.println("ESP_ERR_ESPNOW_NO_MEM");
}
else if (result == ESP_ERR_ESPNOW_NOT_FOUND) {
Serial.println("Peer not found.");
}
else {
Serial.println("Unknown error");
}
}
void espnow_up() {
WiFi.mode(WIFI_STA);
Serial.println("ESPNow Example");
// Output my MAC address - useful for later
Serial.print("My MAC Address is: ");
Serial.println(WiFi.macAddress());
// shut down wifi
WiFi.disconnect();
// startup ESP Now
if (esp_now_init() == ESP_OK) {
Serial.println("ESPNow Init Success");
esp_now_register_recv_cb(receiveCallback);
esp_now_register_send_cb(sentCallback);
}
else {
Serial.println("ESPNow Init Failed");
delay(3000);
ESP.restart();
}
}
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 printDateTime(const RtcDateTime& dt)
{
char datestring[20];
snprintf_P(datestring,
countof(datestring),
PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
dt.Month(),
dt.Day(),
dt.Year(),
dt.Hour(),
dt.Minute(),
dt.Second() );
Serial.print(datestring);
}
int get_ssm(const RtcDateTime& dt) {
char datestring[20];
snprintf_P(datestring,
countof(datestring),
PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
dt.Month(),
dt.Day(),
dt.Year(),
dt.Hour(),
dt.Minute(),
dt.Second() );
Serial.println("Trying to get hrs, mins, sec for ssm calcs");
int cur_hr = dt.Hour();
int cur_min = dt.Minute();
int cur_sec = dt.Second();
int ssm = (cur_hr * 3600L) + (cur_min * 60L) + cur_sec;
Serial.print("Calculated seconds since midnight: "); Serial.println(ssm);
return ssm;
}
void pollpos(int s) {
Serial.print("int passed to pollpos: "); Serial.println(s);
Serial.println("Parsing poll_times to see where we are at");
// if after 9pm, do nothing
Serial.println(poll_times[5] + 30);
if (s > (poll_times[sizeof(poll_times) - 1] + 30)) {
Serial.println("--------- test conditional past 9 pm ---------");
Serial.println("It's past 9pm. No need to do anything till morning.");
// define task as sleep
task = 0;
return;
}
else { //figure out where we are in the poll times
for (int i = 0; i < 6; i++) {
if (s > poll_times[i] + 30) { // if we are 30 seconds past polling time..
Serial.print("poll_time being queried: "); Serial.print(poll_hrs[i]);
Serial.print(":00 hrs - ");
Serial.println("moving on. Not our window");
}
else if (s < poll_times[i] - 30) { // if ssm is less than 30 seconds before polling time..
Serial.print("poll_time being queried: "); Serial.print(poll_hrs[i]);
Serial.print(":00 hrs - ");
Serial.println("We are within the current window");
task = 0;
return;
}
else if (s > poll_times[i] - 30 && s < poll_times[i] + 30) {
Serial.print("poll_time being queried: "); Serial.print(poll_hrs[i]);
Serial.print(":00 hrs - ");
Serial.println("We are within the reporting window!");
Serial.println("+++++ POLL NODES +++++");
task = 1;
return;
}
}
}
}
void setup() {
Serial.begin(115200);
delay(1000); //Take some time to open up the Serial Monitor
//Increment boot number and print it every reboot
++bootCount;
Serial.println("Boot number: " + String(bootCount));
//Print the wakeup reason for ESP32
print_wakeup_reason();
Rtc.Begin();
RtcDateTime now = Rtc.GetDateTime();
printDateTime(now);
// wait untill there is 1 second left to coms window, then move on.
boolean coms_window = false;
while (!coms_window) {
int ssm = get_ssm(now); // get seconds since midnight
long int run_start = millis(); // define start time to adjust sleep later
int adjust_sleep = 600 - (ssm % 600); // sync sleep time to 10 minute intervals.
if (adjust_sleep < 2) {
coms_window = true;
}
}
pollpos(ssm); // find position in poll_times array to determine instructions for nodes
dataOut.x = task; // task: 0 = sleep, 1 = post
dataOut.y = adjust_sleep; // sync node sleep time
espnow_up(); // start esp-now service
broadcast(); // send task instruction and sleep time to nodes
//listen for reply from nodes for 5 seconds
long int listen_start = millis();
Serial.print("waiting for reply from nodes: ");
while (millis() - listen_start < 5000) {
delay(1000);
Serial.println(".");
}
// Sleep time.
int run_end = millis();
TIME_TO_SLEEP = adjust_sleep - (run_end - run_start) / 1000;
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
Serial.println("Setup ESP32 to sleep for every " + String(TIME_TO_SLEEP) + " Seconds ");
Serial.println("Going to sleep now");
Serial.flush();
esp_deep_sleep_start();
Serial.println("This will never be printed");
}
void loop() {
//This is not going to be called
}