Lettura e generazione fogli Excel/CSV con PHP

Molti dei progetti web/app ai quali ho lavorato e sto attualmente lavorando, richiedono l’upload di fogli Excel e CSV per l’immissione di grandi quantità di dati nel database. Altre volte invece è necessario generare dei report o degli export in formato Excel o CSV, come download o allegati ad email automatiche.

Una libreria che consiglio, estremamente semplice da utilizzare, è PHPSpreadSheet:

https://github.com/PHPOffice/PhpSpreadsheet

La libreria è scritta interamente in PHP, linguaggio che ormai è presente in praticamente tutti gli host web (ad esempio, se avete WordPress, avete sicuramente PHP). Se PHP non è presente è sempre possibile aggiungerlo come servizio extra.

Installazione

Installare la libreria è semplice, basta creare una cartella vuota nello spazio web e copiare il build dell’ultima release. Compilare la libreria richiede composer, ma è sempre possibile utilizzare questa comoda scorciatoia

Scaricato lo zip del build, estraetelo nella cartella vuota che avete creato e voilà, la libreria è “installata”.

Esempio: creazione di file xlsx

Vediamo un semplicissimo esempio che tocca tutte le funzionalità base della libreria. Immaginiamo di avere la libreria installata nella cartella “test”.

require 'test/vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;


$spreadsheet = new Spreadsheet();
$sheet = $spreadsheet->getActiveSheet();
$sheet->setCellValue("A1", "Ciao mondo!");
$writer = new Xlsx($spreadsheet);
$writer->save('prova.xlsx');

Questo semplice programma crea un nuovo file Excel (prova.xlxs) nella cartella corrente (sul server ovviamente) e inserisce la scritta “Ciao mondo!” nella cella A1 del foglio. Tutto qui. setCellValue() è sostanzialmente l’unica API da utilizzare per inserire valori nelle varie celle. Tramite appositi loop potrete ad esempio leggere una riga dal database e creare la riga corrispondente nel foglio Excel e cosi via a creare una tabella completa dei dati.

Se indirizzare le celle con i nomi classici “A1”, “A2”, “C3” etc.. risultasse scomodo, è sempre possible indicizzare tramite due indici numerici separati, uno per la riga e uno per la colonna:

setCellValueByColumnAndRow(1, 5,"Ciao Mondo!");

E’ possibile inoltre impostare font, carattere e allargare/restringere le celle a piacimento, la documentazione contiene tutti gli esempi necessari.

Esempio: lettura di un file xlsx caricato in upload

In questo caso vogliamo leggere un file Excel caricato dall’utente e riversare i dati nel database (o fare delle elaborazioni).

require 'test/vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;


$reader = new \PhpOffice\PhpSpreadsheet\Reader\Xlsx();
$reader->setReadDataOnly(true);
$spreadsheet = $reader->load("prova.xlsx");

In questo caso leggiamo un file (prova.xlsx) già presente nella directory corrente. Il file può essere un upload utente oppure un file generato precedentemente, non ha importanza.

Per leggere una cella, utilizziamo la funzione getCellByColumnAndRow():

$sheet = $spreadsheet->getActiveSheet();
$value = $sheet->getCellByColumnAndRow(2, 3);

che restituisce il contenuto della cella B3. Gli indici partono da 1, quindi A1 è (1,1).

Download diretto del file Excel

Magari preferiamo far partire immediatamente il download nel browser dell’utente non appena la libreria ha creato il file Excel, senza passare da un file temporaneo memorizzato sul server. Molto semplicemente, possiamo impostare gli header PHP per il download e scrivere il foglio Excel nel file speciale php://output. Questo file è un’area di memoria piuttosto che un file vero e proprio: la libreria creerà il foglio Excel in memoria che poi verrà passato in download al browser dell’utente.

$now = gmdate("D, d M Y H:i:s");
header("Expires: Tue, 03 Jul 2001 06:00:00 GMT");
header("Cache-Control: max-age=0, no-cache, must-revalidate, proxy-revalidate");
header("Last-Modified: {$now} GMT");
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="prova.xlsx"');
header("Content-Transfer-Encoding: binary");
$writer = new Xlsx($spreadsheet);
$writer->save("php://output");
die();

Il nome del file in download è impostato nell’header content-dispositon filename (nome file: “prova.xlsx”).

Altre funzionalità

