# HG changeset patch # User Matt Johnston # Date 1353336405 -28800 # Node ID 9fbeafc0984527f4e70ff37f18dfd5fddec80853 # Parent 31ac84425a2d0d500ce8ad932dae2d6f6d2023cd# Parent e6ec149d40631b9856407afcd5f9c7f16966d0b5 merge diff -r e6ec149d4063 -r 9fbeafc09845 py/config.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/py/config.py Mon Nov 19 22:46:45 2012 +0800 @@ -0,0 +1,2 @@ +FRIDGE_GPIO = '/sys/class/gpio/gpio5' +FRIDGE_SLEEP = 60 diff -r e6ec149d4063 -r 9fbeafc09845 py/fridge.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/py/fridge.py Mon Nov 19 22:46:45 2012 +0800 @@ -0,0 +1,63 @@ +from utils import L,W,E +import config + +class Fridge(object): + def __init__(self): + self.setup_gpio() + self.wort_valid_clock = 0 + + def setup_gpio(self): + fn = '%s/direction' % config.FRIDGE_GPIO + f = open(fn, 'w') + f.write('low') + f.close() + # .off() shouldn't do anything, but tests that "value" is writable + self.off() + + def turn(self, value): + fn = '%s/value' % config.FRIDGE_GPIO + f = open(fn, 'w') + if value: + f.write('1') + else: + f.write('0') + f.close() + + def on(self): + self.turn(1) + + def off(self): + self.turn(0) + + def do(self): + wort, fridge, ambient = server.current_temps() + + if server.uptime() < config.FRIDGE_DELAY: + L("fridge skipping, too early") + return + + # handle broken wort sensor + if wort is not None: + self.wort_valid_clock = server.now() + else: + W("Invalid wort sensor") + invalid_time = server.now() - self.wort_valid_clock + if invalid_time < config.FRIDGE_WORT_INVALID_TIME: + W("Has only been invalid for %d, waiting" % invalid_time) + return + + if fridge is None: + W("Invalid fridge sensor") + + + + + + + + def run(self, server): + self.server = server + + while True: + self.do() + gevent.sleep(config.FRIDGE_SLEEP) diff -r e6ec149d4063 -r 9fbeafc09845 py/sensor_ds18b20.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/py/sensor_ds18b20.py Mon Nov 19 22:46:45 2012 +0800 @@ -0,0 +1,21 @@ +#!/usr/bin/env python2.7 + +class DS18B20s(object): + + def __init__(self): + # query the bus + pass + + def get_sensors(self): + """ Returns a sequence of sensorname """ + pass + + def read(self): + """ Returns a map of sensorname->temperature """ + pass + + def wort_name(self): + pass + + def fridge_name(self): + pass diff -r e6ec149d4063 -r 9fbeafc09845 py/tempserver.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/py/tempserver.py Mon Nov 19 22:46:45 2012 +0800 @@ -0,0 +1,68 @@ +#!/usr/bin/env python2.7 + +import sys +import os +import gevent + +import utils + +class Tempserver(object): + def __init__(self): + self.readings = [] + self.current = (None, None, None) + + self.start_time = utils.monotonic_time() + + self.fridge = fridge.Fridge() + self.fridge.run(self) + + + def take_readings(self): + ret = self.readings + self.readings = [] + return ret + + def pushfront(self, readings): + """ used if a caller of take_readings() fails """ + self.readings = pushback + self.readings + + def add_reading(self, reading): + """ adds a reading at the current time """ + self.readings.append( (reading, utils.monotonic_time())) + + def current_temps(self): + """ returns (wort_temp, fridge_temp, ambient_temp) tuple """ + return current + + def set_current(self, wort, fridge, ambient): + current = (wort, fridge, ambient) + + def uptime(self): + return utils.monotonic_time() - self.start_time() + + def now(self): + return utils.monotonic_time() + +def spawn_timer(seconds, fn, *args, **kwargs): + def loop(): + while True: + fn(*args, **kwargs) + gevent.sleep(seconds) + return gevent.spawn(loop) + +def setup(): + pass + +def main(): + setup() + + def p(x): + print "hello %s" % x + + spawn_timer(2, p, 'one') + + gevent.sleep(20) + + +if __name__ == '__main__': + main() diff -r e6ec149d4063 -r 9fbeafc09845 py/utils.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/py/utils.py Mon Nov 19 22:46:45 2012 +0800 @@ -0,0 +1,125 @@ +import os +import sys +#import ctypes +import time +import select +import logging + +L = logging.info +W = logging.warning +E = logging.error + +DEFAULT_TRIES = 3 +READLINE_SELECT_TIMEOUT = 1 + +clock_gettime = None +no_clock_gettime = True +def monotonic_time(): + global clock_gettime + global no_clock_gettime + if no_clock_gettime: + return time.time() + + class timespec(ctypes.Structure): + _fields_ = [ + ('tv_sec', ctypes.c_long), + ('tv_nsec', ctypes.c_long) + ] + if not clock_gettime: + try: + librt = ctypes.CDLL('librt.so.0', use_errno=True) + clock_gettime = librt.clock_gettime + clock_gettime.argtypes = [ctypes.c_int, ctypes.POINTER(timespec)] + except: + W("No clock_gettime(), using fake fallback.") + no_clock_gettime = True + return time.time() + + t = timespec() + CLOCK_MONOTONIC = 1 # see + + if clock_gettime(CLOCK_MONOTONIC, ctypes.pointer(t)) != 0: + errno_ = ctypes.get_errno() + raise OSError(errno_, os.strerror(errno_)) + return t.tv_sec + t.tv_nsec * 1e-9 + +# decorator, tries a number of times, returns None on failure, sleeps between +# Must be used as "@retry()" if arguments are defaulted +def retry(retries=DEFAULT_TRIES, try_time = 1): + def inner(func): + def new_f(*args, **kwargs): + for i in range(retries): + d = func(*args, **kwargs) + if d is not None: + return d + time.sleep(try_time) + return None + + new_f.func_name = func.func_name + return new_f + return inner + +def readline(sock): + timeout = READLINE_SELECT_TIMEOUT + buf = '' + while True: + (rlist, wlist, xlist) = select.select([sock], [], [], timeout) + if sock not in rlist: + # hit timeout + return None + + c = sock.recv(1) + if c == '': + # lightblue timeout + return None + if c == '\r': + continue + + buf += c + if c == '\n': + return buf + +# from http://blog.stalkr.net/2011/04/pctf-2011-32-thats-no-bluetooth.html +def crc16(buff, crc = 0, poly = 0x8408): + l = len(buff) + i = 0 + while i < l: + ch = ord(buff[i]) + uc = 0 + while uc < 8: + if (crc & 1) ^ (ch & 1): + crc = (crc >> 1) ^ poly + else: + crc >>= 1 + ch >>= 1 + uc += 1 + i += 1 + return crc + +def cheap_daemon(): + L("Daemonising.") + sys.stdout.flush() + sys.stderr.flush() + out = file('/dev/null', 'a+') + os.dup2(out.fileno(), sys.stdout.fileno()) + os.dup2(out.fileno(), sys.stderr.fileno()) + + try: + pid = os.fork() + if pid > 0: + sys.exit(0) + except OSError, e: + E("Bad fork()") + sys.exit(1) + + os.setsid() + + try: + pid = os.fork() + if pid > 0: + sys.exit(0) + except OSError, e: + E("Bad fork()") + sys.exit(1) + +