micrOSDevToolKit 2.1.5__py3-none-any.whl → 2.26.1__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.
Files changed (400) hide show
  1. env/driver_cp210x/.DS_Store +0 -0
  2. env/driver_cp210x/macOS_VCP_Driver/SiLabsUSBDriverDisk.dmg +0 -0
  3. env/driver_cp210x/macOS_VCP_Driver/macOS_VCP_Driver_Release_Notes.txt +17 -1
  4. micrOS/micropython/esp32-20251209-v1.27.0.bin +0 -0
  5. micrOS/micropython/esp32c3-20251209-v1.27.0.bin +0 -0
  6. micrOS/micropython/esp32c6-20251209-v1.27.0.bin +0 -0
  7. micrOS/micropython/esp32s2-20251209-v1.27.0.bin +0 -0
  8. micrOS/micropython/esp32s2-LOLIN_MINI-20251209-v1.27.0.bin +0 -0
  9. micrOS/micropython/esp32s3-4MBflash-20241129-v1.24.1.bin +0 -0
  10. micrOS/micropython/esp32s3-8MBflash-20251209-v1.27.0.bin +0 -0
  11. micrOS/micropython/esp32s3_spiram_oct-20251209-v1.27.0.bin +0 -0
  12. micrOS/micropython/rpi-pico-w-20251209-v1.27.0.uf2 +0 -0
  13. micrOS/micropython/tinypico-20251209-v1.27.0.bin +0 -0
  14. micrOS/release_info/micrOS_ReleaseInfo/system_analysis_sum.json +191 -151
  15. micrOS/source/Auth.py +37 -0
  16. micrOS/source/Common.py +376 -102
  17. micrOS/source/Config.py +55 -25
  18. micrOS/source/Debug.py +54 -193
  19. micrOS/source/Espnow.py +404 -0
  20. micrOS/source/Files.py +207 -0
  21. micrOS/source/Hooks.py +88 -16
  22. micrOS/source/InterConnect.py +130 -46
  23. micrOS/source/Interrupts.py +8 -8
  24. micrOS/source/Logger.py +131 -0
  25. micrOS/source/Network.py +41 -21
  26. micrOS/source/Notify.py +74 -198
  27. micrOS/source/Pacman.py +326 -0
  28. micrOS/source/Scheduler.py +18 -55
  29. micrOS/source/Server.py +84 -217
  30. micrOS/source/Shell.py +103 -93
  31. micrOS/source/Tasks.py +239 -173
  32. micrOS/source/Time.py +21 -22
  33. micrOS/source/Types.py +89 -54
  34. micrOS/source/Web.py +485 -0
  35. micrOS/source/__pycache__/Common.cpython-312.pyc +0 -0
  36. micrOS/source/__pycache__/Debug.cpython-312.pyc +0 -0
  37. micrOS/source/__pycache__/Files.cpython-312.pyc +0 -0
  38. micrOS/source/__pycache__/Logger.cpython-312.pyc +0 -0
  39. micrOS/source/__pycache__/Scheduler.cpython-312.pyc +0 -0
  40. micrOS/source/__pycache__/Server.cpython-312.pyc +0 -0
  41. micrOS/source/__pycache__/Shell.cpython-312.pyc +0 -0
  42. micrOS/source/__pycache__/replhelper.cpython-312.pyc +0 -0
  43. micrOS/source/helpers.py +132 -0
  44. micrOS/source/micrOS.py +25 -21
  45. micrOS/source/micrOSloader.py +14 -23
  46. micrOS/source/microIO.py +94 -57
  47. toolkit/simulator_lib/LP_darwin.py → micrOS/source/modules/IO_esp32.py +22 -11
  48. micrOS/source/{IO_esp32c3.py → modules/IO_esp32c3.py} +6 -1
  49. micrOS/source/modules/IO_esp32c6.py +38 -0
  50. micrOS/source/{IO_esp32s2.py → modules/IO_esp32s2.py} +6 -1
  51. micrOS/source/{IO_esp32s3.py → modules/IO_esp32s3.py} +43 -2
  52. micrOS/source/modules/IO_m5stamp.py +86 -0
  53. micrOS/source/{IO_qtpy.py → modules/IO_qtpy.py} +28 -18
  54. micrOS/source/{IO_tinypico.py → modules/IO_tinypico.py} +48 -3
  55. micrOS/source/modules/LM_L298N.py +161 -0
  56. {toolkit/workspace/precompiled → micrOS/source/modules}/LM_L9110_DCmotor.py +4 -4
  57. micrOS/source/{LM_OV2640.py → modules/LM_OV2640.py} +53 -42
  58. micrOS/source/{LM_VL53L0X.py → modules/LM_VL53L0X.py} +5 -5
  59. micrOS/source/{LM_aht10.py → modules/LM_aht10.py} +12 -4
  60. micrOS/source/{LM_bme280.py → modules/LM_bme280.py} +13 -25
  61. micrOS/source/{LM_buzzer.py → modules/LM_buzzer.py} +42 -40
  62. micrOS/source/{LM_cct.py → modules/LM_cct.py} +22 -27
  63. micrOS/source/modules/LM_cluster.py +255 -0
  64. micrOS/source/{LM_co2.py → modules/LM_co2.py} +13 -6
  65. micrOS/source/{LM_dht11.py → modules/LM_dht11.py} +13 -29
  66. micrOS/source/{LM_dht22.py → modules/LM_dht22.py} +13 -28
  67. micrOS/source/{LM_dimmer.py → modules/LM_dimmer.py} +19 -16
  68. micrOS/source/modules/LM_distance.py +135 -0
  69. micrOS/source/{LM_ds18.py → modules/LM_ds18.py} +12 -4
  70. micrOS/source/{LM_esp32.py → modules/LM_esp32.py} +16 -4
  71. micrOS/source/modules/LM_espnow.py +53 -0
  72. micrOS/source/modules/LM_fileserver.py +265 -0
  73. micrOS/source/{LM_gameOfLife.py → modules/LM_gameOfLife.py} +5 -5
  74. micrOS/source/{LM_genIO.py → modules/LM_genIO.py} +49 -35
  75. micrOS/source/modules/LM_haptic.py +111 -0
  76. micrOS/source/modules/LM_i2c.py +61 -0
  77. micrOS/source/{LM_i2s_mic.py → modules/LM_i2s_mic.py} +20 -23
  78. micrOS/source/{LM_ld2410.py → modules/LM_ld2410.py} +3 -3
  79. micrOS/source/{LM_light_sensor.py → modules/LM_light_sensor.py} +22 -26
  80. micrOS/source/modules/LM_mh_z19c.py +198 -0
  81. micrOS/source/modules/LM_neoeffects.py +284 -0
  82. micrOS/source/{LM_neopixel.py → modules/LM_neopixel.py} +26 -31
  83. micrOS/source/{LM_oled.py → modules/LM_oled.py} +28 -20
  84. micrOS/source/{LM_oled_sh1106.py → modules/LM_oled_sh1106.py} +28 -24
  85. micrOS/source/{LM_oled_ui.py → modules/LM_oled_ui.py} +132 -174
  86. micrOS/source/modules/LM_pacman.py +320 -0
  87. micrOS/source/{LM_presence.py → modules/LM_presence.py} +24 -36
  88. micrOS/source/modules/LM_qmi8658.py +204 -0
  89. micrOS/source/{LM_rencoder.py → modules/LM_rencoder.py} +40 -11
  90. micrOS/source/modules/LM_rest.py +81 -0
  91. micrOS/source/{LM_rgb.py → modules/LM_rgb.py} +25 -34
  92. micrOS/source/{LM_rgbcct.py → modules/LM_rgbcct.py} +5 -5
  93. micrOS/source/{LM_roboarm.py → modules/LM_roboarm.py} +37 -45
  94. micrOS/source/modules/LM_robustness.py +137 -0
  95. micrOS/source/{LM_rp2w.py → modules/LM_rp2w.py} +3 -0
  96. micrOS/source/{LM_sdcard.py → modules/LM_sdcard.py} +3 -0
  97. micrOS/source/{LM_servo.py → modules/LM_servo.py} +4 -4
  98. micrOS/source/modules/LM_sound_event.py +751 -0
  99. micrOS/source/{LM_stepper.py → modules/LM_stepper.py} +8 -8
  100. micrOS/source/{LM_switch.py → modules/LM_switch.py} +21 -18
  101. micrOS/source/{LM_system.py → modules/LM_system.py} +96 -59
  102. micrOS/source/modules/LM_tcs3472.py +187 -0
  103. micrOS/source/modules/LM_telegram.py +388 -0
  104. micrOS/source/modules/LM_trackball.py +287 -0
  105. micrOS/source/modules/LM_veml7700.py +159 -0
  106. micrOS/source/modules/LM_web.py +38 -0
  107. micrOS/source/urequests.py +204 -91
  108. {toolkit/workspace/precompiled → micrOS/source/web}/dashboard.html +9 -4
  109. micrOS/source/web/editor.js +440 -0
  110. micrOS/source/web/filesui.html +178 -0
  111. micrOS/source/web/filesui.js +338 -0
  112. micrOS/source/{index.html → web/index.html} +44 -2
  113. micrOS/source/web/uapi.js +103 -0
  114. micrOS/source/web/udashboard.js +129 -0
  115. micrOS/source/web/ustyle.css +55 -0
  116. micrOS/source/web/uwidgets.js +172 -0
  117. micrOS/source/web/uwidgets_pro.js +99 -0
  118. micrOS/utests/__init__.py +0 -0
  119. micrOS/utests/test_scheduler.py +435 -0
  120. {micrOSDevToolKit-2.1.5.data → microsdevtoolkit-2.26.1.data}/scripts/devToolKit.py +47 -4
  121. {micrOSDevToolKit-2.1.5.dist-info → microsdevtoolkit-2.26.1.dist-info}/METADATA +392 -279
  122. microsdevtoolkit-2.26.1.dist-info/RECORD +396 -0
  123. {micrOSDevToolKit-2.1.5.dist-info → microsdevtoolkit-2.26.1.dist-info}/WHEEL +1 -1
  124. toolkit/DevEnvCompile.py +63 -33
  125. toolkit/DevEnvOTA.py +72 -22
  126. toolkit/DevEnvUSB.py +147 -77
  127. toolkit/Gateway.py +9 -9
  128. toolkit/LM_to_compile.dat +12 -4
  129. toolkit/MicrOSDevEnv.py +129 -51
  130. toolkit/WebRepl.py +73 -0
  131. toolkit/dashboard_apps/BackupRestore.py +171 -0
  132. toolkit/dashboard_apps/CCTDemo.py +12 -17
  133. toolkit/dashboard_apps/CCTTest.py +20 -24
  134. toolkit/dashboard_apps/CamStream.py +2 -6
  135. toolkit/dashboard_apps/CatGame.py +14 -16
  136. toolkit/dashboard_apps/Dimmer.py +11 -21
  137. toolkit/dashboard_apps/GetVersion.py +11 -19
  138. toolkit/dashboard_apps/MicrophoneTest.py +2 -7
  139. toolkit/dashboard_apps/NeoEffectsDemo.py +22 -35
  140. toolkit/dashboard_apps/NeopixelTest.py +20 -25
  141. toolkit/dashboard_apps/PresenceTest.py +2 -8
  142. toolkit/dashboard_apps/QMI8685_GYRO.py +68 -0
  143. toolkit/dashboard_apps/RGBTest.py +20 -24
  144. toolkit/dashboard_apps/RoboArm.py +24 -32
  145. toolkit/dashboard_apps/SED_test.py +10 -14
  146. toolkit/dashboard_apps/SensorsTest.py +61 -0
  147. toolkit/dashboard_apps/SystemTest.py +219 -117
  148. toolkit/dashboard_apps/Template_app.py +12 -19
  149. toolkit/dashboard_apps/_app_base.py +34 -0
  150. toolkit/dashboard_apps/_gyro_visualizer.py +78 -0
  151. toolkit/dashboard_apps/uLightDemo.py +15 -24
  152. toolkit/index.html +6 -5
  153. toolkit/lib/LocalMachine.py +6 -1
  154. toolkit/lib/MicrosFiles.py +46 -0
  155. toolkit/lib/Repository.py +64 -0
  156. toolkit/lib/TerminalColors.py +4 -0
  157. toolkit/lib/macroScript.py +371 -0
  158. toolkit/lib/micrOSClient.py +124 -51
  159. toolkit/lib/micrOSClientHistory.py +156 -0
  160. toolkit/lib/pip_package_installer.py +31 -4
  161. toolkit/micrOSdashboard.py +16 -21
  162. toolkit/micrOSlint.py +28 -10
  163. toolkit/simulator_lib/.DS_Store +0 -0
  164. micrOS/source/IO_esp32.py → toolkit/simulator_lib/IO_darwin.py +3 -0
  165. toolkit/simulator_lib/__pycache__/IO_darwin.cpython-312.pyc +0 -0
  166. toolkit/simulator_lib/__pycache__/aioespnow.cpython-312.pyc +0 -0
  167. toolkit/simulator_lib/__pycache__/camera.cpython-312.pyc +0 -0
  168. toolkit/simulator_lib/__pycache__/framebuf.cpython-312.pyc +0 -0
  169. toolkit/simulator_lib/__pycache__/machine.cpython-312.pyc +0 -0
  170. toolkit/simulator_lib/__pycache__/micropython.cpython-312.pyc +0 -0
  171. toolkit/simulator_lib/__pycache__/mip.cpython-312.pyc +0 -0
  172. toolkit/simulator_lib/__pycache__/neopixel.cpython-312.pyc +0 -0
  173. toolkit/simulator_lib/__pycache__/network.cpython-312.pyc +0 -0
  174. toolkit/simulator_lib/__pycache__/sim_common.cpython-312.pyc +0 -0
  175. toolkit/simulator_lib/__pycache__/simgc.cpython-312.pyc +0 -0
  176. toolkit/simulator_lib/__pycache__/simulator.cpython-312.pyc +0 -0
  177. toolkit/simulator_lib/__pycache__/uasyncio.cpython-312.pyc +0 -0
  178. toolkit/simulator_lib/__pycache__/uos.cpython-312.pyc +0 -0
  179. toolkit/simulator_lib/__pycache__/urandom.cpython-312.pyc +0 -0
  180. toolkit/simulator_lib/__pycache__/usocket.cpython-312.pyc +0 -0
  181. toolkit/simulator_lib/__pycache__/ussl.cpython-312.pyc +0 -0
  182. toolkit/simulator_lib/aioespnow.py +28 -0
  183. toolkit/simulator_lib/camera.py +84 -0
  184. toolkit/simulator_lib/dht.py +1 -1
  185. toolkit/simulator_lib/framebuf.py +49 -1
  186. toolkit/simulator_lib/machine.py +32 -2
  187. toolkit/simulator_lib/micropython.py +3 -3
  188. toolkit/simulator_lib/mip.py +165 -0
  189. toolkit/simulator_lib/neopixel.py +3 -2
  190. toolkit/simulator_lib/network.py +2 -1
  191. toolkit/simulator_lib/node_config.json +2 -3
  192. toolkit/simulator_lib/ntptime.py +1 -1
  193. toolkit/simulator_lib/{sim_console.py → sim_common.py} +2 -3
  194. toolkit/simulator_lib/simgc.py +6 -2
  195. toolkit/simulator_lib/simulator.py +138 -46
  196. toolkit/simulator_lib/uasyncio.py +34 -3
  197. toolkit/simulator_lib/uos.py +147 -0
  198. toolkit/simulator_lib/urandom.py +4 -0
  199. toolkit/simulator_lib/usocket.py +5 -1
  200. toolkit/simulator_lib/view01.jpg +0 -0
  201. toolkit/simulator_lib/view02.jpg +0 -0
  202. toolkit/socketClient.py +43 -23
  203. toolkit/user_data/webhooks/generic.py +1 -1
  204. toolkit/user_data/webhooks/macro.py +44 -0
  205. toolkit/user_data/webhooks/template.macro +20 -0
  206. toolkit/user_data/webhooks/template.py +1 -1
  207. toolkit/workspace/precompiled/Auth.mpy +0 -0
  208. toolkit/workspace/precompiled/Common.mpy +0 -0
  209. toolkit/workspace/precompiled/Config.mpy +0 -0
  210. toolkit/workspace/precompiled/Debug.mpy +0 -0
  211. toolkit/workspace/precompiled/Espnow.mpy +0 -0
  212. toolkit/workspace/precompiled/Files.mpy +0 -0
  213. toolkit/workspace/precompiled/Hooks.mpy +0 -0
  214. toolkit/workspace/precompiled/InterConnect.mpy +0 -0
  215. toolkit/workspace/precompiled/Interrupts.mpy +0 -0
  216. toolkit/workspace/precompiled/Logger.mpy +0 -0
  217. toolkit/workspace/precompiled/Network.mpy +0 -0
  218. toolkit/workspace/precompiled/Notify.mpy +0 -0
  219. toolkit/workspace/precompiled/Pacman.mpy +0 -0
  220. toolkit/workspace/precompiled/Scheduler.mpy +0 -0
  221. toolkit/workspace/precompiled/Server.mpy +0 -0
  222. toolkit/workspace/precompiled/Shell.mpy +0 -0
  223. toolkit/workspace/precompiled/Tasks.mpy +0 -0
  224. toolkit/workspace/precompiled/Time.mpy +0 -0
  225. toolkit/workspace/precompiled/Types.mpy +0 -0
  226. toolkit/workspace/precompiled/Web.mpy +0 -0
  227. toolkit/workspace/precompiled/_mpy.version +1 -1
  228. toolkit/workspace/precompiled/config/_git.keep +0 -0
  229. toolkit/workspace/precompiled/helpers.mpy +0 -0
  230. toolkit/workspace/precompiled/micrOS.mpy +0 -0
  231. toolkit/workspace/precompiled/micrOSloader.mpy +0 -0
  232. toolkit/workspace/precompiled/microIO.mpy +0 -0
  233. toolkit/workspace/precompiled/modules/IO_esp32.mpy +0 -0
  234. toolkit/workspace/precompiled/modules/IO_esp32c3.mpy +0 -0
  235. toolkit/workspace/precompiled/modules/IO_esp32c6.mpy +0 -0
  236. toolkit/workspace/precompiled/modules/IO_esp32s2.mpy +0 -0
  237. toolkit/workspace/precompiled/modules/IO_esp32s3.mpy +0 -0
  238. toolkit/workspace/precompiled/modules/IO_m5stamp.mpy +0 -0
  239. toolkit/workspace/precompiled/modules/IO_qtpy.mpy +0 -0
  240. toolkit/workspace/precompiled/modules/IO_rp2.mpy +0 -0
  241. toolkit/workspace/precompiled/modules/IO_tinypico.mpy +0 -0
  242. toolkit/workspace/precompiled/modules/LM_L298N.mpy +0 -0
  243. {micrOS/source → toolkit/workspace/precompiled/modules}/LM_L9110_DCmotor.py +4 -4
  244. toolkit/workspace/precompiled/modules/LM_OV2640.mpy +0 -0
  245. toolkit/workspace/precompiled/{LM_VL53L0X.py → modules/LM_VL53L0X.py} +5 -5
  246. toolkit/workspace/precompiled/modules/LM_aht10.mpy +0 -0
  247. toolkit/workspace/precompiled/modules/LM_bme280.mpy +0 -0
  248. toolkit/workspace/precompiled/{LM_buzzer.mpy → modules/LM_buzzer.mpy} +0 -0
  249. toolkit/workspace/precompiled/modules/LM_cct.mpy +0 -0
  250. toolkit/workspace/precompiled/modules/LM_cluster.mpy +0 -0
  251. toolkit/workspace/precompiled/modules/LM_co2.mpy +0 -0
  252. toolkit/workspace/precompiled/modules/LM_dht11.mpy +0 -0
  253. toolkit/workspace/precompiled/modules/LM_dht22.mpy +0 -0
  254. toolkit/workspace/precompiled/modules/LM_dimmer.mpy +0 -0
  255. toolkit/workspace/precompiled/modules/LM_distance.mpy +0 -0
  256. toolkit/workspace/precompiled/modules/LM_ds18.mpy +0 -0
  257. toolkit/workspace/precompiled/{LM_esp32.py → modules/LM_esp32.py} +16 -4
  258. toolkit/workspace/precompiled/modules/LM_espnow.py +53 -0
  259. toolkit/workspace/precompiled/modules/LM_fileserver.mpy +0 -0
  260. toolkit/workspace/precompiled/{LM_gameOfLife.mpy → modules/LM_gameOfLife.mpy} +0 -0
  261. toolkit/workspace/precompiled/modules/LM_genIO.mpy +0 -0
  262. toolkit/workspace/precompiled/modules/LM_haptic.mpy +0 -0
  263. toolkit/workspace/precompiled/modules/LM_i2c.py +61 -0
  264. toolkit/workspace/precompiled/modules/LM_i2s_mic.mpy +0 -0
  265. toolkit/workspace/precompiled/{LM_ld2410.mpy → modules/LM_ld2410.mpy} +0 -0
  266. toolkit/workspace/precompiled/modules/LM_light_sensor.mpy +0 -0
  267. toolkit/workspace/precompiled/modules/LM_mh_z19c.py +198 -0
  268. toolkit/workspace/precompiled/modules/LM_neoeffects.mpy +0 -0
  269. toolkit/workspace/precompiled/modules/LM_neopixel.mpy +0 -0
  270. toolkit/workspace/precompiled/modules/LM_oled.mpy +0 -0
  271. toolkit/workspace/precompiled/modules/LM_oled_sh1106.mpy +0 -0
  272. toolkit/workspace/precompiled/modules/LM_oled_ui.mpy +0 -0
  273. toolkit/workspace/precompiled/modules/LM_pacman.mpy +0 -0
  274. toolkit/workspace/precompiled/modules/LM_presence.mpy +0 -0
  275. toolkit/workspace/precompiled/modules/LM_qmi8658.py +204 -0
  276. toolkit/workspace/precompiled/{LM_rencoder.py → modules/LM_rencoder.py} +40 -11
  277. toolkit/workspace/precompiled/modules/LM_rest.mpy +0 -0
  278. toolkit/workspace/precompiled/modules/LM_rgb.mpy +0 -0
  279. toolkit/workspace/precompiled/{LM_rgbcct.mpy → modules/LM_rgbcct.mpy} +0 -0
  280. toolkit/workspace/precompiled/modules/LM_roboarm.mpy +0 -0
  281. toolkit/workspace/precompiled/modules/LM_robustness.py +137 -0
  282. toolkit/workspace/precompiled/{LM_rp2w.py → modules/LM_rp2w.py} +3 -0
  283. toolkit/workspace/precompiled/{LM_sdcard.py → modules/LM_sdcard.py} +3 -0
  284. toolkit/workspace/precompiled/{LM_servo.mpy → modules/LM_servo.mpy} +0 -0
  285. toolkit/workspace/precompiled/modules/LM_sound_event.mpy +0 -0
  286. toolkit/workspace/precompiled/{LM_stepper.mpy → modules/LM_stepper.mpy} +0 -0
  287. toolkit/workspace/precompiled/modules/LM_switch.mpy +0 -0
  288. toolkit/workspace/precompiled/modules/LM_system.mpy +0 -0
  289. toolkit/workspace/precompiled/modules/LM_tcs3472.py +187 -0
  290. toolkit/workspace/precompiled/modules/LM_telegram.mpy +0 -0
  291. toolkit/workspace/precompiled/{LM_tinyrgb.mpy → modules/LM_tinyrgb.mpy} +0 -0
  292. toolkit/workspace/precompiled/modules/LM_trackball.mpy +0 -0
  293. toolkit/workspace/precompiled/modules/LM_veml7700.mpy +0 -0
  294. toolkit/workspace/precompiled/modules/LM_web.mpy +0 -0
  295. toolkit/workspace/precompiled/urequests.mpy +0 -0
  296. {micrOS/source → toolkit/workspace/precompiled/web}/dashboard.html +9 -4
  297. toolkit/workspace/precompiled/web/editor.js +440 -0
  298. toolkit/workspace/precompiled/web/filesui.html +178 -0
  299. toolkit/workspace/precompiled/web/filesui.js +338 -0
  300. toolkit/workspace/precompiled/{index.html → web/index.html} +44 -2
  301. toolkit/workspace/precompiled/web/uapi.js +103 -0
  302. toolkit/workspace/precompiled/web/udashboard.js +129 -0
  303. toolkit/workspace/precompiled/web/ustyle.css +55 -0
  304. toolkit/workspace/precompiled/web/uwidgets.js +172 -0
  305. toolkit/workspace/precompiled/web/uwidgets_pro.js +99 -0
  306. env/driver_cp210x/CH34XSER_MAC/CH34X_DRV_INSTALL_INSTRUCTIONS.pdf +0 -0
  307. env/driver_cp210x/CH34XSER_MAC/CH34xVCPDriver.pkg +0 -0
  308. micrOS/micropython/esp32-20231005-v1.21.0.bin +0 -0
  309. micrOS/micropython/esp32c3-GENERIC-20240105-v1.22.1.bin +0 -0
  310. micrOS/micropython/esp32c3-GENERIC-20240222-v1.22.2.bin +0 -0
  311. micrOS/micropython/esp32s2-GENERIC-20240105-v1.22.1.bin +0 -0
  312. micrOS/micropython/esp32s2-LOLIN_MINI-20220618-v1.19.1.bin +0 -0
  313. micrOS/micropython/esp32s3-GENERIC-20240105-v1.22.1.bin +0 -0
  314. micrOS/micropython/esp32s3_spiram_oct-20231005-v1.21.0.bin +0 -0
  315. micrOS/micropython/rpi-pico-w-20231005-v1.21.0.uf2 +0 -0
  316. micrOS/micropython/tinypico-20231005-v1.21.0.bin +0 -0
  317. micrOS/micropython/tinypico-usbc-UM-20240105-v1.22.1.bin +0 -0
  318. micrOS/source/LM_L298N_DCmotor.py +0 -86
  319. micrOS/source/LM_catgame.py +0 -74
  320. micrOS/source/LM_dashboard_be.py +0 -37
  321. micrOS/source/LM_demo.py +0 -85
  322. micrOS/source/LM_distance.py +0 -88
  323. micrOS/source/LM_i2c.py +0 -44
  324. micrOS/source/LM_intercon.py +0 -57
  325. micrOS/source/LM_keychain.py +0 -318
  326. micrOS/source/LM_lmpacman.py +0 -126
  327. micrOS/source/LM_neoeffects.py +0 -327
  328. micrOS/source/LM_pet_feeder.py +0 -76
  329. micrOS/source/LM_ph_sensor.py +0 -51
  330. micrOS/source/LM_rest.py +0 -40
  331. micrOS/source/LM_robustness.py +0 -73
  332. micrOS/source/LM_telegram.py +0 -96
  333. micrOS/source/reset.py +0 -11
  334. micrOS/source/uapi.js +0 -76
  335. micrOS/source/udashboard.js +0 -137
  336. micrOS/source/ustyle.css +0 -28
  337. micrOS/source/uwidgets.js +0 -179
  338. micrOSDevToolKit-2.1.5.dist-info/RECORD +0 -337
  339. toolkit/dashboard_apps/AirQualityBME280.py +0 -36
  340. toolkit/dashboard_apps/AirQualityDHT22_CO2.py +0 -36
  341. toolkit/lib/file_extensions.py +0 -16
  342. toolkit/simulator_lib/__pycache__/LP_darwin.cpython-312.pyc +0 -0
  343. toolkit/simulator_lib/__pycache__/LP_darwin.cpython-38.pyc +0 -0
  344. toolkit/simulator_lib/__pycache__/LP_darwin.cpython-39.pyc +0 -0
  345. toolkit/simulator_lib/__pycache__/sim_console.cpython-312.pyc +0 -0
  346. toolkit/simulator_lib/__pycache__/sim_console.cpython-38.pyc +0 -0
  347. toolkit/simulator_lib/__pycache__/sim_console.cpython-39.pyc +0 -0
  348. toolkit/workspace/precompiled/IO_esp32.mpy +0 -0
  349. toolkit/workspace/precompiled/IO_esp32c3.mpy +0 -0
  350. toolkit/workspace/precompiled/IO_esp32s2.mpy +0 -0
  351. toolkit/workspace/precompiled/IO_esp32s3.mpy +0 -0
  352. toolkit/workspace/precompiled/IO_qtpy.mpy +0 -0
  353. toolkit/workspace/precompiled/IO_rp2.mpy +0 -0
  354. toolkit/workspace/precompiled/IO_tinypico.mpy +0 -0
  355. toolkit/workspace/precompiled/LM_L298N_DCmotor.mpy +0 -0
  356. toolkit/workspace/precompiled/LM_OV2640.mpy +0 -0
  357. toolkit/workspace/precompiled/LM_aht10.mpy +0 -0
  358. toolkit/workspace/precompiled/LM_bme280.mpy +0 -0
  359. toolkit/workspace/precompiled/LM_catgame.py +0 -74
  360. toolkit/workspace/precompiled/LM_cct.mpy +0 -0
  361. toolkit/workspace/precompiled/LM_co2.mpy +0 -0
  362. toolkit/workspace/precompiled/LM_dashboard_be.py +0 -37
  363. toolkit/workspace/precompiled/LM_demo.py +0 -85
  364. toolkit/workspace/precompiled/LM_dht11.mpy +0 -0
  365. toolkit/workspace/precompiled/LM_dht22.mpy +0 -0
  366. toolkit/workspace/precompiled/LM_dimmer.mpy +0 -0
  367. toolkit/workspace/precompiled/LM_distance.py +0 -88
  368. toolkit/workspace/precompiled/LM_ds18.mpy +0 -0
  369. toolkit/workspace/precompiled/LM_genIO.mpy +0 -0
  370. toolkit/workspace/precompiled/LM_i2c.py +0 -44
  371. toolkit/workspace/precompiled/LM_i2s_mic.mpy +0 -0
  372. toolkit/workspace/precompiled/LM_intercon.mpy +0 -0
  373. toolkit/workspace/precompiled/LM_keychain.mpy +0 -0
  374. toolkit/workspace/precompiled/LM_light_sensor.mpy +0 -0
  375. toolkit/workspace/precompiled/LM_lmpacman.mpy +0 -0
  376. toolkit/workspace/precompiled/LM_neoeffects.mpy +0 -0
  377. toolkit/workspace/precompiled/LM_neopixel.mpy +0 -0
  378. toolkit/workspace/precompiled/LM_oled.mpy +0 -0
  379. toolkit/workspace/precompiled/LM_oled_sh1106.mpy +0 -0
  380. toolkit/workspace/precompiled/LM_oled_ui.mpy +0 -0
  381. toolkit/workspace/precompiled/LM_pet_feeder.py +0 -76
  382. toolkit/workspace/precompiled/LM_ph_sensor.py +0 -51
  383. toolkit/workspace/precompiled/LM_presence.mpy +0 -0
  384. toolkit/workspace/precompiled/LM_rest.mpy +0 -0
  385. toolkit/workspace/precompiled/LM_rgb.mpy +0 -0
  386. toolkit/workspace/precompiled/LM_roboarm.mpy +0 -0
  387. toolkit/workspace/precompiled/LM_robustness.py +0 -73
  388. toolkit/workspace/precompiled/LM_switch.mpy +0 -0
  389. toolkit/workspace/precompiled/LM_system.mpy +0 -0
  390. toolkit/workspace/precompiled/LM_telegram.mpy +0 -0
  391. toolkit/workspace/precompiled/reset.mpy +0 -0
  392. toolkit/workspace/precompiled/uapi.js +0 -76
  393. toolkit/workspace/precompiled/udashboard.js +0 -137
  394. toolkit/workspace/precompiled/ustyle.css +0 -28
  395. toolkit/workspace/precompiled/uwidgets.js +0 -179
  396. /toolkit/user_data/node_config_archive/.include → /micrOS/source/config/_git.keep +0 -0
  397. /micrOS/source/{IO_rp2.py → modules/IO_rp2.py} +0 -0
  398. /micrOS/source/{LM_tinyrgb.py → modules/LM_tinyrgb.py} +0 -0
  399. {micrOSDevToolKit-2.1.5.dist-info → microsdevtoolkit-2.26.1.dist-info/licenses}/LICENSE +0 -0
  400. {micrOSDevToolKit-2.1.5.dist-info → microsdevtoolkit-2.26.1.dist-info}/top_level.txt +0 -0