Quello che abbiamo visto è veramente il minimo sindacale per creare e leggere file Excel e CSV con PHP. La libreria mette a disposizione moltissime altre feature tra le quali:

  • il supporto per file Excel 2003, CSV, file spreadsheet Mac
  • accesso alle tab
  • calcolo e creazione formule

Per una lista completa delle funzionalità vi rimando alla documentazione e alla pagina ufficiale del progetto:

https://github.com/PHPOffice/PhpSpreadsheet
https://phpspreadsheet.readthedocs.io/en/develop/

Reverse engineering: sblocco di un software proprietario

Un piccolo esempio di reverse engineering e sblocco del software. Tecnica un po’ noob dato che non ho utilizzato alcun disassembler come IDA Pro o altri tool avanzati, ma pur sempre efficace.

Protezione software con licenza controllata da server remoto

Al fine di evitare copie non autorizzate, molti software implementano un meccanismo di protezione che richiede una specifica licenza installata sullo stesso PC dove girerà il programma. Il proprietario del software acquista la licenza d’uso e può così utilizzare il programma. Le copie del programma semplicemente non funzioneranno perchè sprovviste della relativa licenza. I meccanismi di protezione più sofisticati utilizzano un server remoto per controllare la validità della licenza ed è quindi fondamentale che questo server sia accessibile e sempre funzionante, ma non è sempre così.

Sono stato contattato da una persona che, pur avendo regolarmente acquistato la licenza, si è ritrovato con il software bloccato, proprio perchè il relativo server di licenza è stato messo offline.

In questi casi è perfettamente lecita la modifica del software per ripristinarne il funzionamento perchè la licenza d’uso è stata regolarmente acquistata ed è un diritto dell’utente continuare ad utilizzare il programma.

Il software in questione è FinalTable, programma per l’analisti statistiche delle partite a poker :

 

Provando ad avviare il programma si ottiene un errore di connessione con server remoto, la licenza non può essere verificata ed il programma rimane bloccato alla schermata inziale. Questo è quello che lamentava l’utente e mi ha quindi contattato per risolvere il problema.

Alcuni indizi

Nel manuale in pdf si specifica che la licenza viene verificata all’apertura del programma e, se valida, il bottone OK viene abilitato, permettendo l’accesso alla schermata principale. Probabilmente il codice di verifica della licenza, alla fine del processo, non fa altro che abilitare il bottone OK.

Ho notato inoltre che la finestra principale, il font caratteri e lo stesso bottone OK utilizzano lo stile di default in Windows. Probabilmente il programma è scritto in Visual Basic o che almeno utilizza le librerie native MFC. Se così fosse è possibile inviare comandi esterni agli elementi dell’interfaccia, ad esempio è possibile inviare il comando “enable” allo stesso bottone OK così come farebbe il programma stesso dopo la verifica della licenza.

Tentativi & proof of concept

