Exception decoder after connected with PubSubClient in my ESP8266 - mqtt

My code always gets exception decoder message and resets a few ms after MQTT connection is done successfully.
My connectMqtt function:
void MyClass::connectMqtt(PubSubClient client)
{
// Loop until we're reconnected
int attempts = 0;
bool connected = false;
while (!connected && attempts < 5)
{
std::string clientId = _my_device.getBarcode();
// Attempt to connect
if (client.connect(clientId.c_str(), _my_device.getMqttUser(), _my_device.getMqttPassword()))
{
Serial.println(F("MQTT connected"));
connected = true;
//Subscribe to config topic of the device
//TODO not done yet
}
else
{
Serial.print(F("failed, rc="));
Serial.print(client.state());
Serial.println(F(" try again in 5 seconds"));
attempts++;
// Wait 5 seconds before retrying
delay(5000);
}
}
Serial.println(F("Done."));
}
Exception decoder mesage starts by:
Exception (3):
epc1=0x40100691 epc2=0x00000000 epc3=0x00000000 excvaddr=0x40032468 depc=0x00000000

As #Juraj said:
The solution is passing a reference to the function, not a copy
void MyClass::connectMqtt(PubSubClient& client)

Related

Stream Read Error: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host

I am working on a windows service to communicate with servers, In which I am using the TcpListener class.
In TcpListener class, after 3 successful socket connections, the 4th connection is returning an error.
class MyTcpListener
{
public static void Main()
{
TcpListener server=null;
try
{
// Set the TcpListener on port 13000.
Int32 port = 13000;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
// TcpListener server = new TcpListener(port);
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
// Buffer for reading data
Byte[] bytes = new Byte[256];
String data = null;
// Enter the listening loop.
while(true)
{
Console.Write("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also use server.AcceptSocket() here.
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
data = null;
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
int i;
// Loop to receive all the data sent by the client.
while((i = stream.Read(bytes, 0, bytes.Length))!=0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
// Process the data sent by the client.
data = data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
// Send back a response.
stream.Write(msg, 0, msg.Length);
Console.WriteLine("Sent: {0}", data);
}
// Shutdown and end connection
client.Close();
}
}
catch(SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server.Stop();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
}
On this line on the 4th connection, it's returning an error.
// Send back a response.
stream.Write(msg, 0, msg.Length);
Error:
Stream Write Error: Unable to write data to the transport connection:
An existing connection was forcibly closed by the remote host. Stream
Write Error: at System.Net.Sockets.NetworkStream.Write(Byte[]
buffer, Int32 offset, Int32 size)

ESP NOW failing using WIFI_AP_STA and WiFi.begin but working without the WiFi.begin

I am using code derived from Rui Santos https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/
I am using ESP NOW to send readings from an ESP32 sender to an ESP32 receiver then using the ESP32 receiver to send an html message to a ESP32 web server. Per Rui's instructions I need to start WiFi with WIFI_AP_STA to allow both wifi connection methods.
The sender and receiver code is below.
If I run the code as is, i.e. the receiver setup as WIFI_AP_STA but with the WiFi.begin line commented out, I get a sender status of:
Send success, and a receive status of:Receive status. SO there is no problem sending an ESP NOW message from the sender to the receiver (also works with WIFI_STA).
If I use WIFI_AP_STA and uncomment the line in the receiver "WiFi.begin(SSIS, PASSWORD)" so that I can send a message to the ESP32 web server, I get a send status of:Send fail, and a receive status of:Receive status with failed send. The send fails but the receive is still successful. Same fail if I use WIFI_AP. It seems that in WIFI_AP_STA mode with a WiFi.begin, the receiver sends an incorrect status back to the sender.
In summary, on the receiver, using wifi mode WIFI_AP_STA without a WiFi.begin, works for sending an ESP NOW message from sender to receiver, as it should.
Using wifi mode WIFI_AP_STA and WiFi.begin on the receiver, the sender fails when sending an ESP NOW message. When I implement the web code the web html message send works. However the issue can be reproduced using the simplified code below.
Using WiFi#2.0.0.
I've run out of ideas, is anyone able to point me at further investigation areas?
My sender code is:
#include <Arduino.h>
#include <WiFi.h>
#include <esp_now.h>
// Rui Santos https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/
uint8_t broadcastAddress[] = {0x24, 0x6F, 0x28, 0xAA, 0x84, 0x10};
typedef struct struct_message
{
char ESP32NowText[33];
} struct_message;
struct_message ESP32NowMessage;
//
String text = "AAA000010000200003000040000500006";
esp_now_peer_info_t peerInfo;
// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status)
{
Serial.print("\r\nLast Packet Send Status:\t");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}
void setup()
{
Serial.begin(115200);
WiFi.mode(WIFI_STA);
if (esp_now_init() != ESP_OK)
{
Serial.println("Error initializing ESP-NOW");
return;
}
esp_now_register_send_cb(OnDataSent);
// Register peer
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
// Add peer
if (esp_now_add_peer(&peerInfo) != ESP_OK)
{
Serial.println("Failed to add peer");
return;
}
}
void loop()
{
strncpy(ESP32NowMessage.ESP32NowText, text.c_str(), text.length());
Serial.println("Msg to send:" + String(ESP32NowMessage.ESP32NowText));
Serial.println("Snd Len:" + String(sizeof(ESP32NowMessage)));
// Send message via ESP-NOW
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *)&ESP32NowMessage, sizeof(ESP32NowMessage));
if (result == ESP_OK)
{
Serial.println("Sent with success");
}
else
{
Serial.println("Error sending the data");
}
delay(2000);
}
My receiver code is:
#include <Arduino.h>
#include <WiFi.h>
#include <esp_now.h>
// Rui Santos https://RandomNerdTutorials.com/esp-now-esp32-arduino-ide/
typedef struct struct_message
{
char ESP32NowValues[33];
} struct_message;
struct_message ESP32NowMessage;
// callback function that will be executed when data is received
void OnDataRecv(const uint8_t *mac, const uint8_t *incomingData, int len)
{
memcpy(&ESP32NowMessage, incomingData, sizeof(ESP32NowMessage));
Serial.println("Bytes received: " + String(len));
Serial.println("Values:" + String(ESP32NowMessage.ESP32NowValues));
Serial.println("---------------------------------------");
}
const char WiFiSSID[] = "SSID";
const char WiFiPassword[] = "PASSWORD";
//
void setup()
{
Serial.begin(115200);
WiFi.mode(WIFI_AP_STA);
// WiFi.begin(WiFiSSID, WiFiPassword);
// Init ESP-NOW
if (esp_now_init() != ESP_OK)
{
Serial.println("Error initializing ESP-NOW");
return;
}
esp_now_register_recv_cb(OnDataRecv);
}
void loop()
{
}

ESP8266 crashes after simple http request

I am working with the NodeMCU V3 module. Whenever I try to make an http request to my server, the module crashes.
Here's the code:
void setup() {
WiFi.begin("wifi-name", "wifi-password");
while (WiFi.status() != WL_CONNECTED) { //Wait for the WiFI to connect }
}
void loop() {
HTTPClient http;
WiFiClient client;
http.begin( client, "server-address" );
int httpCode = http.GET();
String payload = http.getString(); //Get the response payload
Serial.println(httpCode); //Print HTTP return code
Serial.println(payload); //Print request response payload
http.end(); //Close connection
delay( 1000 );
}
Here's the result, as seen in the serial monitor:
200
["JSON response from the server"]
Exception (28):
epc1=0x40212e82 epc2=0x00000000 epc3=0x00000000 excvaddr=0x000001b6 depc=0x00000000
>>>stack>>>
ctx: cont
sp: 3ffffc90 end: 3fffffc0 offset: 01a0
3ffffe30: 00000000 4bc6a7f0 0000333f 3ffee5f8
3ffffe40: 00000000 00000000 4bc6a7f0 00000000
[...]
3fffffb0: feefeffe feefeffe 3ffe84e8 40100c41
<<<stack<<<
The strange thing is that it retrieves the response from the server correctly, but then, about one second later, it spits out the exception to the serial monitor and resets. At first I thought it could be because I am running ESP8266WebServer at the same time, but it still crashes even when I run the most basic example I could find on the internet. I tried compiling the same code on the Arduino IDE instead of PlatformIO, or even using a different NodeMCU, to no avail.
EDIT: After playing around a bit more, it seems like setting the delay to at least 10 seconds makes the NodeMCU crash after 3 requests instead of after the first one. Could it be that it's memory overflows after a few requests? Am I missing a crucial part that should prepare the ESP8266 for a new request?
There is no need to re-create the WiFi and HTTP clients in the loop() over and over again. You can declare them once globally. Here's a stable version of this simple sketch:
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESPHTTPClient.h>
HTTPClient http;
WiFiClient client;
void setup() {
Serial.begin(115200);
Serial.println();
WiFi.begin("****", "****");
Serial.print("Connecting to WiFi");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("done.");
}
void loop() {
http.begin(client, "http://httpbin.org/get"); // <1KB payload
// http.begin(client, "http://www.geekstips.com/esp8266-arduino-tutorial-iot-code-example/"); // 30KB payload
int httpCode = http.GET();
String payload = http.getString(); //Get the response payload
Serial.println(httpCode); //Print HTTP return code
Serial.println(payload); //Print request response payload
http.end(); //Close connection
Serial.printf("Free heap: %d\n", ESP.getFreeHeap());
delay(1000);
}
The reported free heap is very stable over time.
Please take note of the second URL I added for testing in the commented line. That http.getString() is convenient and works well for small resources but yields unexpected i.e. wrong results for larger resources - you only see a small fraction of the body printed to the console.
For larger payloads you should use the low-level WiFiClient directly and read/parse the response line-by-line or character-by-character. See the documentation at https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/client-examples.html for a template.
void loop()
{
WiFiClient client;
Serial.printf("\n[Connecting to %s ... ", host);
if (client.connect(host, 80))
{
Serial.println("connected]");
Serial.println("[Sending a request]");
client.print(String("GET /") + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n" +
"\r\n"
);
Serial.println("[Response:]");
while (client.connected() || client.available())
{
if (client.available())
{
String line = client.readStringUntil('\n');
Serial.println(line);
}
}
client.stop();
Serial.println("\n[Disconnected]");
}
else
{
Serial.println("connection failed!]");
client.stop();
}
delay(5000);
}

Always get -1 connection refused response from server

I am making a alert device on my node mcu board to report any orders made by customers on my application. The nodemcu should access the network using wifi and call the rest api. I tried researching many sites and modified the code several times, but the response is always -1, connection refused.
tried doing
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>
ESP8266WiFiMulti WiFiMulti;
void setup() {
Serial.begin(9600);
// Serial.setDebugOutput(true);
Serial.println();
Serial.println();
Serial.println();
for (uint8_t t = 4; t > 0; t--) {
Serial.printf("[SETUP] WAIT %d...\n", t);
Serial.flush();
delay(1000);
}
WiFi.mode(WIFI_STA);
WiFiMulti.addAP("----", "----");
}
void loop() {
// wait for WiFi connection
if ((WiFiMulti.run() == WL_CONNECTED)) {
WiFiClient client;
HTTPClient http;
Serial.print("[HTTP] begin...\n");
if (http.begin(client, "http://34.87.116.113:80/api/v1/iot/Notify/poll")) { // HTTP
http.setAuthorization("admin", "admin123!");
Serial.print("[HTTP] GET...\n");
// start connection and send HTTP header
int httpCode = http.GET();
// httpCode will be negative on error
if (httpCode > 0) {
// HTTP header has been send and Server response header has been handled
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
// file found at server
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) {
String payload = http.getString();
Serial.println(payload);
}
} else {
Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str());
}
http.end();
} else {
Serial.printf("[HTTP} Unable to connect\n");
}
}
delay(5000);
}

