Skip to content

Commit c6e20eb

Browse files
author
Myles Metzler
committed
WatlowF4 updates at 'beta' status
1 parent 6939c68 commit c6e20eb

File tree

7 files changed

+622
-185
lines changed

7 files changed

+622
-185
lines changed

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
"python.autoComplete.extraPaths": [
55
"${env.SPARK_HOME}\\python",
66
"${env.SPARK_HOME}\\python\\pyspark"
7-
]
7+
],
8+
"python.linting.pylintPath": "c:/Python27/Scripts/pylint.exe"
89
}

bin/example.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
'''
2+
examples of using the chamberconnectlibrary
3+
'''
4+
from chamberconnectlibrary.watlowf4 import WatlowF4
5+
6+
LOOP_NAMES = ['Temperature', 'Humidity']
7+
8+
CONTROLLER = WatlowF4(
9+
interface='RTU',
10+
serialport='//./COM7',
11+
baudrate=19200,
12+
loop_names=LOOP_NAMES
13+
)
14+
print CONTROLLER.process_controller()
15+
16+
print '\ncascade loops:'
17+
for i in range(CONTROLLER.cascades):
18+
print CONTROLLER.get_loop(i+1, 'cascade', ['processvalue', 'setpoint'])
19+
20+
print '\nloops:'
21+
for i in range(CONTROLLER.loops):
22+
print CONTROLLER.get_loop(i+1, 'loop', 'processvalue', 'setpoint')
23+
24+
print '\nnamed loops:'
25+
for name in LOOP_NAMES:
26+
print CONTROLLER.get_loop(name, ['processvalue', 'setpoint'])
27+
28+
for name in LOOP_NAMES:
29+
print CONTROLLER.set_loop(name, setpoint=60.0)
30+
31+
print '\noperations:'
32+
print CONTROLLER.get_operation()
33+
CONTROLLER.set_operation('standby')
34+
35+
print '\nEvents:'
36+
for i in range(8):
37+
print CONTROLLER.get_event(i+1)

chamberconnectlibrary/controllerinterface.py

Lines changed: 94 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class ControllerInterface:
4444
__metaclass__ = ABCMeta
4545

4646
loop_map = []
47+
named_loop_map = {}
4748

4849
def init_common(self, **kwargs):
4950
'''Setup properties of all controllers of the chamberconnectlibrary'''
@@ -99,16 +100,35 @@ def set_refrig(self, value):
99100
pass
100101