micrOS/source/Tasks.py CHANGED
@@ -10,18 +10,19 @@ Designed by Marcell Ban aka BxNxM
10
10
  #################################################################
11
11
  from sys import modules
12
12
  from json import dumps
13
+ from re import match
13
14
  import uasyncio as asyncio
14
15
  from micropython import schedule
15
16
  from utime import ticks_ms, ticks_diff
16
- from Debug import console_write, errlog_add
17
+ from Debug import console_write, syslog
17
18
  from Config import cfgget
18
19
  from Network import sta_high_avail
19
20
 
20
21
  try:
21
- from gc import collect
22
- except:
22
+ from gc import collect as gcollect
23
+ except ImportError:
23
24
  console_write("[SIMULATOR MODE GC IMPORT]")
24
- from simgc import collect
25
+ from simgc import collect as gcollect
25
26
 
26
27
  #################################################################
27
28
  # Implement custom task class #
@@ -33,26 +34,52 @@ class TaskBase:
33
34
  """
34
35
  Async task base definition for common features
35
36
  """
37
+ __slots__ = ['task', 'done', 'out', 'tag', '__callback', '__inloop', '__sleep']
36
38
  QUEUE_SIZE = cfgget('aioqueue') # QUEUE size from config
37
39
  TASKS = {} # TASK OBJ list
