Hi i have some code for a danish ventilation system reading and writing modbus and with mqtt to Homeasistant the code works well also with w5500 ethernet but i would like to have ethernetmanager to setup mqtt credentials in captiveportal so i can compile and run my code and the ethernet manager but when i put all the code together i can compile but i get
Guru Meditation Error: Core 1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC : 0x400d6689 PS : 0x00060f30 A0 : 0x800d7260 A1 : 0x3ffb1700
A2 : 0x3ffc0b70 A3 : 0x00000000 A4 : 0x0000075b A5 : 0x00000010
A6 : 0x00000011 A7 : 0x00000000 A8 : 0x800f58d4 A9 : 0x3ffb1f20
A10 : 0x00000000 A11 : 0x3ffb1f7c A12 : 0x00000003 A13 : 0x00000000
A14 : 0x00000000 A15 : 0x00000008 SAR : 0x00000020 EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000010 LBEG : 0x400dad7c LEND : 0x400dadde LCOUNT : 0x00000002
Backtrace: 0x400d6689:0x3ffb1700 0x400d725d:0x3ffb1720 0x400dc2d9:0x3ffb1fb0 0x40088215:0x3ffb1fd0
/****************************************************************************************************************************
Ethernet_Generic.ino
For W5x00 and ENC28J60 Ethernet shields.
Ethernet_Manager is a library for nRF52, Teensy, STM32, SAM DUE and SAMD boards, with Ethernet W5x00 or ENC28J60 shields,
to enable easy configuration/reconfiguration of Credentials and autoconnect/autoreconnect of Ethernet.
AVR Mega is not supported.
Built by Khoi Hoang GitHub - khoih-prog/Ethernet_Manager: Simple Ethernet Manager for Teensy, SAM DUE, SAMD21, SAMD51, nRF52, ESP32, ESP8266, etc. boards, with or without SSL, configuration data saved in ESP8266 LittleFS, SPIFFS, nRF52 LittleFS/InternalFS, EEPROM, DueFlashStorage or SAMD FlashStorage.
Licensed under MIT license
VVersion: 1.3.0
Version Modified By Date Comments
1.0.0 K Hoang 14/12/2020 Initial coding.
1.1.0 K Hoang 17/12/2020 Add support to ESP32/ESP8266. Add MQTT related examples to demo dynamic parameter usage
1.1.1 K Hoang 28/12/2020 Suppress all possible compiler warnings
1.2.0 K Hoang 22/02/2021 Optimize code and use better FlashStorage_SAMD and FlashStorage_STM32.
Add customs HTML header feature. Fix bug.
1.3.0 K Hoang 16/05/2021 Add support to RP2040-based boards such as RASPBERRY_PI_PICO
*****************************************************************************************************************************/
#include "defines.h"
#include "Credentials.h"
#include "dynamicParams.h"
#include "HardwareSerial.h"
#include <ModbusMaster.h>
#include <PubSubClient.h>
#include <ArduinoJson.h>
#define HOST "NilanGW-%s" // Change this to whatever you like.
#define MAXREGSIZE 28
#define SENDINTERVAL 5000 // normally set to 180000 milliseconds = 3 minutes. Define as you like
#define VENTSET 1003
#define RUNSET 1001
#define MODESET 1002
#define TEMPSET 1004
#define SELECTSET 500
#define USERFUNCSET 601
#define USERVENTSET 603
#define USERTIMESET 602
#define USERTEMPSET 604
#define COOLVENT 1101
#define COOLSET 1200
#define TEMPSET_T11 1700
#define TEMPSET_T12 1701
char chipid[12];
EthernetServer server(80);
EthernetClient ethClient;
PubSubClient mqttclient(ethClient);
static long lastMsg = -SENDINTERVAL;
static int16_t rsbuffer[MAXREGSIZE];
ModbusMaster node;
char* usersetTopic1 = "ventilation/userset";
String req[4]; //operation, group, address, value
enum reqtypes
{
reqtemp = 0,
reqalarm,
reqtime,
reqcontrol,
reqspeed,
reqairtemp,
reqairflow,
reqairheat,
reqprogram,
requser,
requser2,
reqactstate,
reqinfo,
reqinputairtemp,
reqhotwater,
reqapp,
reqoutput,
reqdisplay1,
reqdisplay2,
reqdisplay,
reqmax
};
String groups[] = {"temp", "alarm", "time", "control", "speed", "airtemp", "airflow", "airheat", "program", "user", "user2", "actstate", "info", "inputairtemp", "hotwater", "app", "output", "display1", "display2", "display"};
byte regsizes[] = {23, 10, 6, 8, 2, 6, 2, 0, 1, 6, 6, 4, 14, 7, 2, 4, 28, 4, 4, 1};
int regaddresses[] = {200, 400, 300, 1000, 200, 1200, 1100, 0, 500, 600, 610, 1000, 100, 1200, 1700, 0, 100, 2002, 2007, 3000};
byte regtypes[] = {8, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 8, 1, 2, 1, 4, 4, 8};
char *regnames[][MAXREGSIZE] = {
//temp
{"T0_Controller", "T1_Intake", "T2_Inlet", "T3_Exhaust", "T4_Outlet", "T5_Cond", "T6_Evap", "T7_Inlet", "T8_Outdoor", "T9_Heater", "T10_Extern", "T11_Top", "T12_Bottom", "T13_Return", "T14_Supply", "T15_Room", "T16", "T17_PreHeat", "T18_PresPibe", "pSuc", "pDis", "RH", "CO2"},
//alarm
{"Status", "List_1_ID ", "List_1_Date", "List_1_Time", "List_2_ID ", "List_2_Date", "List_2_Time", "List_3_ID ", "List_3_Date", "List_3_Time"},
//time
{"Second", "Minute", "Hour", "Day", "Month", "Year"},
//control
{"Type", "RunSet", "ModeSet", "VentSet", "TempSet", "ServiceMode", "ServicePct", "Preset"},
//speed
{"ExhaustSpeed", "InletSpeed"},
//airtemp
{"CoolSet", "TempMinSum", "TempMinWin", "TempMaxSum", "TempMaxWin", "TempSummer"},
//airflow
{"AirExchMode", "CoolVent"},
//airheat
{},
//program
{"Selectset"},
//program.user
{"UserFuncAct", "UserFuncSet", "UserTimeSet", "UserVentSet", "UserTempSet", "UserOffsSet"},
//program.user2
{"User2FuncAct", "User2FuncSet", "User2TimeSet", "User2VentSet", "UserTempSet", "UserOffsSet"},
//actstate
{"RunAct", "ModeAct", "State", "SecInState"},
//info
{"UserFunc", "AirFilter", "DoorOpen", "Smoke", "MotorThermo", "Frost_overht", "AirFlow", "P_Hi", "P_Lo", "Boil", "3WayPos", "DefrostHG", "Defrost", "UserFunc_2"},
//inputairtemp
{"IsSummer", "TempInletSet", "TempControl", "TempRoom", "EffPct", "CapSet", "CapAct"},
//hotwatertemp
{"TempSet_T11", "TempSet_T12"},
//app
{"Bus.Version", "VersionMajor", "VersionMinor", "VersionRelease"},
//output
{"AirFlap", "SmokeFlap", "BypassOpen", "BypassClose", "AirCircPump", "AirHeatAllow", "AirHeat_1", "AirHeat_2", "AirHeat_3", "Compressor", "Compressor_2", "4WayCool", "HotGasHeat", "HotGasCool", "CondOpen", "CondClose", "WaterHeat", "3WayValve", "CenCircPump", "CenHeat_1", "CenHeat_2", "CenHeat_3", "CenHeatExt", "UserFunc", "UserFunc_2", "Defrosting", "AlarmRelay", "PreHeat"},
//display1
{"Text_1_2", "Text_3_4", "Text_5_6", "Text_7_8"},
//display2
{"Text_9_10", "Text_11_12", "Text_13_14", "Text_15_16"},
//airbypass
{"AirBypass/IsOpen"}};
char *getName(reqtypes type, int address)
{
if (address >= 0 && address <= regsizes[type])
{
return regnames[type][address];
}
return NULL;
}
JsonObject HandleRequest(JsonDocument& doc)
{
JsonObject root = doc.to();
reqtypes r = reqmax;
char type = 0;
if (req[1] != "")
{
for (int i = 0; i < reqmax; i++)
{
if (groups[i] == req[1])
{
r = (reqtypes)i;
}
}
}
type = regtypes[r];
if (req[0] == "read")
{
int address = 0;
int nums = 0;
char result = -1;
address = regaddresses[r];
nums = regsizes[r];
result = ReadModbus(address, nums, rsbuffer, type & 1);
if (result == 0)
{
root["status"] = "Modbus connection OK";
for (int i = 0; i < nums; i++)
{
char *name = getName(r, i);
if (name != NULL && strlen(name) > 0)
{
if ((type & 2 && i > 0) || type & 4)
{
String str = "";
str += (char)(rsbuffer[i] & 0x00ff);
str += (char)(rsbuffer[i] >> 8);
root[name] = str;
}
else if (type & 8)
{
root[name] = rsbuffer[i] / 100.0;
}
else
{
root[name] = rsbuffer[i];
}
}
}
}
else
{
root["status"] = "Modbus connection failed";
}
root["requestaddress"] = address;
root["requestnum"] = nums;
}
if (req[0] == "set" && req[2] != "" && req[3] != "")
{
int address = atoi(req[2].c_str());
int value = atoi(req[3].c_str());
char result = WriteModbus(address, value);
root["result"] = result;
root["address"] = address;
root["value"] = value;
}
if (req[0] == "help")
{
for (int i = 0; i < reqmax; i++)
{
root[groups[i]] = 0;
}
}
root["operation"] = req[0];
root["group"] = req[1];
return root;
}
Ethernet_Manager ethernet_manager;
IPAddress localEthernetIP;
// Use to detect W5100 shield. The linkStatus() is not working with W5100, only W5200 and W5500
// To check if W5100 using Ethernet and EthernetLarge libraries
bool isW5500 = true;
void heartBeatPrint()
{
static int num = 1;
static int linkStatus = 0;
localEthernetIP = Ethernet.localIP();
#if ( (USE_ETHERNET2 || USE_ETHERNET3) && !(USE_NATIVE_ETHERNET) )
// To modify Ethernet2 library
linkStatus = Ethernet.link();
ET_LOGINFO3("localEthernetIP = ", localEthernetIP, ", linkStatus = ", (linkStatus == 1) ? "LinkON" : "LinkOFF" );
if ( ( linkStatus == 1 ) && ((uint32_t) localEthernetIP != 0) )
#else
// The linkStatus() is not working with W5100. Just using IP != 0.0.0.0
// Better to use ping for W5100
linkStatus = (int) Ethernet.linkStatus();
ET_LOGINFO3("localEthernetIP = ", localEthernetIP, ", linkStatus = ", (linkStatus == LinkON) ? "LinkON" : "LinkOFF" );
if ( ( (linkStatus == LinkON) || !isW5500 ) && ((uint32_t) localEthernetIP != 0) )
#endif
{
Serial.print(F("H"));
}
else
Serial.print(F("F"));
if (num == 40)
{
Serial.println();
num = 1;
}
else if (num++ % 10 == 0)
{
Serial.print(F(" "));
}
}
void check_status()
{
#define STATUS_CHECK_INTERVAL 10000L
static unsigned long checkstatus_timeout = STATUS_CHECK_INTERVAL;
// Send status report every STATUS_REPORT_INTERVAL (60) seconds: we don't need to send updates frequently if there is no status change.
if ((millis() > checkstatus_timeout))
{
heartBeatPrint();
checkstatus_timeout = millis() + STATUS_CHECK_INTERVAL;
}
}
#if USING_CUSTOMS_STYLE
const char NewCustomsStyle[] /PROGMEM/ = "div,input{padding:5px;font-size:1em;}input{width:95%;}body{text-align: center;}
button{background-color:blue;color:white;line-height:2.4rem;font-size:1.2rem;width:100%;}fieldset{border-radius:0.3rem;margin:0px;}";
#endif
void setup()
{
pinMode(2, OUTPUT);
pinMode(13, OUTPUT);
pinMode(14, OUTPUT);
Serial.begin(115200);
Serial.println();
//uint8_t chipid[6];
//esp_efuse_read_mac(chipid);
//Serial.printf("%X\n",chipid);
while (!Serial);
delay(200);
Serial2.begin(19200, SERIAL_8E1);
node.begin(30, Serial2);
node.clearResponseBuffer();
node.clearTransmitBuffer();
server.begin();
mqttclient.setServer(MQTT_Server, 1883);
mqttclient.setCallback(mqttcallback);
}
void mqttcallback(char *topic, byte *payload, unsigned int length)
{
if (strcmp(topic, "ventilation/ventset") == 0)
{
if (length == 1 && payload[0] >= '0' && payload[0] <= '4')
{
int16_t speed = payload[0] - '0';
WriteModbus(VENTSET, speed);
}
}
if (strcmp(topic, "ventilation/modeset") == 0)
{
if (length == 1 && payload[0] >= '0' && payload[0] <= '4')
{
int16_t mode = payload[0] - '0';
WriteModbus(MODESET, mode);
}
}
if (strcmp(topic, "ventilation/runset") == 0)
{
if (length == 1 && payload[0] >= '0' && payload[0] <= '1')
{
int16_t run = payload[0] - '0';
WriteModbus(RUNSET, run);
}
}
if (strcmp(topic, "ventilation/userset") == 0)
{
if (payload[0] == '1')
{
digitalWrite(4, HIGH);
digitalWrite(25, HIGH);
mqttclient.publish("ventilation/userset", "on");
}
else if (payload[0] == '0')
{
digitalWrite(4, LOW);
digitalWrite(25, LOW);
mqttclient.publish("ventilation/userset", "off");
}
}
if (strcmp(topic, "ventilation/userfuncset") == 0)
{
if (length == 1 && payload[0] >= '0' && payload[0] <= '4')
{
int16_t select = payload[0] - '0';
WriteModbus(USERFUNCSET, select);
}
}
if (strcmp(topic, "ventilation/userventset") == 0)
{
if (length == 1 && payload[0] >= '0' && payload[0] <= '4')
{
int16_t vent = payload[0] - '0';
WriteModbus(USERVENTSET, vent);
}
}
if (strcmp(topic, "ventilation/coolvent") == 0)
{
if (length == 1 && payload[0] >= '0' && payload[0] <= '4')
{
int16_t airflow = payload[0] - '0';
WriteModbus(COOLVENT, airflow);
}
}
if (strcmp(topic, "ventilation/coolset") == 0)
{
if (length == 1 && payload[0] >= '0' && payload[0] <= '8')
{
int16_t airtemp = payload[0] - '0';
WriteModbus(COOLSET, airtemp);
}
}
if (strcmp(topic, "ventilation/usertimeset") == 0)
{
if (length == 3 && payload[0] >= '0' && payload[0] <= '8')
{
String str;
for (int i = 0; i < length; i++)
{
str += (char)payload[i];
}
WriteModbus(USERTIMESET, str.toInt());
}
}
if (strcmp(topic, "ventilation/usertempset") == 0)
{
if (length == 2 && payload[0] >= '0' && payload[0] <= '2')
{
String str;
for (int i = 0; i < length; i++)
{
str += (char)payload[i];
}
WriteModbus(USERTEMPSET, str.toInt());
}
}
if (strcmp(topic, "ventilation/tempset") == 0)
{
if (length == 4 && payload[0] >= '0' && payload[0] <= '2')
{
String str;
for (int i = 0; i < length; i++)
{
str += (char)payload[i];
}
WriteModbus(TEMPSET, str.toInt());
}
}
if (strcmp(topic, "ventilation/tempset_T11") == 0)
{
if (length == 4 && payload[0] >= '0' && payload[0] <= '6')
{
String str;
for (int i = 0; i < length; i++)
{
str += (char)payload[i];
}
WriteModbus(TEMPSET_T11, str.toInt());
}
}
if (strcmp(topic, "ventilation/tempset_T12") == 0)
{
if (length == 4 && payload[0] >= '0' && payload[0] <= '6')
{
String str;
for (int i = 0; i < length; i++)
{
str += (char)payload[i];
}
WriteModbus(TEMPSET_T12, str.toInt());
}
}
if (strcmp(topic, "ventilation/selectset") == 0)
{
if (length == 1 && payload[0] >= '0' && payload[0] <= '4')
{
int16_t select = payload[0] - '0';
WriteModbus(SELECTSET, select);
}
}
lastMsg = -SENDINTERVAL;
}
bool readRequest(EthernetClient ðClient)
{
req[0] = "";
req[1] = "";
req[2] = "";
req[3] = "";
int n = -1;
bool readstring = false;
while (ethClient.connected())
{
if (ethClient.available())
{
char c = ethClient.read();
if (c == '\n')
{
return false;
}
else if (c == '/')
{
n++;
}
else if (c != ' ' && n >= 0 && n < 4)
{
req[n] += c;
}
else if (c == ' ' && n >= 0 && n < 4)
{
return true;
}
}
}
return false;
}
void writeResponse(EthernetClient& ethClient, const JsonDocument& doc)
{
ethClient.println("HTTP/1.1 200 OK");
ethClient.println("Content-Type: application/json");
ethClient.println("Connection: close");
ethClient.println();
serializeJsonPretty(doc,ethClient);
}
char ReadModbus(uint16_t addr, uint8_t sizer, int16_t *vals, int type)
{
char result = 0;
switch (type)
{
case 0:
result = node.readInputRegisters(addr, sizer);
break;
case 1:
result = node.readHoldingRegisters(addr, sizer);
break;
}
if (result == node.ku8MBSuccess)
{
for (int j = 0; j < sizer; j++)
{
vals[j] = node.getResponseBuffer(j);
}
return result;
}
return result;
}
char WriteModbus(uint16_t addr, int16_t val)
{
node.setTransmitBuffer(0, val);
char result = 0;
result = node.writeMultipleRegisters(addr, 1);
if (result == node.ku8MBSuccess)
{
Serial.println("Write OK");
}
else
{
Serial.println("Write NOT OK");
Serial.println("Clear bufs");
node.clearResponseBuffer();
node.clearTransmitBuffer();
}
return result;
}
void mqttreconnect()
{
int numretries = 0;
while (!mqttclient.connected() && numretries < 3)
{
if (mqttclient.connect(chipid, MQTT_UserName, MQTT_PW))
{
digitalWrite(13, 1);
mqttclient.subscribe("ventilation/ventset");
mqttclient.subscribe("ventilation/modeset");
mqttclient.subscribe("ventilation/runset");
mqttclient.subscribe("ventilation/tempset");
mqttclient.subscribe("ventilation/selectset");
mqttclient.subscribe("ventilation/tempset_T11");
mqttclient.subscribe("ventilation/tempset_T12");
mqttclient.subscribe("ventilation/userset");
mqttclient.subscribe("ventilation/userfuncset");
mqttclient.subscribe("ventilation/userventset");
mqttclient.subscribe("ventilation/usertimeset");
mqttclient.subscribe("ventilation/usertempset");
mqttclient.subscribe("ventilation/coolvent");
mqttclient.subscribe("ventilation/coolset");
}
else
{
digitalWrite(13, 0);
delay(1000);
numretries++;
}
}
#if ( USE_LITTLEFS || USE_SPIFFS )
Serial.println("\nStart Ethernet_Generic using " + String(CurrentFileFS) + " on " + String(BOARD_NAME));
#else
Serial.println("\nStart Ethernet_Generic on " + String(BOARD_NAME));
#endif
Serial.println("Ethernet Shield type : " + String(SHIELD_TYPE));
Serial.println(ETHERNET_MANAGER_VERSION);
#if (ESP32 || ESP8266)
Serial.println(ESP_DOUBLE_RESET_DETECTOR_VERSION);
#else
Serial.println(DOUBLERESETDETECTOR_GENERIC_VERSION);
#endif
pinMode(SDCARD_CS, OUTPUT);
digitalWrite(SDCARD_CS, HIGH); // Deselect the SD card
#if USE_ETHERNET_WRAPPER
EthernetInit();
#else
#if ( defined(USE_UIP_ETHERNET) && USE_UIP_ETHERNET )
ET_LOGWARN(F("======== USE_UIP_ETHERNET ========"));
#elif USE_NATIVE_ETHERNET
ET_LOGWARN(F("======== USE_NATIVE_ETHERNET ========"));
#elif USE_ETHERNET
ET_LOGWARN(F("=========== USE_ETHERNET ==========="));
#elif USE_ETHERNET2
ET_LOGWARN(F("=========== USE_ETHERNET2 ==========="));
#elif USE_ETHERNET3
ET_LOGWARN(F("=========== USE_ETHERNET3 ==========="));
#elif USE_ETHERNET_LARGE
ET_LOGWARN(F("=========== USE_ETHERNET_LARGE ==========="));
#elif USE_ETHERNET_ESP8266
ET_LOGWARN(F("=========== USE_ETHERNET_ESP8266 ==========="));
#elif USE_ETHERNET_ENC
ET_LOGWARN(F("=========== USE_ETHERNET_ENC ==========="));
#else
ET_LOGWARN(F("========================="));
#endif
ET_LOGWARN(F("Default SPI pinout:"));
ET_LOGWARN1(F("MOSI:"), MOSI);
ET_LOGWARN1(F("MISO:"), MISO);
ET_LOGWARN1(F("SCK:"), SCK);
ET_LOGWARN1(F("SS:"), SS);
ET_LOGWARN(F("========================="));
#if defined(ESP8266)
#define PIN_D5 14 // Pin D5 mapped to pin GPIO14/HSCLK of ESP8266
#define PIN_D6 12 // Pin D6 mapped to pin GPIO12/HMISO of ESP8266
#define PIN_D7 13 // Pin D7 mapped to pin GPIO13/RXD2/HMOSI of ESP8266
// Connection for ESP8266
// MOSI: D7/GPIO13, MISO: D6/GPIO12, SCK: D5/GPIO14, CS/SS: D2/GPIO4
// For ESP8266, change for other boards if necessary
#ifndef USE_THIS_SS_PIN
#define USE_THIS_SS_PIN D2 // For ESP8266
#endif
ET_LOGWARN1(F("ESP8266 setCsPin:"), USE_THIS_SS_PIN);
#if ( USE_ETHERNET || USE_ETHERNET_LARGE || USE_ETHERNET2 || USE_ETHERNET_ENC )
// For ESP8266
// Pin D0(GPIO16) D1(GPIO5) D2(GPIO4) D3(GPIO0) D4(GPIO2) D8
// Ethernet 0 X X X X 0
// Ethernet2 X X X X X 0
// Ethernet3 X X X X X 0
// EthernetLarge X X X X X 0
// Ethernet_ESP8266 0 0 0 0 0 0
// D2 is safe to used for Ethernet, Ethernet2, Ethernet3, EthernetLarge libs
// Must use library patch for Ethernet, EthernetLarge libraries
Ethernet.init (5);
#elif USE_ETHERNET3
// Use MAX_SOCK_NUM = 4 for 4K, 2 for 8K, 1 for 16K RX/TX buffer
#ifndef ETHERNET3_MAX_SOCK_NUM
#define ETHERNET3_MAX_SOCK_NUM 4
#endif
Ethernet.setCsPin (USE_THIS_SS_PIN);
Ethernet.init (ETHERNET3_MAX_SOCK_NUM);
#elif USE_CUSTOM_ETHERNET
// You have to add initialization for your Custom Ethernet here
// This is just an example to setCSPin to USE_THIS_SS_PIN, and can be not correct and enough
Ethernet.init(5);
#endif //( USE_ETHERNET || USE_ETHERNET2 || USE_ETHERNET3 || USE_ETHERNET_LARGE )
#elif defined(ESP32)
#define PIN_D18 18 // Pin D18 mapped to pin GPIO18/VSPI_SCK of ESP32
#define PIN_D19 19 // Pin D19 mapped to pin GPIO19/VSPI_MISO of ESP32
#define PIN_D23 23 // Pin D23 mapped to pin GPIO23/VSPI_MOSI of ESP32
// You can use Ethernet.init(pin) to configure the CS pin
//Ethernet.init(10); // Most Arduino shields
Ethernet.init(5); // MKR ETH shield
//Ethernet.init(0); // Teensy 2.0
//Ethernet.init(20); // Teensy++ 2.0
//Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet
//Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet
// Connection for ESP32
// MOSI: GPIO23, MISOP: GPIO19, SCK: GPIO18, CS/SS: GPIO22
#ifndef USE_THIS_SS_PIN
#define USING_M5STACK_W5500 false
#if USING_M5STACK_W5500
#warning Using M5Stack_Core_ESP32 with W5500 mudule
#define USE_THIS_SS_PIN 26 // For M5Stack_Core_ESP32 with W5500 mudule
#else
#define USE_THIS_SS_PIN 27 //22 // For ESP32
#endif
#endif
ET_LOGWARN1(F("ESP32 setCsPin:"), USE_THIS_SS_PIN);
// For other boards, to change if necessary
#if ( USE_ETHERNET || USE_ETHERNET_LARGE || USE_ETHERNET2 || USE_ETHERNET_ENC )
// Must use library patch for Ethernet, EthernetLarge libraries
// ESP32 => GPIO2,4,5,13,15,21,22 OK with Ethernet, Ethernet2, EthernetLarge
// ESP32 => GPIO2,4,5,15,21,22 OK with Ethernet3
//Ethernet.setCsPin (USE_THIS_SS_PIN);
Ethernet.init (5);
#elif USE_ETHERNET3
// Use MAX_SOCK_NUM = 4 for 4K, 2 for 8K, 1 for 16K RX/TX buffer
#ifndef ETHERNET3_MAX_SOCK_NUM
#define ETHERNET3_MAX_SOCK_NUM 4
#endif
Ethernet.setCsPin (USE_THIS_SS_PIN);
Ethernet.init (ETHERNET3_MAX_SOCK_NUM);
#elif USE_CUSTOM_ETHERNET
// You have to add initialization for your Custom Ethernet here
// This is just an example to setCSPin to USE_THIS_SS_PIN, and can be not correct and enough
Ethernet.init(5);
#endif //( USE_ETHERNET || USE_ETHERNET2 || USE_ETHERNET3 || USE_ETHERNET_LARGE )
#else //defined(ESP8266)
// unknown board, do nothing, use default SS = 10
#ifndef USE_THIS_SS_PIN
#define USE_THIS_SS_PIN 10 // For other boards
#endif
#if defined(BOARD_NAME)
ET_LOGWARN3(F("Board :"), BOARD_NAME, F(", setCsPin:"), USE_THIS_SS_PIN);
#else
ET_LOGWARN1(F("Unknown board setCsPin:"), USE_THIS_SS_PIN);
#endif
// For other boards, to change if necessary
#if ( USE_ETHERNET || USE_ETHERNET_LARGE || USE_ETHERNET2 || USE_ETHERNET_ENC || USE_NATIVE_ETHERNET )
// Must use library patch for Ethernet, Ethernet2, EthernetLarge libraries
Ethernet.init (5);
#elif USE_ETHERNET3
// Use MAX_SOCK_NUM = 4 for 4K, 2 for 8K, 1 for 16K RX/TX buffer
#ifndef ETHERNET3_MAX_SOCK_NUM
#define ETHERNET3_MAX_SOCK_NUM 4
#endif
Ethernet.setCsPin (USE_THIS_SS_PIN);
Ethernet.init (ETHERNET3_MAX_SOCK_NUM);
#elif USE_CUSTOM_ETHERNET
// You have to add initialization for your Custom Ethernet here
// This is just an example to setCSPin to USE_THIS_SS_PIN, and can be not correct and enough
Ethernet.init(5);
#endif //( USE_ETHERNET || USE_ETHERNET2 || USE_ETHERNET3 || USE_ETHERNET_LARGE )
#endif //defined(ESP8266)
#endif //USE_ETHERNET_WRAPPER
// Just info to know how to connect correctly
Serial.println(F("========================="));
Serial.println(F("Currently Used SPI pinout:"));
Serial.print(F("MOSI:"));
Serial.println(MOSI);
Serial.print(F("MISO:"));
Serial.println(MISO);
Serial.print(F("SCK:"));
Serial.println(SCK);
Serial.print(F("SS:"));
Serial.println(SS);
#if USE_ETHERNET3
Serial.print(F("SPI_CS:"));
Serial.println(SPI_CS);
#endif
Serial.println(F("========================="));
//////////////////////////////////////////////
#if USING_CUSTOMS_STYLE
ethernet_manager.setCustomsStyle(NewCustomsStyle);
#endif
#if USING_CUSTOMS_HEAD_ELEMENT
ethernet_manager.setCustomsHeadElement("html{filter: invert(10%);}");
#endif
#if USING_CORS_FEATURE
ethernet_manager.setCORSHeader("Your Access-Control-Allow-Origin");
#endif
ethernet_manager.begin();
//////////////////////////////////////////////
localEthernetIP = Ethernet.localIP();
#if (USE_ETHERNET2 || USE_ETHERNET3)
// To modify Ethernet2 library
if ( (uint32_t) localEthernetIP != 0 )
#else
if ( (uint32_t) localEthernetIP != 0 )
#endif
{
Serial.print(F("Connected! IP address: "));
Serial.println(localEthernetIP);
}
else
{
Serial.println(F("Ethernet not Connected! Please check."));
}
// Detect W5100 only in Ethernet and EthernetLarge libraries
#if ( USE_ETHERNET || USE_ETHERNET_LARGE)
isW5500 = (Ethernet.hardwareStatus() == EthernetW5500);
Serial.print(F("Ethernet type is "));
Serial.println(isW5500 ? "W5500" : "W5100");
#endif
}
#if (USE_DYNAMIC_PARAMETERS)
void displayCredentials()
{
Serial.println("\nYour stored Credentials :");
for (int i = 0; i < NUM_MENU_ITEMS; i++)
{
Serial.println(String(myMenuItems[i].displayName) + " = " + myMenuItems[i].pdata);
}
}
void displayCredentialsOnce()
{
static bool displayedCredentials = false;
if (!displayedCredentials)
{
for (int i = 0; i < NUM_MENU_ITEMS; i++)
{
if (!strlen(myMenuItems[i].pdata))
{
break;
}
if ( i == (NUM_MENU_ITEMS - 1) )
{
displayedCredentials = true;
displayCredentials();
}
}
}
}
#endif
void loop()
{
ethernet_manager.run();
check_status();
#if (USE_DYNAMIC_PARAMETERS)
displayCredentialsOnce();
#endif
{
EthernetClient ethClient = server.available();
if (ethClient)
{
bool success = readRequest(ethClient);
if (success)
{
StaticJsonDocument<2000> doc;
HandleRequest(doc);
writeResponse(ethClient, doc);
}
ethClient.stop();
}
if (!mqttclient.connected())
{
mqttreconnect();
}
if (mqttclient.connected())
{
mqttclient.loop();
long now = millis();
if (now - lastMsg > SENDINTERVAL)
{
reqtypes rr[] = {reqtemp, reqcontrol, reqtime, reqoutput, reqspeed, reqairtemp, reqalarm, reqinputairtemp, reqhotwater, reqprogram, requser, reqdisplay, reqactstate, reqinfo, reqairflow}; // put another register in this line to subscribe
for (int i = 0; i < (sizeof(rr)/sizeof(rr[0])); i++)
{
reqtypes r = rr[i];
char result = ReadModbus(regaddresses[r], regsizes[r], rsbuffer, regtypes[r] & 1);
if (result == 0)
{
mqttclient.publish("ventilation/error/modbus/", "0"); //no error when connecting through modbus
for (int i = 0; i < regsizes[r]; i++)
{
char *name = getName(r, i);
char numstr[8];
if (name != NULL && strlen(name) > 0)
{
String mqname = "temp/";
switch (r)
{
case reqcontrol:
mqname = "ventilation/control/"; // Subscribe to the "control" register
itoa((rsbuffer[i]), numstr, 10);
break;
case reqtime:
mqname = "ventilation/time/"; // Subscribe to the "output" register
itoa((rsbuffer[i]), numstr, 10);
break;
case reqoutput:
mqname = "ventilation/output/"; // Subscribe to the "output" register
itoa((rsbuffer[i]), numstr, 10);
break;
case reqdisplay:
mqname = "ventilation/display/"; // Subscribe to the "input display" register
itoa((rsbuffer[i]), numstr, 10);
break;
case reqspeed:
mqname = "ventilation/speed/"; // Subscribe to the "speed" register
itoa((rsbuffer[i]), numstr, 10);
break;
case reqairtemp:
mqname = "ventilation/airtemp/"; // Subscribe to the "airtemp" register
itoa((rsbuffer[i]), numstr, 10);
break;
case reqalarm:
mqname = "ventilation/alarm/"; // Subscribe to the "alarm" register
itoa((rsbuffer[i]), numstr, 10);
break;
case reqinputairtemp:
mqname = "ventilation/inputairtemp/"; // Subscribe to the "inputairtemp" register
itoa((rsbuffer[i]), numstr, 10);
break;
case reqhotwater:
mqname = "ventilation/hotwater/"; // Subscribe to the "Hotwater" register
itoa((rsbuffer[i]), numstr, 10);
break;
case reqprogram:
mqname = "ventilation/program/"; // Subscribe to the "program" register
itoa((rsbuffer[i]), numstr, 10);
break;
case requser:
mqname = "ventilation/user/"; // Subscribe to the "user" register
itoa((rsbuffer[i]), numstr, 10);
break;
case reqactstate:
mqname = "ventilation/actstate/"; // Subscribe to the "controlact" register
itoa((rsbuffer[i]), numstr, 10);
break;
case reqinfo:
mqname = "ventilation/info/"; // Subscribe to the "info" register
itoa((rsbuffer[i]), numstr, 10);
break;
case reqairflow:
mqname = "ventilation/airflow/"; // Subscribe to the "airflow" register
itoa((rsbuffer[i]), numstr, 10);
break;
case reqtemp:
if (strncmp("RH", name, 2) == 0) {
mqname = "ventilation/moist/"; // Subscribe to moisture-level
} else {
mqname = "ventilation/temp/"; // Subscribe to "temp" register
}
dtostrf((rsbuffer[i] / 100.0), 5, 2, numstr);
break;
}
mqname += (char *)name;
mqttclient.publish(mqname.c_str(), numstr);
}
}
}
else {
mqttclient.publish("ventilation/error/modbus/", "1"); //error when connecting through modbus
}
}
// Handle text fields
reqtypes rr2[] = {reqdisplay1, reqdisplay2}; // put another register in this line to subscribe
for (int i = 0; i < (sizeof(rr2)/sizeof(rr2[0])); i++) // change value "5" to how many registers you want to subscribe to
{
reqtypes r = rr2[i];
char result = ReadModbus(regaddresses[r], regsizes[r], rsbuffer, regtypes[r] & 1);
if (result == 0)
{
String text = "";
String mqname = "ventilation/text/";
for (int i = 0; i < regsizes[r]; i++)
{
char *name = getName(r, i);
if ((rsbuffer[i] & 0x00ff) == 0xDF) {
text += (char)0x20; // replace degree sign with space
} else {
text += (char)(rsbuffer[i] & 0x00ff);
}
if ((rsbuffer[i] >> 8) == 0xDF) {
text += (char)0x20; // replace degree sign with space
} else {
text += (char)(rsbuffer[i] >> 8);
}
mqname += (char *)name;
}
mqttclient.publish(mqname.c_str(), text.c_str());
}
}
lastMsg = now;
}
}
}
}