Progetto Interfaccia X RPS/3 con sistema Arduino

Sistemi elettronici di controllo e monitoraggio, Arduino, Rasberry ecc.

Moderatori: gasala50, FabioR

FabioR
Messaggi: 125
Iscritto il: ven set 30, 2011 8:11 am

Re: Interfaccia Web per Rotex RPS/2 e RPS/3

Messaggioda FabioR » dom ott 09, 2011 5:11 pm

Allora, ci sono quasi
Quello che segue è il codice per arduino e per un po' funziona, anche se non sempre la stringa è corretta: a volte mancano i primi due campi.
La fine della stringa però dovrei prenderla giusta, con il carattere ascii 13

Devo ancora vedere meglio come leggere da seriale, ma poichè il pin rx di arduino è condiviso con l'usb con cui lo programmo e debuggo non è facile. E per di più devo fare due rampe di scale dopo ogni correzione.

A parte questo, i dati su mysql, almeno per un po', li sta salvando.
Dovrebbe anche salvarli sulla microSD, ma ho ancora qualche problema (anche se riesco a scrivere correttamente sulla scheda).
All'avvio si sincronizza via ntp con il server dell'ora, e usa l'ora interna per creare il record sul file csv nella SD

/*

Save Rotex RSP3 data to SD card and mysql database
Use NTP time provider to sync internal time

*/

#include <SPI.h>
#include <Ethernet.h>
#include <Udp.h>
#include <SD.h>
#include <Time.h>

// Network stuff
byte mac[] = {
0x90, 0xA2, 0xDA, 0x00, 0x66, 0x38 }; //Arduino MAC address
byte ip[] = {
192,168,1,177 }; //Arduino IP address
byte gateway[] = {
192,168,1,250 }; //Network gateway
byte mask[] = {
255,255,255,0 }; //Network netmask

// NTP stuff
unsigned int localPort = 8888; // local port to listen for UDP packets
byte timeServer[] = {
192, 43, 244, 18 }; //NTP server address
const int NTP_PACKET_SIZE= 48; // NTP time stamp
byte packetBuffer[ NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
const long timeZoneOffset = 3600; // set this to the offset in seconds to your local time;

// Web client stuff
byte server[] = {
192,168,12,8 }; //Web server address
//Client client(server, 82); //ip,port (usually 80)

// On the Ethernet Shield, CS is pin 4. Note that even if it's not
// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
// 53 on the Mega) must be left as an output or the SD library
// functions will not work.
const int chipSelect = 4;

boolean SDpresent=false;

#define STRINGTERMINATOR 13 //define end of string
#define BUFFERSIZE 30 //max string lenght
char ReadBuffer[BUFFERSIZE+1]; //Add 1 for NULL terminator

void setup(){

// start Ethernet and UDP
Ethernet.begin(mac, ip, gateway, mask);
Udp.begin(localPort);

//start serial
Serial.begin(9600);

//start SD
Serial.println("Initializing SD card...");
// make sure that the default chip select pin is set to
// output, even if you don't use it:
pinMode(10, OUTPUT);

// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
SDpresent=false;
}
else {
Serial.println("card initialized.");
SDpresent=true;
SDlog("card initialized.");
}

//Sync time and date
setSyncProvider(getNtpTime);
setSyncInterval(3601);
while(timeStatus()== timeNotSet) {
Serial.println("Synching Clock"); // wait until the time is set by the sync provider
SDlog("Synching Clock");
}
delay(1000);
}

void loop(){

while(!Serial.available()){
Serial.println("Waiting for serial");
SDlog("Waiting for serial");
}

if(getSerialString()){

String RPS3data=ReadBuffer;
RPS3data=RPS3data.trim();

WebClient(RPS3data); //Save to db

//Save to SD
if(SDpresent){
String ora=hour();
String minuti=formatDigits(minute());
String secondi=formatDigits(second());
String giorno=day();
String mese=month();
String anno=year();
String record=ora+":"+minuti+":"+secondi+" "+giorno+" "+mese+" "+anno+";"+RPS3data;
Serial.println(record);
SDwrite(record);
}
delay(500);
}
}

/*******************************************************************************
* WebClient function
*******************************************************************************/
void WebClient(String webString){

Client client(server, 82); //ip,port (usually 80)
if (client.connect()) {
Serial.println("connected");
SDlog("connected");
// Make a HTTP request:
client.println("GET /rotex.php?user=username&password=password&data=" + webString + " HTTP/1.0");
client.println();
}
else {
// if you didn't get a connection to the server:
Serial.println("connection failed");
SDlog("connection failed");
}
Serial.println("disconnecting.");
SDlog("disconnecting.");
client.stop();
}

