adafruit / Adafruit_IO_Arduino

Arduino library to access Adafruit IO from WiFi, cellular, and ethernet modules.
Other
208 stars 108 forks source link

Max Feeds per Group AIO Arduino #142

Open Weather411 opened 3 years ago

Weather411 commented 3 years ago

--- PREVIOUSLY STATED ISSUE ON ADAFRUIT FORUM: https://forums.adafruit.com/viewtopic.php?f=56&t=172069 --- --- ADMIN REQUESTED THIS ISSUE BE POSTED HERE ---

Scoured the forum and I don't see this issue previously addressed. I've tried the same code on ESP8266 and ESP32, both show board stack errors/board resets in the Serial Monitor when I write data to more than 7 feeds to 1 group at one time. When I write data to 6 feeds (or less) to 1 group at one time, there are no stack errors/board resets. Was a weather station with many variables coming back, now simplified program to random number generator to troubleshoot.

Adafruit IO Arduino v4.0.1 ESP8266 Board v2.7.4 ESP32 Board v1.0.4

Code:

/*
 * A simple random number generator to test max number of feeds per group (written at once)
*/

/************************** Configuration ***********************************/

//edit the config.h tab and enter your Adafruit IO credentials (including WiFi, cellular or ethernet)
#include "config.h"

//set baud rate and delays
  unsigned long baud_rate = 115200;   //default value for all sketches
  unsigned long refresh_rate = 30000; //number of milliseconds between readings

//for WiFi connection
  const float txPwr = 20.5;               //transmit signal strength in dBm, max = 20.5, min = 0.0
  unsigned long WiFi_retryTime = 20000;   //number of ms to establish WiFi connection, otherwise terminate program (or force deep sleep in ver2)

//set up the group
  AdafruitIO_Group *group = io.group("Test_1");

//set up feed names (format needs to be const char *<variable> = "{FeedName}")
  const char *rn_a = "Random_Num_a";
  const char *rn_b = "Random_Num_b";
  const char *rn_c = "Random_Num_c";
  const char *rn_d = "Random_Num_d";
  const char *rn_e = "Random_Num_e";
  const char *rn_f = "Random_Num_f";
  const char *rn_g = "Random_Num_g";
  const char *rn_h = "Random_Num_h";
  const char *rn_i = "Random_Num_i";
//  const char *rn_j = "Random_Num_j";
//  const char *rn_k = "Random_Num_k";
//  const char *rn_l = "Random_Num_l";

void setup() {

  Serial.begin(baud_rate);

  /************ CAPTURE START SETUP TIME (MS) ************/
  Serial.println(); Serial.println();
  Serial.print("Millis SETUP (start) = "); Serial.println(millis());

  /************ CONNECT TO ADAFRUIT IO LIBRARY ************/
  connect_AIO();

}

void loop() {

  /************ SETUP AND WRITE TO ALL FEEDS ************/ 
    feed_write_AIO();

  /************ DELAY BETWEEN FEED WRITES ************/     
    delay(refresh_rate);

}

void connect_AIO() {
  Serial.println("Connecting to WiFi and Adafruit IO...");
  WiFi.persistent(false);  //will only change in-memory WiFi and does *not* affect the WiFi settings stored in Flash memory (saves having to rewrite Flash each "loop")
  WiFi.setOutputPower(txPwr);
  WiFi.mode(WIFI_STA);  //can be WIFI_AP, WIFI_STA, WIFI_AP_STA, or WIFI_OFF. Setting as STA will save battery.

  unsigned long wifiConnectStart = millis();
  io.connect();
  while (io.status() < AIO_CONNECTED) {
    Serial.print('.'); delay(200);  //draw dots every 200ms while attempting to connect to WiFi
    if (millis() - wifiConnectStart >= WiFi_retryTime) {
      Serial.println("Failed to connect to WiFi!!!");
      stopSketch();
    }
  }

  /******* CONNECTED TO WIFI AT THIS POINT *******/
    Serial.println(); Serial.println("WiFi connected!!");
    Serial.print("IP address: "); Serial.println(WiFi.localIP());
    Serial.println("--------------------------------------------------------------");
}

