Sunday, May 22, 2016

Buderus Logicmatic 2107 external hour meter using Raspberry Pi

When home heating oil reached close to $5 a gallon here in Southern New Jersey, I was on a mission to reduce consumption as much as possible without causing The Chancellor to bundle up like a hooded monk.

To accomplish that, the first step was to accurately be able to determine daily oil consumption, something nearly impossible to do with the crude hour meter on my Buderus Logicmatic 2107 boiler controller. 


I needed a digital hour meter that would record oil burner usage to an electronic file that could then be analyzed to determine usage. 

Step 1 - build an hour meter. 

I had been playing with the Raspberry Pi, a credit card sized computer that runs a Linux variant and thought this was the best approach for me. 

After some research with the Buderus unit I found two terminals that were designed to run an external hour meter that energized a 120 VAC line when the burner was turned on. 

Here I've attached the external power line on terminals 8 & 4


I figured that having the Pi sense 120 VAC sounded like a dangerous and unnecessary proposition, I connected the 120 V line to an old 12 VDC AC to DC brick and now had drive a DC relay to apply a ground to the PiFace logical line that represented when the burner was on. 

Rather than tie directly to the GPIO interface on the Pi I had purchased a PiFace relay board which was designed to accept such inputs and can be accessed programmatically with python. 

And the python code (which must also do a similar function for the garage)
:
#!/usr/bin/python3
#   FILE NAME
#       /usr/local/bin/HouseMeters.py
#
#   FILE CREATION
#       March. 22, 2014 by Mike Falciani.
#
#   FILE REVISION
#       %W% %E% Copyright 2014 amflabs.
#
# A script to record garage and oil burner usage to a file.
#
#
import argparse
import readline
import pifacedigitalio
#from daemonize import Daemonize
#pid="/tmp/test.pid"

#
# Sense when the garage has been opened and closed.
#
def GarageFunction(GarageMagSwitch):
        import time
        global Garagekeepme
        global debug
        global pifacedigital
        global GaragePin
        if GarageMagSwitch.direction == 0:
# Garage was opened
                if pifacedigital.input_pins[GaragePin].value:
                        Garagekeepme = GarageMagSwitch.timestamp
                        pifacedigital.leds[GaragePin].turn_on()
                        outstr = "Opened,%.2f,%s,-1\n" % (GarageMagSwitch.timestamp,time.asctime(time.localtime(GarageMagSwitch.timestamp)))
                        GarageHours.write(outstr)
                        GarageHours.flush()
                        if debug:
                                outstr = "Garage Opened %s " % (time.asctime(time.localtime(GarageMagSwitch.timestamp)))
                                print (outstr)
                else:
                        if debug:
                                print ("False Postive Hairtrigger")
# Garage was closed
        elif GarageMagSwitch.direction == 1 and Garagekeepme:
                pifacedigital.leds[GaragePin].turn_off()
                duration = GarageMagSwitch.timestamp - Garagekeepme
                outstr = "Closed,%.2f,%s,%.2f\n" % (GarageMagSwitch.timestamp,time.asctime(time.localtime(GarageMagSwitch.timestamp)),duration)
                GarageHours.write(outstr)
                GarageHours.flush()
#               outstr = str(out)
                if debug:
                        outstr = "Garage Started %s,Ended %s,\n\tDuration %.2f Sec" % (time.asctime(time.localtime(Garagekeepme)),time.asctime(time.localtime(GarageMagSwitch.timestamp)),duration)
                        print (outstr)
#
# Sense when the oil burner comes on and off.
#

def OilFunction(Oil):
        import time
        global Oilkeepme
        global debug
        global pifacedigital
        global hours
        global OilPin
        if Oil.direction == 0:
# Oil burner ON
                Oilkeepme = Oil.timestamp
                pifacedigital.leds[OilPin].turn_on()
                if debug:
                        outstr = "Oil Started %s " % (time.asctime(time.localtime(Oilkeepme)))
                        print (outstr)
        elif Oil.direction == 1 and Oilkeepme:
                pifacedigital.leds[OilPin].turn_off()
                duration = Oil.timestamp - Oilkeepme
                hours += duration/(60*60)
                outstr = "%.2f,%.2f,%.2f,%.2f\n" % (Oilkeepme,Oil.timestamp,duration,hours)
                OilHours.write(outstr)
                OilHours.flush()
#               outstr = str(out)
                if debug:
                        outstr = "Oil Started %s,Ended %s,\n\tDuration %.2f Sec, Hours=%.2f" % (time.asctime(time.localtime(Oilkeepme)),time.asctime(time.localtime(Oil.timestamp)),duration,hours)
                        print (outstr)
# interrupt_flag:    0b10000000
# interrupt_capture: 0b11111111
# OilPin_num:           7
# direction:         1
# chip:              
# timestamp:         1393882878.562755
#
#
#
# Main loop
# Sense when Opened, write to repective files.
#
#def main_loop():
parser = argparse.ArgumentParser()
parser.add_argument('-d',dest='debug',default=0,help='Debugging On')
args = parser.parse_args()

debug=args.debug

OilPin=2
GaragePin=3

OilHours = open('/charmander/home/mfalcian/data/OilBurnerHours.csv','br+')
OilHours.seek(-60,2) # go to middle of next to last line
last=OilHours.readline() # read partial line
last=OilHours.readline() # read last line as byetstr
OilHours.close() # close binary mode
OilHours = open('/charmander/home/mfalcian/data/OilBurnerHours.csv','r+')
OilHours.seek(0,2) # go to end of file

bhours=last.split(b',')
hours=float(bhours[3])
Oilkeepme=0
Garagekeepme=0
if debug:
        print('Oil last line',last)
        print(hours)
        print('Debug turned on to level ',debug)
#
GarageHours = open('/charmander/home/mfalcian/data/GarageBurnerHours.csv','r+')
GarageHours.seek(0,2) # go to end of file
#
#
pifacedigital = pifacedigitalio.PiFaceDigital()
pifacedigital.leds[OilPin].turn_off()
pifacedigital.leds[GaragePin].turn_off()
listener = pifacedigitalio.InputEventListener(chip=pifacedigital)
listener.register(OilPin, pifacedigitalio.IODIR_RISING_EDGE, OilFunction)
listener.register(OilPin, pifacedigitalio.IODIR_FALLING_EDGE, OilFunction)

listener.register(GaragePin, pifacedigitalio.IODIR_RISING_EDGE, GarageFunction)
listener.register(GaragePin, pifacedigitalio.IODIR_FALLING_EDGE, GarageFunction)
listener.activate()
# Main
#daemon = Daemonize(app="HouseMeters", pid=pid, action=main_loop)
#daemon.start()
#main_loop()


And the resulting log with Start Time (epoch time), End time, Duration and current Oil burner hours after burn. 
1393973497,1393973732,234.88,4937.065244
1393973957,1393974468,510.89,4937.207158
1393974781,1393975176,394.89,4937.31685
1393975513,1393976020,506.9,4937.457656
1393976475,1393977114,638.9,4937.635128
1393977673,1393978020,346.9,4937.731489
1393978345,1393978914,568.89,4937.889514


No comments: