UC2-REST 0.2.0.22__tar.gz → 0.2.0.24__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.
Files changed (40) hide show
  1. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/PKG-INFO +3 -2
  2. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/UC2_REST.egg-info/PKG-INFO +3 -2
  3. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/UC2_REST.egg-info/SOURCES.txt +3 -0
  4. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/UC2Client.py +10 -2
  5. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/__version__.py +1 -1
  6. uc2_rest-0.2.0.24/uc2rest/gripper.py +107 -0
  7. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/home.py +6 -6
  8. uc2_rest-0.2.0.24/uc2rest/ledmatrix.py +324 -0
  9. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/motor.py +134 -37
  10. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/mserial.py +135 -45
  11. uc2_rest-0.2.0.24/uc2rest/objective.py +230 -0
  12. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/LICENSE +0 -0
  13. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/README.md +0 -0
  14. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/UC2_REST.egg-info/dependency_links.txt +0 -0
  15. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/UC2_REST.egg-info/not-zip-safe +0 -0
  16. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/UC2_REST.egg-info/requires.txt +0 -0
  17. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/UC2_REST.egg-info/top_level.txt +0 -0
  18. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/setup.cfg +0 -0
  19. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/setup.py +0 -0
  20. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/MockSerial.py +0 -0
  21. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/__init__.py +0 -0
  22. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/analog.py +0 -0
  23. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/camera.py +0 -0
  24. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/cmdrecorder.py +0 -0
  25. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/config.py +0 -0
  26. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/config_.py +0 -0
  27. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/digitalout.py +0 -0
  28. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/galvo.py +0 -0
  29. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/laser.py +0 -0
  30. /uc2_rest-0.2.0.22/uc2rest/ledmatrix.py → /uc2_rest-0.2.0.24/uc2rest/ledmatrix_.py +0 -0
  31. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/logger.py +0 -0
  32. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/message.py +0 -0
  33. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/modules.py +0 -0
  34. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/pid.py +0 -0
  35. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/rotator.py +0 -0
  36. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/slm.py +0 -0
  37. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/state.py +0 -0
  38. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/temperature.py +0 -0
  39. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/utils.py +0 -0
  40. {uc2_rest-0.2.0.22 → uc2_rest-0.2.0.24}/uc2rest/wifi.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: UC2-REST
3
- Version: 0.2.0.22
3
+ Version: 0.2.0.24
4
4
  Summary: This pacage will help you to drive the ESP32-driven microscopy control modules from UC2
5
5
  Home-page: https://github.com/openUC2/UC2-REST
6
6
  Author: Benedict Diederich
@@ -24,6 +24,7 @@ Dynamic: description-content-type
24
24
  Dynamic: home-page
25
25
  Dynamic: keywords
26
26
  Dynamic: license
27
+ Dynamic: license-file
27
28
  Dynamic: requires-dist
28
29
  Dynamic: requires-python
29
30
  Dynamic: summary
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: UC2-REST
3
- Version: 0.2.0.22
3
+ Version: 0.2.0.24
4
4
  Summary: This pacage will help you to drive the ESP32-driven microscopy control modules from UC2
5
5
  Home-page: https://github.com/openUC2/UC2-REST
6
6
  Author: Benedict Diederich
@@ -24,6 +24,7 @@ Dynamic: description-content-type
24
24
  Dynamic: home-page
25
25
  Dynamic: keywords
26
26
  Dynamic: license
27
+ Dynamic: license-file
27
28
  Dynamic: requires-dist
28
29
  Dynamic: requires-python
29
30
  Dynamic: summary
@@ -18,14 +18,17 @@ uc2rest/config.py
18
18
  uc2rest/config_.py
19
19
  uc2rest/digitalout.py
20
20
  uc2rest/galvo.py
21
+ uc2rest/gripper.py
21
22
  uc2rest/home.py
22
23
  uc2rest/laser.py
23
24
  uc2rest/ledmatrix.py
25
+ uc2rest/ledmatrix_.py
24
26
  uc2rest/logger.py
25
27
  uc2rest/message.py
26
28
  uc2rest/modules.py
27
29
  uc2rest/motor.py
28
30
  uc2rest/mserial.py
31
+ uc2rest/objective.py
29
32
  uc2rest/pid.py
30
33
  uc2rest/rotator.py
31
34
  uc2rest/slm.py
