This project shows how to make an Electricity Monitor for your home that utilises some of the key capabilities of the Arduino Yun that make it an Ideal choice for Cloud Enabled sensor projects such as this. Features :
- WiFi connection allows continuous monitoring of Power Consumed
- Utilises TEMBOO for Cloud Support with Google APIs
- Cloud Support: Writes Power Consumption to a Google Drive Spreadsheet
- Graphing, analysis etc.. available via Google Spreadsheet
A nice feature of the project is that the monitoring is flexible and it's completely wireless (except for the Current Transformer of course), allowing continuous monitoring from a PC or phone and permanent storage on the Cloud. Measured accuracy was 6% (typical), which is excellent for such a simple circuit. Even better accuracy was observed after calibration. Let's Go....
Step 1: You Will Need
You will Need :
- Arduino Yun
- Current Transformer (e.g. SCT-013-030)
- 2 x 10kOhm Resistors
- 1x 47uF Capacitor
- Some wires, Breadboard
- A 5V Power Supply for the Yun (I used a Smart Phone Charger).
Step 2: Make the Circuit
The circuit is very simple. It consists of a Voltage Divider to bias the ADC of the Arduino to a DC Voltage and Voltage Output Current Transformer to add an AC Voltage proportional to the AC Current flowing in the Cable. The Capacitor forms a Low Pass filter with the resistors to remove noise. Lots more details are available at the Open Energy Monitor Project. Build the Circuit as shown here.
Step 3: Arduino Yun / Temboo
If you haven't previously configured your Yun or you've Reset its configuration. When the Yun is unconfigured it presents itself as a Wifi Access Point (AP). You connect to that AP from a Wifi Enabled device (e.g. Laptop or Phone) and configure it from it's default IP address (http://192.168.1.240). Full Details from Arduino here: http://arduino.cc/en/Guide/ArduinoYun We'll also be using Temboo. So you'll need to get yourself an account here : https://temboo.com/ Temboo gives us a simple way to access Google APIs. It even gives you the code you need for Arduino (or your fav. programming language for non-Arduino use).
Step 4: Electricity Measurement
The Current Transformer produces a current proportional to the current flowing though it's magnetic circuit. The proportion of the current in the cable that you get in the transformer is equal to the turns ratio. For example : Current = 30A (rms) , Turns Ratio = 1800 => Transformer Current = 30/1800 = 16.67mA (rms) The SCT013-030 includes a 62 Ohm resistor in parallel with the transformer, making it a Voltage Output type. At 30A in the example above, that corresponds to an output Voltage of 16.67mA x 62 Ohms = 1V (rms) See the datasheet HERE. Make sure the Current Transformer is only around the Live or Neutral NOT BOTH. If it's around both the magnetic flux in both the Live an Neutral will cancel to yield zero current in the Transformer. I installed the Current Probe in the Main Circuit Breaker of the House as shown. Obviously make sure to replace the Housing. You should NOT leave Electrical cables exposed. It's not safe. WARNING: Please be Sensible about this. This exposes LIVE Electrical cables that puts you at risk of DEATH by Electrocution. Please proceed at your OWN RISK and if in any doubt consult a registered Electrical Contractor to install the Current Transformer for you.
Step 5: Arduino Measurement Routine
The Complete Arduino Code involves:
- For 5 Seconds
- Take a Sample from the ADC
- Filter Out the DC component from the potential Divider Circuit and noise using a Digital Band Pass Filter
- Calculate the Mean Square (MS) Value of the current (i.e. square the values and get the running Average)
- Calculate the RMS value from the MS value by square-rooting it.
- Multiply by the RMS Voltage (230V in Ireland / UK ; 110V in the USA).
- Scale to allow for the Current transformer gain and ADC.
Here's the relevant code section
void loop() {
// send the value of analog input 0:
r2 = r1;
r1 = r0;
r0 = analogRead(A0);
u2 = u1;
u1 = u0;
// 0.5Hz to 200Hz Band Pass Filter
u0 = 0.2929*(r0-r2) + 1.411*u1 -0.4142*u2;
v = u0;
// Calculate Mean-Square Current (Amps)
AMS = 0.99*AMS +0.01*v*v;
// Calculate Root-Mean-Square (Amps)
Arms = sqrt(AMS);
// Convert to RMS Power:
// Multipy by 230V (rms)
// 30*5/1024 accounts for the gain of the Current Transformer and ADC
Prms = 230*30*Arms*5/1024;
delay(1);
The Digital Filter Calculation probably deserves a special mention.
You don't need to understand it to do the project but you might find it interesting. It's implemented in the following line of code:
u0 = 0.2929*(r0-r2) + 1.411*u1 -0.4142*u2;
It is an IIR filter because it operates on input values (past and present) and its own output values (past and present). The Response of the BPF is shown above.
Its z-domain Pole/Zero Transfer Function is:
0.2929 (z+1)(z-1)
=================
(z-0.9952)(z-0.4162)
A similar technique is used to filter the Current Readings to yield the Mean-Square Current value. AMS = 0.99*AMS +0.01*v*v; This is simply a low pass filter to form a long term average of its input (v^2).
Step 6: Monitoring the Output
See the Console Window Output as shown in the Picture. The Arduino Code Outputs the RMS Power to the Console every 5 seconds. The Console is located in the Arduino IDE as though you're opening a Serial Monitor Window. But when you have an Arduino Yun connected over IP by Tools -> Port this opens the Console instead. You can access the Console output from your Smart Phone. I use JuiceSSH for Android. Just setup an SSH connection to your Yun.
The default credentials are: Username : root Password: arduino
Once logged into the Yun type : telnet localhost 6571
Now your Power Readings will appear on the JuiceSSH Console every 5 seconds. The Google Docs Spreadsheet is written Once Per Hour. Because the Power is averaged over an Hour the Data in the Spreadsheet will be in Watt Hours.
NOTE: You need to Create a Spreadsheet first with the same name as referred to in the code: const String SPREADSHEET_TITLE = "ElectricityUsage"; Also, don't forget that the Spreadsheet Columns need names in the first row to avoid errors. See the Picture from Temboo previously.
CALIBRATION: Make sure the Monitor reads close to Zero when the Transformer is not connected to the mains cable. Mine read 16Watts. This converts back to 69mA in the mains cable (16W/230V). Therefore the transformer current is 69mA/1800 = 38uA , and the Transformer output Voltage is 38uA * 62 Ohms = 2.4mV . This is equivalent to 1/2 LSB of the ADC which is an excellent result; well within the expected accuracy. Calibrate the Monitor by running it for a day and comparing with the energy consumption recorded on your home's Electricity meter. Multiply the Prms calculation by this factor so they agree. My system accuracy was -6%. Which is excellent. Nevertheless I add a 1.06 CAL factor to correct for this.
Step 7: OK. So Here's the Code
#include <Console.h>
#include <Temboo.h>
#include <Process.h>
/*** SUBSTITUTE YOUR VALUES BELOW: ***/
// Note that for additional security and reusability, you could
// use #define statements to specify these values in a .h file.
const String GOOGLE_USERNAME = "wolola@gmail.com";
const String GOOGLE_PASSWORD = "3e3we3w";
#define TEMBOO_ACCOUNT "aSSdazx" // your Temboo account name
#define TEMBOO_APP_KEY_NAME "myFirstApp" // your Temboo app key name
#define TEMBOO_APP_KEY "ccdfddd-uuuuu" // your Temboo app key
// the title of the spreadsheet you want to send data to
// (Note that this must actually be the title of a Google spreadsheet
// that exists in your Google Drive/Docs account, and is configured
// as described above.)
const String SPREADSHEET_TITLE = "ElectricityUsage";
int r0, r1, r2, u0, u1, u2, v , i= 0;
unsigned long time;
float Arms, AMS, Prms, Ptot, vf = 0;
float CAL = 1.05;
Process date; // process used to get the date
void setup() {
// initialize communication:
Bridge.begin();
Console.begin();
time = millis();
if (!date.running()) {
date.begin("date");
date.addParameter("+%T");
date.run();
}
}
void loop() {
// send the value of analog input 0:
r2 = r1;
r1 = r0;
r0 = analogRead(A0);
u2 = u1;
u1 = u0;
// 0.5Hz to 200Hz Band Pass Filter
u0 = 0.2929*(r0-r2) + 1.411*u1 -0.4142*u2;
v = u0;
// Calculate Mean-Square Current (Amps)
AMS = 0.99*AMS +0.01*v*v;
// Calculate Root-Mean-Square (Amps)
Arms = sqrt(AMS);
// Convert to RMS Power:
// Multipy by 230V (rms)
// 30*5/1024 is the accounts for the gain of the Current Transformer and ADC
Prms = 230*30*Arms*5/1024*CAL;
delay(1);
// Gather data for 5 seconds
if (millis() - time > 5000)
{
// Print the RMS Power in the last 5 seconds to the Console
Console.print("Prms = ");
Console.println(Prms);
if (i == 719) {
// As we just gathered 1 hour's readings this in in kWh
Ptot = Ptot/720;
// we need a Process object to send a Choreo request to Temboo
TembooChoreo AppendRowChoreo;
// invoke the Temboo client
// NOTE that the client must be reinvoked and repopulated with
// appropriate arguments each time its run() method is called.
AppendRowChoreo.begin();
// set Temboo account credentials
AppendRowChoreo.setAccountName(TEMBOO_ACCOUNT);
AppendRowChoreo.setAppKeyName(TEMBOO_APP_KEY_NAME);
AppendRowChoreo.setAppKey(TEMBOO_APP_KEY);
// identify the Temboo Library choreo to run (Google > Spreadsheets > AppendRow)
AppendRowChoreo.setChoreo("/Library/Google/Spreadsheets/AppendRow");
// set the required Choreo inputs
// see https://www.temboo.com/library/Library/Google/Spreadsheets/AppendRow/
// for complete details about the inputs for this Choreo
// your Google username (usually your email address)
AppendRowChoreo.addInput("Username", GOOGLE_USERNAME);
// your Google account password
AppendRowChoreo.addInput("Password", GOOGLE_PASSWORD);
// the title of the spreadsheet you want to append to
// NOTE: substitute your own value, retaining the "SpreadsheetTitle:" prefix.
AppendRowChoreo.addInput("SpreadsheetTitle", SPREADSHEET_TITLE);
// restart the date process:
if (!date.running()) {
date.begin("date");
date.addParameter("+%T");
date.run();
}
// convert the time and sensor values to a comma separated string
String timeString = date.readString();
String rowData(timeString);
rowData += ",";
rowData += Ptot;
// add the RowData input item
AppendRowChoreo.addInput("RowData", rowData);
// run the Choreo and wait for the results
// The return code (returnCode) will indicate success or failure
unsigned int returnCode = AppendRowChoreo.run();
// return code of zero (0) means success
if (returnCode == 0) {
Console.println("Success! Appended " + rowData);
Console.println("");
} else {
// return code of anything other than zero means failure
// read and display any error messages
while (AppendRowChoreo.available()) {
char c = AppendRowChoreo.read();
Console.print(c);
}
}
AppendRowChoreo.close();
i = 0;
Ptot = 0;
}
else {
i++;
Ptot+=Prms;
}
time = millis();
}
}
Comments