micrOSDevToolKit 2.8.6__py3-none-any.whl → 2.9.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.
- env/driver_cp210x/.DS_Store +0 -0
- env/driver_cp210x/macOS_VCP_Driver/SiLabsUSBDriverDisk.dmg +0 -0
- env/driver_cp210x/macOS_VCP_Driver/macOS_VCP_Driver_Release_Notes.txt +0 -0
- micrOS/micropython/esp32-20241129-v1.24.1.bin +0 -0
- micrOS/micropython/esp32s3-20241129-v1.24.1.bin +0 -0
- micrOS/micropython/esp32s3_spiram_oct-20241129-v1.24.1.bin +0 -0
- micrOS/micropython/rpi-pico-w-20241129-v1.24.1.uf2 +0 -0
- micrOS/micropython/tinypico-20241129-v1.24.1.bin +0 -0
- micrOS/release_info/micrOS_ReleaseInfo/system_analysis_sum.json +40 -40
- micrOS/source/Common.py +12 -17
- micrOS/source/Config.py +20 -1
- micrOS/source/Hooks.py +25 -15
- micrOS/source/LM_buzzer.py +16 -9
- micrOS/source/LM_cct.py +2 -3
- micrOS/source/LM_dimmer.py +1 -2
- micrOS/source/LM_distance.py +2 -4
- micrOS/source/LM_genIO.py +1 -1
- micrOS/source/LM_i2s_mic.py +4 -4
- micrOS/source/LM_keychain.py +2 -3
- micrOS/source/LM_light_sensor.py +1 -2
- micrOS/source/LM_neoeffects.py +22 -7
- micrOS/source/LM_neopixel.py +2 -3
- micrOS/source/LM_oledui.py +3 -4
- micrOS/source/LM_pet_feeder.py +3 -4
- micrOS/source/LM_ph_sensor.py +2 -2
- micrOS/source/LM_presence.py +2 -3
- micrOS/source/LM_rest.py +52 -9
- micrOS/source/LM_rgb.py +1 -2
- micrOS/source/LM_roboarm.py +1 -2
- micrOS/source/LM_sound_event.py +2 -3
- micrOS/source/LM_system.py +14 -3
- micrOS/source/LM_telegram.py +226 -15
- micrOS/source/Logger.py +6 -0
- micrOS/source/Notify.py +46 -218
- micrOS/source/Scheduler.py +7 -4
- micrOS/source/Shell.py +2 -2
- micrOS/source/Tasks.py +106 -98
- micrOS/source/Types.py +6 -2
- micrOS/source/Web.py +32 -8
- micrOS/source/dashboard.html +4 -4
- micrOS/source/micrOS.py +5 -10
- micrOS/source/micrOSloader.py +16 -18
- micrOS/source/uapi.js +5 -6
- micrOS/source/urequests.py +171 -85
- {micrOSDevToolKit-2.8.6.dist-info → micrOSDevToolKit-2.9.0.dist-info}/METADATA +2 -2
- {micrOSDevToolKit-2.8.6.dist-info → micrOSDevToolKit-2.9.0.dist-info}/RECORD +95 -97
- toolkit/DevEnvUSB.py +1 -6
- toolkit/MicrOSDevEnv.py +8 -5
- toolkit/simulator_lib/__pycache__/simulator.cpython-312.pyc +0 -0
- toolkit/simulator_lib/__pycache__/uasyncio.cpython-312.pyc +0 -0
- toolkit/simulator_lib/__pycache__/usocket.cpython-312.pyc +0 -0
- toolkit/simulator_lib/simulator.py +14 -0
- toolkit/simulator_lib/uasyncio.py +2 -2
- toolkit/simulator_lib/usocket.py +5 -1
- toolkit/workspace/precompiled/Common.mpy +0 -0
- toolkit/workspace/precompiled/Config.mpy +0 -0
- toolkit/workspace/precompiled/Hooks.mpy +0 -0
- toolkit/workspace/precompiled/LM_buzzer.mpy +0 -0
- toolkit/workspace/precompiled/LM_cct.mpy +0 -0
- toolkit/workspace/precompiled/LM_dimmer.mpy +0 -0
- toolkit/workspace/precompiled/LM_distance.mpy +0 -0
- toolkit/workspace/precompiled/LM_genIO.mpy +0 -0
- toolkit/workspace/precompiled/LM_i2s_mic.mpy +0 -0
- toolkit/workspace/precompiled/LM_keychain.mpy +0 -0
- toolkit/workspace/precompiled/LM_light_sensor.mpy +0 -0
- toolkit/workspace/precompiled/LM_neoeffects.mpy +0 -0
- toolkit/workspace/precompiled/LM_neopixel.mpy +0 -0
- toolkit/workspace/precompiled/LM_oledui.mpy +0 -0
- toolkit/workspace/precompiled/LM_pet_feeder.py +3 -4
- toolkit/workspace/precompiled/LM_ph_sensor.py +2 -2
- toolkit/workspace/precompiled/LM_presence.mpy +0 -0
- toolkit/workspace/precompiled/LM_rest.mpy +0 -0
- toolkit/workspace/precompiled/LM_rgb.mpy +0 -0
- toolkit/workspace/precompiled/LM_roboarm.mpy +0 -0
- toolkit/workspace/precompiled/LM_sound_event.mpy +0 -0
- toolkit/workspace/precompiled/LM_system.mpy +0 -0
- toolkit/workspace/precompiled/LM_telegram.mpy +0 -0
- toolkit/workspace/precompiled/Logger.mpy +0 -0
- toolkit/workspace/precompiled/Notify.mpy +0 -0
- toolkit/workspace/precompiled/Scheduler.mpy +0 -0
- toolkit/workspace/precompiled/Shell.mpy +0 -0
- toolkit/workspace/precompiled/Tasks.mpy +0 -0
- toolkit/workspace/precompiled/Types.mpy +0 -0
- toolkit/workspace/precompiled/Web.mpy +0 -0
- toolkit/workspace/precompiled/dashboard.html +4 -4
- toolkit/workspace/precompiled/micrOS.mpy +0 -0
- toolkit/workspace/precompiled/micrOSloader.mpy +0 -0
- toolkit/workspace/precompiled/node_config.json +1 -1
- toolkit/workspace/precompiled/uapi.js +5 -6
- toolkit/workspace/precompiled/urequests.mpy +0 -0
- env/driver_cp210x/CH34XSER_MAC/CH34X_DRV_INSTALL_INSTRUCTIONS.pdf +0 -0
- env/driver_cp210x/CH34XSER_MAC/CH34xVCPDriver.pkg +0 -0
- micrOS/micropython/esp32-20231005-v1.21.0.bin +0 -0
- micrOS/micropython/esp32-GENERIC-20240602-v1.23.0.bin +0 -0
- micrOS/micropython/rpi-pico-w-20240602-v1.23.0.uf2 +0 -0
- micrOS/micropython/tinypico-20231005-v1.21.0.bin +0 -0
- micrOS/micropython/tinypico_usbc-UM-20240105-v1.22.1.bin +0 -0
- /micrOS/micropython/{esp32c3-GENERIC-20240222-v1.22.2.bin → esp32c3-20240222-v1.22.2.bin} +0 -0
- /micrOS/micropython/{esp32s2-GENERIC-20240602-v1.23.0.bin → esp32s2-20240602-v1.23.0.bin} +0 -0
- /micrOS/micropython/{esp32s3-GENERIC-20240105-v1.22.1.bin → esp32s3-20240105-v1.22.1.bin} +0 -0
- {micrOSDevToolKit-2.8.6.data → micrOSDevToolKit-2.9.0.data}/scripts/devToolKit.py +0 -0
- {micrOSDevToolKit-2.8.6.dist-info → micrOSDevToolKit-2.9.0.dist-info}/LICENSE +0 -0
- {micrOSDevToolKit-2.8.6.dist-info → micrOSDevToolKit-2.9.0.dist-info}/WHEEL +0 -0
- {micrOSDevToolKit-2.8.6.dist-info → micrOSDevToolKit-2.9.0.dist-info}/top_level.txt +0 -0
micrOS/source/Tasks.py
CHANGED
|
@@ -19,7 +19,7 @@ from Network import sta_high_avail
|
|
|
19
19
|
|
|
20
20
|
try:
|
|
21
21
|
from gc import collect
|
|
22
|
-
except:
|
|
22
|
+
except ImportError:
|
|
23
23
|
console_write("[SIMULATOR MODE GC IMPORT]")
|
|
24
24
|
from simgc import collect
|
|
25
25
|
|
|
@@ -38,22 +38,34 @@ class TaskBase:
|
|
|
38
38
|
TASKS = {} # TASK OBJ list
|
|
39
39
|
|
|
40
40
|
def __init__(self):
|
|
41
|
-
self.task = None #
|
|
42
|
-
self.
|
|
43
|
-
self.
|
|
44
|
-
self.
|
|
41
|
+
self.task = None # Store created async task object
|
|
42
|
+
self.tag = None # Task tag (identification)
|
|
43
|
+
self.done = asyncio.Event() # Store task done state
|
|
44
|
+
self.out = "" # Store task output
|
|
45
45
|
|
|
46
46
|
@staticmethod
|
|
47
|
-
def is_busy(tag):
|
|
47
|
+
def is_busy(tag) -> bool:
|
|
48
48
|
"""
|
|
49
|
-
Check task is busy by tag
|
|
50
|
-
|
|
49
|
+
Check task is busy by tag
|
|
50
|
+
:param tag: for task selection
|
|
51
51
|
"""
|
|
52
52
|
task = TaskBase.TASKS.get(tag, None)
|
|
53
53
|
# return True: busy OR False: not busy (inactive)
|
|
54
54
|
return bool(task is not None and not task.done.is_set())
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
@staticmethod
|
|
57
|
+
def task_gc():
|
|
58
|
+
"""
|
|
59
|
+
Automatic passive task deletion over QUEUE_SIZE
|
|
60
|
+
"""
|
|
61
|
+
keep = TaskBase.QUEUE_SIZE
|
|
62
|
+
passive = tuple((task_tag for task_tag in list(TaskBase.TASKS) if not TaskBase.is_busy(task_tag)))
|
|
63
|
+
if len(passive) >= keep:
|
|
64
|
+
for i in range(0, len(passive)-keep+1):
|
|
65
|
+
del TaskBase.TASKS[passive[i]]
|
|
66
|
+
collect() # GC collect
|
|
67
|
+
|
|
68
|
+
def cancel(self) -> bool:
|
|
57
69
|
"""
|
|
58
70
|
Cancel task (+cleanup)
|
|
59
71
|
"""
|
|
@@ -83,13 +95,13 @@ class TaskBase:
|
|
|
83
95
|
collect() # GC collect
|
|
84
96
|
|
|
85
97
|
@staticmethod
|
|
86
|
-
def
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
98
|
+
async def feed(sleep_ms=1):
|
|
99
|
+
"""
|
|
100
|
+
Feed event loop
|
|
101
|
+
:param sleep_ms: in millisecond (min: 1)
|
|
102
|
+
"""
|
|
103
|
+
# TODO: feed WDT - preemptive cooperative multitasking aka reboot if no feed until X time period
|
|
104
|
+
return await asyncio.sleep_ms(sleep_ms)
|
|
93
105
|
|
|
94
106
|
def __del__(self):
|
|
95
107
|
try:
|
|
@@ -187,9 +199,12 @@ class MagicTask(TaskBase):
|
|
|
187
199
|
- self.__inloop: lm call type - one-shot (False) / looped (True)
|
|
188
200
|
- self.__msg_buf: lm msg object redirect to variable - store lm output
|
|
189
201
|
"""
|
|
202
|
+
jsonify = self.__callback[-1] == '>json'
|
|
203
|
+
if jsonify:
|
|
204
|
+
self.__callback = self.__callback[:-1]
|
|
190
205
|
while True:
|
|
191
|
-
await
|
|
192
|
-
state, self.out = _exec_lm_core(self.__callback)
|
|
206
|
+
await self.feed(self.__sleep)
|
|
207
|
+
state, self.out = _exec_lm_core(self.__callback, jsonify)
|
|
193
208
|
if not state or not self.__inloop:
|
|
194
209
|
break
|
|
195
210
|
self.task_gc() # Task pool cleanup
|
|
@@ -265,10 +280,10 @@ class Manager:
|
|
|
265
280
|
try:
|
|
266
281
|
while True:
|
|
267
282
|
# [0] Just chill
|
|
268
|
-
await
|
|
283
|
+
await my_task.feed(300)
|
|
269
284
|
# [1] PROBE SYSTEM LOAD + 300ms
|
|
270
285
|
t = ticks_ms()
|
|
271
|
-
await
|
|
286
|
+
await my_task.feed(300)
|
|
272
287
|
delta_rate = int(((ticks_diff(ticks_ms(), t) / 300) - 1) * 100)
|
|
273
288
|
Manager.LOAD = int((Manager.LOAD + delta_rate) / 2) # Average - smooth
|
|
274
289
|
# [2] NETWORK AUTO REPAIR
|
|
@@ -353,7 +368,6 @@ class Manager:
|
|
|
353
368
|
- by tag: module.function
|
|
354
369
|
- by tag module.*, kill all for selected module
|
|
355
370
|
"""
|
|
356
|
-
|
|
357
371
|
def terminate(_tag):
|
|
358
372
|
to_kill = TaskBase.TASKS.get(_tag, None)
|
|
359
373
|
try:
|
|
@@ -399,85 +413,94 @@ class Manager:
|
|
|
399
413
|
#################################################################
|
|
400
414
|
# LM EXEC CORE functions #
|
|
401
415
|
#################################################################
|
|
402
|
-
|
|
403
|
-
|
|
416
|
+
def exec_builtins(func):
|
|
417
|
+
"""
|
|
418
|
+
Module execution built-in commands and modifiers
|
|
419
|
+
- modules - show active modules list
|
|
420
|
+
- task kill ... - task termination
|
|
421
|
+
show ... - task output dump
|
|
422
|
+
- ... >json - postfix to "jsonize" the output
|
|
423
|
+
"""
|
|
424
|
+
def wrapper(arg_list, jsonify=None):
|
|
425
|
+
# Ensure the parameter is a list of strings
|
|
426
|
+
if isinstance(arg_list, list) and arg_list:
|
|
427
|
+
# JSONIFY: [1] >json in arg_list or [2] jsonify True/False
|
|
428
|
+
json_flag = arg_list[-1] == '>json'
|
|
429
|
+
if json_flag:
|
|
430
|
+
arg_list = arg_list[:-1]
|
|
431
|
+
json_flag = jsonify if isinstance(jsonify, bool) else json_flag
|
|
432
|
+
# MODULES
|
|
433
|
+
if arg_list[0] == 'modules':
|
|
434
|
+
return True, list((m.strip().replace('LM_', '') for m in modules if m.startswith('LM_'))) + ['task']
|
|
435
|
+
# Handle task manipulation commands: list, kill, show - return True -> Command handled
|
|
436
|
+
if 'task' == arg_list[0]:
|
|
437
|
+
arg_len = len(arg_list)
|
|
438
|
+
# task list
|
|
439
|
+
if arg_len > 1 and 'list' == arg_list[1]:
|
|
440
|
+
on, off = Manager.list_tasks(json=json_flag)
|
|
441
|
+
# RETURN: JSON mode Human readable mode with cpu & queue info
|
|
442
|
+
return (True, {'active': on[3:], 'inactive': off}) if json_flag else (True, '\n'.join(on) + '\n' + '\n'.join(off) + '\n')
|
|
443
|
+
# task kill <taskID> / task show <taskID>
|
|
444
|
+
if arg_len > 2:
|
|
445
|
+
if 'kill' == arg_list[1]:
|
|
446
|
+
state, msg = Manager.kill(tag=arg_list[2])
|
|
447
|
+
return True, msg
|
|
448
|
+
if 'show' == arg_list[1]:
|
|
449
|
+
return True, Manager.show(tag=arg_list[2])
|
|
450
|
+
return True, "Invalid task cmd! Help: task list / kill <taskID> / show <taskID>"
|
|
451
|
+
# Call the decorated function with the additional flag
|
|
452
|
+
return func(arg_list, json_flag)
|
|
453
|
+
return wrapper
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
@exec_builtins
|
|
457
|
+
def lm_exec(arg_list, jsonify):
|
|
404
458
|
"""
|
|
405
459
|
Main LM executor function with
|
|
406
460
|
- async (background)
|
|
407
461
|
- sync
|
|
408
462
|
(single) task execution (_exec_lm_core)
|
|
409
463
|
:param arg_list: command parameters
|
|
410
|
-
|
|
464
|
+
:param jsonify: request json output (controlled by the decorator)
|
|
465
|
+
Return Bool(OK/NOK), "Command output"
|
|
411
466
|
"""
|
|
412
467
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
#
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
# Human readable mode with cpu & queue info
|
|
425
|
-
return True, '\n'.join(on) + '\n' + '\n'.join(off) + '\n' # Show active tasks and passive tasks
|
|
426
|
-
# task kill <taskID> / task show <taskID>
|
|
427
|
-
if arg_len > 2:
|
|
428
|
-
if 'kill' == arg_list[1]:
|
|
429
|
-
state, msg = Manager.kill(tag=arg_list[2])
|
|
430
|
-
return True, msg
|
|
431
|
-
if 'show' == arg_list[1]:
|
|
432
|
-
return True, Manager.show(tag=arg_list[2])
|
|
433
|
-
return True, "Invalid task cmd! Help: task list / kill <taskID> / show <taskID>"
|
|
434
|
-
# [2] Start async task, postfix: &, &&
|
|
435
|
-
if arg_len > 2 and '&' in arg_list[-1]:
|
|
436
|
-
# Evaluate task mode: loop + delay
|
|
437
|
-
mode = arg_list.pop(-1)
|
|
438
|
-
loop = mode.count('&') == 2
|
|
439
|
-
delay = mode.replace('&', '').strip()
|
|
440
|
-
delay = int(delay) if delay.isdigit() else None
|
|
441
|
-
# Create and start async lm task
|
|
442
|
-
try:
|
|
443
|
-
state = Manager.create_task(arg_list, loop=loop, delay=delay)
|
|
444
|
-
except Exception as e:
|
|
445
|
-
# Valid & handled task command
|
|
446
|
-
return True, str(e)
|
|
447
|
-
tag = '.'.join(arg_list[0:2])
|
|
468
|
+
# [1] Async "background" task execution, postfix: &, &&
|
|
469
|
+
if len(arg_list) > 2 and '&' in arg_list[-1]:
|
|
470
|
+
# Evaluate task mode: loop + delay
|
|
471
|
+
mode = arg_list.pop(-1)
|
|
472
|
+
loop = mode.count('&') == 2
|
|
473
|
+
delay = mode.replace('&', '').strip()
|
|
474
|
+
delay = int(delay) if delay.isdigit() else None
|
|
475
|
+
# Create and start async lm task
|
|
476
|
+
try:
|
|
477
|
+
state = Manager.create_task(arg_list, loop=loop, delay=delay)
|
|
478
|
+
except Exception as e:
|
|
448
479
|
# Valid & handled task command
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
# modules built-in function: show loaded LoadModules
|
|
457
|
-
arg_len = len(arg_list)
|
|
458
|
-
if arg_len > 0 and arg_list[0] == 'modules':
|
|
459
|
-
return True, list((m.strip().replace('LM_', '') for m in modules if m.startswith('LM_'))) + ['task']
|
|
460
|
-
# [1] Run task command: start (&), list, kill, show
|
|
461
|
-
is_task, out = _exec_task()
|
|
462
|
-
if is_task:
|
|
463
|
-
return True, out
|
|
480
|
+
return True, str(e)
|
|
481
|
+
tag = '.'.join(arg_list[0:2])
|
|
482
|
+
# Valid & handled task command
|
|
483
|
+
if state:
|
|
484
|
+
return True, f"Start {tag}"
|
|
485
|
+
return True, f"{tag} is Busy"
|
|
486
|
+
|
|
464
487
|
# [2] Sync "realtime" task execution
|
|
465
|
-
state, out = _exec_lm_core(arg_list)
|
|
488
|
+
state, out = _exec_lm_core(arg_list, jsonify)
|
|
466
489
|
return state, out
|
|
467
490
|
|
|
468
491
|
|
|
469
|
-
def _exec_lm_core(cmd_list):
|
|
492
|
+
def _exec_lm_core(cmd_list, jsonify):
|
|
470
493
|
"""
|
|
471
494
|
[CORE] Single command executor: MODULE.FUNCTION...
|
|
472
495
|
:param cmd_list: list of string parameters
|
|
473
496
|
[1] module name (LM)
|
|
474
497
|
[2] function
|
|
475
498
|
[3...] parameters (separator: space)
|
|
476
|
-
|
|
499
|
+
:param jsonify: request json output
|
|
477
500
|
Return Bool(OK/NOK), STR(Command output)
|
|
478
501
|
"""
|
|
479
502
|
|
|
480
|
-
def
|
|
503
|
+
def _func_params(param):
|
|
481
504
|
buf = None
|
|
482
505
|
if "'" in param or '"' in param:
|
|
483
506
|
str_index = [i for i, c in enumerate(param) if c in ('"', "'")]
|
|
@@ -489,12 +512,9 @@ def _exec_lm_core(cmd_list):
|
|
|
489
512
|
param = param.format(*buf)
|
|
490
513
|
return param
|
|
491
514
|
|
|
492
|
-
# Check json mode for LM execution
|
|
493
|
-
json_mode = cmd_list[-1] == '>json'
|
|
494
|
-
cmd_list = cmd_list[0:-1] if json_mode else cmd_list
|
|
495
515
|
# LoadModule execution
|
|
496
516
|
if len(cmd_list) >= 2:
|
|
497
|
-
lm_mod, lm_func, lm_params = f"LM_{cmd_list[0]}", cmd_list[1],
|
|
517
|
+
lm_mod, lm_func, lm_params = f"LM_{cmd_list[0]}", cmd_list[1], _func_params(' '.join(cmd_list[2:]))
|
|
498
518
|
try:
|
|
499
519
|
# ------------- LM LOAD & EXECUTE ------------- #
|
|
500
520
|
# [1] LOAD MODULE - OPTIMIZED by sys.modules
|
|
@@ -516,11 +536,11 @@ def _exec_lm_core(cmd_list):
|
|
|
516
536
|
# Handle LM output data
|
|
517
537
|
if isinstance(lm_output, dict):
|
|
518
538
|
# json True: output->json else Format dict output "human readable"
|
|
519
|
-
lm_output = dumps(lm_output) if
|
|
539
|
+
lm_output = dumps(lm_output) if jsonify else '\n'.join(
|
|
520
540
|
[f" {key}: {value}" for key, value in lm_output.items()])
|
|
521
541
|
if lm_func == 'help':
|
|
522
542
|
# Special case for help command: json True: output->json else Format dict output "human readable"
|
|
523
|
-
lm_output = dumps(lm_output) if
|
|
543
|
+
lm_output = dumps(lm_output) if jsonify else '\n'.join([f" {out}," for out in lm_output])
|
|
524
544
|
# Return LM exec result
|
|
525
545
|
return True, str(lm_output)
|
|
526
546
|
# ---------------------------------------------------------------------- #
|
|
@@ -540,7 +560,7 @@ def lm_is_loaded(lm_name):
|
|
|
540
560
|
[Auth mode]
|
|
541
561
|
Check lm_name in enabled modules
|
|
542
562
|
"""
|
|
543
|
-
static_keywords =
|
|
563
|
+
static_keywords = ('task', 'modules')
|
|
544
564
|
loaded_mods = [lm.replace('LM_', '') for lm in modules if lm.startswith('LM_')]
|
|
545
565
|
return lm_name in static_keywords or lm_name in loaded_mods
|
|
546
566
|
|
|
@@ -573,7 +593,7 @@ def exec_lm_pipe(taskstr):
|
|
|
573
593
|
|
|
574
594
|
def exec_lm_pipe_schedule(taskstr):
|
|
575
595
|
"""
|
|
576
|
-
Scheduled Wrapper for exec_lm_pipe for IRQs (extIRQ, timIRQ)
|
|
596
|
+
Scheduled Wrapper for exec_lm_pipe for IRQs (extIRQ, timIRQ, cronIRQ)
|
|
577
597
|
"""
|
|
578
598
|
try:
|
|
579
599
|
schedule(exec_lm_pipe, taskstr)
|
|
@@ -581,15 +601,3 @@ def exec_lm_pipe_schedule(taskstr):
|
|
|
581
601
|
except Exception as e:
|
|
582
602
|
errlog_add(f"[ERR] exec_lm_pipe_schedule: {e}")
|
|
583
603
|
return False
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
def exec_lm_core_schedule(arg_list):
|
|
587
|
-
"""
|
|
588
|
-
Scheduled Wrapper for lm_exec for cron IRQ
|
|
589
|
-
"""
|
|
590
|
-
try:
|
|
591
|
-
schedule(lm_exec, arg_list)
|
|
592
|
-
return True
|
|
593
|
-
except Exception as e:
|
|
594
|
-
errlog_add(f"[ERR] schedule_lm_exec {arg_list}: {e}")
|
|
595
|
-
return False
|
micrOS/source/Types.py
CHANGED
|
@@ -70,8 +70,12 @@ def _generate(type_dict, help_msg):
|
|
|
70
70
|
overwrite[value_type] = values
|
|
71
71
|
valid_params.append(param_str)
|
|
72
72
|
else:
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
if p.startswith("&"):
|
|
74
|
+
# Handle special use case - task postfix
|
|
75
|
+
valid_params.append(p)
|
|
76
|
+
else:
|
|
77
|
+
param_str = f'{p}=:{"range" if "range" in type_dict else "options"}:'
|
|
78
|
+
valid_params.append(param_str)
|
|
75
79
|
type_dict['lm_call'] = f"{func} {' '.join(valid_params)}"
|
|
76
80
|
return dumps(type_dict | overwrite)
|
|
77
81
|
|
micrOS/source/Web.py
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module is responsible for webserver environment
|
|
3
|
+
dedicated to micrOS framework.
|
|
4
|
+
Built-in-function:
|
|
5
|
+
- response
|
|
6
|
+
- landing page: index.html
|
|
7
|
+
- rest/ - call load modules, e.x.: system/top
|
|
8
|
+
- file response (.html, .css, .js, .jped) - generic file server feature
|
|
9
|
+
- "virtual" endpoints - to reply from script on a defined endpoint
|
|
10
|
+
- stream - stream data (jpeg) function
|
|
11
|
+
|
|
12
|
+
Designed by Marcell Ban aka BxNxM
|
|
13
|
+
"""
|
|
14
|
+
|
|
1
15
|
from json import dumps, loads
|
|
2
16
|
import uasyncio as asyncio
|
|
3
17
|
from Tasks import lm_exec, NativeTask, lm_is_loaded
|
|
@@ -60,9 +74,22 @@ class WebEngine:
|
|
|
60
74
|
try:
|
|
61
75
|
# SEND RESOURCE CONTENT: HTML, JS, CSS
|
|
62
76
|
with open(resource, 'r') as file:
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
77
|
+
data = file.read()
|
|
78
|
+
response = self.REQ200.format(dtype=WebEngine.file_type(resource), len=len(data), data=data)
|
|
79
|
+
# Send entire response data
|
|
80
|
+
await self.client.a_send(response)
|
|
81
|
+
|
|
82
|
+
# Send chunks of response data (experimental)
|
|
83
|
+
#response_len, chunk_size, position = len(response), 300, 0
|
|
84
|
+
#while position < response_len:
|
|
85
|
+
# # Calculate the size of the next chunk
|
|
86
|
+
# next_chunk_size = min(chunk_size, response_len - position)
|
|
87
|
+
# chunk = response[position:position + next_chunk_size]
|
|
88
|
+
# await self.client.a_send(chunk)
|
|
89
|
+
# position += next_chunk_size
|
|
90
|
+
except Exception as e:
|
|
91
|
+
if 'memory allocation failed' in str(e):
|
|
92
|
+
errlog_add(f"[ERR] WebCli {resource}: {e}")
|
|
66
93
|
await self.client.a_send(self.REQ404.format(len=13, data='404 Not Found'))
|
|
67
94
|
return
|
|
68
95
|
# INVALID/BAD REQUEST
|
|
@@ -76,14 +103,11 @@ class WebEngine:
|
|
|
76
103
|
# REST sub-parameter handling (rest commands)
|
|
77
104
|
cmd = (cmd.replace('/', ' ').replace('%22', '"').replace('%E2%80%9C', '"')
|
|
78
105
|
.replace('%E2%80%9D', '"').replace('-', ' ').strip().split())
|
|
79
|
-
# request json format instead of default string output (+ handle & tasks syntax)
|
|
80
|
-
cmd.insert(-1, '>json') if cmd[-1].startswith('&') else cmd.append('>json')
|
|
81
106
|
# EXECUTE COMMAND - LoadModule
|
|
82
107
|
if WebEngine.AUTH:
|
|
83
|
-
state, out = lm_exec(cmd) if lm_is_loaded(cmd[0])
|
|
84
|
-
True, 'Auth:Protected')
|
|
108
|
+
state, out = lm_exec(cmd, jsonify=True) if lm_is_loaded(cmd[0]) else (True, 'Auth:Protected')
|
|
85
109
|
else:
|
|
86
|
-
state, out = lm_exec(cmd)
|
|
110
|
+
state, out = lm_exec(cmd, jsonify=True)
|
|
87
111
|
try:
|
|
88
112
|
resp_schema['result'] = loads(out) # Load again ... hack for embedded shell json converter...
|
|
89
113
|
except:
|
micrOS/source/dashboard.html
CHANGED
|
@@ -31,10 +31,10 @@
|
|
|
31
31
|
transition: border-color 0.3s ease; /* Smooth transition for border color */
|
|
32
32
|
}
|
|
33
33
|
</style>
|
|
34
|
-
<script src="uapi.js"
|
|
35
|
-
<script src="uwidgets.js"
|
|
36
|
-
<script src="uwidgets_pro.js"
|
|
37
|
-
<script src="udashboard.js"
|
|
34
|
+
<script src="uapi.js" ></script>
|
|
35
|
+
<script src="uwidgets.js" ></script>
|
|
36
|
+
<script src="uwidgets_pro.js" ></script>
|
|
37
|
+
<script src="udashboard.js" ></script>
|
|
38
38
|
</head>
|
|
39
39
|
<body>
|
|
40
40
|
<h1> micrOS dashboard </h1>
|
micrOS/source/micrOS.py
CHANGED
|
@@ -20,15 +20,6 @@ from Debug import errlog_add
|
|
|
20
20
|
# INTERRUPT HANDLER INTERFACES / WRAPPERS #
|
|
21
21
|
#################################################################
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
def safe_boot():
|
|
25
|
-
try:
|
|
26
|
-
bootup()
|
|
27
|
-
except Exception as e:
|
|
28
|
-
print(f"[micrOS main] Hooks.boot() error: {e}")
|
|
29
|
-
errlog_add(f"[ERR] safe_boot: {e}")
|
|
30
|
-
|
|
31
|
-
|
|
32
23
|
def irq_handler():
|
|
33
24
|
try:
|
|
34
25
|
enableInterrupt()
|
|
@@ -58,7 +49,11 @@ def micrOS():
|
|
|
58
49
|
aio = Manager()
|
|
59
50
|
|
|
60
51
|
# BOOT TASKS: Initial LM executions
|
|
61
|
-
|
|
52
|
+
try:
|
|
53
|
+
bootup()
|
|
54
|
+
except Exception as e:
|
|
55
|
+
print(f"[micrOS main] Hooks.boot() error: {e}")
|
|
56
|
+
errlog_add(f"[ERR] safe_boot: {e}")
|
|
62
57
|
|
|
63
58
|
# NETWORK setup
|
|
64
59
|
nwmd = auto_nw_config()
|
micrOS/source/micrOSloader.py
CHANGED
|
@@ -14,11 +14,12 @@ except:
|
|
|
14
14
|
try:
|
|
15
15
|
from Debug import errlog_add
|
|
16
16
|
except Exception as e:
|
|
17
|
-
print(f"Import error: {e}")
|
|
17
|
+
print(f"[loader] Import error: {e}")
|
|
18
18
|
errlog_add = None
|
|
19
|
+
from machine import reset
|
|
19
20
|
|
|
20
21
|
|
|
21
|
-
def
|
|
22
|
+
def _is_micrOS():
|
|
22
23
|
"""
|
|
23
24
|
Recovery mode for OTA update in case of connection/transfer failure
|
|
24
25
|
.if_mode can have 2 possible values: webrepl or micros (strings)
|
|
@@ -34,7 +35,6 @@ def __is_micrOS():
|
|
|
34
35
|
False -> webrepl
|
|
35
36
|
* EOE (EndOfExecution) -> off
|
|
36
37
|
"""
|
|
37
|
-
mode = 'micros'
|
|
38
38
|
try:
|
|
39
39
|
with open('.if_mode', 'r') as f:
|
|
40
40
|
mode = f.read().strip().lower()
|
|
@@ -54,7 +54,6 @@ def __is_micrOS():
|
|
|
54
54
|
exit(0)
|
|
55
55
|
# start webrepl
|
|
56
56
|
print("[loader][if_mode:False] .if_mode:webrepl -> webrepl interface")
|
|
57
|
-
print("[loader][recovery mode] - manually selected in .if_mode file")
|
|
58
57
|
return False
|
|
59
58
|
|
|
60
59
|
|
|
@@ -71,7 +70,14 @@ def __recovery_mode():
|
|
|
71
70
|
import webrepl
|
|
72
71
|
webrepl.start(password=pwd)
|
|
73
72
|
except Exception as e:
|
|
74
|
-
|
|
73
|
+
if callable(errlog_add):
|
|
74
|
+
errlog_add(f"[ERR][micrOSloader] webrepl failed: {e}")
|
|
75
|
+
print("[loader] Reset .if_mode to micros and reboot")
|
|
76
|
+
with open('.if_mode', 'w') as f:
|
|
77
|
+
f.write("micros")
|
|
78
|
+
# Reboot machine
|
|
79
|
+
reset()
|
|
80
|
+
|
|
75
81
|
|
|
76
82
|
|
|
77
83
|
def __auto_restart_event():
|
|
@@ -82,10 +88,6 @@ def __auto_restart_event():
|
|
|
82
88
|
- value: micros [update was successful - reboot is necessary]
|
|
83
89
|
:return:
|
|
84
90
|
"""
|
|
85
|
-
from sys import platform
|
|
86
|
-
if platform == 'rp2':
|
|
87
|
-
print("[loader][ota-rebooter] SKIP on platform: rp2 (webrepl block)")
|
|
88
|
-
return
|
|
89
91
|
|
|
90
92
|
from utime import sleep
|
|
91
93
|
trigger_is_active = False
|
|
@@ -93,7 +95,7 @@ def __auto_restart_event():
|
|
|
93
95
|
# Wait after webrepl started for possible ota updates (~3s*5= 15sec)
|
|
94
96
|
while wait_update_tout > 0:
|
|
95
97
|
# Wait for micros turns to webrepl until timeout
|
|
96
|
-
if
|
|
98
|
+
if _is_micrOS():
|
|
97
99
|
# micrOS mode
|
|
98
100
|
print(f"[loader][ota-rebooter][micros][{wait_update_tout}] Wait for OTA update possible start")
|
|
99
101
|
wait_update_tout -= 1
|
|
@@ -102,19 +104,18 @@ def __auto_restart_event():
|
|
|
102
104
|
# Set trigger - if_mode changed to webrepl - ota update started - trigger wait
|
|
103
105
|
trigger_is_active = True
|
|
104
106
|
# Restart if trigger was activated
|
|
105
|
-
if trigger_is_active and
|
|
107
|
+
if trigger_is_active and _is_micrOS():
|
|
106
108
|
print("[loader][ota-rebooter][micros][trigger: True] OTA was finished - reboot")
|
|
107
109
|
# Create cleanup indicator file for ConfigHandler
|
|
108
110
|
with open('cleanup.pds', 'w') as f:
|
|
109
111
|
f.write('')
|
|
110
112
|
# Reboot machine
|
|
111
|
-
from machine import reset
|
|
112
113
|
reset()
|
|
113
114
|
sleep(3)
|
|
114
115
|
|
|
115
116
|
|
|
116
117
|
def main():
|
|
117
|
-
if
|
|
118
|
+
if _is_micrOS():
|
|
118
119
|
# Main mode
|
|
119
120
|
try:
|
|
120
121
|
print("[loader][main mode] Start micrOS (default)")
|
|
@@ -126,11 +127,8 @@ def main():
|
|
|
126
127
|
# Handle micrOS system crash (never happened...but) -> webrepl mode default pwd: ADmin123
|
|
127
128
|
print(f"[loader][main mode] micrOS start failed: {e}")
|
|
128
129
|
print("[loader][main mode] -> [recovery mode]")
|
|
129
|
-
if errlog_add
|
|
130
|
-
|
|
131
|
-
errlog_add(f"[ERR][micrOSloader] start failed: {e}")
|
|
132
|
-
except:
|
|
133
|
-
pass
|
|
130
|
+
if callable(errlog_add):
|
|
131
|
+
errlog_add(f"[ERR][micrOSloader] start failed: {e}")
|
|
134
132
|
# Recovery aka webrepl mode
|
|
135
133
|
__recovery_mode()
|
|
136
134
|
__auto_restart_event()
|
micrOS/source/uapi.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
3
|
-
const
|
|
1
|
+
// CORE MICROS BACKEND INTERFACE
|
|
2
|
+
|
|
3
|
+
const BASE_URL = `http://${window.location.hostname}${window.location.port ? `:${window.location.port}` : ""}`;
|
|
4
4
|
|
|
5
5
|
function restAPICore(cmd, timeout=5000) {
|
|
6
|
-
const query =
|
|
6
|
+
const query = `${BASE_URL}/rest/${cmd.trim().replace(/\s+/g, '/')}`;
|
|
7
7
|
const controller = new AbortController();
|
|
8
8
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
9
9
|
const startTime = performance.now();
|
|
@@ -59,5 +59,4 @@ function restInfo() {
|
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
//
|
|
63
|
-
// restInfo();
|
|
62
|
+
// Designed by BxNxM |/|/|/|/
|