I use Serial
communication to interface our device with inverter so for “debug” we are using the secondary UART offered by WeMos D1 mini, you can find deteiled information in my article “WeMos D1 mini (esp8266), debug on secondary UART“.
You can find WeMos D1 mini to WeMos D1 mini - NodeMCU V2 V2.1 V3 - esp01 - esp01 programmer
So in the board I add a pin to this, you can use standard CH340G Module to interface to It,
You can find the correct USB to TTL to USB to TTL CH340G - USB to TTL FT232RL
and you must check that debug is enable in the code.
// Uncomment to enable printing out nice debug messages.
#define AURORA_SERVER_DEBUG
// Define where debug output will be printed.
#define DEBUG_PRINTER Serial1
// Setup debug printing macros.
#ifdef AURORA_SERVER_DEBUG
#define DEBUG_PRINT(...) { DEBUG_PRINTER.print(__VA_ARGS__); }
#define DEBUG_PRINTLN(...) { DEBUG_PRINTER.println(__VA_ARGS__); }
#else
#define DEBUG_PRINT(...) {}
#define DEBUG_PRINTLN(...) {}
#endif
With this system you can grab the ip given from DHCP, (you can use a network sniffer also). If you want I expose i2c pin also, so you can attach a screen where to show IP or other information.
Notifications
For notification system I use my library created to send email, It’s simple configurable and rapid to use.
For the library you can refer to my article “Send email with attachments“, where I explain better the library usage.
I’m going to store the parameter in a config file inside the SPIFFS (I hope that this file change very few times), first you must configure your SMTP server.
Than I’m going to manage all 4 types of alarm that are generated from Inverter.
You can configure a different set of notifications for each actor and remember that you probably haven’t linked all channels, so be careful to disable the configuration for the unused channel.
You can specify the settings for every email, and you can select to send email every time there is a change or only when something goes wrong.
You can do this for every unit monitored:
- Alarm: when an alarm is returned
- State: when the state of the grid is changed
- Channels: when a change is occurred on a specified channel.
Here a piece of configuration file.
"emailNotification": {
"isNotificationEnabled": true,
"subject": "Notifica inverter",
"messageProblem": "Un problema è stato rilevato sull'inverter:",
"messageNoProblem": "E' stato ripristinato lo stato del tuo inverter:",
"emailList": [
{
"email": "renzo.mischianti@gmail.com",
"name": "Renzo Mischianti",
"alarm": "on_problem",
"ch1": "on_problem",
"ch2": "none",
"state": "on_problem"
}
]
},
In this piece of code It manage the sending of the alert email by reading the configuration file:
DEBUG_PRINT(F("MEM "));
DEBUG_PRINTLN(ESP.getFreeHeap());
if (lds.needNotify){
DEBUG_PRINT(F("Open config file..."));
fs::File configFile = SPIFFS.open(F("/mc/config.txt"), "r");
if (configFile) {
DEBUG_PRINTLN(F("done."));
DynamicJsonDocument doc(CONFIG_FILE_HEAP);
DeserializationError error = deserializeJson(doc, configFile);
if (error) {
// if the file didn't open, print an error:
DEBUG_PRINT(F("Error parsing JSON "));
DEBUG_PRINTLN(error.c_str());
}
// close the file:
configFile.close();
DEBUG_PRINT(F("MEM "));
DEBUG_PRINTLN(ESP.getFreeHeap());
JsonObject rootObj = doc.as<JsonObject>();
DEBUG_PRINT(F("After read config check serverSMTP and emailNotification "));
DEBUG_PRINTLN(rootObj.containsKey(F("serverSMTP")) && rootObj.containsKey(F("emailNotification")));
if (rootObj.containsKey(F("serverSMTP")) && rootObj.containsKey(F("emailNotification"))){
// JsonObject serverConfig = rootObj["server"];
JsonObject serverSMTP = rootObj[F("serverSMTP")];
JsonObject emailNotification = rootObj[F("emailNotification")];
bool isNotificationEnabled = (emailNotification.containsKey(F("isNotificationEnabled")))?emailNotification[F("isNotificationEnabled")]:false;
DEBUG_PRINT(F("isNotificationEnabled "));
DEBUG_PRINTLN(isNotificationEnabled);
if (isNotificationEnabled){
const char* serverSMTPAddr = serverSMTP[F("server")];
emailSend.setSMTPServer(serverSMTPAddr);
uint16_t portSMTP = serverSMTP[F("port")];
emailSend.setSMTPPort(portSMTP);
const char* loginSMTP = serverSMTP[F("login")];
emailSend.setEMailLogin(loginSMTP);
const char* passwordSMTP = serverSMTP[F("password")];
emailSend.setEMailPassword(passwordSMTP);
const char* fromSMTP = serverSMTP[F("from")];
emailSend.setEMailFrom(fromSMTP);
DEBUG_PRINT(F("server "));
DEBUG_PRINTLN(serverSMTPAddr);
DEBUG_PRINT(F("port "));
DEBUG_PRINTLN(portSMTP);
DEBUG_PRINT(F("login "));
DEBUG_PRINTLN(loginSMTP);
DEBUG_PRINT(F("password "));
DEBUG_PRINTLN(passwordSMTP);
DEBUG_PRINT(F("from "));
DEBUG_PRINTLN(fromSMTP);
EMailSender::EMailMessage message;
const String sub = emailNotification[F("subject")];
message.subject = sub;
JsonArray emailList = emailNotification[F("emailList")];
DEBUG_PRINT(F("Email list "));
for (uint8_t i=0; i<emailList.size(); i++){
JsonObject emailElem = emailList[i];
// byte asp = lastData[F("asp")];
// byte c1sp = lastData[F("c1sp")];
// byte c2sp = lastData[F("c2sp")];
// byte isp = lastData[F("isp")];
const String alarm = emailElem[F("alarm")];
const String ch1 = emailElem[F("ch1")];
const String ch2 = emailElem[F("ch2")];
const String state = emailElem[F("state")];
DEBUG_PRINT(F("State value "));
DEBUG_PRINTLN(state);
DEBUG_PRINT(F("State value on_problem comparison "));
DEBUG_PRINTLN(state==F("on_problem"));
DEBUG_PRINT(F("Alarm value "));
DEBUG_PRINTLN(alarm);
DEBUG_PRINT(F("Alarm all comparison "));
DEBUG_PRINTLN(alarm==F("all"));
bool allNotification = (
(alarm==F("all") && lds.asp != dataState.alarmState)
||
(ch1==F("all") && lds.c1sp != dataState.channel1State)
||
(ch2==F("all") && lds.c2sp != dataState.channel2State)
||
(state==F("all") && lds.isp != dataState.inverterState)
);
bool onProblem = (
(alarm==F("on_problem") && dataState.alarmState > 0)
||
(ch1==F("on_problem") && dataState.channel1State != 2)
||
(ch2==F("on_problem") && dataState.channel1State != 2)
||
(state==F("on_problem") && (dataState.inverterState != 2 && dataState.inverterState != 1))
);
DEBUG_PRINT(F("Check allNotification "));
DEBUG_PRINTLN(allNotification);
DEBUG_PRINT(F("Check onProblem "));
DEBUG_PRINTLN(onProblem);
DEBUG_PRINT(F("MEM "));
DEBUG_PRINTLN(ESP.getFreeHeap());
if (
allNotification
||
onProblem
){
const String mp = emailNotification[F("messageProblem")];
const String mnp = emailNotification[F("messageNoProblem")];
message.message = ((lds.inverterProblem)?mp:mnp)+
F("<br>Alarm: ")+dataState.getAlarmState()+
F("<br>CH1: ")+dataState.getDcDcChannel1State() +
F("<br>CH2: ")+dataState.getDcDcChannel2State()+
F("<br>Stato: ")+dataState.getInverterState();
EMailSender::Response resp = emailSend.send(emailElem[F("email")], message);
DEBUG_PRINTLN(F("Sending status: "));
const String em = emailElem[F("email")];
DEBUG_PRINTLN(em);
DEBUG_PRINTLN(resp.status);
DEBUG_PRINTLN(resp.code);
DEBUG_PRINTLN(resp.desc);
}
}
}
}
}else{
DEBUG_PRINTLN(F("fail."));
}
}
So the code read the configuration and iterate for all emails inserted check if must be send a particular alert.
Thanks
- ABB Aurora Web Inverter Monitor (WIM): project introduction
- ABB Aurora Web Inverter Monitor (WIM): wiring Arduino to RS-485
- ABB Aurora Web Inverter Monitor (WIM): storage devices
- ABB Aurora Web Inverter Monitor (WIM): debug and notification
- ABB Aurora Web Inverter Monitor (WIM): set time and UPS
- ABB Aurora Web Inverter Monitor (WIM): WIFI configuration and REST Server
- ABB Aurora Web Inverter Monitor (WIM): WebSocket and Web Server
- ABB Aurora Web Inverter Monitor (WIM): Wiring and PCB soldering
- ABB Aurora Web Inverter Monitor (WIM): upload the sketch and front end
- ABB Aurora web inverter Monitor (WIM): 3D printed case to complete project
- ABB Aurora web inverter monitor (WIM): repair E013 error
GitHub repository with all code BE and FE transpiled