micrOSDevToolKit 2.9.1__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 (368) hide show
  1. env/driver_cp210x/macOS_VCP_Driver/SiLabsUSBDriverDisk.dmg +0 -0
  2. env/driver_cp210x/macOS_VCP_Driver/macOS_VCP_Driver_Release_Notes.txt +17 -1
  3. micrOS/micropython/esp32-20251209-v1.27.0.bin +0 -0
  4. micrOS/micropython/esp32c3-20251209-v1.27.0.bin +0 -0
  5. micrOS/micropython/esp32c6-20251209-v1.27.0.bin +0 -0
  6. micrOS/micropython/esp32s2-20251209-v1.27.0.bin +0 -0
  7. micrOS/micropython/esp32s2-LOLIN_MINI-20251209-v1.27.0.bin +0 -0
  8. micrOS/micropython/{esp32s3-20241129-v1.24.1.bin → esp32s3-4MBflash-20241129-v1.24.1.bin} +0 -0
  9. micrOS/micropython/esp32s3-8MBflash-20251209-v1.27.0.bin +0 -0
  10. micrOS/micropython/esp32s3_spiram_oct-20251209-v1.27.0.bin +0 -0
  11. micrOS/micropython/rpi-pico-w-20251209-v1.27.0.uf2 +0 -0
  12. micrOS/micropython/tinypico-20251209-v1.27.0.bin +0 -0
  13. micrOS/release_info/micrOS_ReleaseInfo/system_analysis_sum.json +167 -163
  14. micrOS/source/Auth.py +37 -0
  15. micrOS/source/Common.py +361 -116
  16. micrOS/source/Config.py +32 -22
  17. micrOS/source/Debug.py +50 -94
  18. micrOS/source/Espnow.py +377 -100
  19. micrOS/source/Files.py +207 -0
  20. micrOS/source/Hooks.py +48 -20
  21. micrOS/source/InterConnect.py +126 -42
  22. micrOS/source/Interrupts.py +6 -6
  23. micrOS/source/Logger.py +63 -26
  24. micrOS/source/Network.py +41 -21
  25. micrOS/source/Notify.py +48 -22
  26. micrOS/source/Pacman.py +326 -0
  27. micrOS/source/Scheduler.py +14 -54
  28. micrOS/source/Server.py +67 -69
  29. micrOS/source/Shell.py +99 -91
  30. micrOS/source/Tasks.py +141 -95
  31. micrOS/source/Time.py +19 -18
  32. micrOS/source/Types.py +53 -9
  33. micrOS/source/Web.py +381 -76
  34. micrOS/source/__pycache__/Common.cpython-312.pyc +0 -0
  35. micrOS/source/__pycache__/Debug.cpython-312.pyc +0 -0
  36. micrOS/source/__pycache__/Files.cpython-312.pyc +0 -0
  37. micrOS/source/__pycache__/Logger.cpython-312.pyc +0 -0
  38. micrOS/source/__pycache__/Scheduler.cpython-312.pyc +0 -0
  39. micrOS/source/__pycache__/Server.cpython-312.pyc +0 -0
  40. micrOS/source/__pycache__/Shell.cpython-312.pyc +0 -0
  41. micrOS/source/__pycache__/replhelper.cpython-312.pyc +0 -0
  42. micrOS/source/config/_git.keep +0 -0
  43. micrOS/source/helpers.py +132 -0
  44. micrOS/source/micrOS.py +17 -7
  45. micrOS/source/micrOSloader.py +5 -12
  46. micrOS/source/microIO.py +44 -20
  47. micrOS/source/modules/IO_esp32c6.py +38 -0
  48. micrOS/source/{IO_esp32s3.py → modules/IO_esp32s3.py} +37 -1
  49. micrOS/source/{IO_m5stamp.py → modules/IO_m5stamp.py} +35 -1
  50. micrOS/source/{IO_qtpy.py → modules/IO_qtpy.py} +22 -17
  51. micrOS/source/{IO_tinypico.py → modules/IO_tinypico.py} +38 -0
  52. micrOS/source/modules/LM_L298N.py +161 -0
  53. {toolkit/workspace/precompiled → micrOS/source/modules}/LM_L9110_DCmotor.py +3 -3
  54. micrOS/source/{LM_OV2640.py → modules/LM_OV2640.py} +45 -27
  55. micrOS/source/{LM_VL53L0X.py → modules/LM_VL53L0X.py} +3 -3
  56. micrOS/source/{LM_aht10.py → modules/LM_aht10.py} +2 -2
  57. micrOS/source/{LM_bme280.py → modules/LM_bme280.py} +3 -3
  58. micrOS/source/{LM_buzzer.py → modules/LM_buzzer.py} +18 -25
  59. micrOS/source/{LM_cct.py → modules/LM_cct.py} +17 -21
  60. micrOS/source/modules/LM_cluster.py +255 -0
  61. micrOS/source/{LM_co2.py → modules/LM_co2.py} +3 -3
  62. micrOS/source/{LM_dht11.py → modules/LM_dht11.py} +2 -2
  63. micrOS/source/{LM_dht22.py → modules/LM_dht22.py} +2 -2
  64. micrOS/source/{LM_dimmer.py → modules/LM_dimmer.py} +9 -9
  65. micrOS/source/{LM_distance.py → modules/LM_distance.py} +4 -6
  66. micrOS/source/{LM_ds18.py → modules/LM_ds18.py} +2 -2
  67. micrOS/source/{LM_esp32.py → modules/LM_esp32.py} +5 -0
  68. micrOS/source/modules/LM_espnow.py +53 -0
  69. micrOS/source/modules/LM_fileserver.py +265 -0
  70. micrOS/source/{LM_genIO.py → modules/LM_genIO.py} +52 -37
  71. micrOS/source/{LM_haptic.py → modules/LM_haptic.py} +2 -2
  72. {toolkit/workspace/precompiled → micrOS/source/modules}/LM_i2c.py +5 -4
  73. micrOS/source/{LM_i2s_mic.py → modules/LM_i2s_mic.py} +6 -7
  74. micrOS/source/{LM_ld2410.py → modules/LM_ld2410.py} +2 -2
  75. micrOS/source/{LM_light_sensor.py → modules/LM_light_sensor.py} +10 -21
  76. micrOS/source/modules/LM_mh_z19c.py +198 -0
  77. micrOS/source/modules/LM_neoeffects.py +284 -0
  78. micrOS/source/{LM_neopixel.py → modules/LM_neopixel.py} +19 -23
  79. micrOS/source/{LM_oled.py → modules/LM_oled.py} +2 -2
  80. micrOS/source/{LM_oled_sh1106.py → modules/LM_oled_sh1106.py} +3 -3
  81. micrOS/source/{LM_oled_ui.py → modules/LM_oled_ui.py} +72 -64
  82. micrOS/source/modules/LM_pacman.py +320 -0
  83. micrOS/source/{LM_presence.py → modules/LM_presence.py} +11 -15
  84. micrOS/source/modules/LM_qmi8658.py +204 -0
  85. micrOS/source/{LM_rencoder.py → modules/LM_rencoder.py} +2 -2
  86. micrOS/source/{LM_rest.py → modules/LM_rest.py} +4 -6
  87. micrOS/source/{LM_rgb.py → modules/LM_rgb.py} +21 -29
  88. micrOS/source/{LM_roboarm.py → modules/LM_roboarm.py} +8 -8
  89. micrOS/source/modules/LM_robustness.py +137 -0
  90. micrOS/source/{LM_servo.py → modules/LM_servo.py} +3 -3
  91. micrOS/source/{LM_stepper.py → modules/LM_stepper.py} +5 -5
  92. micrOS/source/{LM_switch.py → modules/LM_switch.py} +11 -9
  93. micrOS/source/{LM_system.py → modules/LM_system.py} +38 -32
  94. micrOS/source/modules/LM_tcs3472.py +187 -0
  95. micrOS/source/{LM_telegram.py → modules/LM_telegram.py} +164 -116
  96. micrOS/source/{LM_trackball.py → modules/LM_trackball.py} +3 -3
  97. micrOS/source/{LM_veml7700.py → modules/LM_veml7700.py} +2 -2
  98. micrOS/source/modules/LM_web.py +38 -0
  99. micrOS/source/urequests.py +39 -15
  100. {toolkit/workspace/precompiled → micrOS/source/web}/dashboard.html +4 -0
  101. micrOS/source/web/editor.js +440 -0
  102. micrOS/source/web/filesui.html +178 -0
  103. micrOS/source/web/filesui.js +338 -0
  104. {toolkit/workspace/precompiled → micrOS/source/web}/index.html +44 -2
  105. micrOS/source/{uapi.js → web/uapi.js} +48 -7
  106. micrOS/source/{ustyle.css → web/ustyle.css} +6 -3
  107. micrOS/utests/__init__.py +0 -0
  108. micrOS/utests/test_scheduler.py +435 -0
  109. {micrOSDevToolKit-2.9.1.data → microsdevtoolkit-2.26.1.data}/scripts/devToolKit.py +33 -3
  110. {micrOSDevToolKit-2.9.1.dist-info → microsdevtoolkit-2.26.1.dist-info}/METADATA +327 -268
  111. microsdevtoolkit-2.26.1.dist-info/RECORD +396 -0
  112. {micrOSDevToolKit-2.9.1.dist-info → microsdevtoolkit-2.26.1.dist-info}/WHEEL +1 -1
  113. toolkit/DevEnvCompile.py +63 -33
  114. toolkit/DevEnvOTA.py +58 -22
  115. toolkit/DevEnvUSB.py +110 -55
  116. toolkit/Gateway.py +6 -6
  117. toolkit/LM_to_compile.dat +6 -4
  118. toolkit/MicrOSDevEnv.py +127 -57
  119. toolkit/WebRepl.py +73 -0
  120. toolkit/dashboard_apps/BackupRestore.py +20 -35
  121. toolkit/dashboard_apps/CCTDemo.py +12 -17
  122. toolkit/dashboard_apps/CCTTest.py +20 -24
  123. toolkit/dashboard_apps/CamStream.py +2 -6
  124. toolkit/dashboard_apps/CatGame.py +14 -16
  125. toolkit/dashboard_apps/Dimmer.py +11 -21
  126. toolkit/dashboard_apps/GetVersion.py +11 -19
  127. toolkit/dashboard_apps/MicrophoneTest.py +1 -6
  128. toolkit/dashboard_apps/NeoEffectsDemo.py +22 -35
  129. toolkit/dashboard_apps/NeopixelTest.py +20 -25
  130. toolkit/dashboard_apps/PresenceTest.py +2 -8
  131. toolkit/dashboard_apps/QMI8685_GYRO.py +68 -0
  132. toolkit/dashboard_apps/RGBTest.py +20 -24
  133. toolkit/dashboard_apps/RoboArm.py +24 -32
  134. toolkit/dashboard_apps/SED_test.py +10 -14
  135. toolkit/dashboard_apps/SensorsTest.py +61 -0
  136. toolkit/dashboard_apps/SystemTest.py +202 -105
  137. toolkit/dashboard_apps/Template_app.py +11 -23
  138. toolkit/dashboard_apps/_app_base.py +34 -0
  139. toolkit/dashboard_apps/_gyro_visualizer.py +78 -0
  140. toolkit/dashboard_apps/uLightDemo.py +15 -24
  141. toolkit/index.html +4 -4
  142. toolkit/lib/LocalMachine.py +6 -1
  143. toolkit/lib/MicrosFiles.py +46 -0
  144. toolkit/lib/Repository.py +64 -0
  145. toolkit/lib/TerminalColors.py +4 -0
  146. toolkit/lib/macroScript.py +6 -0
  147. toolkit/lib/micrOSClient.py +123 -50
  148. toolkit/lib/micrOSClientHistory.py +156 -0
  149. toolkit/lib/pip_package_installer.py +5 -2
  150. toolkit/micrOSdashboard.py +12 -17
  151. toolkit/micrOSlint.py +20 -8
  152. toolkit/simulator_lib/__pycache__/IO_darwin.cpython-312.pyc +0 -0
  153. toolkit/simulator_lib/__pycache__/aioespnow.cpython-312.pyc +0 -0
  154. toolkit/simulator_lib/__pycache__/framebuf.cpython-312.pyc +0 -0
  155. toolkit/simulator_lib/__pycache__/machine.cpython-312.pyc +0 -0
  156. toolkit/simulator_lib/__pycache__/micropython.cpython-312.pyc +0 -0
  157. toolkit/simulator_lib/__pycache__/mip.cpython-312.pyc +0 -0
  158. toolkit/simulator_lib/__pycache__/neopixel.cpython-312.pyc +0 -0
  159. toolkit/simulator_lib/__pycache__/network.cpython-312.pyc +0 -0
  160. toolkit/simulator_lib/__pycache__/sim_common.cpython-312.pyc +0 -0
  161. toolkit/simulator_lib/__pycache__/simgc.cpython-312.pyc +0 -0
  162. toolkit/simulator_lib/__pycache__/simulator.cpython-312.pyc +0 -0
  163. toolkit/simulator_lib/__pycache__/uasyncio.cpython-312.pyc +0 -0
  164. toolkit/simulator_lib/__pycache__/uos.cpython-312.pyc +0 -0
  165. toolkit/simulator_lib/__pycache__/urandom.cpython-312.pyc +0 -0
  166. toolkit/simulator_lib/__pycache__/usocket.cpython-312.pyc +0 -0
  167. toolkit/simulator_lib/__pycache__/ussl.cpython-312.pyc +0 -0
  168. toolkit/simulator_lib/aioespnow.py +28 -0
  169. toolkit/simulator_lib/dht.py +1 -1
  170. toolkit/simulator_lib/framebuf.py +49 -1
  171. toolkit/simulator_lib/machine.py +17 -2
  172. toolkit/simulator_lib/micropython.py +3 -3
  173. toolkit/simulator_lib/mip.py +165 -0
  174. toolkit/simulator_lib/neopixel.py +3 -2
  175. toolkit/simulator_lib/network.py +2 -1
  176. toolkit/simulator_lib/node_config.json +2 -3
  177. toolkit/simulator_lib/ntptime.py +1 -1
  178. toolkit/simulator_lib/{sim_console.py → sim_common.py} +2 -3
  179. toolkit/simulator_lib/simgc.py +6 -2
  180. toolkit/simulator_lib/simulator.py +137 -59
  181. toolkit/simulator_lib/uasyncio.py +33 -2
  182. toolkit/simulator_lib/uos.py +147 -0
  183. toolkit/simulator_lib/urandom.py +4 -0
  184. toolkit/socketClient.py +43 -23
  185. toolkit/user_data/webhooks/generic.py +1 -1
  186. toolkit/user_data/webhooks/macro.py +1 -1
  187. toolkit/user_data/webhooks/template.py +1 -1
  188. toolkit/workspace/precompiled/Auth.mpy +0 -0
  189. toolkit/workspace/precompiled/Common.mpy +0 -0
  190. toolkit/workspace/precompiled/Config.mpy +0 -0
  191. toolkit/workspace/precompiled/Debug.mpy +0 -0
  192. toolkit/workspace/precompiled/Espnow.mpy +0 -0
  193. toolkit/workspace/precompiled/Files.mpy +0 -0
  194. toolkit/workspace/precompiled/Hooks.mpy +0 -0
  195. toolkit/workspace/precompiled/InterConnect.mpy +0 -0
  196. toolkit/workspace/precompiled/Interrupts.mpy +0 -0
  197. toolkit/workspace/precompiled/Logger.mpy +0 -0
  198. toolkit/workspace/precompiled/Network.mpy +0 -0
  199. toolkit/workspace/precompiled/Notify.mpy +0 -0
  200. toolkit/workspace/precompiled/Pacman.mpy +0 -0
  201. toolkit/workspace/precompiled/Scheduler.mpy +0 -0
  202. toolkit/workspace/precompiled/Server.mpy +0 -0
  203. toolkit/workspace/precompiled/Shell.mpy +0 -0
  204. toolkit/workspace/precompiled/Tasks.mpy +0 -0
  205. toolkit/workspace/precompiled/Time.mpy +0 -0
  206. toolkit/workspace/precompiled/Types.mpy +0 -0
  207. toolkit/workspace/precompiled/Web.mpy +0 -0
  208. toolkit/workspace/precompiled/_mpy.version +1 -1
  209. toolkit/workspace/precompiled/config/_git.keep +0 -0
  210. toolkit/workspace/precompiled/helpers.mpy +0 -0
  211. toolkit/workspace/precompiled/micrOS.mpy +0 -0
  212. toolkit/workspace/precompiled/micrOSloader.mpy +0 -0
  213. toolkit/workspace/precompiled/microIO.mpy +0 -0
  214. toolkit/workspace/precompiled/{IO_esp32.mpy → modules/IO_esp32.mpy} +0 -0
  215. toolkit/workspace/precompiled/{IO_esp32c3.mpy → modules/IO_esp32c3.mpy} +0 -0
  216. toolkit/workspace/precompiled/modules/IO_esp32c6.mpy +0 -0
  217. toolkit/workspace/precompiled/{IO_esp32s2.mpy → modules/IO_esp32s2.mpy} +0 -0
  218. toolkit/workspace/precompiled/modules/IO_esp32s3.mpy +0 -0
  219. toolkit/workspace/precompiled/modules/IO_m5stamp.mpy +0 -0
  220. toolkit/workspace/precompiled/modules/IO_qtpy.mpy +0 -0
  221. toolkit/workspace/precompiled/modules/IO_rp2.mpy +0 -0
  222. toolkit/workspace/precompiled/modules/IO_tinypico.mpy +0 -0
  223. toolkit/workspace/precompiled/modules/LM_L298N.mpy +0 -0
  224. {micrOS/source → toolkit/workspace/precompiled/modules}/LM_L9110_DCmotor.py +3 -3
  225. toolkit/workspace/precompiled/modules/LM_OV2640.mpy +0 -0
  226. toolkit/workspace/precompiled/{LM_VL53L0X.py → modules/LM_VL53L0X.py} +3 -3
  227. toolkit/workspace/precompiled/{LM_aht10.mpy → modules/LM_aht10.mpy} +0 -0
  228. toolkit/workspace/precompiled/{LM_bme280.mpy → modules/LM_bme280.mpy} +0 -0
  229. toolkit/workspace/precompiled/{LM_buzzer.mpy → modules/LM_buzzer.mpy} +0 -0
  230. toolkit/workspace/precompiled/modules/LM_cct.mpy +0 -0
  231. toolkit/workspace/precompiled/modules/LM_cluster.mpy +0 -0
  232. toolkit/workspace/precompiled/{LM_co2.mpy → modules/LM_co2.mpy} +0 -0
  233. toolkit/workspace/precompiled/{LM_dht11.mpy → modules/LM_dht11.mpy} +0 -0
  234. toolkit/workspace/precompiled/{LM_dht22.mpy → modules/LM_dht22.mpy} +0 -0
  235. toolkit/workspace/precompiled/modules/LM_dimmer.mpy +0 -0
  236. toolkit/workspace/precompiled/modules/LM_distance.mpy +0 -0
  237. toolkit/workspace/precompiled/{LM_ds18.mpy → modules/LM_ds18.mpy} +0 -0
  238. toolkit/workspace/precompiled/{LM_esp32.py → modules/LM_esp32.py} +5 -0
  239. toolkit/workspace/precompiled/modules/LM_espnow.py +53 -0
  240. toolkit/workspace/precompiled/modules/LM_fileserver.mpy +0 -0
  241. toolkit/workspace/precompiled/{LM_gameOfLife.mpy → modules/LM_gameOfLife.mpy} +0 -0
  242. toolkit/workspace/precompiled/modules/LM_genIO.mpy +0 -0
  243. toolkit/workspace/precompiled/{LM_haptic.mpy → modules/LM_haptic.mpy} +0 -0
  244. {micrOS/source → toolkit/workspace/precompiled/modules}/LM_i2c.py +5 -4
  245. toolkit/workspace/precompiled/modules/LM_i2s_mic.mpy +0 -0
  246. toolkit/workspace/precompiled/{LM_ld2410.mpy → modules/LM_ld2410.mpy} +0 -0
  247. toolkit/workspace/precompiled/modules/LM_light_sensor.mpy +0 -0
  248. toolkit/workspace/precompiled/modules/LM_mh_z19c.py +198 -0
  249. toolkit/workspace/precompiled/modules/LM_neoeffects.mpy +0 -0
  250. toolkit/workspace/precompiled/modules/LM_neopixel.mpy +0 -0
  251. toolkit/workspace/precompiled/{LM_oled.mpy → modules/LM_oled.mpy} +0 -0
  252. toolkit/workspace/precompiled/{LM_oled_sh1106.mpy → modules/LM_oled_sh1106.mpy} +0 -0
  253. toolkit/workspace/precompiled/modules/LM_oled_ui.mpy +0 -0
  254. toolkit/workspace/precompiled/modules/LM_pacman.mpy +0 -0
  255. toolkit/workspace/precompiled/modules/LM_presence.mpy +0 -0
  256. toolkit/workspace/precompiled/modules/LM_qmi8658.py +204 -0
  257. toolkit/workspace/precompiled/{LM_rencoder.py → modules/LM_rencoder.py} +2 -2
  258. toolkit/workspace/precompiled/modules/LM_rest.mpy +0 -0
  259. toolkit/workspace/precompiled/modules/LM_rgb.mpy +0 -0
  260. toolkit/workspace/precompiled/{LM_rgbcct.mpy → modules/LM_rgbcct.mpy} +0 -0
  261. toolkit/workspace/precompiled/modules/LM_roboarm.mpy +0 -0
  262. toolkit/workspace/precompiled/modules/LM_robustness.py +137 -0
  263. toolkit/workspace/precompiled/{LM_servo.mpy → modules/LM_servo.mpy} +0 -0
  264. toolkit/workspace/precompiled/{LM_sound_event.mpy → modules/LM_sound_event.mpy} +0 -0
  265. toolkit/workspace/precompiled/{LM_stepper.mpy → modules/LM_stepper.mpy} +0 -0
  266. toolkit/workspace/precompiled/modules/LM_switch.mpy +0 -0
  267. toolkit/workspace/precompiled/modules/LM_system.mpy +0 -0
  268. toolkit/workspace/precompiled/modules/LM_tcs3472.py +187 -0
  269. toolkit/workspace/precompiled/modules/LM_telegram.mpy +0 -0
  270. toolkit/workspace/precompiled/{LM_tinyrgb.mpy → modules/LM_tinyrgb.mpy} +0 -0
  271. toolkit/workspace/precompiled/{LM_trackball.mpy → modules/LM_trackball.mpy} +0 -0
  272. toolkit/workspace/precompiled/{LM_veml7700.mpy → modules/LM_veml7700.mpy} +0 -0
  273. toolkit/workspace/precompiled/modules/LM_web.mpy +0 -0
  274. toolkit/workspace/precompiled/urequests.mpy +0 -0
  275. {micrOS/source → toolkit/workspace/precompiled/web}/dashboard.html +4 -0
  276. toolkit/workspace/precompiled/web/editor.js +440 -0
  277. toolkit/workspace/precompiled/web/filesui.html +178 -0
  278. toolkit/workspace/precompiled/web/filesui.js +338 -0
  279. {micrOS/source → toolkit/workspace/precompiled/web}/index.html +44 -2
  280. toolkit/workspace/precompiled/{uapi.js → web/uapi.js} +48 -7
  281. toolkit/workspace/precompiled/{ustyle.css → web/ustyle.css} +6 -3
  282. micrOS/micropython/esp32-20241129-v1.24.1.bin +0 -0
  283. micrOS/micropython/esp32c3-20240222-v1.22.2.bin +0 -0
  284. micrOS/micropython/esp32s2-20240602-v1.23.0.bin +0 -0
  285. micrOS/micropython/esp32s2-LOLIN_MINI-20220618-v1.19.1.bin +0 -0
  286. micrOS/micropython/esp32s2-LOLIN_MINI-20240602-v1.23.0.bin +0 -0
  287. micrOS/micropython/esp32s3-20240105-v1.22.1.bin +0 -0
  288. micrOS/micropython/esp32s3_spiram_oct-20231005-v1.21.0.bin +0 -0
  289. micrOS/micropython/esp32s3_spiram_oct-20241129-v1.24.1.bin +0 -0
  290. micrOS/micropython/rpi-pico-w-20241129-v1.24.1.uf2 +0 -0
  291. micrOS/micropython/tinypico-20241129-v1.24.1.bin +0 -0
  292. micrOS/source/LM_L298N_DCmotor.py +0 -86
  293. micrOS/source/LM_catgame.py +0 -75
  294. micrOS/source/LM_dashboard_be.py +0 -37
  295. micrOS/source/LM_demo.py +0 -97
  296. micrOS/source/LM_espnow.py +0 -23
  297. micrOS/source/LM_intercon.py +0 -57
  298. micrOS/source/LM_keychain.py +0 -322
  299. micrOS/source/LM_lmpacman.py +0 -126
  300. micrOS/source/LM_neoeffects.py +0 -331
  301. micrOS/source/LM_oledui.py +0 -972
  302. micrOS/source/LM_pet_feeder.py +0 -78
  303. micrOS/source/LM_ph_sensor.py +0 -51
  304. micrOS/source/LM_robustness.py +0 -74
  305. micrOS/source/reset.py +0 -11
  306. micrOSDevToolKit-2.9.1.dist-info/RECORD +0 -365
  307. toolkit/dashboard_apps/AirQualityBME280.py +0 -36
  308. toolkit/dashboard_apps/AirQualityDHT22_CO2.py +0 -36
  309. toolkit/lib/file_extensions.py +0 -16
  310. toolkit/simulator_lib/__pycache__/sim_console.cpython-312.pyc +0 -0
  311. toolkit/simulator_lib/__pycache__/sim_console.cpython-38.pyc +0 -0
  312. toolkit/simulator_lib/__pycache__/sim_console.cpython-39.pyc +0 -0
  313. toolkit/workspace/precompiled/IO_esp32s3.mpy +0 -0
  314. toolkit/workspace/precompiled/IO_m5stamp.mpy +0 -0
  315. toolkit/workspace/precompiled/IO_qtpy.mpy +0 -0
  316. toolkit/workspace/precompiled/IO_rp2.mpy +0 -0
  317. toolkit/workspace/precompiled/IO_tinypico.mpy +0 -0
  318. toolkit/workspace/precompiled/LM_L298N_DCmotor.mpy +0 -0
  319. toolkit/workspace/precompiled/LM_OV2640.mpy +0 -0
  320. toolkit/workspace/precompiled/LM_catgame.py +0 -75
  321. toolkit/workspace/precompiled/LM_cct.mpy +0 -0
  322. toolkit/workspace/precompiled/LM_dashboard_be.py +0 -37
  323. toolkit/workspace/precompiled/LM_demo.py +0 -97
  324. toolkit/workspace/precompiled/LM_dimmer.mpy +0 -0
  325. toolkit/workspace/precompiled/LM_distance.mpy +0 -0
  326. toolkit/workspace/precompiled/LM_espnow.py +0 -23
  327. toolkit/workspace/precompiled/LM_genIO.mpy +0 -0
  328. toolkit/workspace/precompiled/LM_i2s_mic.mpy +0 -0
  329. toolkit/workspace/precompiled/LM_intercon.mpy +0 -0
  330. toolkit/workspace/precompiled/LM_keychain.mpy +0 -0
  331. toolkit/workspace/precompiled/LM_light_sensor.mpy +0 -0
  332. toolkit/workspace/precompiled/LM_lmpacman.mpy +0 -0
  333. toolkit/workspace/precompiled/LM_neoeffects.mpy +0 -0
  334. toolkit/workspace/precompiled/LM_neopixel.mpy +0 -0
  335. toolkit/workspace/precompiled/LM_oled_ui.mpy +0 -0
  336. toolkit/workspace/precompiled/LM_oledui.mpy +0 -0
  337. toolkit/workspace/precompiled/LM_pet_feeder.py +0 -78
  338. toolkit/workspace/precompiled/LM_ph_sensor.py +0 -51
  339. toolkit/workspace/precompiled/LM_presence.mpy +0 -0
  340. toolkit/workspace/precompiled/LM_rest.mpy +0 -0
  341. toolkit/workspace/precompiled/LM_rgb.mpy +0 -0
  342. toolkit/workspace/precompiled/LM_roboarm.mpy +0 -0
  343. toolkit/workspace/precompiled/LM_robustness.py +0 -74
  344. toolkit/workspace/precompiled/LM_switch.mpy +0 -0
  345. toolkit/workspace/precompiled/LM_system.mpy +0 -0
  346. toolkit/workspace/precompiled/LM_telegram.mpy +0 -0
  347. toolkit/workspace/precompiled/node_config.json +0 -1
  348. toolkit/workspace/precompiled/reset.mpy +0 -0
  349. /micrOS/source/{IO_esp32.py → modules/IO_esp32.py} +0 -0
  350. /micrOS/source/{IO_esp32c3.py → modules/IO_esp32c3.py} +0 -0
  351. /micrOS/source/{IO_esp32s2.py → modules/IO_esp32s2.py} +0 -0
  352. /micrOS/source/{IO_rp2.py → modules/IO_rp2.py} +0 -0
  353. /micrOS/source/{LM_gameOfLife.py → modules/LM_gameOfLife.py} +0 -0
  354. /micrOS/source/{LM_rgbcct.py → modules/LM_rgbcct.py} +0 -0
  355. /micrOS/source/{LM_rp2w.py → modules/LM_rp2w.py} +0 -0
  356. /micrOS/source/{LM_sdcard.py → modules/LM_sdcard.py} +0 -0
  357. /micrOS/source/{LM_sound_event.py → modules/LM_sound_event.py} +0 -0
  358. /micrOS/source/{LM_tinyrgb.py → modules/LM_tinyrgb.py} +0 -0
  359. /micrOS/source/{udashboard.js → web/udashboard.js} +0 -0
  360. /micrOS/source/{uwidgets.js → web/uwidgets.js} +0 -0
  361. /micrOS/source/{uwidgets_pro.js → web/uwidgets_pro.js} +0 -0
  362. {micrOSDevToolKit-2.9.1.dist-info → microsdevtoolkit-2.26.1.dist-info/licenses}/LICENSE +0 -0
  363. {micrOSDevToolKit-2.9.1.dist-info → microsdevtoolkit-2.26.1.dist-info}/top_level.txt +0 -0
  364. /toolkit/workspace/precompiled/{LM_rp2w.py → modules/LM_rp2w.py} +0 -0
  365. /toolkit/workspace/precompiled/{LM_sdcard.py → modules/LM_sdcard.py} +0 -0
  366. /toolkit/workspace/precompiled/{udashboard.js → web/udashboard.js} +0 -0
  367. /toolkit/workspace/precompiled/{uwidgets.js → web/uwidgets.js} +0 -0
  368. /toolkit/workspace/precompiled/{uwidgets_pro.js → web/uwidgets_pro.js} +0 -0
