ESP8266 unwanted delay using client.readStringUntil(), with Microsoft SQL server - sql-server

My goal is to read the number of button press within a period(30s), upload it to a Microsoft SQl table using a php script. On the table, there is another column which adds in accumulated sum of the presses, which will be echo-ed back by the php script, and be read by the ESP8266 board.
So everything went through: I can read the count, upload it, read the accumulated sum back. The issue is it always takes ~5s in order to get a value back from the server. Attached is my troubleshooting:Serial Windows
It takes almost instantly to connect to the server(~100ms) but 5s to read the data that be echo-ed.
My guess was the php script takes time to run to the line where it echo out the value, but same delay(~5s) happens even if I tried a simple script(just echo).
Is this how the server behaves (not giving out the data right away) or is this how Arduino code (client.readStringUntil()) behaves?
Here is my code:
#include <SPI.h>
#include <ESP8266WiFi.h>
// Wifi Connection config
const char* ssid = "------";
const char* password = "------";
WiFiServer server(80);
IPAddress dbserver(10,1,1,138);
void setup_wifi()
{
delay(10);
// We start by connecting to a WiFi network
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
}
void setup()
{
Serial.begin(115200);
// Connect to WiFi network
setup_wifi();
}
void loop ()
{
WiFiClient client;
const int httpPort = 80;
bool conn = client.connect(dbserver,httpPort);
if (!conn) {
Serial.println("connection failed");
return;
}
else {
// call php script on the server(echo 1 value)
client.print("GET /test10.php HTTP/1.1");
client.println("Host: 10.1.1.138");
client.println("Connection: close");
client.println(); // Empty line
// Read from the server
Serial.println(millis()); // millis start reading
unsigned long timeout = millis();
while (client.available()==0){
if (millis()-timeout >1000){
Serial.println(">>> Client Timeout !");
client.stop();
}
}
Serial.println(millis()); // millis get the data stream
while (client.available()){
String line = client.readStringUntil('\r');
Serial.println(String(millis()) + " >>> "+line); // millis get each
// data line
}
delay(10);
client.stop(); // Closing connection to server
Serial.println("done");
}
delay(30000);
}
And is there any other way to fetch the data from the server to an ESP8266 module?
Thank you,
-Danny-

[SOLVED]: I need to set the Timeout parameter for the readStringUntil() function.
readStringUntil() is a blocking function. I will wait until it sees a char ('\r' in your case) or the timeout exceeds.
Just need to add client.setTimeout as:
WifiClient client;
client.setTimeout(10);
Still not sure if this practice is recommended, and how smaller should I go to for timeout?

Another solution would be using freeRTOS, and put the webserver in a separate task.
Then it can wait forever until a request is coming in.

Related

Start ESP32 when start is published in mqtt

This is my first time working with Arduino, an esp32 and MQTT. I made a motion sensor that prints to an LCD when it senses movement and publishes a message to mqtt, but it loops on forever. I am trying to make it so it will only start when start is published through mqtt and stops when stop is published. However, I am having some trouble figuring it out. Here is my current code (the main part excluding the MQTT set up), and I've been told putting it in callback may help but I get an error saying "a function-definition is not allowed here before '{' token" referring to void loop. Any suggestions are appreciated.
void callback(char *topic, byte *payload, unsigned int length) {
Serial.print("Message arrived in topic: ");
Serial.println(topic);
Serial.print("Message:");
for (int i = 0; i < length; i++) {
Serial.print((char) payload[i]);
}
Serial.println();
Serial.println("-----------------------");
}
void loop() {
client.loop();
int motion = digitalRead(sensorPin);
if (motion == HIGH)
{
lcd.setCursor(0, 0);
lcd.print("!!!!!MOTION!!!!!");
client.publish(topic, "MOTION");
delay(100);
}
else
{
lcd.setCursor(0, 0);
lcd.print(" no motion ");
client.publish(topic, "NO MOTION");
delay(500);
}
}
first: why would you publish unlimited times on mqtt when motion is detected?
you detect the motion (digitalRead), publish it (i.e. with retain=true), and once published, set the flag i.e. published=true. Store the previous state of the motion and don't publish until it changed (either from motion to no-motion or vice versa).
Your code is publishing for ever when motion is detected (client.publish(topic, "MOTION");) or when motion is cleared (client.publish(topic, "NO MOTION");)
if I get you correctly: you want to publish motion state ONLY when the message on MQTT came: "start checking the motion", right?
if so, in callback you change the global variable i.e. "start_checking_motion = true" when message arrives (before the command on MQTT you set it to false)
Then in loop, first what you do is to check if start_checking_motion == true - if so, you perform the check of the motion and you publish - but again: only when motion changed - see the first paragraph of my post

Cannot get the correct data from firebase using esp32. Everytime I use get function, the output is 0 in serial monitor

Firebase
Below is the code. I should get output as 1, but getting 0. I am sure that my firebase details are correct such as host and authentication because the demo example runs perfect.
I am using esp32 with Arduino IDE 1.8.12. Arduino Json 5.13.5
#include <IOXhop_FirebaseESP32.h>
#include <IOXhop_FirebaseESP32.h>
#include <WiFi.h>
#define FIREBASE_HOST "lab.firebaseio.com" // include the link of your firebase project
#define FIREBASE_AUTH "QWTbVwv" // Include the authentication of your firebase project
#define WIFI_SSID "TAIM5_2.4Ghz" // the name of the WiFi connection of your home or office
#define WIFI_PASSWORD "abc" // password of the WiFi connection of your home or office
int a;
void setup()
{
Serial.begin(9600);
delay(1000);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD); //try to connect with wifi
Serial.print("Connecting to ");
Serial.print(WIFI_SSID);
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.println();
Serial.print("Connected to ");
Serial.println(WIFI_SSID);
Serial.print("IP Address is : ");
Serial.println(WiFi.localIP()); //print local IP address
Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH); // connect to firebase
}
void loop()
{
a = (Firebase.getInt("fan/Fan"));
if (Firebase.failed()) {
Serial.println(Firebase.error());
}
else {
Serial.println(a);
}
delay(1000);
}
I have tried to access other nodes also and still getting 0. What can be the problem?
I have tried to access other nodes also and still getting 0. What can
be the problem?
Could it be all your values are string instead of int?
Have you tried:
String str = Firebase.getString("fan/Fan");
//...
Serial.println(str);

