comparison py/fridge.py @ 143:0895f5ad7731

copied fridge logic from main.c
author Matt Johnston <matt@ucc.asn.au>
date Tue, 20 Nov 2012 22:03:10 +0800
parents 4755e6f9a5b8
children 482d7852b511
comparison
equal deleted inserted replaced
142:8375616bbc7b 143:0895f5ad7731
1 # -*- coding: utf-8 -*-
1 from utils import L,W,E 2 from utils import L,W,E
2 import config 3 import config
3 4
4 class Fridge(object): 5 class Fridge(object):
6
7 OVERSHOOT_MAX_DIV = 1800.0 # 30 mins
8 FRIDGE_AIR_MIN_RANGE = 4 # ÂșC
9 FRIDGE_AIR_MAX_RANGE = 4
10
5 def __init__(self): 11 def __init__(self):
6 self.setup_gpio() 12 self.setup_gpio()
7 self.wort_valid_clock = 0 13 self.wort_valid_clock = 0
14 self.fridge_on_clock = 0
15 self.fridge_off_clock = 0
8 16
9 def setup_gpio(self): 17 def setup_gpio(self):
10 fn = '%s/direction' % config.FRIDGE_GPIO 18 dir_fn = '%s/direction' % config.FRIDGE_GPIO
11 f = open(fn, 'w') 19 with f = open(dir_fn, 'w'):
12 f.write('low') 20 f.write('low')
13 f.close() 21 val_fn = '%s/value' % config.FRIDGE_GPIO
14 # .off() shouldn't do anything, but tests that "value" is writable 22 self.value_file = f.open(val_fn, 'r+')
15 self.off()
16 23
17 def turn(self, value): 24 def turn(self, value):
18 fn = '%s/value' % config.FRIDGE_GPIO 25 self.value_file.seek(0)
19 f = open(fn, 'w')
20 if value: 26 if value:
21 f.write('1') 27 self.value_file.write('1')
22 else: 28 else:
23 f.write('0') 29 self.value_file.write('0')
24 f.close() 30 self.value_file.flush()
25 31
26 def on(self): 32 def on(self):
27 self.turn(1) 33 self.turn(True)
28 34
29 def off(self): 35 def off(self):
30 self.turn(0) 36 self.turn(False)
31 37
32 def do(self): 38 def is_on(self):
39 self.value_file.seek(0)
40 buf = self.value_file.read().strip()
41 if buf == '0':
42 return False
43 if buf != '1':
44 E("Bad value read from gpio '%s': '%s'"
45 % (self.value_file.name, buf))
46 return True
47
48 def run(self, server):
49
50 while True:
51 self.do(server)
52 gevent.sleep(config.FRIDGE_SLEEP)
53
54 def do(self, server):
55 """ this is the main fridge control logic """
33 wort, fridge, ambient = server.current_temps() 56 wort, fridge, ambient = server.current_temps()
34 57
35 if server.uptime() < config.FRIDGE_DELAY: 58 fridge_min = params.fridge_setpoint - self.FRIDGE_AIR_MIN_RANGE
59 fridge_max = params.fridge_setpoint + self.FRIDGE_AIR_MAX_RANGE
60
61 wort_max = params.fridge_setpoint + params.fridge_difference
62
63 off_time = server.now() - self.fridge_off_clock
64
65 if off_time < config.FRIDGE_DELAY:
36 L("fridge skipping, too early") 66 L("fridge skipping, too early")
37 return 67 return
38 68
39 # handle broken wort sensor 69 # handle broken wort sensor
40 if wort is not None: 70 if wort is not None:
47 return 77 return
48 78
49 if fridge is None: 79 if fridge is None:
50 W("Invalid fridge sensor") 80 W("Invalid fridge sensor")
51 81
52 82 if self.is_on():
83 turn_off = False
84 on_time = server.now() - self.fridge_on_clock
53 85
54 86 overshoot = 0
87 if on_time > params.overshoot_delay:
88 overshoot = params.overshoot_factor \
89 * min(self.OVERSHOOT_MAX_DIV, on_time) \
90 / self.OVERSHOOT_MAX_DIV
91 L("on_time %(on_time)f, overshoot %(overshoot)f" % locals())
55 92
56 93 if wort is not None:
94 if (wort - overshoot) < params.fridge_setpoint:
95 L("wort has cooled enough")
96 turn_off = True
97 else:
98 # wort sensor is broken
99 if fridge is not None and last_fridge < fridge_min:
100 W("fridge off fallback")
101 turn_off = True
57 102
58 def run(self, server): 103 if turn_off:
59 self.server = server 104 L("Turning fridge off")
105 self.off()
106 self.fridge_off_clock = server.now()
60 107
61 while True: 108 else:
62 self.do() 109 # fridge is off
63 gevent.sleep(config.FRIDGE_SLEEP) 110 turn_on = False
111 if wort is not None:
112 if wort >= wort_max:
113 L("Wort is too hot")
114 turn_on = True
115 else:
116 # wort sensor is broken
117 if fridge is not None and fridge >= fridge_max:
118 W("frdge on fallback")
119 turn_on = True
120
121 if turn_on:
122 L("Turning fridge on")
123 self.on()
124 fridge_on_clock = server.now()