101102
@exclusive
102-
def get_loop(self, N, loop_type, param_list=None):
103+
def get_loop(self, identifier, *args):
103104
'''
104105
Get all parameters for a loop from a given list.
105-
106-
Args:
107-
N (int): The loop number (1-4).
108-
loop_type (str): The loop type::
109-
"cascade" -- A cascade control loop.
110-
"loop" -- A standard control loop.
111-
param_list (list(str)): The list of parameters to read defaults::
106+
There are four different ways to call this method; all methods return the same data:
107+
108+
get_loop(str(identifier), *str(parameters))
109+
Args:
110+
identifier (str): The name of the loop.
111+
parameters (list(string)): The list of parameters to get from the loop, (see below)
112+
113+
get_loop(str(identifier), [str(parameters)])
114+
Args:
115+
identifier (str): The name of the loop.
116+
parameters (list(string)): The list of parameters to get from the loop, (see below)
117+
118+
get_loop(int(identifier), str(loop_type), *str(parameters))
119+
Args:
120+
identifier (str): The name of the loop.
121+
loop_type (str): The type of loop to be accessed ("loop" or "cascade")
122+
parameters (list(string)): The list of parameters to get from the loop, (see below)
123+
124+
get_loop(int(identifier), str(loop_type), [str(parameters)])
125+
Args:
126+
identifier (str): The name of the loop.
127+
loop_type (str): The type of loop to be accessed ("loop" or "cascade")
128+
parameters (list(string)): The list of parameters to get from the loop, (see below)
129+
130+
parameters:
131+
The following is a list of available parameters as referenced by each call type:
112132
"setpoint" -- The target temp/humi/altitude/etc of the control loop
113133
"processvalue" -- The current conditions inside the chamber
114134
"range" -- The settable range for the "setpoint"
@@ -158,41 +178,62 @@ def get_loop(self, N, loop_type, param_list=None):
158178
'power':self.get_loop_power
159179
}
160180
}
181+
182+
if isinstance(identifier, basestring):
183+
my_loop_map = self.loop_map[self.named_loop_map[identifier]]
184+
loop_number = my_loop_map['num']
185+
loop_type = my_loop_map['type']
186+
param_list = args if len(args) > 0 else None
187+
elif isinstance(identifier, int) and len(args) >= 1:
188+
loop_number = identifier
189+
loop_type = args[0]
190+
param_list = args[1:] if len(args) > 1 else None
191+
else:
192+
raise ValueError(
193+
'invalid argument format, call w/: '
194+
'get_loop(int(identifier), str(loop_type), *args) or '
195+
'get_loop(str(identifier), *args), *args are optional.'
196+
)
197+
161198
if param_list is None:
162199
param_list = loop_functions[loop_type].keys()
163200
excludes = ['setPoint', 'setValue', 'processValue']
164201
param_list = [x for x in param_list if x not in excludes]
202+
elif len(param_list) >= 1 and \
203+
(isinstance(param_list[0], list) or isinstance(param_list[0], tuple)):
204+
param_list = param_list[0]
165205
ret = {}
166206
for key in param_list:
167207
try:
168-
ret[key] = loop_functions[loop_type][key](N, exclusive=False)
208+
ret[key] = loop_functions[loop_type][key](loop_number, exclusive=False)
169209
except KeyError:
170210
ret[key] = None
171211
except NotImplementedError:
172212
ret[key] = None
173213
return ret
174214

175215
@exclusive
176-
def set_loop(self, N, loop_type, param_list):
216+
def set_loop(self, identifier, loop_type='loop', param_list=None, **kwargs):
177217
'''
178218
Set all parameters for a loop from a given list.
179219
180220
Args:
181-
N (int): The loop number (1-4).
182-
loop_type (str): The loop type::
221+
identifier (int or str): The loop number, or the name of the loop
222+
loop_type (str): The loop type (disregarded when identifier is a str)::
183223
"cascade" -- A cascade control loop.
184-
"loop" -- A standard control loop.
185-
param_list (dict(dict)): The possible keys and there values::
224+
"loop" -- A standard control loop (default).
225+
param_list (dict(dict)): The parameters to update as a dictionary::
226+
see kwargs for possible keys/values
227+
kwargs (dict): The parameters to update as key word arguments, param_list overrides::
186228
"setpoint" -- The target temp/humi/altitude/etc of the control loop
187229
"range" -- The settable range for the "setpoint"
188230
"enable" -- turn the control loop on or off
189231
"power" -- set the manual power of the control loop
232+
"mode" -- set the control mode of the control loop
190233
"deviation" -- (type="cascade" only) The allowable difference between air/prod.
191234
"enable_cascade" -- (type="cascade" only) Enable or disable cascade type control
192235
Returns:
193236
None
194-
Raises:
195-
ModbusError
196237
'''
197238
loop_functions = {
198239
'cascade':{
@@ -216,14 +257,39 @@ def set_loop(self, N, loop_type, param_list):
216257
'power':self.set_loop_power
217258
}
218259
}
260+
if param_list is None:
261+
param_list = kwargs
262+
if isinstance(identifier, basestring):
263+
my_loop_map = self.loop_map[self.named_loop_map[identifier]]
264+
loop_number = my_loop_map['num']
265+
loop_type = my_loop_map['type']
266+
elif isinstance(identifier, int):
267+
loop_number = identifier
268+
else:
269+
raise ValueError(
270+
'invalid argument format, call w/: '
271+
'set_loop(int(identifier), str(loop_type), **kwargs) or '
272+
'get_loop(str(identifier), **kwargs)'
273+
)
274+
219275
#mode must be done first
220276
if 'mode' in param_list:
221-
loop_functions[loop_type]['mode'](exclusive=False, N=N, value=param_list.pop('mode'))
277+
loop_functions[loop_type]['mode'](
278+
exclusive=False,
279+
N=loop_number,
280+
value=param_list.pop('mode')
281+
)
222282
for key, val in param_list.items():
223283
try:
224-
loop_functions[loop_type][key](exclusive=False, N=N, value=val)
284+
loop_functions[loop_type][key](
285+
exclusive=False,
286+
N=loop_number,
287+
value=val
288+
)
225289
except KeyError:
226290
pass
291+
except NotImplementedError:
292+
pass
227293

228294
@exclusive
229295
def get_operation(self, pgm=None):
@@ -341,7 +407,7 @@ def set_program(self, N, value):
341407
342408
Args:
343409
N (int): The program number
344-
value (dict): The program to write to the controller
410+
value (dict): The program to write to the controller, None erases the given program
345411
'''
346412
if value is None:
347413
return self.prgm_delete(N, exclusive=False)
@@ -996,6 +1062,15 @@ def set_network_settings(self, value):
9961062
'''
9971063
pass
9981064

1065+
def get_operation_modes(self):
1066+
'''
1067+
Get the supported operation modes for this controller.
1068+
1069+
Returns:
1070+
["standby","constant","program"] or ["constant","program"]
1071+
'''
1072+
return ['standby', 'constant', 'program']
1073+
9991074
def self_test(self, loops, cascades):
10001075
'''
10011076
preform a self test on all functions