Ho utilizzato il comodissimo tool WinHack (http://sandsprite.com/) per provare a giocare con la UI ed inviare alcuni comandi al bottone OK

 

 

Il tool permette di conoscere l’ID del bottone (ogni elemento grafico ha il suo ID) , in questo caso 131642.

 

 

A questo punto è possibile inviare messaggi al bottone. Noi siamo interessati al messaggio WM_ENABLE

 

 

Inviando il comando WM_ENABLE il bottone si abiliterà e potremo cliccarlo col mouse:

 

 

E potremo così accedere al programma vero e proprio bypassando completamente il controllo di licenza:

 

 

Implementazione del crack

Il più è fatto, abbiamo trovato un modo per aggirare il controllo di licenza ed entrare comunque nel programma. Adesso occorre scrivere un piccolo programma che automatizza gli step visti prima: cerca il bottone, recupera l’id, invia il comando WM_ENABLE al bottone e lo clicca (comando WM_CLICK).

Il lavoro perfetto per C++ e <windows.h>


#include <cstdlib>
#include <conio.h>
#include <iostream>
#include <windows.h>
using namespace std;

HWND buttonHandle = 0;

BOOL CALLBACK GetButtonHandle(HWND handle, LPARAM)
{
   char label[100];
   int size = GetWindowTextA(handle, label, sizeof(label));

   if (strcmp(label, "OK") == 0)
   {
      buttonHandle = handle;
      cout << handle << endl;

      EnableWindow( handle, TRUE );
      SendMessage(buttonHandle, BM_CLICK, 0, 0);
      exit(0);
      return false;
   }
   return true;
}

int main()
{
   HWND windowHandle = FindWindowA(NULL, "Final Table");
 
   if (windowHandle == NULL)
   {
      cout << "Final Table non trovato!" << endl;
   }

   else
   {
      cout << "Final Table trovato!" << endl;
      SetForegroundWindow(windowHandle);
      BOOL ret = EnumChildWindows(windowHandle, GetButtonHandle, 0);
   }
}

L’utilizzo è semplice: avviare FinalTable e attendere che venga mostrata la schermata principale con il bottone disabilitato (il controllo di licenza è ovviamente fallito). A questo punto basta lanciare il crack e si verrà portati automaticamente alla sezione principale come se la licenza fosse stata correttamente verificata.

 

Lettura remota del fotovoltaico con NodeMCU

Vediamo come realizzare un semplice dispositivo per leggere la produzione di un impianto fotovoltaico e caricare i dati su un server online. La lettura manuale degli inverter di un impianto fotovoltaico è una procedura scomoda e tediosa ma è possibile automatizzare l’estrazione dei dati di produzione poichè molti inverter dispongono di interfaccia RS485. Grazie a tale interfaccia è possibile collegare un piccolo dispositivo elettronico in grado di interrogare gli inverter ad intervalli regolari e memorizzarli o inviarli ad un server remoto. I dati possono poi essere letti da smartphone o computer desktop da qualsiasi parte del mondo!

Un impianto fotovoltaico consiste di un insieme di pannelli, uno o più inverter, il contatore di produzione e quello di scambio:

 

 

L’inverter funziona autonomamente ma controllarne il corretto funzionamento è di primaria importanza per evitare cali di produzione e intervenire tempestivamente per guasti e malfunzionamenti. L’interfaccia RS485 mette a disposizione un numero di dati interessanti tra i quali:

  • Temperatura (C)
  • Produzione giornaliera (kWh)
  • Produzione totale (kWh)
  • Stato (OK o guasto)
  • Tensione, corrente e potenza istantanea

Schema di base

Lo schema di base del progetto è abbastanza semplice. Siccome la stragrande maggioranza degli inverter usa RS485 ho optato per NodeMCU, un minicomputer da 7 euro (7 euro!) che dispone di interfaccia seriale, un certo numeri di GPIO programmabili e un potente modulo WiFi.
NodeMCU può essere programmato per connettersi alla rete WiFi di casa e può ricevere o inviare dati ad un server remoto. Si programma esattamente come una scheda Arduino e non dispone di sistema operativo o programmi vari come un Raspberry Pi. Questa caratteristica lo rende perfetto al nostro scopo perchè l’imperativo in questo caso è l’affidabilità: un Raspberry Pi sarebbe stato altrettanto capace ma essendo un computer vero e proprio è soggetto ad aggiornamenti improvvisi, corruzioni del filesystem, blocchi inaspettati di sistema e chi più ne ha più ne metta. NodeMCU è più simile ad un microcontrollore che ad un vero PC: esegue un solo programma nella sua memoria flash, non ha una SD card che può deteriorarsi nel tempo e se viene a mancare la corrente si azzera tutto e riparte da capo senza problemi.

La scheda NodeMCU ha una seriale UART TTL che non è direttamente compatibile con RS485, è quindi necessario un secondo modulo in grado di convertire l’UART TTL del NodeMCU in un segnale RS485 adatto all’inverter. Queste schede di conversione si trovano a pochi centesimi su ebay o amazon.

NodeMCU dialoga con l’inverter tramite il modulo di conversione RS485, preleva i dati di produzione e li invia in wifi al server remoto. Un semplice script PHP nel server riceve i dati, li elabora e produce una pagina HTML consultabile da qualsiasi smartphone Android/iPhone o PC desktop

L’intervallo di interrogazione e di caricamento dei dati nel server è totalmente configurabile, 1 minuto è più che sufficiente. Lo script PHP può essere configurato per inviare email in caso di guasto o temperatura eccessiva degli inverter o semplicemente per notificare l’utente a fine giornata della produzione totale. La pagina HTML è estremamente semplice e mostra i dati cosi’ come vengono acquisiti dalla scheda NodeMCU:

Ogni blocco corrisponde ad un inverter e contiene i dati di produzione. Il blocco è verde quando tutto è ok, diventa rosso in caso di guasto o temperatura eccessiva.

NodeMCU

Il cervello del progetto è questa piccola scheda, NodeMCU, un minicomputer da 7 euro in grado di connettersi in WiFi alla rete di casa, implementa tutto lo stack TCP/IP per l’invio e ricezione di dati a server remoti, possiede 16 GPIO programmabili, una UART bidirezionale, un’altra UART solo in trasmissione, interfaccia pr SD card (opzionale) e interfaccia SPI:

Ecco i dettagli della piedinatura:

La scheda si programma tramite USB esattamente come Arduino, basta scaricare l’IDE ufficiale Arduino, installare la libreria ESP8266 (NodeMCU è essenzialmente una dev board per ESP8266) e configurare l’ambiente di sviluppo per la programmazione. Ecco un’ottima guida per iniziare. La seriale UART è mappata ai pin RX/TX e purtroppo non possono essere usati direttamente per dialogare con l’inverter che accetta RS485. Fortunatamente l’unica sostanziale differenza tra seriale UART e RS485 è soltanto nel livello fisico e non quello di protocollo percui un semplice convertitore è tutto quello che serve

Modulo RS485

Questo convertitore a basso costo trasforma il segnale UART del NodeMCU in un segnale RS485 e viceversa.

I pin A e B andranno collegati ai corrispondenti piedini A e B degli inverter nella classica configurazione in cascata mentre all’altro lato i piedini RO, DI, DE, RE andranno collegati alla scheda NodeMCU. I pin RO (Out) e DI (In) vanno collegati rispettivamente ai pin RX e TX della scheda NodeMCU. DE e RE sono piedini speciali utilizzati per abilitare la lettura o la scrittura sul doppino RS485. DE abilita il driver interno di scrittura e va impostato ad 1 quando si vuole transmettere un pacchetto dati verso gli inverter. RE abilita l’ascolto e va impostato a 0 quando si vuole ricevere un pacchetto di risposta da uno degli inverter. Siccome DE è attivo alto e RE attivo basso e siccome la comunicazione con gli inververter è half-duplex (botta e risposta con un solo master) è possibile collegare tra loro questi due pin e comandarli con un unico GPIO della scheda NodeMCU. Quando vogliamo inviare un pacchetto dati agli inverter basterà alzare il GPIO ad 1 , quando vogliamo ricevere lo impostiamo basso

Circuito

Il circuito è estremamente semplice, la scheda NodeMCU viene alimentata tramite USB da un normale alimentatore a 5v (assicuriamoci che riesca a fornire almeno 1000mA di corrente, altrimenti il driver RS485 non riuscirà a comunicare con gli inverter). I piedini TX/RX della scheda sono collegati a RO/DI del convertirore RS485. Il GPIO5 comanda la scrittura / ricezione dei dati ed è collegato ai piedini RE/DE del convertitore. Il convertitore è alimentato a 3.3V dalla scheda NodeMCU stessa. I pin A e B del convertitore vanno agli inverter

Il convertitore è alimentato a 3.3v per renderlo compatibile con i livelli elettrici dell’ UART del NodeMCU, che sono a 0-3.3v. La tensione massima prodotta dal convertitore RS485 sarà di 3.3v che è perfettamente sufficiente per dialogare con gli inverter (lo standard RS485 prevede un minimo di 1.5v, alcuni dispositivi accettano fino a 200mV):

Ecco una foto dei due moduli collegati tra loro, a sinistra la scheda NodeMCU, a destra il convertitore RS485 collegato al doppino che va agli inverter

 

Protocollo di comunicazione

Gli inverter utilizzano una variante del protocollo MODBUS in modalità half-duplex. Ciò significa che ad ogni istante di tempo c’è solo un dispositivo che “parla” sulla linea mentre gli altri “ascoltano”. Esiste un solo master ossia la scheda NodeMCU, tutti gli inverter sono slave. Il protocollo è di tipo “botta e risposta” cioè il master invia una richiesta e uno slave (un inverter) risponde: gli inverter non iniziano mai di loro iniziativa a dialogare con il master, è sempre e solo il master che interroga e riceve (eventualmente) una risposta.

Una trasmissione si compone di un singolo pacchetto MODBUS che include 7 campi:

  • header: un codice fisso 0xAA, 0xAA di preambolo che da tempo agli inverter di “mettersi in ascolto” sulla linea
  • sender address: l’indirizzo 16 bit del mittente (0x0100 è il master)
  • receiver address: indirizzo 16 bit del destinatario (0x0000 è l’indirizzo broadcast)
  • command: un codice a 16 bit che descrive uno tra 4 possibili richieste, poi vedremo quali nel dettaglio
  • payload length: 8 bit per specificare la lunghezza del prossimo campo (payload)
  • payload: il contenuto del pacchetto vero e proprio (dati di produzione degli inverter o altro)
  • CRC: il classico campo di controllo utile al ricevente per verificare la corretta ricezione del pacchetto

Esistono 4 tipi diversi di comandi:

  • comando RICHIESTA NUMERO SERIALE
  • comando ASSEGNAZIONE INDIRIZZO
  • comando RICHIESTA DATI DI PRODUZIONE
  • comando RESET

Richiesta dati di produzione

Il comando RICHIESTA DATI DI PRODUZIONE viene inviato dal master (NodeMCU) ad intervalli regolari e contiene l’indirizzo di destinazione dell’inverter che vogliamo interrogare. Il payload è vuoto. L’inverter risponderà con un pacchetto simile contenente i dati di produzione. Nel caso degli inverter Solartec si tratta di un payload di esattamente 90 byte che contiene temperatura, corrente, tensione, produzione giornaliera, produzione totale e molto altro. La corretta decodifica di questo payload va fatta caso per caso e dipende dal modello di inverter. Ogni inverter ha il suo indirizzo univoco (receiver address) ma come viene assegnato questo indirizzo? Lo vediamo nel prossimo comando.

Assegnazione indirizzo

Il comando ASSEGNAZIONE INDIRIZZO è inviato dal master in broadcast (non abbiamo ancora un indirizzo specifico al quale inviare il pacchetto!) e contiene nel payload il numero seriale dell’inverter e l’indirizzo che vogliamo assegnare, ad esempio:

1003BW0063, 0x0012

Ossia assegnamo l’indirizzo 0x0012 all’inverter con numero seriale 1003BW0063. L’inverter con questo seriale (e solo lui) risponderà  affermativamente con un ulteriore pacchetto modbus nel quale payload sarà di nuovo specificato l’indirizzo richiesto, a conferma dell’avvenuta associazione.

Il master non fa altro che inviare una richiesta di associazione per tutti gli inverter che conosce (la lista dei numeri seriali). Ma come fa il master a sapere la lista dei seriali? Ci sono due modi possibili. O la codifichiamo la lista nel firmware della scheda NodeMCU, soluzione non esattamente flessibile, oppure usiamo il prossimo comando.

Richesta numero seriale

Il comando RICHIESTA NUMERO SERIALE è inviato dal master ad intervalli regolari per “cercare” nuovi inverter sulla linea e richiederne il codice seriale. Siccome gli inverter possono accendersi e spegnersi continuamente  per via delle differenti condizioni atmosferiche o semplicemente alla sera, è necessario inviare questo pacchetto ad intervalli regolari, tipo ogni 10 secondi, e vedere quali nuovi inverter sono disponibili in linea. Il payload è vuoto e l’indirizzo di destinazione è broadcast. Non appena un inverter si accende (tipo al mattino) riceverà questo pacchetto e risponderà con il proprio seriale (nel payload della risposta ovviamente). Il master procederà quindi ad assegnare un indirizzo e poi a ciclare continuamente con le richieste di produzione.

Comando reset

Questo comando è inviato dal master al primo riavvio tre o quattro volte di fila per resettare gli inverter e annullare eventuali associazioni indirizzo precedenti. In questo modo tutti gli inverter saranno di nuovo disponibili a farsi assegnare un nuovo indirizzo. Se non inviassimo questo comando all’avvio del master, potremmo cadere nel caso sfortunato in cui il master si riavvia per qualche motivo (ad esempio una interruzione momentanea dell’alimentazione), perde memoria degli indirizzi degli inverter, ma gli inverter stessi non accettano ulteriori associazioni indirizzo perchè ne hanno già uno impostato.

 

Firmware NodeMCU

Andiamo ora a vedere il firmware della scheda NodeMCU. Il firmware è scritto in C e contiene tutto il codice per dialogare con gli inverter tramite protocollo MODBUS e per inviare i dati al backend remoto PHP.

Il cuore del firmware è questo ciclo infinito che colleziona i dati dagli inverter e poi li invia in HTTP al server remoto

void loop()
{
  int u = 0;
  
  delay(1000);
  
  // get data from inverters
  getdata();

  // upload data online
  upload();
}

La fase di setup imposta la seriale TX/RX del NodeMCU, il GPIO 2 per selezionare il modo trasmissione / ricezione dei dati, alloca la memoria e invia 3 comandi di reset per resettare le associazioni indizzo-inverter.

void setup()
{
  Serial.begin(9600);
  pinMode(gpiod2, OUTPUT);
  delay(1000);

  memset(inverters, 0, sizeof(inverters));
  
  sendpacket(0, 4, 0); // reset
  sendpacket(0, 4, 0); // reset
  sendpacket(0, 4, 0); // reset
}

La funzione GetData() non fa altro che ciclare su tutti gli inverter attuamente conosciuti e ne richiede i dati di produzione:

void getdata()
{
  int discover = 1;
  for(int slot = 0; slot < MAX_INVERTERS; slot++) { if(discover) { discovernew(); discover = 0; } if(inverters[slot] != 0) { discover = 1; t_inverter* ptr = inverters[slot]; sendpacket(ptr->address, 0x0102, 0); // data request
      int res = readpacket();

      if(res > 0)
      {
        // copy payload
        ptr->lastdatalen = res;
        for(int p = 0; p < res; p++) ptr->lastdata[p] = payload[p];
      }
      else if(res == -1) // timeout
      {
        ptr->retry++;
        if(ptr->retry == MAX_RETRY)
        {
          free(ptr);
          inverters[slot] = 0;
        }
      }
    }     
  }
}

La funzione GetNew() invece si inframezza alle richieste di produzione e prova a cercare nuovi inverter da aggiungere alla lista di quelli già conosciuti:

int discovernew()
{  
  int slot = nextempty();
    
  if(slot < 0) return -1; // no more space left sendpacket(0, 0x0000, 0); // serial request int res = readpacket(); if(res > 0)
  {
    // choose address
    int address = slot + 1;
    char name[1024];

    // copy name
    for(int n = 0; n < res; n++) name[n] = payload[n]; name[res] = 0; sendhttp("found:" + String(name)); // build payload payload[res] = address & 0xff; sendpacket(0, 0x0001, res + 1); // pairing request res = readpacket(); if(res == 1) // payload must be 1 byte long { // confirmed t_inverter* ptr = (t_inverter*)malloc(sizeof(t_inverter)); ptr->retry = 0;
      ptr->address = address;
      strcpy(ptr->name, name);
      inverters[slot] = ptr;

      return 1;
    }
  }
  return -1;
}

