Create a gist now

Instantly share code, notes, and snippets.

@ikriz /kwh_monitor.pde Secret
Created Mar 9, 2013

What would you like to do?
The Arduino Sketch for my kWh monitoring project
#include <SPI.h>
#include <Ethernet.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define READINGS 250
#define MS_PER_HOUR 3.6e6
// LCD Connected to A4=SDA & A5=SCM & 5V & GND
LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display
byte mac[] = { 0xDE, 0xAD, 0xBC, 0xEA, 0xFA, 0xCE };
EthernetServer server(80);
float cycles_per_kwh = 187.5; //specific setting for my kwh-meter
unsigned int lower_threshold = 99; // this worked best for me
unsigned int upper_threshold = 101; // this worked best for me
unsigned short max_watt = 6000;
unsigned short readings[READINGS];
unsigned short cursor = 0;
boolean gotenough = false;
unsigned short hits = 0;
long bounceDelay = 50;
struct button {
int pin;
int value;
int state;
int prev;
int last;
long time;
boolean active;
void update()
{
value = digitalRead(pin);
if(value != last) time = millis();
if((millis() - time) > bounceDelay) state = value;
if(state != prev)
{
if(state) active = !active;
prev = state;
}
last = value;
}
};
boolean ledstate = LOW;
unsigned long cycle = 0;
unsigned long previous = 0; // timestamp
int sensorPin = A0; // select the input pin for the potentiometer
int ledPin = 13; // select the pin for the LED
button btn1;
button btn2;
button btn3;
int mode = 0;
unsigned long debounce_time;
double W;
double lastMaxWatt;
int error;
byte glyphs[8][8]={
{B00000,B00000,B00000,B00000,B00000,B00000,B00000,B11111},
{B00000,B00000,B00000,B00000,B00000,B00000,B11111,B11111},
{B00000,B00000,B00000,B00000,B00000,B11111,B11111,B11111},
{B00000,B00000,B00000,B00000,B11111,B11111,B11111,B11111},
{B00000,B00000,B00000,B11111,B11111,B11111,B11111,B11111},
{B00000,B00000,B11111,B11111,B11111,B11111,B11111,B11111},
{B00000,B11111,B11111,B11111,B11111,B11111,B11111,B11111},
{B11111,B11111,B11111,B11111,B11111,B11111,B11111,B11111},
};
void calc_debounce() {
debounce_time = (1000 * ((double) MS_PER_HOUR / ((long) cycles_per_kwh * max_watt)));
}
void setup()
{
calc_debounce();
btn1.pin = 2;
btn2.pin = 3;
btn3.pin = 4;
lcd.init(); // initialize the lcd
lcd.backlight(); // initialize the lcd
for(int i=0; i < 8; i++) lcd.createChar(i, glyphs[i]);
lcd.clear();
pinMode(ledPin, OUTPUT);
pinMode(btn1.pin, INPUT);
pinMode(btn2.pin, INPUT);
pinMode(btn3.pin, INPUT);
if (Ethernet.begin(mac) == 0) error = 1;
}
void loop()
{
EthernetClient client = server.available();
if (client) {
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connnection: close");
client.println();
client.print("watt.value ");
client.print(W,2);
client.print("\n");
client.print("maxwatt.value ");
client.print(lastMaxWatt,2);
client.print("\n");
client.print("cycle.value ");
client.print(cycle);
lastMaxWatt = 0;
break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
//delay(0.11);
// close the connection:
client.stop();
}
// read the value from the sensor:
unsigned short sum = 0;
for (byte i = 0; i < 40; i++) sum += analogRead(sensorPin);
unsigned long bigsum = 0;
for (unsigned short i = 0; i < READINGS; i++) bigsum += readings[i];
unsigned short average = bigsum / READINGS;
unsigned short ratio = (double) sum / (average+1) * 100;
boolean newledstate = ledstate ? (ratio > lower_threshold) : (ratio >= upper_threshold);
if ((!gotenough) || (!newledstate)) {
readings[cursor++] = sum;
if (cursor >= READINGS) {
cursor = 0;
if (!gotenough) {
gotenough = true;
}
}
}
btn3.update();
if(btn3.active)
{
lcd.clear();
btn3.active = false;
if(++mode == 5)
{
lcd.noDisplay();
lcd.noBacklight();
}
else
{
lcd.display();
lcd.backlight();
}
if(mode == 6) mode = 0;
}
LcdOutput(ratio, sum);
if (newledstate) hits++;
if (newledstate == ledstate) return;
digitalWrite(13, ledstate = newledstate);
if (!ledstate) {
hits = 0;
return;
}
unsigned long now = millis();
unsigned long time = now - previous;
if (time < debounce_time) return;
previous = now;
if (!cycle++) {
return;
}
W = 1000 * ((double) MS_PER_HOUR / time) / cycles_per_kwh;
if(W > lastMaxWatt) lastMaxWatt = W;
}
void DrawBar(int line, int pos, byte x)
{
lcd.setCursor(pos,line);
for(int i=0;i<8;i++)
{
if(i-1 < x)
lcd.write(i);
else
lcd.print(' ');
}
}
void LcdOutput(unsigned short ratio, unsigned short sum)
{
if(ratio > 200) ratio = 200;
lcd.setCursor(0,0);
lcd.print("r:");
if(ratio < 1000) lcd.print(' ');
if(ratio < 100) lcd.print(' ');
if(ratio < 10) lcd.print(' ');
lcd.print(ratio);
lcd.print(' ');
if(error != 0)
{
lcd.print("e:");
lcd.print(error);
}
else
{
lcd.print("s:");
unsigned int avg = sum/40;
if(avg < 1000) lcd.print(' ');
if(avg < 100) lcd.print(' ');
if(avg < 10) lcd.print(' ');
lcd.print(avg);
lcd.print(" ");
}
switch(mode)
{
case 0:
DrawBar(1,0,map(ratio,0,200,0,7));
lcd.print(" C:");
lcd.print(cycle);
break;
case 1:
lcd.setCursor(0,1);
lcd.print("W:");
lcd.print(W, 2);
break;
case 2:
btn1.update();
btn2.update();
lcd.setCursor(0,1);
lcd.print("l:");
if(lower_threshold < 100) lcd.print(' ');
lcd.print(lower_threshold);
if(btn2.active){ btn2.active = false; --lower_threshold;}
if(btn1.active){ btn1.active = false; ++lower_threshold;}
break;
case 3:
btn1.update();
btn2.update();
lcd.setCursor(0,1);
lcd.print("u:");
if(upper_threshold < 100) lcd.print(' ');
lcd.print(upper_threshold);
if(btn2.active){ btn2.active = false; --upper_threshold;}
if(btn1.active){ btn1.active = false; ++upper_threshold;}
break;
case 4:
lcd.setCursor(0,1);
lcd.print(Ethernet.localIP());
break;
default:
break;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment