Context
Hello everybody. I'm working on a project where I need to send about 60 TCP sockets per second to my ESP8266 in order to change a light bulb intensity "in real time". The sockets are really small, like 5 bytes.
Hardware
Server device: NodeMCU 1.0 (ESP-12E Module)
Client device: Linux 16.04 PC sending data with Node.js
-The NodeMCU board is running the last Arduino firmware: https://github.com/esp8266/Arduino
The problem
When I send a lot of TCP packets every second, the ESP8266 wifi eventually stops working. The cpu keeps working but it won't reply any ping or TCP request.
I created a really small program just to test this bug, and here it is the wireshark output.
(192.168.1.11) -> ESP8266
(192.168.1.101) -> Linux PC
As you can see, there is a moment where the ESP8266 stops sending ACKs. Sometimes it will recover after a few seconds, sometimes it doesn't.
Here is the code I use in the ESP8266:
#include <ESP8266WiFi.h>
#define TCP_PORT 17717
#define PIN_LED 2
#define MAX_INTENSITY 255
#define MAX_PWM_FREQ 1023
WiFiServer server(TCP_PORT);
WiFiClient socket;
const char * ssid = "MyWifi";
const char * password = "MyPass";
void setLed(byte intensity) {
analogWrite(PIN_LED, (int)(intensity/(float)MAX_INTENSITY * MAX_PWM_FREQ));
}
void setup() {
Serial.begin(115200);
pinMode(PIN_LED, OUTPUT);
setLed(0);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
Serial.print("Ready! IP = ");
Serial.println(WiFi.localIP());
server.begin();
}
void loop() {
if (server.hasClient()) {
socket = server.available();
while (socket.connected()) {
if (socket.available()) {
setLed(socket.read());
}
}
}
}
Any idea of what is going on here?
It's probably because the MAX_SOCK_NUM is 4 defined in the Ethernet.h file. So we cannot connect more than 4 TCP connections which is restricted by the small memory size of the TCP/IP stack in ESP8266 and if we exceed the fixed number the board crashes.
Related
My WeMos D1 Mini is running a script that is supposed to perform certain actions if it receives certain strings in udp packets.
It works most of the time, but sometimes it just doesn't respond to anything.
Usually it's enough to just wait a few minutes or send the packet a couple of times. My guess is that it might go into some kind of deep sleep. Sometimes the only thing that helps is to restart it.
I tried implementing a watchdog but that didn't really work (but that's a separate issue) and i'm not sure if it would even solve the problem.
I'm sending the packets through Netcat and the WiFi strength is ok (but not great).
Everything is on the local network.
Please take a look at my code and check it for mistakes/improvements.
#include <ESP8266WiFi.h>
#include <WiFiUDP.h>
#define SSID "XXX"
#define PASSWORD "XXX"
#define PORT XXX
WiFiUDP udpServer;
char MESSAGE[] = "message";
void setup() {
Serial.begin(9600);
WiFi.mode(WIFI_STA);
WiFi.begin(SSID, PASSWORD);
wifiStrength();
udpServer.begin(PORT);
delay(100);
}
void wifiStrength(){
if (WiFi.status() != WL_CONNECTED) {
Serial.println("no wifi, reconnecting...");
delay(3000);
WiFi.begin(SSID, PASSWORD);
}
long rssi = WiFi.RSSI();
Serial.print("connected, RSSI:");
Serial.println(rssi);
}
void loop() {
if (udpServer.parsePacket()) {
char receiveBuffer[WIFICLIENT_MAX_PACKET_SIZE + 1];
udpServer.read(receiveBuffer, sizeof(receiveBuffer) - 1);
if (strstr(receiveBuffer, MESSAGE)) {
Serial.println("do stuff...");
}
}
}
While running the UDP example on my node mcu v3.0 I encountered the following strange problem.
If I connect both my computer and the node mcu to a WIFI-hotspot hosted by my phone everything runs perfectly (I can send udp packets from my computer via netcat to the node mcu and get an answer).
However if I switch to the WiFi-network provided by the student residence where Im living (we have to connect to the next router with corresponding ssid and password like for any other normal wifi network) the node mcu doesn't receive any packets at all (it still prints out an IP address so I guess it could connect to the network). I also tried sending udp packets from my computer to my laptop via netcat, which stills works normally.
What's going on here?
Here's the code:
/*
UDPSendReceive.pde:
This sketch receives UDP message strings, prints them to the serial port
and sends an "acknowledge" string back to the sender
A Processing sketch is included at the end of file that can be used to send
and received messages for testing with a computer.
created 21 Aug 2010
by Michael Margolis
This code is in the public domain.
adapted from Ethernet library examples
*/
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#ifndef STASSID
#define STASSID ".."
#define STAPSK ".."
#endif
unsigned int localPort = 8888; // local port to listen on
// buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE + 1]; //buffer to hold incoming packet,
char ReplyBuffer[] = "acknowledged\r\n"; // a string to send back
WiFiUDP Udp;
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(STASSID, STAPSK);
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(500);
}
Serial.print("Connected! IP address: ");
Serial.println(WiFi.localIP());
Serial.printf("UDP server on port %d\n", localPort);
Udp.begin(localPort);
}
void loop() {
// if there's data available, read a packet
int packetSize = Udp.parsePacket();
if (packetSize) {
Serial.printf("Received packet of size %d from %s:%d\n (to %s:%d, free heap = %d B)\n",
packetSize,
Udp.remoteIP().toString().c_str(), Udp.remotePort(),
Udp.destinationIP().toString().c_str(), Udp.localPort(),
ESP.getFreeHeap());
// read the packet into packetBufffer
int n = Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
packetBuffer[n] = 0;
Serial.println("Contents:");
Serial.println(packetBuffer);
// send a reply, to the IP address and port that sent us the packet we received
Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
Udp.write(ReplyBuffer);
Udp.endPacket();
}
}
/*
test (shell/netcat):
--------------------
nc -u 192.168.esp.address 8888
*/
EDIT: Calling a website (like google) from the node mcu works fine
Most likely you will have to add IO firewall rules.
Check This link.
Or by using PowerShell:
PS C:\> New-NetFirewallRule -DisplayName "Allow UDP 8888 over Teredo" -Direction Inbound -Action Allow -EdgeTraversalPolicy Allow -Protocol UDP -LocalPort 8888 -Program "C:\Program Files (x86)\TestIPv6App.exe"
I am connecting 4 nodemcu (esp8266). 1 esp8266 is used as access point and others are connected to it.
When I send UDP packets as a broadcast message to all the esp8266 via with esp8266 as access point it is not recieved by the others however when I use a home router or even by mobile hotspot as access point, the broadcast messages are received by the other esp8266.
Also, I have posted here a part of my code that is used for UDP so there may be some variables that you will see as undeclared but they are originally declared and the code is working when I connect it with Access Point that is not esp8266
Code For Access Point:
#include
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.print("Setting soft-AP ... ");
boolean result = WiFi.softAP("ssid", "password123456");
if(result == true)
{
Serial.println("Ready");
}
else
{
Serial.println("Failed!");
}
}
void loop()
{
Serial.printf("Stations connected = %d\n",
WiFi.softAPgetStationNum());
delay(3000);
}
Code for sending UPD packet as broadcast:
unsigned int localPort = 2000;
IPAddress SendIP(192,168,43,255);
setup()
{
udp.begin(localPort);
Serial.print("Local port: ");
Serial.println(udp.localPort());
}
loop()
{
udp.beginPacket(SendIP, 2000);
udp.write("p");
udp.endPacket();
}
Code for Recieving UDP packets:
void loop()
{
int packetSize = udp.parsePacket();
if(packetSize)
{
udp.read(packetBuffer,UDP_TX_PACKET_MAX_SIZE);
p = packetBuffer[0];
Serial.println(p);
function();
}
Please tell me whats the problem with using esp8266 as access point to send UDP packets.
And if esp8266 can not be used please tell me any other chip that can do the work, I want to make a portable system so I cannot use the router.
The default IP address of ESP8266 router in AP mode is 192.168.244.1.
Try to change sending address to 192.168.244.255.
I have a Raspberry Pi 3 Model B with ioBroker (Raspbian light Stretch) as an MQTT broker and Wemos D1 ESP 8266 with a test script. Both devices are connected to the network via Wi-Fi.
Good news:
1) I can send the MQTT signal from the phone (myMQTT apps) and it will be displayed in the ioBroker logs (the phone is connected to Wi-Fi, MicroTik).
I can send an MQTT signal from my laptop (connected to Wi-Fi or ethernet).
I can send a successful MQTT signal from a Debian virtual server (on vmware).
2) Wemos D1 successfully connects to the test server test.mosquitto.org.
The bad news:
Wemos D1 does not want to connect to ioBroker on the local network and reports the error "Attempting MQTT connection ... failed, rc = -2 try again in 5 seconds".
Why all devices except Wemos D1 ESP 8266 successfully connect to mqtt broker?
Could it be the case in the firewall?
Tell me, please, what should I do to solve this problem.
/*
Basic ESP8266 MQTT example
This sketch demonstrates the capabilities of the pubsub library in combination
with the ESP8266 board/library.
It connects to an MQTT server then:
- publishes "hello world" to the topic "outTopic" every two seconds
- subscribes to the topic "inTopic", printing out any messages
it receives. NB - it assumes the received payloads are strings not binary
- If the first character of the topic "inTopic" is an 1, switch ON the ESP Led,
else switch it off
It will reconnect to the server if the connection is lost using a blocking
reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to
achieve the same result without blocking the main loop.
To install the ESP8266 board, (using Arduino 1.6.4+):
- Add the following 3rd party board manager under "File -> Preferences -> Additional Boards Manager URLs":
http://arduino.esp8266.com/stable/package_esp8266com_index.json
- Open the "Tools -> Board -> Board Manager" and click install for the ESP8266"
- Select your ESP8266 in "Tools -> Board"
*/
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
// Update these with values suitable for your network.
const char* ssid = "XXX";
const char* password = "XXX";
const char* mqtt_server = "test.mosquitto.org";
WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;
void setup_wifi() {
delay(5000);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode (WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
// Switch on the LED if an 1 was received as first character
if ((char)payload[0] == '1') {
digitalWrite(BUILTIN_LED, LOW); // Turn the LED on (Note that LOW is the voltage level
// but actually the LED is on; this is because
// it is active low on the ESP-01)
} else {
digitalWrite(BUILTIN_LED, HIGH); // Turn the LED off by making the voltage HIGH
}
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "ESP8266Client-";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("outTopic", "hello world");
// ... and resubscribe
client.subscribe("inTopic");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(1000);
}
}
}
void setup() {
pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output
Serial.begin(115200);
setup_wifi();
client.setServer(mqtt_server, 1883);
client.setCallback(callback);
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
long now = millis();
if (now - lastMsg > 2000) {
lastMsg = now;
++value;
snprintf (msg, 50, "hello world #%ld", value);
Serial.print("Publish message: ");
Serial.println(msg);
client.publish("outTopic", msg);
}
}
Screenshots:
1) netstat -tulpn | grep LISTEN
2) ioBrocker log
3) Arduino IDE
UPDATE:
I did not find where you can change or disable listen port 1883 tcp6.
But I managed to establish a connection between the devices by replacing the Mikrotik router with Keenetic.
Now we need to figure out what's wrong with the settings of the router.
Your screenshot:
shows that ioBroker is listening on the IPv4 loopback interface (127.0.0.1) for ports 9000 and 9001, and on a tcp6 (IPv6) interface for ports 8081, 8082 and 1883.
That means it's only reachable via IPv4 from programs running on the same server as it, or from programs running on computers capable of speaking IPv6.
The ESP8266 is not capable of speaking IPv6.
You need to reconfigure ioBroker to listen on 0.0.0.0:mqtt so that IPv4 software can reach it.
I have been playing around with an arduino ethernet shield, trying to get basic examples to work, to no avail. Here is my setup:
The Arduino Mega 2560 is connected to the computer via usb and the ethernet shield is stacked upon it. I have tried many variations of the examples that come with the arduino software, and none seemed to work properly.After lots of debugging with wireshark, I figured that:
I can't use DHCP, because it just hangs at the Ethernet.begin(mac) call.
When I try with a static ip, the Ethernet.localIP() function returns 0.0.0.0. However, I can ping my device from my computer using the ip I have set and the device seems to receive and send packets properly.The problem now is that for some reason it drops the tcp connections.E.g here is the code I run that comes the closest to working:
#include <SPI.h>
#include <Ethernet.h>
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress ip(192,168,2,27);
IPAddress server(192,168,2,52);
EthernetClient client;
void setup() {
// start the Ethernet connection:
Ethernet.begin(mac, ip);
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
Serial.println("a");
delay(1000);
Serial.println("connecting...");
if (client.connect(server, 23)) {
Serial.println("connected");
}
else {
Serial.println("connection failed");
}
Serial.println(Ethernet.localIP());
}
void loop()
{
// if there are incoming bytes available
// from the server, read them and print them:
if (client.available()) {
char c = client.read();
Serial.print(c);
}
// as long as there are bytes in the serial queue,
// read them and send them out the socket if it's open:
while (Serial.available() > 0) {
char inChar = Serial.read();
if (client.connected()) {
client.print(inChar);
}
}
// if the server's disconnected, stop the client:
if (!client.connected()) {
Serial.println();
Serial.println("disconnecting.");
client.stop();
// do nothing:
while(true);
}
}
Its basically the Ethernet/TelnetClient example.
I have set up a telnet server on my computer. Now this is the arduino/computer exchange:
The arduino sends a RST packet, but my server goes on to send it the greeting and login prompt.
I have tried the same with an arduino uno, and have also tried disconnecting the usb and using another power supply.
So, what could be the issue?
The problem is in the connection to the shield, sometimes this shield if it is chinese version, It might have small short-circuit.
I tried disconnect the shield and connect with wire as like as arduino website indicate for arduino uno (the connections with arduino mega aren't correct, so you need connect like arduino uno)
If it don't work , try change the arduino shield. I have a similar problem with the same shield , and normally the problem is the connection to the arduino.
The example should work if the arduino is correctly connected
Strangely, I found that Ethernet fails to initialize if an SD card is inserted and not initialized. So, either take the SD card out, or initialize the SD card:
Sd2Card card;
card.init(speed, pinSelect);
I have some Chinese (SunFounder) version of Ethernet Shield, so it might not be relevant to cards from other manufacturers.