initial
This commit is contained in:
20
Metro/LICENSE
Normal file
20
Metro/LICENSE
Normal file
@@ -0,0 +1,20 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2013 thomasfredericks
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
61
Metro/Metro.cpp
Normal file
61
Metro/Metro.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
|
||||
|
||||
#if defined(ARDUINO) && ARDUINO >= 100
|
||||
#include "Arduino.h"
|
||||
#else
|
||||
#include "WProgram.h"
|
||||
#endif
|
||||
#include "Metro.h"
|
||||
|
||||
Metro::Metro()
|
||||
{
|
||||
|
||||
this->interval_millis = 1000;
|
||||
|
||||
}
|
||||
|
||||
|
||||
Metro::Metro(unsigned long interval_millis)
|
||||
{
|
||||
|
||||
this->interval_millis = interval_millis;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Metro::interval(unsigned long interval_millis)
|
||||
{
|
||||
this->interval_millis = interval_millis;
|
||||
}
|
||||
|
||||
uint8_t Metro::check()
|
||||
{
|
||||
|
||||
unsigned long now = millis();
|
||||
|
||||
if ( interval_millis == 0 ){
|
||||
previous_millis = now;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ( (now - previous_millis) >= interval_millis) {
|
||||
#ifdef NOCATCH-UP
|
||||
previous_millis = now ;
|
||||
#else
|
||||
previous_millis += interval_millis ;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void Metro::reset()
|
||||
{
|
||||
|
||||
this->previous_millis = millis();
|
||||
|
||||
}
|
||||
|
||||
|
||||
49
Metro/Metro.h
Normal file
49
Metro/Metro.h
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
Main code by Thomas O Fredericks (tof@t-o-f.info)
|
||||
Contributions by Paul Bouchier and Benjamin.soelberg
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef Metro_h
|
||||
#define Metro_h
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
|
||||
class Metro
|
||||
{
|
||||
|
||||
public:
|
||||
Metro();
|
||||
Metro(unsigned long interval_millis);
|
||||
void interval(unsigned long interval_millis);
|
||||
uint8_t check();
|
||||
void reset();
|
||||
|
||||
private:
|
||||
unsigned long previous_millis, interval_millis;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
1
Metro/README.md
Normal file
1
Metro/README.md
Normal file
@@ -0,0 +1 @@
|
||||
Please visit https://github.com/thomasfredericks/Metro-Arduino-Wiring for latest code and documentation.
|
||||
30
Metro/examples/blinking/blinking.ino
Normal file
30
Metro/examples/blinking/blinking.ino
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
This code will blink an LED attached to pin 13 on and off.
|
||||
It will stay on for 0.25 seconds.
|
||||
It will stay off for 1 second.
|
||||
*/
|
||||
#include <Metro.h> //Include Metro library
|
||||
#define LED 13 // Define the led's pin
|
||||
|
||||
//Create a variable to hold theled's current state
|
||||
int state = HIGH;
|
||||
|
||||
// Instanciate a metro object and set the interval to 250 milliseconds (0.25 seconds).
|
||||
Metro ledMetro = Metro(250);
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED,OUTPUT);
|
||||
digitalWrite(LED,state);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
if (ledMetro.check() == 1) { // check if the metro has passed its interval .
|
||||
if (state==HIGH) state=LOW;
|
||||
else state=HIGH;
|
||||
|
||||
digitalWrite(LED,state);
|
||||
}
|
||||
}
|
||||
51
Metro/examples/blinking_2_instances/blinking_2_instances.ino
Normal file
51
Metro/examples/blinking_2_instances/blinking_2_instances.ino
Normal file
@@ -0,0 +1,51 @@
|
||||
// This code will blink output 13 every 250 ms
|
||||
// abd will blink output 9 every 125 ms
|
||||
|
||||
|
||||
#include <Metro.h> // Include Metro library
|
||||
#define LED0 13 // Define a LED pin
|
||||
#define LED1 9 // Define another LED pin
|
||||
|
||||
// Create variables to hold the LED states
|
||||
int state0 = HIGH;
|
||||
int state1 = HIGH;
|
||||
|
||||
// Instantiate a metro object and set the interval to 250 milliseconds (0.25 seconds).
|
||||
Metro metro0 = Metro(250);
|
||||
|
||||
// Instantiate another metro object and set the interval to 125 milliseconds (0.125 seconds).
|
||||
Metro metro1 = Metro(125);
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED0,OUTPUT);
|
||||
digitalWrite(LED0,state0);
|
||||
|
||||
pinMode(LED1,OUTPUT);
|
||||
digitalWrite(LED1,state1);
|
||||
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
if (metro0.check() == 1) { // check if the metro has passed its interval .
|
||||
if (state0==HIGH) {
|
||||
state0=LOW;
|
||||
} else {
|
||||
state0=HIGH;
|
||||
}
|
||||
digitalWrite(LED0,state0);
|
||||
}
|
||||
|
||||
if (metro1.check() == 1) { // check if the metro has passed its interval .
|
||||
if (state1==HIGH) {
|
||||
state1=LOW;
|
||||
} else {
|
||||
state1=HIGH;
|
||||
}
|
||||
digitalWrite(LED1,state1);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
36
Metro/examples/blinking_2_intervals/blinking_2_intervals.ino
Normal file
36
Metro/examples/blinking_2_intervals/blinking_2_intervals.ino
Normal file
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
This code will blink an LED attached to pin 13 on and off.
|
||||
It will stay on for 0.25 seconds.
|
||||
It will stay off for 1 second.
|
||||
*/
|
||||
#include <Metro.h> //Include Metro library
|
||||
#define LED 13 // Define the led's pin
|
||||
|
||||
//Create a variable to hold theled's current state
|
||||
int state = HIGH;
|
||||
|
||||
// Instanciate a metro object and set the interval to 250 milliseconds (0.25 seconds).
|
||||
Metro ledMetro = Metro(250);
|
||||
|
||||
void setup()
|
||||
{
|
||||
pinMode(LED,OUTPUT);
|
||||
digitalWrite(LED,state);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
|
||||
if (ledMetro.check() == 1) { // check if the metro has passed its interval .
|
||||
if (state==HIGH) {
|
||||
state=LOW;
|
||||
ledMetro.interval(250); // if the pin is HIGH, set the interval to 0.25 seconds.
|
||||
}
|
||||
else {
|
||||
ledMetro.interval(1000); // if the pin is LOW, set the interval to 1 second.
|
||||
state=HIGH;
|
||||
}
|
||||
digitalWrite(LED,state);
|
||||
}
|
||||
}
|
||||
|
||||
24
Metro/examples/serialInterval/serialInterval.ino
Normal file
24
Metro/examples/serialInterval/serialInterval.ino
Normal file
@@ -0,0 +1,24 @@
|
||||
// This example sends a Serial message every 250 milliseconds
|
||||
|
||||
#include <Metro.h> // Include the Metro library
|
||||
|
||||
Metro serialMetro = Metro(250); // Instantiate an instance
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200); // Start the Serial communication
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
if (serialMetro.check() == 1) { // check if the metro has passed it's interval .
|
||||
// Output all the analog readings seperated by a space character
|
||||
for (int i = 0; i < 6; i++ ) {
|
||||
Serial.print (analogRead( i) );
|
||||
Serial.print(32,BYTE);
|
||||
}
|
||||
// Terminate message with a linefeed and a carriage return
|
||||
Serial.print(13,BYTE);
|
||||
Serial.print(10,BYTE);
|
||||
}
|
||||
}
|
||||
|
||||
25
Metro/keywords.txt
Normal file
25
Metro/keywords.txt
Normal file
@@ -0,0 +1,25 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map For Test
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
Metro KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
check KEYWORD2
|
||||
interval KEYWORD2
|
||||
|
||||
#######################################
|
||||
# Instances (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
|
||||
BIN
ferrarismonitor.zip
Normal file
BIN
ferrarismonitor.zip
Normal file
Binary file not shown.
141
ferrarismonitor/FerrarisMonitor/FerrarisMonitor.ino
Normal file
141
ferrarismonitor/FerrarisMonitor/FerrarisMonitor.ino
Normal file
@@ -0,0 +1,141 @@
|
||||
int portLeft = 4;
|
||||
int portRight = 3;
|
||||
|
||||
long sampleMetro = 10;
|
||||
long printMetro = 100;
|
||||
|
||||
int16_t stateLeft = 0;
|
||||
int16_t stateRight = 0;
|
||||
|
||||
int16_t minLeft = 1024;
|
||||
int16_t maxLeft = 0;
|
||||
int16_t nextMinLeft = 1024;
|
||||
int16_t nextMaxLeft = 0;
|
||||
int16_t minRight = 1024;
|
||||
int16_t maxRight = 0;
|
||||
int16_t nextMinRight = 1024;
|
||||
int16_t nextMaxRight = 0;
|
||||
|
||||
int16_t margin = 5;
|
||||
int16_t rotation = 1; // right = 1, normal, -1 is reverse
|
||||
|
||||
int16_t lightLeft = 0; // latest reading
|
||||
int16_t lightRight = 0;
|
||||
|
||||
double prevMs = 0; // timestamp of last peak
|
||||
long previousSample = 0;
|
||||
long previousPrint = 0;
|
||||
double len = 0; // delay between the last two peaks
|
||||
|
||||
void setup() {
|
||||
Serial.begin(57600);
|
||||
Serial.println("\n[Monitoring a Ferraris Meter]");
|
||||
|
||||
//portLeft.mode(INPUT);
|
||||
//portRight.mode(INPUT);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
unsigned long currentMillis = millis();
|
||||
// take a reading from both sensors
|
||||
if(currentMillis - previousSample > sampleMetro) {
|
||||
previousSample = currentMillis;
|
||||
// read sensors
|
||||
lightLeft = analogRead(portLeft);
|
||||
lightRight = analogRead(portRight);
|
||||
|
||||
// to take into account changing peak sizes, we follow the peak size continuously
|
||||
// the found peak size serves as the target (minus a small margin) for the next peak detection
|
||||
// update minimum and maximum for the left sensor
|
||||
if ( lightLeft > nextMaxLeft ) {
|
||||
nextMaxLeft = lightLeft;
|
||||
}
|
||||
// we also do this for the valley
|
||||
if ( lightLeft < nextMinLeft ) {
|
||||
nextMinLeft = lightLeft;
|
||||
}
|
||||
|
||||
// and the same for the right sensor
|
||||
// update minimum and maximum for the right sensor
|
||||
if ( lightRight > nextMaxRight ) {
|
||||
nextMaxRight = lightRight;
|
||||
}
|
||||
if ( lightRight < nextMinRight ) {
|
||||
nextMinRight = lightRight;
|
||||
}
|
||||
|
||||
if (( stateLeft == 0 ) && (lightLeft > maxLeft - margin )) {
|
||||
// make state = 1 when light above threshold and state == 0
|
||||
stateLeft = 1;
|
||||
|
||||
// we are now going to a minimum, reset the minimum value of the left sensor
|
||||
minLeft = nextMinLeft;
|
||||
nextMinLeft = 1024;
|
||||
|
||||
// calculate rotation direction
|
||||
if (( stateRight == 0 ) && (rotation < 1)) {
|
||||
rotation++;
|
||||
} else if ((stateRight == 1 ) && (rotation > -1)) {
|
||||
rotation--;
|
||||
}
|
||||
|
||||
// calculate delay between the last two peaks, now and prevMs
|
||||
double ms = millis();
|
||||
len = ms - prevMs;
|
||||
prevMs = ms;
|
||||
|
||||
} else if ((stateLeft == 1 ) && (lightLeft < minLeft + margin)) {
|
||||
// make state = 0 when light below threshold and state == 1
|
||||
stateLeft = 0;
|
||||
|
||||
// we are now going to a maximum, reset the maximum value of the left sensor
|
||||
maxLeft = nextMaxLeft;
|
||||
nextMaxLeft = 0;
|
||||
|
||||
}
|
||||
|
||||
if (( stateRight == 0 ) && (lightRight > maxRight - margin )) {
|
||||
// make state = 1 when light above threshold and state == 0
|
||||
stateRight = 1;
|
||||
|
||||
// we are now going to a minimum, reset the minimum value of the right sensor
|
||||
minRight = nextMinRight;
|
||||
nextMinRight = 1024;
|
||||
|
||||
} else if ((stateRight == 1 ) && (lightRight < minRight + margin)) {
|
||||
// make state = 0 when light below threshold and state == 1
|
||||
stateRight = 0;
|
||||
|
||||
// we are now going to a maximum, reset the maximum value of the right sensor
|
||||
maxRight = nextMaxRight;
|
||||
nextMaxRight = 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// print current status
|
||||
if(currentMillis - previousPrint > printMetro) {
|
||||
previousPrint = currentMillis;
|
||||
// calculate new delay between now and the previous peak (prevMs)
|
||||
double ms = millis();
|
||||
double tempDelay = ms - prevMs;
|
||||
|
||||
// if 'tempDelay' is larger than the delay between the last two peaks 'len' it means that the disc is spinning slower and power usage is decreasing
|
||||
// so max power consumption at this moment is not len, but tempDelay.
|
||||
if ( len > tempDelay ) {
|
||||
tempDelay = len;
|
||||
}
|
||||
|
||||
int watt = rotation * 4800000 / tempDelay; // my kwh meter says 600 rotations per kwh
|
||||
|
||||
Serial.print(watt);
|
||||
Serial.print(" | ");
|
||||
Serial.print(rotation);
|
||||
Serial.print(" | ");
|
||||
Serial.print(lightLeft);
|
||||
Serial.print(" | ");
|
||||
Serial.println(lightRight);
|
||||
}
|
||||
}
|
||||
|
||||
38
kwhmeter.conf
Normal file
38
kwhmeter.conf
Normal file
@@ -0,0 +1,38 @@
|
||||
[kWh Settings]
|
||||
leftchannelid = 0
|
||||
rightchannelid = 2
|
||||
|
||||
[kWh]
|
||||
importcounter = 1359430
|
||||
exportcounter = 1190820
|
||||
rotationsperkwh = 480
|
||||
minleft = 76
|
||||
maxleft = 722
|
||||
minmarginleft = 396
|
||||
maxmarginleft = 594
|
||||
minright = 92
|
||||
maxright = 807
|
||||
minmarginright = 447
|
||||
maxmarginright = 665
|
||||
cumuliday = 20150331
|
||||
importday = 2229
|
||||
exportday = 3077
|
||||
|
||||
[MySQL]
|
||||
host = localhost
|
||||
user = root
|
||||
passwd = root
|
||||
db = kwhRijnsraat214
|
||||
|
||||
[pvout]
|
||||
pvout_enabled = true
|
||||
pvout_apikey = b8795509823e9439f9d107c8f608c0dd7a96239f
|
||||
pvout_sysid = 28910
|
||||
|
||||
[EmonCMS]
|
||||
emoncmspath = emoncms
|
||||
domain = 192.168.2.2
|
||||
apikey = 1e01f7ef0c6c83f4c2fe0bced49374ad
|
||||
nodeid = 10
|
||||
emon_enable = true
|
||||
|
||||
554
kwhmeter_20131014.py
Normal file
554
kwhmeter_20131014.py
Normal file
@@ -0,0 +1,554 @@
|
||||
# This Python script needs a SPI module.
|
||||
# For more info, please see:
|
||||
# http://www.100randomtasks.com/simple-spi-on-raspberry-pi
|
||||
#
|
||||
# This script also uses a "LoadAverage" module. This module can be downloaded from:
|
||||
# http://patrick.i234.me/kwhmeter/LoadAverage.py
|
||||
#
|
||||
# This script is written for use on a Raspberri Pi, in combination with some
|
||||
# custom-made hardware.
|
||||
# The schematic of the hardware can be found here:
|
||||
# https://www.circuitlab.com/circuit/eae95u/raspberry-pi-kwh-meter/
|
||||
#
|
||||
# or an PDF can be found on my own site:
|
||||
# http://patrick.i234.me/kwhmeter/raspberry-pi-kwh-meter.pdf
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
# Unused modules, that I might incorporate later
|
||||
#import rrdtool
|
||||
#import os
|
||||
|
||||
import MySQLdb
|
||||
|
||||
|
||||
import spidev
|
||||
import time
|
||||
import RPi.GPIO as GPIO
|
||||
import ConfigParser
|
||||
# for the module LoadAverage, see: http://patrick.i234.me/kwhmeter/LoadAverage.py
|
||||
import LoadAverage
|
||||
import datetime
|
||||
from datetime import date
|
||||
# For PVoutput
|
||||
import urllib, urllib2
|
||||
|
||||
|
||||
DEBUG = False
|
||||
|
||||
# GPIO Pins for the different components:
|
||||
switch = 23
|
||||
redLED = 17
|
||||
greenLED = 18
|
||||
boardLED = 22
|
||||
|
||||
|
||||
# Initialise SPI
|
||||
spi = spidev.SpiDev()
|
||||
spi.open(0, 0)
|
||||
|
||||
|
||||
# read SPI data from MCP3008 chip, 8 possible adc's (0 thru 7)
|
||||
def readadc(adcnum):
|
||||
if ((adcnum > 7) or (adcnum < 0)):
|
||||
return -1
|
||||
r = spi.xfer2([1, (8 + adcnum) << 4, 0])
|
||||
adcout = ((r[1] & 3) << 8) + r[2]
|
||||
return adcout
|
||||
|
||||
|
||||
def turnonLED(LED):
|
||||
GPIO.output(LED, True)
|
||||
|
||||
|
||||
def turnoffLED(LED):
|
||||
GPIO.output(LED, False)
|
||||
|
||||
|
||||
def toggleLED(LED):
|
||||
GPIO.output(LED, GPIO.input(LED) ^ 1)
|
||||
|
||||
|
||||
def writeLog(watt, total, importCount, exportCount, rotTime, loadaverage):
|
||||
localtime = time.localtime(time.time())
|
||||
filename = '%s_kWh-meter.log' % time.strftime("%Y-%m-%d", localtime)
|
||||
line = "%s\t%s\t%s\t%s\t%.3f\t%.3f\t%.3f\t%.0f\t%.3f\t%.3f\t%.3f\n" % (
|
||||
time.strftime("%Y-%m-%d %H:%M:00", localtime), time.strftime("%Y-%m-%d", localtime),
|
||||
time.strftime("%H:%M:00", localtime), watt, total, importCount, exportCount, rotTime, loadaverage[0],
|
||||
loadaverage[1], loadaverage[2])
|
||||
|
||||
logfile = open(filename, 'a')
|
||||
try:
|
||||
logfile.write(line)
|
||||
finally:
|
||||
logfile.close()
|
||||
|
||||
logfile.close()
|
||||
|
||||
|
||||
def writesettings(config):
|
||||
with open('kwhmeter.conf', 'wb') as configfile:
|
||||
config.write(configfile)
|
||||
return True
|
||||
|
||||
|
||||
def readsettings():
|
||||
config = ConfigParser.SafeConfigParser()
|
||||
config.read('kwhmeter.conf')
|
||||
|
||||
if not config.has_section('kWh Settings'):
|
||||
config.add_section('kWh Settings')
|
||||
if not config.has_option('kWh Settings', 'LeftChannelID'):
|
||||
config.set('kWh Settings', 'LeftChannelID', '2')
|
||||
if not config.has_option('kWh Settings', 'RightChannelID'):
|
||||
config.set('kWh Settings', 'RightChannelID', '0')
|
||||
|
||||
|
||||
# Section kWh data
|
||||
if not config.has_section('kWh'):
|
||||
config.add_section('kWh')
|
||||
if not config.has_option('kWh', 'importCounter'):
|
||||
config.set('kWh', 'importCounter', '0')
|
||||
if not config.has_option('kWh', 'exportCounter'):
|
||||
config.set('kWh', 'exportCounter', '0')
|
||||
if not config.has_option('kWh', 'rotationsPerKWh'):
|
||||
config.set('kWh', 'rotationsPerKWh', '600')
|
||||
if not config.has_option('kWh', 'cumuliday'):
|
||||
config.set('kWh', 'cumuliday', date.today().strftime("%Y%m%d"))
|
||||
|
||||
# Add Pvoutput stuff
|
||||
if not config.has_section('pvout'):
|
||||
config.add_section('pvout')
|
||||
if not config.has_option('pvout','pvout_enabled'):
|
||||
config.set('pvout','pvout_enabled','false')
|
||||
if not config.has_option('pvout','pvout_apikey'):
|
||||
config.set('pvout','pvout_apikey','0')
|
||||
if not config.has_option('pvout','pvout_sysid'):
|
||||
config.set('pvout','pvout_sysid','0')
|
||||
|
||||
# If you want to save in a MySQL DB, uncomment below:
|
||||
# Section MySQL
|
||||
#if not config.has_section('MySQL'):
|
||||
# config.add_section('MySQL')
|
||||
#if not config.has_option('MySQL', 'host'):
|
||||
# config.set('MySQL', 'host', 'localhost')
|
||||
#if not config.has_option('MySQL', 'user'):
|
||||
# config.set('MySQL', 'user', 'root')
|
||||
#if not config.has_option('MySQL', 'passwd'):
|
||||
# config.set('MySQL', 'passwd', 'root')
|
||||
#if not config.has_option('MySQL', 'db'):
|
||||
# config.set('MySQL', 'db', 'kwhRijnsraat214')
|
||||
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def savekwhdata(config, importCounter, exportCounter):
|
||||
config.set('kWh', 'importCounter', "%.0f" % importCounter)
|
||||
config.set('kWh', 'exportCounter', "%.0f" % exportCounter)
|
||||
writesettings(config)
|
||||
|
||||
|
||||
# If you want to save in a MySQL DB, uncomment below:
|
||||
#def savetodb(config, watt, total, imported, exported):
|
||||
# section = 'MySQL'
|
||||
# localtime = time.localtime(time.time())
|
||||
#
|
||||
# conn = MySQLdb.connect(host = config.get(section, 'host'),
|
||||
# user = config.get(section, 'user'),
|
||||
# passwd = config.get(section, 'passwd'),
|
||||
# db = config.get(section, 'db'))
|
||||
# cursor = conn.cursor()
|
||||
#
|
||||
# try:
|
||||
# cursor.execute(
|
||||
# "INSERT INTO `DayDatakWh` (`DateTime`, `CurrentPower`, `ETotalToday`, `EImportToday`, `EExportToday`, `CurrentUsage`, `EUsageToday`, `PVOutput`, `CHANGETIME`) VALUES ('%s', %s, %.3f, %.3f, %.3f, NULL, NULL, NULL, '0000-00-00 00:00:00');" % (
|
||||
# time.strftime("%Y-%m-%d %H:%M:00", localtime), watt, total, imported, exported))
|
||||
# conn.commit()
|
||||
# except:
|
||||
# conn.rollback()
|
||||
# conn.close()
|
||||
#
|
||||
# return True
|
||||
|
||||
def printinfo(line):
|
||||
timeStr = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
|
||||
print "%s\t%s" % (timeStr, line)
|
||||
#serialDev.writeLine("%s\t%s" % (timeStr, line))
|
||||
|
||||
def exportPvoutput(config, gentotal, genpower, contotal, conpower):
|
||||
|
||||
pvout_enabled = config.getboolean('pvout','pvout_enabled')
|
||||
pvout_apikey = config.get('pvout','pvout_apikey')
|
||||
pvout_sysid = config.get('pvout','pvout_sysid')
|
||||
|
||||
url = "http://pvoutput.org/service/r2/addstatus.jsp"
|
||||
now = datetime.datetime.now()
|
||||
|
||||
get_data = {
|
||||
'key': pvout_apikey,
|
||||
'sid': pvout_sysid,
|
||||
'd': now.strftime('%Y%m%d'),
|
||||
't': now.strftime('%H:%M'),
|
||||
'v1': gentotal * 1000,
|
||||
'v2': genpower,
|
||||
'v3': contotal * 1000,
|
||||
'v4': conpower,
|
||||
'c1': "1"
|
||||
}
|
||||
|
||||
|
||||
get_data_encoded = urllib.urlencode(get_data) # UrlEncode the parameters
|
||||
printinfo(get_data_encoded)
|
||||
request_object = urllib2.Request(url + '?' + get_data_encoded) # Create request object
|
||||
try:
|
||||
response = urllib2.urlopen(request_object) #make the request and store the response
|
||||
printinfo("Pvoutput Exported")
|
||||
return True
|
||||
except urllib.error.HTTPError, e:
|
||||
printinfo('HTTPError = ' + str(e.code))
|
||||
return False
|
||||
except Exception:
|
||||
import traceback
|
||||
checksLogger.error('generic exception: ' + traceback.format_exc())
|
||||
|
||||
#http://pvoutput.org/service/r2/addstatus.jsp?
|
||||
|
||||
def calibratesensors(config):
|
||||
printinfo("Do calibration of sensors . . .")
|
||||
sensorleftLValue = 9999
|
||||
sensorleftHValue = -1
|
||||
sensorrightLValue = 9999
|
||||
sensorrightHValue = -1
|
||||
|
||||
turnoffLED(boardLED)
|
||||
turnoffLED(greenLED)
|
||||
turnonLED(redLED)
|
||||
|
||||
startTime = millis()
|
||||
elapsedTime = millis() - startTime
|
||||
startBlink = millis()
|
||||
startInfo = millis()
|
||||
|
||||
sensorleftDiff = 0
|
||||
sensorrightDiff = 0
|
||||
|
||||
while (elapsedTime < 30000) or (sensorleftDiff < 40) or (sensorrightDiff < 40): #or not GPIO.input(switch):
|
||||
# run calibration for min. 10 seconds,
|
||||
# and distance between low and high value must be at least 40 ticks
|
||||
# or while the switch on the board is hold down (pressing the switch = 0, not pressing the switch = 1)
|
||||
|
||||
sensordata = samplesensors(config)
|
||||
sensorleftCurrent = sensordata['left']
|
||||
sensorrightCurrent = sensordata['right']
|
||||
|
||||
if sensorleftLValue > sensorleftCurrent:
|
||||
sensorleftLValue = sensorleftCurrent
|
||||
if sensorleftHValue < sensorleftCurrent:
|
||||
sensorleftHValue = sensorleftCurrent
|
||||
|
||||
if sensorrightLValue > sensorrightCurrent:
|
||||
sensorrightLValue = sensorrightCurrent
|
||||
if sensorrightHValue < sensorrightCurrent:
|
||||
sensorrightHValue = sensorrightCurrent
|
||||
|
||||
if DEBUG:
|
||||
printinfo("Sensor left: %s\tSensor right: %s" % (sensorleftCurrent, sensorrightCurrent))
|
||||
|
||||
if millis() - startBlink > 100:
|
||||
toggleLED(boardLED)
|
||||
toggleLED(greenLED)
|
||||
toggleLED(redLED)
|
||||
startBlink = millis()
|
||||
|
||||
|
||||
sensorleftDiff = sensorleftHValue - sensorleftLValue
|
||||
sensorrightDiff = sensorrightHValue - sensorrightLValue
|
||||
|
||||
if millis() - startInfo > 1000:
|
||||
printinfo("Time %s: \tSL: %s (diff: %s) \t\tSR: %s (diff: %s)" % (elapsedTime, sensorleftCurrent, sensorleftDiff, sensorrightCurrent, sensorrightDiff))
|
||||
startInfo = millis()
|
||||
|
||||
|
||||
time.sleep(0.1)
|
||||
elapsedTime = millis() - startTime
|
||||
|
||||
|
||||
sensorleftLTh = sensorleftLValue + ((sensorleftDiff / 10) * 5) # 50% above min
|
||||
sensorleftHTh = sensorleftHValue - ((sensorleftDiff / 10) * 2) # 20% below max
|
||||
sensorrightLTh = sensorrightLValue + ((sensorrightDiff / 10) * 5) # 50% above min
|
||||
sensorrightHTh = sensorrightHValue - ((sensorrightDiff / 10) * 2) # 20% below max
|
||||
|
||||
turnoffLED(boardLED)
|
||||
turnoffLED(greenLED)
|
||||
turnoffLED(redLED)
|
||||
|
||||
printinfo("Calibration done!")
|
||||
printinfo("Left low: %s" % sensorleftLValue)
|
||||
printinfo(" high: %s" % sensorleftHValue)
|
||||
printinfo(" diff: %s" % sensorleftDiff)
|
||||
printinfo(" lthld.%s" % sensorleftLTh)
|
||||
printinfo(" hthld.%s" % sensorleftHTh)
|
||||
printinfo("Right low: %s" % sensorrightLValue)
|
||||
printinfo(" high: %s" % sensorrightHValue)
|
||||
printinfo(" diff: %s" % sensorrightDiff)
|
||||
printinfo(" lthld.%s" % sensorrightLTh)
|
||||
printinfo(" hthld.%s" % sensorrightHTh)
|
||||
printinfo("")
|
||||
|
||||
config.set('kWh', 'minleft', "%.0f" % sensorleftLValue)
|
||||
config.set('kWh', 'maxleft', "%.0f" % sensorleftHValue)
|
||||
config.set('kWh', 'minmarginleft', "%.0f" % sensorleftLTh)
|
||||
config.set('kWh', 'maxmarginleft', "%.0f" % sensorleftHTh)
|
||||
|
||||
config.set('kWh', 'minright', "%.0f" % sensorrightLValue)
|
||||
config.set('kWh', 'maxright', "%.0f" % sensorrightHValue)
|
||||
config.set('kWh', 'minmarginright', "%.0f" % sensorrightLTh)
|
||||
config.set('kWh', 'maxmarginright', "%.0f" % sensorrightHTh)
|
||||
|
||||
return config
|
||||
|
||||
|
||||
def millis():
|
||||
return int(round(time.time() * 1000))
|
||||
|
||||
|
||||
def samplesensors(config):
|
||||
# Sample the left and right sensor for maxsamples times (in order to get an average value)
|
||||
leftid = config.getint('kWh Settings', 'LeftChannelID')
|
||||
rightid = config.getint('kWh Settings', 'RightChannelID')
|
||||
maxsamples = 20
|
||||
sensorleft = 0
|
||||
sensorright = 0
|
||||
|
||||
for loopCount in range(0, maxsamples):
|
||||
sensorleft += readadc(leftid)
|
||||
sensorright += readadc(rightid)
|
||||
#print "%s | %s" % (sensorleft, sensorright)
|
||||
sensorleft /= maxsamples
|
||||
sensorright /= maxsamples
|
||||
|
||||
return {'left': sensorleft, 'right': sensorright}
|
||||
|
||||
|
||||
def dotFollower(config):
|
||||
# This is the main part of the code, which will start to minitor the black dot on the disc
|
||||
|
||||
# Do some initialisations
|
||||
rotationsperkwh = config.getfloat("kWh", "rotationsPerKWh") * 1.00
|
||||
counterimport = config.getint("kWh", "importCounter")
|
||||
counterexport = config.getint("kWh", "exportCounter")
|
||||
countertotal = counterimport + counterexport
|
||||
currentpower = 0
|
||||
timeperrotation = 0
|
||||
|
||||
left = False
|
||||
right = False
|
||||
leftdetected = False
|
||||
rightdetected = False
|
||||
lefttimestamp = time.time()
|
||||
leftprevtimestamp = time.time()
|
||||
righttimestamp = time.time()
|
||||
rightprevtimestamp = time.time()
|
||||
sensorinnertimestamp = time.time()
|
||||
sensorinnerlength = 0
|
||||
sensoroutertimestamp = time.time()
|
||||
sensoroutherlength = 0
|
||||
exportpower = 0
|
||||
importpower = 0
|
||||
|
||||
thisday = config.get("kWh", "cumuliday")
|
||||
printinfo("Date: %s" % thisday)
|
||||
|
||||
|
||||
leftmin = config.getint("kWh", "minmarginleft")
|
||||
leftmax = config.getint("kWh", "maxmarginleft")
|
||||
rightmin = config.getint("kWh", "minmarginright")
|
||||
rightmax = config.getint("kWh", "maxmarginright")
|
||||
|
||||
logexported = False
|
||||
loadaverage = LoadAverage.Loadaverage()
|
||||
loadaverageadded = False
|
||||
|
||||
# Keep on running while the switch is NOT pressed
|
||||
while 1: #GPIO.input(switch):
|
||||
sensordata = samplesensors(config)
|
||||
|
||||
# left sensor
|
||||
if sensordata['left'] >= leftmax and not left:
|
||||
# turn left to False
|
||||
left = True
|
||||
turnonLED(greenLED)
|
||||
leftdetected = True
|
||||
leftprevtimestamp = lefttimestamp
|
||||
lefttimestamp = time.time()
|
||||
#printinfo("Left sensor: . %.5f secs" % (lefttimestamp - leftprevtimestamp))
|
||||
if not rightdetected:
|
||||
sensorinnertimestamp = time.time()
|
||||
sensoroutherlength = time.time() - sensoroutertimestamp
|
||||
else:
|
||||
sensoroutertimestamp = time.time()
|
||||
sensorinnerlength = time.time() - sensorinnertimestamp
|
||||
|
||||
if sensordata['left'] <= leftmin and left:
|
||||
# turn left to False
|
||||
left = False
|
||||
turnoffLED(greenLED)
|
||||
#printinfo("Left off")
|
||||
|
||||
|
||||
|
||||
# right sensor
|
||||
if sensordata['right'] >= rightmax and not right:
|
||||
# turn right to False
|
||||
right = True
|
||||
turnonLED(redLED)
|
||||
rightdetected = True
|
||||
rightprevtimestamp = righttimestamp
|
||||
righttimestamp = time.time()
|
||||
#printinfo("Right sensor:. %.5f secs" % (righttimestamp - rightprevtimestamp))
|
||||
if not leftdetected:
|
||||
sensorinnertimestamp = time.time()
|
||||
sensoroutherlength = time.time() - sensoroutertimestamp
|
||||
else:
|
||||
sensoroutertimestamp = time.time()
|
||||
sensorinnerlength = time.time() - sensorinnertimestamp
|
||||
|
||||
if sensordata['right'] <= rightmin and right:
|
||||
# turn right to False
|
||||
right = False
|
||||
turnoffLED(redLED)
|
||||
#printinfo("Right off")
|
||||
|
||||
if not left and not right and leftdetected and rightdetected:
|
||||
#rotation detected!
|
||||
leftdetected = False
|
||||
rightdetected = False
|
||||
if sensorinnerlength < sensoroutherlength: # detection of left and right was correct
|
||||
turnonLED(boardLED)
|
||||
# Determine direction
|
||||
if lefttimestamp < righttimestamp:
|
||||
# The left sensor was seen before the right
|
||||
# S1 --> S2
|
||||
# Rotation is "importing from the net"
|
||||
rotation = 1
|
||||
counterimport += 1
|
||||
else:
|
||||
# The right sensor was seen before the left
|
||||
# S1 <-- S2
|
||||
# Rotation is "exporting to the net"
|
||||
rotation = -1
|
||||
counterexport += 1
|
||||
countertotal = counterimport - counterexport
|
||||
|
||||
# I'll average the left and right rotation time to get a "smoother" value (in principle I calculate the point between the 2 sensors)
|
||||
timeperrotation = (((lefttimestamp - leftprevtimestamp) + (righttimestamp - rightprevtimestamp)) / 2)
|
||||
currentpower = int(rotation * rotationsperkwh * 10 / (timeperrotation))
|
||||
|
||||
if rotation == 1:
|
||||
printinfo("-> importing from net")
|
||||
importpower = currentpower
|
||||
exportpower = 0
|
||||
else:
|
||||
printinfo("<- exporting to net")
|
||||
exportpower = currentpower * -1
|
||||
importpower = 0
|
||||
#printinfo("Rotation time: . %.5f secs" % timeperrotation)
|
||||
#printinfo("-- -- -- -- -- -- -- -- -- -- --")
|
||||
#printinfo("Inner gab: . . . %.5f secs" % sensorinnerlength)
|
||||
#printinfo("Outer: . . . . . %.5f secs" % sensoroutherlength)
|
||||
#printinfo("Total: . . . . . %.5f secs" % (sensoroutherlength + sensorinnerlength))
|
||||
printinfo("Rotation time: . %.5f secs" % timeperrotation)
|
||||
printinfo("Current power: . %.0f Watt" % currentpower)
|
||||
#printinfo("ImportCount: . . %.0f" % counterimport)
|
||||
#printinfo("ExportCount: . . %.0f" % counterexport)
|
||||
printinfo("Import:. . . . . %.2f kWh" % (counterimport / rotationsperkwh))
|
||||
printinfo("Export:. . . . . %.2f kWh" % (counterexport / rotationsperkwh))
|
||||
printinfo("Total: . . . . . %.2f kWh" % (countertotal / rotationsperkwh))
|
||||
printinfo("Load average:. . %.0f W, %.0f W, %.0f W" % loadaverage.loadaverage())
|
||||
printinfo("--------------------------------------------------------------------------------")
|
||||
|
||||
# do a tiny nap
|
||||
time.sleep(0.1)
|
||||
turnoffLED(boardLED)
|
||||
else:
|
||||
# Ooops... inner gab is bigger then the outer route??? We are detecting the wrong way!
|
||||
# sleep a bit and try again
|
||||
printinfo("Skipping rotation . . .")
|
||||
if (sensoroutherlength / 4) < 10:
|
||||
time.sleep(sensoroutherlength / 4)
|
||||
else:
|
||||
time.sleep(10)
|
||||
else:
|
||||
time.sleep(0.001)
|
||||
|
||||
if time.gmtime()[5] % 10 == 0:
|
||||
# Every 10 seconds print the current values
|
||||
if not loadaverageadded:
|
||||
loadaverage.addvalue(currentpower)
|
||||
loadaverageadded = True
|
||||
|
||||
if time.gmtime()[4] % 5 == 0:
|
||||
# Every 5 minutes, write a log entry & DB record
|
||||
if not logexported:
|
||||
writeLog(currentpower, (countertotal / rotationsperkwh), (counterimport / rotationsperkwh),
|
||||
(counterexport / rotationsperkwh), (timeperrotation * 1000), loadaverage.loadaverage())
|
||||
savekwhdata(config, counterimport, counterexport)
|
||||
# If you want to save to pvoutput, uncomment the line below:
|
||||
exportPvoutput(config, (counterexport / rotationsperkwh), exportpower, (counterimport / rotationsperkwh), importpower)
|
||||
logexported = True
|
||||
else:
|
||||
logexported = False
|
||||
else:
|
||||
loadaverageadded = False
|
||||
|
||||
if thisday != date.today().strftime("%Y%m%d"):
|
||||
if logexported == True:
|
||||
exportpower = 0
|
||||
importpower = 0
|
||||
thisday = date.today().strftime("%Y%m%d")
|
||||
config.set('kWh', 'cumuliday',thisday)
|
||||
|
||||
writesettings(config)
|
||||
|
||||
|
||||
# Main program routine begins here:
|
||||
#----------------------------------
|
||||
|
||||
config = readsettings()
|
||||
writesettings(config)
|
||||
|
||||
#init raspberry pi gpio pins
|
||||
GPIO.setwarnings(False)
|
||||
GPIO.setmode(GPIO.BCM)
|
||||
|
||||
GPIO.setup(switch, GPIO.IN)
|
||||
GPIO.setup(boardLED, GPIO.OUT, initial = GPIO.LOW)
|
||||
GPIO.setup(greenLED, GPIO.OUT, initial = GPIO.LOW)
|
||||
GPIO.setup(redLED, GPIO.OUT, initial = GPIO.LOW)
|
||||
|
||||
#set LEDs default off
|
||||
turnoffLED(boardLED)
|
||||
turnoffLED(greenLED)
|
||||
turnoffLED(redLED)
|
||||
|
||||
writesettings(config)
|
||||
|
||||
# Infinite loop
|
||||
while True:
|
||||
config = calibratesensors(config)
|
||||
dotFollower(config)
|
||||
|
||||
# we will never get here...
|
||||
GPIO.remove_event_detect(switch)
|
||||
GPIO.cleanup()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user