38
40
 
39
41
  def __init__(self):
40
- self.task = None # [TASK] Store created async task object
41
- self.done = asyncio.Event() # [TASK] Store done state
42
- self.out = "" # [TASK] Store output
43
- self.tag = None # [TASK] Task tag (identification)
42
+ self.task = None # Store created async task object
43
+ self.tag = None # Task tag (identification)
44
+ self.done = asyncio.Event() # Store task done state
45
+ self.out = "" # Store task output
44
46
 
47
+ ###### BASE METHODS FOR CHILD CLASSES ####
48
+ def _create(self, callback:callable) -> dict:
49
+ """
50
+ Create async task and register it to TASKS dict by tag
51
+ :param callback: coroutine function
52
+ """
53
+ # Create async task from coroutine function
54
+ self.task = asyncio.get_event_loop().create_task(callback)
55
+ # Store Task object by key - for task control
56
+ TaskBase.TASKS[self.tag] = self
57
+ return {self.tag: "Starting"}
58
+
59
+ @staticmethod
60
+ def _task_gc():
61
+ """
62
+ Automatic passive task deletion over QUEUE_SIZE
63
+ """
64
+ keep = TaskBase.QUEUE_SIZE
65
+ passive = tuple((task_tag for task_tag in list(TaskBase.TASKS) if not TaskBase.is_busy(task_tag)))
66
+ if len(passive) >= keep:
67
+ for i in range(0, len(passive)-keep+1):
68
+ del TaskBase.TASKS[passive[i]]
69
+ gcollect()
70
+
71
+ ###### PUBLIC TASK METHODS #####
45
72
  @staticmethod
