In questo articolo vediamo come realizzare in modo semplice un energy logger utilizzando i nostri prodotti in grado di memorizzare i dati su file locali CSV e trasferirli su server FTP in cloud o inviarli ad un broker MQTT o ad un API REST. Un energy logger è un dispositivo elettronico progettato per misurare, registrare e analizzare i consumi energetici di impianti, macchinari o edifici. È uno strumento fondamentale per il monitoraggio energetico, consentendo di raccogliere dati precisi e continui sull’uso dell’energia, al fine di ottimizzare l’efficienza e ridurre gli sprechi. Gli energy logger trovano impiego in diversi contesti:
- Industria: per monitorare il consumo energetico di macchinari e processi produttivi.
- Edifici commerciali e residenziali: per analizzare i consumi e identificare aree di inefficienza.
- Impianti fotovoltaici e di cogenerazione: per verificare la produzione e l’autoconsumo di energia.
- Audit energetici: come strumento di diagnosi per valutare le prestazioni energetiche e proporre interventi di miglioramento.
Vantaggi dell’utilizzo
- Riduzione dei costi: identificando sprechi e ottimizzando l’uso dell’energia.
- Conformità normativa: supportando le aziende nel rispetto delle normative sull’efficienza energetica.
- Sostenibilità ambientale: contribuendo alla diminuzione delle emissioni di CO₂.
- Decisioni informate: fornendo dati concreti per pianificare interventi e investimenti.

