micrOSDevToolKit 2.17.2__py3-none-any.whl → 2.20.0__py3-none-any.whl

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.

Potentially problematic release.


This version of micrOSDevToolKit might be problematic. Click here for more details.

Files changed (73) hide show
  1. micrOS/release_info/micrOS_ReleaseInfo/system_analysis_sum.json +29 -33
  2. micrOS/source/Common.py +5 -13
  3. micrOS/source/Config.py +2 -2
  4. micrOS/source/Espnow.py +32 -18
  5. micrOS/source/InterConnect.py +106 -31
  6. micrOS/source/Server.py +2 -3
  7. micrOS/source/Shell.py +1 -1
  8. micrOS/source/Tasks.py +66 -62
  9. micrOS/source/micrOSloader.py +1 -1
  10. micrOS/source/modules/LM_buzzer.py +1 -4
  11. micrOS/source/modules/LM_cct.py +2 -4
  12. micrOS/source/modules/LM_dimmer.py +1 -2
  13. micrOS/source/modules/LM_distance.py +1 -3
  14. micrOS/source/modules/LM_espnow.py +18 -1
  15. micrOS/source/modules/LM_i2s_mic.py +1 -2
  16. micrOS/source/modules/LM_keychain.py +1 -2
  17. micrOS/source/modules/LM_light_sensor.py +1 -4
  18. micrOS/source/modules/LM_mqtt_client.py +13 -10
  19. micrOS/source/modules/LM_neoeffects.py +1 -1
  20. micrOS/source/modules/LM_neomatrix.py +1 -1
  21. micrOS/source/modules/LM_neopixel.py +1 -2
  22. micrOS/source/modules/LM_oled_ui.py +4 -3
  23. micrOS/source/modules/LM_oledui.py +6 -7
  24. micrOS/source/modules/LM_presence.py +1 -2
  25. micrOS/source/modules/LM_rest.py +1 -2
  26. micrOS/source/modules/LM_rgb.py +1 -2
  27. micrOS/source/modules/LM_roboarm.py +3 -4
  28. micrOS/source/modules/LM_robustness.py +1 -2
  29. micrOS/source/modules/LM_tcs3472.py +131 -17
  30. micrOS/source/modules/LM_telegram.py +17 -18
  31. {microsdevtoolkit-2.17.2.dist-info → microsdevtoolkit-2.20.0.dist-info}/METADATA +151 -215
  32. {microsdevtoolkit-2.17.2.dist-info → microsdevtoolkit-2.20.0.dist-info}/RECORD +69 -73
  33. toolkit/Gateway.py +1 -1
  34. toolkit/dashboard_apps/SystemTest.py +39 -32
  35. toolkit/micrOSdashboard.py +8 -13
  36. toolkit/socketClient.py +27 -7
  37. toolkit/workspace/precompiled/Common.mpy +0 -0
  38. toolkit/workspace/precompiled/Config.mpy +0 -0
  39. toolkit/workspace/precompiled/Espnow.mpy +0 -0
  40. toolkit/workspace/precompiled/InterConnect.mpy +0 -0
  41. toolkit/workspace/precompiled/Server.mpy +0 -0
  42. toolkit/workspace/precompiled/Shell.mpy +0 -0
  43. toolkit/workspace/precompiled/Tasks.mpy +0 -0
  44. toolkit/workspace/precompiled/micrOSloader.mpy +0 -0
  45. toolkit/workspace/precompiled/modules/LM_buzzer.mpy +0 -0
  46. toolkit/workspace/precompiled/modules/LM_cct.mpy +0 -0
  47. toolkit/workspace/precompiled/modules/LM_dimmer.mpy +0 -0
  48. toolkit/workspace/precompiled/modules/LM_distance.mpy +0 -0
  49. toolkit/workspace/precompiled/modules/LM_espnow.py +18 -1
  50. toolkit/workspace/precompiled/modules/LM_i2s_mic.mpy +0 -0
  51. toolkit/workspace/precompiled/modules/LM_keychain.mpy +0 -0
  52. toolkit/workspace/precompiled/modules/LM_light_sensor.mpy +0 -0
  53. toolkit/workspace/precompiled/modules/LM_mqtt_client.mpy +0 -0
  54. toolkit/workspace/precompiled/modules/LM_neoeffects.mpy +0 -0
  55. toolkit/workspace/precompiled/modules/LM_neomatrix.mpy +0 -0
  56. toolkit/workspace/precompiled/modules/LM_neopixel.mpy +0 -0
  57. toolkit/workspace/precompiled/modules/LM_oled_ui.mpy +0 -0
  58. toolkit/workspace/precompiled/modules/LM_oledui.mpy +0 -0
  59. toolkit/workspace/precompiled/modules/LM_presence.mpy +0 -0
  60. toolkit/workspace/precompiled/modules/LM_rest.mpy +0 -0
  61. toolkit/workspace/precompiled/modules/LM_rgb.mpy +0 -0
  62. toolkit/workspace/precompiled/modules/LM_roboarm.mpy +0 -0
  63. toolkit/workspace/precompiled/modules/LM_robustness.py +1 -2
  64. toolkit/workspace/precompiled/modules/LM_tcs3472.py +131 -17
  65. toolkit/workspace/precompiled/modules/LM_telegram.mpy +0 -0
  66. micrOS/micropython/esp32s2-LOLIN_MINI-20220618-v1.19.1.bin +0 -0
  67. micrOS/micropython/esp32s3_spiram_oct-20231005-v1.21.0.bin +0 -0
  68. micrOS/source/modules/LM_pet_feeder.py +0 -78
  69. toolkit/workspace/precompiled/modules/LM_pet_feeder.py +0 -78
  70. {microsdevtoolkit-2.17.2.data → microsdevtoolkit-2.20.0.data}/scripts/devToolKit.py +0 -0
  71. {microsdevtoolkit-2.17.2.dist-info → microsdevtoolkit-2.20.0.dist-info}/WHEEL +0 -0
  72. {microsdevtoolkit-2.17.2.dist-info → microsdevtoolkit-2.20.0.dist-info}/licenses/LICENSE +0 -0
  73. {microsdevtoolkit-2.17.2.dist-info → microsdevtoolkit-2.20.0.dist-info}/top_level.txt +0 -0
