changeset 278:fd9c6517225e

merge
author Matt Johnston <matt@ucc.asn.au>
date Tue, 17 Nov 2015 22:26:54 +0800
parents 0a1c02160e66 (diff) c0f903cf8268 (current diff)
children 6848907f85be
files
diffstat 5 files changed, 125 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/py/fridge.py	Tue Nov 17 22:25:02 2015 +0800
+++ b/py/fridge.py	Tue Nov 17 22:26:54 2015 +0800
@@ -5,6 +5,7 @@
 import config
 
 import gpio
+import utils
 
 class Fridge(object):
 
@@ -13,6 +14,7 @@
     def __init__(self, server, nowait = False):
         self.server = server
         self.gpio = gpio.Gpio(config.FRIDGE_GPIO_PIN, "fridge")
+        self.integrator = utils.StepIntegrator(self.server.now, self.server.params.overshoot_delay)
         self.wort_valid_clock = 0
         self.fridge_on_clock = 0
         self.off()
@@ -21,10 +23,10 @@
 
     def turn(self, value):
         self.gpio.turn(value)
+        self.integrator.turn(value)
 
     def on(self):
         self.turn(True)
-        pass
 
     def off(self):
         self.turn(False)
@@ -61,6 +63,8 @@
         if wort is not None:
             self.wort_valid_clock = self.server.now()
 
+        self.integrator.set_limit(params.overshoot_delay)
+
         # Safety to avoid bad things happening to the fridge motor (?)
         # When it turns off don't start up again for at least FRIDGE_DELAY
         if not self.is_on() and off_time < config.FRIDGE_DELAY:
@@ -88,14 +92,10 @@
 
         if self.is_on():
             turn_off = False
-            on_time = self.server.now() - self.fridge_on_clock
+            on_percent = self.integrator.integrate() / params.overshoot_delay
 
-            overshoot = 0
-            if on_time > params.overshoot_delay:
-                overshoot = params.overshoot_factor \
-                    * min(self.OVERSHOOT_MAX_DIV, on_time) \
-                    / self.OVERSHOOT_MAX_DIV
-            D("on_time %(on_time)f, overshoot %(overshoot)f" % locals())
+            overshoot = params.overshoot_factor * on_percent
+            D("on_time %(on_percent)f, overshoot %(overshoot)f" % locals())
 
             if not params.nowort and wort is not None:
                 if wort - overshoot < params.fridge_setpoint:
--- a/py/test.py	Tue Nov 17 22:25:02 2015 +0800
+++ b/py/test.py	Tue Nov 17 22:26:54 2015 +0800
@@ -1,4 +1,3 @@
-#!/usr/bin/env python2.7
 import io
 
 import unittest
@@ -7,7 +6,7 @@
 
 class TestSensors(unittest.TestCase):
     def setUp(self):
-        self.sensors = sensor_ds18b20.DS18B20s(None)
+        self.sensors = sensor_ds18b20.SensorDS18B20(None)
 
     def test_sensors_regex(self):
         f1 = """6e 01 4b 46 7f ff 02 10 71 : crc=71 YES
@@ -66,9 +65,7 @@
         jsbuf = io.StringIO()
 
         self.params.overshoot_delay = 123
-        self.params.save(f=jsbuf)
-
-        s = jsbuf.getvalue()
+        s = self.params.save_string()
         self.assertTrue('"overshoot_delay": 123' in s, msg=s)
             
 unittest.main()
--- a/py/utils.py	Tue Nov 17 22:25:02 2015 +0800
+++ b/py/utils.py	Tue Nov 17 22:26:54 2015 +0800
@@ -7,6 +7,7 @@
 import binascii
 import json
 import datetime
+import collections
 
 D = logging.debug
 L = logging.info
@@ -171,3 +172,103 @@
             L(msg + " (log interval %s)" % str(self.limit))
         else:
             D(msg)
+
+Period = collections.namedtuple('Period', 'start end')
+class StepIntegrator(object):
+    """
+    Takes on/off events and a monotonically increasing timefn. Returns the integral 
+    of (now-limittime, now) over those events.
+
+    >>> s = StepIntegrator(lambda: t, 40)
+    >>> t = 1
+    >>> s.turn(1)
+    >>> t = 10
+    >>> s.turn(0)
+    >>> t = 20
+    >>> s.turn(1)
+    >>> t = 30
+    >>> print(s.integrate())
+    19
+    >>> s.turn(0)
+    >>> print(s.integrate())
+    19
+    >>> t = 35
+    >>> print(s.integrate())
+    19
+    >>> t = 42
+    >>> print(s.integrate())
+    18
+    >>> t = 52
+    >>> print(s.integrate())
+    10
+    >>> t = 69
+    >>> print(s.integrate())
+    1
+    >>> t = 70
+    >>> print(s.integrate())
+    0
+    >>> t = 170
+    >>> print(s.integrate())
+    0
+    """
+    def __init__(self, timefn, limittime):
+        # _on_periods is a list of [period]. End is None if still on
+        self._on_periods = []
+        self._timefn = timefn
+        self._limittime = limittime
+
+    def set_limit(self, limittime):
+        if self._limittime == limittime:
+            return
+        self._limittime = limittime
+        self._trim()
+
+    def turn(self, value):
+        if not self._on_periods:
+            if value:
+                self._on_periods.append(Period(self._timefn(), None))
+            return
+
+        # state hasn't changed
+        on_now = (self._on_periods[-1].end is None)
+        if value == on_now:
+            return
+
+        if value:
+            self._on_periods.append(Period(self._timefn(), None))
+        else:
+            self._on_periods[-1] = self._on_periods[-1]._replace(end = self._timefn())
+
+    def _trim(self):
+        begin = self._timefn() - self._limittime
+        # shortcut, first start is after begin
+        if not self._on_periods or self._on_periods[0].start >= begin:
+            return
+
+        new_periods = []
+        for s, e  in self._on_periods:
+            if s == e:
+                continue
+            elif s >= begin:
+                new_periods.append(Period(s,e))
+            elif e is not None and e < begin:
+                continue
+            else:
+                new_periods.append(Period(begin, e))
+        self._on_periods = new_periods
+
+    def integrate(self):
+        self._trim()
+        tot = 0
+        for s, e in self._on_periods:
+            if e is None:
+                e = self._timefn()
+            tot += (e-s)
+        return tot
+
+
+
+
+
+
+
--- a/web/config.py	Tue Nov 17 22:25:02 2015 +0800
+++ b/web/config.py	Tue Nov 17 22:26:54 2015 +0800
@@ -31,8 +31,8 @@
     'sensor_fridge_setpoint': 'Setpoint',
     'sensor_fridge_on': 'Cool',
     'sensor_28-0000042cf4dd': "Wort",
-    'sensor_28-0000042cccc4': "Fridge",
-    'sensor_28-0000042c6dbb': "Ambient",
+    'sensor_28-0000042cccc4': "OldFridge",
+    'sensor_28-0000042c6dbb': "Fridge",
     'sensor_internal': "Processor",
     }
 
--- a/web/templog.py	Tue Nov 17 22:25:02 2015 +0800
+++ b/web/templog.py	Tue Nov 17 22:26:54 2015 +0800
@@ -69,6 +69,12 @@
 
 @route('/set/update', method='post')
 def set_update():
+    if not secure.check_user_hash(config.ALLOWED_USERS):
+        # the "Save" button should be disabled if the cert wasn't
+        # good
+        response.status = 403
+        return "No cert, dodginess"
+
     post_json = json.loads(request.forms.data)
 
     csrf_blob = post_json['csrf_blob']
@@ -79,7 +85,7 @@
 
     ret = log.update_params(post_json['params'])
     if not ret is True:
-        response.status = 403
+        response.status = 409 # Conflict
         return ret
         
     return "Good"
@@ -157,6 +163,11 @@
     #var_lookup = environ['mod_ssl.var_lookup']
     #return var_lookup("SSL_SERVER_I_DN_O")
 
+@route('/h')
+def headers():
+    response.set_header('Content-Type', 'text/plain')
+    return '\n'.join("%s: %s" % x for x in request.headers.items())
+
 @route('/get_settings')
 def get_settings():
     response.set_header('Cache-Control', 'no-cache')