@@ -11,7 +11,9 @@ from .galvo import Galvo
11
11
  from .config import config
12
12
  from .ledmatrix import LedMatrix
13
13
  from .motor import Motor
14
+ from .gripper import Gripper
14
15
  from .home import Home
16
+ from .objective import Objective
15
17
  from .state import State
16
18
  from .laser import Laser
17
19
  from .wifi import Wifi
@@ -41,7 +43,7 @@ class UC2Client(object):
41
43
  # BAUDRATE = 500000
42
44
  BAUDRATE = 500000
43
45
 
44
- def __init__(self, host=None, port=31950, serialport=None, identity="UC2_Feather", baudrate=BAUDRATE, NLeds=64, SerialManager=None, DEBUG=False, logger=None):
46
+ def __init__(self, host=None, port=31950, serialport=None, identity="UC2_Feather", baudrate=BAUDRATE, NLeds=64, SerialManager=None, DEBUG=False, logger=None, skipFirmwareCheck=False):
45
47
  '''
46
48
  This client connects to the UC2-REST microcontroller that can be found here
47
49
  https://github.com/openUC2/UC2-REST
@@ -64,7 +66,7 @@ class UC2Client(object):
64
66
  # initialize communication channel (# connect to wifi or usb)
65
67
  if serialport is not None:
66
68
  # use USB connection
67
- self.serial = Serial(serialport, baudrate, parent=self, identity=identity, DEBUG=DEBUG)
69
+ self.serial = Serial(serialport, baudrate, parent=self, identity=identity, DEBUG=DEBUG, skipFirmwareCheck=skipFirmwareCheck)
68
70
  self.is_serial = True
69
71
  self.is_connected = self.serial.is_connected
70
72
  self.serial.DEBUG = DEBUG
@@ -109,12 +111,18 @@ class UC2Client(object):
109
111
  # initilize motor
110
112
  self.motor = Motor(self)
111
113
 
114
+ # initialize gripper
115
+ self.gripper = Gripper(self)
116
+
112
117
  # initialize rotator
113
118
  self.rotator = Rotator(self)
114
119
 
115
120
  # initiliaze homing
116
121
  self.home = Home(self)
117
122
 
123
+ # initialize objective
124
+ self.objective = Objective(self)
125
+
118
126
  # initialize temperature
119
127
  self.temperature = Temperature(self)
120
128
 
@@ -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.22"
9
+ __version__ = "v0.2.0.24"
10
10
  __author__ = 'Benedict Diederich'
11
11
  __author_email__ = 'benedictdied@gmail.com'
12
12
  __license__ = 'GPL v3'
@@ -0,0 +1,107 @@
1
+ import time
2
+ import json
3
+
4
+ class Gripper(object):
5
+ """
6
+ Example Python class for controlling a gripper servo via JSON commands
7
+ to the MCU, similar in style to the Objective class provided.
8
+ """
9
+
10
+ def __init__(self, parent):
11
+ """
12
+ parent: an object that handles the low-level post_json(path, payload, getReturn, timeout, nResponses)
13
+ similar to the 'Home' or 'Objective' parent in the template.
14
+ """
15
+ self._parent = parent
16
+ self.timeout = 10 # default timeout for blocking commands
17
+ # Default angles
18
+ self.close_angle = 0
19
+ self.open_angle = 180
20
+
21
+ def close(self, isBlocking=False):
22
+ """
23
+ Closes the gripper to close_angle (0° by default).
24
+ Sends {"task":"/gripper_act","action":"close"} over Serial/JSON.
25
+ """
26
+ path = "/gripper_act"
27
+ payload = {
28
+ "task": path,
29
+ "action": "close"
30
+ }
31
+ # Possibly wait for the MCU response
32
+ nResponses = 1 if isBlocking else 0
33
+ r = self._parent.post_json(
34
+ path,
35
+ payload,
36
+ getReturn=isBlocking,
37
+ timeout=self.timeout if isBlocking else 0,
38
+ nResponses=nResponses
39
+ )
40
+ return r
41
+
42
+ def open(self, isBlocking=False):
43
+ """
44
+ Opens the gripper to open_angle (180° by default).
45
+ Sends {"task":"/gripper_act","action":"open"}.
46
+ """
47
+ path = "/gripper_act"
48
+ payload = {
49
+ "task": path,
50
+ "action": "open"
51
+ }
52
+ nResponses = 1 if isBlocking else 0
53
+ r = self._parent.post_json(
54
+ path,
55
+ payload,
56
+ getReturn=isBlocking,
57
+ timeout=self.timeout if isBlocking else 0,
58
+ nResponses=nResponses
59
+ )
60
+ return r
61
+
62
+ def setAngle(self, angle, isBlocking=False):
63
+ """
64
+ Moves the gripper servo to an arbitrary angle (0–180).
65
+ Sends {"task":"/gripper_act","action":"degree","value":<angle>}.
66
+ """
67
+ path = "/gripper_act"
68
+ payload = {
69
+ "task": path,
70
+ "action": "degree",
71
+ "value": angle
72
+ }
73
+ nResponses = 1 if isBlocking else 0
74
+ r = self._parent.post_json(
75
+ path,
76
+ payload,
77
+ getReturn=isBlocking,
78
+ timeout=self.timeout if isBlocking else 0,
79
+ nResponses=nResponses
80
+ )
81
+ return r
82
+
83
+ def getstatus(self):
84
+ """
85
+ Query the current gripper status.
86
+ Expects MCU to return something like:
87
+ {
88
+ "gripper":{
89
+ "pos": 90,
90
+ "isOpen": 0 or 1,
91
+ "state": 1,
92
+ "isRunning": 0
93
+ }
94
+ }
95
+ """
96
+ path = "/gripper_get"
97
+ payload = {"task": path}
98
+ r = self._parent.post_json(path, payload, timeout=1)
99
+
100
+ try:
101
+ # The last item in r is assumed to contain the "gripper" field
102
+ status = r[-1]["gripper"]
103
+ except:
104
+ # Fallback if parsing fails
105
+ status = {"pos": 0, "isOpen": None, "state": 0, "isRunning": 0}
106
+
107
+ return status
@@ -15,7 +15,7 @@ class Home(object):
15
15
  # axis = 1 corresponds to 'X'
16
16
  axis = 1
17
17
  self.home(axis=axis,
18
- timeout=timeout,
18
+ endstoptimeout=timeout,
19
19
  speed = speed,
20
20
  direction = direction,
21
21
  endposrelease=endposrelease,
@@ -26,7 +26,7 @@ class Home(object):
26
26
  # axis = 2 corresponds to 'Y'
27
27
  axis = 2
28
28
  self.home(axis=axis,
29
- timeout=timeout,
29
+ endstoptimeout=timeout,
30
30
  speed = speed,
31
31
  direction = direction,
32
32
  endposrelease=endposrelease,
@@ -37,7 +37,7 @@ class Home(object):
37
37
  # axisa = 3 corresponds to 'Z'
38
38
  axis = 3
39
39
  self.home(axis=axis,
40
- timeout=timeout,
40
+ endstoptimeout=timeout,
41
41
  speed = speed,
42
42
  direction = direction,
43
43
  endposrelease=endposrelease,
@@ -48,14 +48,14 @@ class Home(object):
48
48
  # axis = 0 corresponds to 'A'
49
49
  axis = 0
50
50
  self.home(axis=axis,
51
- timeout=timeout,
51
+ endstoptimeout=timeout,
52
52
  speed = speed,
53
53
  direction = direction,
54
54
  endposrelease=endposrelease,
55
55
  endstoppolarity=endstoppolarity,
56
56
  isBlocking=isBlocking)
57
57
 
58
- def home(self, axis=None, timeout=None, speed=None, direction=None, endposrelease=None, endstoppolarity=None, isBlocking=False):
58
+ def home(self, axis=None, timeout=None, speed=None, direction=None, endposrelease=None, endstoppolarity=None, endstoptimeout=10000, isBlocking=False):
59
59
  '''