micrOS/source/Tasks.py CHANGED
@@ -18,10 +18,10 @@ from Config import cfgget
18
18
  from Network import sta_high_avail
19
19
 
20
20
  try:
21
- from gc import collect
21
+ from gc import collect as gcollect
22
22
  except ImportError:
23
23
  console_write("[SIMULATOR MODE GC IMPORT]")
24
- from simgc import collect
24
+ from simgc import collect as gcollect
25
25
 
26
26
  #################################################################
27
27
  # Implement custom task class #
@@ -43,18 +43,20 @@ class TaskBase:
43
43
  self.done = asyncio.Event() # Store task done state
44
44
  self.out = "" # Store task output
45
45
 
46
- @staticmethod
47
- def is_busy(tag:str) -> bool:
46
+ ###### BASE METHODS FOR CHILD CLASSES ####
47
+ def _create(self, callback:callable) -> dict:
48
48
  """
49
- Check task is busy by tag
50
- :param tag: for task selection
49
+ Create async task and register it to TASKS dict by tag
50
+ :param callback: coroutine function
51
51
  """
52
- task = TaskBase.TASKS.get(tag, None)
53
- # return True: busy OR False: not busy (inactive)
54
- return bool(task is not None and not task.done.is_set())
52
+ # Create async task from coroutine function
53
+ self.task = asyncio.get_event_loop().create_task(callback)
54
+ # Store Task object by key - for task control
55
+ TaskBase.TASKS[self.tag] = self
56
+ return {self.tag: "Starting"}
55
57
 
56
58
  @staticmethod
57
- def task_gc():
59
+ def _task_gc():
58
60
  """
59
61
  Automatic passive task deletion over QUEUE_SIZE
60
62
  """
@@ -63,18 +65,18 @@ class TaskBase:
63
65
  if len(passive) >= keep:
64
66
  for i in range(0, len(passive)-keep+1):
65
67
  del TaskBase.TASKS[passive[i]]
66
- collect() # GC collect
68
+ gcollect()
67
69
 
70
+ ###### PUBLIC TASK METHODS #####
68
71
  @staticmethod
69
- async def feed(sleep_ms=1):
72
+ def is_busy(tag:str) -> bool:
70
73
  """
71
- Feed event loop
72
- :param sleep_ms: in millisecond
74
+ Check task is busy by tag
75
+ :param tag: for task selection
73
76
  """
74
- # TODO: feed WDT - preemptive cooperative multitasking aka reboot if no feed until X time period
75
- if sleep_ms <= 0:
76
- return await asyncio.sleep(0.000_000_1) # 0 means: 100ns (Absolute minimum)
77
- return await asyncio.sleep_ms(sleep_ms)
77
+ task = TaskBase.TASKS.get(tag, None)
78
+ # return True: busy OR False: not busy (inactive) OR None: not exists
79
+ return bool(task is not None and not task.done.is_set())
78
80
 