@@ -0,0 +1,187 @@
1
+ """
2
+ A MicroPython library for the TCS3472 light sensing chip
3
+ https://github.com/tti0/tcs3472-micropython
4
+
5
+ Copyright (c) 2021 tti0
6
+ Licensed under the MIT License
7
+ """
8
+
9
+ from struct import unpack
10
+ from time import sleep
11
+ from machine import I2C, Pin, PWM
12
+ from microIO import bind_pin, pinmap_search
13
+ from Types import resolve
14
+
15
+ from LM_neopixel import load as neo_load, color as neo_color, toggle as neo_toggle # local neopixel light indicator
16
+ from LM_cluster import run as cluster_run # DEMO: neomatrix cluster
17
+
18
+ CURRENT_ANIMATION_INDEX = 0 # DEMO: neomatrix cluster animation
19
+
20
+ class TCS3472:
21
+ INSTANCE = None
22
+
23
+ def __init__(self, address=0x29, led_pin=None):
24
+ self._bus = I2C(sda=Pin(bind_pin('i2c_sda')), scl=Pin(bind_pin('i2c_scl')))
25
+ self._i2c_address = address
26
+ self._bus.writeto(self._i2c_address, b'\x80\x03')
27
+ self._bus.writeto(self._i2c_address, b'\x81\x2b')
28
+ self.led = PWM(Pin(bind_pin('led', led_pin), Pin.OUT), freq=20480)
29
+ self.led_brightness = 20
30
+ TCS3472.INSTANCE = self
31
+
32
+ def scaled(self, saturation=1.5):
33
+ """
34
+ Normalize by strongest color, then adjust saturation.
35
+ saturation = 1.0 -> normal
36
+ saturation > 1.0 -> more vibrant
37
+ saturation < 1.0 -> more pastel
38
+ """
39
+ _, r, g, b = self.raw()
40
+ m = max(r, g, b)
41
+ if m == 0:
42
+ return 0.0, 0.0, 0.0
43
+
44
+ # Normalize by strongest channel
45
+ r, g, b = r / m, g / m, b / m
46
+
47
+ # Grayscale = average of channels
48
+ gray = (r + g + b) / 3
49
+
50
+ # Interpolate between gray and color
51
+ r = gray + (r - gray) * saturation
52
+ g = gray + (g - gray) * saturation
53
+ b = gray + (b - gray) * saturation
54
+
55
+ # Clamp to 0..1
56
+ return max(0, min(1, r)), max(0, min(1, g)), max(0, min(1, b))
57
+
58
+ def rgb(self):
59
+ return tuple(int(x * 255) for x in self.scaled())
60
+
61
+ def light(self):
62
+ return self.raw()[0]
63
+
64
+ def brightness(self, level=65.535):
65
+ return int((self.light() / level))
66
+
67
+ def valid(self):
68
+ self._bus.writeto(self._i2c_address, b'\x93')
69
+ return self._bus.readfrom(self._i2c_address, 1)[0] & 1
70
+
71
+ def raw(self):
72
+ self._bus.writeto(self._i2c_address, b'\xb4')
73
+ return unpack("<HHHH", self._bus.readfrom(self._i2c_address, 8))
74
+
75
+
76
+ ############################ Exposed functions ############################
77
+
78
+ def load(led_pin=20):
79
+ """
80
+ Load the TCS3472 Color sensor instance.
81
+ """
82
+ if TCS3472.INSTANCE is None:
83
+ TCS3472(led_pin=led_pin)
84
+ neo_load(ledcnt=1)
85
+ led(False)
86
+ return TCS3472.INSTANCE
87
+
88
+
89
+ def pinmap():
90
+ """
91
+ Show used pin mapping for this module.
92
+ """
93
+ return pinmap_search(['i2c_scl', 'i2c_sda', 'led'])
94
+
95
+
96
+ def measure():
97
+ """
98
+ MEASURE sensor
99
+ """
100
+ sensor = load()
101
+ measurement = {"rgb": sensor.rgb(), "light": sensor.light(), "brightness": sensor.brightness()}
102
+ return measurement
103
+
104
+
105
+ def led(state:bool=None, br:int=None):
106
+ """
107
+ SENSOR LED toggle
108
+ :param state: None-automatic, True-ON, False-OFF
109
+ :param br: brightness 0-100
110
+ """
111
+ def _set_duty(_br):
112
+ _br = sensor.led_brightness if _br is None else _br
113
+ sensor.led.duty(int(_br * 10))
114
+ if _br != 0:
115
+ sensor.led_brightness = _br
116
+
117
+ sensor = load()
118
+ if state is None:
119
+ # INVERT STATE
120
+ led_current_state = sensor.led.duty() > 0
121
+ if led_current_state:
122
+ _set_duty(br)
123
+ _set_duty(0)
124
+ neo_toggle(False)
125
+ else:
126
+ _set_duty(br)
127
+ neo_toggle(True)
128
+ else:
129
+ # SET STATE: ON/OFF
130
+ if state:
131
+ _set_duty(br)
132
+ neo_toggle(True)
133
+ else:
134
+ _set_duty(br)
135
+ _set_duty(0)
136
+ neo_toggle(False)
137
+ return f"LED on, {sensor.led_brightness}%" if sensor.led.duty()>0 else f"LED off"
138
+
139
+
140
+ def indicator(br=5):
141
+ """
142
+ Color indicator Neopixel LED update
143
+ :param br: brightness 0-100
144
+ """
145
+ r, g, b = measure()['rgb']
146
+ br = float(br / 100)
147
+ _r, _g, _b = int(r*br), int(g*br), int(b*br)
148
+ neo_color(_r, _g, _b, smooth=False)
149
+ return r, g, b
150
+
151
+
152
+ def neomatrix_update():
153
+ """
154
+ DEMO - Send color codes for all neomatrix devices over espnow cluster
155
+ """
156
+ r, g, b = indicator()
157
+ command = f"neomatrix color_fill {r} {g} {b}"
158
+ cluster_run(command)
159
+ return {"cmd": command, "cluster": "task show con.espnow.*"}
160
+
161
+
162
+ def neomatrix_animation():
163
+ """
164
+ DEMO - Set random animation on neomatrix espnow cluster
165
+ """
166
+ global CURRENT_ANIMATION_INDEX
167
+ animations = ('spiral', 'snake', 'noise')
168
+
169
+ next_animation = CURRENT_ANIMATION_INDEX + 1
170
+ CURRENT_ANIMATION_INDEX = 0 if next_animation >= len(animations) else next_animation
171
+ command = f"neomatrix {animations[CURRENT_ANIMATION_INDEX]}"
172
+ cluster_run(command)
173
+ return {"cmd": command, "cluster": "task show con.espnow.*"}
174
+
175
+
176
+ def help(widgets=False):
177
+ """
178
+ TCS3472 Color sensor
179
+ """
180
+ return resolve(('load led_pin=20',
181
+ 'TEXTBOX measure',
182
+ 'BUTTON led state=<True,False>',
183
+ 'SLIDER led state=True br=<0-100-5>',
184
+ 'indicator br=<0-100>',
185
+ 'BUTTON neomatrix_update',
186
+ 'BUTTON neomatrix_animation',
187
+ 'pinmap'), widgets=widgets)
Binary file
@@ -38,6 +38,9 @@
38
38
  </head>
