Writing code for the emontx
Part 1 – Measuring current with a single CT
#include "EmonLib.h" // Include Emon Library EnergyMonitor ct1; // Create an instance void setup() { Serial.begin(9600); ct1.currentTX(1, 115.6); // CT channel, calibration } void loop() { double Irms = ct1.calcIrms(1480); // Calculate RMS current (1480: no. of samples) Serial.print(Irms*240.0); // Print to serial apparent power Serial.print(" "); Serial.println(Irms); // Print to serial Irms }
For details on the rms current calculations and real power calculation below that occur in EmonLib.h see this page on AC Power Theory - Arduino maths for an overview.
Part 2 – Adding another CT
To add another CT, create a second instance of the EnergyMonitor class, see ct2:
#include "EmonLib.h" // Include Emon Library EnergyMonitor ct1, ct2; // Create two instances void setup() { Serial.begin(9600); ct1.currentTX(1, 115.6); // CT channel 1, calibration. ct2.currentTX(2, 115.6); // CT channel 2, calibration. } void loop() { double Irms1 = ct1.calcIrms(1480); // Calculate RMS current 1 double Irms2 = ct2.calcIrms(1480); // Calculate RMS current 2 Serial.print(Irms1*240.0); // Print apparent power 1 Serial.print(' '); Serial.println(Irms2*240.0); // Print apparent power 2 }
Part 3 – Measuring real power by adding AC Voltage measurement.
#include "EmonLib.h" // Include Emon Library EnergyMonitor ct1; // Create an instance void setup() { Serial.begin(9600); ct1.voltageTX(238.5, 1.7); // Calibration, phase_shift ct1.currentTX(1, 115.6); // CT channel, calibration. } void loop() { ct1.calcVI(20,2000); // Calculate all. No.of wavelengths, time-out ct1.serialprint(); // Print out all variables }
Part 4 – Measuring temperature
By using direct addressing its possible to make sure that as you add temperature sensors the temperature sensor to variable mapping will not change. To find the addresses of your temperature sensors use the: **temperature_search sketch**
#include <OneWire.h> #include <DallasTemperature.h> OneWire oneWire(4); // Setup one-wire on digital input pin 4 DallasTemperature sensors(&oneWire); // Pass the oneWire reference to Dallas Temperature. DeviceAddress address_T1 = { 0x28, 0x22, 0x70, 0xEE, 0x02, 0x00, 0x00, 0xB8 }; void setup() { Serial.begin(9600); sensors.begin(); } void loop() { sensors.requestTemperatures(); double temperature = sensors.getTempC(address_T1); // Get the temperature of the sensor Serial.println(temperature); // Print temperature }
Part 5 – Pulse counting
long pulseCount = 0; unsigned long pulseTime,lastTime; // Used to measure time between pulses double power; int ppwh = 1; // pulses per watt hour - found or set on the meter. void setup() { Serial.begin(9600); // pulse detection interrupt (emontx pulse channel - IRQ0 D3) attachInterrupt(1, onPulse, FALLING); } void loop() { Serial.print(power); Serial.print(' '); Serial.println(pulseCount * ppwh); // watt hour elapsed delay(1000); } // The interrupt routine - runs each time a falling edge of a pulse is detected void onPulse() { lastTime = pulseTime; pulseTime = micros(); pulseCount++; // count pulse power = int((3600000000.0 / (pulseTime - lastTime))/ppwh); // calculate power }
Part 6 – Transmitting data via the RFM12
Bare bones low power emontx sketch (based on JeeLabs radioBlip sketch)
#include <JeeLib.h> // this is added as we're using the watchdog for low-power waiting ISR(WDT_vect) { Sleepy::watchdogEvent(); } #include "EmonLib.h" EnergyMonitor ct1; // create structure - a neat way of packaging data for RF comms typedef struct { int power; } PayloadTX; PayloadTX emontx; void setup() { ct1.currentTX(1, 115.6); // initialize RFM12B (node id, frequency, group) rf12_initialize(10, RF12_433MHZ, 210); rf12_sleep(RF12_SLEEP); } void loop() { emontx.power = ct1.calcIrms(1480) * 240.0; rf12_sleep(RF12_WAKEUP); int i = 0; while (!rf12_canSend() && i<10) {rf12_recvDone(); i++;} rf12_sendStart(0, &emontx, sizeof emontx); // set the sync mode to 2 if the fuses are still the Arduino default // mode 3 (full powerdown) can only be used with 258 CK startup fuses rf12_sendWait(2); rf12_sleep(RF12_SLEEP); Sleepy::loseSomeTime(5000); }
Basic receiver sketch
#include <JeeLib.h>
typedef struct { int power; } PayloadTX;
PayloadTX emontx;
void setup()
{
Serial.begin(9600);
rf12_initialize(10, RF12_433MHZ, 210);
}
void loop()
{
if (rf12_recvDone()){
if (rf12_crc == 0 && (rf12_hdr & RF12_HDR_CTL) == 0)
{
int node_id = (rf12_hdr & 0x1F); // get node id
if (node_id == 10) // if emontx node id
{
emontx = *(PayloadTX*) rf12_data; // extract payload
Serial.println(emontx.power); // Print power value
}
}
}
}
Part 7 – Adding a watchdog for extra reliability
The following sketch is a skeleton watchdog only sketch, it does not do much at all, it is only to illustrate the commands needed and their location
If wdt_reset() is not called in more than 8 seconds such as under a fault condition the atmega will reset it self, otherwise if all is well the watchdog timer will continually be reset and will never reach 8 seconds
#include <avr/wdt.h> // Include watchdog library void setup() { wdt_enable(WDTO_8S); // Enable watchdog: max 8 seconds } void loop() { wdt_reset(); // Reset watchdog }