Hello all,
I need some help on my project used to read epever and manage x3 opto driven relay boards connected to D3, D2 & D1 respectively. The epever part and relays connected to D3 & D2 are working fine, however when D1 is turned ON via the BLYNK_WRITE(vPin_in_3), the Wemos will timeout with a WDT reset after few seconds from activation. Same code is used for the other outputs and relay board was replaced without any improvement.
ets Jan 8 2013,rst cause:4, boot mode:(3,0)
wdt reset
load 0x4010f000, len 3460, room 16
tail 4
chksum 0xcc
load 0x3fff20b8, len 40, room 4
tail 4
chksum 0xc9
csum 0xc9
v000689f0
~ld
The board is driven from a separate 5V supply while the relays are being powered from a separate 3.3V supply.
/*************************************************************
Epever Solar Tracer
*************************************************************/
#include <FS.h>
#include "config.h"
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <ESP8266httpUpdate.h>
#include <ESP8266HTTPUpdateServer.h>
#include <BlynkSimpleEsp8266.h>
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager
#include <ModbusMaster.h>
#include <Ticker.h>
#include <uptime_formatter.h>
#include <DoubleResetDetector.h>
#include <ArduinoJson.h> //https://github.com/bblanchon/ArduinoJson
#include <PubSubClient.h>
char blynk_template_id[] = BLYNK_TEMPLATE_ID;
char blynk_device_name[] = BLYNK_DEVICE_NAME;
char blynk_auth_token[] = BLYNK_AUTH_TOKEN;
String overTheAirURL = "";
char mqtt_server[40];
char mqtt_port[6] = MQTT_DEFAULT_PORT;
char mqtt_username[40];
char mqtt_password[40];
char time_2_wifi[5] = TIME_TO_CON_WIFI;
bool is_MQTT_trigger_Rly = false;
//flag for saving data
bool shouldSaveConfig = false;
//Real-time data (read only) input register
struct Epever_RTS{
String param_name;
unsigned long param_address;
double result_value;
int blynk_Vpin;
}
Epever_RTS[] ={
{"PV array voltage", 0x00, 0, vPin_VPV},
{"PV array current", 0x01, 0, vPin_IPV},
{"PV array power", 0x02, 0, vPin_PPV},
{"Battery voltage", 0x04, 0, vPin_VBatt},
{"Battery charging current", 0x05, 0, vPin_IBatt},
{"Battery charging power", 0x06, 0, vPin_PBatt},
{"Load current", 0x0D, 0, vPin_ILoad},
{"Load power", 0x0E, 0, vPin_PLoad},
{"Battery Temperature", 0x10, 0, vPin_BTemp},
{"Temperature inside case", 0x11, 0, vPin_CTemp}
};
//Statistical parameter (read only) input register
struct Epever_Stat{
String param_name;
unsigned long param_address;
double result_value;
int blynk_Vpin;
}
Epever_Stat[] ={
{"Maximum input volt (PV) today", 0x00, 0, vPin_VPVMax},
{"Minimum input volt (PV) today", 0x01, 0, vPin_VPVMin},
{"Maximum battery volt today", 0x02, 0, vPin_VBMax},
{"Minimum battery volt today", 0x03, 0, vPin_VBMin},
{"Consumed energy today", 0x04, 0, vPin_LPTod},
{"Consumed energy this month", 0x06, 0, vPin_LPMon},
{"Consumed energy this year", 0x08, 0, vPin_LPYr},
{"Generated energy today", 0x0C, 0, vPin_PVGenTod},
{"Generated energy this month", 0x0E, 0, vPin_PVGenMon},
{"Generated energy this year", 0x10, 0, vPin_PVGenYr}
};
//Initialise blynker time
BlynkTimer timer;
//Initialise modbus
ModbusMaster node;
//Initialise Ticker
Ticker ticker;
//Initailise double reset
DoubleResetDetector drd(DRD_TIMEOUT, DRD_ADDRESS);
//Initialise MQTT
WiFiClient espClient;
PubSubClient client(espClient);
unsigned long lastMsg = 0;
#define MSG_BUFFER_SIZE (50)
char msg[MSG_BUFFER_SIZE];
int value = 0;
long lastReconnectAttempt = 0;
/* Blynk Functions */
//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
// This function is called every time the Virtual Pin vPin_in_1 state changes
BLYNK_WRITE(vPin_in_1)
{
// Set incoming value from pin vPin_in_1 to a variable
int value = param.asInt();
changeRlyOutState(vPin_in_1,vPin_out_1,OUT_D3_1,value);
is_MQTT_trigger_Rly = false;
}
// This function is called every time the Virtual Pin vPin_in_2 state changes
BLYNK_WRITE(vPin_in_2)
{
// Set incoming value from pin vPin_in_2 to a variable
int value = param.asInt();
changeRlyOutState(vPin_in_2,vPin_out_2,OUT_D2_2,value);
is_MQTT_trigger_Rly = false;
}
// This function is called every time the Virtual Pin vPin_in_3 state changes
BLYNK_WRITE(vPin_in_3)
{
// Set incoming value from pin vPin_in_3 to a variable
int value = param.asInt();
changeRlyOutState(vPin_in_3, vPin_out_3,OUT_D1_3,value);
is_MQTT_trigger_Rly = false;
}
void changeRlyOutState(int VpinIn, int VpinOut, int PpinOut, int value ){
//VpinOut = Blynk Virtual Pin
//PpinOut = ESP Physical Pin
//value = pin state i.e. 1 / 0
// start ticker with 0.4 because we received some data
ticker.attach(0.4, tick);
// Update Blynk state
Blynk.virtualWrite(VpinOut, value);
//let's see who send the request
//if MQTT then update the Blynk switch status for visual purpose only
if(is_MQTT_trigger_Rly){
Blynk.virtualWrite(VpinIn, value);
}
//Let's sync to the server
Blynk.syncAll();
//Publish the status to MQTT
if(VpinOut == vPin_out_1){
client.publish("SolarTracer/inTopic/relay/1/state_topic", (value == 1)? "ON" : "OFF");
}
else if(VpinOut == vPin_out_2){
client.publish("SolarTracer/inTopic/relay/2/state_topic", (value == 1)? "ON" : "OFF");
}
else if(VpinOut == vPin_out_3){
client.publish("SolarTracer/inTopic/relay/3/state_topic", (value == 1)? "ON" : "OFF");
}
// set the RELAY with the virtual switch of the variable:
digitalWrite(PpinOut, (value == 1)? LOW : HIGH);
Serial.print("[Blynk/MQTT]: Relay connected to IO " + String(PpinOut) + " value is: ");
Serial.print((value == 1)? "ON" : "OFF");
Serial.println();
ticker.detach();
//keep LED off
digitalWrite(LED, HIGH);
}
// This function is called every time the device is connected to the Blynk.Cloud
BLYNK_CONNECTED()
{
//Lets send log to USB & LOG to Blynk server
Serial.println(F("[Blynk]: We are now connected to Blynk cloud server."));
Blynk.logEvent("event_code", String("[Blynk]: We are now connected to Blynk cloud server."));
//Update virtual pin
Blynk.virtualWrite(vPin_blynk_status, WiFi.SSID() + " " + WiFi.localIP().toString());
//Send the WIFI details as logs
Blynk.logEvent("event_code", String("[WiFi Manager] Connected to: ") + WiFi.SSID() + " with IP address " + WiFi.localIP().toString());
//Let's sync to the server
Blynk.syncAll();
}
// This function sends Arduino's uptime every second to Virtual Pin 2.
void myTimerEvent()
{
String value_str;
char valuestring[50];
if(Blynk.connected() && WiFi.isConnected()){
// You can send any value at any time.
// Please don't send more that 10 values per second.
Blynk.virtualWrite(vPin_uptime, "up " + uptime_formatter::getUptime());
}
//Send data in various formats to MQTT Server
if(client.connected() && WiFi.isConnected()){
value_str = uptime_formatter::getUptime();
value_str.toCharArray(valuestring, value_str.length() + 1);
client.publish("SolarTracer/outTopic/uptime", valuestring);
}
}
// This function sends EPEVER values
void timerSendRealtime()
{
uint8_t result;
uint16_t data[6];
String value_str;
char valuestring[5];
String outTopic_Str;
char paramOutTopic[50];
// Read all 18 realtime registers starting at 0x3100)
node.clearResponseBuffer();
result = node.readInputRegisters(0x3100, 18);
if (result == node.ku8MBSuccess)
{
//Lets loop through each realtime struct value
for (byte i = 0; i < sizeof(Epever_RTS) / sizeof(Epever_RTS[0]); i++) {
//Check if we are going to request power registers
if(Epever_RTS[i].param_address == 0x02 || Epever_RTS[i].param_address == 0x06
|| Epever_RTS[i].param_address == 0x0E)
{
Epever_RTS[i].result_value = (long)(node.getResponseBuffer(Epever_RTS[i].param_address) |
node.getResponseBuffer(Epever_RTS[i].param_address+1) << 16)/100.0f;
}
else {
Epever_RTS[i].result_value = (long)node.getResponseBuffer(Epever_RTS[i].param_address)/100.0f;
}
//Print the output to serial debug
Serial.print(F("[EPEVER]: "));
Serial.print(Epever_RTS[i].param_name);
Serial.print(" ");
Serial.println(Epever_RTS[i].result_value);
//Send data in various formats to Blynk Virtual Pins
if(Blynk.connected() && WiFi.isConnected()){
Blynk.virtualWrite(Epever_RTS[i].blynk_Vpin,Epever_RTS[i].result_value);
}
//Send data in various formats to MQTT Server
if(client.connected() && WiFi.isConnected()){
value_str = String(Epever_RTS[i].result_value,2);
value_str.toCharArray(valuestring, value_str.length() + 1);
outTopic_Str = String("SolarTracer/outTopic/" + Epever_RTS[i].param_name);
outTopic_Str.replace(" ","_");
//publish to server
outTopic_Str.toCharArray(paramOutTopic, outTopic_Str.length() + 1);
client.publish(paramOutTopic, valuestring);
}
}
}
else
{
//Read attempt failed thus send error to serial monitor
modbusMaster_PrintError("0x3100",result);
}
// Let's Obtain the Battery SOC status from the 0x311A register
node.clearResponseBuffer();
result = node.readInputRegisters(0x311A, 1);
if (result == node.ku8MBSuccess)
{
//Send data in various formats to Blynk Virtual Pins
if(Blynk.connected() && WiFi.isConnected()){
Blynk.virtualWrite(vPin_BSOC,(long)node.getResponseBuffer(0)/1.0f);
}
//Send data in various formats to MQTT Server
if(client.connected() && WiFi.isConnected()){
value_str = String(node.getResponseBuffer(0),2);
value_str.toCharArray(valuestring, value_str.length() + 1);
outTopic_Str = String("SolarTracer/outTopic/Battery SOC");
outTopic_Str.replace(" ","_");
//publish to server
outTopic_Str.toCharArray(paramOutTopic, outTopic_Str.length() + 1);
client.publish(paramOutTopic, valuestring);
}
//Print the output to serial debug
Serial.print(F("[EPEVER]: "));
Serial.print(F("Battery SOC"));
Serial.print(" ");
Serial.println(node.getResponseBuffer(0));
}
else
{
//Read attempt failed thus send error to serial monitor
modbusMaster_PrintError("0x311A",result);
}
// Let's Obtain the day status from the 0x2000 register
/*node.clearResponseBuffer();
result = node.readDiscreteInputs(0x200C, 1);
if (result == node.ku8MBSuccess)
{
//Send data in various formats to Blynk Virtual Pins
if(Blynk.connected() && WiFi.isConnected()){
((node.getResponseBuffer(0) == 1) ? Blynk.virtualWrite(vPin_SunStat,"Night") : Blynk.virtualWrite(vPin_SunStat,"Day"));
}
//Send data in various formats to MQTT Server
if(client.connected() && WiFi.isConnected()){
outTopic_Str = String("SolarTracer/outTopic/Day Status");
outTopic_Str.replace(" ","_");
//publish to server
outTopic_Str.toCharArray(paramOutTopic, outTopic_Str.length() + 1);
((node.getResponseBuffer(0) == 1) ? client.publish(paramOutTopic, "Night") : client.publish(paramOutTopic, "Day"));
}
//Print the output to serial debug
Serial.print(F("[EPEVER]: "));
Serial.print(F("Day Status"));
Serial.print(" ");
Serial.println(node.getResponseBuffer(0));
}
else
{
//Read attempt failed thus send error to serial monitor
modbusMaster_PrintError("0x220C",result);
}*/
//toggle LED status
tick();
}
// This function sends further EPEVER values.
void timerSendStatistics()
{
uint8_t result;
uint16_t data[6];
String value_str;
char valuestring[5];
String outTopic_Str;
char paramOutTopic[50];
// Read 20 registers starting at 0x3300)
node.clearResponseBuffer();
result = node.readInputRegisters(0x3300, 20);
if (result == node.ku8MBSuccess)
{
//Lets loop through each struct value
for (byte i = 0; i < sizeof(Epever_Stat) / sizeof(Epever_Stat[0]); i++) {
//Check if we are going to request power registers
if(Epever_Stat[i].param_address == 0x04 || Epever_Stat[i].param_address == 0x06
|| Epever_Stat[i].param_address == 0x08 || Epever_Stat[i].param_address == 0x0C
|| Epever_Stat[i].param_address == 0x0E || Epever_Stat[i].param_address == 0x10)
{
Epever_Stat[i].result_value = (long)(node.getResponseBuffer(Epever_Stat[i].param_address) |
node.getResponseBuffer(Epever_Stat[i].param_address+1) << 16)/100.0f;
}
else {
Epever_Stat[i].result_value = (long)node.getResponseBuffer(Epever_Stat[i].param_address)/100.0f;
}
//Print the output to serial debug
Serial.print(F("[EPEVER Stat]: "));
Serial.print(Epever_Stat[i].param_name);
Serial.print(" ");
Serial.println(Epever_Stat[i].result_value);
//Send data in various formats to Blynk Virtual Pins
if(Blynk.connected() && WiFi.isConnected()){
Blynk.virtualWrite(Epever_Stat[i].blynk_Vpin,Epever_Stat[i].result_value);
}
//Send data in various formats to MQTT Server
if(client.connected() && WiFi.isConnected()){
value_str = String(Epever_Stat[i].result_value,2);
value_str.toCharArray(valuestring, value_str.length() + 1);
outTopic_Str = String("SolarTracer/outTopic/" + Epever_Stat[i].param_name);
outTopic_Str.replace(" ","_");
//publish to server
outTopic_Str.toCharArray(paramOutTopic, outTopic_Str.length() + 1);
client.publish(paramOutTopic, valuestring);
}
}
}
else
{
//Read attempt failed thus send error to serial monitor
modbusMaster_PrintError("0x3300",result);
}
//toggle LED status
tick();
}
//Blynk remote device reboot
BLYNK_WRITE(InternalPinDBG) {
if (String(param.asStr()) == "reboot") {
Serial.println(F("[Blynk]: Rebooting your device..."));
// turn off peripherals, write state to EEPROM, etc.
rebootDevice();
}
}
void rebootDevice(){
//keep relay pins at high thus OFF
setPins2StateHIGH();
delay(2000);
//Let's sync to the server
Blynk.syncAll();
//disconnect from server
Blynk.disconnect();
//Let's reboot now
ESP.restart();
}
BLYNK_WRITE(InternalPinOTA) {
Serial.println(F("[Blynk]: OTA Started"));
overTheAirURL = param.asString();
Serial.print(F("[Blynk]: overTheAirURL = "));
Serial.println(overTheAirURL);
WiFiClient my_wifi_client;
HTTPClient http;
http.begin(my_wifi_client, overTheAirURL);
t_httpUpdate_return ret = ESPhttpUpdate.update(my_wifi_client, overTheAirURL);
switch(ret) {
case HTTP_UPDATE_FAILED:
Serial.println(F("[Blynk] Update failed."));
break;
case HTTP_UPDATE_NO_UPDATES:
Serial.println(F("[Blynk] Update no Update."));
break;
case HTTP_UPDATE_OK:
Serial.println(F("[Blynk] Update ok.")); // may not be called since we reboot the ESP
break;
}
Serial.println(F("[Blynk] Rebooting now!"));
reboot();
}
void reboot()
{
Serial.println(F("[Blynk]: Rebooting after OTA Update..."));
#if defined(ARDUINO_ARCH_MEGAAVR)
wdt_enable(WDT_PERIOD_8CLK_gc);
#elif defined(__AVR__)
wdt_enable(WDTO_15MS);
#elif defined(__arm__)
NVIC_SystemReset();
#elif defined(ESP8266) || defined(ESP32)
ESP.restart();
#else
#error "[Blynk]: MCU reset procedure not implemented"
#endif
for (;;) {}
}
//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
/* END Blynk functions */
void preTransmission()
{
digitalWrite(RS485_CTR, 1);
}
void postTransmission()
{
digitalWrite(RS485_CTR, 0);
}
void tick()
{
//toggle state
digitalWrite(LED, !digitalRead(LED)); // set pin to the opposite state
}
//callback notifying us of the need to save config
void saveConfigCallback () {
Serial.println(F("[WiFi Manager]: Should save config"));
shouldSaveConfig = true;
}
void configModeCallback (WiFiManager *myWiFiManager) {
Serial.println(F("[WiFi Manager]: Entered config mode"));
Serial.println(WiFi.softAPIP());
drd.stop();
}
//Function to set pins as output
void setPins2Output(){
pinMode(LED, OUTPUT);
pinMode(OUT_D3_1, OUTPUT);
pinMode(OUT_D2_2, OUTPUT);
pinMode(OUT_D1_3, OUTPUT);
pinMode(RS485_CTR, OUTPUT);
}
//function to set pins to a known state
void setPins2StateHIGH(){
changeRlyOutState(vPin_in_1, vPin_out_1,OUT_D3_1,0);
changeRlyOutState(vPin_in_2, vPin_out_2,OUT_D2_2,0);
changeRlyOutState(vPin_in_3, vPin_out_3,OUT_D1_3,0);
is_MQTT_trigger_Rly = true;
}
//function to report MODBUS errors to serial.
void modbusMaster_PrintError(String registerID , uint8_t result){
Serial.print("[EPEVER]: Modbus node failed to read register "+ registerID +" with result (");
Serial.print(result, HEX);
switch (result)
{
case 0xE0 :
Serial.println(F(") -> invalid response slave ID exception"));
break;
case 0xE1 :
Serial.println(F(") -> invalid response function exception"));
break;
case 0xE2 :
Serial.println(F(") -> response timed out exception"));
break;
case 0xE3 :
Serial.println(F(") -> invalid response CRC exception"));
break;
default : break;;
}
}
/* MQTT Functions */
//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
void MQTTcallback(char* topic, byte* payload, unsigned int length) {
// handle message arrived
String inMSG = "";
Serial.print(F("[MQTT] Message received ["));
Serial.print(topic);
Serial.print("] ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
inMSG += (char)payload[i];
}
;
Serial.println();
if(strcmp(topic, "SolarTracer/inTopic/relay/1") == 0){
if(inMSG=="ON"){
changeRlyOutState(vPin_in_1,vPin_out_1,OUT_D3_1,1);
}
else if(inMSG=="OFF"){
changeRlyOutState(vPin_in_1,vPin_out_1,OUT_D3_1,0);
}
is_MQTT_trigger_Rly = true;
}
else if(strcmp(topic, "SolarTracer/inTopic/relay/2") == 0){
if(inMSG=="ON"){
changeRlyOutState(vPin_in_2,vPin_out_2,OUT_D2_2,1);
}
else if(inMSG=="OFF"){
changeRlyOutState(vPin_in_2,vPin_out_2,OUT_D2_2,0);
}
is_MQTT_trigger_Rly = true;
}
else if(strcmp(topic, "SolarTracer/inTopic/relay/3") == 0){
if(inMSG=="ON"){
changeRlyOutState(vPin_in_3,vPin_out_3,OUT_D1_3,1);
}
else if(inMSG=="OFF"){
changeRlyOutState(vPin_in_3,vPin_out_3,OUT_D1_3,0);
}
is_MQTT_trigger_Rly = true;
}
else if(strcmp(topic, "SolarTracer/inTopic/cmd") == 0){
if(inMSG=="reboot"){
rebootDevice();
}
}
}
//MQTT reconect function
boolean reconnect() {
Serial.print(F("[MQTT] 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(),mqtt_username,mqtt_password)) {
Serial.println(F("[MQTT] connected"));
// Once connected, publish an announcement...
client.publish("SolarTracer/outTopic/", "hello world");
// ... and resubscribe
client.subscribe("SolarTracer/inTopic/relay/1");
client.subscribe("SolarTracer/inTopic/relay/2");
client.subscribe("SolarTracer/inTopic/relay/3");
client.subscribe("SolarTracer/inTopic/reset");
}
else {
Serial.print(F("[MQTT] failed, rc="));
Serial.print(String(client.state()));
Serial.println(F(" try again soon"));
}
return client.connected();
}
//""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
/* END Blynk functions */
void setup()
{
// set the digital pin as output:
setPins2Output();
//keep relay pins at high thus OFF
setPins2StateHIGH();
//Keep modbus control pin low
digitalWrite(RS485_CTR, LOW);
// start ticker with 0.5 because we start in AP mode and try to connect
ticker.attach(0.5, tick);
// explicitly set mode, esp defaults to STA+AP
WiFi.mode(WIFI_STA);
// Initialise Debug console
delay(2000);
Serial.begin(HW_SERIAL_BAUD_RATE);
//print the banner and firmware version
Serial.println(F(" "));
Serial.println(F(" _____ __ ______ "));
Serial.println(F(" / ___/____ / /___ ______ /_ __/________ _________ _____"));
Serial.println(F(" \__ \/ __ \/ / __ `/ ___/ / / / ___/ __ `/ ___/ _ \/ ___/"));
Serial.println(F(" ___/ / /_/ / / /_/ / / / / / / / /_/ / /__/ __/ / "));
Serial.println(F("/____/\____/_/\__,_/_/ /_/ /_/ \__,_/\___/\___/_/ "));
Serial.println(F(" "));
Serial.println(F(" "));
Serial.println("[ESP8266]: Firmware Version: " + String(BLYNK_FIRMWARE_VERSION));
Serial.println(F("[ESP8266]: Author: Christmark Chircop"));
Serial.println(F("[ESP8266]: Supporting Plug-in: MQTT & Blynk"));
//read configuration from FS json
Serial.println(F("[SPIFFS]: mounting FS..."));
if (SPIFFS.begin()) {
Serial.println(F("[SPIFFS]: mounted file system"));
if (SPIFFS.exists("/config.json")) {
//file exists, reading and loading
Serial.println(F("[SPIFFS]: reading config file"));
File configFile = SPIFFS.open("/config.json", "r");
if (configFile) {
Serial.println(F("[SPIFFS]: 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);
#if defined(ARDUINOJSON_VERSION_MAJOR) && ARDUINOJSON_VERSION_MAJOR >= 6
DynamicJsonDocument json(1024);
auto deserializeError = deserializeJson(json, buf.get());
serializeJson(json, Serial);
if ( ! deserializeError ) {
#else
DynamicJsonBuffer jsonBuffer;
JsonObject& json = jsonBuffer.parseObject(buf.get());
json.printTo(Serial);
if (json.success()) {
#endif
Serial.println(F("\n[SPIFFS]: parsed json"));
strcpy(blynk_template_id, json["blynk_template_id"]);
strcpy(blynk_device_name, json["blynk_device_name"]);
strcpy(blynk_auth_token, json["blynk_auth_token"]);
strcpy(mqtt_server, json["mqtt_server"]);
strcpy(mqtt_port, json["mqtt_port"]);
strcpy(mqtt_username, json["mqtt_username"]);
strcpy(mqtt_password, json["mqtt_password"]);
strcpy(time_2_wifi, json["time_2_wifi"]);
} else {
Serial.println(F("[SPIFFS] failed to load json config"));
}
configFile.close();
}
}
} else {
Serial.println(F("[SPIFFS] failed to mount FS"));
}
//end read
// The extra parameters to be configured (can be either global or just in the setup)
// After connecting, parameter.getValue() will get you the configured value
// id/name placeholder/prompt default length
WiFiManagerParameter custom_blynk_template_id("blynk_template_id", "Blynk Template ID", blynk_template_id, 34);
WiFiManagerParameter custom_blynk_device_name("blynk_device_name", "Blynk Device Name", blynk_device_name, 34);
WiFiManagerParameter custom_blynk_auth_token("blynk_auth_token", "Blynk API token", blynk_auth_token, 34);
WiFiManagerParameter custom_mqtt_server("mqtt_server", "MQTT Server", mqtt_server, 40);
WiFiManagerParameter custom_mqtt_port("mqtt_port", "MQTT Port Number", mqtt_port, 6);
WiFiManagerParameter custom_mqtt_username("mqtt_username", "MQTT Username", mqtt_username, 40);
WiFiManagerParameter custom_mqtt_password("mqtt_password", "MQTT Password", mqtt_password, 40);
WiFiManagerParameter custom_time_2_wifi("time_2_wifi", "Time (min) to connect to WIFI (0 = disable)", time_2_wifi, 5);
//WiFiManager
//Local intialization. Once its business is done, there is no need to keep it around
WiFiManager wm;
//set config notify callback
wm.setAPCallback(configModeCallback);
wm.setSaveConfigCallback(saveConfigCallback);
//Add some custom parameters
wm.addParameter(&custom_blynk_template_id);
wm.addParameter(&custom_blynk_device_name);
wm.addParameter(&custom_blynk_auth_token);
wm.addParameter(&custom_mqtt_server);
wm.addParameter(&custom_mqtt_port);
wm.addParameter(&custom_mqtt_username);
wm.addParameter(&custom_mqtt_password);
wm.addParameter(&custom_time_2_wifi);
//Set the portal to dark mode
wm.setClass("invert");
if (drd.detectDoubleReset()) {
Serial.println("[Double Reset]: We have detected double reset hence entering config mode.");
wm.startConfigPortal(BLYNK_DEVICE_NAME,WIFI_AP_DEFAULT_PASSWORD);
}
else {
ticker.detach();
// start ticker with 0.3
ticker.attach(0.3, tick);
//Wait here for some time to ensure wifi is available
if(atoi(time_2_wifi)>0){
delay(atoi(time_2_wifi) * 60 * 1000);
}
//automatically connect using saved credentials if they exist
//If connection fails it starts an access point with the specified name
if(wm.autoConnect(BLYNK_DEVICE_NAME,WIFI_AP_DEFAULT_PASSWORD)){
Serial.println(F("[WiFi Manager]: We have connected to WIFI"));
//Keep modbus CTR OFF pin HIGH
digitalWrite(RS485_CTR, HIGH);
}
else {
Serial.println(F("[WiFi Manager]: Entering config portal."));
}
}
//read updated parameters
strcpy(blynk_template_id, custom_blynk_template_id.getValue());
strcpy(blynk_device_name, custom_blynk_device_name.getValue());
strcpy(blynk_auth_token, custom_blynk_auth_token.getValue());
strcpy(mqtt_server, custom_mqtt_server.getValue());
strcpy(mqtt_port, custom_mqtt_port.getValue());
strcpy(mqtt_username, custom_mqtt_username.getValue());
strcpy(mqtt_password, custom_mqtt_password.getValue());
strcpy(time_2_wifi, custom_time_2_wifi.getValue());
//save the custom parameters to FS
if (shouldSaveConfig) {
Serial.println(F("[SPIFFS] saving config"));
#if defined(ARDUINOJSON_VERSION_MAJOR) && ARDUINOJSON_VERSION_MAJOR >= 6
DynamicJsonDocument json(1024);
#else
DynamicJsonBuffer jsonBuffer;
JsonObject& json = jsonBuffer.createObject();
#endif
json["blynk_template_id"] = blynk_template_id;
json["blynk_device_name"] = blynk_device_name;
json["blynk_auth_token"] = blynk_auth_token;
json["mqtt_server"] = mqtt_server;
json["mqtt_port"] = mqtt_port;
json["mqtt_username"] = mqtt_username;
json["mqtt_password"] = mqtt_password;
json["time_2_wifi"] = time_2_wifi;
File configFile = SPIFFS.open("/config.json", "w");
if (!configFile) {
Serial.println(F("[SPIFFS] failed to open config file for writing"));
}
#if defined(ARDUINOJSON_VERSION_MAJOR) && ARDUINOJSON_VERSION_MAJOR >= 6
serializeJson(json, Serial);
serializeJson(json, configFile);
#else
json.printTo(Serial);
json.printTo(configFile);
#endif
configFile.close();
//end save
}
Serial.println(F("[SPIFFS] The values in the file are: "));
Serial.println("\blynk_template_id : " + String(blynk_template_id));
Serial.println("\blynk_device_name : " + String(blynk_device_name));
Serial.println("\tblynk_auth_token : " + String(blynk_auth_token));
Serial.println("\tmqtt_server : " + String(mqtt_server));
Serial.println("\tmqtt_port : " + String(mqtt_port));
Serial.println("\tmqtt_username : " + String(mqtt_username));
Serial.println("\ttime_2_wifi : " + String(time_2_wifi));
//Configure Blynk
Blynk.config(blynk_auth_token);
//Configure MQTT
client.setServer(mqtt_server,atoi(mqtt_port)); //Set the MQTT server as per parameter in config.h
client.setCallback(MQTTcallback); //Callback function
// Modbus slave ID 1
node.begin(1, Serial);
// Callbacks allow us to configure the RS485 transceiver correctly
node.preTransmission(preTransmission);
node.postTransmission(postTransmission);
// Setup a function to be called every second
timer.setInterval(1000L, myTimerEvent);
// Setup a function to be called every 4 second
timer.setInterval(4000L, timerSendRealtime);
// Setup a function to be called every 90 seconds
timer.setInterval(90000L, timerSendStatistics);
ticker.detach();
//keep LED off
digitalWrite(LED, HIGH);
// You can also call drd.stop() when you wish to no longer
// consider the next reset as a double reset.
drd.stop();
}
void loop()
{
//local variables
static int blynk_connect_attempts = 0;
// Call the double reset detector loop method every so often,
// so that it can recognise when the timeout expires.
drd.loop();
//Check if we connected to blynk if not try again only if we are connected to wifi
if(Blynk.connected() && WiFi.isConnected()){
Blynk.run();
}
else if(!Blynk.connected() && WiFi.isConnected())
{
Serial.print(F("[Blynk]: We are trying to connect to Blynk cloud server. Attempt: "));
Serial.print(String(blynk_connect_attempts));
Serial.println();
Blynk.connect();
blynk_connect_attempts++;
}
timer.run();
if (!client.connected() && WiFi.isConnected()) {
long now = millis();
if (now - lastReconnectAttempt > (MQTT_TIMEOUT*1000)) {
lastReconnectAttempt = now;
// Attempt to reconnect
if (reconnect()) {
lastReconnectAttempt = 0;
}
}
}
else if(client.connected() && WiFi.isConnected()){
client.loop();
}
}
Thanks