UC2-REST 0.2.0.28__tar.gz → 0.2.0.29__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.28 → uc2_rest-0.2.0.29}/PKG-INFO +1 -1
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/UC2_REST.egg-info/PKG-INFO +1 -1
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/UC2_REST.egg-info/SOURCES.txt +2 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/UC2Client.py +9 -1
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/__version__.py +1 -1
- uc2_rest-0.2.0.29/uc2rest/can.py +33 -0
- uc2_rest-0.2.0.29/uc2rest/lcddisplay.py +59 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/motor.py +79 -3
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/mserial.py +15 -13
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/objective.py +1 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/LICENSE +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/README.md +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/UC2_REST.egg-info/dependency_links.txt +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/UC2_REST.egg-info/not-zip-safe +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/UC2_REST.egg-info/requires.txt +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/UC2_REST.egg-info/top_level.txt +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/setup.cfg +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/setup.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/MockSerial.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/__init__.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/analog.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/camera.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/cmdrecorder.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/digitalout.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/galvo.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/gripper.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/home.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/laser.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/ledmatrix.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/logger.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/message.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/modules.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/pid.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/rotator.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/slm.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/state.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/temperature.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/utils.py +0 -0
- {uc2_rest-0.2.0.28 → uc2_rest-0.2.0.29}/uc2rest/wifi.py +0 -0
|
@@ -13,12 +13,14 @@ uc2rest/__init__.py
|
|
|
13
13
|
uc2rest/__version__.py
|
|
14
14
|
uc2rest/analog.py
|
|
15
15
|
uc2rest/camera.py
|
|
16
|
+
uc2rest/can.py
|
|
16
17
|
uc2rest/cmdrecorder.py
|
|
17
18
|
uc2rest/digitalout.py
|
|
18
19
|
uc2rest/galvo.py
|
|
19
20
|
uc2rest/gripper.py
|
|
20
21
|
uc2rest/home.py
|
|
21
22
|
uc2rest/laser.py
|
|
23
|
+
uc2rest/lcddisplay.py
|
|
22
24
|
uc2rest/ledmatrix.py
|
|
23
25
|
uc2rest/logger.py
|
|
24
26
|
uc2rest/message.py
|
|
@@ -9,6 +9,7 @@ from .mserial import Serial
|
|
|
9
9
|
from .mserial import SerialManagerWrapper
|
|
10
10
|
from .galvo import Galvo
|
|
11
11
|
from .ledmatrix import LedMatrix
|
|
12
|
+
from .lcddisplay import LCDDisplay
|
|
12
13
|
from .motor import Motor
|
|
13
14
|
from .gripper import Gripper
|
|
14
15
|
from .home import Home
|
|
@@ -25,6 +26,7 @@ from .logger import Logger
|
|
|
25
26
|
from .cmdrecorder import cmdRecorder
|
|
26
27
|
from .temperature import Temperature
|
|
27
28
|
from .message import Message
|
|
29
|
+
from .can import CAN
|
|
28
30
|
try:
|
|
29
31
|
import requests
|
|
30
32
|
except:
|
|
@@ -88,7 +90,7 @@ class UC2Client(object):
|
|
|
88
90
|
|
|
89
91
|
# import libraries depending on API version
|
|
90
92
|
self.logger.debug("Using API version 2")
|
|
91
|
-
|
|
93
|
+
|
|
92
94
|
# initialize state
|
|
93
95
|
self.state = State(self)
|
|
94
96
|
|
|
@@ -98,9 +100,15 @@ class UC2Client(object):
|
|
|
98
100
|
# initialize LED matrix
|
|
99
101
|
self.led = LedMatrix(self, NLeds=NLeds)
|
|
100
102
|
|
|
103
|
+
# initialize LCD display
|
|
104
|
+
self.lcd = LCDDisplay(self)
|
|
105
|
+
|
|
101
106
|
# initilize motor
|
|
102
107
|
self.motor = Motor(self)
|
|
103
108
|
|
|
109
|
+
# initialize CAN
|
|
110
|
+
self.can = CAN(self)
|
|
111
|
+
|
|
104
112
|
# initialize gripper
|
|
105
113
|
self.gripper = Gripper(self)
|
|
106
114
|
|
|
@@ -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.29"
|
|
10
10
|
__author__ = 'Benedict Diederich'
|
|
11
11
|
__author_email__ = 'benedictdied@gmail.com'
|
|
12
12
|
__license__ = 'GPL v3'
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
class CAN(object):
|
|
2
|
+
def __init__(self, parent):
|
|
3
|
+
"""
|
|
4
|
+
CANController handles sending commands to a remote CAN device via the parent post_json interface.
|
|
5
|
+
|
|
6
|
+
:param parent: Parent object with post_json(path, payload, getReturn, timeout, nResponses)
|
|
7
|
+
"""
|
|
8
|
+
self._parent = parent
|
|
9
|
+
|
|
10
|
+
def reboot_remote(self, qid=1, can_address=0, isBlocking=False, timeout=2):
|
|
11
|
+
"""
|
|
12
|
+
Send a reboot signal to the remote CAN device.
|
|
13
|
+
|
|
14
|
+
:param qid: Query ID for the CAN command (default: 1)
|
|
15
|
+
:param isBlocking: If True, wait for response
|
|
16
|
+
:param timeout: Timeout for the command in seconds
|
|
17
|
+
:param can_address: Address of the CAN device to reboot (0 is master)
|
|
18
|
+
:return: Response from the device
|
|
19
|
+
"""
|
|
20
|
+
path = "/can_act"
|
|
21
|
+
payload = {
|
|
22
|
+
"task": path,
|
|
23
|
+
"restart": int(can_address)
|
|
24
|
+
}
|
|
25
|
+
nResponses = 1 if isBlocking else 0
|
|
26
|
+
# Send the payload to the parent, which handles the actual communication
|
|
27
|
+
return self._parent.post_json(
|
|
28
|
+
path,
|
|
29
|
+
payload,
|
|
30
|
+
getReturn=isBlocking,
|
|
31
|
+
timeout=timeout if isBlocking else 0,
|
|
32
|
+
nResponses=nResponses
|
|
33
|
+
)
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
class LCDDisplay:
|
|
2
|
+
def __init__(self, parent):
|
|
3
|
+
"""
|
|
4
|
+
LCD controller interface.
|
|
5
|
+
Sends JSON commands to draw on the LCD via the parent object.
|
|
6
|
+
"""
|
|
7
|
+
self._parent = parent
|
|
8
|
+
self.path = "/lcd_act"
|
|
9
|
+
self.timeout = 10
|
|
10
|
+
self.color = (255, 255, 255) # Default color
|
|
11
|
+
|
|
12
|
+
def _send(self, action, isBlocking=True, **kwargs):
|
|
13
|
+
payload = {
|
|
14
|
+
"task": self.path,
|
|
15
|
+
"action": action,
|
|
16
|
+
**kwargs
|
|
17
|
+
}
|
|
18
|
+
return self._parent.post_json(self.path, payload, getReturn=isBlocking, nResponses=1, timeout=self.timeout)
|
|
19
|
+
|
|
20
|
+
def set_grating(self, perdiod, r=255, g=255, b=255, horizontal=True):
|
|
21
|
+
# {"task":"/lcd_act", "action":"gratingh","period":3,"r":255,"g":255,"b":255}
|
|
22
|
+
if horizontal:
|
|
23
|
+
return self._send("gratingh", period=perdiod, r=r, g=g, b=b)
|
|
24
|
+
else:
|
|
25
|
+
return self._send("gratingv", period=perdiod, r=r, g=g, b=b)
|
|
26
|
+
|
|
27
|
+
def set_timeout(self, timeout=5):
|
|
28
|
+
"""
|
|
29
|
+
Set the timeout for the LCD display.
|
|
30
|
+
:param timeout: Timeout in seconds.
|
|
31
|
+
"""
|
|
32
|
+
self.timeout = timeout
|
|
33
|
+
|
|
34
|
+
def set_color(self, r=255, g=255, b=255):
|
|
35
|
+
self.color = (r, g, b)
|
|
36
|
+
|
|
37
|
+
def clear(self, r=0, g=0, b=0):
|
|
38
|
+
return self._send("clear", r=r, g=g, b=b)
|
|
39
|
+
|
|
40
|
+
def hline(self, x, y, length, width=1):
|
|
41
|
+
r, g, b = self.color
|
|
42
|
+
# {"task":"/lcd_act","action":"hline","x":0,"y":10,"len":800,"width":1,"r":255,"g":255,"b":0}
|
|
43
|
+
return self._send("hline", x=x, y=y, len=length, width=width, r=r, g=g, b=b)
|
|
44
|
+
|
|
45
|
+
def vline(self, x, y, length, width=1):
|
|
46
|
+
r, g, b = self.color
|
|
47
|
+
return self._send("vline", x=x, y=y, len=length, width=width, r=r, g=g, b=b)
|
|
48
|
+
|
|
49
|
+
def point(self, x, y, diam=1):
|
|
50
|
+
r, g, b = self.color
|
|
51
|
+
return self._send("point", x=x, y=y, diam=diam, r=r, g=g, b=b)
|
|
52
|
+
|
|
53
|
+
def rect(self, x, y, len, width):
|
|
54
|
+
r, g, b = self.color
|
|
55
|
+
return self._send("rect", x=x, y=y, len=len, width=width, r=r, g=g, b=b)
|
|
56
|
+
|
|
57
|
+
def fill(self, x, y, len, width):
|
|
58
|
+
r, g, b = self.color
|
|
59
|
+
return self._send("fill", x=x, y=y, len=len, width=width, r=r, g=g, b=b)
|
|
@@ -42,7 +42,7 @@ class Motor(object):
|
|
|
42
42
|
self.offsetY = 0
|
|
43
43
|
self.offsetZ = 0
|
|
44
44
|
|
|
45
|
-
self.DEFAULT_ACCELERATION =
|
|
45
|
+
self.DEFAULT_ACCELERATION = 1000000
|
|
46
46
|
|
|
47
47
|
self.motorAxisOrder = [0,1,2,3] # motor axis is 1,2,3,0 => X,Y,Z,T # FIXME: Hardcoded
|
|
48
48
|
|
|
@@ -142,6 +142,38 @@ class Motor(object):
|
|
|
142
142
|
def setMotorAxisOrder(self, order=[0,1,2,3]):
|
|
143
143
|
self.motorAxisOrder = order
|
|
144
144
|
|
|
145
|
+
# { "task": "/motor_act", "focusscan": { "zStart": 0, "zStep": 50, "nZ": 20, "tPre": 80, "tTrig": 20, "tPost": 0, "led": 0, "illumination": [0, 255, 0, 0], "speed": 20000, "acceleration": 1000000, "qid": 42 }}
|
|
146
|
+
def startFocusScanning(self, zStart=0, zStep=50, nZ=20, tPre=80, tTrig=20, tPost=0, led=0, illumination=[0, 255, 0, 0], speed=20000, acceleration=1000000, qid=42):
|
|
147
|
+
path = "/motor_act"
|
|
148
|
+
payload = {
|
|
149
|
+
"task": path,
|
|
150
|
+
"focusscan": {
|
|
151
|
+
"zStart": zStart,
|
|
152
|
+
"zStep": zStep,
|
|
153
|
+
"nZ": nZ,
|
|
154
|
+
"tPre": tPre,
|
|
155
|
+
"tTrig": tTrig,
|
|
156
|
+
"tPost": tPost,
|
|
157
|
+
"led": led,
|
|
158
|
+
"illumination": illumination,
|
|
159
|
+
"speed": speed,
|
|
160
|
+
"acceleration": acceleration,
|
|
161
|
+
"qid": qid
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
r = self._parent.post_json(path, payload)
|
|
165
|
+
return r
|
|
166
|
+
|
|
167
|
+
def stopFocusScanning(self):
|
|
168
|
+
path = "/motor_act"
|
|
169
|
+
payload = {
|
|
170
|
+
"task": path,
|
|
171
|
+
"focusscan": {
|
|
172
|
+
"stopped": 1
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
r = self._parent.post_json(path, payload)
|
|
176
|
+
return r
|
|
145
177
|
'''################################################################################################################################################
|
|
146
178
|
HIGH-LEVEL Functions that rely on basic REST-API functions
|
|
147
179
|
################################################################################################################################################'''
|
|
@@ -423,7 +455,7 @@ class Motor(object):
|
|
|
423
455
|
self.currentDirection[iMotor] = np.sign(steps[iMotor])
|
|
424
456
|
if self.lastDirection[iMotor] != self.currentDirection[iMotor]:
|
|
425
457
|
# we want to overshoot a bit
|
|
426
|
-
steps[iMotor] = steps[iMotor] +
|
|
458
|
+
steps[iMotor] = steps[iMotor] + self.currentDirection[iMotor]*self.backlash[iMotor]
|
|
427
459
|
|
|
428
460
|
|
|
429
461
|
if isAbsoluteArray[iMotor]:
|
|
@@ -459,6 +491,10 @@ class Motor(object):
|
|
|
459
491
|
motorPropList = []
|
|
460
492
|
for iMotor in range(4):
|
|
461
493
|
if isAbsoluteArray[iMotor] or abs(steps[iMotor])>0:
|
|
494
|
+
# if we are absolute and the last target position is the same as the current one, we don't need to move
|
|
495
|
+
if isAbsoluteArray[iMotor] and abs(steps[iMotor] - self.currentPosition[iMotor])<1:
|
|
496
|
+
if self._parent.serial.DEBUG: self._parent.logger.debug(f"Motor {iMotor} is already at target position {steps[iMotor]}")
|
|
497
|
+
continue
|
|
462
498
|
motorProp = { "stepperid": int(self.motorAxisOrder[iMotor]),
|
|
463
499
|
"position": int(steps[iMotor]),
|
|
464
500
|
"speed": int(speed[iMotor]),
|
|
@@ -471,7 +507,8 @@ class Motor(object):
|
|
|
471
507
|
else:
|
|
472
508
|
motorProp["accel"] = self.DEFAULT_ACCELERATION
|
|
473
509
|
motorPropList.append(motorProp)
|
|
474
|
-
|
|
510
|
+
if len(motorPropList)==0:
|
|
511
|
+
return "{'return':-1}"
|
|
475
512
|
path = "/motor_act"
|
|
476
513
|
payload = {
|
|
477
514
|
"task":path,
|
|
@@ -698,7 +735,46 @@ class Motor(object):
|
|
|
698
735
|
|
|
699
736
|
def set_direction(self, axis=1, sign=1, timeout=1):
|
|
700
737
|
return False
|
|
738
|
+
|
|
739
|
+
def stop_stage_scanning(self):
|
|
740
|
+
# {"task":"/motor_act", "stagescan":{ "stopped":1 }}
|
|
741
|
+
path = "/motor_act"
|
|
742
|
+
payload = {
|
|
743
|
+
"task": path,
|
|
744
|
+
"stagescan": {
|
|
745
|
+
"stopped": 1
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
r = self._parent.post_json(path, payload)
|
|
749
|
+
return r
|
|
750
|
+
|
|
751
|
+
|
|
701
752
|
|
|
753
|
+
def start_stage_scanning(self, xstart=0, xstep=1000, nx=20, ystart=0, ystep=1000, ny=10, tsettle=5, tExposure=50, illumination=(0,0,0,0), led=0, speed=20000, acceleration=None):
|
|
754
|
+
# {"task": "/motor_act", "stagescan": {"xStart": 0, "yStart": 0, "xStep": 500, "yStep": 500, "nX": 10, "nY": 10, "tPre": 50, "tPost": 50, "illumination": [0, 1, 0, 0], "led": 255}}
|
|
755
|
+
if acceleration is None:
|
|
756
|
+
acceleration = self.DEFAULT_ACCELERATION
|
|
757
|
+
path = "/motor_act"
|
|
758
|
+
payload = {
|
|
759
|
+
"task": path,
|
|
760
|
+
"stagescan": {
|
|
761
|
+
"xStart": xstart / self.stepSizeX,
|
|
762
|
+
"xStep": xstep / self.stepSizeX,
|
|
763
|
+
"nX": nx,
|
|
764
|
+
"yStart": ystart / self.stepSizeY,
|
|
765
|
+
"yStep": ystep / self.stepSizeY,
|
|
766
|
+
"nY": ny,
|
|
767
|
+
"tPre": tsettle,
|
|
768
|
+
"tPost": tExposure,
|
|
769
|
+
"illumination": illumination,
|
|
770
|
+
"led": led,
|
|
771
|
+
"accel": self.DEFAULT_ACCELERATION, # default acceleration
|
|
772
|
+
"speed": speed, # default speed
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
r = self._parent.post_json(path, payload)
|
|
776
|
+
return r
|
|
777
|
+
|
|
702
778
|
def set_tmc_parameters(self, axis=0, msteps=None, rms_current=None, stall_value=None, sgthrs=None, semin=None, semax=None, blank_time=None, toff=None, timeout=1):
|
|
703
779
|
''' set the TMC parameters for a specific axis
|
|
704
780
|
msteps: microsteps
|
|
@@ -33,7 +33,7 @@ class Serial:
|
|
|
33
33
|
self._logger.addHandler(logging.StreamHandler())
|
|
34
34
|
else:
|
|
35
35
|
self._logger = self._parent.logger
|
|
36
|
-
|
|
36
|
+
self.identifier_counter = 0
|
|
37
37
|
self.identity = identity
|
|
38
38
|
self.DEBUG = DEBUG
|
|
39
39
|
self.is_connected = False
|
|
@@ -228,7 +228,8 @@ class Serial:
|
|
|
228
228
|
try:
|
|
229
229
|
mLine = serialdevice.readline()
|
|
230
230
|
if self.cmdReadCallBackFct is not None and mLine!=b'' and mLine != b'\n' :
|
|
231
|
-
self.cmdReadCallBackFct(mLine)
|
|
231
|
+
try:self.cmdReadCallBackFct(mLine)
|
|
232
|
+
except:pass
|
|
232
233
|
return mLine
|
|
233
234
|
except SerialException as e:
|
|
234
235
|
self._logger.error("Failed to read the line in serial: "+str(e))
|
|
@@ -305,7 +306,7 @@ class Serial:
|
|
|
305
306
|
def _process_commands(self):
|
|
306
307
|
buffer = ""
|
|
307
308
|
reading_json = False
|
|
308
|
-
currentIdentifier =
|
|
309
|
+
currentIdentifier = 0
|
|
309
310
|
nLineCountTimeout = 50 # maximum number of lines read before timeout
|
|
310
311
|
lineCounter = 0
|
|
311
312
|
nFailedCommands = 0
|
|
@@ -339,19 +340,20 @@ class Serial:
|
|
|
339
340
|
line = ""
|
|
340
341
|
|
|
341
342
|
# if we have a problem with the serial connection, we need to reconnect
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
self.
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
343
|
+
if nFailedCommands>5:
|
|
344
|
+
for i in range(4):
|
|
345
|
+
nFailedCommands=0
|
|
346
|
+
if self.reconnect():
|
|
347
|
+
self._logger.debug("Reconnected to the serial device")
|
|
348
|
+
break
|
|
349
|
+
else:
|
|
350
|
+
self._logger.debug("Failed to reconnect to the serial device")
|
|
351
|
+
time.sleep(1)
|
|
350
352
|
|
|
351
353
|
if line == "++":
|
|
352
354
|
reading_json = True
|
|
353
355
|
continue
|
|
354
|
-
elif line.find("error") != -1:
|
|
356
|
+
elif line.find("error") != -1 and currentIdentifier is not None:
|
|
355
357
|
# if we have an error, we need to reset the last command
|
|
356
358
|
self._logger.debug("Error - last command did not match the firmware: "+str(self.commands[currentIdentifier]))
|
|
357
359
|
self.resetLastCommand = True
|
|
@@ -365,7 +367,7 @@ class Serial:
|
|
|
365
367
|
reading_json = False
|
|
366
368
|
try:
|
|
367
369
|
json_response = json.loads(buffer)
|
|
368
|
-
self._logger.debug("[ProcessCommands]: "+str(json_response))
|
|
370
|
+
if self.DEBUG: self._logger.debug("[ProcessCommands]: "+str(json_response))
|
|
369
371
|
if len(self.callBackList) > 0:
|
|
370
372
|
for callback in self.callBackList:
|
|
371
373
|
# check if json has key
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|