void feed_write_AIO() {
  Serial.println("Setting up and writing data to Adafruit IO feeds...");

  // io.run(); is required for all sketches
  // it should always be present at the top of your loop function
  // it keeps the client connected to io.adafruit.com, and processes any incoming data
  io.run();

/*********** GET RANDOM NUMBER VALUES ***********/
  int random_num_1 = random(1, 21);
  int random_num_2 = random(22, 41);
  int random_num_3 = random(42, 61);
  int random_num_4 = random(62, 81);
  int random_num_5 = random(82, 101);
  int random_num_6 = random(102, 121);
  int random_num_7 = random(122, 141);
  int random_num_8 = random(142, 161);
  int random_num_9 = random(162, 181);
//  int random_num_10 = random(182, 201);
//  int random_num_11 = random(202, 221);
//  int random_num_12 = random(222, 241); 

/*********** SERIAL PRINT VALUES ***********/   
  Serial.print("Random Number 01: "); Serial.print(random_num_1); Serial.println();
  Serial.print("Random Number 02: "); Serial.print(random_num_2); Serial.println();
  Serial.print("Random Number 03: "); Serial.print(random_num_3); Serial.println();
  Serial.print("Random Number 04: "); Serial.print(random_num_4); Serial.println();
  Serial.print("Random Number 05: "); Serial.print(random_num_5); Serial.println();
  Serial.print("Random Number 06: "); Serial.print(random_num_6); Serial.println();
  Serial.print("Random Number 07: "); Serial.print(random_num_7); Serial.println();
  Serial.print("Random Number 08: "); Serial.print(random_num_8); Serial.println();
  Serial.print("Random Number 09: "); Serial.print(random_num_9); Serial.println();
//  Serial.print("Random Number 10: "); Serial.print(random_num_10); Serial.println();
//  Serial.print("Random Number 11: "); Serial.print(random_num_11); Serial.println();
//  Serial.print("Random Number 12: "); Serial.print(random_num_12); Serial.println();
  Serial.println();

/******** FORMAT group->set("{FEED NAME VARIABLE}", {VALUE}) ********/
  group->set(rn_a, random_num_1);
  group->set(rn_b, random_num_2);
  group->set(rn_c, random_num_3);
  group->set(rn_d, random_num_4);
  group->set(rn_e, random_num_5);
  group->set(rn_f, random_num_6);
  group->set(rn_g, random_num_7);
  group->set(rn_h, random_num_8);
  group->set(rn_i, random_num_9);
//  group->set(rn_j, random_num_10);
//  group->set(rn_k, random_num_11);
//  group->set(rn_l, random_num_12);

  Serial.println("All group feed data set completed");

/*********** SAVE TO ADAFRUIT IO ***********/
  group->save();

  Serial.println("All group feed data SAVED");
}

/**************** TERMINATES PROGRAM VIA INFINITE LOOP ****************/
void stopSketch()
    {
     noInterrupts();
     while(true) {}
    }

This program makes it easy to troubleshoot since I just have to comment/uncomment a few lines to add or decrease number of feeds writing to the one group ("Test_1").

When I decode my stack error, I get this:

Exception 28: LoadProhibited: A load referenced a page mapped with an attribute that does not permit loads
PC: 0x4000bf80
EXCVADDR: 0x00b98e28

