I’ve been trying to get the openEnergyMonitor project running on my Photon.
I’m using the following code and it seems to work quite good for a while but then it hard crashes (requiring a power toggle) or just reboots.
What can be the source of error? My Particle is connected to two CT sensors, an AC/AC adapter and one pulse counter via a modified emonTXv2 (where changed the burden resistors to the CTs to 18ohm to comply with 3.3V).
I get quite good readings so there is nothing wrong with the hardware, but it is really annoying that the Photon restarts and crashes. (It is currently powered by a 2A 5V adapter).
#define APIKEY ""
#define emonTxV3
#include "EmonLib/EmonLib.h"
TCPClient myTCP;
EnergyMonitor ct1,ct2,ct3,ct4; // Create instances for each CT channel
#define FILTERSETTLETIME 5000 // Time (ms) to allow the filters to settle before sending data
//http://openenergymonitor.org/emon/buildingblocks/calibration
const float Ical1 = 111.1; // (2000 turns / 18 Ohm burden) = 111.1
const float Ical2 = 111.1; // (2000 turns / 18 Ohm burden) = 111.1
const float Ical3 = 111.1; // (2000 turns / 18 Ohm burden) = 111.1
const float Ical4 = 111.1; // (2000 turns / 18 Ohm burden) = 111.1
//const float Vcal = 268.97; // (230V x 13) / (9V x 1.2) = 276.9 Calibration for UK AC-AC adapter 77DB-06-09
const float Vcal = 260; // Calibration for EU AC-AC adapter 77DE-06-09
const int ppwh = 1; // 1000 pulses/kwh = 1 pulse per wh - Number of pulses per wh - found or set on the meter.
const byte Vrms= 230; // Vrms for apparent power readings (when no AC-AC voltage sample is present)
const byte TIME_BETWEEN_READINGS= 10; //Time between readings
const float phase_shift= 1.7;
const int no_of_samples= 1480;
const int no_of_half_wavelengths= 20;
const int timeout= 2000; //emonLib timeout
const int ACAC_DETECTION_LEVEL= 3000;
const byte min_pulsewidth= 110; // minimum width of interrupt pulse (default pulse output meters = 100ms)
const int pulse_count_ppwh= 10;
const int TEMPERATURE_PRECISION= 11; //9 (93.8ms),10 (187.5ms) ,11 (375ms) or 12 (750ms) bits equal to resplution of 0.5C, 0.25C, 0.125C and 0.0625C
const byte MaxOnewire= 6;
const byte pulse_countINT= D3;
const byte LEDpin= D7;
const byte inPinV= A0;
boolean CT1=1, CT2=1, CT3=1, CT4=1, ACAC=1, debug=1, DS18B20_STATUS=0;
byte CT_count=0;
volatile unsigned int pulseCount = 0;
volatile unsigned int pulsePower = 0;
unsigned long pulsetime = 0; // Record time of interrupt pulse
typedef struct {
int power1, power2, power3, power4, Vrms, temp[MaxOnewire];
unsigned int pulseCount; int pulsePower;
} PayloadTX; // create structure - a neat way of packaging data for RF comms
PayloadTX emontx;
//*********************************************************************************************************************
double calc_rms(int pin, int samples) {
unsigned long sum = 0;
for (int i=0; i<samples; i++) // 178 samples takes about 20ms
{
int raw = (analogRead(0)-512);
sum += (unsigned long)raw * raw;
}
double rms = sqrt((double)sum / samples);
return rms;
}
// The interrupt routine - runs each time a falling edge of a pulse is detected
void onPulse() {
if ( (millis() - pulsetime) > min_pulsewidth) {
pulseCount++; //calculate wh elapsed from time between pulses
pulsePower = int((3600000000.0 / (micros() - pulsetime))/ppwh);
pulsetime = millis();
}
}
void sendGetRequest(const char * server, const char * url) {
if (myTCP.connect(server, 80)) {
Serial.print("Connected to Server");
myTCP.print("GET ");
myTCP.print(url);
myTCP.println(" HTTP/1.1");
myTCP.println("Connection: close");
myTCP.print("Host: ");
myTCP.println(server);
myTCP.println();
myTCP.println();
myTCP.flush();
myTCP.stop();
}
}
void send_data() {
digitalWrite(D7, HIGH);
String data = "";
data += "power1:" + String(emontx.power1);
data += ",power2:" + String(emontx.power2);
data += ",power3:" + String(emontx.power3);
data += ",power4:" + String(emontx.power3);
data += ",Vrms:" + String(emontx.Vrms);
data += ",temp:" + String(emontx.temp[0]);
data += ",pulseCount:" + String(emontx.pulseCount);
data += ",pulsePower:" + String(emontx.pulsePower);
data += ",uptime:" + String(millis()/1000);
String path = "/input/post.json?node=test&json={" + data + "}&apikey=" + APIKEY;
sendGetRequest("emoncms.org", path);
digitalWrite(D7, LOW);
}
void setup() {
pinMode(A0, INPUT); pinMode(A1, INPUT); pinMode(A2, INPUT); pinMode(A3, INPUT); pinMode(A4, INPUT);
pinMode(pulse_countINT, INPUT);
RGB.control(true);
Serial.begin(9600);
Serial.println(F(""));
Serial.println(F("OpenEnergyMonitor.org"));
Spark.publish("init", "OpenEnergyMonitor.org");
attachInterrupt(pulse_countINT, onPulse, FALLING); // Attach pulse counting interrupt CT1=1;CT2=1;CT3=1;CT4=1;CT_count=4;
// Calculate if there is an ACAC adapter on analog input 0
//double vrms = calc_rms(0,1780) * (Vcal * (3.3/1024) );
double vrms = calc_rms(A0, 1780) * 0.87;
if (vrms>90) ACAC = 1; else ACAC=0;
if (CT1) ct1.current(A1, Ical1);
if (CT2) ct2.current(A2, Ical2);
if (CT3) ct3.current(A3, Ical3);
if (CT4) ct4.current(A4, Ical4);
if (ACAC) {
if (CT1) ct1.voltage(A0, Vcal, phase_shift); // ADC pin, Calibration, phase_shift
if (CT2) ct2.voltage(A0, Vcal, phase_shift); // ADC pin, Calibration, phase_shift
if (CT3) ct3.voltage(A0, Vcal, phase_shift); // ADC pin, Calibration, phase_shift
if (CT4) ct4.voltage(A0, Vcal, phase_shift); // ADC pin, Calibration, phase_shift
}
RGB.control(false);
}
void loop() {
if (ACAC) {
delay(200); //if powering from AC-AC allow time for power supply to settle
emontx.Vrms=0; //Set Vrms to zero, this will be overwirtten by CT 1-4
}
if (CT1) {
if (ACAC) {
ct1.calcVI(no_of_half_wavelengths,timeout); emontx.power1=ct1.realPower;
emontx.Vrms=ct1.Vrms*100;
} else
emontx.power1 = ct1.calcIrms(no_of_samples)*Vrms; // Calculate Apparent Power 1 1480 is number of sample
}
if (CT2) {
if (ACAC) {
ct2.calcVI(no_of_half_wavelengths,timeout); emontx.power2=ct2.realPower;
emontx.Vrms=ct2.Vrms*100;
} else
emontx.power2 = ct2.calcIrms(no_of_samples)*Vrms; // Calculate Apparent Power 1 1480 is number of samples
}
if (CT3) {
if (ACAC) {
ct3.calcVI(no_of_half_wavelengths,timeout); emontx.power3=ct3.realPower;
emontx.Vrms=ct3.Vrms*100;
} else
emontx.power3 = ct3.calcIrms(no_of_samples)*Vrms; // Calculate Apparent Power 1 1480 is number of samples
}
if (CT4) {
if (ACAC) {
ct4.calcVI(no_of_half_wavelengths,timeout); emontx.power4=ct4.realPower;
emontx.Vrms=ct4.Vrms*100;
} else
emontx.power4 = ct4.calcIrms(no_of_samples)*Vrms; // Calculate Apparent Power 1 1480 is number of samples
}
if (pulseCount) // if the ISR has counted some pulses, update the total count
{
emontx.pulseCount += pulseCount;
pulseCount = 0;
emontx.pulsePower = pulsePower;
}
send_data();
delay(TIME_BETWEEN_READINGS*1000);
}