60
60
  axis = 0,1,2,3 or 'A, 'X','Y','Z'
61
61
  timeout => when to stop homing (it's a while loop on the MCU)
@@ -88,7 +88,7 @@ class Home(object):
88
88
  "steppers": [
89
89
  {
90
90
  "stepperid": axis,
91
- "timeout":timeout,
91
+ "timeout":endstoptimeout,
92
92
  "speed":abs(speed),
93
93
  "direction":direction,
94
94
  "endstoppolarity":endstoppolarity
@@ -0,0 +1,324 @@
1
+ import numpy as np
2
+
3
+ gTimeout = 2
4
+
5
+ class LedMatrix(object):
6
+ def __init__(self, parent, NLeds=64):
7
+ """
8
+ This class handles sending JSON commands for controlling a NeoPixel or LED matrix device.
9
+ The 'parent' is assumed to be an object providing post_json(...) and get_json(...) methods.
10
+ """
11
+ self.NLeds = NLeds
12
+ self.Nx = self.Ny = int(np.sqrt(NLeds)) if NLeds > 0 else 8
13
+
14
+ # We assume the pattern is binary (0 or 1) for an NxN grid, stored in ledpattern NxN or flattened.
15
+ # We store an RGB for each LED if needed. -1 indicates "unset" or no color assigned.
16
+ self.ledpattern = np.ones((self.NLeds, 3)) * -1
17
+
18
+ self._parent = parent # must have post_json() etc.
19
+ self.timeout = 1
20
+ self.intensity = (255, 255, 255)
21
+
22
+ # Maps textual modes to an integer, used for backward compatibility
23
+ self.ledArrayModes = {
24
+ "array": 0,
25
+ "full": 1,
26
+ "single": 2,
27
+ "off": 3,
28
+ "left": 4,
29
+ "right": 5,
30
+ "top": 6,
31
+ "bottom": 7,
32
+ "multi": 8
33
+ }
34
+
35
+ self.currentLedArrayMode = "full"
36
+
37
+ ######################################################################################################
38
+ # BASE / LEGACY METHODS
39
+ ######################################################################################################
40
+
41
+ def send_LEDMatrix_array(self, led_pattern, getReturn=True, timeout=gTimeout):
42
+ """
43
+ Send an LED array pattern e.g. a list of { id, r, g, b } or a NumPy array shape (N,3).
44
+ Produces JSON:
45
+ {
46
+ "task": "/ledarr_act",
47
+ "led": {
48
+ "action": "array",
49
+ "LEDArrMode": 0,
50
+ "led_array": [
51
+ {"id":0,"r":...,"g":...,"b":...},
52
+ ...
53
+ ]
54
+ }
55
+ }
56
+ """
57
+ path = "/ledarr_act"
58
+
59
+ # If led_pattern is a NumPy array, convert it to a list of dict
60
+ if not isinstance(led_pattern, list):
61
+ if len(led_pattern.shape) == 3:
62
+ # flatten 3D into 2D
63
+ led_pattern = np.reshape(led_pattern, (led_pattern.shape[0]*led_pattern.shape[1], led_pattern.shape[2]))
64
+
65
+ pattern_list = []
66
+ for i in range(led_pattern.shape[0]):
67
+ pattern_list.append({
68
+ "id": i,
69
+ "r": int(led_pattern[i, 0]),
70
+ "g": int(led_pattern[i, 1]),
71
+ "b": int(led_pattern[i, 2])
72
+ })
73
+ else:
74
+ pattern_list = led_pattern
75
+
76
+ payload = {
77
+ "task": path,
78
+ "qid": 0, # or fill in dynamically if you like
79
+ "led": {
80
+ "action": "array",
81
+ "LEDArrMode": self.ledArrayModes["array"],
82
+ "led_array": pattern_list
83
+ }
84
+ }
85
+
86
+ r = self._parent.post_json(path, payload, getReturn=getReturn, timeout=timeout)
87
+ if not getReturn or timeout == 0:
88
+ r = {"success": 1}
89
+ self.currentLedArrayMode = "array"
90
+ return r
91
+
92
+ def send_LEDMatrix_full(self, intensity=(255, 255, 255), getReturn=True, timeout=gTimeout):
93
+ """
94
+ Fill all LEDs with the same (r,g,b).
95
+ Creates JSON with: "action": "fill"
96
+ """
97
+ path = "/ledarr_act"
98
+ payload = {
99
+ "task": path,
100
+ "qid": 0,
101
+ "led": {
102
+ "action": "fill",
103
+ "LEDArrMode": self.ledArrayModes["full"],
104
+ "r": int(intensity[0]),
105
+ "g": int(intensity[1]),
106
+ "b": int(intensity[2])
107
+ }
108
+ }
109
+
110
+ r = self._parent.post_json(path, payload, getReturn=getReturn, timeout=timeout)
111
+ if not getReturn or timeout == 0:
112
+ r = {"success": 1}
113
+ self.currentLedArrayMode = "full"
114
+ return r
115
+
116
+ def send_LEDMatrix_single(self, indexled=0, intensity=(255, 255, 255), getReturn=True, timeout=gTimeout):
117
+ """
118
+ Update only a single LED with color (r,g,b).
119
+ Creates JSON: "action":"single"
120
+ """
121
+ path = "/ledarr_act"
122
+ payload = {
123
+ "task": path,
124
+ "qid": 0,
125
+ "led": {
126
+ "action": "single",
127
+ "LEDArrMode": self.ledArrayModes["single"],
128
+ "ledIndex": int(indexled),
129
+ "r": int(intensity[0]),
130
+ "g": int(intensity[1]),
131
+ "b": int(intensity[2])
132
+ }
133
+ }
134
+
135
+ r = self._parent.post_json(path, payload, getReturn=getReturn, timeout=timeout)
136
+ if not getReturn or timeout == 0:
137
+ r = {"success": 1}
138
+ self.currentLedArrayMode = "single"
139
+ return r
140
+
141
+ def get_LEDMatrix(self, timeout=gTimeout):
142
+ """
143
+ Request info from the device about pin/LED count, etc.
144
+ Usually the device responds with JSON containing these details.
145
+ """
146
+ path = "/ledarr_get"
147
+ payload = {"task": path}
148
+ r = self._parent.post_json(path, payload, getReturn=True, timeout=timeout)
149
+ return r
150
+
151
+ def setSingle(self, indexled, state):
152
+ """
153
+ High-level usage: set a single LED's "state" (0 or 1), then send it with intensity scaling.
154
+ """
155
+ ix = indexled // self.Nx
156
+ iy = indexled % self.Nx
157
+ self.ledpattern[indexled] = (state, state, state)
158
+ # If your wiring is zig-zag or reversed, you may need to adapt index
159
+ if ix % 2 != 0:
160
+ indexled = (ix * self.Nx) + (self.Ny - iy - 1)
161
+
162
+ intensityScaled = np.array(state) * np.array(self.intensity)
163
+ self.send_LEDMatrix_single(indexled=indexled, intensity=intensityScaled, timeout=self.timeout)
164
+ return self.ledpattern
165
+
166
+ def setAll(self, state: int, intensity:int =None, getReturn=True):
167
+ """
168
+ Turn on or off all LEDs at a certain intensity.
169
+ If state is a boolean array or a single boolean, we set them all.
170
+ """
171
+ onval = np.sum(state) > 0
172
+ if intensity is not None:
173
+ self.intensity = intensity
174
+ intensity2display = np.array(self.intensity) * onval
175
+ self.send_LEDMatrix_full(intensity=intensity2display, getReturn=getReturn)
176
+ self.ledpattern = onval * np.ones((self.NLeds, 3))
177
+ return self.ledpattern
178
+
179
+ def setIntensity(self, intensity:int, getReturn:bool=True):
180
+ self.intensity = intensity
181
+ self.setPattern(getReturn=getReturn)
182
+
183
+ def setPattern(self, getReturn:bool=True, ledpattern=None):
184
+ """
185
+ If ledpattern is provided, store it, then send to device.
186
+ If the entire pattern is "on", we do a 'full' fill for speed,
187
+ otherwise we do 'array' updates for each LED.
188
+ """
189
+ if ledpattern is not None:
190
+ self.ledpattern = ledpattern
191
+ pattern2send = (self.ledpattern >= 1) * self.intensity
192
+
193
+ if np.sum(self.ledpattern, 0)[0] == self.ledpattern.shape[0]:
194
+ # All on => just do a fill
195
+ self.send_LEDMatrix_full(pattern2send[0, :], getReturn=getReturn)
196
+ else:
197
+ # partial => send an array of per-LED
198
+ self.send_LEDMatrix_array(pattern2send, getReturn=getReturn)
199
+ return self.ledpattern
200
+
201
+ def getPattern(self):
202
+ return self.ledpattern
203
+
204
+ def set_led(self, colour=(0, 0, 0)):
205
+ """
206
+ (Legacy) Possibly sets a single color.
207
+ Demo only - not used in the new command style.
208
+ """
209
+ path = "/led"
210
+ payload = {"r": colour[0], "g": colour[1], "b": colour[2]}
211
+ r = self._parent.post_json(path, payload)
212
+ return r
213
+
214
+ def get_ledpin(self):
215
+ """
216
+ Another legacy method that might do a GET request.
217
+ """
218
+ path = "/ledarr_get"
219
+ r = self._parent.get_json(path, getReturn=True, timeout=1)
220
+ return r
221
+
222
+ ######################################################################################################
223
+ # NEW METHODS FOR "OFF", "RINGS", "CIRCLES", "HALVES", etc.
224
+ ######################################################################################################
225
+ def send_LEDMatrix_off(self, getReturn=True, timeout=gTimeout):
226
+ """
227
+ Turn all LEDs off.
228
+ JSON: "action":"off"
229
+ """
230
+ path = "/ledarr_act"
231
+ payload = {
232
+ "task": path,
233
+ "qid": 0,
234
+ "led": {
235
+ "action": "off"
236
+ }
237
+ }
238
+ r = self._parent.post_json(path, payload, getReturn=getReturn, timeout=timeout)
239
+ return r
240
+
241
+ def send_LEDMatrix_halves(self, region="left", intensity=(255,255,255), getReturn=True, timeout=gTimeout):
242
+ """
243
+ Light only "left"/"right"/"top"/"bottom" half in color, rest is dark.
244
+ JSON: "action":"halves", "region": <string>
245
+ """
246
+ if type(intensity)==int:
247
+ intensity = (intensity, intensity, intensity)
248
+ path = "/ledarr_act"
249
+ payload = {
250
+ "task": path,
251
+ "qid": 0,
252
+ "led": {
253
+ "action": "halves",
254
+ "region": region,
255
+ "r": int(intensity[0]),
256
+ "g": int(intensity[1]),
257
+ "b": int(intensity[2])
258
+ }
259
+ }
260
+ r = self._parent.post_json(path, payload, getReturn=getReturn, timeout=timeout)
261
+ return r
262
+
263
+ def send_LEDMatrix_rings(self, radius=4, intensity=(255,255,255), getReturn=True, timeout=gTimeout):
264
+ """
265
+ Draw a ring of radius N. Often done by filling the circle and carving out center to make it hollow.
266
+ JSON: "action":"rings", "radius": <int>
267
+ """
268
+ if type(intensity)==int:
269
+ intensity = (intensity, intensity, intensity)
270
+ path = "/ledarr_act"
271
+ payload = {
272
+ "task": path,
273
+ "qid": 0,
274
+ "led": {
275
+ "action": "rings",
276
+ "radius": radius,
277
+ "r": int(intensity[0]),
278
+ "g": int(intensity[1]),
279
+ "b": int(intensity[2])
280
+ }
281
+ }
282
+ r = self._parent.post_json(path, payload, getReturn=getReturn, timeout=timeout)
283
+ return r
284
+
285
+ def send_LEDMatrix_circles(self, radius=4, intensity=(255,255,255), getReturn=True, timeout=gTimeout):
286
+ """
287
+ Draw a filled circle of radius N in color.
288
+ JSON: "action":"circles", "radius": <int>
289
+ """
290
+ if type(intensity)==int:
291
+ intensity = (intensity, intensity, intensity)
292
+ path = "/ledarr_act"
293
+ payload = {
294
+ "task": path,
295
+ "qid": 0,
296
+ "led": {
297
+ "action": "circles",
298
+ "radius": radius,
299
+ "r": int(intensity[0]),
300
+ "g": int(intensity[1]),
301
+ "b": int(intensity[2])
302
+ }
303
+ }
304
+ r = self._parent.post_json(path, payload, getReturn=getReturn, timeout=timeout)
305
+ return r
306
+
307
+ def send_LEDMatrix_status(self, status="idle"):
308
+ """
309
+ Set the status of the LED matrix to "idle" or "busy".
310
+ JSON: "action":"status", "status": <string>
311
+ """
312
+ if status not in ["error", "idle", "warn", "success", "busy", "rainbow"]:
313
+ status = "idle"
314
+ path = "/ledarr_act"
315
+ payload = {
316
+ "task": path,
317
+ "qid": 0,
318
+ "led": {
319
+ "action": "status",
320
+ "status": status
321
+ }
322
+ }
323
+ r = self._parent.post_json(path, payload)
324
+ return r