+
+def ac_is_on():
+ # Heuristics to tell if AC is currently on
+
+ tie = st.get_sensor_avg('air/inside-exhaust')
+ tmix = st.get_sensor_avg('air/mixed')
+ if tie is None or tmix is None:
+ return 0
+
+ # Mixed air is significantly colder than inside exhaust
+ ac_on = -st.hysteresis('ac_off', tmix, tie - 5, tie - 4)
+
+ # FIXME: It might also mean that the loft is cold
+
+ return ac_on
+
+
+def auto_air():
+ global st
+ 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)
+ ac_on = ac_is_on()
+
+ # XXX: Temporarily disabled
+ #house_warm = -1
+ #house_hot = -1
+ #ac_on = -1
+
+ # Do we want to bypass the heat exchanger?
+ 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:
+ st.set('air/bypass', 1)
+
+ # Is mixed air colder than air from the inside?
+ mixed_warmer = st.hysteresis('mixed_warmer', diff(tmix, tii), -1, 0)
+
+ # Do we want to boost heat exchanger fan?
+ if ac_on > 0 or (house_hot > 0 and mixed_warmer < 0):
+ st.set('air/exchanger-fan', 255)
+ else:
+ st.set('air/exchanger-fan', 0)
+
+ debug("Air: house_warm={} house_hot={} ac_on={} outside_warmer={} mixed_warmer={}".format(house_warm, house_hot, ac_on, outside_warmer, mixed_warmer))
+
+
+def auto_aircon():
+ global st
+ tii = st.get_sensor_avg('air/inside-intake')
+ tie = st.get_sensor_avg('air/inside-exhaust')
+ house_hot = st.hysteresis('ac_house_hot', tii, 23.5, 24)
+ outside_hot = st.hysteresis('ac_outside_hot', tie, 24, 25)
+ ac_on = ac_is_on()
+
+ if house_hot > 0 and outside_hot > 0:
+ want_ac = 1
+ else:
+ want_ac = -1
+
+ if not hasattr(st, 'last_ac_change'):
+ st.last_ac_change = st.now
+ need_wait = st.last_ac_change + 300 - st.now # FIXME: Increase
+
+ if need_wait > 0:
+ action = f"wait({need_wait:.0f})"
+ elif ac_on == 0:
+ action = "need-data"
+ elif ac_on != want_ac:
+ action = "change"
+ st.send('air/aircon-remote', 'p')
+ st.last_ac_change = st.now
+ else:
+ action = "none"
+
+ debug("AC: house_hot={} outside_hot={} ac_on={} want_ac={} action={}".format(house_hot, outside_hot, ac_on, want_ac, action))
+
+
+def on_connect(mq, userdata, flags, rc):
+ mq.subscribe("burrow/#")
+
+def on_message(mq, userdata, msg):
+ global st
+ # debug("Message {}: {}".format(msg.topic, msg.payload))
+ st.attrs[msg.topic] = msg.payload.decode('utf-8')
+