Per la mia centralina inverter stavo pensando ad un’interfaccia web, quindi prima è necessario un modo semplice per connettere il dispositivo alla rete WiFi.
A tale scopo esiste una semplice libreria che spiego in “Come gestire dinamicamente la configurazione WIFI su esp8266 o esp32”, questa permette di avviare la centralina si avvia in modalità AP e da qui puoi collegarti e configurare il tuo wifi.
Quando ci si connette all’AP, automaticamente si viene reindirizzati alla pagina di configurazione WIFI, qui si seleziona il proprio SSID e si inserisce la password.
Ora puoi connetterti all’url http: //invertercentraline, ma in alcune configurazioni di rete non funziona l’mDNS (Multicast DNS) quindi devi controllare quale IP hai ricevuto, puoi connetterti alla porta Seriale per il debug o usare un programma (per Cellulare Android o Desktop) come Fing che esegue la scansione di tutti i dispositivi nella rete.
Se non è specificata nessuna configurazione, il comando che avvia tutto il processo è
wifiManager.autoConnect("InverterCentralineConfiguration");
altrimenti se viene trovata una configurazione, i dati verranno impostati utilizzando questo codice
DEBUG_PRINT(F("Set static data..."));
if (isDNS){
wifiManager.setSTAStaticIPConfig(_ip, _gw, _sn, _dns1, _dns2);
}else{
wifiManager.setSTAStaticIPConfig(_ip, _gw, _sn);
}
Ma fai attenzione, WiFiManager di default non supporta la configurazione dei DNS, quindi dovrai usare la mia libreria
https://github.com/xreef/WiFiManager
Ho aggiunto la gestione del DNS e ci permette di usare l’esp8266 come un client e fare richieste verso l’esterno.
Quando hai trovato il dispositivo apri l’ip nel browser e vai direttamente al menu “Configurazione”. Qui imposta un IP statico più comodo da usare.
Al riavvio del dispositivo, se tutto va bene: D, potrai usare sempre quell’ip per gestire l’inverter.
REST Server
Ho separato il server REST dal Web Server e ho implementato una serie di API per controllare il dispositivo in ogni sua parte.
Puoi avere maggiori informazioni sui server REST su esp8266 ed esp32 in questi tutorial “Come creare un server REST su esp8266 o esp32“.
Questo è il codice dove censisco gli end-point rest REST.
void restServerRouting() {
// httpRestServer.header("Access-Control-Allow-Headers: Authorization, Content-Type");
//
httpRestServer.on("/", HTTP_GET, []() {
httpRestServer.send(200, F("text/html"),
F("Welcome to the Inverter Centraline REST Web Server"));
});
httpRestServer.on(F("/production"), HTTP_GET, getProduction);
httpRestServer.on(F("/productionTotal"), HTTP_GET, getProductionTotal);
httpRestServer.on(F("/monthly"), HTTP_GET, getMontlyValue);
httpRestServer.on(F("/historical"), HTTP_GET, getHistoricalValue);
httpRestServer.on(F("/config"), HTTP_OPTIONS, sendCrossOriginHeader);
httpRestServer.on(F("/config"), HTTP_POST, postConfigFile);
httpRestServer.on(F("/config"), HTTP_GET, getConfigFile);
httpRestServer.on(F("/inverterInfo"), HTTP_GET, getInverterInfo);
httpRestServer.on(F("/inverterState"), HTTP_GET, getInverterLastState);
httpRestServer.on(F("/inverterDayWithProblem"), HTTP_GET, inverterDayWithProblem);
httpRestServer.on(F("/inverterDayState"), HTTP_GET, getInverterDayState);
httpRestServer.on(F("/serverState"), HTTP_GET, getServerState);
httpRestServer.on(F("/battery"), HTTP_GET, getBatteryInfo);
httpRestServer.on(F("/reset"), HTTP_GET, getReset);
}
Tutti gli endpoint possono operare in CORS (controllare l’articolo sui server REST).
E’ possibile avere tutti gli end point documentati con esempi e con il codice necessario per tutti i linguaggi a questo link.
Qui la documentazione delle API.
Invio del file di configurazione
POST
http://192.168.1.15:8080/config
BODY raw
{
"server": {
"hostname": "invertercentraline",
"isStatic": true,
"address": "192.168.1.15",
"gatway": "192.168.1.1",
"netMask": "255.255.255.0",
"dns1": "8.8.8.8",
"dns2": "85.37.17.51"
},
"serverSMTP": {
"server": "smtp.gmail.com",
"port": 465,
"login": "account@gmail.com",
"password": "yourpasswd",
"from": "smtp.mischianti@gmail.com"
},
"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"
}
]
},
"preferences": {
"GTM": {
"timeZoneId": 31,
"gmtAdjustment": "GMT+01:00",
"useDaylightTime": 1,
"value": 1,
"description": "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"
},
"DST": {
"id": 2,
"code": "CET",
"description": "Central European Time (Frankfurt, Paris)"
},
"adminEmail": "renzo.mischianti@gmail.com",
"undefined": {
"id": 0,
"code": "GMT",
"description": "Standard GMT"
}
}
}
JS
var data = JSON.stringify({"server":{"hostname":"invertercentraline","isStatic":true,"address":"192.168.1.15","gatway":"192.168.1.1","netMask":"255.255.255.0","dns1":"8.8.8.8","dns2":"85.37.17.51"},"serverSMTP":{"server":"smtp.gmail.com","port":465,"login":"smtp.mischianti@gmail.com","password":"miapassword","from":"smtp.mischianti@gmail.com"},"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"}]},"preferences":{"GTM":{"timeZoneId":31,"gmtAdjustment":"GMT+01:00","useDaylightTime":1,"value":1,"description":"(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"},"DST":{"id":2,"code":"CET","description":"Central European Time (Frankfurt, Paris)"},"adminEmail":"renzo.mischianti@gmail.com","undefined":{"id":0,"code":"GMT","description":"Standard GMT"}}});
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function() {
if(this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("POST", "http://192.168.1.15:8080/config");
xhr.setRequestHeader("Content-Type", "application/json");
xhr.send(data);
Get config file
GET
http://192.168.1.11:8080/config
JS
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function() {
if(this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("GET", "http://192.168.1.11:8080/config");
xhr.send();
RESPONSE
{
"server": {
"hostname": "invertercentraline",
"isStatic": true,
"address": "192.168.1.11",
"gatway": "192.168.1.1",
"netMask": "255.255.255.0",
"dns1": "85.37.17.12",
"dns2": "8.8.8.8"
},
"serverSMTP": {
"server": "smtp.gmail.com",
"port": 465,
"login": "smtp.mischianti@gmail.com",
"password": "yourpasswd",
"from": "smtp.mischianti@gmail.com"
},
"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": "none",
"ch2": "none",
"state": "on_problem"
}
]
},
"preferences": {
"GTM": {
"timeZoneId": 31,
"gmtAdjustment": "GMT+01:00",
"useDaylightTime": 1,
"value": 1,
"description": "(GMT+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna"
}
}
}
Ottenere i dati di produzione
GET
http://192.168.1.11:8080/production?day=20181020&type=power
PARAMETRI
day | 20181020 | YYYYMMDD |
type | power |
JS
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function() {
if(this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("GET", "http://192.168.1.11:8080/production?day=20181130&type=power");
xhr.send();
RESPONSE
{
"lastUpdate": "30/11/2018 16:25:49",
"data": [
{
"h": "1520",
"val": 76.6
},
{
"h": "1525",
"val": 87.3
},
{
"h": "1530",
"val": 92.2
},
{
"h": "1535",
"val": 113.8
},
{
"h": "1540",
"val": 112.3
},
{
"h": "1545",
"val": 135.3
},
{
"h": "1550",
"val": 122.1
},
{
"h": "1555",
"val": 87.3
},
{
"h": "1600",
"val": 60.9
},
{
"h": "1605",
"val": 48.2
},
{
"h": "1610",
"val": 44.7
},
{
"h": "1615",
"val": 54
},
{
"h": "1620",
"val": 27.5
},
{
"h": "1625",
"val": 7.2
}
]
}
Ottenere le statistiche mensili
http://192.168.1.11:8080/monthly?month=201810
Parametri
month | 201801 | YYYYMM |
JS
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function() {
if(this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("GET", "http://192.168.1.11:8080/monthly?month=201810");
xhr.send();
RESPONSE
{
"lastUpdate": "21/01/2020 23:58:21",
"data": {
"2235": 4.036887,
"2255": 4.012887,
"2258": 4.009645,
"2318": 3.996532,
"2338": 3.973693,
"2358": 3.963484
}
}
Stato dell’inverter
http://192.168.1.11:8080/inverterState
JS
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function() {
if(this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("GET", "http://192.168.1.11:8080/inverterState");
xhr.send();
RESPONSE
{
"lastUpdate": "01/12/2018 17:06:08",
"alarmStateParam": 0,
"alarmState": "No Alarm",
"channel1StateParam": 2,
"channel1State": "MPPT",
"channel2StateParam": 7,
"channel2State": "Input Low",
"inverterStateParam": 2,
"inverterState": "Run"
}
Giorni in cui l’inverter ha avuto problemi
http://192.168.1.11:8080/inverterDayWithProblem
JS
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function() {
if(this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("GET", "http://192.168.1.11:8080/inverterDayWithProblem");
xhr.send();
Variazioni di stato giornaliere
http://192.168.1.11:8080/inverterDayState?day=20181023
PARAMETRI
day | 20181023 |
JS
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function() {
if(this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("GET", "http://192.168.1.11:8080/inverterDayState?day=20181023");
xhr.send();
RESPONSE
{
"lastUpdate": null,
"data": [
{
"h": "0753",
"asp": 2,
"c1sp": 2,
"c2sp": 7,
"isp": 2
},
{
"h": "0958",
"asp": 0,
"c1sp": 2,
"c2sp": 7,
"isp": 2
},
{
"h": "1035",
"asp": 2,
"c1sp": 2,
"c2sp": 7,
"isp": 2
},
{
"h": "1041",
"asp": 0,
"c1sp": 2,
"c2sp": 7,
"isp": 2
},
{
"h": "1045",
"asp": 2,
"c1sp": 2,
"c2sp": 7,
"isp": 2
},
{
"h": "1050",
"asp": 0,
"c1sp": 2,
"c2sp": 7,
"isp": 2
},
{
"h": "1052",
"asp": 2,
"c1sp": 2,
"c2sp": 7,
"isp": 2
},
{
"h": "1056",
"asp": 0,
"c1sp": 2,
"c2sp": 7,
"isp": 2
},
{
"h": "1058",
"asp": 2,
"c1sp": 2,
"c2sp": 7,
"isp": 2
},
{
"h": "1100",
"asp": 0,
"c1sp": 2,
"c2sp": 7,
"isp": 2
},
{
"h": "1102",
"asp": 2,
"c1sp": 2,
"c2sp": 7,
"isp": 2
},
{
"h": "1104",
"asp": 0,
"c1sp": 2,
"c2sp": 7,
"isp": 2
},
{
"h": "1106",
"asp": 2,
"c1sp": 2,
"c2sp": 7,
"isp": 2
},
{
"h": "1109",
"asp": 0,
"c1sp": 2,
"c2sp": 7,
"isp": 2
},
{
"h": "1111",
"asp": 2,
"c1sp": 2,
"c2sp": 7,
"isp": 2
}
]
}
Produzione totale
http://192.168.1.11:8080/productionTotal
JS
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function() {
if(this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("GET", "http://192.168.1.11:8080/productionTotal");
xhr.send();
RESPONSE
{
"lastUpdate": "01/12/2018 17:05:07",
"energyLifetime": 20213214,
"energyYearly": 3142014,
"energyMonthly": 6150,
"energyWeekly": 26081,
"energyDaily": 6151,
"W": "201848",
"M": "201812",
"Y": "2018"
}
Dati storici
GET
http://192.168.1.15:8080/historical?frequence=years&year=2018
PARAMS
frequence | years |
year | 2018 |
JS
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function() {
if(this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("GET", "192.168.1.15:8080/historical?frequence=years&year=2018");
xhr.send();
RESPONSE
{
"2020": 155011
}
Stato del server
http://192.168.1.15:8080/serverState
JS
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function() {
if(this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("GET", "192.168.1.15:8080/serverState");
xhr.send();
RESPONSE
{
"network": {
"ip": "192.168.1.15",
"gw": "192.168.1.1",
"nm": "255.255.255.0",
"dns1": "8.8.8.8",
"dns2": "85.37.17.51",
"signalStrengh": -41
},
"lastUpdate": "27/01/2020 08:46:49",
"chip": {
"chipId": 8644639,
"flashChipId": 1458208,
"flashChipSize": 4194304,
"flashChipRealSize": 4194304,
"freeHeap": 28096,
"batteryVoltage": 0.059468
}
}
Stato della batteria
http://192.168.1.15:8080/battery?day=20200121
PARAMETRI
day | 20200121 |
JS
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function() {
if(this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("GET", "http://192.168.1.15:8080/battery?day=20200121");
xhr.send();
RESPONSE
{
"lastUpdate": "21/01/2020 23:58:21",
"data": {
"2235": 4.036887,
"2255": 4.012887,
"2258": 4.009645,
"2318": 3.996532,
"2338": 3.973693,
"2358": 3.963484
}
}
Thanks
- Centralina Web per inverter ABB (ex Power One) Aurora (WIM): intro al progetto
- Centralina Web per inverter ABB Aurora (WIM): connessione Arduino all’RS-485
- Centralina Web per inverter ABB Aurora (WIM): dispositivi di archiviazione
- Centralina Web per inverter ABB Aurora (WIM): debug e notifica
- Centralina Web per inverter ABB Aurora (WIM): impostare l’ora e UPS
- Centralina Web per inverter ABB Aurora (WIM): configurazione WIFI e server REST
- Centralina Web per inverter ABB Aurora (WIM): WebSocket e Web Server
- Centralina Web per inverter ABB Aurora (WIM): cablaggio e PCB
- Centralina Web per inverter ABB Aurora (WIM): caricare il programma ed il front end
- Centralina Web per inverter ABB Aurora (WIM): scatola stampata in 3D e completamento
- Centralina Web per inverter ABB Aurora (WIM): riparare l’errore E013
GitHub repository con tutto il codice FE (transpilato) e BE