/*******************************************************************************
* Get NTP time function
*******************************************************************************/
unsigned long getNtpTime() {

sendNTPpacket(timeServer); // send an NTP packet to a time server

// wait to see if a reply is available
delay(1000);
if ( Udp.available() ) {
Udp.readPacket(packetBuffer,NTP_PACKET_SIZE); // read the packet into the buffer

//the timestamp starts at byte 40 of the received packet and is four bytes,
// or two words, long. First, esxtract the two words:

unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
// combine the four bytes (two words) into a long integer
// this is NTP time (seconds since Jan 1 1900):
unsigned long secsSince1900 = highWord << 16 | lowWord;
const unsigned long seventyYears = 2208988800UL - timeZoneOffset;
// subtract seventy years:
return secsSince1900 - seventyYears;
}
return 0; // return 0 if unable to get the time
}

/*******************************************************************************
* send an NTP request to the time server at the given address
*******************************************************************************/
// send an NTP request to the time server at the given address
unsigned long sendNTPpacket(byte *address){
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;

// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
Udp.sendPacket( packetBuffer,NTP_PACKET_SIZE, address, 123); //NTP requests are to port 123
}
/*******************************************************************************
* Write to SD card function
*******************************************************************************/
void SDwrite(String SDString){
// make a string for assembling the data to log:

// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
File dataFile = SD.open("rotex.csv", FILE_WRITE);

// if the file is available, write to it:
if (dataFile){
dataFile.println(SDString);
dataFile.close();
// print to the serial port too:
//Serial.println(SDString);
}
// if the file isn't open, pop up an error:
else {
Serial.println("error opening rotex.csv");
}
}
/*******************************************************************************
* log to SD card function
*******************************************************************************/
void SDlog(String SDString){
// make a string for assembling the data to log:
if(SDpresent){
File dataFile = SD.open("log.txt", FILE_WRITE);

// if the file is available, write to it:
if (dataFile){
dataFile.println(SDString);
dataFile.close();
}
// if the file isn't open, pop up an error:
else {
Serial.println("error opening rotex.csv");
}
}
}
/*******************************************************************************
* Format minutes and seconds
*******************************************************************************/
String formatDigits(int digits){
if(digits < 10){
String dig = digits;
return "0"+dig;
}
else {
String dig = digits;
return dig;
}
}
/*******************************************************************************
* Read from serial
*******************************************************************************/
boolean getSerialString(){
byte ReadIndex = 0; //was static
while(Serial.available()>0){
char incomingbyte = Serial.read();
//Let's check our index here, and abort if we're outside our buffer size
//We use our define here so our buffer size can be easily modified
if(ReadIndex==BUFFERSIZE){
//Oops, our index is pointing to an array element outside our buffer.
ReadIndex = 0;
break;
}
if(incomingbyte==STRINGTERMINATOR){
ReadBuffer[ReadIndex] = 0; //null terminate the C string
//Our data string is complete. return true
return true;
}
else{
ReadBuffer[ReadIndex++] = incomingbyte;
ReadBuffer[ReadIndex] = 0; //null terminate the C string
}
}
//We've read in all the available Serial data, and don't have a valid string yet, so return false
return false;
}

FabioR
Messaggi: 125
Iscritto il: ven set 30, 2011 8:11 am

Re: Interfaccia Web per Rotex RPS/2 e RPS/3

Messaggioda FabioR » ven ott 14, 2011 6:15 pm

Funziona!!

sono ripartito quasi da zero, implementando solo le funzioni base.
Ho escluso per ora le gestione dell'ora e della SD.
Ho usato una gestione più rigorosa delle stringhe, come array di char.
Ho provato anche ad usare i puntatori.

Soprattutto ho trovato una libreria che emula una seriale usando le altre porte digitali di arduino, permettendomi di usare la seriale built-in per il debug.

questo è il codice minimo, che funziona perfettamente

Codice: Seleziona tutto

/* test solo web client */

#include <SPI.h>
#include <Ethernet.h>
#include <NewSoftSerial.h>

//Network stuff
byte mac[]={ 0x90, 0xA2, 0xDA, 0x00, 0x66, 0x38 };
byte ip[]={ 192,168,1,177 };
byte gateway[]={ 192,168,1,250 };
byte mask[]={ 255,255,255,0 };

//Web client stuff
byte server[]={ 192,168,12,8 };

//Serial stuff
const char EndChar=13;
const unsigned int BufferSize=35;
unsigned int i = 0;
boolean getSerialString=false;
NewSoftSerial mySerial(2,3); //rx,tx

void setup(){

  //start Ethernet and UDP
  Ethernet.begin(mac, ip, gateway, mask);

  //start serial
  Serial.begin(9600);
  mySerial.begin(9600);
 
  delay(1000);
 
  Serial.println("Arduino started");
}