Decoding stack results
0x4020201d: Adafruit_MQTT::readSubscription(short) at C:\Users\Mike\Documents\Arduino\Sketches\1_Testing\libraries\Adafruit_MQTT\Adafruit_MQTT.cpp line 460
0x40100274: millis() at C:\Users\Mike\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_wiring.cpp line 188
0x402053c4: BearSSL::WiFiClientSecure::available() at C:\Users\Mike\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\libraries\ESP8266WiFi\src\WiFiClientSecureBearSSL.cpp line 394
0x4020215c: Adafruit_MQTT::processPackets(short) at C:\Users\Mike\Documents\Arduino\Sketches\1_Testing\libraries\Adafruit_MQTT\Adafruit_MQTT.cpp line 418
0x40209238: Adafruit_MQTT_Client::connected() at C:\Users\Mike\Documents\Arduino\Sketches\1_Testing\libraries\Adafruit_MQTT\Adafruit_MQTT_Client.cpp line 48
0x40201739: AdafruitIO::run(unsigned short, bool) at C:\Users\Mike\Documents\Arduino\Sketches\1_Testing\libraries\Adafruit_IO_Arduino\src\AdafruitIO.cpp line 342
0x40206b34: Print::println() at C:\Users\Mike\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\Print.cpp line 186
0x402011c6: feed_write_AIO() at C:\Users\Mike\Desktop\Temp\Arduino\AIO\AIO_RandomNumber_MaxFeedTest_Forum/AIO_RandomNumber_MaxFeedTest_Forum.ino line 94
0x402074a8: __esp_yield() at C:\Users\Mike\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_main.cpp line 119
0x40201360: loop() at C:\Users\Mike\Desktop\Temp\Arduino\AIO\AIO_RandomNumber_MaxFeedTest_Forum/AIO_RandomNumber_MaxFeedTest_Forum.ino line 57
0x402075c0: loop_wrapper() at C:\Users\Mike\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266\core_esp8266_main.cpp line 197

I really want to be able to code more than 7 feeds to one group at once. I did test another version of this program where feed data is split amongst multiple groups, and in that case, I can send more than 7 feeds (just not ideal for my needs). This will significantly impact how I'm going to code my next project so any and all help is greatly appreciated - thanks in advance!

amcmahon01 commented 1 year ago

I've been having this issue on an ESP32-S3, but I found a workable hack/potential fix. It looks like the crashes are being caused by too small of a buffer being allocated in the save() function of AdafruitIO_Group.cpp, Line 206:

char csv[150];

I changed the buffer size to 1024 bytes and it stopped the crashes/resets, but still only the first 6 feeds of the group were being updated. It looks like this truncation was due to the value similarly defined in Adafruit_MQTT.h, Line 110:

`

define MAXBUFFERSIZE (150)

`

After changing both of these to 1024, I can send 9 values without issue. I'd guess these were both created with single feed values in mind rather than group transactions, but I might be missing something in the MQTT protocol. I'm not sure if this is a really fix or if it could cause issues with applications that assume/depend on a limited packet size. My IO account overview isn't showing any errors, so that side of things appears to be OK with this (as expected given the prescribed 1kb limit per "value" in the docs).

Relevant snippets of my now working code for reference:

    AdafruitIO_Group *aq_group = io.group("air-quality");

    ...connect, get data...

    aq_group->set("battery", battPer);
    aq_group->set("temperature", ambientTemperature);
    aq_group->set("rh", ambientHumidity);
    aq_group->set("pm-1-dot-0", massConcentrationPm1p0);
    aq_group->set("pm-2-dot-5", massConcentrationPm2p5);
    aq_group->set("pm-4-dot-0", massConcentrationPm4p0);
    aq_group->set("pm-10-dot-0", massConcentrationPm10p0);
    aq_group->set("vocs", vocIndex);
    aq_group->set("nox", noxIndex);
    aq_group->save();
    io.run();
Weather411 commented 1 year ago

It's been such a long time since I wrote this, I had given up hope that Adafruit (or anyone else) would ever address and/or fix. I have since figured out other methods (using URL concatenation with api calls) but it's good to know that there is this workaround within this library. Thanks for taking the time to write your solution, Andrew. Cheers!