ESP8266 + WiFiManager + pubsubclient - arduino

I'm using an ESP8266 and want to control it using MQTT with the MQTT server being my Synology DS415+. I want the ESP to sit in a place where I cannot access it using serial once it is installed, so I need to be able to configure it's Wifi-Credentials and the MQTT-Server IP, Port and credentials using WiFi.
Thus I decided that the WiFiManager-Library and the PubSubClient-Library can do this for me. The problem is: I cannot get PubSubClient to work using WiFiManager, because I haven't yet found out how I can tell PubSubClient the right "client" to use.
The following example works on my ESP, however it does not allow for dynamic configuration of the ESPs Wifi: https://github.com/knolleary/pubsubclient/blob/master/examples/mqtt_esp8266/mqtt_esp8266.ino
I came up with the following:
http://pastebin.com/t5evEy1i
This however does not work, its output via serial is the following:
mounting FS...
mounted file system
reading config file
opened config file
{"mqtt_server":"192.168.1.250","mqtt_port":"9001","switch_token":"BackupSwitch"}
parsed json
*WM: Adding parameter
*WM: server
*WM: Adding parameter
*WM: port
*WM: Adding parameter
*WM: blynk
*WM:
*WM: AutoConnect
*WM: Reading SSID
*WM: SSID:
*WM: XXX
*WM: Reading Password
*WM: Password: XXX
*WM: Connecting as wifi client...
*WM: Connection result:
*WM: 3
*WM: IP Address:
*WM: 192.168.1.74
connected...yeey :)
local ip
192.168.1.74
Attempting MQTT connection...192.168.1.250:9001
failed, rc=-2 try again in 5 seconds
Attempting MQTT connection...192.168.1.250:9001
failed, rc=-2 try again in 5 seconds
I'm pretty sure the problem lies in the definition of the PubSubClient in line 17 and 18:
WiFiClient espClient;
PubSubClient client(espClient);
But I don't know how to extract the client from WiFiManager to give it to the PubSubClient-Library.
What I need is how to get an object that is equal to what WiFiClient or EthernetClient creates, that WiFiManager probably creates and that I can give as an argument to PubSubClient client(espClient);
Does anyone have any idea how to achieve this? Thanks in advance.

You don't need to pull anything out of WiFiManager since it is using WiFiClient. All you need to do is:
#include <ESP8266WiFi.h>
#include <WiFiManager.h>
#include <PubSubClient.h>
WiFiClient espClient;
PubSubClient client(espClient);
void mqttCallback(char* topic, byte* payload, unsigned int length) {
// message received
}
void mqttReconnect() {
// reconnect code from PubSubClient example
}
void setup() {
WiFiManager wifiManager;
wifiManager.setTimeout(180);
if(!wifiManager.autoConnect("AutoConnectAP")) {
Serial.println("failed to connect and hit timeout");
delay(3000);
ESP.reset();
delay(5000);
}
Serial.println("connected...yeey :)");
client.setServer(mqtt_server, 1883);
client.setCallback(mqttCallback);
}
void loop() {
if (!client.connected()) {
mqttReconnect();
}
client.loop();
yield();
}

Related

How to solve "Connection failed" for D1mini(ESP8266)