void loop(){
  Serial.println("-------------------");
  Serial.println("Main loop started");
  Serial.println();
 
  mySerial.flush();
  while (mySerial.available()==0){};
  Serial.println("Serial data available");
 
  i=0;
  char serInString[BufferSize+1];
  getSerialString=false;
 
  while ((mySerial.available()>0)&&(i<=BufferSize)){
   char incomingbyte=mySerial.read();
   Serial.print("Incoming char: ");
   Serial.println(incomingbyte);
   if (incomingbyte==EndChar){
        serInString[i]=0;
      getSerialString=true;
      Serial.println("End char found: processing data");
      break;
   }
   else{
     serInString[i]=incomingbyte;
     i++;
     Serial.print("i= ");
     Serial.println(i);
   }
  }
  Serial.print("Received string: ");
  Serial.println(serInString);
  mySerial.flush();
  if (getSerialString) WebClient(serInString); //Save to db 
}

void WebClient(char *strArray){
   
  Client client(server, 82);
  Serial.print("Web request: ");
  Serial.println(String(strArray));
  if (client.connect()){
    client.println("GET /rotex.php?user=user&password=pass&data="+String(strArray)+" HTTP/1.0");
    client.println();
  }
  client.stop();
}


STAFF
Site Admin
Messaggi: 1850
Iscritto il: mar nov 27, 2007 7:44 pm
Contatta:

Progetto Interfaccia X RPS/3 con sistema Arduino

Messaggioda STAFF » sab ott 15, 2011 9:06 am

Questo tread è dedicato al progetto che verte alla realizzazione di una interfaccia che utilizzi Arduino come sistema di acquisizione e memorizzazione dei dati .

L'idea e' quella di realizzare un complesso HD e software in grado di raccogliere i dati via seriale dalla centralina Rotex originale RPS/3 e di memorizzarli in una schedina SD.


Suggerisco di definire ogni script con un numero di versione incrementale, allo scopo di non fare confusione con gli aggiornamenti.

F.

FabioR
Messaggi: 125
Iscritto il: ven set 30, 2011 8:11 am

Re: Progetto Interfaccia X RPS/3 con sistema Arduino

Messaggioda FabioR » lun ott 17, 2011 7:53 am

Ho la soluzione in funzione :mrgreen:
Sto sviluppando la parte web. Conosco molto poco il php, ma per fortuna me la cavo bene con SQL (preferirei oracle ma mi accontento) per cui tutte le elaborazioni dati le faccio fare al DB con apposite viste.
Da qui in avanti descriverò il lavoro fatto, compreso il codice e le query.
Un'anteprima si può vedere qui
http://cicuci.dnsalias.com/solar_data.php
Abbiate pietà per la veste grafica, ma il web design è proprio l'ultima cosa che so fare :mrgreen:

FabioR
Messaggi: 125
Iscritto il: ven set 30, 2011 8:11 am

Re: Progetto Interfaccia X RPS/3 con sistema Arduino

Messaggioda FabioR » lun ott 17, 2011 10:24 am

HARDWARE

Io ho comprato l'arduino ethernet, che integra già la porta ethernet e il lettore SD card.
La stessa cosa si può fare con un arduino UNO più shield ethernet.
Il costo è intorno ai 50€ ma sulla baia si può trovare anche a meno.
Ho aggiunto un alimentatore cinese con uscita variabile: l'arduino può essere alimentato dai 7V ai 12V. Io uso i 9V.
Una scatoletta in plastica completa il tutto. Si trovano già pronte per arduino (in realtà sono perfette per arduino + shield ethernet, un po' meno per l'arduino ethernet).

Ho recuperato un vecchio cavetto audio con jack stereo da 3.5 e ho utilizzato solo la massa e il filo bianco, che corrisponde al TX della RPS3.
Le porte di arduino già funzionano in ttl quindi non è necessario nessun adattatore per collegarsi alla Rotex.

FabioR
Messaggi: 125
Iscritto il: ven set 30, 2011 8:11 am

Re: Progetto Interfaccia X RPS/3 con sistema Arduino

Messaggioda FabioR » lun ott 17, 2011 12:20 pm

DATABASE

Per memorizzare i dati uso mysql. Su arduino i dati vengono salvati anche sulla scheda SD sotto forma di un file CSV ma solo per backup.

Su mysql ho creato la seguente tabella

Codice: Seleziona tutto

