Hello everyone,
TL;DR:
After WiFi connection loss, a NodeMCU unit connected to an Arduino NANO via TX-RX pins doesn't automatically reconnect to WiFi and hangs. I need to manually power on-and off the NodeMCU (and Arduino NANO as the power supply is common). The WiFi auto-reconnect feature on the NodeMCU was working fine before implementing Serial connection to the NANO.
Should I try to use Serial.end() in my code to stop serial communication in case of WiFi connection loss to avoid hanging?
Complete Post:
My project setup is as follows:
- NodeMCU v1.0 connected to WiFi and MQTT
- Arduino NANO connected to NodeMCU via Hardware Serial pins
The NodeMCU is connected to a remote WiFi AP that has a tendency to lose internet connection. I've setup my NodeMCU code so that, in case of MQTT or WiFi disconnection, the board either tries to re-connect (in case of MQTT disconnection) or reboots (in case of WiFi disconnection). This works fine.
The Arduino NANO has some analog sensors and their readings are transmitted to NodeMCU via Hardware Serial "on demand".
All works fine, but today the AP failed and the NodeMCU disconnected. After restarting the AP manually, the NodeMCU didn't connected back. Only cutting power to NodeMCU and Arduino NANO made the trick.
Is it possible that the Hardware Serial communication is preventing NodeMCU from properly reconnecting or rebooting?
Should I try to use the "Serial.end" function to stop serial communication in case of WiFi connection loss or MQTT disconnection?
I tried putting Serial.end() in my code below but I have yet to test it.
This is the NodeMCU code:
#include <FS.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <ESP8266WiFi.h>
#include <Ticker.h>
#include <AsyncMqttClient.h>
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager
//#include <ESP8266WebServer.h>
#include <SoftwareSerial.h>
#include <ArduinoJson.h> //https://github.com/bblanchon/ArduinoJson
String myString; // complete message from arduino, which consistors of snesors data
char rdata; // received charactors
float Irms1, Irms2, Irms3; // sensors
String rms1, rms2, rms3;
// #define WIFI_SSID "TP-LINK_DOWN"
// #define WIFI_PASSWORD ""
// Raspberri Pi Mosquitto MQTT Broker
#define MQTT_HOST "192.168.5.20"
#define MQTT_PORT "1883"
#define MQTT_USER "Marco"
#define MQTT_PASS ""
#define MQTT_PUB_TEMP "centraletermica"
int mqtt_port_int;
char id[7];
String ids;
//flag for saving data
bool shouldSaveConfig = false;
void saveConfigCallback () {
Serial.println("Should save config");
shouldSaveConfig = true;
}
// GPIO where the DS18B20 is connected to
const int oneWireBus = 4;
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(oneWireBus);
// Pass our oneWire reference to Dallas Temperature sensor
DallasTemperature sensors(&oneWire);
// Temperature value
float T1;
float T2;
float T3;
float T4;
float T5;
DeviceAddress sensor1 = { 0x28, 0xFF, 0x74, 0x84, 0x73, 0x15, 0x2, 0x49 };
DeviceAddress sensor2 = { 0x28, 0xFF, 0x22, 0x38, 0x74, 0x15, 0x3, 0xE7 };
DeviceAddress sensor3= { 0x28, 0xFF, 0x65, 0xA2, 0x73, 0x15, 0x1, 0x63 };
DeviceAddress sensor4= { 0x28, 0xFF, 0x9D, 0xA3, 0x73, 0x15, 0x1, 0x74 };
DeviceAddress sensor5= { 0x28, 0xFF, 0x2F, 0xC0, 0x73, 0x15, 0x2, 0x42 };
AsyncMqttClient mqttClient;
Ticker mqttReconnectTimer;
WiFiEventHandler wifiConnectHandler;
WiFiEventHandler wifiDisconnectHandler;
Ticker wifiReconnectTimer;
unsigned long previousMillis = 0; // Stores last time temperature was published
const long interval = 10000; // Interval at which to publish sensor readings
boolean stringComplete = false; // whether the string is complete
void connectToMqtt() {
//Serial.println("Connecting to MQTT...");
mqttClient.connect();
}
void onWifiConnect(const WiFiEventStationModeGotIP& event) {
Serial.println("Connected to Wi-Fi.");
connectToMqtt();
}
// void onWifiDisconnect(const WiFiEventStationModeDisconnected& event) {
// Serial.println("Disconnected from Wi-Fi.");
// mqttReconnectTimer.detach(); // ensure we don't reconnect to MQTT while reconnecting to Wi-Fi
// wifiReconnectTimer.once(2, connectToWifi);
// }
void onMqttConnect(bool sessionPresent) {
Serial.println("Connected to MQTT.");
Serial.print("Session present: ");
Serial.println(sessionPresent);
}
void onMqttDisconnect(AsyncMqttClientDisconnectReason reason) {
Serial.println("Disconnected from MQTT.");
// Serial.end(); currently not used
if (WiFi.isConnected()) {
mqttReconnectTimer.once(2, connectToMqtt);
// Serial.begin(9600); currently not used
}
}
/*void onMqttSubscribe(uint16_t packetId, uint8_t qos) {
Serial.println("Subscribe acknowledged.");
Serial.print(" packetId: ");
Serial.println(packetId);
Serial.print(" qos: ");
Serial.println(qos);
}
void onMqttUnsubscribe(uint16_t packetId) {
Serial.println("Unsubscribe acknowledged.");
Serial.print(" packetId: ");
Serial.println(packetId);
}*/
void onMqttPublish(uint16_t packetId) {
Serial.print("Publish acknowledged.");
Serial.print(" packetId: ");
Serial.println(packetId);
}
String getValue(String data, char separator, int index)
{
int found = 0;
int strIndex[] = { 0, -1 };
int maxIndex = data.length() - 1;
for (int i = 0; i <= maxIndex && found <= index; i++) {
if (data.charAt(i) == separator || i == maxIndex) {
found++;
strIndex[0] = strIndex[1] + 1;
strIndex[1] = (i == maxIndex) ? i+1 : i;
}
}
return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
}
unsigned strToInt(const char *str, int base)
{
const char digits[] = "01234567890ABCDEF";
unsigned result = 0;
while(*str)
{
result *= base;
result += strchr(digits, *str++) - digits;
}
return result;
}
//per la ricezione delle letture da Nano
const byte numChars = 100;
char receivedChars[numChars]; // an array to store the received data
boolean newData = false;
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '*';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
myString = myString + rc;
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
//myString = rc;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
void showNewData() {
if (newData == true) {
//Serial.print("This just in ... ");
//Serial.println(receivedChars);
newData = false;
}
}
void setup(){
WiFi.mode(WIFI_STA); // explicitly set mode, esp defaults to STA+AP
sensors.begin();
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
Serial.println();
WiFiManager wm;
//clean FS for testing
// SPIFFS.format();
//read configuration from FS json
Serial.println("mounting FS...");
if (SPIFFS.begin()) {
Serial.println("mounted file system");
if (SPIFFS.exists("/config.json")) {
//file exists, reading and loading
Serial.println("reading config file");
File configFile = SPIFFS.open("/config.json", "r");
if (configFile) {
Serial.println("opened config file");
size_t size = configFile.size();
// Allocate a buffer to store contents of the file.
std::unique_ptr<char[]> buf(new char[size]);
configFile.readBytes(buf.get(), size);
DynamicJsonBuffer jsonBuffer;
JsonObject& json = jsonBuffer.parseObject(buf.get());
json.printTo(Serial);
if (json.success()) {
Serial.println("\nparsed json");
strcpy(MQTT_HOST, json["MQTT_HOST"]);
strcpy(MQTT_PORT, json["MQTT_PORT"]);
strcpy(MQTT_USER, json["MQTT_USER"]);
strcpy(MQTT_PASS, json["MQTT_PASS"]);
strcpy(MQTT_PUB_TEMP, json["MQTT_PUB_TEMP"]);
} else {
Serial.println("failed to load json config");
}
}
}
} else {
Serial.println("failed to mount FS");
}
//end read
//reset settings - wipe credentials for testing
//wm.resetSettings();
//wm.setConfigPortalBlocking(false);
//set custom field(s)
WiFiManagerParameter custom_text("<p>Insert mqtt server address, port, topic, user and pwd</p>");
wm.addParameter(&custom_text);
WiFiManagerParameter custom_mqtt_server("server", "mqtt server", "192.168.5.20", 40);
wm.addParameter(&custom_mqtt_server);
WiFiManagerParameter custom_mqtt_port("port", "mqtt port", "1883", 40);
wm.addParameter(&custom_mqtt_port);
WiFiManagerParameter custom_mqtt_topic("topic", "mqtt topic", (MQTT_PUB_TEMP + ids).c_str(), 40); //String(id)).c_str()
wm.addParameter(&custom_mqtt_topic);
WiFiManagerParameter custom_mqtt_user("user", "mqtt user", "", 20);
wm.addParameter(&custom_mqtt_user);
WiFiManagerParameter custom_mqtt_pass("pass", "mqtt pass", "", 20);
wm.addParameter(&custom_mqtt_pass);
bool res;
// res = wm.autoConnect(); // auto generated AP name from chipid
// res = wm.autoConnect("AutoConnectAP"); // anonymous ap
res = wm.autoConnect("CentraleTermica",""); // password protected ap
if(!res) {
Serial.println("Failed to connect");
ESP.restart();
}
else {
//if you get here you have connected to the WiFi
Serial.println("connected...yeey :)");
}
//set config save notify callback
wm.setSaveConfigCallback(saveConfigCallback);
strcpy(MQTT_HOST, custom_mqtt_server.getValue());
strcpy(MQTT_PORT, custom_mqtt_port.getValue());
strcpy(MQTT_USER, custom_mqtt_user.getValue());
strcpy(MQTT_PASS, custom_mqtt_pass.getValue());
strcpy(MQTT_PUB_TEMP, custom_mqtt_topic.getValue());
//save the custom parameters to FS
if (shouldSaveConfig) {
Serial.println("saving config");
DynamicJsonBuffer jsonBuffer;
JsonObject& json = jsonBuffer.createObject();
json["MQTT_HOST"] = MQTT_HOST;
json["MQTT_PORT"] = MQTT_PORT;
json["MQTT_USER"] = MQTT_USER;
json["MQTT_PASS"] = MQTT_PASS;
json["MQTT_PUB_TEMP"] = MQTT_PUB_TEMP;
File configFile = SPIFFS.open("/config.json", "w");
if (!configFile) {
Serial.println("failed to open config file for writing");
}
json.printTo(Serial);
json.printTo(configFile);
configFile.close();
//end save
}
wifiConnectHandler = WiFi.onStationModeGotIP(onWifiConnect);
//wifiDisconnectHandler = WiFi.onStationModeDisconnected(onWifiDisconnect);
mqtt_port_int = strToInt(MQTT_PORT,10);
// MQTT_USER = strtol(MQTT_USER);
// MQTT_PORT = strtol(MQTT_PORT);
// MQTT_PASS = strtol(MQTT_PASS);
mqttClient.onConnect(onMqttConnect);
mqttClient.onDisconnect(onMqttDisconnect);
//mqttClient.onSubscribe(onMqttSubscribe);
//mqttClient.onUnsubscribe(onMqttUnsubscribe);
mqttClient.onPublish(onMqttPublish);
mqttClient.setServer(MQTT_HOST, mqtt_port_int);
// If your broker requires authentication (username and password), set them below
mqttClient.setCredentials(MQTT_USER, MQTT_PASS);
//connectToWifi();
mqttClient.connect();
}
void loop(){
//wm.process();
unsigned long currentMillis = millis();
// Every X number of seconds (interval = 10 seconds)
// it publishes a new MQTT message
if ((WiFi.status() != WL_CONNECTED) && (currentMillis - previousMillis >=interval)) {
Serial.print(millis());
Serial.println("Reconnecting to WiFi...");
Serial.println(WiFi.localIP());
// Serial.end(); currently not used
//Alternatively, you can restart your board
ESP.restart();
//Serial.println(WiFi.RSSI());
previousMillis = currentMillis;
}
if (currentMillis - previousMillis >= interval) {
// Save the last time a new reading was published
previousMillis = currentMillis;
Serial.println("<Nano read CTs>"); //ordinare a Nano di leggere i CT
recvWithStartEndMarkers();
if (newData == true) {
String rms1 = getValue(myString, ',', 1);
String rms2 = getValue(myString, ',', 2);
String rms3 = getValue(myString, ',', 3);
Irms1 = rms1.toFloat();
Irms2 = rms2.toFloat();
Irms3 = rms3.toFloat();
myString = "";
// end new code
}
newData = false;
sensors.requestTemperatures(); // Send the command to get temperatures
T1 = sensors.getTempC(sensor1);
T2 = sensors.getTempC(sensor2);
T3 = sensors.getTempC(sensor3);
T4 = sensors.getTempC(sensor4);
T5 = sensors.getTempC(sensor5);
uint16_t packetIdPub1 = mqttClient.publish(MQTT_PUB_TEMP"/T1", 1, true, String(T1).c_str());
// Serial.printf("Publishing on topic %s at QoS 1, packetId: %i ", MQTT_PUB_TEMP, packetIdPub1);
// Serial.printf("Message: %.2f \n", T1);
uint16_t packetIdPub2 = mqttClient.publish(MQTT_PUB_TEMP"/T2", 1, true, String(T2).c_str());
// Serial.printf("Publishing on topic %s at QoS 1, packetId: %i ", MQTT_PUB_TEMP, packetIdPub2);
// Serial.printf("Message: %.2f \n", T2);
uint16_t packetIdPub3 = mqttClient.publish(MQTT_PUB_TEMP"/T3", 1, true, String(T3).c_str());
// Serial.printf("Publishing on topic %s at QoS 1, packetId: %i ", MQTT_PUB_TEMP, packetIdPub3);
// Serial.printf("Message: %.2f \n", T3);
uint16_t packetIdPub4 = mqttClient.publish(MQTT_PUB_TEMP"/T4", 1, true, String(T4).c_str());
// Serial.printf("Publishing on topic %s at QoS 1, packetId: %i ", MQTT_PUB_TEMP, packetIdPub4);
// Serial.printf("Message: %.2f \n", T4);
uint16_t packetIdPub5 = mqttClient.publish(MQTT_PUB_TEMP"/T5", 1, true, String(T5).c_str());
// Serial.printf("Publishing on topic %s at QoS 1, packetId: %i ", MQTT_PUB_TEMP, packetIdPub5);
// Serial.printf("Message: %.2f \n", T5);
uint16_t packetIdPub6 = mqttClient.publish(MQTT_PUB_TEMP"/Irms1", 1, true, String(Irms1).c_str());
// Serial.printf("Publishing on topic %s at QoS 1, packetId: %i ", MQTT_PUB_TEMP, packetIdPub6);
// Serial.printf("Message: %.2f \n", Irms1);
uint16_t packetIdPub7 = mqttClient.publish(MQTT_PUB_TEMP"/Irms2", 1, true, String(Irms2).c_str());
// Serial.printf("Publishing on topic %s at QoS 1, packetId: %i ", MQTT_PUB_TEMP, packetIdPub7);
// Serial.printf("Message: %.2f \n", Irms2);
uint16_t packetIdPub8 = mqttClient.publish(MQTT_PUB_TEMP"/Irms3", 1, true, String(Irms3).c_str());
// Serial.printf("Publishing on topic %s at QoS 1, packetId: %i ", MQTT_PUB_TEMP, packetIdPub8);
// Serial.printf("Message: %.2f \n", Irms3);
}
}
This is the NANO code:
#include <Arduino.h>
//#include <SoftwareSerial.h>
#include "EmonLib.h" // Include Emon Library
EnergyMonitor emon1; // Create an instance
EnergyMonitor emon2; // Create an instance
EnergyMonitor emon3; // Create an instance
//SoftwareSerial nodemcuserial(10,11); //rx-tx pins --> connect to tx-rx
String cdata;
unsigned long interval = 10000; //Time between readings
unsigned long previousMillis = 0; //will store last time LED was updated
// funzioni per ricevere la richiesta di lettura da NodeMCU
const byte numChars = 32;
char receivedChars[numChars];
boolean newData = false;
void recvWithStartEndMarkers() {
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false) {
rc = Serial.read();
if (recvInProgress == true) {
if (rc != endMarker) {
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars) {
ndx = numChars - 1;
}
}
else {
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker) {
recvInProgress = true;
}
}
}
void showNewData() {
if (newData == true) {
//Serial.print("This just in ... ");
//Serial.println(receivedChars);
newData = false;
}
}
// the setup function runs once when you press reset or power the board
void setup() {
//analogReference(EXTERNAL); // use AREF for reference voltage
Serial.begin(9600); // setup serial
//nodemcuserial.begin(9600);
//emon1.voltage(3, 234.26, 1.7); // Voltage: input pin, calibration, phase_shift
emon1.voltage(1, 205.0, 1.68); // Voltage: input pin, calibration, phase_shift
emon1.current(3, 30); // Current: input pin, calibration.
emon2.voltage(1, 205.0, 1.68); // Voltage: input pin, calibration, phase_shift
emon2.current(4, 30); // Current: input pin, calibration.
emon3.voltage(1, 205.0, 1.68); // Voltage: input pin, calibration, phase_shift
emon3.current(5, 30); // Current: input pin, calibration.
}
// the loop function runs over and over again forever
void loop() {
// unsigned long currentMillis = millis();
// if(currentMillis - previousMillis > interval) {
// previousMillis = currentMillis; //save the last time you blinked the LED
recvWithStartEndMarkers();
if(newData == true){
showNewData();
emon1.calcVI(20,2000); // Calculate all. No.of wavelengths, time-out
//emon1.serialprint(); // Print out all variables
emon2.calcVI(20,2000); // Calculate all. No.of wavelengths, time-out
// emon2.serialprint(); // Print out all variables
emon3.calcVI(20,2000); // Calculate all. No.of wavelengths, time-out
// emon3.serialprint(); // Print out all variables
double P1 = emon1.realPower;// Calculate Irms only
//if (Irms1 < 0.05) Irms1=0.0;
//Serial.print(Irms1*230.0); // Apparent power
//Serial.print(" ");
//Serial.println(Irms1); // Irms
double P2 = emon2.realPower; // Calculate Irms only
// if (Irms2 < 0.05) Irms2=0.0;
//Serial.print(Irms2*230.0); // Apparent power
//Serial.print(" ");
//Serial.println(Irms2); // Irms
double P3 = emon3.realPower; // Calculate Irms only
// if (Irms3 < 0.05) Irms3=0.0;
//Serial.print(Irms3*230.0); // Apparent power
//Serial.print(" ");
//Serial.println(Irms3); // Irms
// emon1.calcVI(20,2000); // Calculate all. No.of wavelengths, time-out
// emon1.serialprint(); // Print out all variables
// emon2.calcVI(20,2000); // Calculate all. No.of wavelengths, time-out
// emon2.serialprint(); // Print out all variables
// emon3.calcVI(20,2000); // Calculate all. No.of wavelengths, time-out
// emon3.serialprint(); // Print out all variables
cdata = cdata + "<" + "," + P1 + "," + P2 + "," + P3 +"*" ;
Serial.print(cdata);
Serial.println();
//nodemcuserial.println(cdata);
//nodemcuserial.println();
cdata = "";
}
}
Thanks for your help!