Arduino Socket.io shows disconnected when delay() is used

I am new to Arduino and facing an issue. I am implementing socket in Arduino for ESP8266 . It works as expected when I am not using delay() or not using someFunction(). As soon as i use delay or do some processing than i am getting connection disconnected one server socket.
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ArduinoJson.h>
#include <WebSocketsClient.h>
#include <SocketIOclient.h>
#include <Hash.h>
ESP8266WiFiMulti WiFiMulti;
SocketIOclient socketIO;
#define USE_SERIAL Serial1
void socketIOEvent(socketIOmessageType_t type, uint8_t * payload, size_t length) {
switch(type) {
case sIOtype_DISCONNECT:
USE_SERIAL.printf("[IOc] Disconnected!\n");
break;
case sIOtype_CONNECT:
USE_SERIAL.printf("[IOc] Connected to url: %s\n", payload);
break;
case sIOtype_EVENT:
USE_SERIAL.printf("[IOc] get event: %s\n", payload);
break;
case sIOtype_ACK:
USE_SERIAL.printf("[IOc] get ack: %u\n", length);
hexdump(payload, length);
break;
case sIOtype_ERROR:
USE_SERIAL.printf("[IOc] get error: %u\n", length);
hexdump(payload, length);
break;
case sIOtype_BINARY_EVENT:
USE_SERIAL.printf("[IOc] get binary: %u\n", length);
hexdump(payload, length);
break;
case sIOtype_BINARY_ACK:
USE_SERIAL.printf("[IOc] get binary ack: %u\n", length);
hexdump(payload, length);
break;
}
}
void setup() {
// USE_SERIAL.begin(921600);
USE_SERIAL.begin(115200);
//Serial.setDebugOutput(true);
USE_SERIAL.setDebugOutput(true);
USE_SERIAL.println();
USE_SERIAL.println();
USE_SERIAL.println();
for(uint8_t t = 4; t > 0; t--) {
USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
USE_SERIAL.flush();
delay(1000);
}
// disable AP
if(WiFi.getMode() & WIFI_AP) {
WiFi.softAPdisconnect(true);
}
WiFiMulti.addAP("SSID", "passpasspass");
//WiFi.disconnect();
while(WiFiMulti.run() != WL_CONNECTED) {
delay(100);
}
String ip = WiFi.localIP().toString();
USE_SERIAL.printf("[SETUP] WiFi Connected %s\n", ip.c_str());
// server address, port and URL
socketIO.begin("10.11.100.100", 8880);
// event handler
socketIO.onEvent(socketIOEvent);
}
unsigned long messageTimestamp = 0;
void loop() {
socketIO.loop();
uint64_t now = millis();
if(now - messageTimestamp > 2000) {
messageTimestamp = now;
// creat JSON message for Socket.IO (event)
DynamicJsonDocument doc(1024);
JsonArray array = doc.to<JsonArray>();
// add evnet name
// Hint: socket.on('event_name', ....
array.add("event_name");
// add payload (parameters) for the event
JsonObject param1 = array.createNestedObject();
param1["now"] = now;
// JSON to String (serializion)
String output;
serializeJson(doc, output);
// Send event
socketIO.sendEVENT(output);
// Print JSON for debugging
USE_SERIAL.println(output);
}
//NEED TO DO SOME PROCESSIONG
delay(2000);
someFuntion();
}
void someFunction(){
//some processing that consume the time
}
You are getting timeout on server side.
When you are making delay(10000) esp8266 is just hanging on some loop (as a delay implementation) - any other code is not executed due this time. So when the server is not getting any data it disconnects client.
The solution (easy way) is to make a new connection every time you want to send data. In pseudocode it will look like this:
void loop(){
connectToServer();
sendData();
Disconnect();
delay(1000);
SomeFunction();
}
Then it should work.
The more complicated method is to familiarize yourself with the concept of Events and callbacks and get rid of delay() function. Or try to use esp_rtos_sdk witch is asynchronous tasks concepts RTOS framework.
Have fun!
Edited:
After refreshed the code I'm able to tell more about it, so I'm editing the previous post.
The quickest way to make it work(partly) is to remove the delay(2000) statement - because this If() statement is handling sending messages in 2 seconds interval. As I see you may wan't to put this void someFunction() to this if() statement too. This will make "some processing" in 2 seconds interval.
socketIO.loop() is handling maintaining connection with server and sending event's to server so it has to be call as quick as plausible. In case with delay you are getting socket timeout and disconnection.
void loop() function must be shortest as plausible to maintain the connection. Probably it is 500ms or so - regarding to you experiments. So any delay's is not plausible. If you need more processing try to familiarize with event processing. The easiest way is to declare flags as Boolean and timers counting time intervals. When timer is lunched it's sets the flag as true and you may process function.
Websockets on ESP(or other embedded microprocessors) are hard for beginners because they are time dependent. You need to have short processing loop or some of asynchronous methods used.
I hope, that I help.

serial.println(String) prints "#" instead of the string

i'm just trying to recieve a string using a serial and to send this string back. So when i send a string to an arduino over a serial the arduino should automaticly send this string back.
i created this code:
String test;
void setup(){
Serial.begin(9600);
Serial.setTimeout(2);
test = "null";
}
void loop(){
if(Serial.available()){
test = Serial.readString();
}
Serial.println(test);
}
I guess it is not that difficult to understand. However now the arduino will always print a "#" instead of the variable test. My connected serial device is a bluetooth modul. (hc-06)
What did i do wrong?
Thank you!
(i also ran this code in the arduino emulator 123D Circuits. There it worked just fine)
You need change your code. Move println into if statement.
Try increase timeout interval, 2ms is not enough, good value (at 9600) lies above 10ms. Theoretically timeout should be at least 3.5 characters long and for current speed this equals ~0,4 ms. But in practice higher values are used.
String test;
void setup(){
Serial.begin(9600);
Serial.setTimeout(10);// or more
test = "null";
}
void loop(){
if(Serial.available()){
test = Serial.readString();
Serial.println(test);// moved into if
}
}
Update: Another simple solution to return characters back looks like:
void loop(){
if(Serial.available()) Serial.write(Serial.read());
}
Update 2: Had similar issue with BLE module HM10 (clone, not official). It was sending about 15 dummy bytes prior to any array. And i didn't solve it. But if weired bytes always the same you can make a simple trick using String.remove():
if(Serial.available()){
test = Serial.readString();
test.remove(0,5);
// test.remove - add code to remove last character
Serial.println(test);
}
Also try another terminal.

SDLNet Networking Not Working

I am working on a game written in C using SDL. Given that it already uses SDL, SDL_image, and SDL_ttf, I decided to add SDL_mixer and SDL_net to my engine. Getting SDL_mixer set up and working was very easy, but I am having a lot of trouble with SDL_net.
To test I created a very simple application with the following rules:
Run without arguments act as a TCP server on port 9999
Run with an argument try to connect to the server at the given IP address on port 9999
Here are some of the key lines of the program (I'm not going to post my whole event-driven SDL engine because its too long):
char *host = NULL;
if (argc > 1) host = argv[1];
and...
IPaddress ip;
TCPsocket server = NULL;
TCPsocket conn = NULL;
if (host) { /* client mode */
if (SDLNet_ResolveHost(&ip,host,port) < 0)
return NULL; //this is actually inside an engine method
if (!(conn = SDLNet_TCP_Open(&ip)))
return NULL;
} else { /* server mode */
if (SDLNet_ResolveHost(&ip,NULL,port) < 0)
return NULL;
if (!(server = SDLNet_TCP_Open(&ip)))
return NULL;
}
and... inside the event loop
if (server) {
if (!conn)
conn = SDLNet_TCP_Accept(server);
}
if (conn) {
void *buf = malloc(size); //server, conn, size are actually members of a weird struct
while (SDLNet_TCP_Recv(conn,buf,size))
onReceive(buf); //my engine uses a callback system to handle things
free(buf);
}
The program seems to start up just fine. However for some reason when I run it in client mode trying to connect to my home computer (which I have on a different IP) from my laptop I find that the call to SDLNet_TCP_Open blocks the program for awhile (5-10 seconds) then returns NULL. Can anybody see what I did wrong? Should I post more of the code? Let me know.

Resources