Arduino ESP32 stops posting to ThingSpeak after random times (error -301)

The following code runs on an Adafruit ESP32 Feather that connects to the internet via my ASUS RT-N66U router. The ESP32 is "remote" and is accessible only via wifi.
It posts to ThingSpeak every 10 minutes and works fine for a day, sometimes a few days, but then it stops posting and returns error -301 ("failed to connect") with every attempt. It only starts posting again after a hard reboot.
I suspected heap fragmentation, but free heap is constant at 247k (after an initial quick decline from 250k) and max allocatable heap is constant at 114k from the start.
ESP32 hasn't lost wifi connectivity, since I can access the ESP32 via the router (and run the "server.on" commands).
I also have an ESP8266 posting to ThingSpeak every five minutes and it has been online for months, so the problem probably isn't with the router or ISP.
Even after the ESP32 stops posting, I can successfully manually post from a browser with https://api.thingspeak.com/update.json?api_key=xyz&field5=199, so it seems the problem is with the code.
I'm running the latest ThingSpeak library, ESP library and core (but not developmental version), and Arduino IDE.
Would appreciate suggestions on things to try or monitor.
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ArduinoOTA.h>
#include <ESP_Mail_Client.h>
#include <esp_int_wdt.h> // for hard reboot
#include <esp_task_wdt.h>// ditto
#include "ThingSpeak.h" // "always put this last in the list of includes"
WebServer server(80); // OTA and server.on
WiFiClient client; // TS only
//**** definitions etc ****
#define SMTP_HOST "smtp.gmail.com"
#define SMTP_PORT 465
#define AUTHOR_EMAIL "xyz@gmail.com"
#define AUTHOR_PASSWORD "abc"
SMTPSession smtp;
void smtpCallback(SMTP_Status status);
ESP_Mail_Session session;
SMTP_Message message;
const char * myWriteAPIKey = "efg"; // TS
const byte deltaDecreaseCM = 30; // threshold in cm... 12" = 30.48 cm
const int distAvg = 1060; // average distance
const unsigned long myChannelNumber = 123; // TS
bool paused = false;
bool savedPaused;
bool intruder = false;
bool alarmSounded = false;
bool snowing = false;
bool snowTriggeredOnce = false;
bool distSaving = true;
byte reqdNumBreaks = 6;
byte lastTSalarmFlag;
byte snowFactor = 1;
byte savedSnowFactor;
byte snowCount;
byte saveDist[100];
byte saveIdx = 99;
int distCurrent;
int savedDistance;
int lastTScode = 200;
int wiFiFailsTS;
unsigned long numIntruders; // can be very large if beam is blocked for a long time (eg. by parked car)
unsigned long alarmTriggeredTime;
unsigned long prevTSfailTime = 0;
unsigned long startSnowingTime;
unsigned long firstSnowTrigger;
unsigned long pauseStartTime;
unsigned long pauseDuration;
//**** setup ****
void setup()
{
Serial1.begin(115200); // TF03 default rate = 115200
WiFi.begin();
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
delay(5000);
ESP.restart();
}
setupMail();
server.on("/", handleRoot);
server.on("/reboot", reBootMe);
server.on("/postTS", doTSpost);
server.on("/showTS", showTScode);
server.onNotFound(handleNotFound);
ArduinoOTA.begin();
server.begin();
ThingSpeak.begin(client);
readTFxTimes(50); // clear serial1 buffer
}
//***************************************************************************************
//**** loop ****
//***************************************************************************************
void loop() {
ArduinoOTA.handle(); // this works even if posting to TS does not work
server.handleClient(); // ditto
unsigned long currTime = millis();
const unsigned long writeTSinterval = 600000UL; // post to TS every 10 min (and upon sounding alarm)
static unsigned long prevTSwriteTime = 0;
const unsigned long maxAlertInterval = 600000UL; // no duplicate alarms for 10 min after an alarm
// reset pause flag if time is up
if (paused && (currTime - pauseStartTime > pauseDuration)) {
paused = false;
}
// reset alarm flag if time is up
if (alarmSounded && (currTime - alarmTriggeredTime > maxAlertInterval)) {
alarmSounded = false;
}
readTFxTimes(1); // read TF03 once every loop
if (! paused && ! alarmSounded) { // chk for intruder, but only if not paused and not w/in 10 min of an alarm
chkForIntruder();
if (intruder && (numIntruders == reqdNumBreaks * snowFactor)) soundAlarm(); // sound alarm if sufficient number of sequential brks
}
// post to thingSpeak
if (prevTSfailTime) { // if an alarmFlag=1 write failed (posted too soon after an alarmFlag=0 post)
if (currTime - prevTSfailTime > 20000UL) { // try again after 20 sec (15.1 sec didn't seem to work on 1/27 when there was a collision)
prevTSfailTime = 0;
prevTSwriteTime = currTime;
writeThingSpeak(1, savedDistance, savedSnowFactor, savedPaused);
//this will only do one re-try. If this fails again with -401 (for whatever reason)
//it will just continue on with normal (alarmFlag=0) posts after 10 minutes.
}
} else if ((currTime - prevTSwriteTime > writeTSinterval) && (! intruder)) {
prevTSwriteTime = currTime;
writeThingSpeak(0, distCurrent, snowFactor, paused); // zero indicates no alarmFlag
}
}
//***************************************************************************************
//**** writeThingSpeak ****
//***************************************************************************************
void writeThingSpeak(byte alarmF, int distC, byte snowF, bool pausD) {
if (WiFi.status() != WL_CONNECTED) { // should already be connected, but check again anyway
wiFiFailsTS++; //this has never been > 1
while (WiFi.status() != WL_CONNECTED) {
WiFi.begin();
delay(5000);
}
}
int freeHeap = ESP.getFreeHeap();
int maxAllocatable = ESP.getMaxAllocHeap();
ThingSpeak.setField(1, distC);
ThingSpeak.setField(2, alarmF); // 0 = no intruder; 1 = intruder; 4 = manual test post
ThingSpeak.setField(3, snowF); // 1 = no snow; other = snowing
ThingSpeak.setField(4, pausD);
ThingSpeak.setField(5, lastTScode);
ThingSpeak.setField(6, freeHeap);
ThingSpeak.setField(7, maxAllocatable);
ThingSpeak.setField(8, wiFiFailsTS);
lastTScode = ThingSpeak.writeFields(myChannelNumber, myWriteAPIKey);
readTFxTimes(50); // in case the above takes "a while". 100 = about one second of reads, so 50 is about half a second
/*
https://github.com/mathworks/thingspeak-arduino
Return Codes
Value Meaning
200 OK / Success
404 Incorrect API key (or invalid ThingSpeak server address)
-101 Value is out of range or string is too long (> 255 characters)
-201 Invalid field number specified
-210 setField() was not called before writeFields()
-301 Failed to connect to ThingSpeak <-------------------------------
-302 Unexpected failure during write to ThingSpeak
-303 Unable to parse response
-304 Timeout waiting for server to respond
-401 Point was not inserted (most probable cause is the rate limit of once every 15 seconds)
0 Other error
*/
}
//**** chkForIntruder ****
void chkForIntruder() {
int deltaDist = distAvg - distCurrent;
if (distSaving) { // not currently accessible (deleted the associated server.on)
saveIdx = (saveIdx + 1) % 100;
if (deltaDist < 0) {
saveDist[saveIdx] = 0;
} else {
saveDist[saveIdx] = deltaDist;
}
}
if (deltaDist > deltaDecreaseCM) { // if distance descreases more than the limit, then there's an intruder
intruder = true;
numIntruders++; // number of sequential breaks, actually
} else {
if (snowing) {
if (millis() - startSnowingTime < 1800000UL) {
if ((reqdNumBreaks / 2 < numIntruders) && (numIntruders < reqdNumBreaks)) snowCount++;
} else { // time is up
if (! snowCount) { // if snowCount == 0, reset flag and factor
snowing = false;
snowFactor = 1;
} else { // snowCount was > 0, so need to keep checking...
startSnowingTime = millis(); // reset time, so check again later
snowCount = 0; // restart count for this new period
} // end "else" (snow count > 0)
} // end "else" (time is up)
} else { // end "if snowing"
if (snowTriggeredOnce) {
if (millis() - firstSnowTrigger > 300000UL) { // triggered once, but time expired, so re-set flag
snowTriggeredOnce = false;
} else if ((reqdNumBreaks / 2 < numIntruders) && (numIntruders < reqdNumBreaks)) { // triggered once, time not expired, meets criteria...set snowing flag, etc.
startSnowingTime = millis();
snowing = true;
snowFactor = 4;
snowTriggeredOnce = false;
distSaving = false;
} //end snowTriggeredOnce
} else if ((reqdNumBreaks / 2 < numIntruders) && (numIntruders < reqdNumBreaks)) { // not triggered yet, but meets criteria, so set triggered once flag, etc.
snowTriggeredOnce = true;
firstSnowTrigger = millis();
} // end not triggered yet but meets criteria
} // end "not snowing"
intruder = false;
numIntruders = 0;
} // end "else" distance not decreased...so no intruder, and numIntruders reset to zero
}
//**** soundAlarm ****
void soundAlarm() {
alarmTriggeredTime = millis();
alarmSounded = true;
sendMyMailNow(); //send an alert
if (snowing && (startSnowingTime - alarmTriggeredTime < 5000)) {
snowing = false;
snowFactor = 1;
}
writeThingSpeak(1, distCurrent, snowFactor, paused); // 1 indicates intruder
if (lastTScode == -401) {
prevTSfailTime = millis();
savedDistance = distCurrent;
savedSnowFactor = snowFactor;
savedPaused = paused;
}
}
//**** readTFxTimes ****
void readTFxTimes(byte numOfReads) {
for (byte i = 0; i < numOfReads; i++) {
while (! readTF03once()) { //read until a number is obtained
}
}
}
//**** readTF03once ****
bool readTF03once() {
int check; // checksum
byte uart[9]; // stores each byte of data returned by LiDAR (was int... I changed to byte)
const byte HEADER = 0x59; // data package frame header...the letter "Y" in ASCII (was int... I changed to byte)
if (Serial1.available()) { //check whether the serial port has data input
if (Serial1.read() == HEADER) { // determine data package frame header = 0x59
uart[0] = HEADER;
if (Serial1.read() == HEADER) { // determine data package frame header = 0x59
uart[1] = HEADER;
for (byte i = 2; i < 9; i++) { // store rest of data to array
uart[i] = Serial1.read();
}
check = uart[0] + uart[1] + uart[2] + uart[3] + uart[4] + uart[5] + uart[6] + uart[7];
if (uart[8] == (check & 0xff)) { // check the received data as per protocols 0xff = 0b11111111
// Not sure why bitwise and (&) is used.
distCurrent = uart[2] + uart[3] * 256; // calculate distance value
return true; //got a reading
}
}
}
}
distCurrent = 0;
return false; //didn't get a reading
}
void handleRoot() {
if (server.arg("pause") != "") { // i.e., if not zero, then user entered ...?pause=(a number)
paused = true;
pauseDuration = (unsigned long) server.arg("pause").toInt(); // in minutes
pauseStartTime = millis();
if (pauseDuration <= 0) { // if neg, do nothing
paused = false;
} else if (pauseDuration > 1200) { // if large, limit to 1200 minutes = 20 hours
pauseDuration = 1200UL;
intruder = false; // so posting to TS continues during pause
numIntruders = 0;
} else { // otherwise, use received value
intruder = false; // so posting to TS continues during pause
numIntruders = 0;
}
pauseDuration *= 60000UL; // convert minutes to milliseconds
server.send(200, "text/plain", "pausing");
} else { // not break or pause
server.send(200, "text/plain", "ESP32 eye .151");
}
}
void reBootMe() { // run with /reboot
// see e32hardReset in test_espB folder for basis of this
server.send(200, "text/plain", "reboot in 2");
delay(2000);
esp_task_wdt_init(1, true);
esp_task_wdt_add(NULL);
while (true);
}
void doTSpost() { // run with /postTS
server.send(200, "text/plain", "posting a 2 to TS");
writeThingSpeak(2, distCurrent, snowFactor, paused);
}
void showTScode() { // run with /showTS
char myCstr[15];
snprintf(myCstr, 15, "TScode=%d", lastTScode);
server.send(200, "text/plain", myCstr);
}
void handleNotFound() {
server.send(404, "text/plain", "404: Not found");
}
void smtpCallback(SMTP_Status status) {
Serial.println(status.info());
if (status.success())
{
Serial.println("----------------");
Serial.printf("Message sent success: %d\n", status.completedCount());
Serial.printf("Message sent failled: %d\n", status.failedCount());
Serial.println("----------------\n");
struct tm dt;
for (size_t i = 0; i < smtp.sendingResult.size(); i++)
{
SMTP_Result result = smtp.sendingResult.getItem(i);
localtime_r(&result.timesstamp, &dt);
Serial.printf("Message No: %d\n", i + 1);
Serial.printf("Status: %s\n", result.completed ? "success" : "failed");
Serial.printf("Date/Time: %d/%d/%d %d:%d:%d\n", dt.tm_year + 1900, dt.tm_mon + 1, dt.tm_mday, dt.tm_hour, dt.tm_min, dt.tm_sec);
Serial.printf("Recipient: %s\n", result.recipients);
Serial.printf("Subject: %s\n", result.subject);
}
Serial.println("----------------\n");
}
}
void setupMail() {
smtp.debug(0); // 0 = none
smtp.callback(smtpCallback);
session.server.host_name = SMTP_HOST;
session.server.port = SMTP_PORT;
session.login.email = AUTHOR_EMAIL;
session.login.password = AUTHOR_PASSWORD;
session.login.user_domain = "mydomain.net";
message.sender.name = "ESP Mail";
message.sender.email = AUTHOR_EMAIL;
message.subject = "Test sending plain text Email";
message.addRecipient("Someone", "phoneNum@mms.cricketwireless.net");
message.text.content = "This is simple plain text message";
message.text.charSet = "us-ascii";
message.text.transfer_encoding = Content_Transfer_Encoding::enc_7bit;
message.priority = esp_mail_smtp_priority::esp_mail_smtp_priority_normal;
message.response.notify = esp_mail_smtp_notify_success | esp_mail_smtp_notify_failure | esp_mail_smtp_notify_delay;
message.addHeader("Message-ID: <abcde.fghij@gmail.com>");
}
void sendMyMailNow() {
if (!smtp.connect(&session)) {
Serial.println("failed to connec to smtp sesh");
return;
} else if (!MailClient.sendMail(&smtp, &message)) { /* Start sending Email and close the session */
//Serial.println("Error sending Email, " + smtp.errorReason());
}
}