DROP TABLE IF EXISTS `rotex`.`Produzione`;
CREATE TABLE  `rotex`.`Produzione` (
  `Data` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `HA` tinyint(1) NOT NULL COMMENT 'Manuale/Automatico',
  `BK` tinyint(1) NOT NULL COMMENT 'Blocco Bruciatore',
  `Pompa1` smallint(5) unsigned NOT NULL COMMENT '%',
  `Pompa2` tinyint(1) NOT NULL COMMENT 'ON/OFF',
  `TCollettore` float NOT NULL COMMENT 'TK °C',
  `TRitorno` float NOT NULL COMMENT 'TR °C dal bollitore',
  `TBollitore` float NOT NULL COMMENT 'TS °C',
  `TMandata` float NOT NULL COMMENT 'TV °C dal collettore',
  `Portata` float NOT NULL COMMENT 'l/min',
  `Potenza` float NOT NULL COMMENT 'KW',
  `Energia` float NOT NULL COMMENT 'KWh',
  PRIMARY KEY (`Data`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;


Ho poi creato una serie di viste con cui interrogo il database per presentare dei riepiloghi dei dati, o per calcolare l'energia prodotta.
Le query sono le seguenti
total_energy
Mostra la produzione totale e i massimi da quando raccolgo i dati

Codice: Seleziona tutto

select sum(((`Produzione`.`Potenza` * 60) / 3600)) AS `Energia`,
max(`Produzione`.`Potenza`) AS `MaxPotenza`,
max(`Produzione`.`TBollitore`) AS `MaxBollitore`,
max(`Produzione`.`TCollettore`) AS `MaxCollettore`
from `Produzione`;

yearly_energy
mostra energia e massimi su base annuale

Codice: Seleziona tutto

select year(`Produzione`.`Data`) AS `Data`,
sum(((`Produzione`.`Potenza` * 60) / 3600)) AS `Energia`,
max(`Produzione`.`Potenza`) AS `MaxPotenza`,
max(`Produzione`.`TBollitore`) AS `MaxBollitore`,
max(`Produzione`.`TCollettore`) AS `MaxCollettore`
from `Produzione`
group by year(`Produzione`.`Data`)
order by year(`Produzione`.`Data`) desc;

monthly_energy
su base mensile

Codice: Seleziona tutto

select date_format(`Produzione`.`Data`,'%m-%Y') AS `Data`,
sum(((`Produzione`.`Potenza` * 60) / 3600)) AS `Energia`,
max(`Produzione`.`Potenza`) AS `MaxPotenza`,
max(`Produzione`.`TBollitore`) AS `MaxBollitore`,
max(`Produzione`.`TCollettore`) AS `MaxCollettore`
from `Produzione`
group by year(`Produzione`.`Data`),
month(`Produzione`.`Data`)
order by year(`Produzione`.`Data`) desc,
month(`Produzione`.`Data`) desc;

daily_energy
su base giornaliera

Codice: Seleziona tutto

select date_format(`Produzione`.`Data`,'%d-%m-%Y') AS `Data`,
sum(((`Produzione`.`Potenza` * 60) / 3600)) AS `Energia`,
max(`Produzione`.`Potenza`) AS `MaxPotenza`,
max(`Produzione`.`TBollitore`) AS `MaxBollitore`,
max(`Produzione`.`TCollettore`) AS `MaxCollettore`
from `Produzione`
group by year(`Produzione`.`Data`),
month(`Produzione`.`Data`),
dayofmonth(`Produzione`.`Data`)
order by year(`Produzione`.`Data`) desc,
month(`Produzione`.`Data`) desc,
dayofmonth(`Produzione`.`Data`) desc;

daily_sample_number
per tenere sotto controllo il numero di campionamenti giornalieri

Codice: Seleziona tutto

select date_format(`Produzione`.`Data`,'%d-%m-%Y') AS `Data`,
count(*) AS `Campioni`
from `Produzione`
group by year(`Produzione`.`Data`),
month(`Produzione`.`Data`),
dayofmonth(`Produzione`.`Data`)
order by year(`Produzione`.`Data`) desc,
month(`Produzione`.`Data`) desc,
dayofmonth(`Produzione`.`Data`) desc;

current_data
si appoggia alla sotto query per mostrare gli ultimi valori registrati, e mostrare lo stato corrente del sistema

Codice: Seleziona tutto

select date_format(`P1`.`Data`,'%H:%i:%s ') AS `Ora`,
`P1`.`HA` AS `HA`,
`P1`.`BK` AS `BK`,
`P1`.`Pompa1` AS `Pompa1`,
`P1`.`Pompa2` AS `Pompa2`,
`P1`.`TCollettore` AS `TCollettore`,
`P1`.`TRitorno` AS `TRitorno`,
`P1`.`TBollitore` AS `TBollitore`,
`P1`.`TMandata` AS `TMandata`,
`P1`.`Portata` AS `Portata`,
`P1`.`Potenza` AS `Potenza`
from (`Produzione` `P1` join `last_date` `P2` on((`P2`.`Data` = `P1`.`Data`)));

la sotto query è last_date

Codice: Seleziona tutto

select max(`Produzione`.`Data`) AS `Data`
from `Produzione`;
Ultima modifica di FabioR il lun ott 17, 2011 12:24 pm, modificato 1 volta in totale.

FabioR
Messaggi: 125
Iscritto il: ven set 30, 2011 8:11 am

Re: Progetto Interfaccia X RPS/3 con sistema Arduino

Messaggioda FabioR » lun ott 17, 2011 12:23 pm

hourly_data
contiene le medie orarie dei dati e viene utilizzata per mostrare il grafico di produzione del giorno in corso

Codice: Seleziona tutto

select cast(`Produzione`.`Data` as date) AS `data`,
hour(`Produzione`.`Data`) AS `ora`,
avg(`Produzione`.`TCollettore`) AS `TCollettore`,
avg(`Produzione`.`TRitorno`) AS `TRitorno`,
avg(`Produzione`.`TBollitore`) AS `TBollitore`,
avg(`Produzione`.`TMandata`) AS `TMandata`,
avg(`Produzione`.`Portata`) AS `Portata`,
avg(`Produzione`.`Potenza`) AS `Potenza`,
sum(((`Produzione`.`Potenza` * 60) / 3600)) AS `Energia`
from `Produzione`
group by year(`Produzione`.`Data`),
month(`Produzione`.`Data`),
dayofmonth(`Produzione`.`Data`),
hour(`Produzione`.`Data`)
order by year(`Produzione`.`Data`) desc,
month(`Produzione`.`Data`) desc,
dayofmonth(`Produzione`.`Data`) desc,
hour(`Produzione`.`Data`);

FabioR
Messaggi: 125
Iscritto il: ven set 30, 2011 8:11 am

Re: Progetto Interfaccia X RPS/3 con sistema Arduino

Messaggioda FabioR » lun ott 17, 2011 12:33 pm

CODICE ARDUINO

Questa è la versione corrente del codice che sto usando.
Ho utilizzato due librerie aggiuntive rispetto alla dotazione standard dell'IDE di arduino:
    Time
    NewSoftSerial
Si possono trovare e scaricare facilmente. Basta copiare le due directory nella cartella "libraries" dell'IDE di arduino
NewSoftSerial mi permette di emulare una seconda porta COM, in modo da poter utilizzare la principale per il debug dell'applicazione (è quella utilizzata dalla connessione USB di arduino).
Tutte le istruzioni "Serial.println()" sono commentate perchè sono state utilizzate per il debug del software. Attenzione ad attivarne troppe perchè si rischia uno stack overflow con il riavvio di arduino.

Codice: Seleziona tutto

/*

 Save Rotex RSP3 data to SD card and mysql database
 Use NTP time provider to sync internal time
 Fabio Roverso 15/10/11
 V 1.0
 
*/

#include <SPI.h>
#include <Ethernet.h>
#include <NewSoftSerial.h>
#include <Udp.h>
#include <SD.h>
#include <Time.h>

//Network stuff
byte mac[]={ 0x90, 0xA2, 0xDA, 0x00, 0x66, 0x38 }; //Arduino MAC address
byte ip[]={ 192,168,1,177 }; //Arduino IP address
byte gateway[]={ 192,168,1,250 }; //Network gateway
byte mask[]={ 255,255,255,0 }; //Network netmask

//NTP stuff
byte timeServer[]={ 192, 168, 1, 8 }; //NTP server address
unsigned int localPort=8888; //local port to listen for UDP packets
const int NTP_PACKET_SIZE=48; //NTP time stamp
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
const unsigned long timeZoneOffset=3600; //set this to the offset in seconds to your local time;

//Web client stuff
byte server[]={ 192,168,12,8 }; //Web server address

//Serial stuff
NewSoftSerial mySerial(2,3); //Initialize 2nd serial port (rx,tx)
const char EndChar=13; //End of transmission
const unsigned int BufferSize=40; //Max transmission lenght
unsigned int i=0; //Buffer index
boolean getSerialString=false;

//SD Stuff
//On the Ethernet Shield, CS is pin 4. Note that even if it's not
//used as the CS pin, the hardware CS pin (10 on most Arduino boards,
//53 on the Mega) must be left as an output or the SD library
//functions will not work.
const int chipSelect = 4;
boolean SDpresent=false;

void setup(){

  //start Ethernet and UDP
  Ethernet.begin(mac, ip, gateway, mask);
  Udp.begin(localPort);

  //start serial
  Serial.begin(9600);
  mySerial.begin(9600);
 
  //start SD
  //Serial.println("Initializing SD card...");
  //make sure that the default chip select pin is set to
  //output, even if you don't use it:
  pinMode(10, OUTPUT);
  //see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)){
    //Serial.println("Card failed, or not present.");
    SDpresent=false;
  }
  else {
    //Serial.println("Card initialized.");
    SDpresent=true;
  }
 
  //Sync time and date
  setSyncProvider(getNtpTime);
  setSyncInterval(86400);
  //Serial.print("Synching Clock...");
  while(timeStatus()==timeNotSet){
    //Serial.print("."); //wait until the time is set by the sync provider
    delay(1000);
  }
  //Serial.println();

  //Serial.println(GetTime());
  //Serial.println("Arduino started.");
  //Serial.println("================================");
 
  delay(1000);
}

void loop(){

  //Serial.println();
  //Serial.println("--Main Loop--");
  //Serial.println();
  mySerial.flush();
 
  //Serial.print("Waiting for serial data");
  while (mySerial.available()==0){
    //Serial.print(".");
    delay(100);
  };
  //Serial.println();
  //Serial.println("Serial data incoming:");
 
  i=0;
  char serInString[BufferSize+1]; //define string buffer and set to empty
  getSerialString=false;
 
  while ((mySerial.available()>0)&&(i<=BufferSize)){
   char incomingbyte=mySerial.read();
   //Serial.print(i);
        //Serial.print(" ");
   if (incomingbyte==EndChar){
        serInString[i]=0;
      getSerialString=true;
      //Serial.println();
      //Serial.println("End char found: processing data.");
      break;
   }
   else{
     serInString[i]=incomingbyte;
     i++;
   }
  }
  //Serial.print("Received string: ");
  Serial.println(serInString);

  if (getSerialString){
    WebClient(serInString); //Save to db
    if(SDpresent){
      //Serial.println("SD present");
      String record=GetTime()+";"+String(serInString);
      SDWrite(record); //Save to SD
    }
  }
}

void WebClient(char *strArray){
   
  Client client(server, 82); //ip,port (usually 80)
  //Serial.print("Web request: ");
  //Serial.println(String(strArray));
  if (client.connect()){
    //Serial.println("Connected.");
    client.println("GET /rotex.php?user=dbusername&password=dbpassword&data="+String(strArray)+" HTTP/1.0");
    client.println();
  }
  else{
    //Serial.println("Connection failed."); 
  }
  //Serial.println("Disconnecting.");
  client.stop();
}

void SDWrite(String strSD){

  //Serial.println("Opening file.");
  File dataFile = SD.open("rotex.csv", FILE_WRITE);
  //if the file is available, write to it:
  if (dataFile){
    //Serial.println("Writing.");
    //Serial.print("Record: ");
    //Serial.println(strSD);   
    dataFile.println(strSD);
    //Serial.println("Closing file.");
    dataFile.close();
  }
  else {
    //Serial.println("Error opening file.");
  }
}

String GetTime(){
  String ora=hour();
  String minuti=formatDigits(minute());
  String secondi=formatDigits(second());
  String giorno=day();
  String mese=month();
  String anno=year();
  return ora+":"+minuti+":"+secondi+" "+giorno+" "+mese+" "+anno;
}
String formatDigits(unsigned int digits){
  if(digits < 10){
    return "0"+String(digits);
  }
  else {
    return String(digits);
  }
}

/*******************************************************************************
 * Get NTP time function
 *******************************************************************************/
unsigned long getNtpTime(){
  sendNTPpacket(timeServer); //send an NTP packet to a time server
  delay(1000); //wait to see if a reply is available
  if ( Udp.available() ){
    Udp.readPacket(packetBuffer,NTP_PACKET_SIZE); //read the packet into the buffer

    //the timestamp starts at byte 40 of the received packet and is four bytes,
    //or two words, long. First, esxtract the two words:
    unsigned long highWord = word(packetBuffer[40], packetBuffer[41]);
    unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]);
    //combine the four bytes (two words) into a long integer
    //this is NTP time (seconds since Jan 1 1900):
    unsigned long secsSince1900 = highWord << 16 | lowWord;
    const unsigned long seventyYears = 2208988800UL - timeZoneOffset;
    //subtract seventy years:
    return secsSince1900 - seventyYears;
  }
  return 0; //return 0 if unable to get the time
}
/*******************************************************************************
 * send an NTP request to the time server at the given address
 *******************************************************************************/
