This commit is contained in:
2025-06-23 11:51:54 +02:00
commit 8108b800da
13 changed files with 1030 additions and 0 deletions

20
Metro/LICENSE Normal file
View 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
View 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
View 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
View File

@@ -0,0 +1 @@
Please visit https://github.com/thomasfredericks/Metro-Arduino-Wiring for latest code and documentation.

View 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);
}
}

View 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);
}
}

View 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);
}
}

View 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
View 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

Binary file not shown.

View 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
View 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
View 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()