UC2-REST 0.2.0.18__tar.gz → 0.2.0.19__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/PKG-INFO +1 -1
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/UC2_REST.egg-info/PKG-INFO +1 -1
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/UC2_REST.egg-info/SOURCES.txt +1 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/UC2Client.py +5 -2
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/__version__.py +1 -1
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/home.py +1 -1
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/laser.py +1 -1
- uc2_rest-0.2.0.19/uc2rest/message.py +85 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/motor.py +3 -13
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/mserial.py +71 -18
- uc2_rest-0.2.0.19/uc2rest/temperature.py +93 -0
- UC2-REST-0.2.0.18/uc2rest/temperature.py +0 -54
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/LICENSE +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/README.md +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/UC2_REST.egg-info/dependency_links.txt +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/UC2_REST.egg-info/not-zip-safe +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/UC2_REST.egg-info/requires.txt +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/UC2_REST.egg-info/top_level.txt +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/setup.cfg +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/setup.py +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/__init__.py +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/analog.py +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/camera.py +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/cmdrecorder.py +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/config.py +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/config_.py +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/digitalout.py +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/galvo.py +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/ledmatrix.py +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/logger.py +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/modules.py +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/pid.py +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/rotator.py +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/slm.py +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/state.py +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/updater.py +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/utils.py +0 -0
- {UC2-REST-0.2.0.18 → uc2_rest-0.2.0.19}/uc2rest/wifi.py +0 -0
|
@@ -23,7 +23,7 @@ from .rotator import Rotator
|
|
|
23
23
|
from .logger import Logger
|
|
24
24
|
from .cmdrecorder import cmdRecorder
|
|
25
25
|
from .temperature import Temperature
|
|
26
|
-
|
|
26
|
+
from .message import Message
|
|
27
27
|
try:
|
|
28
28
|
import requests
|
|
29
29
|
except:
|
|
@@ -141,6 +141,9 @@ class UC2Client(object):
|
|
|
141
141
|
# initialize digital out
|
|
142
142
|
self.digitalout = DigitalOut(self)
|
|
143
143
|
|
|
144
|
+
# initialize messaging
|
|
145
|
+
self.message = Message(self)
|
|
146
|
+
|
|
144
147
|
# initialize config
|
|
145
148
|
if False: # not self.isPyScript:
|
|
146
149
|
self.config = config(self)
|
|
@@ -173,7 +176,7 @@ class UC2Client(object):
|
|
|
173
176
|
elif self.is_serial or self.isPyScript:
|
|
174
177
|
if timeout <=0:
|
|
175
178
|
getReturn = False
|
|
176
|
-
return self.serial.post_json(path, payload, getReturn=getReturn,
|
|
179
|
+
return self.serial.post_json(path, payload, getReturn=getReturn, nResponses=nResponses, timeout=timeout)
|
|
177
180
|
else:
|
|
178
181
|
self.logger.error("No ESP32 device is connected - check IP or Serial port!")
|
|
179
182
|
return None
|
|
@@ -6,7 +6,7 @@ __version__.py
|
|
|
6
6
|
|
|
7
7
|
__title__ = 'UC2-REST'
|
|
8
8
|
__description__ = 'This pacage will help you to drive the ESP32-driven microscopy control modules from UC2'
|
|
9
|
-
__version__ = "v0.2.0.
|
|
9
|
+
__version__ = "v0.2.0.19"
|
|
10
10
|
__author__ = 'Benedict Diederich'
|
|
11
11
|
__author_email__ = 'benedictdied@gmail.com'
|
|
12
12
|
__license__ = 'GPL v3'
|
|
@@ -11,7 +11,7 @@ class Laser(object):
|
|
|
11
11
|
def set_laser(self, channel=1, value=0, auto_filterswitch=False,
|
|
12
12
|
filter_axis=-1, filter_position = None,
|
|
13
13
|
despeckleAmplitude = 0.,
|
|
14
|
-
despecklePeriod=10, timeout=20, is_blocking =
|
|
14
|
+
despecklePeriod=10, timeout=20, is_blocking = False):
|
|
15
15
|
if channel not in (0,1,2,3):
|
|
16
16
|
if channel=="R":
|
|
17
17
|
channel = 1
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import time
|
|
3
|
+
import json
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
gTIMEOUT = 1 # seconds to wait for a response from the ESP32
|
|
7
|
+
class Message(object):
|
|
8
|
+
'''
|
|
9
|
+
This class only parses incoming messages from the ESP32 that can be used e.g. for triggering events such as taking an image
|
|
10
|
+
or converting hardware inputs such as button presses to software events
|
|
11
|
+
'''
|
|
12
|
+
def __init__(self, parent=None):
|
|
13
|
+
self._parent = parent
|
|
14
|
+
|
|
15
|
+
# create a dictionary of callback functions that can be triggered by incoming messages
|
|
16
|
+
self._callbackPerKey = {}
|
|
17
|
+
self.NCallBacks = 10
|
|
18
|
+
for i in range(self.NCallBacks):
|
|
19
|
+
self._callbackPerKey[i] = None
|
|
20
|
+
|
|
21
|
+
# register a callback function for the motor status on the serial loop
|
|
22
|
+
if hasattr(self._parent, "serial"):
|
|
23
|
+
self._parent.serial.register_callback(self._callback_message, pattern="message")
|
|
24
|
+
|
|
25
|
+
def _callback_message(self, data):
|
|
26
|
+
''' cast the json in the form:
|
|
27
|
+
{
|
|
28
|
+
"message": {
|
|
29
|
+
"key": 1,
|
|
30
|
+
"data": 1
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
into seperated actions that follow this pattern:
|
|
34
|
+
data lookup:
|
|
35
|
+
{
|
|
36
|
+
key | meaning | value
|
|
37
|
+
--------------------------------
|
|
38
|
+
1 | snap image | 0
|
|
39
|
+
2 | exposure time | 0....1000000
|
|
40
|
+
3 | gain | 0...100
|
|
41
|
+
...
|
|
42
|
+
|
|
43
|
+
Example:
|
|
44
|
+
#%%
|
|
45
|
+
import uc2rest
|
|
46
|
+
import time
|
|
47
|
+
|
|
48
|
+
port = "unknown"
|
|
49
|
+
port = "/dev/cu.SLAB_USBtoUART"
|
|
50
|
+
ESP32 = uc2rest.UC2Client(serialport=port, baudrate=500000, DEBUG=True)
|
|
51
|
+
|
|
52
|
+
# register callback function for key/value pair
|
|
53
|
+
def my_callback_key1(value):
|
|
54
|
+
print("Callback: ", value)
|
|
55
|
+
ESP32.message.register_callback(1, my_callback_key1)
|
|
56
|
+
|
|
57
|
+
while True:
|
|
58
|
+
time.sleep(.1)
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
'''
|
|
62
|
+
try:
|
|
63
|
+
# parse the message
|
|
64
|
+
key = data["message"]["key"]
|
|
65
|
+
value = data["message"]["data"]
|
|
66
|
+
# trigger the action
|
|
67
|
+
if self._callbackPerKey[key] is not None:
|
|
68
|
+
self._callbackPerKey[key](value) # we call the function with the value
|
|
69
|
+
except Exception as e:
|
|
70
|
+
print("Error in _callback_message: ", e)
|
|
71
|
+
|
|
72
|
+
def register_callback(self, key, callback):
|
|
73
|
+
''' register a callback function for a specific key '''
|
|
74
|
+
self._callbackPerKey[key] = callback
|
|
75
|
+
|
|
76
|
+
def trigger_message(self, key:int=1, value:int=1):
|
|
77
|
+
# {"task": "/message_act", "message": 1, "key":1, "value":1}
|
|
78
|
+
path = "/heat_act"
|
|
79
|
+
payload = {
|
|
80
|
+
"task": path,
|
|
81
|
+
"key": key,
|
|
82
|
+
"value": value
|
|
83
|
+
}
|
|
84
|
+
r = self._parent.post_json(path, payload, getReturn=False)
|
|
85
|
+
return r
|
|
@@ -9,16 +9,6 @@ class Motor(object):
|
|
|
9
9
|
# indicate if there is any motion happening
|
|
10
10
|
isRunning = False
|
|
11
11
|
|
|
12
|
-
# a dictionary that stores all motor parameters for each dxis
|
|
13
|
-
settingsdict = {"motor": {"steppers":
|
|
14
|
-
[{"stepperid":0,"dir":0,"step":0,"enable":0,"dir_inverted":False,"step_inverted":False,"enable_inverted":False,"speed":0,"speedmax":200000,"max_pos":100000,"min_pos":-100000},
|
|
15
|
-
{"stepperid":1,"dir":0,"step":0,"enable":0,"dir_inverted":False,"step_inverted":False,"enable_inverted":False,"speed":0,"speedmax":200000,"max_pos":100000,"min_pos":-100000},
|
|
16
|
-
{"stepperid":2,"dir":0,"step":0,"enable":0,"dir_inverted":False,"step_inverted":False,"enable_inverted":False,"speed":0,"speedmax":200000,"max_pos":100000,"min_pos":-100000},
|
|
17
|
-
{"stepperid":3,"dir":0,"step":0,"enable":0,"dir_inverted":False,"step_inverted":False,"enable_inverted":False,"speed":0,"speedmax":200000,"max_pos":100000,"min_pos":-100000}]
|
|
18
|
-
}}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
12
|
def __init__(self, parent=None):
|
|
23
13
|
self._parent = parent
|
|
24
14
|
|
|
@@ -99,8 +89,8 @@ class Motor(object):
|
|
|
99
89
|
r = self._parent.post_json(path, payload)
|
|
100
90
|
return r
|
|
101
91
|
|
|
102
|
-
# {"task": "/motor_act", "stagescan": {"nStepsLine":
|
|
103
|
-
def startStageScanning(self, nStepsLine=100, dStepsLine=1, nTriggerLine=1, nStepsPixel=100, dStepsPixel=1, nTriggerPixel=1, delayTimeStep=10, nFrames=5):
|
|
92
|
+
# {"task": "/motor_act", "stagescan": {"nStepsLine": 50, "dStepsLine": 1, "nTriggerLine": 1, "nStepsPixel": 50, "dStepsPixel": 1, "nTriggerPixel": 1, "delayTimeStep": 10, "stopped": 0, "nFrames": 50}}"}}
|
|
93
|
+
def startStageScanning(self, nStepsLine=100, dStepsLine=1, nTriggerLine=1, nStepsPixel=100, dStepsPixel=1, nTriggerPixel=1, delayTimeStep=10, nFrames=5, isBlocking = False):
|
|
104
94
|
path = "/motor_act"
|
|
105
95
|
payload = {
|
|
106
96
|
"task": path,
|
|
@@ -115,7 +105,7 @@ class Motor(object):
|
|
|
115
105
|
"stopped": 0,
|
|
116
106
|
"nFrames": nFrames
|
|
117
107
|
}}
|
|
118
|
-
r = self._parent.post_json(path, payload)
|
|
108
|
+
r = self._parent.post_json(path, payload, getReturn=isBlocking)
|
|
119
109
|
return r
|
|
120
110
|
|
|
121
111
|
def stopStageScanning(self):
|
|
@@ -14,7 +14,7 @@ class Serial:
|
|
|
14
14
|
self.baudrate = baudrate
|
|
15
15
|
self.timeout = timeout
|
|
16
16
|
self._parent = parent
|
|
17
|
-
|
|
17
|
+
self.manufacturer = ""
|
|
18
18
|
if self._parent is None:
|
|
19
19
|
import logging
|
|
20
20
|
self._logger = logging.getLogger(__name__)
|
|
@@ -26,18 +26,19 @@ class Serial:
|
|
|
26
26
|
self.identity = identity
|
|
27
27
|
self.DEBUG = DEBUG
|
|
28
28
|
self.is_connected = False
|
|
29
|
-
self.write_timeout = 0.
|
|
29
|
+
self.write_timeout = 0.05
|
|
30
30
|
self.read_timeout = 0.02
|
|
31
31
|
|
|
32
32
|
self.cmdCallBackFct = None
|
|
33
33
|
|
|
34
34
|
# setup command queue
|
|
35
35
|
self.resetLastCommand = False
|
|
36
|
-
self.
|
|
36
|
+
self.sender_queue = queue.Queue()
|
|
37
37
|
self.responses = {}
|
|
38
38
|
self.commands = {}
|
|
39
39
|
self.lock = threading.Lock()
|
|
40
|
-
|
|
40
|
+
|
|
41
|
+
# setup callback list for parent modules
|
|
41
42
|
self.callBackList = []
|
|
42
43
|
|
|
43
44
|
# initialize serial connection
|
|
@@ -101,6 +102,11 @@ class Serial:
|
|
|
101
102
|
self.identifier_counter = 0 # Counter for generating unique identifiers
|
|
102
103
|
self.thread = threading.Thread(target=self._process_commands)
|
|
103
104
|
self.thread.start()
|
|
105
|
+
|
|
106
|
+
# setup sender queue
|
|
107
|
+
self.sender_worker_thread = threading.Thread(target=self._sending_commands)
|
|
108
|
+
self.sender_worker_thread.daemon = True # Ensure the thread exits when the main program does
|
|
109
|
+
self.sender_worker_thread.start()
|
|
104
110
|
return ser
|
|
105
111
|
|
|
106
112
|
def findCorrectSerialDevice(self):
|
|
@@ -119,12 +125,14 @@ class Serial:
|
|
|
119
125
|
any(port.description.startswith(allowed_description) for allowed_description in descriptions_to_check):
|
|
120
126
|
if self.tryToConnect(port.device):
|
|
121
127
|
self.is_connected = True
|
|
128
|
+
self.manufacturer = port.manufacturer
|
|
122
129
|
return self.serialdevice
|
|
123
130
|
|
|
124
131
|
self.is_connected = False
|
|
125
132
|
self.serialport = "NotConnected"
|
|
126
133
|
self.serialdevice = None
|
|
127
134
|
self._logger.debug("No USB device connected! Using DUMMY!")
|
|
135
|
+
self.manufacturer = "UC2Mock"
|
|
128
136
|
return None
|
|
129
137
|
|
|
130
138
|
def tryToConnect(self, port):
|
|
@@ -168,6 +176,29 @@ class Serial:
|
|
|
168
176
|
self.identifier_counter += 1
|
|
169
177
|
return self.identifier_counter
|
|
170
178
|
|
|
179
|
+
def _enqueue_command(self, json_command):
|
|
180
|
+
"""Add a command to the queue."""
|
|
181
|
+
self.sender_queue.put(json_command)
|
|
182
|
+
|
|
183
|
+
def _sending_commands(self):
|
|
184
|
+
"""Sending commands from the queue with a 1s delay between them."""
|
|
185
|
+
while self.running:
|
|
186
|
+
|
|
187
|
+
# Wait for the next command
|
|
188
|
+
json_command = self.sender_queue.get()
|
|
189
|
+
|
|
190
|
+
# Process the command
|
|
191
|
+
try:
|
|
192
|
+
self.serialdevice.write(json_command.encode('utf-8'))
|
|
193
|
+
except Exception as e:
|
|
194
|
+
self._logger.error("Failed to write the line in serial: "+str(e))
|
|
195
|
+
|
|
196
|
+
# Signal that the command has been processed
|
|
197
|
+
self.sender_queue.task_done()
|
|
198
|
+
|
|
199
|
+
# Wait for .05 second before processing the next command
|
|
200
|
+
time.sleep(0.05)
|
|
201
|
+
|
|
171
202
|
def _process_commands(self):
|
|
172
203
|
buffer = ""
|
|
173
204
|
reading_json = False
|
|
@@ -176,9 +207,9 @@ class Serial:
|
|
|
176
207
|
lineCounter = 0
|
|
177
208
|
while self.running:
|
|
178
209
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
210
|
+
if self.manufacturer == "UC2Mock":
|
|
211
|
+
self.running = False
|
|
212
|
+
return
|
|
182
213
|
|
|
183
214
|
# device not ready yet
|
|
184
215
|
if self.serialdevice is None:
|
|
@@ -188,6 +219,7 @@ class Serial:
|
|
|
188
219
|
self.is_connected = True
|
|
189
220
|
|
|
190
221
|
# if we just want to send but not even wait for a response
|
|
222
|
+
|
|
191
223
|
try:
|
|
192
224
|
mReadline = self.serialdevice.readline()
|
|
193
225
|
except Exception as e:
|
|
@@ -219,15 +251,26 @@ class Serial:
|
|
|
219
251
|
self._logger.error("Error: %s" % str(e))
|
|
220
252
|
json_response = {}
|
|
221
253
|
|
|
254
|
+
try: currentIdentifier = json_response["qid"]
|
|
255
|
+
except: pass
|
|
256
|
+
|
|
222
257
|
with self.lock:
|
|
223
|
-
try: currentIdentifier = json_response["qid"]
|
|
224
|
-
except: pass
|
|
225
258
|
try:
|
|
226
259
|
self.responses[currentIdentifier].append(json_response.copy())
|
|
227
260
|
except:
|
|
228
261
|
self.responses[currentIdentifier] = list()
|
|
229
262
|
self.responses[currentIdentifier].append(json_response.copy())
|
|
230
|
-
|
|
263
|
+
buffer = "" # reset buffer
|
|
264
|
+
|
|
265
|
+
# detect a reboot of the device and return the current QIDs
|
|
266
|
+
elif line == "reboot":
|
|
267
|
+
self._logger.warning("Device rebooted")
|
|
268
|
+
self.resetLastCommand = True
|
|
269
|
+
buffer = ""
|
|
270
|
+
lineCounter = 0
|
|
271
|
+
reading_json = False
|
|
272
|
+
self.responses[currentIdentifier].append({"reboot": 1})
|
|
273
|
+
self.responses[currentIdentifier].append({"qid": currentIdentifier})
|
|
231
274
|
|
|
232
275
|
if reading_json:
|
|
233
276
|
buffer += line
|
|
@@ -285,24 +328,25 @@ class Serial:
|
|
|
285
328
|
If nResponses is 1, then the command is sent and the response is returned.
|
|
286
329
|
If nResponses is >1, then the command is sent and a list of responses is returned.
|
|
287
330
|
'''
|
|
288
|
-
t0 = time.time()
|
|
289
331
|
if type(command) == str:
|
|
290
332
|
command = json.loads(command)
|
|
291
333
|
identifier = self._generate_identifier()
|
|
292
334
|
command["qid"] = identifier
|
|
293
|
-
self.command_queue.put((identifier, command))
|
|
294
335
|
try:
|
|
295
336
|
json_command = json.dumps(command)+"\n"
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
337
|
+
self.serialdevice.flush()
|
|
338
|
+
if self.DEBUG: self._logger.debug("[SendMessage]: "+str(json_command))
|
|
339
|
+
# we have to queue the commands and give it some time to process
|
|
340
|
+
self._enqueue_command(json_command)
|
|
341
|
+
|
|
300
342
|
except Exception as e:
|
|
301
343
|
if self.DEBUG: self._logger.error(e)
|
|
302
344
|
return "Failed to Send"
|
|
303
|
-
self.commands[identifier]=command
|
|
304
|
-
if nResponses <= 0 or not self.is_connected or
|
|
345
|
+
self.commands[identifier]=command # FIXME: Need to clear this after the response is received
|
|
346
|
+
if nResponses <= 0 or not self.is_connected or self.manufacturer=="UC2Mock":
|
|
305
347
|
return identifier
|
|
348
|
+
t0 = time.time()
|
|
349
|
+
timeReturnReceived = 0.3
|
|
306
350
|
while self.running:
|
|
307
351
|
time.sleep(0.002)
|
|
308
352
|
if self.resetLastCommand or time.time()-t0>timeout or not self.is_connected:
|
|
@@ -315,6 +359,15 @@ class Serial:
|
|
|
315
359
|
if -identifier in self.responses:
|
|
316
360
|
self._logger.debug("You have sent the wrong command!")
|
|
317
361
|
return "Wrong Command"
|
|
362
|
+
if time.time()-t0>timeReturnReceived and not (identifier in self.responses and len(self.responses[identifier]) > 0):
|
|
363
|
+
self._logger.debug("It takes too long to get a response, we will resend the last command")
|
|
364
|
+
try:
|
|
365
|
+
self.DEBUG=1
|
|
366
|
+
self.serialdevice.write(json.dumps(self.commands[identifier]).encode('utf-8'))
|
|
367
|
+
time.sleep(0.1)
|
|
368
|
+
except Exception as e:
|
|
369
|
+
self._logger.error("Failed to write the line in serial: "+str(e))
|
|
370
|
+
|
|
318
371
|
|
|
319
372
|
def interruptCurrentSerialCommunication(self):
|
|
320
373
|
self.resetLastCommand = True
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import threading
|
|
3
|
+
class Temperature(object):
|
|
4
|
+
|
|
5
|
+
def __init__(self, parent):
|
|
6
|
+
self._parent = parent
|
|
7
|
+
self._temperature = -273.15
|
|
8
|
+
|
|
9
|
+
self.is_temperature_polling = False
|
|
10
|
+
|
|
11
|
+
# register a callback function for the motor status on the serial loop
|
|
12
|
+
if hasattr(self._parent, "serial"):
|
|
13
|
+
self._parent.serial.register_callback(self._callback_temperature_status, pattern="heat")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
'''
|
|
17
|
+
##############################################################################################################################
|
|
18
|
+
Temperature Controllers
|
|
19
|
+
##############################################################################################################################
|
|
20
|
+
'''
|
|
21
|
+
|
|
22
|
+
def start_temperature_polling(self, period=5):
|
|
23
|
+
self.is_temperature_polling = True
|
|
24
|
+
def _poll_temperature():
|
|
25
|
+
while self.is_temperature_polling:
|
|
26
|
+
path = "/heat_get"
|
|
27
|
+
r = self._parent.get_json(path, timeout=0)
|
|
28
|
+
time.sleep(period)
|
|
29
|
+
threading.Thread(target=_poll_temperature).start()
|
|
30
|
+
|
|
31
|
+
def stop_temperature_polling(self):
|
|
32
|
+
self.is_temperature_polling = False
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _callback_temperature_status(self, data):
|
|
36
|
+
''' cast the json in the form:
|
|
37
|
+
{
|
|
38
|
+
"qid": 0,
|
|
39
|
+
"heat": 37.0
|
|
40
|
+
}
|
|
41
|
+
into the position array of the motors '''
|
|
42
|
+
try:
|
|
43
|
+
self._temperature = data["heat"]
|
|
44
|
+
except Exception as e:
|
|
45
|
+
print("Error in _callback_temperature_status: ", e)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def stop_heating(self):
|
|
49
|
+
r = self.set_temperature(active=0)
|
|
50
|
+
return r
|
|
51
|
+
|
|
52
|
+
def set_temperature(self, active=1, Kp=1000, Ki=0.1, Kd=0.1, target=37, timeout=600000000, updaterate=1000):
|
|
53
|
+
# {"task": "/heat_act", "active":1, "Kp":1000, "Ki":0.1, "Kd":0.1, "target":37, "timeout":60000000, "updaterate":1000}
|
|
54
|
+
path = "/heat_act"
|
|
55
|
+
payload = {
|
|
56
|
+
"task": path,
|
|
57
|
+
"active": int(active),
|
|
58
|
+
"Kp": Kp,
|
|
59
|
+
"Ki": Ki,
|
|
60
|
+
"Kd": Kd,
|
|
61
|
+
"target": target,
|
|
62
|
+
"timeout": timeout,
|
|
63
|
+
"updaterate": updaterate
|
|
64
|
+
}
|
|
65
|
+
r = self._parent.post_json(path, payload, getReturn=False)
|
|
66
|
+
return r
|
|
67
|
+
|
|
68
|
+
def get_temperature(self, timeout=0.5, isBlocking=False):
|
|
69
|
+
# {"task": "/heat_get"}
|
|
70
|
+
if isBlocking:
|
|
71
|
+
path = "/heat_get"
|
|
72
|
+
r = self._parent.get_json(path, timeout=timeout)
|
|
73
|
+
try:
|
|
74
|
+
r = r["heat"]
|
|
75
|
+
except:
|
|
76
|
+
r = -273.15
|
|
77
|
+
return r
|
|
78
|
+
else:
|
|
79
|
+
return self._temperature
|
|
80
|
+
|
|
81
|
+
if __name__ == "__main__":
|
|
82
|
+
|
|
83
|
+
#%%
|
|
84
|
+
import uc2rest
|
|
85
|
+
import time
|
|
86
|
+
port = "/dev/cu.SLAB_USBtoUART"
|
|
87
|
+
ESP32 = uc2rest.UC2Client(serialport=port, DEBUG=True)
|
|
88
|
+
ESP32.temperature.set_temperature(active=1, Kp=1000, Ki=0.1, Kd=0.1, target=37, timeout=600000, updaterate=1000)
|
|
89
|
+
for i in range(10):
|
|
90
|
+
print(ESP32.temperature.get_temperature())
|
|
91
|
+
time.sleep(1)
|
|
92
|
+
ESP32.temperature.stop_heating()
|
|
93
|
+
ESP32.close()
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
class Temperature(object):
|
|
2
|
-
|
|
3
|
-
def __init__(self, parent):
|
|
4
|
-
self._parent = parent
|
|
5
|
-
|
|
6
|
-
'''
|
|
7
|
-
##############################################################################################################################
|
|
8
|
-
Temperature Controllers
|
|
9
|
-
##############################################################################################################################
|
|
10
|
-
'''
|
|
11
|
-
|
|
12
|
-
def stop_heating(self):
|
|
13
|
-
r = self.set_temperature(active=0)
|
|
14
|
-
return r
|
|
15
|
-
|
|
16
|
-
def set_temperature(self, active=1, Kp=1000, Ki=0.1, Kd=0.1, target=37, timeout=600000000, updaterate=1000):
|
|
17
|
-
# {"task": "/heat_act", "active":1, "Kp":1000, "Ki":0.1, "Kd":0.1, "target":37, "timeout":60000000, "updaterate":1000}
|
|
18
|
-
path = "/heat_act"
|
|
19
|
-
payload = {
|
|
20
|
-
"task": path,
|
|
21
|
-
"active": int(active),
|
|
22
|
-
"Kp": Kp,
|
|
23
|
-
"Ki": Ki,
|
|
24
|
-
"Kd": Kd,
|
|
25
|
-
"target": target,
|
|
26
|
-
"timeout": timeout,
|
|
27
|
-
"updaterate": updaterate
|
|
28
|
-
}
|
|
29
|
-
r = self._parent.post_json(path, payload, getReturn=False)
|
|
30
|
-
return r
|
|
31
|
-
|
|
32
|
-
def get_temperature(self, timeout=0.5):
|
|
33
|
-
path = "/heat_get"
|
|
34
|
-
r = self._parent.get_json(path, timeout=timeout)
|
|
35
|
-
try:
|
|
36
|
-
r = r["heat"]
|
|
37
|
-
except:
|
|
38
|
-
r = -273.15
|
|
39
|
-
return r
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if __name__ == "__main__":
|
|
43
|
-
|
|
44
|
-
#%%
|
|
45
|
-
import uc2rest
|
|
46
|
-
import time
|
|
47
|
-
port = "/dev/cu.SLAB_USBtoUART"
|
|
48
|
-
ESP32 = uc2rest.UC2Client(serialport=port, DEBUG=True)
|
|
49
|
-
ESP32.temperature.set_temperature(active=1, Kp=1000, Ki=0.1, Kd=0.1, target=37, timeout=600000, updaterate=1000)
|
|
50
|
-
for i in range(10):
|
|
51
|
-
print(ESP32.temperature.get_temperature())
|
|
52
|
-
time.sleep(1)
|
|
53
|
-
ESP32.temperature.stop_heating()
|
|
54
|
-
ESP32.close()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|