Realizzazione pratica
Vediamo come realizzare un energy logger basato sui nostri sistemi programmabili SlimLine che si interfacciano con i meter di energia Eastron tramite interfaccia RS485 Modbus. La connessione con ii meters può avvenire tramite seriale RS485 diretta oppure via TCP/IP utilizzando un convertitore Ethernet/Seriale o WiFi/Seriale. I sistemi sono liberamente programmabili con i linguaggi standard PLC secondo la normativa IEC61131-3 con il tool gratuito LogicLab.Per l’acquisizione dei valori forniamo appositi blocchi funzione da istanziare nel programma (EastronSDM120, EastronSDM630). Tramite i FB è possibile acquisire parametri come:
- Potenza attiva e reattiva
- Corrente e tensione
- Frequenza
- Fattore di potenza
- Energia consumata nel tempo
I dati raccolti possono essere memorizzati nel file system del sistema su file in formato CSV con il FB StringToLogFile, successivamente i files potranno essere scaricati da locale e/o da remoto con un cient FTP oppure è il sistema stesso che invia i file CSV direttamente su di un server FTP nel cloud con il FB FTPClient, ad un broker MQTT con il FB MQTTClient (Esempio), o ad una API REST con il FB RESTClient (Esempio).
Programma PTP211, FTPEnergyLogger
In questo programma (Distribuito con LogicLab) i dati acquisiti da due meters Eastron SDM630 sono salvati ogni 15 minuti in un file CSV. Il file è salvato nel file system del sistema SlimLine ed poi inviato ad un server FTP nel cloud. Vediamo come è suddiviso il programma.
MetersAcquisition: Esegue l’acquisizione di due meters Eastron SDM630.
DateTimeMng: Gestisce data/ora di sistema, sincronizza il real time clock con un server NTP su Internet e gestisce lo strobe di log ogni 15 minuti.
CSVDataStore: Su strobe tempo crea un file CSV con un nome del tipo “HHQDDMM.csv” dove MM (2 cifre): Mese dell’anno, DD (2 cifre): Giorno del mese, HH (2 cifre): Ora del giorno, MM (2 cifre): Minuti del giorno.Nella prima riga del file inserisce il nome delle colonne e nella seconda riga i dati acquisiti dai meters.
LogicLab (Ptp211, CSVDataStore)
PROGRAM CSVDataStore
VAR CONSTANT
BSize : UINT := 512; (* Buffer size (SysRMalloc) *)
END_VAR
VAR
i : UDINT; (* Auxiliary variable *)
DBuffer : @STRING; (* Data buffer (SysRMalloc) *)
Filename : STRING[ 32 ]; (* Log file name *)
Logger : StringToLogFile_v3; (* Log manager *)
END_VAR
// *****************************************************************************
// PROGRAM "CSVDataStore"
// *****************************************************************************
// Esegue la compilazione del file CSV con i dati in log.
// -----------------------------------------------------------------------------
// -------------------------------------------------------------------------
// INITIALIZATION
// -------------------------------------------------------------------------
// Execute program initialization.
IF (SysFirstLoop) THEN
Logger.Mode:=1; //AsciiHex mode
Logger.LDLength:=0; //Log data length
Logger.Header:=eNULL; //Header string
Logger.Filename:=ADR(Filename); //Log file
END_IF;
// -------------------------------------------------------------------------
// ATTESA STROBE ESECUZIONE
// -------------------------------------------------------------------------
// Attesa strobe esecuzione log dati.
IF (DBuffer <> eNULL) THEN eTO_JUNK(SysRMFree(ADR(DBuffer))); END_IF;
IF NOT(GBVars.LDStrobe) THEN RETURN; END_IF;
// Allocate the log string buffer.
IF NOT(SysRMAlloc(BSize, ADR(DBuffer))) THEN RETURN; END_IF;
GBVars.LDStrobe:=FALSE; //Log data strobe
// -------------------------------------------------------------------------
// MANAGE THE DISK FILE
// -------------------------------------------------------------------------
// Creo nome file di log "HHQDDMM.csv"
// MM (2 cifre): Mese dell'anno
// DD (2 cifre): Giorno del mese
// HH (2 cifre): Ora del giorno
// MM (2 cifre): Minuti del giorno
eTO_JUNK(SysVsnprintf(ADR(Filename), SIZEOF(Filename), ADR('%s\'), STRING_TYPE, ADR(GBPars.DFilePath)));
eTO_JUNK(DateTimeFormat(GBVars.LDTime, ADR('mdHi\."csv"'), ADR(Filename), SIZEOF(Filename)));
// Se file non esiste lo creo definendo i nomi delle colonne.
IF (SysGetFileLen(ADR(Filename)) = eEOF) THEN
eTO_JUNK(SysVsnprintf(DBuffer, BSize, ADR('%s;'), STRING_TYPE, ADR('TIMESTAMP')));
eTO_JUNK(SysCVsnprintf(DBuffer, BSize, ADR('%s;'), STRING_TYPE, ADR('Meter_1_Voltage')));
eTO_JUNK(SysCVsnprintf(DBuffer, BSize, ADR('%s;'), STRING_TYPE, ADR('Meter_1_Current')));
eTO_JUNK(SysCVsnprintf(DBuffer, BSize, ADR('%s;'), STRING_TYPE, ADR('Meter_1_Energy')));
eTO_JUNK(SysCVsnprintf(DBuffer, BSize, ADR('%s;'), STRING_TYPE, ADR('Meter_1_Voltage')));
eTO_JUNK(SysCVsnprintf(DBuffer, BSize, ADR('%s;'), STRING_TYPE, ADR('Meter_1_Current')));
eTO_JUNK(SysCVsnprintf(DBuffer, BSize, ADR('%s;'), STRING_TYPE, ADR('Meter_1_Energy')));
Logger(LData:=DBuffer); //FB gestione log
END_IF;
// -------------------------------------------------------------------------
// WRITE THE LOG RECORD
// -------------------------------------------------------------------------
// Initialize it with date and time.
eTO_JUNK(DateTimeFormat(GBVars.LDTime, ADR('^d/m/Y H\:i\:s\;'), DBuffer, BSize)); //TIMESTAMP 22/09/2022 16:21:08
// Insert column values separated by a ",".
eTO_JUNK(SysCVsnprintf(DBuffer, BSize, ADR('%.1f;'), REAL_TYPE, ADR(Meter[0].Voltage[3])));
eTO_JUNK(SysCVsnprintf(DBuffer, BSize, ADR('%.1f;'), REAL_TYPE, ADR(Meter[0].Current[4])));
eTO_JUNK(SysCVsnprintf(DBuffer, BSize, ADR('%.1f;'), REAL_TYPE, ADR(Meter[0].TAcEnergy)));
eTO_JUNK(SysCVsnprintf(DBuffer, BSize, ADR('%.1f;'), REAL_TYPE, ADR(Meter[1].Voltage[3])));
eTO_JUNK(SysCVsnprintf(DBuffer, BSize, ADR('%.1f;'), REAL_TYPE, ADR(Meter[1].Current[4])));
eTO_JUNK(SysCVsnprintf(DBuffer, BSize, ADR('%.1f;'), REAL_TYPE, ADR(Meter[1].TAcEnergy)));
// Separatore decimale richiesto deve essere "," sostituisco ".".
FOR i:=0 TO BSize DO
IF (eGetBYTE(DBuffer+i) = 16#00) THEN EXIT; END_IF; //Fine stringa
IF (eGetBYTE(DBuffer+i) = 16#2E) THEN eTO_JUNK(eSetBYTE(DBuffer+i, 16#2C)); END_IF;
END_FOR;
// Eseguo scrittura record di log.
Logger(LData:=DBuffer); //Store record on disk
// [End of file]
FTPDataSend: Esegue la ricerca nella cartella dove sono memorizzati i files CSV generati dal programma CSVDataStore. Per permettere la gestione dell’invio al server dei nuovi file memorizzati si antepone al nome del file un carattere dal significato:
- (#) Corrente: File corrente su cui sono memorizzati idati. Si utilizza nel caso il file contenga più registrazioni. In questo esempio il file ha sempre solo una registrazione quindi non si utilizza.
- (!) Archiviato: File già inviato al server FTP. Il file è comunque mantenuto nella cartella del sistema per sicurezza.
- (_) In errore: Questo file non è stato possibile inviarlo al server FTP.
Nel programma si itera su tutti i files presenti nella cartella e i file nuovi sono inviati al server FTP. In caso di errore invio si ritenta per un numero di tentativi e se sempre in errore il file viene segnato in errore. I files gia inviati al server con data antecedente il perido definito vengono cancellati dalla cartella.
LogicLab (Ptp211, FTPDataSend)
PROGRAM FTPDataSend
VAR
CaseNr : USINT; (* Program case *)
FTPErrors : USINT; (* FTP error counter *)
TimeBf : UDINT; (* Time buffer (mS) *)
DirWithFilter : STRING[ 32 ]; (* Directory name with filter *)
LFilename : STRING[ 64 ]; (* Local filename *)
RFilename : STRING[ 64 ]; (* Remote filename *)
DList : SysGetFileInfos; (* Directory listing *)
FTP : FTPClient_v4; (* FTP client *)
END_VAR
// *****************************************************************************
// PROGRAM "FTPDataSend"
// *****************************************************************************
// Esegue trasferimento file dati su server FTP.
// -----------------------------------------------------------------------------
// -------------------------------------------------------------------------
// INITIALIZAZTION
// -------------------------------------------------------------------------
// Program initialization.
IF (SysFirstLoop) THEN
// Definizione filtro di ricerca in directory.
DList.PathName:=ADR(DirWithFilter); //Directory to list
eTO_JUNK(SysVsnprintf(ADR(DirWithFilter), SIZEOF(DirWithFilter), ADR('%s\*.csv'), STRING_TYPE, ADR(GBPars.DFilePath)));
// Configurazione client FTP.
FTP.SpyOn:=TRUE; //Spy active
FTP.FTPServer:=ADR(GBPars.FTPServer); //Server FTP address
FTP.FTPPort:=GBPars.FTPPort; //Server FTP port
FTP.User:=ADR(GBPars.FTPUser); //User
FTP.Password:=ADR(GBPars.FTPPassword); //Password
FTP.LocalFile:=ADR(LFilename); //Local file
FTP.RemoteFile:=ADR(RFilename); //Remote file
END_IF;
// -------------------------------------------------------------------------
// FTP CLIENT MANAGEMENT
// -------------------------------------------------------------------------
// On FTP error set the parking sequence in waiting to retry the
// connection. In this phase the log records are saved in the FIFO.
FTP(); //FTP client
IF (FTP.Fault) THEN CaseNr:=200; END_IF;
// -------------------------------------------------------------------------
// DIRECTORY LISTING MANAGEMENT
// -------------------------------------------------------------------------
// Manage the directory listing.
DList(); //Directory listing
DList.Init:=FALSE; //Init listing
DList.Next:=FALSE; //Next command
// -------------------------------------------------------------------------
// PROGRAM CASES
// -------------------------------------------------------------------------
// Program cases.
CASE (CaseNr) OF
// ---------------------------------------------------------------------
// INIZIALIZZAZIONE
// ---------------------------------------------------------------------
// Inizializzo trasferimento in FTP.
0:
TimeBf:=SysTimeGetMs(); //Time buffer (mS)
CaseNr:=CaseNr+1; //Program case
// ---------------------------------------------------------------------
// Attendo tempo di pausa su ricerca file da inviare.
1:
IF ((SysTimeGetMs()-TimeBf) < TO_UDINT(GBPars.FTPDelay)) THEN RETURN; END_IF;
CaseNr:=CaseNr+1; //Program case
// ---------------------------------------------------------------------
// Inizializzo listing directory.
2:
DList.Init:=TRUE; //Init listing
CaseNr:=10; //Program case
// ---------------------------------------------------------------------
// CONTROLLO SE FILE PRESENTE
// ---------------------------------------------------------------------
// Se nessun file presente termino.
10:
IF NOT(DList.Found) THEN CaseNr:=0; RETURN; END_IF;
// Controllo se directory.
IF (DList.IsDir) THEN DList.Next:=TRUE; RETURN; END_IF;
// Definisco percorso e nome file locale.
eTO_JUNK(SysVsnprintf(ADR(LFilename), SIZEOF(LFilename), ADR('%s/'), STRING_TYPE, ADR(GBPars.DFilePath)));
eTO_JUNK(SysCVsnprintf(ADR(LFilename), SIZEOF(LFilename), ADR('%s'), STRING_TYPE, DList.Name));
// Controllo se file da cancellare.
IF (DList.FTime < (SysDateTime-(TO_UDINT(GBPars.FileLTime)/1000))) THEN
eTO_JUNK(SysFileRemove(ADR(LFilename))); //File remove
DList.Next:=TRUE; //Next command
RETURN;
END_IF;
// Scarto il files corrente, se archiviato ed in errore.
IF (eGetBYTE(DList.Name) = 16#21) THEN DList.Next:=TRUE; RETURN; END_IF; //(!) Archiviato
IF (eGetBYTE(DList.Name) = 16#23) THEN DList.Next:=TRUE; RETURN; END_IF; //(#) Corrente
IF (eGetBYTE(DList.Name) = 16#5F) THEN DList.Next:=TRUE; RETURN; END_IF; //(_) In errore
// Definisco percorso e nome file remoto.
// Antepongo anno davanti al nome del file per generare anno a 4 cifre.
eTO_JUNK(DateTimeFormat(TO_LDATE_AND_TIME(SysDateGetNs()), ADR('^Y'), ADR(RFilename), SIZEOF(RFilename)));
eTO_JUNK(SysCVsnprintf(ADR(RFilename), SIZEOF(RFilename), ADR('%s'), STRING_TYPE, DList.Name));
FTP.Store:=TRUE; //Store command
CaseNr:=100; //Program case
// ---------------------------------------------------------------------
// ESEGUO TRASFERIMENTO
// ---------------------------------------------------------------------
// Controllo se fine trasferimento.
100:
IF NOT(FTP.Done) THEN RETURN; END_IF;
FTP.Store:=FALSE; //Store command
FTPErrors:=0; //FTP error counter
// Rinomino file locale anteponendo "!" per identificarlo come inviato.
// Uso "RFilename" come buffer di appoggio nome file.
eTO_JUNK(SysVsnprintf(ADR(RFilename), SIZEOF(RFilename), ADR('%s/'), STRING_TYPE, ADR(GBPars.DFilePath)));
eTO_JUNK(SysCVsnprintf(ADR(RFilename), SIZEOF(RFilename), ADR('!%s'), STRING_TYPE, DList.Name));
eTO_JUNK(SysFileRename(ADR(LFilename), ADR(RFilename)));
CaseNr:=0; //Program case
// ---------------------------------------------------------------------
// FTP SERVER ERROR
// ---------------------------------------------------------------------
// Arrivo se trasferimento FTP in errore.
200:
FTP.Store:=FALSE; //Store command
FTPErrors:=FTPErrors+1; //FTP error counter
// Se superato numero errori rinomino file locale.
// Rinomino file locale anteponendo "_" per identificarlo come errore.
// Uso "RFilename" come buffer di appoggio nome file.
IF (FTPErrors > 3) THEN
eTO_JUNK(SysVsnprintf(ADR(RFilename), SIZEOF(RFilename), ADR('%s/'), STRING_TYPE, ADR(GBPars.DFilePath)));
eTO_JUNK(SysCVsnprintf(ADR(RFilename), SIZEOF(RFilename), ADR('_%s'), STRING_TYPE, DList.Name));
eTO_JUNK(SysFileRename(ADR(LFilename), ADR(RFilename)));
CaseNr:=0; //Program case
RETURN;
END_IF;
// Inizializzo temporizzazione per retry.
TimeBf:=SysTimeGetMs(); //Time buffer (mS)
CaseNr:=CaseNr+1; //Program case
// ---------------------------------------------------------------------
// Wait a while before to retry.
201:
IF ((SysTimeGetMs()-TimeBf) < TO_UDINT(T#5m)) THEN RETURN; END_IF;
FTP.Store:=TRUE; //Store command
CaseNr:=100; // Program case
END_CASE;
// [End of file]
Programma PTP212, RESTEnergyLogger
In questo programma (Distribuito con LogicLab) i dati acquisiti da due meters Eastron SDM630 sono inviati ogni 15 minuti ad una API REST sul cloud, utilizzando il FB RESTClient. In realtà i dati sono memorizzati in un registro FIFO su file ed inviati al server solo se possibile. Questo permette nel caso di problemi di cominicazione con il server di mantenere tutte le acquisizioni con il relativo timestamp. Vediamo come è suddiviso il programma.
MetersAcquisition: Esegue l’acquisizione di due meters Eastron SDM630.
DateTimeMng: Gestisce data/ora di sistema, sincronizza il real time clock con un server NTP su Internet e gestisce lo strobe di log ogni 15 minuti.
JSONDataStore: Su strobe tempo crea un record JSON con tutte le misure evvettuate e memorizza il record nel registro FIFO.
LogicLab (Ptp212, JSONDataStore)
PROGRAM JSONDataStore
VAR CONSTANT
BSize : UINT := 1024; (* Buffer size (SysRMalloc) *)
END_VAR
VAR
DBuffer : @STRING; (* Data buffer (SysRMalloc) *)
END_VAR
// *****************************************************************************
// PROGRAM "JSONDataStore"
// *****************************************************************************
// Creo record JSON e lo memorizza nel registro FIFO.
// -----------------------------------------------------------------------------
// -------------------------------------------------------------------------
// ATTESA STROBE ESECUZIONE
// -------------------------------------------------------------------------
// Attesa strobe esecuzione log dati.
IF (DBuffer <> eNULL) THEN eTO_JUNK(SysRMFree(ADR(DBuffer))); END_IF;
IF NOT(GBVars.LDStrobe) THEN RETURN; END_IF;
// Allocate the log string buffer.
IF NOT(SysRMAlloc(BSize, ADR(DBuffer))) THEN RETURN; END_IF;
GBVars.LDStrobe:=FALSE; //Log data strobe
// -------------------------------------------------------------------------
// RECORD DATI ENERGETICI
// -------------------------------------------------------------------------
// Compilo record JSON con dati energetici.
eTO_JUNK(JSONEncoder(DBuffer, BSize, ADR('Meter_1_Voltage'), REAL_TYPE, ADR(Meter[0].Voltage[3]), 1));
eTO_JUNK(JSONEncoder(DBuffer, BSize, ADR('Meter_1_Current'), REAL_TYPE, ADR(Meter[0].Current[4]), 1));
eTO_JUNK(JSONEncoder(DBuffer, BSize, ADR('Meter_1_Energy'), REAL_TYPE, ADR(Meter[0].TAcEnergy), 1));
eTO_JUNK(JSONEncoder(DBuffer, BSize, ADR('Meter_2_Voltage'), REAL_TYPE, ADR(Meter[1].Voltage[3]), 1));
eTO_JUNK(JSONEncoder(DBuffer, BSize, ADR('Meter_2_Current'), REAL_TYPE, ADR(Meter[1].Current[4]), 1));
eTO_JUNK(JSONEncoder(DBuffer, BSize, ADR('Meter_2_Energy'), REAL_TYPE, ADR(Meter[1].TAcEnergy), 1));
RDFIFO(In:=TRUE, Dp:=DBuffer, Dls:=Sysstrlen(DBuffer)); //Write record on RDFIFO
eTO_JUNK(SysWrSpyData(SPY_ASCII, 0, 16#00000001, ADR('JStore[3]'), DBuffer));
// [End of file]
RESTDataSend: Controlla se dati nel registro FIFO e li invia al server REST. Se invio correttamente eseguito elimina dal registro FIFO il record inviato:
LogicLab (Ptp212, RESTDataSend)
PROGRAM RESTDataSend
VAR
i : UDINT; (* Auxiliary variable *)
RESTAnswer : STRING[ 128 ]; (* REST answer *)
TCPClient : SysTCPClient; (* TCP client management *)
HTTPRq : HTTPClient_v5; (* HTTP client *)
REST : RESTClient_v7; (* REST service client *)
END_VAR
// *****************************************************************************
// PROGRAM "RESTDataSend"
// *****************************************************************************
// Invio dati ad API REST.
// -----------------------------------------------------------------------------
// -------------------------------------------------------------------------
// PROGRAM INIT
// -------------------------------------------------------------------------
// Executed at first program execution, all variables are initialized.
IF (SysFirstLoop) THEN
// If "RDFIFOFilename" it's not defined the data are stored in memory
// instead of a file on disk. Stored data are lost on system power off.
// If "RDFIFOIDx" it's not defined the index are stored internally of the
// FB. Stored data are lost on power off.
RDFIFO.FIFOFilename:=ADR('D:/REST.bin'); //Path and name of RDFIFO file
RDFIFO.FIFOSize:=24000; //RDFIFO file size
RDFIFO.FIFOIDx:=ADR(FIFOIDx); //RDFIFO indexes
// Set TCPClient parameters.
TCPClient.PeerAdd:=ADR('server.com'); //Peer address
TCPClient.PeerPort:=80; //Peer port
TCPClient.LocalAdd:=ADR('0.0.0.0'); //Local address
TCPClient.LocalPort:=0; //Local port
TCPClient.FlushTm:=50; //Flush time (mS)
TCPClient.LifeTm:=20; //Life time (S)
TCPClient.RxSize:=512; //Rx buffer size
TCPClient.TxSize:=512; //Tx buffer size
// Set HTTPClient parameters.
HTTPRq.SpyOn:=FALSE; //Activate the spy
HTTPRq.KeepAlive:=FALSE; //HTTP keep-alive
HTTPRq.RMethod:=HTTP_REQUEST#HTTP_POST; //Request method
HTTPRq.HostName:=ADR('server.com'); // Hostname
HTTPRq.Page:=ADR('page'); //Web page
HTTPRq.Header:=ADR('Content-Type:application/json$r$n'); //HTTP header
HTTPRq.DBSize:=512; //Data buffer size
HTTPRq.Timeout:=T#10s; //Execution timeout
// REST definitions.
REST.SpyOn:=TRUE; //Spy On
REST.BLength:=512; //REST Request/Answer buffers length
REST.Delay:=T#2s; //Delay time
REST.HBitTime:=T#30s; //Heartbeat time
// REST auxiliary object references.
REST.FIFOFile:=ADR(RDFIFO); //RDFIFO on file
REST.HTTPClient:=ADR(HTTPRq); //HTTP Client
END_IF;
// -------------------------------------------------------------------------
// REST CLIENT MANAGEMENT
// -------------------------------------------------------------------------
// Here the REST client is managed, it's always enabled.
TCPClient(Connect:=HTTPRq.Connect); //TCPClient management
HTTPRq(File:=TCPClient.File); //HTTP client
REST(Enable:=TRUE); //REST client management
REST.DDelete:=FALSE; //Delete data from RDFIFO
// -------------------------------------------------------------------------
// ERROR MANAGEMENT
// -------------------------------------------------------------------------
// On error it's possible to count the retries and then decide what to do.
IF (REST.SvcError) THEN
// After 3 retries the message to be sent to the REST server is removed
// from the RDFIFO register. Before to remove the message it's returned
// to the spy console.
IF (REST.Retries > 3) THEN
RDFIFO(Out:=TRUE, Dp:=eNULL, Dls:=0); //Read record length
IF NOT(SysRMAlloc(RDFIFO.Dl+1, ADR(RDFIFO.Dp))) THEN RETURN; END_IF;
RDFIFO(Out:=TRUE, Dls:=RDFIFO.Dl); //Read record data
i:=SysWrSpyData(SPY_ASCII, 0, 16#00000001, ADR('-Delete-'), RDFIFO.Dp);
i:=SysRMFree(ADR(RDFIFO.Dp)); //Free malloc memory
REST.DDelete:=TRUE; //Delete data from RDFIFO
END_IF;
END_IF;
// -------------------------------------------------------------------------
// RECEIVED VARIABLES ACQUISITION
// -------------------------------------------------------------------------
// When answer is received decodes it's value and store it on variable.
// The REST server answer will be {"Result":"xxxx"}
IF (REST.SvcOk AND (REST.PBuffer <> eNULL)) THEN
// Copy the received data to buffer.
i:=Sysmemset(ADR(RESTAnswer), 0, SIZEOF(RESTAnswer));
i:=Sysstrlen(REST.PBuffer);
IF (i > SIZEOF(RESTAnswer)) THEN i:=SIZEOF(RESTAnswer); END_IF;
eTO_JUNK(Sysmemmove(ADR(RESTAnswer), REST.PBuffer, i));
END_IF;
// [End of file]