79
81
  def cancel(self) -> bool:
80
82
  """
@@ -95,15 +97,16 @@ class TaskBase:
95
97
  return False
96
98
  return True
97
99
 
98
- def __task_del(self, keep_cache=False):
100
+ @staticmethod
101
+ async def feed(sleep_ms=1):
99
102
  """
100
- Delete task from TASKS
103
+ Feed event loop
104
+ :param sleep_ms: in millisecond
101
105
  """
102
- self.done.set()
103
- if self.tag in TaskBase.TASKS:
104
- if not keep_cache: # True - In case of destructor
105
- del TaskBase.TASKS[self.tag]
106
- collect() # GC collect
106
+ # TODO?: feed WDT - auto restart when system is frozen
107
+ if sleep_ms <= 0:
108
+ return await asyncio.sleep(0.000_000_1) # 0 means: 100ns (Absolute minimum)
109
+ return await asyncio.sleep_ms(sleep_ms)
107
110
 
108
111
  async def await_result(self, timeout:int=5):
109
112
  """
@@ -116,6 +119,17 @@ class TaskBase:
116
119
  return "Timeout has beed exceeded"
117
120
  return self.out
118
121
 
122
+ ###### PRIVATE LCM METHODS #####
123
+ def __task_del(self, keep_cache=False):
124
+ """
125
+ Delete task from TASKS
126
+ """
127
+ self.done.set()
128
+ if self.tag in TaskBase.TASKS:
129
+ if not keep_cache: # True - In case of destructor
130
+ del TaskBase.TASKS[self.tag]
131
+ gcollect()
132
+
119
133
  def __del__(self):
120
134
  try:
121
135
  self.__task_del(keep_cache=True)
@@ -129,7 +143,7 @@ class NativeTask(TaskBase):
129
143
  - could be built in function or custom code from load modules
130
144
  """
131
145
 
132
- def create(self, callback:callable=None, tag:str=None) -> bool:
146
+ def create(self, callback:callable=None, tag:str=None) -> dict:
133
147
  """
134
148
  Create async task with coroutine callback (no queue limit check!)
135
149
  + async socket server task
@@ -138,15 +152,11 @@ class NativeTask(TaskBase):
138
152
  """
139
153
  # Create task tag
140
154
  self.tag = f"aio.{ticks_ms()}" if tag is None else tag
141
- if TaskBase.is_busy(self.tag):
155
+ if self.is_busy(self.tag):
142
156
  # Skip task if already running
143
- return False
144
-
145
- # Start task with coroutine callback
146
- self.task = asyncio.get_event_loop().create_task(callback)
147
- # Store Task object by key - for task control
148
- TaskBase.TASKS[self.tag] = self
149
- return True
157
+ return {self.tag: "Already running"}
158
+ # Create task with coroutine callback
159
+ return super()._create(callback)
150
160
 
151
161
  def __enter__(self):
152
162
  """
@@ -163,7 +173,7 @@ class NativeTask(TaskBase):
163
173
  Helper function for Task creation in Load Modules
164
174
  [HINT] Use python with feature to utilize this feature
165
175
  """
166
- self.task_gc() # Task pool cleanup
176
+ self._task_gc() # Task pool cleanup
167
177
  self.done.set()
168
178
 
169
179
 
@@ -179,7 +189,7 @@ class MagicTask(TaskBase):
179
189
  self.__inloop = False # [LM] Task while loop for LM callback
180
190
  self.__sleep = 20 # [LM] Task while loop - async wait (proc feed) [ms]
181
191
 
182
- def create(self, callback:list=None, loop:bool=None, sleep:int=None) -> bool:
192
+ def create(self, callback:list=None, loop:bool=None, sleep:int=None) -> dict:
183
193
  """
184
194
  Create async task with function callback (with queue limit check)
185
195
  - wrap (sync) function into async task (task_wrapper)
@@ -189,20 +199,16 @@ class MagicTask(TaskBase):
189
199
  """
190
200
  # Create task tag
191
201
  self.tag = '.'.join(callback[0:2])
192
- if TaskBase.is_busy(self.tag):
202
+ if self.is_busy(self.tag):
193
203
  # Skip task if already running
194
- return False
195
-
204
+ return {self.tag: "Already running"}
196
205
  # Set parameters for async wrapper
197
206
  self.__callback = callback
198
207
  self.__inloop = self.__inloop if loop is None else loop
199
208
  # Set sleep value for async loop - optional parameter with min sleep limit check (20ms)
200
209
  self.__sleep = self.__sleep if sleep is None else sleep if sleep > 19 else self.__sleep
201
-
202
- self.task = asyncio.get_event_loop().create_task(self.__task_wrapper())
203
- # Store Task object by key - for task control
204
- TaskBase.TASKS[self.tag] = self
205
- return True
210
+ # Create task with coroutine callback
211
+ return super()._create(self.__task_wrapper())
206
212
 
207
213
  async def __task_wrapper(self):
208
214
  """
