changeset 141:4755e6f9a5b8

python raspberry pi rewrite
author Matt Johnston <matt@ucc.asn.au>
date Mon, 19 Nov 2012 22:46:34 +0800
parents 94330d90f11f
children 8375616bbc7b
files py/config.py py/fridge.py py/sensor_ds18b20.py py/tempserver.py py/utils.py
diffstat 5 files changed, 279 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/py/config.py	Mon Nov 19 22:46:34 2012 +0800
@@ -0,0 +1,2 @@
+FRIDGE_GPIO = '/sys/class/gpio/gpio5'
+FRIDGE_SLEEP = 60
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/py/fridge.py	Mon Nov 19 22:46:34 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)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/py/sensor_ds18b20.py	Mon Nov 19 22:46:34 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/py/tempserver.py	Mon Nov 19 22:46:34 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()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/py/utils.py	Mon Nov 19 22:46:34 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 <linux/time.h>
+
+    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)
+
+