How to create an intelligent, web enabled, Power Meter with Arduino
Electricity costs are rising, and just in case this is not enough, if you exaggerate with consumption your house circuit often stops working in the very moment of your greatest need. This project allows you to keep an eye on your electricity instant consumption even remotely.
[iframe_loader src=”http://emoncms.org/boris&id=2505 ” ]
The acquisition of current consumption rates takes place by means of small clamps placed on top of the phase conductor of the power line section you want to control. The acquisition system is based on a commercial product available in our store, the FR491. The kit includes a meter clamp to measure current plus a data transmission unit. The transmission occurs at 433.92 MHz and can cover about thirty meters. The central unit gathers samples sent via radio by the peripheral devices and stores them and shows a series of information about consumption, usage bursts and relative costs, by means of a nice web page.
The central unit is also equipped with an RJ45 output that allows you to connect it to a PC via a TTL-USB converter. Our goal is to connect the central unit to an Arduino Uno (instead of a PC), and implement a web enabled monitoring system. To do this we bypass the TTL-USB converter and connect the output of the controller directly to the D6 (RX) and D7 (TX) pins on the Arduino. The Arduino board mounts two shield. The Ethernet shield allows you to do both: sending data to the emoncms remote service for collection, storage and presentation, and respond directly to web calls used to monitor the status of sensors and alarms and manage the thresholds under which the alarm is started.
The shield must be connected via the Ethernet connector to a network that allows access to the internet. The second shield is the local monitoring and alarm management unit and the wiring diagram is visible in the section. The shield has a relay output and a buzzer, triggered if the consumption exceeds the threshold set via the web page. It also sports two buttons (besides the reset button) that can be activated to pausea the alarm function. The software sketch is made so that the alarm is still reactivated as soon as the consumption goes back below the threshold that caused the trip. A LED indicates the general operational state of the system.
From the embedded web page you can activate and deactivate the alarm, pause it and set the alarm new threshold: upon alarm activation, buzzer plays a melody .
Regarding emoncms, obviously you cannot install the server on Arduino, we will use the functionality available from emoncms website itself, integrating them with the available page from Arduino web server.
Diagram of the shield
The shield is powered thanks to Arduino’s 12 V: used to power the relay coil and the buzzer.
But, let’s analyze the serial line coming from the FR491 central controller. The output signal taken from line 8 of the RJ45 connector is connected to pin D6 (RX) of Arduino while the input signal on line 7 of the RJ45 connector is connected to pin D7 (TX) of Arduino. To use Arduino’s D6 and D7 pins for serial communication your need, in the sketch, to call the SoftSerial library.
The threshold breaking alarm activation outputs are at D4 pin for the relay driven by the switching transistor T1 and at D5 for what regards the buzzer, which is also driven by the switching transistor T2. Pin D3 drives LD1.
On FT1046 shield two additional buttons P1, connected to pin D9, to activate and deactivate the alarm locally and P2, connected to pin D8, to pause the alarm function.
The sketch for Arduino
#include <EtherCard.h>
#include <SoftwareSerial.h>
#include <EEPROM.h>
#define DEBUG 1 // set to 1 to display debug info via seral link
int ledalarm = 3; // pin the LED is on (you can't use the onboard one as the ethernet card uses it)
int pulsalarm = 9;
int pulspause = 8;
int alarmout = 4;
int speakerPin = 5;
char TextBox1[10]; // Data in text box
int length = 15; // the number of notes
char notes[] = "ccggaagffeeddc "; // a space represents a rest
int beats[] = { 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 2, 4 };
int tempo = 300;
boolean alarm=0;
#define APIKEY "**************"
#define emonlink "http://emoncms.org/boris&id=2505"
// ethernet interface mac address
static byte mymac[] = { 0x74,0x69,0x69,0x2D,0x30,0x31 };
// ethernet interface ip address
static byte myip[] = { 192,168,0,99 };
// gateway ip address
static byte gwip[] = { 192,168,0,1 };
static const byte dnsip[] = { 192,168,0,1 };
char website[] PROGMEM = "emoncms.org";
static const byte hisip[] = { 213,138,101,177 };
unsigned long previousMillis_power=0;
int power_postrate=10000; //post every 10s
int watts=0;
int maxwatts=3000;
byte inData1[10]; // Allocate some space for the string
byte inData2[10];
//byte inData3[10];
boolean pause=0;
char str[20];
SoftwareSerial mySerial(6, 7); // RX, TX
// web page buffer
byte Ethernet::buffer[800];
BufferFiller bfill;
// store html header in flash to save memory
char htmlHeader[] PROGMEM =
"<html><head><title>Power meter by Boris</title></head><body>"
"<h2 style='text-align: center;'><em><span style='color: rgb(153, 0, 0);'>Power meter by Boris</span></em></h2>"
;
// ----------------------------------------------
// HTML page to display
static word homePage() {
checkmcee();
bfill = ether.tcpOffset();
// read A0 status
//word sensorValue = analogRead(sensorPin);
maxwatts = EEPROM_readint(0);
Serial.print("maxwatts in mem : ");
Serial.println(maxwatts);
Serial.print("alarm in mem : ");
Serial.println(EEPROM_readint(5));
// read statues of the LED
char* alarmstat;
if ( EEPROM_readint(5) == 1 ) {
alarmstat = "On" ; }
else {
alarmstat = "Off"; }
bfill.emit_p( PSTR (
"$F<p>" // $F = htmlheader in flash memory
"<center>"
"<iframe src='$S' width='1000' height='500' frameborder='0' ></iframe><br/>"
"<em>Alarm: $S <br/>"
"Alarm threshold: $D <br/>"
"</em></p><p>"
"<A HREF='?cmd=on'>Alarm on</A><br/><br/>"
"<A HREF='?cmd=off'>Alarm off</A><br/><br/><br/>"
"<A HREF='?cmd=pause'>Alarm pause</A><br/><br/>"
"<FORM>Insert alarm threshold <input type=text name=maxwatts size=4 value=$D> <input type=submit value=Enter> </form> <br/><br/>"
"<A HREF='https://oe2.open-electronics.org'>More info</A>"
"</p></center></body></html>"
) , htmlHeader , emonlink, alarmstat , maxwatts , maxwatts ) ;
return bfill.position();
}
// ----------------------------------------------
void setup () {
pinMode(ledalarm, OUTPUT);
pinMode(alarmout, OUTPUT);
pinMode(speakerPin, OUTPUT);
pinMode(pulsalarm, INPUT);
digitalWrite(pulsalarm, HIGH);
pinMode(pulspause, INPUT);
digitalWrite(pulspause, HIGH);
Serial.begin(9600);
Serial.println("n[webClient]");
if ((EEPROM.read(10)!=10)){
Serial.println("First power on");
EEPROM.write(10, 10);
EEPROM_writeint(0, maxwatts);
alarmoff();
}
else
{
Serial.println("Data on eeprom already stored");
}
maxwatts = EEPROM_readint(0);
Serial.print("maxwatts in mem : ");
Serial.println(maxwatts);
Serial.print("alarm in mem : ");
Serial.println(EEPROM_readint(5));
if (EEPROM_readint(5)==1){
digitalWrite(ledalarm, HIGH);
}
if (!ether.begin(sizeof Ethernet::buffer, mymac,10))
Serial.println( "Failed to access Ethernet controller");
else
Serial.println("Ethernet controller initialized");
ether.staticSetup(myip,gwip,dnsip);
ether.copyIp(ether.hisip, hisip);
ether.printIp("IP Address:t", ether.myip);
ether.printIp("Netmask:t", ether.mymask);
ether.printIp("Gateway:t", ether.gwip);
ether.printIp("DNS:t", ether.dnsip);
ether.printIp("SRV: ", ether.hisip);
mySerial.begin(9600);
}
// ----------------------------------------------
void loop () {
word len = ether.packetReceive();
word pos = ether.packetLoop(len);
if(pos) {
Serial.print("pos ");
Serial.println(pos);
printpage(pos);
}
if ((millis()%1000)==0){
Serial.println(millis());
delay(50);
if (pause==1)
{
digitalWrite(ledalarm, HIGH);
delay(200);
digitalWrite(ledalarm, LOW);
delay(200);
}
else
{
if (alarm=1)
{
digitalWrite(ledalarm, HIGH);
}
else
{
digitalWrite(ledalarm, LOW);
}
}
}
if ((millis() - previousMillis_power) > (power_postrate) )
{
previousMillis_power=millis();
checkmcee();
Serial.print("watts ");
Serial.println (watts,DEC);
pubblica();
checkalarm();
}
if (digitalRead(pulsalarm)==0){ //toggle alarm
if (EEPROM_readint(5)==1) {
alarmoff();
delay(500);
}
else
{
alarmon();
delay(500);
}
}
if (digitalRead(pulspause)==0){ //toggle alarm
pause=1;
Serial.println("pause on");
}
}
void alarmon(){
digitalWrite(ledalarm, HIGH); // set the LED on
EEPROM_writeint(5, 1); //alarm off
Serial.println("alarm on");
alarm=1;
}
void alarmoff(){
digitalWrite(ledalarm, LOW); // set the LED on
EEPROM_writeint(5, 0); //alarm off
Serial.println("alarm off");
alarm=0;
}
void printpage(word pos){
char* bufferdata = (char *) Ethernet::buffer + pos;
Serial.println("----------------");
Serial.println("data received:");
Serial.println(bufferdata);
Serial.println("----------------");
// "on" command received
if (strncmp( "GET /?cmd=on" , bufferdata , 12 ) == 0) {
alarmon();
}
// "off" command received
if (strncmp( "GET /?cmd=off" , bufferdata , 13 ) == 0) {
alarmoff();
}
// "pause" command received
if (strncmp( "GET /?cmd=pause" , bufferdata , 13 ) == 0) {
//digitalWrite(LEDpin, LOW); // set the LED on
Serial.println("pause received");
pause=1;
}
// read data from text box
if (strncmp( "GET /?maxwatts=" , bufferdata , 11 ) == 0) {
Serial.print ( "text box input received - " );
if (ether.findKeyVal(bufferdata + 6, TextBox1 , sizeof TextBox1 , "maxwatts") > 0) {
Serial.print ( "input = " );
Serial.println ( TextBox1 );
EEPROM_writeint(0, atoi(TextBox1));
}
}
ether.httpServerReply(homePage()); // send web page data
}
void checkmcee(){
Serial.println("checkmcee ");
int data=0;
int index=0;
mySerial.write((byte)0xAA);
mySerial.write((byte)0x02);
mySerial.write((byte)0x00);
mySerial.write((byte)0xAD);
delay(500);
while (mySerial.available() > 0) {
byte inByte = mySerial.read();
//Serial.write(inByte);
if (inByte=='S'){
index=0;
data++;
}
switch (data){
case 1:
inData1[index] = inByte; // Store it
index++;
break;
case 2:
inData2[index] = inByte; // Store it
index++;
break;
}
}
watts=0;
watts=(inData2[6]<<8) + inData2[5];
}
void pubblica()
{
str[0]='