@@ -217,7 +223,7 @@ class MagicTask(TaskBase):
217
223
  state, self.out = _exec_lm_core(self.__callback)
218
224
  if not state or not self.__inloop:
219
225
  break
220
- self.task_gc() # Task pool cleanup
226
+ self._task_gc() # Task pool cleanup
221
227
  self.done.set()
222
228
 
223
229
  def cancel(self):
@@ -308,12 +314,16 @@ class Manager:
308
314
  my_task.done.set()
309
315
 
310
316
  @staticmethod
311
- def create_task(callback, tag:str=None, loop:bool=False, delay:int=None):
317
+ def create_task(callback, tag:str=None, loop:bool=False, delay:int=None) -> dict:
312
318
  """
313
- Primary interface
314
- Generic task creator method
315
- Create async Task with coroutine/list(lm call) callback
316
- :param callback: list|callable
319
+ Primary interface of micrOS Generic task creator method
320
+ :param tag: task unique identifier
321
+ NativeTask:
322
+ :param callback: callable, coroutine to start a task
323
+ MagicTask with queue limiter:
324
+ :param callback: list of staring (command)
325
+ :param loop: MagicTask looping parameter
326
+ :param delay: MagicTask delay parameter
317
327
  """
318
328
  if isinstance(callback, list):
319
329
  # Check queue if task is Load Module
@@ -373,7 +383,7 @@ class Manager:
373
383
  return '\n'.join(output)
374
384
 
375
385
  @staticmethod