10 comentarios

I had a similar -301 issue. It only occurred when using a wifi repeater listening to the church wifi at my local church. (I have a project to monitor the time-keeping of the tower clock.)
I tried waiting a bit then reconnecting following a -301 result and that improved matters, but didn't solve. Same system worked reliably at home, and at home via a repeater.
Raspberry Pi works fine in the church situation. I have given up on the ESP32 implementation but will revisit if you guys come up with a solution.
Thanks for posting. Do you still have a copy of the code that had the -301 problem? If so, please post it, if you don't mind.
I wonder if it has something to do with low RSSI. Mine is around -65, which isn't great. But even so, it can operate reliably for several days...until it doesn't. And I'd hope that the ESP32 would be robust enough to reconnect after a connection failure. Maybe it isn't.
A solution is to have the code reboot the ESP32 when a -301 is encountered, or maybe after two in a row. Currently, I have ThingSpeak notify me when posting stops, and I reboot manually (via my "reBootMe" server.on subroutine). It works. It would be easy to call that in code upon a -301, but I'd rather get to the bottom of the problem.
// needs two wdt libs...see includes at top of code in OP
void reBootMe() { // run with /reboot
esp_task_wdt_init(1, true);
esp_task_wdt_add(NULL);
while (true);
}
Have just tried out the following code, in the church environment. I have used bluetooth serial to print out some messages, and captured these on my phone, since the ESP32 is running headless. The code is based on Arduino Examples
#include "BluetoothSerial.h"
#include "ThingSpeak.h"
#include "secrets.h"
#include <WiFi.h>
BluetoothSerial SerialBT;
WiFiClient client;
char ssid[] = SECRET_SSID; // your network SSID (name)
char pass[] = SECRET_PASS; // your network password
int keyIndex = 0; // your network key Index number (needed only for WEP)
unsigned long myChannelNumber = SECRET_CH_ID;
const char * myWriteAPIKey = SECRET_WRITE_APIKEY;
int number = 0;
int led = 2; //ESP32 DevKitV1
//int led = 13; //ESP32 with SIM800
boolean TS_OK;
void setup()
{
pinMode(led,OUTPUT);
digitalWrite(led,HIGH); //turn on blue on-board LED
WiFi.mode(WIFI_STA);
ThingSpeak.begin(client); // Initialize ThingSpeak
SerialBT.begin("ESP32DEVKITV1"); //Bluetooth device name
delay(2000); //wait a couple of seconds to see the LED
}
void loop()
{
// Connect or reconnect to WiFi
if(WiFi.status() != WL_CONNECTED)
{
while(WiFi.status() != WL_CONNECTED)
{
WiFi.begin(ssid, pass); // Connect to WiFi network.
delay(5000);
}
digitalWrite(led, LOW); //turn off led to show WiFi connected
}
// Repeatedly write number to field1 of myChannelNumber at ThingSpeak until successful.
TS_OK = false;
while (TS_OK == false)
{
int x = ThingSpeak.writeField(myChannelNumber, 1, number, myWriteAPIKey);
if(x == 200) //successful write
{
SerialBT.println("Channel update successful " + String(number));
TS_OK = true;
number +=1;
if (number == 60) number = 0;
}
else
{
SerialBT.println("Problem updating channel. HTTP error code " + String(x));
delay(10000); //try again in 10 seconds
}
}
delay(60000); // Wait 60 seconds to update the channel again
}
The bluetooth messages are:
12:39:20.515 Connecting to ESP32DEVKITV1 ...
12:39:22.067 Connected
12:40:06.677 Problem updating channel. HTTP error code -301
12:40:21.428 Connection lost
12:40:35.696 Connecting to ESP32DEVKITV1 ...
12:40:36.945 Connected
12:40:39.999 Channel update successful 0 indentation applied manually to help viewing the data
12:41:40.211 Problem updating channel. HTTP error code -301
12:41:51.180 Channel update successful 1
12:42:51.032 Problem updating channel. HTTP error code -301
12:43:02.006 Channel update successful 2
12:44:02.356 Problem updating channel. HTTP error code -301
12:44:16.899 Connection lost
12:48:30.538 Connecting to ESP32DEVKITV1 ...
12:48:33.826 Connected
12:48:43.171 Problem updating channel. HTTP error code -301
12:48:54.123 Channel update successful 1
12:49:53.974 Problem updating channel. HTTP error code -301
12:50:08.956 Connection lost
12:50:20.428 Connecting to ESP32DEVKITV1 ...
12:50:20.708 Connected
12:50:27.703 Channel update successful 0
12:51:27.739 Problem updating channel. HTTP error code -301
12:51:38.665 Channel update successful 1
12:52:39.053 Problem updating channel. HTTP error code -301
12:52:49.982 Channel update successful 2
12:53:49.881 Problem updating channel. HTTP error code -301
12:54:01.347 Channel update successful 3
12:55:00.704 Problem updating channel. HTTP error code -301
12:55:15.684 Connection lost
12:56:11.636 Connecting to ESP32DEVKITV1 ...
12:56:12.692 Connected
12:56:34.670 Problem updating channel. HTTP error code -301
12:56:45.396 Channel update successful 1
12:57:45.290 Problem updating channel. HTTP error code -301
12:57:56.259 Channel update successful 2
12:58:56.613 Problem updating channel. HTTP error code -301
12:59:07.466 Channel update successful 3
13:00:07.433 Problem updating channel. HTTP error code -301
13:00:18.402 Channel update successful 4
13:01:18.754 Problem updating channel. HTTP error code -301
13:01:29.728 Channel update successful 5
13:02:29.580 Problem updating channel. HTTP error code -301
13:02:40.504 Channel update successful 6
13:03:40.401 Problem updating channel. HTTP error code -301
13:03:55.384 Connection lost
13:04:01.674 Connecting to ESP32DEVKITV1 ...
13:04:03.318 Connected
13:04:14.057 Channel update successful 0
The very first connection attempt seems to work OK: see the entry at 12:40:39 Then a subsequent connection attempt fails, the code waits for 10 seconds, has another go, and succeeds: see entries at 12:41:40, 12:41:51. Ditto at 12:42 to 12:43.
At 12:44 the fourth attempt fails, but the retry is also unsuccessful - not only unsuccessful, but causes the system to crash and the BT connection is lost. I subsequently re-established the link to my phone, and things repeat.
The best run I had this morning was for 7 connections.
You can see the results of the uploads on TS channel 1208350:
The entries at the start of the chart were successful posts from the the bench, here at home.
The ESP32 is clearly restarting itself following the unsuccessful retries. I haven't managed to capture any system error messages in the church environment.
Thx. Will be out most of today. Will look at this tonight or tomorrow.
David Evans
David Evans el 8 de Feb. de 2021
Editada: David Evans el 9 de Feb. de 2021
@Vinod would you please take a look at @John Rice code and serial output? His code is about as simple as it gets, with only the Bluetooth library in addition to WiFi and ThingSpeak, so it doesn't seem like it could be library conflicts.
Is there something in the ThingSpeak library that needs to be tailored for the ESP32? Do ThingSpeak servers have some timeout/reconnect issue? Any other ideas?
PS: note that power cycling my router didn't help...see post in the following string...
I've started using an ESP32 and also after a few days have found gaps in data uploaded to ThingSpeak. I've added additional code to trigger a restart ( ESP.restart() ) after 5 failed ThingSpeak update attempts, and also if the WiFi connection is lost. This additional diagnostics shows the same apparent behaviour:
13:39:43.798 -> Got IP: 192.168.0.35
13:39:43.798 -> HTTP server started
13:39:43.798 -> ThingSpeak initialised
13:44:44.330 -> Problem updating channel. HTTP error code -301
13:49:40.344 -> Problem updating channel. HTTP error code -301
13:54:40.326 -> Problem updating channel. HTTP error code -301
13:59:40.336 -> Problem updating channel. HTTP error code -301
14:04:40.320 -> Problem updating channel. HTTP error code -301
I'll read the thread in depth to see if the suggestions cure my issue as the ESP.restart() does not appear to be sufficient.
Thanks for posting - misery loves company! We're just wandering around in the dark at the moment. The only thing that works for me is the reboot code in my original post, reproduced below, but it doesn't get at the root of the problem.
// needs two wdt libs...see includes at top of code in OP
void reBootMe() { // run with /reboot
esp_task_wdt_init(1, true);
esp_task_wdt_add(NULL);
while (true);
}
As one additional piece of information, are you folks logging the RSSI of your WiFi signal? Also, can you describe your networking setup -is it just a wifi connection to a single router connected to the cable modem, or are there wifi extenders involved?
ESP32->router->cable modem. Yes, I tracked RSSI for a while - it was around -63 to -65 dBm. I have never lost the wifi connection, fwiw.
When I was getting 301 errors and WiFi connection issues, I added an ESP.restart if I had lost my WiFi connection, and often after this, the problems just continued. I then changed the WiFi connection check (in the loop() function) to just disconnect and reconnect. So far the system has been stable.
if (WiFi.status() != WL_CONNECTED) {
Serial.println("Reconnecting to WiFi...");
WiFi.disconnect();
WiFi.reconnect();
}