chamberconnectlibrary/espec.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,11 @@ def __update_loop_map(self):
6464
'''
6565
update the loop map.
6666
'''
67+
self.named_loop_map = {'Temperature':0, 'temperature':0, 'Temp':0, 'temp':0}
6768
self.loop_map = [{'type':'cascade', 'num':j+1} for j in range(self.cascades)]
6869
self.loop_map += [{'type':'loop', 'num':j+1} for j in range(self.loops)]
70+
if len(self.loop_map) > 1:
71+
self.named_loop_map = {'Humidity':1, 'humidity':1, 'Hum':1, 'hum':1}
6972

7073
def connect(self):
7174
'''
@@ -124,7 +127,7 @@ def set_refrig(self, value):
124127
self.client.write_set(**value)
125128

126129
@exclusive
127-
def set_loop(self, N, loop_type, param_list):
130+
def set_loop(self, N, loop_type, param_list=None, **kwargs):
128131
#cannot use the default controllerInterface version.
129132
lpfuncs = {
130133
'cascade':{
@@ -144,6 +147,8 @@ def set_loop(self, N, loop_type, param_list):
144147
'mode':self.set_loop_mode
145148
}
146149
}
150+
if param_list is None:
151+
param_list = kwargs
147152
spt1 = 'setpoint' in param_list
148153
spt2 = 'setPoint' in param_list
149154
spt3 = 'setValue' in param_list
@@ -299,12 +304,12 @@ def set_loop_mode(self, N, value):
299304
def get_loop_mode(self, N):
300305
if N > 2:
301306
raise ValueError(self.lp_exmsg)
302-
if self.lpd[N] == self.temp:
303-
cur = 'On'
304-
con = 'On'
305-
elif self.lpd[N] == self.humi:
307+
if self.lpd[N] == self.humi:
306308
cur = 'On' if self.cached(self.client.read_humi)['enable'] else 'Off'
307309
con = 'On' if self.cached(self.client.read_constant_humi)['enable'] else 'Off'
310+
else:
311+
cur = 'On'
312+
con = 'On'
308313
if self.client.read_mode() in ['OFF', 'STANDBY']:
309314
cur = 'Off'
310315
return {"current": cur, "constant": con}
@@ -317,11 +322,12 @@ def get_loop_modes(self, N):
317322
else:
318323
raise ValueError(self.lp_exmsg)
319324

325+
@exclusive
320326
def get_loop_power(self, N):
321327
if self.lpd[N] == self.temp:
322-
val = self.cached(self.client.read_htr['dry'])
328+
val = self.cached(self.client.read_htr)['dry']
323329
elif self.lpd[N] == self.humi:
324-
val = self.cached(self.client.read_htr['wet'])
330+
val = self.cached(self.client.read_htr)['wet']
325331
else:
326332
raise ValueError(self.lp_exmsg)
327333
return {'current':val, 'constant':val}
@@ -434,11 +440,13 @@ def set_cascade_deviation(self, N, value):
434440
raise ValueError('value must contain "positive" and "negative" keys')
435441
self.client.write_temp_ptc(self.get_cascade_ctl(self.temp, exclusive=False), **value)
436442

443+
@exclusive
437444
def get_cascade_power(self, N):
438445
if self.lpd[N] != self.temp:
439446
raise ValueError(self.cs_exmsg)
440447
return self.get_loop_power(self.temp, exclusive=False)
441448

449+
@exclusive
442450
def set_cascade_power(self, N, value):
443451
raise NotImplementedError
444452

0 commit comments

Comments
 (0)