376
- def kill(tag):
386
+ def kill(tag:str) -> (bool, str):
377
387
  """
378
388
  Primary interface
379
389
  Kill/terminate async task
@@ -474,11 +484,11 @@ def exec_builtins(func):
474
484
  if arg_len > 1 and 'list' == arg_list[1]:
475
485
  on, off = Manager.list_tasks(json=json_flag)
476
486
  # RETURN: JSON mode Human readable mode with cpu & queue info
477
- return (True, {'active': on[3:], 'inactive': off}) if json_flag else (True, '\n'.join(on) + '\n' + '\n'.join(off) + '\n')
487
+ return (True, dumps({'active': on[3:], 'inactive': off})) if json_flag else (True, '\n'.join(on) + '\n' + '\n'.join(off) + '\n')
478
488
  # task kill <taskID> / task show <taskID>
479
489
  if arg_len > 2:
480
490
  if 'kill' == arg_list[1]:
481
- state, msg = Manager.kill(tag=arg_list[2])
491
+ _, msg = Manager.kill(tag=arg_list[2])
482
492
  return True, msg
483
493
  if 'show' == arg_list[1]:
484
494
  return True, Manager.show(tag=arg_list[2])
@@ -511,15 +521,9 @@ def lm_exec(arg_list:list, jsonify:bool=None):
511
521
  delay = int(delay) if delay.isdigit() else None
512
522
  # Create and start async lm task
513
523
  try:
514
- state = Manager.create_task(arg_list, loop=loop, delay=delay)
524
+ return True, Manager.create_task(arg_list, loop=loop, delay=delay)
515
525
  except Exception as e:
516
- # Valid & handled task command
517
- return True, str(e)
518
- tag = '.'.join(arg_list[0:2])
519
- # Valid & handled task command
520
- if state:
521
- return True, f"Start {tag}"
522
- return True, f"{tag} is Busy"
526
+ return False, {".".join(arg_list[0:2]): str(e)}
523
527
 
524
528
  # [2] Sync "realtime" task execution
525
529
  state, out = _exec_lm_core(arg_list, jsonify)
@@ -588,7 +592,7 @@ def _exec_lm_core(cmd_list, jsonify):
588
592
  # UNLOAD MODULE IF MEMORY ERROR HAPPENED + gc.collect
589
593
  if lm_mod in modules:
590
594
  del modules[lm_mod]
591
- collect()
595
+ gcollect()
592
596
  # LM EXECUTION ERROR
593
597
  return False, f"Core error: {lm_mod}->{lm_func}: {e}"
594
598
  return False, "Shell: for hints type help.\nShell: for LM exec: [1](LM)module [2]function [3...]optional params"
@@ -102,7 +102,7 @@ def __auto_restart_event():
102
102
  if trigger_is_active and _is_micrOS():
103
103
  print("[loader][ota-rebooter][micros][trigger: True] OTA was finished - reboot")
104
104
  # Create cleanup indicator file for ConfigHandler
105
- with open('cleanup.pds', 'w') as f:
105
+ with open('.cleanup', 'w') as f:
106
106
  f.write('')
107
107
  # Reboot machine
108
108
  reset()
@@ -270,10 +270,7 @@ def play(rtttlstr='Indiana'):
270
270
  global CHECK_NOTIFY
271
271
  if CHECK_NOTIFY and not notify():
272
272
  return "NoBipp - notify off"
273
- state = micro_task(tag=__TASK_TAG, task=_play(rtttlstr))
274
- if state:
275
- return 'Play song'
276
- return 'Song already playing'
273
+ return micro_task(tag=__TASK_TAG, task=_play(rtttlstr))
277
274
 
278
275
 
279
276
  def list_tones():
@@ -238,8 +238,7 @@ def transition(cw=None, ww=None, sec=1.0, wake=False):
238
238
  # Create transition generator and calculate step_ms
239
239
  cct_gen, step_ms = transition_gen(cw_from, cw_to, ww_from, ww_to, interval_sec=sec)
240
240
  # [!] ASYNC TASK CREATION [1*] with async task callback + taskID (TAG) handling
241
- state = micro_task(tag=Data.CCT_TASK_TAG, task=_task(ms_period=step_ms, iterable=cct_gen))
242
- return "Starting transition" if state else "Transition already running"
241
+ return micro_task(tag=Data.CCT_TASK_TAG, task=_task(ms_period=step_ms, iterable=cct_gen))
243
242
 
244
243
 
245
244
  def hue_transition(percent, sec=1.0, wake=False):
@@ -288,8 +287,7 @@ def hue_transition(percent, sec=1.0, wake=False):
288
287
  #print("Actual percent: {}, target percent: {}".format(actual_percent, warm_percent))
289
288
  hue_gen, step_ms = transition_gen(hue_curr_percent, percent*10, interval_sec=sec)
290
289
  # [!] ASYNC TASK CREATION [1*] with async task callback + taskID (TAG) handling
291
- state = micro_task(tag=Data.HUE_TASK_TAG, task=_task(ms_period=step_ms, iterable=hue_gen))
292
- return "Starting transition" if state else "Transition already running"
290
+ return micro_task(tag=Data.HUE_TASK_TAG, task=_task(ms_period=step_ms, iterable=hue_gen))
293
291
  else:
294
292
  return "Invalid range, percent=<0-100>"
295
293
 
@@ -184,8 +184,7 @@ def transition(value, sec=1.0, wake=False):
184
184
  # Create transition generator and calculate step_ms
185
185
  fade_gen, fade_step_ms = transition_gen(from_dim, value, interval_sec=sec)
186
186
  # [!] ASYNC TASK CREATION [1*] with async task callback + taskID (TAG) handling
187
- state = micro_task(tag=Data.DIMM_TASK_TAG, task=_task(ms_period=fade_step_ms, iterable=fade_gen))
188
- return "Starting transition" if state else "Transition already running"
187
+ return micro_task(tag=Data.DIMM_TASK_TAG, task=_task(ms_period=fade_step_ms, iterable=fade_gen))
189
188
 
190
189
 
191
190
  def subscribe_presence():
@@ -70,9 +70,7 @@ def start_dimmer_indicator(idle_distance=180):
70
70
  """Distance visualization on LED brightness (LM_dimmer)"""
71
71
  from LM_dimmer import set_value
72
72
  # [!] ASYNC TASK CREATION [1*] with async task callback + taskID (TAG) handling
73
- state = micro_task(tag="distance.visual", task=__task(period_ms=200, dimmer=set_value, idle_cm=idle_distance))
74
- return "Starting" if state else "Already running"
75
-
73
+ return micro_task(tag="distance.visual", task=__task(period_ms=200, dimmer=set_value, idle_cm=idle_distance))
76
74
 
77
75
 
78
76
  #########################
@@ -17,6 +17,13 @@ def stats():
17
17
  return ESPNOW.stats()
18
18
 
19
19
 
20
+ def members():
21
+ """
22
+ Get ESPNow devices
23
+ """
24
+ return ESPNOW.members()
25
+
26
+
20
27
  def handshake(peer:bytes|str):
21
28
  """
