Un saluto a tutti, ho deciso di condividere con voi il mio lavoro che consente di monitorare in tempo reale i regolatori mp solar serie RN e BN.
solare.altervista.orgRingrazio jackie2_it che mi ha fornito utili indicazioni per realizzare lo scketch da caricare nell'arduino, e specialmente Gigi600 che ha fatto da beta tester
Il sistema consente di monitorare il regolatore da remoto tramite web. Ciò è possibile sia con arduino con ethernet shiel, sia con il modulo Esp8266-01. La prima soluzione è piu semplice e rapida, mentre la seconda soluzione ci consente di collegare il regolatore in wi-fi!!!
Condizione necessaria è quella di possedere uno spazio web con database mysql. Io ho usato quello di altervista, gratuito e funzionale.
Di seguito gli schemi di collegamento:
Regolatori serie RN con arduino
Regolatori serie RN con esp8266-01
Regolatori serie BN con arduino
Regolatori serie BN con esp8266
Nel caso abbiate scelto arduino questo è lo scketch da caricare. Prima però dobbiamo inserire dei settaggi a inizio codice mettendo quelli esatti.
Schetch da modificare:
#include <SPI.h>
#include <Ethernet.h>
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
//------------------------- Settaggi
IPAddress ip(192, 168, 178, 40);//indirizzo ip da assegnare ad arduino
char server[] = "tuosito.altervista.org";//indirizzo del server web
int unsigned long capacita_batteria = 300; //indica la capacità della batteria in carica in Ah
const int psw = 1234; //password per l'aggiornamento dati server web
const int psw2 = 5678; //password per sincronizzazione ah server web
const char* regolatore = "bn"; //bn=regolatori serie BN ---- rn=regolatori serie RN
//solo per la serie BN alla riga 337 ah_prodotti = 5000; per la serie RN mettere ah_prodotti = 0
//-------------------------- Fine settaggi
EthernetClient client;
String strURL = "";
String strEsito = "";
int tensione_pannello;
int corrente_pannello;
int tensione_batteria;
int corrente_batteria;
int tensione_carico;
int corrente_carico;
int data_long = 0;
int data[50];
int temperatura;
int soc = 100;
unsigned long ah_prodotti;
unsigned long ah_consumati;
unsigned long lettura_ah_prodotti;
unsigned long lettura_ah_consumati;
unsigned long ah_batteria;
//--------------------------- Pin di uscita digitali
const int led_pin = 5; // pin di uscita dedicato al stato di segnalazione di funzionamento
//--------------------------- Variabili di temporizzazione
unsigned long time_Ah_old = 0;
unsigned long lastTime = 0; //variabile di temporizzazione
const int postingInterval = 3500;
//---------------------------
int stato = 1;
void setup()
{
if (regolatore == "bn")
{
Serial.begin(115200);
}
else
{
Serial.begin(9600);
}
pinMode(4, OUTPUT); // disattiva il pin della SD card
digitalWrite(4, HIGH);
pinMode(led_pin, OUTPUT);
Ethernet.begin(mac, ip);
delay(5000);
capacita_batteria = capacita_batteria * 1000000;
ah_batteria = capacita_batteria; // fa partire il soc dal 100%
if (client.connect(server, 80)) { // Interroga il server per avere gli ultimi Ah salvati
String strURL = "GET /arduino/arduino.php?psw=";
strURL += psw2;
strURL += " HTTP/1.1";
client.println(strURL);
client.print("Host: ");
client.println(server);
client.println("User-Agent: arduino-ethernet");
client.println("Connection: close");
client.println();
delay(1000);
rispostaServer();
}
else
{
while (true);
}
}
bool update()
{
bool updok = false;
if (regolatore == "bn")
{
//tensione batteria
Serial.write(0x01);
Serial.write(0x04);
Serial.write(0x31);
Serial.write(0x04);
Serial.write((uint8_t)0x00);
Serial.write(0x01);
Serial.write(0x7E);
Serial.write(0xF7);
delay(500);
if (Serial.available())
{
data_long = Serial.available();
for (int n = 0; n < data_long; n++)
{
data[n] = Serial.read();
}
tensione_batteria = (data[3] << 8) | data[4];
//tensione pannello
Serial.write(0x01);
Serial.write(0x04);
Serial.write(0x31);
Serial.write((uint8_t)0x00);
Serial.write((uint8_t)0x00);
Serial.write(0x01);
Serial.write(0x3F);
Serial.write(0x36);
delay(500);
if (Serial.available())
{
data_long = Serial.available();
for (int n = 0; n < data_long; n++)
{
data[n] = Serial.read();
}
tensione_pannello = (data[3] << 8) | data[4];
}
//corrente batteria
Serial.write(0x01);
Serial.write(0x04);
Serial.write(0x33);
Serial.write(0x1B);
Serial.write((uint8_t)0x00);
Serial.write(0x01);
Serial.write(0x4E);
Serial.write(0x89);
delay(500);
if (Serial.available())
{
data_long = Serial.available();
for (int n = 0; n < data_long; n++)
{
data[n] = Serial.read();
}
corrente_batteria = (data[3] << 8) | data[4];
}
//corrente pannello
Serial.write(0x01);
Serial.write(0x04);
Serial.write(0x31);
Serial.write(0x01);
Serial.write((uint8_t)0x00);
Serial.write(0x01);
Serial.write(0x6E);
Serial.write(0xF6);
delay(500);
if (Serial.available())
{
data_long = Serial.available();
for (int n = 0; n < data_long; n++)
{
data[n] = Serial.read();
}
corrente_pannello = (data[3] << 8) | data[4];
}
//corrente carico
Serial.write(0x01);
Serial.write(0x04);
Serial.write(0x31);
Serial.write(0x0D);
Serial.write((uint8_t)0x00);
Serial.write(0x01);
Serial.write(0xAE);
Serial.write(0xF5);
delay(500);
if (Serial.available())
{
data_long = Serial.available();
for (int n = 0; n < data_long; n++)
{
data[n] = Serial.read();
}
corrente_carico = (data[3] << 8) | data[4];
}
//temperatura
Serial.write(0x01);
Serial.write(0x04);
Serial.write(0x31);
Serial.write(0x10);
Serial.write((uint8_t)0x00);
Serial.write(0x01);
Serial.write(0x3E);
Serial.write(0xF3);
delay(500);
if (Serial.available())
{
data_long = Serial.available();
for (int n = 0; n < data_long; n++)
{
data[n] = Serial.read();
}
temperatura = (data[3] << 8) | data[4];
temperatura = temperatura / 100;
}
//SOC Batteria
Serial.write(0x01);
Serial.write(0x04);
Serial.write(0x31);
Serial.write(0x1A);
Serial.write((uint8_t)0x00);
Serial.write(0x01);
Serial.write(0x1E);
Serial.write(0xF1);
delay(500);
if (Serial.available())
{
data_long = Serial.available();
for (int n = 0; n < data_long; n++)
{
data[n] = Serial.read();
}
soc = (data[3] << 8) | data[4];
}
updok = true;
}
}
else if (regolatore == "rn")
{
Serial.write(0xAA);
Serial.write(0x55);
Serial.write(0xAA);
Serial.write(0x55);
Serial.write(0xAA);
Serial.write(0x55);
Serial.write(0xEB);
Serial.write(0x90);
Serial.write(0xEB);
Serial.write(0x90);
Serial.write(0xEB);
Serial.write(0x90);
Serial.write(0x16);
Serial.write(0xA0);
Serial.write((uint8_t)0x00);
Serial.write(0xB1);
Serial.write(0xA7);
Serial.write(0x7F);
delay(500);
if (Serial.available())
{
data_long = Serial.available();
for (int n = 0; n < data_long; n++)
{
data[n] = Serial.read();
}
tensione_pannello = (data[12] << 8) | data[11];
corrente_pannello = 0;
tensione_batteria = (data[10] << 8) | data[9];
corrente_batteria = (data[31] << 8) | data[30];
tensione_carico = tensione_batteria;
corrente_carico = (data[16] << 8) | data[15];
temperatura = data[29] - 30;
updok = true;
}
}
tensione_carico = tensione_batteria;
if(updok)
{
lettura_ah_consumati = ((float)corrente_carico / 3600) * (millis() - time_Ah_old) * 10; //restituisce la lettura in micro Ah
if(regolatore == "bn")
{
int totAmpereProdotti = corrente_batteria + corrente_carico;
lettura_ah_prodotti = ((float)totAmpereProdotti / 3600) * (millis() - time_Ah_old) * 10; //restituisce la lettura in micro Ah
}
else if (regolatore == "rn")
{
lettura_ah_prodotti = ((float)corrente_batteria / 3600) * (millis() - time_Ah_old) * 10; //restituisce la lettura in micro Ah
}
ah_consumati += lettura_ah_consumati;
ah_prodotti += lettura_ah_prodotti;
if (regolatore == "rn"){
calcolo_soc();
}
}
time_Ah_old = millis();
return updok;
}
void calcolo_soc() {
ah_batteria += (lettura_ah_prodotti - lettura_ah_consumati);
if (ah_batteria > capacita_batteria) {
ah_batteria = capacita_batteria;
soc = 100;
} else {
soc = map((float)ah_batteria / 1000000, 0, (float)capacita_batteria / 1000000, 0, 100);
}
}
void httpRequest() {
client.stop();
if (client.connect(server, 80)) {
String strURL = "GET /arduino/arduino.php?psw=";
strURL += (int)psw;
strURL += "&tensione_pannello=";
strURL += (int)tensione_pannello;
strURL += "&corrente_pannello=";
strURL += (int)corrente_pannello;
strURL += "&tensione_batteria=";
strURL += (int)tensione_batteria;
strURL += "&corrente_batteria=";
strURL += (short)corrente_batteria;
strURL += "&tensione_carico=";
strURL += (int)tensione_carico;
strURL += "&corrente_carico=";
strURL += (int)corrente_carico;
strURL += "&soc=";
strURL += (int)soc;
strURL += "&temperatura=";
strURL += (short)temperatura;
strURL += "&ah_consumati=";
strURL += (unsigned long)ah_consumati;
strURL += "&ah_prodotti=";
strURL += (unsigned long)ah_prodotti;
strURL += " HTTP/1.1";
client.println(strURL);
client.print("Host: ");
client.println(server);
client.println("User-Agent: arduino-ethernet");
client.println("Connection: close");
client.println();
}
}
void rispostaServer()
{
int risp_server = client.available();
if (risp_server < 300 && risp_server > 10) {
while (client.available())
{
char c = client.read();
strEsito += (char) c;
}
if (strEsito.indexOf("update_ok") > 0)
{
stato = 1;
}
else
{
stato = 3;
}
if (strEsito.indexOf("reset_ah") > 0)
{
ah_consumati = 0;
ah_prodotti = 5000; //solo per la serie BN 5000 , per la serie RN mettere 0
}
if (strEsito.indexOf("Ah_prodotti=") > 0) // Recupera dal server gli ultimi valori del giorno salvati prima del reset di arduino.
{
ah_prodotti = atol(strEsito.substring(strEsito.indexOf("ah_prodotti=") + 12, strEsito.indexOf(" ah_consumati=")).c_str());
ah_consumati = atol(strEsito.substring(strEsito.indexOf("ah_consumati=") + 13, strEsito.indexOf(" endah")).c_str());
}
}
strEsito = "";
}
void ledStato(int st)
{
switch (st)
{
case 1: // Nessun errore di funzionamento
for (int i = 1; i <= 1; i++)
{
digitalWrite(led_pin, HIGH);
delay(50);
digitalWrite(led_pin, LOW);
delay(500);
}
break;
case 2: // Impossibile leggere i dati dal regolatore
for (int i = 1; i <= 2; i++)
{
digitalWrite(led_pin, HIGH);
delay(50);
digitalWrite(led_pin, LOW);
delay(500);
}
break;
case 3: // Errore di comunicazone con il server remoto
for (int i = 1; i <= 3; i++)
{
digitalWrite(led_pin, HIGH);
delay(50);
digitalWrite(led_pin, LOW);
delay(500);
}
break;
case 4: // Attesa reset ethernet shield
for (int i = 1; i <= 4; i++)
{
digitalWrite(led_pin, HIGH);
delay(50);
digitalWrite(led_pin, LOW);
delay(500);
}
break;
}
delay(1000);
}
void loop() {
rispostaServer();
if (millis() - lastTime >= postingInterval)
{
if (update() == false)
{
stato = 2;
lastTime = millis();
}
else {
httpRequest();
lastTime = millis();
}
}
else
{
ledStato(stato);
}
}
Questo lo scketch se avete scelto esp8266-01
Si può far riferimento a questa guida per preparare l'ide di arduino a funzionare con l'esp8266
https://www.reboot.ms/forum/threads/programmare-esp8266-usando-arduino-ide.385/Scketch da modificare
#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
//------------------------- Settaggi
IPAddress ip(192, 168, 1, 60); //indirizzo ip da assegnare a esp8266
IPAddress gateway(192, 168, 1, 1); //indirizzo ip del gateway ( di solito è l'indirizzo del router wi-fi)
IPAddress subnet(255, 255, 255, 0); //subnet mask di solito è sempre 255.255.255.0
char server[] = "tuosito.altervista.org"; //indirizzo del server web
const char* ssid = "nome_rete_wifi"; // indica il nome della rete wi-fi
const char* password = "password_wifi"; // password della rete wi-fi
int unsigned long capacita_batteria = 300; //indica la capacità della batteria in carica in Ah
const int psw = 5678; //password per l'aggiornamento dati server web
const int psw2 = 1234; //password per sincronizzazione ah server web
const char* regolatore = "bn"; //bn=regolatori serie BN ---- rn=regolatori serie RN
//-------------------------- Fine settaggi
WiFiClient client;
String strURL = "";
String strEsito = "";
int tensione_pannello;
int corrente_pannello;
int tensione_batteria;
short corrente_batteria;
int tensione_carico;
int corrente_carico;
int data_long = 0;
int data[50];
short temperatura;
int soc = 100;
unsigned long ah_prodotti;
unsigned long ah_consumati;
unsigned long lettura_ah_prodotti;
unsigned long lettura_ah_consumati;
unsigned long ah_batteria;
//--------------------------- Pin di uscita digitali
const int led_pin = 2; // pin di uscita dedicato al led di stato funzionamento
//--------------------------- Variabili di temporizzazione
unsigned long time_Ah_old = 0;
unsigned long lastTime = 0; //variabile di temporizzazione
const int postingInterval = 3500;
//---------------------------
void calcolo_soc() {
ah_batteria += (lettura_ah_prodotti - lettura_ah_consumati);
if (ah_batteria > capacita_batteria) {
ah_batteria = capacita_batteria;
soc = 100;
} else {
soc = map((float)ah_batteria / 1000000, 0, (float)capacita_batteria / 1000000, 0, 100);
}
}
bool update()
{
bool updok = false;
if (regolatore == "bn")
{
//tensione batteria
Serial.write(0x01);
Serial.write(0x04);
Serial.write(0x31);
Serial.write(0x04);
Serial.write(0x00);
Serial.write(0x01);
Serial.write(0x7E);
Serial.write(0xF7);
delay(500);
if (Serial.available())
{
data_long = Serial.available();
for (int n = 0; n < data_long; n++)
{
data[n] = Serial.read();
}
tensione_batteria = (data[3] << 8) | data[4];
//tensione pannello
Serial.write(0x01);
Serial.write(0x04);
Serial.write(0x31);
Serial.write(0x00);
Serial.write(0x00);
Serial.write(0x01);
Serial.write(0x3F);
Serial.write(0x36);
delay(500);
if (Serial.available())
{
data_long = Serial.available();
for (int n = 0; n < data_long; n++)
{
data[n] = Serial.read();
}
tensione_pannello = (data[3] << 8) | data[4];
}
//corrente batteria
Serial.write(0x01);
Serial.write(0x04);
Serial.write(0x33);
Serial.write(0x1B);
Serial.write(0x00);
Serial.write(0x01);
Serial.write(0x4E);
Serial.write(0x89);
delay(500);
if (Serial.available())
{
data_long = Serial.available();
for (int n = 0; n < data_long; n++)
{
data[n] = Serial.read();
}
corrente_batteria = (data[3] << 8) | data[4];
}
//corrente pannello
Serial.write(0x01);
Serial.write(0x04);
Serial.write(0x31);
Serial.write(0x01);
Serial.write(0x00);
Serial.write(0x01);
Serial.write(0x6E);
Serial.write(0xF6);
delay(500);
if (Serial.available())
{
data_long = Serial.available();
for (int n = 0; n < data_long; n++)
{
data[n] = Serial.read();
}
corrente_pannello = (data[3] << 8) | data[4];
}
//corrente carico
Serial.write(0x01);
Serial.write(0x04);
Serial.write(0x31);
Serial.write(0x0D);
Serial.write(0x00);
Serial.write(0x01);
Serial.write(0xAE);
Serial.write(0xF5);
delay(500);
if (Serial.available())
{
data_long = Serial.available();
for (int n = 0; n < data_long; n++)
{
data[n] = Serial.read();
}
corrente_carico = (data[3] << 8) | data[4];
}
//temperatura
Serial.write(0x01);
Serial.write(0x04);
Serial.write(0x31);
Serial.write(0x11);
Serial.write(0x00);
Serial.write(0x01);
Serial.write(0x6F);
Serial.write(0x33);
delay(500);
if (Serial.available())
{
data_long = Serial.available();
for (int n = 0; n < data_long; n++)
{
data[n] = Serial.read();
}
temperatura = (data[3] << 8) | data[4];
temperatura = temperatura / 100;
}
//SOC Batteria
Serial.write(0x01);
Serial.write(0x04);
Serial.write(0x31);
Serial.write(0x1A);
Serial.write(0x00);
Serial.write(0x01);
Serial.write(0x1E);
Serial.write(0xF1);
delay(500);
if (Serial.available())
{
data_long = Serial.available();
for (int n = 0; n < data_long; n++)
{
data[n] = Serial.read();
}
soc = (data[3] << 8) | data[4];
}
updok = true;
}
}
else if (regolatore == "rn")
{
Serial.write(0xAA);
Serial.write(0x55);
Serial.write(0xAA);
Serial.write(0x55);
Serial.write(0xAA);
Serial.write(0x55);
Serial.write(0xEB);
Serial.write(0x90);
Serial.write(0xEB);
Serial.write(0x90);
Serial.write(0xEB);
Serial.write(0x90);
Serial.write(0x16);
Serial.write(0xA0);
Serial.write(0x00);
Serial.write(0xB1);
Serial.write(0xA7);
Serial.write(0x7F);
delay(500);
if (Serial.available())
{
data_long = Serial.available();
for (int n = 0; n < data_long; n++)
{
data[n] = Serial.read();
}
tensione_pannello = (data[12] << 8) | data[11];
corrente_pannello = 0;
tensione_batteria = (data[10] << 8) | data[9];
corrente_batteria = (data[31] << 8) | data[30];
tensione_carico = tensione_batteria;
corrente_carico = (data[16] << 8) | data[15];
temperatura = data[29] - 30;
updok = true;
}
}
tensione_carico = tensione_batteria;
if(updok)
{
lettura_ah_consumati = ((float)corrente_carico / 3600) * (millis() - time_Ah_old) * 10; //restituisce la lettura in micro Ah
if(regolatore == "bn")
{
int totAmpereProdotti = corrente_batteria + corrente_carico;
lettura_ah_prodotti = ((float)totAmpereProdotti / 3600) * (millis() - time_Ah_old) * 10; //restituisce la lettura in micro Ah
}
else if (regolatore == "rn")
{
lettura_ah_prodotti = ((float)corrente_batteria / 3600) * (millis() - time_Ah_old) * 10; //restituisce la lettura in micro Ah
}
ah_consumati += lettura_ah_consumati;
ah_prodotti += lettura_ah_prodotti;
if (regolatore == "rn"){
calcolo_soc();
}
}
time_Ah_old = millis();
return updok;
}
void httpRequest() {
client.stop();
if (client.connect(server, 80)) {
String strURL = "GET /arduino/arduino.php?psw=";
strURL += (int)psw;
strURL += "&tensione_pannello=";
strURL += (int)tensione_pannello;
strURL += "&corrente_pannello=";
strURL += (int)corrente_pannello;
strURL += "&tensione_batteria=";
strURL += (int)tensione_batteria;
strURL += "&corrente_batteria=";
strURL += (short)corrente_batteria;
strURL += "&tensione_carico=";
strURL += (int)tensione_carico;
strURL += "&corrente_carico=";
strURL += (int)corrente_carico;
strURL += "&soc=";
strURL += (int)soc;
strURL += "&temperatura=";
strURL += (short)temperatura;
strURL += "&ah_consumati=";
strURL += (unsigned long)ah_consumati;
strURL += "&ah_prodotti=";
strURL += (unsigned long)ah_prodotti;
strURL += " HTTP/1.1";
client.println(strURL);
client.print("Host: ");
client.println(server);
client.println("User-Agent: arduino-ethernet");
client.println("Connection: close");
client.println();
}
}
void rispostaServer()
{
int risp_server = client.available();
if (risp_server < 300 && risp_server > 10) {
while (client.available())
{
char c = client.read();
strEsito += (char) c;
}
if (strEsito.indexOf("reset_ah") > 0)
{
ah_consumati = 0;
ah_prodotti = 5000;
}
if (strEsito.indexOf("ah_prodotti=") > 0) // Recupera dal server gli ultimi valori del giorno salvati prima del reset di arduino.
{
ah_prodotti = atol(strEsito.substring(strEsito.indexOf("ah_prodotti=") + 12, strEsito.indexOf(" ah_consumati=")).c_str());
ah_consumati = atol(strEsito.substring(strEsito.indexOf("ah_consumati=") + 13, strEsito.indexOf(" endah")).c_str());
}
}
strEsito = "";
}
void setup()
{
if(regolatore == "bn")
{
Serial.begin(115200);
}
else
{
Serial.begin(9600);
}
pinMode(led_pin, OUTPUT);
digitalWrite(led_pin, HIGH);
pinMode(0, OUTPUT);
digitalWrite(0, LOW);
WiFi.begin(ssid, password);
WiFi.config(ip, gateway, subnet);
delay(5000);
capacita_batteria = capacita_batteria * 1000000;
ah_batteria = capacita_batteria; // fa partire il soc dal 100%
if (client.connect(server, 80)) { // Interroga il server per avere gli ultimi Ah salvati
String strURL = "GET /arduino/arduino.php?psw=";
strURL += psw2;
strURL += " HTTP/1.1";
client.println(strURL);
client.print("Host: ");
client.println(server);
client.println("User-Agent: esp8266 wi-fi");
client.println("Connection: close");
client.println();
delay(5000);
rispostaServer();
}
else
{
while (true);
}
ArduinoOTA.begin();
}
void loop() {
rispostaServer();
if (millis() - lastTime >= postingInterval)
{
if (update() == false)
{
lastTime = millis();
}
else {
httpRequest();
lastTime = millis();
}
}
ArduinoOTA.handle();
}
A questo punto si può caricare lo scketch!
Arduino va collegato al regolatore tramite la porta seriale a disposizione.
Per questa parte non dovrebbe mancare nulla, la prossima volta provvederò a postare il codice sorgente da caricare sul server web remoto