Iniciar sesión para comentar.

Respuestas (1)

Vinod
Vinod el 4 de Feb. de 2021
Thank you for trying to eliminate some of the potential issues and posting what you've tried before posting. That certainly helps me suggest some things you may not have tried.
Can you try slimming down your code to remove the WebServer and ArduinoOTA libraries from your sketch? My suspicion is there is possibly some conflict between those libraries and the WiFiClient's ability to open outgoing network connections. Maybe a resource leak on Network port connections which ultimately makes it impossible to open outgoing connections.

40 comentarios

David Evans
David Evans el 5 de Feb. de 2021
Editada: David Evans el 5 de Feb. de 2021
Thank you for the reply. I can't eliminate the OTA library, since that's the only way I can access the device (without great difficulty) and eliminating the WebServer library will kill one of the important functions. Is there some code I can add to monitor network resources?
PS: I've also thought about deleting the email capability/library but haven't tried that yet. That's one big difference between my long-running, no-problems ESP8266 and this ESP32 with problems: the 8266 doesn't do email (it does have OTA and WebServer). Of course, they're completely different microcontrollers......
Also, fyi, the "failed to connect" and subsquent never-connect-again don't seem to be related to any OTA or WebServer activity. The failures always occurs after a long string (hours) of just posting to ThingSpeak.
That makes me wonder if it has to do with DNS caching. Are you using a WiFi connection or a GSM modem for connectivity from your ESP32?
Rather than rebooting the ESP32, does restarting your router get the updates to happen automatically? If so, then it is likely a DNS caching issue.
Thanks again. It's a WIFI connection via my router (ASUS RT-N66U). If it is a DNS caching issue, wouldn't my ESP8266 have the same problem? It continously posts to ThingSpeak every five minutes, with zero connection issues, ever. Well, anyway, the next time it happens, I'll try restarting the router and let you know the outcome!
If you have another device on the same network working fine, it is unlikely DNS caching issue. This then might have to do with the libraries on the ESP32. The suggestion I have is to compare the differences in the libraries used in the code on the ESP8266 and the ESP32 and eliminate bits to determine where the issue is.
David Evans
David Evans el 5 de Feb. de 2021
Editada: David Evans el 5 de Feb. de 2021
Ok. I'll start with disabling the email library on the ESP32. That will be the simplest to try. But also, is there any way to monitor "resource leaks on the Network port connections"? (As mentioned in my 1st post, free heap is stable at a high value.)
David Evans
David Evans el 8 de Feb. de 2021
Editada: David Evans el 9 de Feb. de 2021
I haven't disabled the email library yet...was waiting for the problem to happen so I could try power cycling the router first. It stopped posting to TS again yesterday (continuous -301 errors, as usual), so I tried power cycling the router instead of rebooting the ESP32. No joy.
I'm running out of ideas. I've read forums which say the ESP32's BLE stack can interfere with WiFi. Can you try disabling the BLE stack and seeing if the issue recurs?
That may work for @John Rice, but I'm not doing Bluetooth... :(
Vinod
Vinod el 9 de Feb. de 2021
Editada: Vinod el 9 de Feb. de 2021
You may not be using it, but the BLE radio may be on by default. Can you try your code with explicitly stopping the Bluetooth stack?
Here's a link with info on the relevant APIs. I believe you need to call esp_bt_controller_disable() followed by esp_bt_controller_deinit() in your setup().
Thank you. Will try it and follow up.
I think btStop(); will stop BT. I tried it this morning, but also used WiFi client code - see below (URL is "api.thingspeak.com" - to connect to TS. Wouldn't even connect once when tried in the church environment, although OK-ish at home. Will try stopping BT and use ThingSpeak.h library tomorrow morning.
if (client.connect(URL, 80))
{
//Serial.println("Connected to TS " + String(number));
//SerialBT.println("Connected to TS " + String(number));
String postStr = apiKey;
postStr += "&field1=";
postStr += number;
postStr += "\r\n\r\n\r\n\r\n";
client.print("POST /update HTTP/1.1\n");
client.print("Host: api.thingspeak.com\n");
client.print("Connection: close\n");
client.print("X-THINGSPEAKAPIKEY: " + apiKey + "\n");
client.print("Content-Type: application/x-www-form-urlencoded\n");
client.print("Content-Length: ");
client.print(postStr.length());
client.print("\n\n");
client.print(postStr);
TS_OK = true;
number += 1;
if (number == 60) number = 0;
}
Thanks - I was also thinking of ditching the ThingSpeak library and trying Wifi client code, like you, or HTTPClient code...example below. Haven't had time to try those or stopping BT yet, but I plan to and will report back.
/*
Rui Santos
Complete project details at Complete project details at https://RandomNerdTutorials.com/esp32-http-post-ifttt-thingspeak-arduino/
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
https://www.mathworks.com/help/thingspeak/writedata.html
*/
#include <WiFi.h>
#include <HTTPClient.h>
const char* serverName = "http://api.thingspeak.com/update";
String apiKey = "REPLACE_WITH_YOUR_API_KEY";
unsigned long lastTime = 0;
unsigned long timerDelay = 600000;
void setup() {
Serial.begin(115200);
WiFi.begin();
Serial.println("Connecting");
while(WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(""); Serial.println(WiFi.localIP());
randomSeed(analogRead(33));
}
void loop() {
if ((millis() - lastTime) > timerDelay) {
if(WiFi.status()== WL_CONNECTED){
HTTPClient http; // <--- Evans asks...shouldn't this be above setup()???
http.begin(serverName);
http.addHeader("Content-Type", "application/x-www-form-urlencoded");
String httpRequestData = "api_key=" + apiKey + "&field1=" + String(random(40));
int httpResponseCode = http.POST(httpRequestData);
/*
// If you need an HTTP request with a content type: application/json, use the following:
http.addHeader("Content-Type", "application/json");
// JSON data to send with HTTP POST
String httpRequestData = "{\"api_key\":\"" + apiKey + "\",\"field1\":\"" + String(random(40)) + "\"}";
// Send HTTP POST request
int httpResponseCode = http.POST(httpRequestData);*/
Serial.print("HTTP Response code: "); Serial.println(httpResponseCode);
http.end();
}
else {
Serial.println("WiFi Disconnected");
}
lastTime = millis();
}
}
This link from github
suggests the following in lieu of btStop(). Similar to what @Vinodrecommended, but with a few more commands.
Need these libs...
#include "esp_bt_main.h"
#include "esp_bt.h"
esp_bluedroid_disable();
esp_bluedroid_deinit();
esp_bt_controller_disable();
esp_bt_controller_deinit();
//At the end you can try to add this to release heap:
esp_bt_mem_release(ESP_BT_MODE_BTDM);
David Evans
David Evans el 10 de Feb. de 2021
Editada: David Evans el 10 de Feb. de 2021
I have added the five "disable/deinit/release BT" commands in previous comment. Still with the TS library. Haven't disabled email yet, either. Fingers crossed...but not holding my breath.
David Evans
David Evans el 11 de Feb. de 2021
Editada: David Evans el 11 de Feb. de 2021
Well, that didn't take long. -301 error after about two hours of successful posting every 10 minutes. So, stopping BT didn't help. Using the client.print or HTTPclient approach next (and not the ThingSpeak library).
Martin Rice
Martin Rice el 11 de Feb. de 2021
Editada: Vinod el 11 de Feb. de 2021
Same here: issuing btStop(); in setup() didn't help in my situation.
However, allowing PRINT_DEBUG_MESSAGES in ThingSpeak.h did! I couldn't quite believe that my system worked reliably for over 12 hours, one post every 70 seconds. When I say 'worked reliably' I mean every first attempt at connecting failed, but then succeeded 10 seconds later, so it's not exactly working according to plan, but it is working.
Here is an excerpt from the messages ThingSpeak.h prints.
  • 17:31:07.157 -> Serial comms OK
17:31:07.251 -> ts::tsBegin
17:31:14.282 -> ts::writeField (channelNumber: 1208350 writeAPIKey: REDACTED field: 1 value: "0")
17:31:14.282 -> ts::writeRaw (channelNumber: 1208350 writeAPIKey: REDACTED
17:31:14.282 -> Connect to default ThingSpeak: api.thingspeak.com:80...Failed.
17:31:18.267 -> Problem updating channel. HTTP error code -301
17:31:28.297 -> ts::writeField (channelNumber: 1208350 writeAPIKey: REDACTED field: 1 value: "-1")
17:31:28.297 -> ts::writeRaw (channelNumber: 1208350 writeAPIKey: REDACTED
17:31:28.297 -> Connect to default ThingSpeak: api.thingspeak.com:80...Success.
17:31:28.579 -> POST "field1=-1&headers=false"
17:31:29.235 -> Got Status of 200
17:31:29.235 -> Content Length: 3
17:31:29.235 -> Found end of header
17:31:29.235 -> Response: "424"
17:31:29.235 -> Entry ID "424" (424)
17:31:29.235 -> disconnected.
  • 17:31:29.235 -> Channel update successful -1
The bullet point entries are from my code, the rest from ThingSpeak.h
I don't thing this reveals an awful lot, but it seems to me to point to some critical timing issue.
Here's what happened when I turned off the printing this morning:
09:40:03.830 -> Serial comms OK
09:40:14.906 -> Problem updating channel. HTTP error code -301
09:40:25.851 -> Channel update successful 0
09:41:25.841 -> Problem updating channel. HTTP error code -301
09:41:36.781 -> Channel update successful 1
09:42:36.811 -> Problem updating channel. HTTP error code -301
09:42:47.733 -> Channel update successful 2
09:43:47.751 -> Problem updating channel. HTTP error code -301
09:43:58.692 -> Channel update successful 3
09:44:58.724 -> Problem updating channel. HTTP error code -301
09:45:09.659 -> Channel update successful 4
09:46:09.659 -> Problem updating channel. HTTP error code -301
09:46:20.647 -> Channel update successful 5
09:47:20.652 -> Problem updating channel. HTTP error code -301
09:47:31.620 -> Channel update successful 6
09:48:31.601 -> Problem updating channel. HTTP error code -301
09:48:42.553 -> Channel update successful 7
09:49:42.582 -> Problem updating channel. HTTP error code -301
  • 09:49:53.493 -> ets Jun 8 2016 00:22:57
  • 09:49:53.493 ->
  • 09:49:53.493 -> rst:0x8 (TG1WDT_SYS_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
  • 09:49:53.493 -> configsip: 0, SPIWP:0xee
  • 09:49:53.493 -> clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
  • 09:49:53.493 -> mode:DIO, clock div:1
  • 09:49:53.493 -> load:0x3fff0018,len:4
  • 09:49:53.493 -> load:0x3fff001c,len:1216
  • 09:49:53.493 -> ho 0 tail 12 room 4
  • 09:49:53.493 -> load:0x40078000,len:9720
  • 09:49:53.493 -> ho 0 tail 12 room 4
  • 09:49:53.493 -> load:0x40080400,len:6352
  • 09:49:53.493 -> entry 0x400806b8
09:49:54.758 -> Serial comms OK
09:50:05.837 -> Problem updating channel. HTTP error code -301
09:50:16.555 -> Channel update successful 0
The bullet-pointed stuff is from the ESP32 when it crashed. Doesn't mean much to me, but perhaps to you?
I will now take a look at client.h, which provides the connection facilities to ThingSpeak.h, and is where things seem to go wrong.
David Evans
David Evans el 11 de Feb. de 2021
Editada: David Evans el 12 de Feb. de 2021
Interesting...but the crash-related bullet points are over my head! They look like the typical crash reports I've seen, but I've never tried to interpret them.
UPDATE: I modified my code to use HTTPClient (as in the RandomNerds example I posted above), not the TS lib, and will follow up with results. If it still has the problem, it may take a few days (or hours) to find out.
@Vinod ... any thoughts on the @John Rice's timing idea and why every other connection would fail?
(My problem is different...I get a string of successes, and then can't connect ever again...)
@John Rice you may want to check out the changes @Vinod recommended in this post about using the client.print approach, especially his post 11 and 14.
David Evans
David Evans el 13 de Feb. de 2021
Editada: David Evans el 14 de Feb. de 2021
Well, the code with HTTPClient (in lieu of the TS library) stopped posting. Next try: switch back to the TS library and disable email, but I have doubts. If that doesn't work then I think I will give up and just make the ESP32 automatically reboot upon getting a -301
And maybe post something about this on the Arduino ESP32 github site, since it seems like it must be related to the ESP32 itself or its libraries or core.
I rebooted the HTTPClient version and am letting it run again, since I forgot to check the httpresponse code when it quit posting. It hasn't stopped posting again, yet, but for one attempt it returned a -2, which is HTTPC_ERROR_SEND_HEADER_FAILED, according to HTTPClient.h Subsequent posts were successful.
I've been working to pin down why I always got -301 error code on alternate posts and think it is to do with the
int WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult)
function in WiFiGeneric.h. Its purpose is:
/**
* Resolve the given hostname to an IP address.
* @param aHostname Name to be resolved
* @param aResult IPAddress structure to store the returned IP address
* @return 1 if aIPAddrString was successfully converted to an IP address,
* else error code
*/
For some reason it couldn't always do this for "api.thingspeak.com".
I wondered if I supplied the IP address instead of the URL to client.connect it might cope better. It does!
My code just needed the amendment:
//const char* URL = "api.thingspeak.com";
const char* URL = "184.106.153.149";
...
...
if (client.connect(URL, 80))
...
100% reliable now.
David Evans
David Evans el 15 de Feb. de 2021
Editada: David Evans el 15 de Feb. de 2021
Awesome! Thanks for the sleuthing. Can't wait to try that...will do after my HTTPClient bombs again (so I can get the error code, just out of curiosity).
John Rice
John Rice el 15 de Feb. de 2021
Editada: John Rice el 15 de Feb. de 2021
A similar amendment to ThingSpeak.h works in my situation.
//#define THINGSPEAK_URL "api.thingspeak.com"
#define THINGSPEAK_URL "184.106.153.149"
With this change, my code utilising the ThingSpeak library now behaves as expected.
I notice that the time taken to post is significantly reduced - now less than one second, where it used to take several seconds. The process of turning a host name into an IP address is obviously complex and time-consuming.
The file I mentioned before should have been WiFiGeneric.cpp rather than WiFiGeneric.h, by the way. There are several same-named files in an Arduino set-up. The relevant one is in
C:\Users\<your name>\AppData\Local\Arduino15\packages\esp32\hardware\esp32\1.0.4\libraries\WiFi\src
(I discovered this by requesting 'verbose' compile messages.)
The static IP is not reccemended for new designs, it may be depricated in a future release. Its too bad that seemed to fix your problem. I wonder why your DNS has such a hard time with the ThingSpeak API URL. Is it possible to try a really minimal script with just the ThingSpeak library on a similar device in parallel? That might help find what is prohibiting name resolution.
David Evans
David Evans el 15 de Feb. de 2021
Editada: David Evans el 16 de Feb. de 2021
My ESP32 version with HTTPClient (instead of the ThingSpeak library) and the normal URL stopped posting to ThingSpeak again after about 63 hours of successful posts every 10 minutes. But as always the WiFi connection is still fine and the ESP32 still responds to "server.on" requests.
Now, every attempt to post (every 10 minutes) returns error -1, HTTPC_ERROR_CONNECTION_REFUSED ... which I understand means that the ThingSpeak server is actively refusing each connection attempt. Presumably the same thing is happening when I successfully use the ThingSpeak library for hours or days, and then get continuous -301 errors with every attempt. (So it seems like my problem may not be a DNS server problem, but I will try the static IP approach next, anyway.)
Why would the ThingSpeak server begin actively refusing connection requests, ad infinitum, after accepting hundreds? Can you look at server logs to see what's happening? Most recently, the last successful post prior to refused connections was 2/15 10:38:26 GMT-0900 and there should have been five or six unsuccessful attempts after that, until 11:57:03 GMT-0900, when I rebooted.
PS: @Christopher Stapels I hope @John Rice replies, but his code (see a prior post) is about as simple as it gets...
What is likely happening is that a stale DNS cache somewhere is telling your device that api.thingspeak.com is at 'x' IP address. However, since ThingSpeak dynamically scales the servers based on demand, it is possible that the server at the IP address 'x' is terminated. The device however is still relying on the cached IP address and trying to send data to a server that is not api.thingspeak.com anymore and the connection is refused.
One workaround is to use the static IP address, but, that is very strongly not recommended.
I'd recommend that we find what is caching a DNS address and figure out a way to set the time to live (TTL) on the cache.
That sounds plausible, but my ESP8266 has been "up" for months (using the ThingSpeak library and the URL, not the static IP) and it has never had the -301 problem. Only the ESP32 has the problem. I revised the ESP32 code to use the static IP. Will report back..
As you don't think using a static IP address is a good idea, I've managed to find another solution to my problem. (In fact I've found two alternatives!)
As mentioned previously, I have pinned down the code that gives rise to the issue that I am experiencing. It is in WiFiGeneric.cpp, which is called (not sure if 'called' is the right terminology - this is all a bit deep for me) by WiFiClient.cpp, which in turn is called by ThingSpeak.h.
/**
* Resolve the given hostname to an IP address.
* @param aHostname Name to be resolved
* @param aResult IPAddress structure to store the returned IP address
* @return 1 if aIPAddrString was successfully converted to an IP address,
* else error code
*/
int WiFiGenericClass::hostByName(const char* aHostname, IPAddress& aResult)
{
Serial.println("Started DNS stuff"); //added by me
ip_addr_t addr;
aResult = static_cast<uint32_t>(0);
waitStatusBits(WIFI_DNS_IDLE_BIT, 10000); //increased by me from 5000
clearStatusBits(WIFI_DNS_IDLE_BIT);
err_t err = dns_gethostbyname(aHostname, &addr, &wifi_dns_found_callback, &aResult);
Serial.print("Err = "); Serial.println(err); //added by me
if(err == ERR_OK && addr.u_addr.ip4.addr) {
aResult = addr.u_addr.ip4.addr;
} else if(err == ERR_INPROGRESS) {
waitStatusBits(WIFI_DNS_DONE_BIT, 10000); //increased by me from 4000
clearStatusBits(WIFI_DNS_DONE_BIT);
}
setStatusBits(WIFI_DNS_IDLE_BIT);
if((uint32_t)aResult == 0){
Serial.print("DNS Failed for "); Serial.println(aHostname); //added by me
log_e("DNS Failed for %s", aHostname);
}
return (uint32_t)aResult != 0;
}
This attempts to turn a string like "api.thingspeak.com" into an IP address like 54.210.227.170, I gather. What was going wrong (I think) was that the procedure was timing out before it could lookup the IP address. It wasn't that it was coming back with an incorrect address, but just timing out. I have increased the timeouts in both of the lines indicated, and now all's well.
Before I did this, I got WiFiClient to run this function twice. I found that the first time it would print Err = -5, wait about 4 seconds, then print the DNS Failed message. Then the second time it still printed Err = -5, but not the DNS Failed message, and the ESP32 would manage to connect OK and post to my ThingSpeak channel successfully. This was a bit mysterious, and unsatisfactory, so I then thought about the timeouts.
The process takes quite some time to look up the IP address. I still get Err = -5 printed then there's a long wait (up to 8 seconds) before I get a message from WiFiClient indicating everything is OK.
I don't know why it takes so long to find the IP address, but is presumably to do with the WiFi repeater hardware, and the router involved.
Thx. I'm currently testing the static IP approach. If that solves my problem (I'm skeptical, since my ESP8266 has no problems using the URL), then I'll try your mods to the ESP32 WiFiGeneric.cpp code. FWIW, the ESP8266WiFiGeneric.cpp default timeout for "hostByName" is 10 sec, but the code is considerably different than the ESP32 code.
"FWIW, the ESP8266WiFiGeneric.cpp default timeout for "hostByName" is 10 sec, but the code is considerably different than the ESP32 code."
Perhaps therin lies the reason why your ESP8266 has been working reliably and the ESP32 has been flaky. @David Evans Maybe post an issue on the GitHub library for the WiFiClient library to see if they can resolve it?
David Evans
David Evans el 16 de Feb. de 2021
Editada: David Evans el 16 de Feb. de 2021
The ESP32 with static IP and HTTPClient code has been up for 24 hours now. The "record" up-time (with ThingSpeak lib and URL) is about three days before -301 errors start. If the current code manages to run for a week or more without problem, then I'll switch back to the ThingSpeak library and URL, and increase the timeout in WiFiGeneric.cpp If that works, then I'll definitely post an issue on GitHub. Will keep you posted.
PS: also, it sounds like @John Rice problem may be related to his WiFi repeater...which I don't have. We'll see!
Vinod
Vinod el 16 de Feb. de 2021
Editada: Vinod el 16 de Feb. de 2021
@David Evans: There may be another simple workaround that overall is better.
Replace WiFiClient with WiFiClientSecure. Essentially, have this code (in this order) replace #include <WiFiClient.h>
#define TS_ENABLE_SSL // For HTTPS SSL connection
#include <WiFiClientSecure.h>
#include "ThingSpeak.h"
Then, where you have
WiFiClient client;
change it to
WiFiClientSecure client;
As a bonus to a more stable solution, you will also get secure connections between your device and ThingSpeak servers.
Disclosure: I have not tried this for extended run time apart from the examples. However, given that WiFiClientSecure has a different implementation, I have a better feeling about this.
David Evans
David Evans el 16 de Feb. de 2021
Editada: David Evans el 17 de Feb. de 2021
Thanks - will give that a try.
But check this out: Github commit changes WiFiGeneric.cpp timeouts to 16 seconds and 15 seconds...same as @John Rice's changes (but longer)! Related to this issue.
Apparently, due to some black magic, the current short timeouts can result in stack corruption... which I suppose could explain my "-301 forever and ever" situation.
@John Rice Good job! But note the commit also added "WIFI_DNS_DONE_BIT" to the clear status bits.
Those changes (made in September 2020) apparently haven't migrated into our libraries because the latest "stable" release available via the Boards Manager is from October 2019... :( Grrrrrr.
I posted a note about this on "Gitter" https://gitter.im/espressif/arduino-esp32?at=602c4a5aa8c6a7784813b994 In a response, I learned that supposedly, the next version of the core, which will include that commit and a few hundred others, will be released "any day now."
In the meantime, the up-to-date "development" version can be obtained using Boards Manager with this link:
John Rice
John Rice el 17 de Feb. de 2021
Editada: John Rice el 17 de Feb. de 2021
@David Evans How interesting! (Or something...)
I've had to increase the timeout to 15 seconds as well. 10 seconds proved to be too short after 253 posts. 15 seconds has worked for 781 posts and counting
Will add the WIFI_DNS_DONE_BIT to the clear.
Thanks
Thanks, everyone, for your help.
@David Evans: Could you please also post what you did so others can also benefit from your solution?
David Evans
David Evans el 18 de Feb. de 2021
Editada: David Evans el 19 de Feb. de 2021
Sure. This may be premature celebration, but the short answer is: make the changes to WiFiGeneric.cpp noted in this commit.
The long story is that I switched back to the ThingSpeak library and URL, and made the secure client changes you recommended. I also updated the ESP32 core to the latest developmental edition 1.0.5.rc-7, which included that commit. I uploaded that via ArduinoOTA, but it never posted to ThingSpeak, and the web server didn't respond. I then tried another OTA upload of the same sketch, and it failed..."no response from device" error. But, my router said it was connected.
So, I bailed back to the "stable" 1.0.4, updated WiFiGeneric per the commit, and switched back to the HTTPClient approach (just because it was the last thing that worked), but now with the URL, not the static IP. Then did a manual upload, not OTA...I was not a happy camper doing the manual flash, since it's a PITA to get to the ESP32 to connect a cable.
All good, so far.
8 days and counting!
LUCA DI NUZZO
LUCA DI NUZZO el 17 de En. de 2022
Editada: LUCA DI NUZZO el 17 de En. de 2022
Hi everyone,
sorry for resuming this old post. I'm stuck on exactly the same problem: after a random number of times, my ESP32 stops connecting to my WiFi and stucks on "Connecting...". Only an hard reset is able to restore the correct functioning. If I undestrand correctly this bug should have been resolved in older version of ESP core so I have updated the ESP core boards to version 2.0.2 and Thingspeak library to 2.0.0. I don't understand why my board is not working.. I have tried also using the HTTPClient but result are the same. I tried two different modems, so they are not the problem. The only different thing to the situation of David is that I send my board to light sleep after every cycle but I think that this is not the problem. Another difference is that the problem jumps out very often, like every 3 or 4 cycles.
Any idea of what is going on and how to solve this?
Thanks in advance.

Iniciar sesión para comentar.

Comunidades de usuarios

Más respuestas en  ThingSpeak Community

Categorías

Más información sobre Programming en Centro de ayuda y File Exchange.

Productos

Preguntada:

el 3 de Feb. de 2021

Editada:

el 17 de En. de 2022

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by