TIdTCPServer OnExecute not fired for some messages unless mouse in window

We have a Windows app that we're adding a socket interface for remote configuration and data processing. A TIdTCPServer object receives the messages in the OnExecute event. For some messages, however, the OnExecute event is not fired unless the cursor is moved in the main window.
UPDATE: With a lot more experimenting, whether or not the message is processed immediately, or after a long pause, or not at all, seems more random. In all cases, moving the cursor causes the message to be processed immediately. However, it doesn't seem to be specific to a message, or the order of messages.
Updated source code listings: Here's the OnExecute handler:
void __fastcall TSigToolForm::IdTCPServer1Execute(TIdContext *AContext)
{
TIdBytes buffer;
if (ReceiveBuffer(AContext, buffer))
{
try
{
try
{
msg = &buffer[0]; // msg is class member
TThread::Synchronize(0, mProcess); // Doesn't return until mProcess finishes
buffer = IPOK().toByteArray(); // Ack
SendBuffer(AContext, buffer);
}
catch (const std::exception & ex)
{
buffer = IPFailCommand(ex.what()).toByteArray();
SendBuffer(AContext, buffer);
}
catch (const Exception & ex)
{
buffer = IPFailCommand(toStdString(ex.Message)).toByteArray();
SendBuffer(AContext, buffer);
}
catch (const EIdException & ex)
{
throw; // Let Indy have it
}
}
__finally
{
msg = 0;
}
}
}
The mProcess function and the processMessage function it calls. I stripped all but one message type that processMessage handles:
void __fastcall TSigToolForm::mProcess()
{
if (msg) processMessage(msg);
}
void TSigToolForm::processMessage(byte * message)
{
CSLock lock(cs); // RAII class, cs is TCriticalSection
try
{
IPCommand cmd(message);
switch (cmd.ID)
{
case IPCommand::SET_CAD :
{
setObjectCad(cmd);
break;
}
}
}
catch(const std::exception & ex)
{
ShowMessage(ex.what());
}
catch (const EIdException & ex)
{
throw;
}
catch (...)
{
ShowMessage("Exception in processMessage");
}
}
The ReceiveBuffer and SendBuffer functions:
bool ReceiveBuffer(TIdTCPClient * aClient, TIdBytes & ABuffer)
{
return ReceiveBuffer(aClient->IOHandler, ABuffer);
}
bool ReceiveBuffer(TIdContext * AContext, TIdBytes & ABuffer)
{
return ReceiveBuffer(AContext->Connection->IOHandler, ABuffer);
}
bool ReceiveBuffer(TIdIOHandler * IO, TIdBytes & ABuffer)
{
CSLock lock(cs);
try
{
long sz = IO->ReadLongInt();
IO->ReadBytes(ABuffer, sz, false);
return true;
}
catch (const EIdException & ex)
{
throw;
}
return false;
}
bool SendBuffer(TIdIOHandler * IO, const TIdBytes & ABuffer)
{
CSLock lock(cs);
try
{
IO->WriteBufferOpen();
try
{
IO->Write(ABuffer.Length);
IO->Write(ABuffer);
IO->WriteBufferClose();
}
catch(const Exception &)
{
IO->WriteBufferCancel();
throw;
}
}
catch(const EIdException &)
{
throw;
}
catch (...)
{
return false;
}
return true;
}
bool SendBuffer(TIdContext * AContext, const TIdBytes & ABuffer)
{
return SendBuffer(AContext->Connection->IOHandler, ABuffer);
}
bool SendBuffer(TIdTCPClient * aClient, const TIdBytes & aBuffer)
{
return SendBuffer(aClient->IOHandler, aBuffer);
}
For testing I have a separate program that creates and send the various messages, using TIdTCPClient and the same send / receive buffer functions. This is the only connection to the server program. Here's an example:
void TForm16::setPortAndConnect()
{
IdTCPClient1->Port = bdePort->IntValue();
IdTCPClient1->Host = editHost->Text;
IdTCPClient1->Connect();
}
void TForm16::sendCommandToSVST(const TIdBytes & buffer)
{
try
{
setPortAndConnect();
if (SendBuffer(IdTCPClient1, buffer))
{
TIdBytes recv;
//
// Read the response
if (ReceiveBuffer(IdTCPClient1, recv))
{
IPCommand response = IPCommand::fromByteArray(recv);
}
}
}
__finally
{
IdTCPClient1->Disconnect();
}
}
bdePort is an internal TEdit-derived that deals with numerical input. I'm confident that the data itself is correct. It's getting the server to respond that is a problem right now.
I assume at this point that there must be something the program itself is doing that's interfering with the GUI thread or the socket connection or both. I know this is very open-ended, but any hints on what to look for would be appreciated.
This is C++Builder 10.1 update 1, using the classic compiler.
For some messages, however, the OnExecute event is not fired unless the cursor is moved in the main window.
TIdTCPServer is a multi-threaded component, the OnExecute event is fired in a worker thread in a continuous loop for the lifetime of the socket connection. So the ONLY way it could be getting blocked until mouse activity is detected is if your OnExecute code is synchronizing with the main UI thread, and the main UI thread is blocked until window messages are received.
In the code you have shown, the only places where your OnExecute code could be getting blocked are the calls to ReceiveBuffer(), mProcess(), and SendBuffer(). Make sure they are all thread-safe. You did not show the code for any of those methods, or the code for your main UI thread, but mProcess() is being called via TThread::Synchronize() so start with that one and make sure your main UI thread is not blocking mProcess() while it is trying to process a socket message.
BTW, you are catching only STL-based exceptions (derived from std::exception), but you are completely ignoring RTL-based exceptions (derived from System::Sysutils::Exception). And in the case of Indy-based exceptions (which are derived from EIdException, which itself is derived from System::Sysutils::Exception), DO NOT swallow them! If you catch an Indy exception, re-throw it and let TIdTCPServer handle it, otherwise its threads will not be able to detect socket disconnects and clean up properly (unless you manually call AContext->Connection->Disconnect() in your code).
Don't know the Indy version, whatever came with the compiler.
You can find out the Indy version by:
looking for Indy in the IDE's "About" box
right-clicking on any Indy component in the Form Designer at design-time.
reading the Version property of any Indy component at runtime.
UPDATE: Why are you using a critical section around everything? You don't need that.
You are reading/writing a client socket from only 1 thread (the one firing the OnExecute event). Even if you were reading in one thread and writing in another thread, that is safe to do with sockets without placing a lock around the IOHandler. So you don't need a lock around those IOHandler operations at all.
And your mProcess() method is already being serialized by TThread::Synchronize(), so it will only ever run in the main UI thread. If multiple client threads want to call mProcess() at the same time, Synchronize() ensures it runs only one at a time. So you don't need a lock for that, either. However, your use of ShowMessage() inside of mProcess() is problematic, because it runs a secondary message loop that will allow pending Synchronize() requests to run while mProcess() is still running, so you can end up with multiple mProcess() calls overlapping each other. You should not be doing anything inside of a synced method that can cause window messages to be processed. If a synced method throws an exception, you should not try to catch it. Synchronize() catches exceptions and rethrows them in the context of the thread that called Synchronize(), and you already have exception handlers in your OnExecute code.
The only place I see where you should be using any kind of lock, if any at all, would be inside of setObjectCad(), but only if it needs to access data that can be accessed by multiple threads at the same time.
With that said, try something more like this instead:
void ReceiveBuffer(TIdTCPClient * aClient, TIdBytes & ABuffer)
{
ReceiveBuffer(aClient->IOHandler, ABuffer);
}
bool ReceiveBuffer(TIdContext * AContext, TIdBytes & ABuffer)
{
ReceiveBuffer(AContext->Connection->IOHandler, ABuffer);
}
void ReceiveBuffer(TIdIOHandler * IO, TIdBytes & ABuffer)
{
long sz = IO->ReadLongInt();
IO->ReadBytes(ABuffer, sz, false);
}
void SendBuffer(TIdIOHandler * IO, const TIdBytes & ABuffer)
{
IO->WriteBufferOpen();
try
{
IO->Write(ABuffer.Length);
IO->Write(ABuffer);
IO->WriteBufferClose();
}
catch(const Exception &)
{
IO->WriteBufferCancel();
throw;
}
}
void SendBuffer(TIdContext * AContext, const TIdBytes & ABuffer)
{
SendBuffer(AContext->Connection->IOHandler, ABuffer);
}
void SendBuffer(TIdTCPClient * aClient, const TIdBytes & aBuffer)
{
SendBuffer(aClient->IOHandler, aBuffer);
}
void __fastcall TSigToolForm::IdTCPServer1Execute(TIdContext *AContext)
{
TIdBytes buffer;
ReceiveBuffer(AContext, buffer);
try
{
msg = &buffer[0]; // msg is class member
TThread::Synchronize(0, mProcess); // Doesn't return until mProcess finishes
buffer = IPOK().toByteArray(); // Ack
SendBuffer(AContext, buffer);
}
catch (const std::exception & ex)
{
buffer = IPFailCommand(ex.what()).toByteArray();
SendBuffer(AContext, buffer);
}
catch (const Exception & ex)
{
buffer = IPFailCommand(toStdString(ex.Message)).toByteArray();
SendBuffer(AContext, buffer);
if (dynamic_cast<const EIdException *>(&ex))
throw;
}
catch (...)
{
buffer = IPFailCommand("Unknown exception").toByteArray();
SendBuffer(AContext, buffer);
}
}
void __fastcall TSigToolForm::mProcess()
{
if (msg) processMessage(msg);
}
void TSigToolForm::processMessage(byte * message)
{
IPCommand cmd(message);
switch (cmd.ID)
{
case IPCommand::SET_CAD :
{
setObjectCad(cmd);
break;
}
}
}
void TSigToolForm::setObjectCad(const IPCommand &cmd)
{
// here is where you should be using CSLock, if at all...
}
void TForm16::setPortAndConnect()
{
IdTCPClient1->Port = bdePort->IntValue();
IdTCPClient1->Host = editHost->Text;
IdTCPClient1->Connect();
}
void TForm16::sendCommandToSVST(const TIdBytes & buffer)
{
setPortAndConnect();
try
{
// Send the command
SendBuffer(IdTCPClient1, buffer);
// Read the response
TIdBytes recv;
ReceiveBuffer(IdTCPClient1, recv);
IPCommand response = IPCommand::fromByteArray(recv);
}
__finally
{
IdTCPClient1->Disconnect();
}
}

Resources