39
39
  <body>
40
40
  <h1> micrOS dashboard </h1>
41
+ <div id="restInfo">
42
+ <div id="restInfoHeader"></div>
43
+ </div>
41
44
  <!-- Container for the dynamically generated list -->
42
45
  <section id="widgets-section"></section>
43
46
  <br><br><br>
@@ -54,6 +57,7 @@
54
57
  <script>
55
58
  document.addEventListener("DOMContentLoaded", function() {
56
59
  // Init basic info from board after DOM is fully loaded
60
+ restInfo(showPages=false);
57
61
 
58
62
  // INIT DASHBOARD (load active modules -> build page)
59
63
  DynamicWidgetLoad();
@@ -0,0 +1,440 @@
1
+ /* ============================================================
2
+ * Embedded MicroPython Editor
3
+ * Self-contained, embeddable, dependency-free
4
+ *
5
+ * Public API:
6
+ * createEditor(container)
7
+ * openEditor(url, { anchor, list })
8
+ * destroyEditor()
9
+ * ============================================================ */
10
+
11
+ let _editor = null;
12
+
13
+ // 🔹 track original DOM position of editor container
14
+ let _host = {
15
+ container: null,
16
+ parent: null,
17
+ next: null
18
+ };
19
+
20
+ /* ---------- Public API ---------- */
21
+
22
+ window.createEditor = function (container) {
23
+ console.info("editor.js: createEditor");
24
+ injectCSS();
25
+
26
+ if (!_editor) {
27
+ _host.container = container;
28
+ _host.parent = container.parentNode;
29
+ _host.next = container.nextSibling;
30
+
31
+ _editor = new EmbeddedEditor(container);
32
+ }
33
+ return _editor;
34
+ };
35
+
36
+ window.openEditor = function (url, opts = {}) {
37
+ if (!_editor) {
38
+ console.warn("Editor not active");
39
+ return;
40
+ }
41
+ console.info("editor.js: openEditor");
42
+ const { anchor, list } = opts;
43
+ const c = _host.container;
44
+ // 🔹 editor owns placement logic
45
+ if (anchor) {
46
+ anchor.insertAdjacentElement("afterend", c);
47
+ console.info("editor.js: openEditor.placed after selected element");
48
+ } else if (list) {
49
+ list.insertAdjacentElement("beforebegin", c);
50
+ console.info("editor.js: openEditor.placed before selected element");
51
+ }
52
+
53
+ _editor.open(url);
54
+ };
55
+
56
+ window.destroyEditor = function () {
57
+ if (_editor) {
58
+ _editor.close();
59
+ if (_host.container) {
60
+ _host.container.remove();
61
+ console.info("editor.js: destroyEditor - container removed");
62
+ }
63
+ _editor = null;
64
+ _host.container = null;
65
+ _host.parent = null;
66
+ _host.next = null;
67
+ console.info("editor.js: destroyEditor - editor destroyed");
68
+ }
69
+ };
70
+
71
+ /* ---------- CSS (scoped + injected) ---------- */
72
+
73
+ function injectCSS() {
74
+ if (document.getElementById("mp-editor-css")) return;
75
+
76
+ const css = document.createElement("style");
77
+ css.id = "mp-editor-css";
78
+ css.textContent = `
79
+ .mp-editor {
80
+ font-family: monospace;
81
+ background: #1e1e1e;
82
+ color: #d4d4d4;
83
+ }
84
+ .mp-editor .toolbar {
85
+ background: #252526;
86
+ padding: 6px;
87
+ display: flex;
88
+ gap: 6px;
89
+ align-items: center;
90
+ }
91
+ .mp-editor input {
92
+ background: #1e1e1e;
93
+ color: #d4d4d4;
94
+ border: 1px solid #555;
95
+ padding: 4px 6px;
96
+ }
97
+ .mp-editor button {
98
+ background: #0e639c;
99
+ border: none;
100
+ color: #fff;
101
+ padding: 6px 10px;
102
+ cursor: pointer;
103
+ }
104
+ .mp-editor button:hover { background: #1177bb; }
105
+ .mp-editor .close {
106
+ margin-left: auto;
107
+ background: transparent;
108
+ color: #ccc;
109
+ font-size: 16px;
110
+ padding: 4px 8px;
111
+ }
112
+ .mp-editor .close:hover { background: #333; color: #fff; }
113
+ .mp-editor .status { font-size: 13px; }
114
+ .mp-editor .status.ok { color: #6a9955; }
115
+ .mp-editor .status.err { color: #f44747; }
116
+ .mp-editor .status.info { color: #cccccc; }
117
+ .mp-editor .editor {
118
+ display: flex;
119
+ height: 500px;
120
+ overflow: hidden;
121
+ }
122
+ .mp-editor .lines {
123
+ background: #252526;
124
+ color: #858585;
125
+ padding: 8px;
126
+ text-align: right;
127
+ user-select: none;
128
+ line-height: 20px;
129
+ flex-shrink: 0;
130
+ overflow: hidden;
131
+ white-space: pre;
132
+ }
133
+ .mp-editor textarea {
134
+ flex: 1;
135
+ background: #1e1e1e;
136
+ color: #d4d4d4;
137
+ border: none;
138
+ padding: 8px;
139
+ resize: none;
140
+ outline: none;
141
+ font-family: monospace;
142
+ line-height: 20px;
143
+ overflow: auto;
144
+ }
145
+ .mp-editor .lines,
146
+ .mp-editor input,
147
+ .mp-editor textarea {
148
+ font-size: 14px;
149
+ }
150
+ `;
151
+ document.head.appendChild(css);
152
+ }
153
+
154
+ /* ---------- Syntax registry ---------- */
155
+
156
+ // 🔹 NEW
157
+ const SYNTAX_CHECKERS = {
158
+ ".py": checkPythonSyntax,
159
+ // ".js": checkJSSyntax,
160
+ // ".html": checkHTMLSyntax,
161
+ };
162
+
163
+ // 🔹 NEW
164
+ function getCheckerFor(name) {
165
+ const ext = "." + name.split(".").pop().toLowerCase();
166
+ return SYNTAX_CHECKERS[ext] || null;
167
+ }
168
+
169
+ /* ---------- Editor Implementation ---------- */
170
+
171
+ class EmbeddedEditor {
172
+ constructor(container) {
173
+ this.container = container;
174
+ this.buildUI();
175
+ this.bindEvents();
176
+ }
177
+
178
+ buildUI() {
179
+ console.info("editor.js: EmbeddedEditor.buildUI");
180
+ this.container.innerHTML = `
181
+ <div class="mp-editor">
182
+ <div class="toolbar">
183
+ <input class="filename" value="">
184
+ <button class="load">Load</button>
185
+ <button class="save">Save</button>
186
+ <button class="syntax">Syntax</button>
187
+ <span class="status info">ready</span>
188
+ <button class="close" title="Close">✕</button>
189
+ </div>
190
+ <div class="editor">
191
+ <div class="lines"></div>
192
+ <textarea class="code" wrap="off"></textarea>
193
+ </div>
194
+ </div>`;
195
+ this.codeEl = this.container.querySelector(".code");
196
+ this.linesEl = this.container.querySelector(".lines");
197
+ this.fileEl = this.container.querySelector(".filename");
198
+ this.statusEl = this.container.querySelector(".status");
199
+ this.syntaxBtn = this.container.querySelector(".syntax"); // 🔹 NEW
200
+ }
201
+
202
+ bindEvents() {
203
+ this.codeEl.addEventListener("input", () => {
204
+ this.updateLines();
205
+ this.setStatus("edited");
206
+ });
207
+ this.codeEl.addEventListener("scroll", () =>
208
+ this.linesEl.scrollTop = this.codeEl.scrollTop
209
+ );
210
+ this.codeEl.addEventListener("keydown", e => {
211
+ if (e.key === "Tab") {
212
+ e.preventDefault();
213
+ const s = this.codeEl.selectionStart;
214
+ const ePos = this.codeEl.selectionEnd;
215
+ this.codeEl.value =
216
+ this.codeEl.value.slice(0, s) +
217
+ " " +
218
+ this.codeEl.value.slice(ePos);
219
+ this.codeEl.selectionStart = this.codeEl.selectionEnd = s + 4;
220
+ this.updateLines();
221
+ }
222
+ });
223
+ this.fileEl.addEventListener("input", () => // 🔹 NEW
224
+ this.updateSyntaxAvailability()
225
+ );
226
+ this.container.querySelector(".load")
227
+ .addEventListener("click", () => this.loadFile());
228
+ this.container.querySelector(".save")
229
+ .addEventListener("click", () => this.save());
230
+ this.container.querySelector(".syntax")
231
+ .addEventListener("click", () => this.syntaxCheck());
232
+ this.container.querySelector(".close")
233
+ .addEventListener("click", () => window.destroyEditor());
234
+ }
235
+
236
+ /* ---------- UI helpers ---------- */
237
+
238
+ setStatus(text, type = "info") {
239
+ this.statusEl.textContent = text;
240
+ this.statusEl.className = "status " + type;
241
+ }
242
+
243
+ updateSyntaxAvailability() { // 🔹 NEW
244
+ this.syntaxBtn.style.display =
245
+ getCheckerFor(this.fileEl.value) ? "" : "none";
246
+ }
247
+
248
+ updateLines() {
249
+ const scroll = this.codeEl.scrollTop;
250
+ const count = this.codeEl.value.split("\n").length;
251
+ this.linesEl.textContent =
252
+ Array.from({ length: count }, (_, i) => i + 1).join("\n");
253
+ this.linesEl.scrollTop = scroll;
254
+ }
255
+
256
+ /* ---------- File ops ---------- */
257
+ open(url) {
258
+ const name = url?.split("/").pop();
259
+ this.setStatus("loading...");
260
+ fetch(url)
261
+ .then(r => r.ok ? r.text() : Promise.reject())
262
+ .then(t => {
263
+ // 🔹 Success → show file content + path
264
+ this.codeEl.value = t;
265
+ this.fileEl.value = url;
266
+ this.updateLines();
267
+ this.updateSyntaxAvailability();
268
+ this.setStatus("loaded", "ok");
269
+ })
270
+ .catch(() => {
271
+ // 🔹 Failure → special case for LM_blinky.py
272
+ if (name === "LM_blinky.py") {
273
+ this.fileEl.value = url || ""; // 🔹 show path in input
274
+ this.loadExample();
275
+ } else {
276
+ // 🔹 Empty editor, but still show file path
277
+ this.codeEl.value = "";
278
+ this.fileEl.value = url || "";
279
+ this.updateLines();
280
+ this.updateSyntaxAvailability();
281
+ this.setStatus("file not found or unreadable", "err");
282
+ }
283
+ });
284
+ }
285
+
286
+ loadFile() {
287
+ if (!this.fileEl.value)
288
+ return this.setStatus("no filename", "err");
289
+ console.info("editor.js: EmbeddedEditor.loadFile: ", this.fileEl.value);
290
+ this.open(this.fileEl.value);
291
+ }
292
+
293
+ save() {
294
+ const name = this.fileEl.value;
295
+ if (!name) {
296
+ this.setStatus("no filename", "err");
297
+ return;
298
+ }
299
+
300
+ console.info("editor.js: EmbeddedEditor.save (upload): ", name);
301
+ const blob = new Blob([this.codeEl.value], { type: "text/plain" });
302
+ const file = new File([blob], name);
303
+ const fd = new FormData();
304
+ fd.append("file", file);
305
+
306
+ fetch("/fs/files", { method: "POST", body: fd })
307
+ .then(async r => {
308
+ if (!r.ok) {
309
+ const t = (await r.text()) || r.statusText;
310
+ console.error("editor.js: upload failed:", r.status, r.statusText, t);
311
+ throw new Error(`${r.status} - ${t}`);
312
+ }
313
+ this.setStatus("saved", "ok");
314
+ })
315
+ .catch(err => {
316
+ console.error("editor.js: upload error:", err);
317
+ this.setStatus("Save failed: " + err.message, "err");
318
+ });
319
+ }
320
+
321
+ /* ---------- Syntax ---------- */
322
+ syntaxCheck() { // 🔹 MODIFIED
323
+ const checker = getCheckerFor(this.fileEl.value);
324
+ if (!checker) return;
325
+
326
+ const r = checker(this.codeEl.value);
327
+ this.setStatus(
328
+ r.ok ? "syntax OK" : Object.entries(r.errors[0]).map(([k, v]) => `${k}=${JSON.stringify(v)}`).join(" "),
329
+ r.ok ? "ok" : "err"
330
+ );
331
+ }
332
+
333
+ /* ---------- Close ---------- */
334
+ close() {
335
+ this.container.innerHTML = "";
336
+ }
337
+
338
+ /* ---------- Example ---------- */
339
+
340
+ loadExample() {
341
+ console.info("editor.js: EmbeddedEditor.loadExample");
342
+ this.codeEl.value =
343
+ `# LM_blinky.py – MicroPython example
344
+ # Guide: https://github.com/BxNxM/micrOS/blob/master/APPLICATION_GUIDE.md
345
+ import machine
346
+ from microIO import bind_pin, pinmap_search
347
+ from Common import micro_task
348
+
349
+ global LED = None
350
+
351
+ def load(pin=2):
352
+ global LED
353
+ if LED is None:
354
+ LED = machine.Pin(bind_pin("led", pin), machine.Pin.OUT)
355
+ return LED
356
+
357
+ @micro_task("blinky", _wrap=True)
358
+ def blink(tag):
359
+ with micro_task(tag=tag) as my_task:
360
+ if LED is None:
361
+ my_task.out = "LED uninitialized"
362
+ return
363
+ my_task.out = "BlinkyBlink task"
364
+ while True:
365
+ LED.value(not LED.value())
366
+ await my_task.feed(sleep_ms=500)
367
+
368
+ def pinmap():
369
+ return pinmap_search(['led'])
370
+
371
+ def help(widgets=False):
372
+ return "load pin=2", "blink", "pinmap"
373
+ `;
374
+ this.updateLines();
375
+ this.updateSyntaxAvailability();
376
+ this.setStatus("example loaded", "info");
377
+ }
378
+
379
+ }
380
+
381
+ /* ---------- Syntax checker(s) ---------- */
382
+
383
+ function checkPythonSyntax(text) {
384
+ const lines = text
385
+ .replace(/\t/g, " ")
386
+ .replace(/\s+$/, "")
387
+ .split("\n");
388
+ const stack = [0];
389
+ const errors = [];
390
+ const colonRE = /^(async\s+)?(def|with|class)\s+/;
391
+ let depth = 0;
392
+ function lastCodeLine(i) {
393
+ while (i >= 0) {
394
+ const t = lines[i].trim();
395
+ if (t && !t.startsWith("#")) return t;
396
+ i--;
397
+ }
398
+ return "";
399
+ }
400
+ function updateDepth(d, line) {
401
+ for (const c of line.replace(/#.*$/, "")) {
402
+ if ("([{".includes(c)) d++;
403
+ else if (")]}".includes(c)) d = Math.max(0, d - 1);
404
+ }
405
+ return d;
406
+ }
407
+ lines.forEach((line, i) => {
408
+ const n = i + 1;
409
+ const t = line.trim();
410
+ const depthBefore = depth;
411
+ depth = updateDepth(depth, line);
412
+ const topLevel = depthBefore === 0 && depth === 0;
413
+ if (!t || t.startsWith("#")) return;
414
+ const ind = line.match(/^ */)[0].length;
415
+ const cur = stack[stack.length - 1];
416
+ // Indentation check (only at top level)
417
+ if (topLevel) {
418
+ if (ind > cur) {
419
+ const prev = lastCodeLine(i - 1);
420
+ if (!prev.endsWith(":")) {
421
+ errors.push({ line: n, error: "indent", prev, got: ind, expected: cur });
422
+ return;
423
+ }
424
+ stack.push(ind);
425
+ }
426
+ while (stack.length > 1 && ind < stack[stack.length - 1]) {
427
+ stack.pop();
428
+ }
429
+ if (ind !== stack[stack.length - 1]) {
430
+ errors.push({ line: n, error: "dedent", got: ind, expected: stack[stack.length - 1] });
431
+ return;
432
+ }
433
+ }
434
+ // Colon check
435
+ if (colonRE.test(t) && !t.endsWith(":")) {
436
+ errors.push({ line: n, error: "colon", lineText: t });
437
+ }
438
+ });
439
+ return { ok: errors.length === 0, errors };
440
+ }