46
- def is_busy(tag):
73
+ def is_busy(tag:str) -> bool:
47
74
  """
48
- Check task is busy by tag in TASKS
49
- - exists + running = busy
75
+ Check task is busy by tag
76
+ :param tag: for task selection
50
77
  """
51
78
  task = TaskBase.TASKS.get(tag, None)
52
- # return True: busy OR False: not busy (inactive)
79
+ # return True: busy OR False: not busy (inactive) OR None: not exists
53
80
  return bool(task is not None and not task.done.is_set())
54
81
 
55
- def cancel(self):
82
+ def cancel(self) -> bool:
56
83
  """
57
84
  Cancel task (+cleanup)
58
85
  """
@@ -62,15 +89,38 @@ class TaskBase:
62
89
  self.task.cancel() # Try to cancel task by asyncio
63
90
  except Exception as e:
64
91
  if "can't cancel self" != str(e):
65
- errlog_add(f"[WARN] IRQ Task cancel: {e}")
92
+ syslog(f"[WARN] IRQ Task cancel: {e}")
66
93
  self.__task_del()
67
94
  else:
68
95
  return False
69
96
  except Exception as e:
70
- errlog_add(f"[ERR] Task kill: {e}")
97
+ syslog(f"[ERR] Task kill: {e}")
71
98
  return False
