-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathredox.py
More file actions
191 lines (181 loc) · 7.63 KB
/
redox.py
File metadata and controls
191 lines (181 loc) · 7.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#!/usr/bin/python
import threading
from defines import *
from mode import Mode
from relay import Relay
class Redox(Relay, Mode):
ORP_CAN_PIN = 1
CL_GPIO_PIN = 21
LOWER_BOUND = -2000
UPPER_BOUND = 2000
MIN_LEVEL = 350
MAX_LEVEL = 950
INCREMENT = 1.0
PAUSE = 15.0
FILTER = 30
def __init__(self, debug, database, default, analog):
Mode.__init__(self, database, "redox")
self.__lock = threading.RLock()
Relay.__init__(self, self.CL_GPIO_PIN)
self.__debug = debug
self.__default = default
self.__analog = analog
self.__injectionTimer = None
self.__current = 0
self.__waitTick = 0
self.__injection = 37.5 # 250ml
self.__wait = 600 / REFRESH_TICK # 10mn de stabilisation
self.offset = 0
self.idle = 650
def __del__(self):
with self.__lock:
if self.__injectionTimer is not None:
self.__injectionTimer.cancel()
self.switchOff()
def __startInjection(self):
with self.__lock:
self.switchOn()
self.__injectionTimer = threading.Timer([self.INCREMENT, self.__duration][self.__duration < self.INCREMENT], self.__endOfInjection)
self.__injectionTimer.start()
def __endOfInjection(self):
with self.__lock:
self.switchOff()
if self.__duration < self.INCREMENT:
self.__duration = 0
else:
self.__duration -= self.INCREMENT
if self.__duration:
self.__injectionTimer = threading.Timer(self.PAUSE, self.__startInjection)
self.__injectiodefaultnTimer.start()
else:
self.__debug.TRACE(self.__debug.DETAIL, "CL injection is stopped\n")
self.__waitTick = self.__wait
self.__count = 0
self.__injectionTimer = None
def __regulation(self):
if self.__waitGuard > 0:
self.__waitGuard -= 1
delta = self.idle - self.__current
if self.__waitTick > 0:
self.__waitTick -= 1
if abs(self.__previous - self.__current) > self.FILTER:
self.__count = 0
else:
self.__count += 1
self.__previous = self.__current
if self.__waitTick == 0:
ratio = 1 + abs(delta / self.__delta)
if self.__count >= (self.__wait * 0.2):
# Stable
self.__injection *= ratio
self.getDatabase().save("redox", "injection", self.__injection)
self.__debug.TRACE(self.__debug.WARNING, "CL injection need to be increased: %.1fs\n", self.__injection)
else:
# Not yet stable
self.__wait *= ratio
self.getDatabase().save("redox", "wait", self.__wait)
self.__debug.TRACE(self.__debug.WARNING, "Wait after CL injection need to be increased: %.1fs\n", self.__wait)
self.__waitGuard = self.__wait
if delta > 0:
if self.__injectionTimer is None and self.__waitTick == 0 and self.__waitGuard == 0:
if delta >= ((self.idle / 10.0) * 3):
duration = self.__injection
elif delta >= ((self.idle / 10.0) * 2):
duration = self.__injection * 0.75
elif delta >= (self.idle / 10.0):
duration = self.__injection * 0.5
else:
duration = self.__injection * 0.2
self.__debug.TRACE(self.__debug.DETAIL, "CL injection is started: %.1fs\n", duration)
self.__delta = delta
self.__duration = duration
self.__startInjection()
else:
if self.__injectionTimer is not None:
self.__injectionTimer.cancel()
self.__injectionTimer = None
self.switchOff()
self.__injection /= 2
if self.__injection < 2:
self.__injection = 2.0
self.__debug.TRACE(self.__debug.WARNING, "CL injection is really too big: %.1fs\n", self.__injection)
self.__waitGuard = self.__wait
elif self.__waitTick > 0:
if self.__count >= (self.__wait * 0.2):
# Stable
self.__wait *= 0.9
self.getDatabase().save("redox", "wait", self.__wait)
self.__debug.TRACE(self.__debug.WARNING, "Wait after CL injection could be decreased: %.1fs\n", self.__wait)
else:
# Not yet stable
self.__injection *= 0.9
self.getDatabase().save("redox", "injection", self.__injection)
self.__debug.TRACE(self.__debug.WARNING, "CL injection could be decreased: %.1fs\n", self.__injection)
self.__waitTick = 0
self.__waitGuard = self.__wait
def __getORPLevel(self):
# Range: 0.5V to 4.5V: 2.5V +/- 2000mV
orpMeasure = self.__analog.read(self.ORP_CAN_PIN)
return int((2500 - orpMeasure) / 1.037) # mV
def read(self):
return self.__current
def update(self):
with self.__lock:
self.__current = self.offset + self.__getORPLevel()
if self.isOffMode():
if self.isSwitchOn():
self.__debug.TRACE(self.__debug.DETAIL, "Chlore injection is stopped: Forced to OFF\n")
self.switchOff()
elif self.isOnMode():
if self.isSwitchOff():
self.__debug.TRACE(self.__debug.DETAIL, "Chlore injection is started: Forced to ON\n")
self.switchOn()
elif self.isAutoMode():
self.__regulation()
if self.__current < self.MIN_LEVEL:
self.__default.add(self.__default.IMPORTANT, "ORP", "Level too low!")
elif self.__current > self.MAX_LEVEL:
self.__default.add(self.__default.IMPORTANT, "ORP", "Level too high!")
self.__debug.TRACE(self.__debug.DETAIL, "Chlore injection is stopped: ORP level too high\n")
self.switchOff()
if __name__ == '__main__':
import time, sys, os
sys.path.append(os.path.join(os.path.pardir, "RRaspPY"))
sys.path.append("lib")
import RPi.GPIO as GPIO
from default import Default
from analog import Analog
from relay import Relay
from pump import Pump
from debug import Debug
debug = Debug(Debug.DEBUG)
GPIO.cleanup()
GPIO.setmode(GPIO.BCM)
class Database:
def __init__(self):
self.mode = dict()
self.mode["redox"] = Mode.READ_STATE # AUTO_STATE READ_STATE
def save(self, a, b, c):
print "SAVE %s::%s = %s" % (a, b, c)
try:
redox = Redox(debug, Database(), Default(), Analog(0x49))
GPIO.setup(Pump.LIQUID_MOVE_GPIO_PIN, GPIO.IN, pull_up_down=GPIO.PUD_UP)
state = GPIO.input(Pump.LIQUID_MOVE_GPIO_PIN)
relayPump = Relay(Pump.PUMP_GPIO_PIN)
relayPump.switchOn()
time.sleep(2.0)
if state == GPIO.input(Pump.LIQUID_MOVE_GPIO_PIN):
relayPump.switchOff()
raise ValueError, "Water move not detected"
for i in range(12):
redox.update()
print redox.read()
time.sleep(5)
except KeyboardInterrupt:
pass
except Exception as error:
print str(error)
finally:
if relayPump.isSwitchOn():
relayPump.switchOff()
GPIO.cleanup()