Mi sono basato su questo progetto http://enerduino.blogspot.com/2009/12/enerduino-italiano.html
che però salva i dati solo su sd
Ho realizzato il tutto usando un arduino ethernet con modulo poe, in modo da poter alimentare arduino attraverso il solo cavo di rete
http://www.ebay.it/itm/ARDUINO-UNO-ETHERNET-con-modulo-PoE-con-microcontrollore-ATmega328-/330636290287?pt=Componenti_elettronici_attivi&hash=item4cfb7568ef
alimentatore poe http://www.ebay.it/itm/160549197582?ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1439.l2649
Usando un cavo di rete da esterni a doppia guaina non dovrebbero esserci problemi di coesistenza con le linee a 220V
http://www.ebay.it/itm/170716227871?ssPageName=STRK:MEWNX:IT&_trksid=p3984.m1439.l2649
Questo è il codice di arduino
Codice: Seleziona tutto
/*
Save Enel production SD card and mysql database
Use NTP time provider to sync internal time
Fabio Roverso 5/11/11
V 1.0
*/
#include <SPI.h>
#include <Ethernet.h>
#include <Udp.h>
#include <SD.h>
#include <Time.h>
#include <MsTimer2.h>
//Network stuff
byte mac[] = {
0x90, 0xA2, 0xDA, 0x00, 0x76, 0xBE }; //Arduino MAC address
byte ip[] = {
192, 168, 1, 178 }; //Arduino IP address
byte gateway[] = {
192, 168, 1, 250 }; //Network gateway
byte subnet[] = {
255, 255, 255, 0 }; //Network subnet mask
//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
unsigned int port = 82; //Web server http port (usually 80)
Client client(server, port); //Creates an http client handle
//led stuff
const byte ledPin = 9;
const byte HalfLed = 0;
const byte FullLed = 10;
// Analog input for photoresistor
#define PHOTO_IN 0
int threshold=450; // If photoresistor read more than this value, it count a flash
long timer=60000; // Log file is written every minute
long flash=0;
boolean writeLog=false;
byte i = 0;
// 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;
boolean blndebug=true;
void setup(){
// sets the digital pin as output
pinMode(ledPin, OUTPUT);
// Setup for photoresistor
pinMode(PHOTO_IN,INPUT);
//start Ethernet and UDP
Ethernet.begin(mac, ip, gateway, subnet);
Udp.begin(localPort);
//start serial
Serial.begin(9600);
if (blndebug) Serial.print("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)){
if (blndebug){
Serial.println();
Serial.println("Card failed, or not present");
}
SDpresent = false;
}
else {
if (blndebug) Serial.println("OK");
SDpresent = true;
}
//Sync time and date
setSyncProvider(getNtpTime);
setSyncInterval(86400); //24h
if (blndebug) Serial.println("Synching Clock...");
while(timeStatus() == timeNotSet){
if (i > 100){
if (blndebug) Serial.println("Time not set");
break;
}
i++;
delay(10);
}
// Initialize timer
MsTimer2::set(timer, flushCounter);
MsTimer2::start();
if (blndebug){
Serial.println();
digitalClockDisplay();
Serial.println("Arduino started");
Serial.println("================================");
}
analogWrite(ledPin, HalfLed);
delay(50);
}
void loop(){
// Read the photo sensor value
if (analogRead(PHOTO_IN) > threshold){
analogWrite(ledPin, FullLed);
while (analogRead(PHOTO_IN) > threshold){
// Just wait the flash to turn off (to avoid multiple counts)
delay(10);
}
analogWrite(ledPin, HalfLed);
flash++;
}
if (writeLog){
WebClient(flash); //Save to db
if(SDpresent){
SDWrite(flash); //Save to SD
}
writeLog=false;
flash=0;
}
}
void WebClient(long conteggio){
if (client.connect()){
client.flush();
client.print("GET ");
client.print("/enel.php?user=username&password=password&data=");
client.print(conteggio);
client.println(" HTTP/1.0");
client.println();
while(!client.available()){
delay(1);
}
while (client.available()){
char c = client.read();
if (blndebug) Serial.print(c);
}
if (blndebug) Serial.println();
}
else {
if (blndebug) Serial.println("EXCEPTION: during HTTP GET. Could not connect");
return;
}
while(client.connected()){
if (blndebug) Serial.println("Waiting for server to disconnect");
}
client.stop();
}
void SDWrite(long conteggio){
int digits;
File dataFile = SD.open("enel.csv", FILE_WRITE); //define file handle
//if the file is available, write to it:
if (dataFile){
if (blndebug) Serial.print("Writing to SD card...");
dataFile.print(hour());
dataFile.print(":");
digits = minute();
if (digits < 10) dataFile.print("0");
dataFile.print(digits);
dataFile.print(":");
digits = second();
if (digits < 10) dataFile.print("0");
dataFile.print(digits);
dataFile.print(" ");
dataFile.print(day());
dataFile.print("-");
dataFile.print(month());
dataFile.print("-");
dataFile.print(year());
dataFile.print(";");
dataFile.println(conteggio);
dataFile.close();
if (blndebug) Serial.println("done");
}
else {
if (blndebug) Serial.println("Error opening file.");
}
}
// Routine executed by the timer interrupt. This flush the
// data to the log file
void flushCounter(void){
if(flash>0) writeLog=true;
}
void digitalClockDisplay(){
// digital clock display of the time
Serial.print(hour());
printDigits(minute());
printDigits(second());
Serial.print(" ");
Serial.print(day());
Serial.print(" ");
Serial.print(month());
Serial.print(" ");
Serial.print(year());
Serial.println();
}
void printDigits(int digits){
// utility function for digital clock display: prints preceding colon and leading 0
Serial.print(":");
if(digits < 10)
Serial.print("0");
Serial.print(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
}
In pratica conta i lampeggi del contatore gse (1 ogni Wh) e una volta al minuto invia i dati al database, via rete, e, se presente, li salva su scheda SD.
Un led aggiuntivo riproduce i lampeggi letti dalla fotoresistenza per avere un feedback immediato del funzionamento.
L'ora viene presa e sincronizzata tramite server NTP (anche pubblico)
il file php sul web server
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);
$Impulsi=$_GET['data'];
//Execute the insert query
$result = mysql_query("INSERT INTO FV (Impulsi) VALUES ($Impulsi)");
if (!$result) {
die('Invalid query: ' . mysql_error());
}
mysql_close($con);
print "OK";
?>
La tabella sul db contiene solo due campi: un timestamp e un numerico per i conteggio degli impulsi