72
99
  return True
73
100
 
101
+ @staticmethod
102
+ async def feed(sleep_ms=1):
103
+ """
104
+ Feed event loop
105
+ :param sleep_ms: in millisecond
106
+ """
107
+ # TODO?: feed WDT - auto restart when system is frozen
108
+ if sleep_ms <= 0:
109
+ return await asyncio.sleep(0.000_000_1) # 0 means: 100ns (Absolute minimum)
110
+ return await asyncio.sleep_ms(sleep_ms)
111
+
112
+ async def await_result(self, timeout:int=5):
113
+ """
114
+ Wait for task completion with timeout
115
+ :param timeout: in seconds
116
+ """
117
+ try:
118
+ await asyncio.wait_for(self.done.wait(), timeout)
119
+ except asyncio.TimeoutError:
120
+ return "Timeout has beed exceeded"
121
+ return self.out
122
+
123
+ ###### PRIVATE LCM METHODS #####
74
124
  def __task_del(self, keep_cache=False):
75
125
  """
76
126
  Delete task from TASKS
@@ -79,22 +129,13 @@ class TaskBase:
79
129
  if self.tag in TaskBase.TASKS:
80
130
  if not keep_cache: # True - In case of destructor
81
131
  del TaskBase.TASKS[self.tag]
82
- collect() # GC collect
83
-
84
- @staticmethod
85
- def task_gc():
86
- keep = TaskBase.QUEUE_SIZE
87
- passive = tuple([task_tag for task_tag in list(TaskBase.TASKS) if not TaskBase.is_busy(task_tag)])
88
- if len(passive) >= keep:
89
- for i in range(0, len(passive)-keep+1):
90
- del TaskBase.TASKS[passive[i]]
91
- collect() # GC collect
132
+ gcollect()
92
133
 
93
134
  def __del__(self):
94
135
  try:
95
136
  self.__task_del(keep_cache=True)
96
137
  except Exception as e:
97
- errlog_add(f"[ERR] TaskBase.__del__: {e}")
138
+ syslog(f"[ERR] TaskBase.__del__: {e}")
98
139
 
99
140
 
100
141
  class NativeTask(TaskBase):
@@ -103,7 +144,7 @@ class NativeTask(TaskBase):
103
144
  - could be built in function or custom code from load modules
104
145
  """
