-
-
Save ikriz/c8bdf8c72393da598468 to your computer and use it in GitHub Desktop.
The Arduino Sketch for my kWh monitoring project
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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