]> mj.ucw.cz Git - home-hw.git/blobdiff - auto/burrow-auto
Merge branch 'master' of ssh://git.ucw.cz/home/mj/GIT/home-hw
[home-hw.git] / auto / burrow-auto
index 4c30f59cc813e50c8641f25b23aa0d648956ef86..47707181ad1d0a2a85e42358c328599fac8f6870 100755 (executable)
@@ -12,9 +12,17 @@ def debug(msg):
     if debug_mode:
         print(("\t" * indent) + msg)
 
+def diff(x, y):
+    if x is None or y is None:
+        return None
+    else:
+        return x - y
+
 class State:
     def __init__(self):
-            self.attrs = {}
+        self.attrs = {}
+        self.hyst_state = {}
+        self.running_averages = {}
 
     def update(self):
         self.now = time.time()
@@ -25,7 +33,6 @@ class State:
         self.hour = tm.tm_hour
         self.min = tm.tm_min
         self.wday = tm.tm_wday
-        self.hyst_state = {}
         debug("[{}-{:02d}-{:02d} {:02d}:{:02d}:{:02d} wday={}]".format(
             self.year, self.month, self.day,
             self.hour, self.min, tm.tm_sec,
@@ -79,6 +86,43 @@ class State:
         self.hyst_state[key] = new_state
         return new_state
 
+    def update_average(self, key, window_seconds):
+        if key not in self.running_averages:
+            self.running_averages[key] = ([], 0, 0, None)
+        (history, sum, count, avg) = self.running_averages[key]
+
+        while len(history) > 0 and history[0][0] <= self.now - window_seconds:
+            if history[0][1] is not None:
+                sum -= history[0][1]
+                count -= 1
+            history.pop(0)
+
+        curr = self.get_sensor(key)
+        history.append((self.now, curr))
+        if curr is not None:
+            sum += curr
+            count += 1
+
+        if count > len(history) // 2:
+            avg = sum / count
+        else:
+            avg = None
+
+        self.running_averages[key] = (history, sum, count, avg)
+        if avg is None:
+            debug("= avg NONE ({} samples, {} non-null)".format(len(history), count))
+        else:
+            debug("= avg {:.6} ({} samples, {} non-null)".format(avg, len(history), count))
+            self.set("avg/" + key, "{:.6} {}".format(avg, int(self.now)))
+
+    def get_sensor_avg(self, key):
+        val = self.running_averages[key][3]
+        if val is None:
+            debug("< {} = avg NONE".format(key))
+        else:
+            debug("< {} = avg {:.6}".format(key, val))
+        return val
+
 st = State()
 
 def on_connect(mq, userdata, flags, rc):
@@ -115,7 +159,7 @@ def auto_loft_fan():
 
 def auto_circ():
     global st
-    if st.hour in range(20, 22):
+    if st.hour in range(7, 24):
         c = 1
     else:
         c = 0;
@@ -123,10 +167,10 @@ def auto_circ():
 
 def auto_air():
     global st
-    tii = st.get_sensor('air/inside-intake')
-    tie = st.get_sensor('air/inside-exhaust')
-    toi = st.get_sensor('air/outside-intake')
-    tmix = st.get_sensor('air/mixed')
+    tii = st.get_sensor_avg('air/inside-intake')
+    tie = st.get_sensor_avg('air/inside-exhaust')
+    toi = st.get_sensor_avg('air/outside-intake')
+    tmix = st.get_sensor_avg('air/mixed')
     house_warm = st.hysteresis('house_warm', tii, 23.5, 24.5)
     house_hot = st.hysteresis('house_hot', tii, 24.5, 25)
 
@@ -136,21 +180,21 @@ def auto_air():
     else:
         ac_off = st.hysteresis('ac_off', tmix, tie - 5, tie - 4)
 
+    # XXX: Temporarily disabled
+    house_warm = -1
+    house_hot = -1
+    ac_off = 1
+
     # Do we want to bypass the heat exchanger?
-    if toi is None or tie is None:
+    outside_warmer = st.hysteresis('outside_warmer', diff(toi, tii), -0.5, 0.5)
+    if (house_warm > 0) and (outside_warmer > 0) or \
+       (house_warm < 0) and (outside_warmer < 0):
         st.set('air/bypass', 0)
     else:
-        outside_warmer = (st.hysteresis('bypass', toi, tii - 0.5, tii + 0.5) >= 0)
-        if (house_warm >= 0) == outside_warmer:
-            st.set('air/bypass', 0)
-        else:
-            st.set('air/bypass', 1)
+        st.set('air/bypass', 1)
 
     # Is mixed air colder than air from the inside?
-    if tii is None or tmix is None:
-        mixed_warmer = 0
-    else:
-        mixed_warmer = st.hysteresis('mixed_warmer', tmix, tii - 1, tii)
+    mixed_warmer = st.hysteresis('mixed_warmer', diff(tmix, tii), -1, 0)
 
     # Do we want to boost heat exchanger fan?
     if ac_off < 0 or (house_hot > 0 and mixed_warmer < 0):
@@ -170,7 +214,7 @@ mq = mqtt.Client()
 mq.on_connect = on_connect
 mq.on_message = on_message
 mq.will_set("status/auto", "dead", retain=True)
-mq.connect("127.0.0.1")
+mq.connect("burrow-mqtt")
 mq.publish("status/auto", "ok", retain=True)
 mq.loop_start()
 
@@ -185,6 +229,15 @@ checks = [
 
 while True:
     st.update()
+
+    debug("averages")
+    indent += 1
+    st.update_average('air/outside-intake', 60)
+    st.update_average('air/inside-intake', 60)
+    st.update_average('air/inside-exhaust', 60)
+    st.update_average('air/mixed', 60)
+    indent -= 1
+
     for name, func in checks:
         if st.auto_enabled(name):
             debug(name)