105
146
 
106
- def create(self, callback=None, tag=None):
147
+ def create(self, callback:callable=None, tag:str=None) -> dict:
107
148
  """
108
149
  Create async task with coroutine callback (no queue limit check!)
109
150
  + async socket server task
@@ -112,15 +153,11 @@ class NativeTask(TaskBase):
112
153
  """
113
154
  # Create task tag
114
155
  self.tag = f"aio.{ticks_ms()}" if tag is None else tag
115
- if TaskBase.is_busy(self.tag):
156
+ if self.is_busy(self.tag):
116
157
  # Skip task if already running
117
- return False
118
-
119
- # Start task with coroutine callback
120
- self.task = asyncio.get_event_loop().create_task(callback)
121
- # Store Task object by key - for task control
122
- TaskBase.TASKS[self.tag] = self
123
- return True
158
+ return {self.tag: "Already running"}
159
+ # Create task with coroutine callback
160
+ return super()._create(callback)
124
161
 
125
162
  def __enter__(self):
126
163
  """
@@ -137,7 +174,7 @@ class NativeTask(TaskBase):
137
174
  Helper function for Task creation in Load Modules
138
175
  [HINT] Use python with feature to utilize this feature
139
176
  """
140
- self.task_gc() # Task pool cleanup
177
+ self._task_gc() # Task pool cleanup
141
178
  self.done.set()
142
179
 
143
180
 
@@ -153,7 +190,7 @@ class MagicTask(TaskBase):
153
190
  self.__inloop = False # [LM] Task while loop for LM callback
154
191
  self.__sleep = 20 # [LM] Task while loop - async wait (proc feed) [ms]
155
192
 
156
- def create(self, callback=None, loop=None, sleep=None):
193
+ def create(self, callback:list=None, loop:bool=None, sleep:int=None) -> dict:
157
194
  """
158
195
  Create async task with function callback (with queue limit check)
159
196
  - wrap (sync) function into async task (task_wrapper)
@@ -163,20 +200,16 @@ class MagicTask(TaskBase):
163
200
  """
164
201
  # Create task tag
165
202
  self.tag = '.'.join(callback[0:2])
166
- if TaskBase.is_busy(self.tag):
203
+ if self.is_busy(self.tag):
167
204
  # Skip task if already running
168
- return False
169
-
205
+ return {self.tag: "Already running"}
170
206
  # Set parameters for async wrapper
171
207
  self.__callback = callback
172
208
  self.__inloop = self.__inloop if loop is None else loop
173
209
  # Set sleep value for async loop - optional parameter with min sleep limit check (20ms)
174
210
  self.__sleep = self.__sleep if sleep is None else sleep if sleep > 19 else self.__sleep
175
-
176
- self.task = asyncio.get_event_loop().create_task(self.__task_wrapper())
177
- # Store Task object by key - for task control
178
- TaskBase.TASKS[self.tag] = self
179
- return True
211
+ # Create task with coroutine callback
212
+ return super()._create(self.__task_wrapper())
180
213
 
181
214
  async def __task_wrapper(self):
182
215
  """
@@ -187,11 +220,11 @@ class MagicTask(TaskBase):
187
220
  - self.__msg_buf: lm msg object redirect to variable - store lm output
188
221
  """
189
222
  while True:
190
- await asyncio.sleep_ms(self.__sleep)
223
+ await self.feed(self.__sleep)
191
224
  state, self.out = _exec_lm_core(self.__callback)
192
225
  if not state or not self.__inloop:
193
226
  break
194
- self.task_gc() # Task pool cleanup
227
+ self._task_gc() # Task pool cleanup
195
228
  self.done.set()
196
229
 
197
230
  def cancel(self):
@@ -208,8 +241,10 @@ class Manager:
208
241
  """
209
242
  micrOS async task handler
210
243
  """
244
+ __slots__ = ['_initialized', 'idle_counter']
211
245
  INSTANCE = None # Manager object
212
246
  LOAD = 0 # CPU overload measure
247
+ INTERCON = None # Dynamic ref. for interconnect calls
213
248
 
214
249
  def __new__(cls):
215
250
  """
@@ -223,7 +258,7 @@ class Manager:
223
258
  cls.INSTANCE._initialized = False
224
259
  # Set async event loop exception handler
225
260
  asyncio.get_event_loop().set_exception_handler(lambda loop=None, context=None:
226
- errlog_add(f"[aio] exception: {loop}:{context}"))
261
+ syslog(f"[aio] exception: {loop}:{context}"))
227
262
  return cls.INSTANCE
228
263
 
229
264
  def __init__(self):
@@ -248,7 +283,7 @@ class Manager:
248
283
  """
249
284
  if Manager._queue_len() >= TaskBase.QUEUE_SIZE:
250
285
  msg = f"[aio] Task queue full: {TaskBase.QUEUE_SIZE}"
251
- errlog_add(msg)
286
+ syslog(msg)
252
287
  raise Exception(msg)
253
288
 
254
289
  async def idle_task(self):
@@ -263,28 +298,33 @@ class Manager:
263
298
  try:
264
299
  while True:
265
300
  # [0] Just chill
266
- await asyncio.sleep_ms(300)
301
+ await my_task.feed(300)
267
302
  # [1] PROBE SYSTEM LOAD + 300ms
268
303
  t = ticks_ms()
269
- await asyncio.sleep_ms(300)
304
+ await my_task.feed(300)
270
305
  delta_rate = int(((ticks_diff(ticks_ms(), t) / 300) - 1) * 100)
271
306
  Manager.LOAD = int((Manager.LOAD + delta_rate) / 2) # Average - smooth
272
307
  # [2] NETWORK AUTO REPAIR
273
- if self.idle_counter > 200: # ~120 sec
308
+ if self.idle_counter > 300: # ~ 3 min
274
309
  self.idle_counter = 0 # Reset counter
275
- # Check and fix STA network (example: after power outage - micrOS boards boots faster then router)
310
+ # Check and fix STA network (reboot if target ssid is available not yet connected)
276
311
  sta_high_avail()
277
312
  self.idle_counter += 1 # Increase counter
278
313
  except Exception as e:
279
- errlog_add(f"[ERR] Idle task exists: {e}")
314
+ syslog(f"[ERR] Idle task exists: {e}")
280
315
  my_task.done.set()
281
316
 
282
317
  @staticmethod
283
- def create_task(callback, tag=None, loop=False, delay=None):
318
+ def create_task(callback, tag:str=None, loop:bool=False, delay:int=None) -> dict:
284
319
  """
285
- Primary interface
286
- Generic task creator method
287
- Create async Task with coroutine/list(lm call) callback
320
+ Primary interface of micrOS Generic task creator method
321
+ :param tag: task unique identifier
322
+ NativeTask:
323
+ :param callback: callable, coroutine to start a task
324
+ MagicTask with queue limiter:
325
+ :param callback: list of staring (command)
326
+ :param loop: MagicTask looping parameter
327
+ :param delay: MagicTask delay parameter
288
328
  """
289
329
  if isinstance(callback, list):
290
330
  # Check queue if task is Load Module
@@ -320,7 +360,7 @@ class Manager:
320
360
  _tasks = []
321
361
  tag_parts = tag.split('.')
322
362
  for t in TaskBase.TASKS:
323
- if t.startswith(tag_parts[0]) and len(tag_parts) > 1 and tag_parts[1] == '*':
363
+ if len(tag_parts) > 1 and t.startswith('.'.join(tag_parts[0:-1])) and tag_parts[-1] == '*':
324
364
  _tasks.append(t)
325
365
  if len(_tasks) == 0:
326
366
  return []
@@ -344,20 +384,19 @@ class Manager:
344
384
  return '\n'.join(output)