Le funzioni accessorie sendpacket(), readpacket() e sendhttp() sono usate rispettivamente per inviare un pacchetto MODBUS sulla linea, riceverne uno di risposta, e per inviare i dati di produzione al server remoto tramite protocollo standard HTTP. Username e password della rete WiFi sono codificati nel firmware cosi come l’indirizzo remoto della pagina PHP; una soluzione più sofisticata potrebbe prevedere una modalità di configurazione via USB nella quale specificare tutti questi parametri.

Server e funzionamento finale

La scheda NodeMCU completa del convertitore RS485 può essere alimentata direttamente dalla porta USB di uno degli inverter. Se gli inverter non hanno una porta USB basta usare un normale caricatore del telefono da almeno 1000mA.

Ovviamente deve essere presente un segnale WiFi. Se la rete non fosse presente in prossimità degli inverter è necessario portare il doppino RS485 all’interno dell’abitazione o in prossimità, nessun problema considerando che è possibile coprire un chilometro e mezzo con RS485 a 9600 baud. Il trasmettitore funziona in completa autonomia, si collega automaticamente alla rete WiFi e si ricollega in caso di connessione internet temporaneamente assente. Nel server una semplice pagina PHP riceve i dati di produzione e ripropone gli stessi dati nel browser:

La pagina HTML può essere aperta da smartphone, tablet o PC desktop da qualsiasi parte del mondo senza essere nelle vicinanze degli inverter. Inoltre è possibile configurare il server in modo tale da inviare email a fine giornata con il totale della produzione oppure email di notifica in caso di guasti o temperatura eccessiva