unsigned long sendNTPpacket(byte *address){
  //set all bytes in the buffer to 0
  memset(packetBuffer, 0, NTP_PACKET_SIZE);
  //Initialize values needed to form NTP request
  //(see URL above for details on the packets)
  packetBuffer[0] = 0b11100011; //LI, Version, Mode
  packetBuffer[1] = 0; //Stratum, or type of clock
  packetBuffer[2] = 6; //Polling Interval
  packetBuffer[3] = 0xEC; //Peer Clock Precision
  //8 bytes of zero for Root Delay & Root Dispersion
  packetBuffer[12] = 49;
  packetBuffer[13] = 0x4E;
  packetBuffer[14] = 49;
  packetBuffer[15] = 52;

  //all NTP fields have been given values, now
  //you can send a packet requesting a timestamp:
  Udp.sendPacket( packetBuffer,NTP_PACKET_SIZE, address, 123); //NTP requests are to port 123
}

FabioR
Messaggi: 125
Iscritto il: ven set 30, 2011 8:11 am

Re: Progetto Interfaccia X RPS/3 con sistema Arduino

Messaggioda FabioR » lun ott 17, 2011 12:43 pm

Il codice utilizza un server ntp per ottenere l'ora all'avvio, e fa il sync ogni giorno.
Ricordo che non è presente un real time clock, quindi è necessario sincronizzare l'ora in qualche modo.
Il server ntp può anche essere pubblico.
Il MAC address deve essere modificato in base all'adesivo presente sul vostro ethernet shield.
Dovete anche modificare le informazioni di rete in base alla vostra configurazione.