345
385
 
346
386
  @staticmethod
347
- def kill(tag):
387
+ def kill(tag:str) -> (bool, str):
348
388
  """
349
389
  Primary interface
350
390
  Kill/terminate async task
351
391
  - by tag: module.function
352
392
  - by tag module.*, kill all for selected module
353
393
  """
354
-
355
394
  def terminate(_tag):
356
395
  to_kill = TaskBase.TASKS.get(_tag, None)
357
396
  try:
358
397
  return False if to_kill is None else to_kill.cancel()
359
398
  except Exception as e:
360
- errlog_add(f"[ERR] Task kill: {e}")
399
+ syslog(f"[ERR] Task kill: {e}")
361
400
  return False
362
401
 
363
402
  # Handle task group kill (module.*)
@@ -383,126 +422,130 @@ class Manager:
383
422
  try:
384
423
  asyncio.get_event_loop().run_forever()
385
424
  except Exception as e:
386
- errlog_add(f"[aio] loop stopped: {e}")
425
+ syslog(f"[aio] loop stopped: {e}")
387
426
  asyncio.get_event_loop().close()
388
427
 
389
428
  @staticmethod
390
- def server_task_msg(msg):
391
- server_task = TaskBase.TASKS.get('server', None)
392
- if server_task is None:
393
- return
394
- server_task.out = msg
429
+ def task_msg(tag:str, msg:str=None) -> bool|str:
430
+ """
431
+ Set/Get task message (for server virtual task, etc.)
432
+ """
433
+ _task = TaskBase.TASKS.get(tag, None)
434
+ if _task is None:
435
+ return False
436
+ # Get task output
437
+ if tag is None:
438
+ return _task.out
439
+ # Set task output
440
+ _task.out = msg
441
+ return True
395
442
 
396
443
 
397
444
  #################################################################
398
445
  # LM EXEC CORE functions #
399
446
  #################################################################
400
-
401
- def exec_lm_pipe(taskstr):
447
+ def exec_builtins(func):
402
448
  """
403
- Input: taskstr contains LM calls separated by ;
404
- Used for execute config callback parameters (BootHook, ...)
449
+ [Decorator] Module execution built-in commands and modifiers
450
+ - modules - show active modules list
451
+ - task kill ... - task termination
452
+ show ... - task output dump
453
+ - ... >json - postfix to jsonify the output
405
454
  """
406
- try:
407
- # Handle config default empty value (do nothing)
408
- if taskstr.startswith('n/a'):
409
- return True
410
- # Execute individual commands - msgobj->"/dev/null"
411
- for cmd in (cmd.strip().split() for cmd in taskstr.split(';') if len(cmd) > 0):
412
- if not lm_exec(cmd)[0]:
413
- console_write(f"|-[LM-PIPE] task error: {cmd}")
414
- except Exception as e:
415
- errlog_add(f"[ERR] exec_lm_pipe {taskstr}: {e}")
416
- return False
417
- return True
418
-
419
-
420
- def exec_lm_pipe_schedule(taskstr):
455
+ def wrapper(arg_list:list, jsonify=None):
456
+ # Ensure the parameter is a list of strings
457
+ if isinstance(arg_list, list) and arg_list:
458
+ # Postfix operator handling
459
+ # ... >json - command output format option
460
+ # ... >>node01.local - intercon: command execution on remote device by hostname/IP address
461
+ arg_list, json_flag = (arg_list[:-1], True) if arg_list[-1] == '>json' else (arg_list, False)
462
+ json_flag = jsonify if isinstance(jsonify, bool) else json_flag
463
+ arg_list, intercon_target = ((arg_list[:-1], arg_list[-1].replace(">>", ""))
464
+ if match(r'^>>[A-Za-z0-9._-]+$', arg_list[-1])
465
+ else (arg_list, None))
466
+
467
+ # INTERCONNECT
468
+ if intercon_target:
469
+ if Manager.INTERCON is None:
470
+ from InterConnect import send_cmd
471
+ Manager.INTERCON = send_cmd
472
+ try:
473
+ out = Manager.INTERCON(host=intercon_target, cmd=arg_list)
474
+ except Exception as e:
475
+ out = {}
476
+ syslog(f"[ERR] Intercon: {e}")
477
+ return True, out
478
+
479
+ # MODULES
480
+ if arg_list[0] == 'modules':
481
+ return True, list((m.strip().replace('LM_', '') for m in modules if m.startswith('LM_'))) + ['task']
482
+
483
+ # Handle task manipulation commands: list, kill, show - return True -> Command handled
484
+ if 'task' == arg_list[0]:
485
+ arg_len = len(arg_list)
486
+ # task list
487
+ if arg_len > 1 and 'list' == arg_list[1]:
488
+ on, off = Manager.list_tasks(json=json_flag)
489
+ # RETURN: JSON mode Human readable mode with cpu & queue info
490
+ return (True, dumps({'active': on[3:], 'inactive': off})) if json_flag else (True, '\n'.join(on) + '\n' + '\n'.join(off) + '\n')
491
+ # task kill <taskID> / task show <taskID>
492
+ if arg_len > 2:
493
+ if 'kill' == arg_list[1]:
494
+ _, msg = Manager.kill(tag=arg_list[2])
495
+ return True, msg
496
+ if 'show' == arg_list[1]:
497
+ return True, Manager.show(tag=arg_list[2])
498
+ return True, "Invalid task cmd! Help: task list / kill <taskID> / show <taskID>"
499
+
500
+ # Call the decorated function with the additional flag
501
+ return func(arg_list, json_flag)
502
+ return False, None
503
+
504
+ return wrapper
505
+
506
+
507
+ def lm_exec(arg_list:list, jsonify:bool=None):
421
508
  """
422
- Wrapper for exec_lm_pipe
423
- - Schedule LM executions from IRQs (extIRQ, timIRQ)
509
+ Main LM executor function with
510
+ - async (background)
511
+ - sync
512
+ (single) task execution (_exec_lm_core)
513
+ :param arg_list: command parameters
514
+ :param jsonify: request json output (controlled by the decorator)
515
+ Return Bool(OK/NOK), "Command output"
424
516
  """
425
- try:
426
- schedule(exec_lm_pipe, taskstr)
427
- return True
428
- except Exception as e:
429
- errlog_add(f"[ERR] exec_lm_pipe_schedule: {e}")
430
- return False
431
517
 
518
+ # [1] Async "background" task execution, postfix: &, &&
519
+ if len(arg_list) > 2 and '&' in arg_list[-1]:
520
+ # Evaluate task mode: loop + delay
521
+ mode = arg_list.pop(-1)
522
+ loop = mode.count('&') == 2
523
+ delay = mode.replace('&', '').strip()
524
+ delay = int(delay) if delay.isdigit() else None
525
+ # Create and start async lm task
526
+ try:
527
+ return True, Manager.create_task(arg_list, loop=loop, delay=delay)
528
+ except Exception as e:
529
+ return False, {".".join(arg_list[0:2]): str(e)}
432
530
 
