So I've been struggling to have this working.
I have an ESP32, but I can't use the wifi on the module (I simply can't, due to the implementation of the ESP).
Now, I have an W5500 shield for arduino, but I figure, that this should work just fine on an ESP, since it communicates via SPI.
I have had code that works perfectly with the Wifi of the ESP, but now it needs to run on the Ethernet thing.
HTTPClient http;
void sendHeartBeat(void *pvParameters) {
// Infinite loop (while true is more risky for some reason)
unsigned long previousMillis = 0;
const long interval = 300000; // 5 minutes
for (;;) {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis; // reset timer
int httpResponseCode;
http.begin(DIGITAL_HQ_HEARTBEAT_ENDPOINT); // test environment
http.addHeader("Content-Type", "application/json");
http.setUserAgent(DIGITAL_HQ_USER_AGENT);
StaticJsonDocument<128> doc;
doc["mac"] = deviceMacAddress;
doc["key"] = DEVICE_SECRET;
doc["type"] = DIGITAL_HQ_SOFTWARE_TYPE;
String output;
serializeJson(doc, output);
httpResponseCode = http.POST(output);
// If the device was deleted from HQ, re-register it.
if (httpResponseCode == 202) {
registerDevice();
}
http.end();
}
}
}
The above code worked perfectly on the ESP when using wifi. Now it doesn't anymore and just crashes the whole device.
This is the stacktrace;
16:20:52.874 -> assertion "Invalid mbox" failed: file "/home/runner/work/esp32-arduino-lib-builder/esp32-arduino-lib-builder/esp-idf/components/lwip/lwip/src/api/tcpip.c", line 374, function: tcpip_send_msg_wait_sem
16:20:53.110 -> abort() was called at PC 0x400dced7 on core 1
16:20:53.143 ->
16:20:53.143 -> ELF file SHA256: 0000000000000000
16:20:53.176 ->
16:20:53.176 -> Backtrace: 0x400891f4:0x3ffb1a00 0x4008946d:0x3ffb1a20 0x400dced7:0x3ffb1a40 0x401122bb:0x3ffb1a70 0x40111d55:0x3ffb1aa0 0x40111f08:0x3ffb1ac0 0x40108f10:0x3ffb1b00 0x400d4fbd:0x3ffb1b20 0x400d4cee:0x3ffb1da0 0x400d4e09:0x3ffb1dd0 0x40126337:0x3ffb1df0 0x400d783e:0x3ffb1e10 0x400d78d1:0x3ffb1e40 0x400d7a63:0x3ffb1e90 0x400d7a83:0x3ffb1eb0 0x400d284e:0x3ffb1ed0 0x400d9fd1:0x3ffb1fb0 0x4008a472:0x3ffb1fd0
What am I doiçng wrong? How can I resolve this issue without too much hassle? I also have this on any other used library (e.g. MQTTClient.h, WiFiClientSecure.h). Those I use and I really don't want to re-write all of the code just for the sake of 'I use an rj45 connector instead of wifi'....
Edit:
The issue was with https, but I need to be able to use https urls also... When I use http, the request just doesn't hapen either.
Related
I'm facing problem with sending AT Commands using Arduino Uno. I've written a small program (link below) to set up a server. I need to send data to Atmega from my laptop using Wifi module ESP8266. Everything would be fine if the entire program would do at once at the moment I need to comment and uncomment (adding and removing double slashes) every line of AT code, because only one AT command executes in a single compilation.
It seems like the program gets stuck somewhere in the while-loop (even on the module, I can see that blue diode stops blinking). I think that I've done something wrong in code and I would appreciate any help.
#include <SoftwareSerial.h>
SoftwareSerial espmod(2, 3);
void commands(String cmd, int waittime);
void setup(void) {
Serial.begin(9600);
espmod.begin(9600);
while (!Serial) {;}
commands("AT+GMR\r\n", 1000);
commands("AT+RST\r\n", 500);
commands("AT+CWMODE=1\r\n", 500);
commands("AT+CWJAP=\"SSID\",\"PASS\"\r\n", 4000);
commands("AT+CIPMUX=1\r\n", 500);
commands("AT+CIPSERVER=1,333\r\n", 500);
commands("AT+CIFSR\r\n", 500);
}
void loop() { // run over and over
}
void commands(String cmd, int waittime) {
espmod.print(cmd);
delay(waittime);
while(espmod.available()) {
char val = espmod.read();
Serial.write(val);
}
}
Here's the screen:
Version:
AT Version: 0.21.0.0
SDK Version: 0.9.5
Connections:
ESP
VCC -- 3,3 V (external source)
GND -- GND -- Arduino GND
RX -- TX (Arduino pin 3)
TX -- RX (Arduino pin 2)
CH_PD -- 3,3 V
RST -- 3,3 V
EDIT:
I've been fighting with this for couple of days, still without solution, but today it worked finally, but only once (after reseting power supply it's still the same) ! I could've seen all commands doing on SerialMonitor, so there is everything fine with code and i guess there is something wrong with esp module. As far as i can get only one AT command sent and executed in a single compilation, is it possible that 0,5 A current i provide to the module is not enough? Can module be out of the memory ? Is there any way to see SoftwareSerial monitor (is there anything like that)?
There is an unnecessary loop in command function. Let the arduino handle the loop for you. Also it is better to try with different delay parameters, maybe you can decrease some. Here the code I offer :
void loop() {
while (espmod.available()){
String result = espmod.readStringUntil('\n');
Serial.println("AT result : " + result);
}
}
void commands(String cmd, int waittime) {
espmod.print(cmd);
delay(waittime);
}
I'm using Arduino IDE 1.6.8 and ESP8266 Arduino community ver 2.2.0
Every page request the free heap size goes down, until eventually it crashes.
I've seen String class usage on other web serve code so I assume it isn't that..
#include <ESP8266WiFi.h>
String freeHeap;
WiFiServer webServer(80);
const char* html1 = "<!DOCTYPE html><html><head><meta name=\"viewport\" content=\"width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1\"/></head><body style=\"background-color:#EEE;font-family:Arial,Tahoma,Verdana;\"><h1>Title</h1>";
String html2 = "";
String req;
void setup() {
WiFi.mode(WIFI_STA);
WiFi.begin("name","pwd");
WiFi.config(IPAddress (192,168,1,201), IPAddress (192,168,1,1), IPAddress (255,255,255,0));
WiFi.softAPdisconnect(true);
webServer.begin();
}
void loop() {
WiFiClient webClient = webServer.available();
if (!webClient) {
delay(1);
return;
}
req = webClient.readStringUntil('\r');
webClient.flush();
setHTML();
webClient.print(html1);
webClient.print(html2);
delay(1);
}
void setHTML() {
long fh = ESP.getFreeHeap();
char fhc[20];
ltoa(fh, fhc, 10);
freeHeap = String(fhc);
html2 = "Heap " + freeHeap + "</body></html>";
}
Although WiFiClient is destroyed at the end of loop, the actual TCP buffer living behind it doesn't get free'd until either the client disconnects, or the TCP MSL limit is reached. Either the browser is keeping the connection alive, or more likely the buffer is kept alive after loop because you (implicitly) destroy the WiFiClient before the client can acknowledge that they received the data correctly.
Per the spec, the ESP has to keep this data around for the entire MSL duration, or until the client says they have received everything correctly. Since this can't happen in your loop, it'll consume RAM until this 2 minute time period is up.
This is easily fixed by waiting until the client has actively closed the connection with some sort of while loop using client.connected(), and additionally instructing the browser/HTTP client to close the connection when they are done with the Connection: close header. Once it has disconnected, then you should call client.stop();
I am quite rusty when it comes to Serial ports. I want to send an AT command to a GSM/ GPRS shield connected to my Arduino UNO. The AT command I want to pass in particular is the command to get a networks signal strength.
I am using the SIM900 and SoftwareSerial library to send the command as the GSM library does not compile correctly for me. Meaning I have to use the SoftwareSerial library.
I have this example code from the SIM900 library working that relies on reading inputs from the serial monitor to carry out commands but I need it to be automated and the command to be passed in hardcoded. In this example code, the place of interest is the simplehwread() method.
#include "SIM900.h"
#include <SoftwareSerial.h>
int numdata;
char inSerial[40];
int i=0;
void setup()
{
//Serial connection.
Serial.begin(9600);
Serial.println("GSM Shield testing.");
//Start configuration of shield with baudrate.
//For http uses is raccomanded to use 4800 or slower.
if (gsm.begin(9600))
Serial.println("\nstatus=READY");
else Serial.println("\nstatus=IDLE");
};
void loop()
{
//Read for new byte on serial hardware,
//and write them on NewSoftSerial.
serialhwread();
//Read for new byte on NewSoftSerial.
serialswread();
};
void serialhwread()
{
i=0;
if (Serial.available() > 0) {
while (Serial.available() > 0) {
inSerial[i]=(Serial.read());
delay(10);
i++;
}
inSerial[i]='\0';
if(!strcmp(inSerial,"/END")) {
Serial.println("_");
inSerial[0]=0x1a;
inSerial[1]='\0';
gsm.SimpleWriteln(inSerial);
}
//Send a saved AT command using serial port.
if(!strcmp(inSerial,"TEST")) {
Serial.println("SIGNAL QUALITY");
gsm.SimpleWriteln("AT+CSQ");
} else {
Serial.println(inSerial);
gsm.SimpleWriteln(inSerial);
}
inSerial[0]='\0';
}
}
void serialswread()
{
gsm.SimpleRead();
}
No matter how I modify this code, the command does not get passed in and response displayed while the method here does it but not the way I want it to be done. i.e Direct input. Could anyone assist here?
i have dealt with exactly this scenario at a company with a cellular radio on board. there are many status signals that come over and if not dealt with appropriately these status flags from the cell modem will be lost
you need to look at the data sheets associated with your cell modem and its protocol so you know what flags to watch for at the various steps taken along the way from configuration, to eventual connection to cellular service.
multi-threaded coding techniques must be followed as well.
keep in mind that the comm channel is not ideal and there WILL be failures. provided your coding techniques are sound and you follow protocol requirements, then it should work.
Ron
Boise, ID
I'm currently working with an Arduino trying to build an ad hoc network to which a device can connect to and send web requests to. The problem I am currently having is that I can only set up one connection and then when that connection is terminated (with client.stop()), all subsequent connections are not picked up by the server, even a cURL command just sits there spinning. The first connection I start when I reset the server works fine, and I am able to talk to the server; but after that, the Arduino can no longer find new clients (even though it's trying with the library given).
I`m using the SparkFun library for the WiFly shield cloned from GitHub, along with an Arduino Uno.
My current code is based off their default example 'WiFly_AdHoc_Example', but I had to remove a few things to get the network to start up which might be the cause of this problem.
Here is the .ino file that I am running.
#include <SPI.h>
#include <WiFly.h>
//#include <SoftwareSerial.h>
//SoftwareSerial mySerial( 5, 4); //Part from example not used (see below)
WiFlyServer server(80); //Use telnet port instead, if debugging with telnet
void setup()
{
Serial.begin(9600);
//The code below is from the example, but when I run it the WiFly will hang
// on Wifly.begin(). Without it, the WiFly starts up fine.
//mySerial.begin(9600);
//WiFly.setUart(&mySerial); // Tell the WiFly library that we are not
// using the SPIUart
Serial.println("**************Starting WiFly**************");
// Enable Adhoc mod
WiFly.begin(true);
Serial.println("WiFly started, creating network.");
if (!WiFly.createAdHocNetwork("wifly"))
{
Serial.print("Failed to create ad hoc network.");
while (1)
{
// Hang on failure.
}
}
Serial.println("Network created");
Serial.print("IP: ");
Serial.println(WiFly.ip());
Serial.println("Starting Server...");
server.begin();
Serial.print("Server started, waiting for client.");
}
void loop()
{
delay(200);
WiFlyClient client = server.available();
if (client)
{
Serial.println("Client Found.");
// A string to store received commands
String current_command = "";
while (client.connected())
{
if (client.available())
{
//Gets a character from the sent request.
char c = client.read();
if (c=='#' || c=='\n') //End of extraneous output
{
current_command = "";
}
else if(c!= '\n')
{
current_command+=c;
}
if (current_command== "get")
{
// output the value of each analog input pin
for (int i = 0; i < 6; i++)
{
client.print("analog input ");
client.print(i);
client.print(" is ");
client.print(analogRead(i));
client.println("<br />");
}
}
else if(current_command== "hello")
{
client.println("Hello there, I'm still here.");
}
else if (current_command== "quit")
{
client.println("Goodbye...");
client.stop();
current_command == "";
break;
}
else if (current_command == "*OPEN*")
{
current_command == "";
}
}
}
// Give the web browser time to receive the data
delay(200);
// close the connection
client.stop();
}
}
This script is just a mini protocol I set up to test. Once connected with the wifly module you can send text such as "get" "hello" or "quit" and the wifly module should respond back.
Using Telnet I can successfully connect (the first time) and send commands to the Arduino including "quit" to terminate the connection (calls the client.stop() method). But when I try to reconnect though Telnet, it says the connection was successful, but on the Arduino it's still looping thinking the client is still false. What??
I know right, I'm getting mixed messages from Telnet vs Arduino. None of the commands work obviously since the Ardunio is still looping waiting for a client that evaluates to true. I'm going to take a look at WiFlyServer from the library I imported and see if I can dig up the problem, because somehow that server.available() method isn't finding new clients.
I am noticing a lot of TODO's in the library code....
So I found the reason for the problem. It was in the WiFlyServer.cpp file from the SparkFun library. The code that was causing the reconnect issue was in fact the server.availible() method. Right at the top of the method, there is a check:
// TODO: Ensure no active non-server client connection.
if (!WiFly.serverConnectionActive) {
activeClient._port = 0;
}
For some reason when I comment this out, I can connect and reconnect perfectly fine and everything works as it should. I will now dive into the library and see if I can fix this, I'm not exactly sure what this is doing, but it gets called when the server connection is not active and is somehow blocking subsequent connections. The problem with this solution is that the Arduino always thinks it has found a client since client and client.connected() evaluate to true even if one doesn't exist. Even client.available() evaluates to true right when the connection is terminated and the ghost "client" is found, but after that first run through the if-statement the ghost "client" is no longer available(). Even with this flaw it still picks up a new client when it comes along which is why it works.
How might I get to the root of this problem without using this commenting hack?
Are their any risks or future problems I might run into doing it this way?
What is the purpose of the block that I commented out in the first place?
Well, when you're calling client.stop(); how does the Arduino know whether the client has to start again?
Remember setup() executes only once.
Have you tried to include the following code in your loop to tell the Arduino to create the WiFly AdHoc network again? This may or may not work. I don't have one myself and haven't played with the Wifly shield but it's worth a try.
Remember to only ever execute the code once every time you need to connect again since it's sitting inside a loop that's always going to be running.
WiFly.begin(true);
Serial.println("WiFly started, creating network.");
if (!WiFly.createAdHocNetwork("wifly"))
{
Serial.print("Failed to create ad hoc network.");
while (1)
{
// Hang on failure.
}
}
I'm developing an application that uses IPC between a local server and a client application. There is nothing particular to it, as it's structured like the Qt documentation and examples.
The problem is that the client sends packets frequently and connecting/disconnecting from the server local socket (named pipe on NT) is very slow. So what I'm trying to achieve is a "persistent" connection between the two applications.
The client application connects to the local server (QLocalServer) without any problem:
void IRtsClientImpl::ConnectToServer(const QString& name)
{
connect(_socket, SIGNAL(connected()), this, SIGNAL(connected()));
_blockSize = 0;
_socket->abort();
_socket->connectToServer(name, QIODevice::ReadWrite);
}
And sends requests also in the traditional Qt manner:
void IRtsClientImpl::SendRequest( quint8 cmd, const QVariant* const param_array,
unsigned int cParams )
{
// Send data through socket
QByteArray hdr(PROTO_BLK_HEADER_PROJ);
QByteArray dataBlock;
QDataStream out(&dataBlock, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_5);
quint8 command = cmd;
out << blocksize_t(0) // block size
<< hdr // header
<< quint32(PROTO_VERSION_PROJ) // protocol version
<< command // command
<< cParams; // number of valid parameters
for (unsigned int i = 0; i < cParams; ++i)
out << param_array[i];
// Write the current block size
out.device()->seek(0);
out << dataBlock.size() - sizeof(blocksize_t);
_socket->write(dataBlock);
}
No problem. But the trick resides on the readyRead() signal in the server-side. Here's the current implementation of the readyRead() handling slot:
void IRtsServerImpl::onReadyRead()
{
QDataStream in(_lsock);
in.setVersion(QDataStream::Qt_4_5);
if (_blocksize == 0)
{
qDebug("Bytes Available on socket: %d", _lsock->bytesAvailable());
if (_lsock->bytesAvailable() < sizeof(blocksize_t))
return;
in >> _blocksize;
}
// We need more data?
if (_lsock->bytesAvailable() < _blocksize)
return;
ReadRequest(in);
// Reset
_blocksize = 0;
}
Without setting _blocksize to zero I could not receive more data, only the first block group (I would expect an entire block to arrive without segmentation since this is through a pipe, but it does not, go figure). I expect that behavior, sure, since the _blocksize does not represent the current stream flow anymore. All right, resetting _blocksize does the trick, but I can't resend another packet from the client without getting an increasing array of bytes on the socket. What I want is to process the request in ReadRequest and receive the next data blocks without resorting to connecting/reconnecting the applications involved.
Maybe I should 'regulate' the rate of the incoming data?
Thank you very much.