I'm trying to use D1 mini to fetch some data from website. I created an API key on Thingspeak ThingHttp. However, the client didn't connect properly. I got "connection failed" from the Serial monitor.
Here is my code. I think they are almost the same as this.
#include <ESP8266WiFi.h>
#include <WiFiClientSecure.h>
WiFiClientSecure client;
#define HOST "api.thingspeak.com"
void setup()
{
const char *ssid = "my_wifi";
const char *password = "qwertyui";
const char *API = "W0B96PD71W3Z245Q";
Serial.begin(115200);
WiFi.mode(WIFI_STA);
delay(100);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(500);
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
IPAddress ip=WiFi.localIP();
Serial.println(ip);
delay(5000);
Serial.println("finish setup");
}
void loop()
{
delay(5000);
if (!client.connect(HOST, 80))
{
Serial.println(F("Connection failed"));
return;
}
Serial.println("***");
}
And here is what I got from the serial monitor.
WiFi connected
IP address:
192.168.0.53
finish setup
Connection failed
Connection failed
It's obvious that it indeed connected to my wifi correctly, but just unable to connect to the server.
Does anyone know how to fix this? Or are there any crucial step I should set on my D1mini?
(I'm using VSCode instead of Arduino IDE)
You're using the wrong port number.
Port 80 is for unencrypted HTTP.
Port 443 is for HTTPS.
You're using WiFiClientSecure, so presumably you're intending to use HTTPS. HTTPS runs on port 443, not port 80. You'll need to change your code to use 443, or you'll need to use WiFiClient in order to work with port 80 (but make sure the API you're trying to connect to allows access over plain HTTP - most will not).
I highly recommend that you use an existing HTTP client rather than implement the protocol yourself as you'll need to with WiFiClient or WiFiClientSecure, which just provide TCP and encrypted TCP connections. You can find examples of how to use ESP8266HTTPClient in the ESP8266 Arduino core repository.

ESP32 MQTT client stuck at client.subscribe()

I'm trying to connect my ESP32 to mosquitto with MQTTClient but it get stuck when trying to subscribe to any topic and it won't recive messages. I've searched all the afternoon and can't find any solution. I've also tested the broker with MQTTBox and I can subscribe and publish just fine.
Here is the code uploaded to the NodeMCU:
#include <Arduino.h>
#include <MQTTClient.h>
#include "WiFi.h"
#include "secrets.h"
#include <WiFiManager.h>
WiFiClient net = WiFiClient();
MQTTClient client = MQTTClient(256);
void connectMQTT(){
WiFiManager wifiManager;
if(!wifiManager.autoConnect(WIFI_SSID,WIFI_PASSWORD)) {
Serial.println("failed to connect and hit timeout");
//reset and try again, or maybe put it to deep sleep
ESP.restart();
delay(1000);
}
Serial.println("Connected to Wi-Fi");
// Connect to the MQTT broker
client.begin(MQTT_ENDPOINT, MQTT_PORT, net);
// Create a message handler
client.onMessage(messageHandler);
Serial.println("Connecting to MQTT");
while (!client.connect(THINGNAME)) {
Serial.print(".");
delay(100);
}
if(!client.connected()){
Serial.println("MQTT Timeout!");
return;
}
Serial.println("MQTT Connected!");
Serial.println("Subscribing to irtopic");
// Subscribe to topics
client.subscribe("esp32/ir");
Serial.println("");
Serial.println("Success!");
}
void setup() {
Serial.begin(115200);
connectMQTT();
}
And the serial output:
*WM:
*WM: AutoConnect
*WM: Connecting as wifi client...
*WM: Using last saved values, should be faster
*WM: Connection result:
*WM: 3
*WM: IP Address:
*WM: 192.168.0.155
Connected to Wi-Fi
Connecting to MQTT
MQTT Connected!
Subscribing to irtopic

Arduino ESP32 DHCP server

I searched how to configure a DHCP server on ESP32 Arduino to distribute addresses for clients that connect to my ESP32 access point, but unfortunately I did not get any source code for that.
Any help?
As long as you use WiFi.softAP(), you do not need to explicitly configure a DHCP server on the ESP32. It will happen automatically - the library looks after it for you.
Here is a minimal example, where - in addition to setting the ESP32 up as an access point - a TCP server is also started on port 80.
WiFiServer server(80);
static const char *ap_ssid = "ESP32-001";
static const char *ap_pass = "temp_pass";
void setup() {
Serial.begin(115200);
WiFi.softAP(ap_ssid, ap_pass);
Serial.print("Access point running. IP address: ");
Serial.print(WiFi.softAPIP());
Serial.println("");
server.begin();
}
void loop() {
WiFiClient client = server.available();
if (client) {
String client_ip = client.remoteIP().toString();
Serial.print("Client connected. IP address = ");
Serial.print(client_ip);
Serial.println("");
client.println("Hello ...");
client.stop();
}
}
I have attached the serial output in a screenshot below. Notice the
dhcps: send_offer>>udp_sendto result 0
message.

Arduino Ethernet Shield client.connect() always returns error

I have been searching around for this problem for a couple of days but still do not find an answer.
I am trying to make a simple Webclient connection with the arduino shield based on the sample code provided by Arduino IDE. Here is a simplified version of what I am trying to execute:
#include <Ethernet.h>
#include <SPI.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
byte server[] = { 173 ,194, 46, 34 }; // Google
EthernetClient client;
void setup()
{
Ethernet.begin(mac);
Serial.begin(9600);
delay(1000);
Serial.println(Ethernet.localIP());
Serial.println("connecting...");
if (client.connect(server, 80)) {
Serial.println("connected");
client.println("GET /search?q=arduino HTTP/1.0");
client.println();
} else {
Serial.println("connection failed");
}
}
void loop()
{
if (client.available()) {
char c = client.read();
Serial.print(c);
}
if (!client.connected()) {
Serial.println();
Serial.println("disconnecting.");
client.stop();
for(;;)
;
}
}
and always get the answer:
192.168.0.103
connecting...
connection failed
disconnecting.
That means that client.connect(server, 80) is failing. I have tried several IP addresses and same results. The shield is working properly as I have tried the WebServer example and that seems to work flawlessly.
PS on hardware: I am using Arduino UNO R3 and ethernet shield based on W5100
Any suggestions?
I took a look at the source code of the Ethernet library, assuming that you have a recent version of the libraries. It seems to me that Arduino EthernetClient connect() function wants either an IPAddress object or a string (char *) with the name of the remote host. You are passing a byte array to it, and my guess is that it probably interprets it as a string.
Try to declare the server global variable as follows instead:
IPAddress server(173 ,194, 46, 34);
If it works, then it is an indication that the official documentation, from which you probably took the code, is obsolete.
Also, you could try giving to the begin() function all the other parameters as IPAddress objects, so that DHCP is not used and you can rule out problems of automatic configuration. The prototype is:
void begin(uint8_t *mac_address, IPAddress local_ip, IPAddress dns_server, IPAddress gateway, IPAddress subnet);
sorry for the late reply.
Just add delay of 6 seconds before call to client.connect()
so it takes time to initialize ethernet shield....
-by experience
Well, my solution was to put all the configuration by myself; google dns(8.8.8.8), gateway, subnet, ip. and I think that the main trick was to have a sweet delay after the Ethernet.begin. I give a 3000 delay so the connection could be established fine and hands'on...
I managed to come with a workaround. It seems client.connect only fails the first time it is called. So I added a dummy call after the 1 second delay (before the real call is made).
This does not answer the question, but it does solve the problem. Any feedback on why this is happening is welcome.
delay(1000);
client.connect(server, 80); // Dummy call
I faced the similar problem with my client code until i figured out that it was my antivirus's firewall which was blocking arduino's client to connect.
I added an exception in my antivirus and now it works fine.

My Arduino + Ethernet shield WebServer sketch sometimes fails to connect to the client. Causes?

My Arduino web server sketch sporadically fails on:
EthernetClient client = server.available();
if (client)
This morning, it connected just fine on the first run. Now, it can't connect to the client again. A couple of days ago, it worked several times, but failed several time as well. I have the shield connected via an Ethernet cable to my home router. I've verified the IP address assigned to the Arduino. I've tried ports 80 and 8080. What could be going wrong and what else can I try? Could my ISP be blocking something here? Please don't be afraid to suggest the obvious, since I know almost nothing about networks.
If relevant, here is a larger piece of the code, which loops on
Serial.println("Listening");
Code:
#include <SPI.h>
#include <Ethernet.h>n
// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = { 0x90, 0xA2, 0xDA, 0x00, 0xF7, 0x99 };
IPAddress ip(192,168,2,5);
// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);
String roundOpenTag = "";
String roundCloseTag = "";
void setup()
{
// Start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
server.begin();
int ledPin = 8;
// Initialize the digital pin as an output.
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
Serial.println("Setting up");
}
void loop()
{
// Listen for incoming clients
EthernetClient client = server.available();
Serial.println("Listening");
if (client)
{
Serial.println("Server available");
// An HTTP request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
Serial.println("Client connected");
if (client.available())
{
char c = client.read();
I don't see the purpose in including the rest of the sketch. I really appreciate your help.
You have a empty Seiral.begin() in your setup() function. Try removing it.
Edit:
When you call Serial.begin() you have to provide the baut rate(speed) at which you want to communicate. You can read more about the function at Arduino library page.
You had two problems in your code
You had a empty Serial.begin() function call, without any parameter
You had duplicate Serial.begin() function. You had already specified it in the beginning of the setup() function.

Resources