433
- def lm_exec(arg_list):
434
- """
435
- Main LM executor function wrapper
436
- - handle async (background) task execution
437
- - handle sync task execution (_exec_lm_core)
438
- """
439
-
440
- def task_manager(msg_list):
441
- msg_len = len(msg_list)
442
- # [1] Handle task manipulation commands: list, kill, show - return True -> Command handled
443
- if 'task' == msg_list[0]:
444
- # task list
445
- if msg_len > 1 and 'list' == msg_list[1]:
446
- if msg_len > 2 and msg_list[2].strip() == '>json':
447
- # JSON mode
448
- on, off = Manager.list_tasks(json=True)
449
- return True, {'active': on[3:], 'inactive': off}
450
- on, off = Manager.list_tasks(json=False)
451
- # Human readable mode with cpu & queue info
452
- return True, '\n'.join(on) + '\n' + '\n'.join(off) + '\n' # Show active tasks and passive tasks
453
- # task kill <taskID> / task show <taskID>
454
- if msg_len > 2:
455
- if 'kill' == msg_list[1]:
456
- state, msg = Manager.kill(tag=msg_list[2])
457
- return True, msg
458
- if 'show' == msg_list[1]:
459
- return True, Manager.show(tag=msg_list[2])
460
- return True, "Invalid task cmd! Help: task list / kill <taskID> / show <taskID>"
461
- # [2] Start async task, postfix: &, &&
462
- if msg_len > 2 and '&' in arg_list[-1]:
463
- # Evaluate task mode: loop + delay
464
- mode = arg_list.pop(-1)
465
- loop = mode.count('&') == 2
466
- delay = mode.replace('&', '').strip()
467
- delay = int(delay) if delay.isdigit() else None
468
- # Create and start async lm task
469
- try:
470
- state = Manager.create_task(arg_list, loop=loop, delay=delay)
471
- except Exception as e:
472
- # Valid & handled task command
473
- return True, str(e)
474
- tag = '.'.join(arg_list[0:2])
475
- # Valid & handled task command
476
- if state:
477
- return True, f"Start {tag}"
478
- return True, f"{tag} is Busy"
479
- # Not valid task command
480
- return False, ''
481
-
482
- # ================ main function ================
483
- # modules built-in function: show loaded LoadModules
484
- if len(arg_list) > 0 and arg_list[0] == 'modules':
485
- return True, list([m.strip().replace('LM_', '') for m in modules if m.startswith('LM_')])
486
- # [1] Run task command: start (&), list, kill, show
487
- is_task, out = task_manager(arg_list)
488
- if is_task:
489
- return True, out
490
531
  # [2] Sync "realtime" task execution
491
- state, out = _exec_lm_core(arg_list)
532
+ state, out = _exec_lm_core(arg_list, jsonify)
492
533
  return state, out
493
534
 
494
535
 
495
- def _exec_lm_core(cmd_list):
536
+ @exec_builtins
537
+ def _exec_lm_core(cmd_list, jsonify):
496
538
  """
497
- CORE STRING REFERENCE EXECUTOR: MODULE.FUNCTION...
539
+ [CORE] Single command executor: MODULE.FUNCTION...
498
540
  :param cmd_list: list of string parameters
499
541
  [1] module name (LM)
500
542
  [2] function
501
543
  [3...] parameters (separator: space)
502
- Built-in json output handler: >json
544
+ :param jsonify: request json output
545
+ Return Bool(OK/NOK), Str(Command output)
503
546
  """
504
547
 
505
- def __conv_func_params(param):
548
+ def _func_params(param):
506
549
  buf = None
507
550
  if "'" in param or '"' in param:
508
551
  str_index = [i for i, c in enumerate(param) if c in ('"', "'")]
@@ -514,12 +557,9 @@ def _exec_lm_core(cmd_list):
514
557
  param = param.format(*buf)
515
558
  return param
516
559
 
517
- # Check json mode for LM execution
518
- json_mode = cmd_list[-1] == '>json'
519
- cmd_list = cmd_list[0:-1] if json_mode else cmd_list
520
560
  # LoadModule execution
521
561
  if len(cmd_list) >= 2:
522
- lm_mod, lm_func, lm_params = f"LM_{cmd_list[0]}", cmd_list[1], __conv_func_params(' '.join(cmd_list[2:]))
562
+ lm_mod, lm_func, lm_params = f"LM_{cmd_list[0]}", cmd_list[1], _func_params(' '.join(cmd_list[2:]))
523
563
  try:
524
564
  # ------------- LM LOAD & EXECUTE ------------- #
525
565
  # [1] LOAD MODULE - OPTIMIZED by sys.modules
@@ -540,12 +580,13 @@ def _exec_lm_core(cmd_list):
540
580
  # ------------ LM output format: dict(jsonify) / str(raw) ------------- #
541
581
  # Handle LM output data
542
582
  if isinstance(lm_output, dict):
543
- # json True: output->json else Format dict output "human readable"
544
- lm_output = dumps(lm_output) if json_mode else '\n'.join(
583
+ # jsonify (True) json output, (False) default, "human readable" output)
584
+ lm_output = dumps(lm_output) if jsonify else '\n'.join(
545
585
  [f" {key}: {value}" for key, value in lm_output.items()])
546
586
  if lm_func == 'help':
547
- # Special case for help command: json True: output->json else Format dict output "human readable"
548
- lm_output = dumps(lm_output) if json_mode else '\n'.join([f" {out}," for out in lm_output])
587
+ # Special case:
588
+ # jsonify (True) json output, (False) default, "human readable" formatted output)
589
+ lm_output = dumps(lm_output) if jsonify else '\n'.join([f" {out}," for out in lm_output])
549
590
  # Return LM exec result
550
591
  return True, str(lm_output)
551
592
  # ---------------------------------------------------------------------- #
@@ -554,30 +595,55 @@ def _exec_lm_core(cmd_list):
554
595
  # UNLOAD MODULE IF MEMORY ERROR HAPPENED + gc.collect
555
596
  if lm_mod in modules:
556
597
  del modules[lm_mod]
557
- collect()
598
+ gcollect()
558
599
  # LM EXECUTION ERROR
559
600
  return False, f"Core error: {lm_mod}->{lm_func}: {e}"
560
601
  return False, "Shell: for hints type help.\nShell: for LM exec: [1](LM)module [2]function [3...]optional params"
561
602
 
603
+
562
604
  def lm_is_loaded(lm_name):
563
605
  """
564
606
  [Auth mode]
565
607
  Check lm_name in enabled modules
566
608
  """
567
- static_keywords = tuple('task')
609
+ static_keywords = ('task', 'modules')
568
610
  loaded_mods = [lm.replace('LM_', '') for lm in modules if lm.startswith('LM_')]
569
611
  return lm_name in static_keywords or lm_name in loaded_mods
570
612
 
571
613
 
572
- def exec_lm_core_schedule(arg_list):
614
+ ##################### LM EXEC CORE WRAPPERS #####################
615
+
616
+ def exec_lm_pipe(taskstr):
573
617
  """
574
- Wrapper for lm_exec for Scheduler
575
- - micropython scheduling
576
- - exec protection for cron IRQ
618
+ Real-time multi command executor
619
+ - with #comment annotation feature
620
+ :param taskstr: contains LM calls separated by ;
621
+ Used for execute config callback parameters (BootHook, IRQs, ...)
577
622
  """
578
623
  try:
579
- schedule(lm_exec, arg_list)
624
+ # Handle config default empty value (do nothing)
625
+ if taskstr.startswith('n/a'):
626
+ return True
627
+ # Execute individual commands - msgobj->"/dev/null"
628
+ for cmd in (cmd.strip().split() for cmd in taskstr.split(';') if len(cmd) > 0):
629
+ if cmd[0].startswith("#"):
630
+ console_write(f"[SKIP] exec_lm_pipe: {' '.join(cmd)}")
631
+ continue
632
+ if not lm_exec(cmd)[0]:
633
+ syslog(f"[WARN] exec_lm_pipe: {' '.join(cmd)}")
634
+ except Exception as e:
635
+ syslog(f"[ERR] exec_lm_pipe {taskstr}: {e}")
636
+ return False
637
+ return True
638
+
639
+
640
+ def exec_lm_pipe_schedule(taskstr):
641
+ """
642
+ Scheduled Wrapper for exec_lm_pipe for IRQs (extIRQ, timIRQ, cronIRQ)
643
+ """
644
+ try:
645
+ schedule(exec_lm_pipe, taskstr)
580
646
  return True
581
647
  except Exception as e:
582
- errlog_add(f"[ERR] schedule_lm_exec {arg_list}: {e}")
648
+ syslog(f"[ERR] exec_lm_pipe_schedule: {e}")
583
649
  return False