Dopo aver ottenuto l'ora arduino resta in attesa di ricevere dati sulla seriale virtuale: in questo caso pin 2 e 3 digitali. In pratica utilizzeremo solo il pin 2 RX e il pin ground per la massa.

Appena riceve dati sul buffer seriale comincia ad acquisirli fino a che non trova un CR (ASCII 13) . A questo punto processa la stringa.
Se vengono ricevuto più di 40 caratteri rifiuta i dati e ritorna in ascolto, per evitare overflow in caso di problemi alla ricezione dei dati.

La stringa viene quindi inviata al web server tramite una chiamata http GET
Dovete modificare username e password del database sulla richiesta.

Inoltre, se è presente una SD card, la stringa viene inserita in coda al file rotex.csv, insieme con il timestamp.

Se non usate la SD card potete togliere tutta la parte relativa alla gestione dell'ora, poichè sarà lo stesso DB server ad aggiungere il timestamp ad ogni record aggiunto.

FabioR
Messaggi: 125
Iscritto il: ven set 30, 2011 8:11 am

Re: Progetto Interfaccia X RPS/3 con sistema Arduino

Messaggioda FabioR » lun ott 17, 2011 12:46 pm

WEB SERVER

Utilizzo un server linux con lighttpd, php e mysql.
Usare apache è la stessa cosa, basta che sia configurato correttamente php con i moduli per mysql