22
29
  Handshake with ESPNow Peer
@@ -27,10 +34,20 @@ def handshake(peer:bytes|str):
27
34
  return ESPNOW.handshake(peer)
28
35
 
29
36
 
37
+ def remove(peer:bytes):
38
+ """
39
+ Remove peer by binary mac address
40
+ :param peer: binary mac address of espnow device
41
+ """
42
+ return ESPNOW.remove_peer(peer)
43
+
44
+
30
45
  def help():
31
46
  """
32
47
  ESPNOW sender/receiver with LM execution
33
48
  """
34
49
  return ('handshake peer=<mac-address>',
35
50
  'send peer=<peer-name> cmd="hello"',
36
- 'stats')
51
+ 'remove peer=<binary-mac-address>',
52
+ 'stats',
53
+ 'members')
@@ -94,8 +94,7 @@ def background_capture():
94
94
  if not Data.MIC_ENABLED:
95
95
  return "Microphone is disabled"
96
96
 
97
- state = micro_task(tag=Data.TASK_TAG, task=__task(ms_period=1))
98
- return "Starting" if state else "Already running"
97
+ return micro_task(tag=Data.TASK_TAG, task=__task(ms_period=1))
99
98
 
100
99
 
101
100
  def get_from_buffer(capture_duration=Data.CAPTURE_DURATION,
@@ -216,8 +216,7 @@ def display(period=1000, tts=30):
216
216
  # [!] ASYNC TASK CREATION [1*] with async task callback + taskID (TAG) handling
217
217
  period_ms = 500 if period < 500 else period
218
218
  tts_ms = 5000 if tts < 5 else tts*1000
219
- state = micro_task(tag="keychain.display", task=_ui_task(period_ms, tts_ms))
220
- return "Starting" if state else "Already running"
219
+ return micro_task(tag="keychain.display", task=_ui_task(period_ms, tts_ms))
221
220
 
222
221
 
223
222
  def temperature():
@@ -96,11 +96,8 @@ def subscribe_intercon(on, off, threshold=4, tolerance=2, sample_sec=60):
96
96
  """
97
97
  # Start play - servo XY in async task
98
98
  # [!] ASYNC TASK CREATION [1*] with async task callback + taskID (TAG) handling
99
- state = micro_task(tag="light_sensor.intercon", task=_task(on, off, threshold, tolerance=tolerance,
99
+ return micro_task(tag="light_sensor.intercon", task=_task(on, off, threshold, tolerance=tolerance,
100
100
  check_ms=sample_sec*1000))
101
- if state:
102
- return 'Light sensor remote trigger starts'
103
- return 'Light sensor remote trigger - already running'
104
101
 
105
102
 
106
103
  #######################
@@ -123,8 +123,8 @@ def publish(topic: str, message: str, retain: bool = False):
123
123
  :return: Status message string.
124
124
  """
125
125
  unique_tag = f'mqtt.publish.{topic}.{time.ticks_ms()}'
126
- state = micro_task(tag=unique_tag, task=_publish(unique_tag, message, topic, retain))
127
- return f"Message was sent {state}"
126
+ state:dict = micro_task(tag=unique_tag, task=_publish(unique_tag, message, topic, retain))
127
+ return f"Message was sent ({list(state.values())[0]})"
128
128
 
129
129
 
130
130
  ####################
@@ -142,8 +142,8 @@ async def _up():
142
142
  my_task.out = "Wait"
143
143
  await MQTT.CLIENT.up.wait()
144
144
  MQTT.CLIENT.up.clear()
145
- state = micro_task(tag=MQTT.SUB_TASK, task=_subscribe(MQTT.DEFAULT_TOPIC))
146
- my_task.out = f"Re-Subscription {state}"
145
+ state:dict = micro_task(tag=MQTT.SUB_TASK, task=_subscribe(MQTT.DEFAULT_TOPIC))
146
+ my_task.out = f"Re-Subscription ({list(state.values())[0]})"
147
147
  my_task.feed()
148
148
 
149
149
 
@@ -165,10 +165,14 @@ async def _init_client():
165
165
  MQTT.CLIENT.up.clear()
166
166
 
167
167
  # Initialize mqtt topics
168
- if not micro_task(tag=MQTT.SUB_TASK, task=_subscribe(MQTT.DEFAULT_TOPIC)):
169
- syslog(f"Failed start mqtt subscribe")
170
- if not micro_task(tag=MQTT.UP_TASK, task=_up()):
171
- syslog(f"Failed start mqtt up")
168
+ try:
169
+ micro_task(tag=MQTT.SUB_TASK, task=_subscribe(MQTT.DEFAULT_TOPIC))
170
+ except Exception as err:
171
+ syslog(f"Failed start mqtt subscribe: {err}")
172
+ try:
173
+ micro_task(tag=MQTT.UP_TASK, task=_up())
174
+ except Exception as err:
175
+ syslog(f"Failed start mqtt up: {err}")
172
176
  # Async listener loop
173
177
  await _receiver()
174
178
  my_task.out = "Receiver closed"
@@ -230,8 +234,7 @@ def load(username: str, password: str, server_ip: str, server_port: str='1883',
230
234
  MQTT.CLIENT = MQTTClient(_configure(username, password, server_ip, server_port))
231
235
  MQTT.QOS = qos
232
236
 
233
- state = micro_task(tag=MQTT.CLIENT_TASK, task=_init_client())
234
- return {MQTT.CLIENT_TASK: "Starting"} if state else {MQTT.CLIENT_TASK: "Already running"}
237
+ return micro_task(tag=MQTT.CLIENT_TASK, task=_init_client())
235
238
 
236
239
 
237
240
  def help(widgets=False):
@@ -277,7 +277,7 @@ def help(widgets=False):
277
277
  'BUTTON fire speed_ms=150',
278
278
  'BUTTON stop',
279
279
  'shader offset=0 size=6',
280
- 'control speed_ms=None batch=None',
280
+ 'SLIDER control speed_ms=<1-200> batch=None',
281
281
  'random max_val=255',
282
282
  'pinmap',
283
283
  'COLOR color r=<0-255-10> g b'
@@ -430,7 +430,7 @@ def help(widgets=False):
430
430
  'BUTTON rainbow',
431
431
  'BUTTON spiral speed_ms=40',
432
432
  'BUTTON noise speed_ms=85',
433
- 'SLIDER control speed_ms=<1-200-2> bt_draw=None',
433
+ 'SLIDER control speed_ms=<1-200> bt_draw=None',
434
434
  'draw_colormap bitmap=[(0,0,(10,2,0)),(x,y,color),...]',
435
435
  'get_colormap',
436
436
  'status'
@@ -278,8 +278,7 @@ def transition(r=None, g=None, b=None, sec=1.0, wake=False):
278
278
  # Create transition generator and calculate step_ms
279
279
  rgb_gen, step_ms = transition_gen(r_from, r_to, g_from, g_to, b_from, b_to, interval_sec=sec)
280
280
  # [!] ASYNC TASK CREATION [1*] with async task callback + taskID (TAG) handling
281
- state = micro_task(tag=Data.RGB_TASK_TAG, task=_task(ms_period=step_ms, iterable=rgb_gen))
282
- return "Starting transition" if state else "Transition already running"
281
+ return micro_task(tag=Data.RGB_TASK_TAG, task=_task(ms_period=step_ms, iterable=rgb_gen))
283
282
 
284
283
 
285
284
  def random(smooth=True, max_val=255):
@@ -343,9 +343,10 @@ class PageUI:
343
343
  # Send CMD to other device & show result
344
344
  state, data_meta = exec_cmd(cmd + [f">>{host}"], jsonify=True)
345
345
  if state:
346
- self.cmd_task_tag = data_meta['tag']
347
- if "Task is Busy" in data_meta['verdict'] and not run:
348
- self.cmd_out = data_meta['verdict'] # Otherwise the task start output not relevant on UI
346
+ self.cmd_task_tag = list(data_meta.keys())[0]
347
+ verdict = list(data_meta.values())[0]
348
+ if "Already running" in verdict and not run:
349
+ self.cmd_out = verdict # Otherwise the task start output not relevant on UI
349
350
  else:
350
351
  self.cmd_out = f"Error: {data_meta}"
351
352
  except Exception as e:
@@ -121,8 +121,7 @@ class Frame(BaseFrame):
121
121
  """
122
122
  # [!] ASYNC TASK CREATION [1*] with async task callback + taskID (TAG) handling
123
123
  self._taskid = f"oledui.{tid}"
124
- state = micro_task(tag=self._taskid, task=self._task(period_ms=period_ms))
125
- return "Starting" if state else "Already running"
124
+ return micro_task(tag=self._taskid, task=self._task(period_ms=period_ms))
126
125
 
127
126
  def hover(self):
128
127
  """
@@ -486,8 +485,7 @@ class ScreenSaver(BaseFrame):
486
485
  def run(self, fps=10):
487
486
  # [!] ASYNC TASK CREATION [1*] with async task callback + taskID (TAG) handling
488
487
  period_ms = int(1000/fps)
489
- state = micro_task(tag="oledui.anim", task=self._task(period_ms))
490
- return "Starting" if state else "Already running"
488
+ return micro_task(tag="oledui.anim", task=self._task(period_ms))
491
489
 
492
490
  def cancel(self):
493
491
  if self.running:
@@ -782,9 +780,10 @@ class PageUI:
782
780
  # Send CMD to other device & show result
783
781
  state, data_meta = exec_cmd(cmd + [f">>{host}"], jsonify=True)
784
782
  if state:
785
- self._cmd_task_tag = data_meta['tag']
786
- if "Task is Busy" in data_meta['verdict'] and not run:
787
- self.app_frame.press_output = data_meta['verdict'] # Otherwise the task start output not relevant on UI
783
+ self._cmd_task_tag = list(data_meta.keys())[0]
784
+ verdict = list(data_meta.values())[0]
785
+ if "Already running" in verdict and not run:
786
+ self.app_frame.press_output = verdict # Otherwise the task start output not relevant on UI
788
787
  else:
789
788
  self.app_frame.press_output = f"Error: {data_meta}"
790
789
  except Exception as e:
@@ -213,8 +213,7 @@ def motion_trig(sample_ms=15, buff_size=10):
213
213
 
214
214
  # [3] Start mic sampling in async task
215
215
  # [!] ASYNC TASK CREATION [1*] with async task callback + taskID (TAG) handling
216
- state = micro_task(tag=Data.TASK_TAG, task=__task(ms_period=sample_ms, buff_size=buff_size))
217
- return "Starting" if state else "Already running"
216
+ return micro_task(tag=Data.TASK_TAG, task=__task(ms_period=sample_ms, buff_size=buff_size))
218
217
 
219
218
 
220
219
  def subscribe_intercon(on, off):
@@ -66,8 +66,7 @@ def aurl(subdomain):
66
66
  tag = "rest." + subdomain.replace("http://", '').replace("https://", '')
67
67
  if len(tag) > 50:
68
68
  tag = tag[0:50]
69
- state = micro_task(tag=tag, task=__task(subdomain, tag))
70
- return f"Starting" if state else f"Already running"
69
+ return micro_task(tag=tag, task=__task(subdomain, tag))
71
70
 
72
71
 
73
72
  def help(widgets=False):
@@ -246,8 +246,7 @@ def transition(r=None, g=None, b=None, sec=1.0, wake=False):
246
246
  # Create transition generator and calculate step_ms
247
247
  rgb_gen, step_ms = transition_gen(r_from, r, g_from, g, b_from, b, interval_sec=sec)
248
248
  # [!] ASYNC TASK CREATION [1*] with async task callback + taskID (TAG) handling
249
- state = micro_task(tag=Data.RGB_TASK_TAG, task=_task(ms_period=step_ms, iterable=rgb_gen))
250
- return "Starting transition" if state else "Transition already running"
249
+ return micro_task(tag=Data.RGB_TASK_TAG, task=_task(ms_period=step_ms, iterable=rgb_gen))
251
250
 
252
251
 
253
252
  def random(smooth=True, max_val=1000):
@@ -204,11 +204,10 @@ def play(*args, s=None, delay=None, deinit=True):
204
204
 
205
205
  # Start play - servo XY in async task
206
206
  # [!] ASYNC TASK CREATION [1*] with async task callback + taskID (TAG) handling
207
- state = micro_task(tag=RoboArm.PLAY_TAG, task=_play(args, deinit, delay))
208
- if state:
209
- return 'Play: {} steps'.format(int(len(args)/2))
210
- return 'Play - already running'
211
207
 
208
+ state:dict = micro_task(tag=RoboArm.PLAY_TAG, task=_play(args, deinit, delay))
209
+ state.update({"Play steps": int(len(args)/2)})
210
+ return state
212
211
 
213
212
  def record(clean=False, rec_limit=8):
214
213
  """
@@ -83,8 +83,7 @@ def create_task():
83
83
  """
84
84
  # [!] ASYNC TASK CREATION [1*] with async task callback + taskID (TAG) handling
85
85
  task_tag = "microtask.run"
86
- state = micro_task(tag=task_tag, task=__task(tag=task_tag, period_ms=5))
87
- return "Starting" if state else "Already running"
86
+ return micro_task(tag=task_tag, task=__task(tag=task_tag, period_ms=5))
88
87
 
89
88
 
90
89
  @micro_task("microtask", _wrap=True)