Questo è il file rotex.php che viene chiamato da arduino per salvare i dati

Codice: Seleziona tutto

<?php
//Connect to database
$con = mysql_connect("localhost", $_GET['user'], $_GET['password']);
if(!$con)
    {
    die('Could not connect: ' .mysql_error());
    }

//Select database
mysql_select_db("rotex", $con);

//Parse the data string
$data = str_replace(",",".",$_GET['data']);
$data = explode(";", $data);

//Temperature correction factors
$a = 0.0001;
$b = 0.0501;
$c = -1.0613;
$T = 60; //Intervallo di campionamento

//Assign data
$HA = $data[0];
$BK = $data[1];
$P1 = $data[2];
$P2 = $data[3];
$TK = $data[4];
  $y = ($a*($data[5])^2)+($b*($data[5]))+$c; //Apply polynomial data correction
$TR = ($data[5]-$y);
  $y = ($a*($data[6])^2)+($b*($data[6]))+$c; //Apply polynomial data correction
$TS = ($data[6]-$y);
$TV = $data[7];
$P = $data[8]; //litri al minuto
$W = $P*($TV-$TR)*0.0697; //Potenza istantanea in KW
if ($W < 0) {
  $W = 0;
}
$E = $W*($T/3600); //considerato un campionamento ogni T secondi


//Execute the insert query
$result = mysql_query("INSERT INTO Produzione (HA,BK,Pompa1,Pompa2,TCollettore,TRitorno,TBollitore,TMandata,Portata,Potenza,Energia) VALUES
($HA,$BK,$P1,$P2,$TK,$TR,$TS,$TV,$P,$W,$E)");

if (!$result) {
    die('Invalid query: ' . mysql_error());
}

mysql_close($con);

print "OK";
?>

Mauro1980
Messaggi: 356
Iscritto il: mer ago 31, 2011 10:00 pm

Re: Progetto Interfaccia X RPS/3 con sistema Arduino

Messaggioda Mauro1980 » lun ott 17, 2011 9:50 pm

Fabio,

Con Arduino posso leggere anche i segnali delle sonde di T presenti nella caldaia? (dovrebbero essere NTC) come quella di mandata, ritorno riscaldamento e T sanitari per chi ha l'istantanea

C'è anche un flussimetro digitale in quelle nuove,forse si riesce a leggere anche quello

Sarebbe interessante per chi (es Sergio) ha aggiunto qualche sonda ridondante, ma di tecnologia diversa (penso 1-wire) vedere la differenza di misura

FabioR
Messaggi: 125
Iscritto il: ven set 30, 2011 8:11 am

Re: Progetto Interfaccia X RPS/3 con sistema Arduino

Messaggioda FabioR » mar ott 18, 2011 12:55 pm

Mauro1980 ha scritto:Fabio,

Con Arduino posso leggere anche i segnali delle sonde di T presenti nella caldaia? (dovrebbero essere NTC) come quella di mandata, ritorno riscaldamento e T sanitari per chi ha l'istantanea

C'è anche un flussimetro digitale in quelle nuove,forse si riesce a leggere anche quello

Sarebbe interessante per chi (es Sergio) ha aggiunto qualche sonda ridondante, ma di tecnologia diversa (penso 1-wire) vedere la differenza di misura

Non saprei.
Io leggo semplicemente i dati dalla centralina.
Arduino può gestire nativamente i sensori 1-wire, quindi non ci sarebbero problemi per quello (e su ebay avevo visto anche un flussimetro)

Mauro1980
Messaggi: 356
Iscritto il: mer ago 31, 2011 10:00 pm

Re: Progetto Interfaccia X RPS/3 con sistema Arduino

Messaggioda Mauro1980 » mar ott 18, 2011 9:06 pm

Si Arduino può leggere con un piccolo circuitino (si trova in rete lo schema), questi flussimetri (ad effetto Hall penso)

http://www.seeedstudio.com/depot/g12-wa ... th=144_151

si trovano anche in Italia

Avevo letto che, tramite un opportuno circuito,può leggere anche le NTC, su alcuni forum se ne parla, ma in maniera n concludente

STAFF
Site Admin
Messaggi: 1850
Iscritto il: mar nov 27, 2007 7:44 pm
Contatta:

Re: Progetto Interfaccia X RPS/3 con sistema Arduino

Messaggioda STAFF » sab ott 22, 2011 4:10 pm

Vorrei un chiarimento sulo tuo sistema :

Da quello che ho capito ,
- con la scheda Arduino leggi i dati seriali dalla RPS/3 e li memorizzi sulla scheda SD.
- Oltre a questo li metti a disposizione sulla interfaccia ethernet di Arduino via protocollo http ( web ).

Con un server esterno poi leggi questi dati e li memorizzi via Msql.. e' corretto ?

Puoi postare la pagina web cosi come e' prodotta da Arduino ?

Grazie,
F.

FabioR
Messaggi: 125
Iscritto il: ven set 30, 2011 8:11 am

Re: Progetto Interfaccia X RPS/3 con sistema Arduino

Messaggioda FabioR » sab ott 22, 2011 5:26 pm

arduino fa questa chiamata

Codice: Seleziona tutto

client.println("GET /rotex.php?user=dbusername&password=dbpassword&data="+String(strArray)+" HTTP/1.0");


cioè fa una chiamata http get ad un web server richiamando uno script php e passando come argomenti username e password del database e la stringa dati acquisita.

Il web server è un server che ho in casa ma può essere anche un server esterno pubblico.

Lo script php fa il parsing della stringa usando i ; per separare i campi, applica le correzioni alle temperature e calcola la potenza istantanea.
Dopo di che salva i dati sul database.
Un campo timestamp sulla tabella aggiunge automaticamente data e ora di sistema (il server si sincronizza con NTP sui server di tempo ufficiali).

la pagina che ho pubblicato non fa altro che mostrare i dati memorizzati sul db, elaborandoli attraverso query e viste. Il calcolo dell'energia prodotta ad esempio è svolto da una vista. Il tutto gira sullo stesso server.

Su arduino non ho attivato la parte http server, ma in teroria sarebbe possibile implementarla in modo che rstituisca il contenuto del file salvato sulla SD. Di più non potrebbe fare perchè non è in grado di far girare un db di qualsiasi tipo o addirittura pagine web attive, se non una specie di cgi scritti in C


Torna a “Domotica, monitoraggio e controllo.”



Chi c’è in linea

Visitano il forum: Nessuno e 4 ospiti