micrOSDevToolKit 2.10.6__py3-none-any.whl → 2.13.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (151) 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/esp32c6-GENERIC-20250415-v1.25.0.bin +0 -0
  4. micrOS/micropython/esp32s3-4MBflash-20241129-v1.24.1.bin +0 -0
  5. micrOS/release_info/micrOS_ReleaseInfo/system_analysis_sum.json +57 -61
  6. micrOS/source/Common.py +286 -91
  7. micrOS/source/Config.py +7 -7
  8. micrOS/source/Debug.py +50 -94
  9. micrOS/source/Espnow.py +7 -7
  10. micrOS/source/Files.py +23 -2
  11. micrOS/source/Hooks.py +62 -19
  12. micrOS/source/IO_esp32c6.py +16 -0
  13. micrOS/source/IO_esp32s3.py +37 -1
  14. micrOS/source/IO_m5stamp.py +35 -1
  15. micrOS/source/IO_qtpy.py +22 -17
  16. micrOS/source/IO_s3matrix.py +21 -0
  17. micrOS/source/IO_tinypico.py +38 -0
  18. micrOS/source/InterConnect.py +5 -5
  19. micrOS/source/Interrupts.py +2 -2
  20. micrOS/source/LM_VL53L0X.py +1 -1
  21. micrOS/source/LM_buzzer.py +6 -7
  22. micrOS/source/LM_cct.py +6 -5
  23. micrOS/source/LM_dashboard_be.py +2 -2
  24. micrOS/source/LM_dimmer.py +6 -5
  25. micrOS/source/LM_espnow.py +15 -10
  26. micrOS/source/LM_i2c.py +3 -2
  27. micrOS/source/LM_neoeffects.py +173 -230
  28. micrOS/source/LM_neomatrix.py +335 -0
  29. micrOS/source/LM_neopixel.py +10 -10
  30. micrOS/source/LM_pacman.py +40 -23
  31. micrOS/source/LM_qmi8658.py +204 -0
  32. micrOS/source/LM_rgb.py +6 -6
  33. micrOS/source/LM_roboarm.py +5 -4
  34. micrOS/source/LM_switch.py +6 -4
  35. micrOS/source/LM_tcs3472.py +75 -0
  36. micrOS/source/LM_telegram.py +5 -4
  37. micrOS/source/Logger.py +47 -33
  38. micrOS/source/Network.py +6 -6
  39. micrOS/source/Notify.py +2 -2
  40. micrOS/source/Scheduler.py +5 -5
  41. micrOS/source/Server.py +6 -6
  42. micrOS/source/Shell.py +4 -4
  43. micrOS/source/Tasks.py +20 -17
  44. micrOS/source/Time.py +12 -10
  45. micrOS/source/Types.py +2 -2
  46. micrOS/source/Web.py +20 -13
  47. micrOS/source/__pycache__/Common.cpython-312.pyc +0 -0
  48. micrOS/source/__pycache__/Debug.cpython-312.pyc +0 -0
  49. micrOS/source/__pycache__/Logger.cpython-312.pyc +0 -0
  50. micrOS/source/__pycache__/Server.cpython-312.pyc +0 -0
  51. micrOS/source/micrOS.py +10 -7
  52. micrOS/source/micrOSloader.py +6 -6
  53. micrOS/source/microIO.py +8 -6
  54. micrOS/source/urequests.py +4 -4
  55. {microsdevtoolkit-2.10.6.dist-info → microsdevtoolkit-2.13.0.dist-info}/METADATA +24 -22
  56. {microsdevtoolkit-2.10.6.dist-info → microsdevtoolkit-2.13.0.dist-info}/RECORD +142 -132
  57. toolkit/DevEnvCompile.py +20 -15
  58. toolkit/DevEnvOTA.py +29 -8
  59. toolkit/DevEnvUSB.py +52 -10
  60. toolkit/LM_to_compile.dat +1 -0
  61. toolkit/MicrOSDevEnv.py +10 -2
  62. toolkit/MicrosFiles.py +26 -0
  63. toolkit/dashboard_apps/NeoEffectsDemo.py +8 -15
  64. toolkit/dashboard_apps/QMI8685_GYRO.py +68 -0
  65. toolkit/dashboard_apps/_app_base.py +2 -2
  66. toolkit/dashboard_apps/_gyro_visualizer.py +78 -0
  67. toolkit/lib/LocalMachine.py +6 -1
  68. toolkit/lib/file_extensions.py +9 -3
  69. toolkit/micrOSlint.py +3 -1
  70. toolkit/simulator_lib/__pycache__/IO_darwin.cpython-312.pyc +0 -0
  71. toolkit/simulator_lib/__pycache__/machine.cpython-312.pyc +0 -0
  72. toolkit/simulator_lib/__pycache__/neopixel.cpython-312.pyc +0 -0
  73. toolkit/simulator_lib/machine.py +0 -1
  74. toolkit/simulator_lib/neopixel.py +3 -2
  75. toolkit/socketClient.py +3 -2
  76. toolkit/workspace/precompiled/Common.cpython-312.pyc +0 -0
  77. toolkit/workspace/precompiled/Common.mpy +0 -0
  78. toolkit/workspace/precompiled/Config.mpy +0 -0
  79. toolkit/workspace/precompiled/Debug.mpy +0 -0
  80. toolkit/workspace/precompiled/Espnow.mpy +0 -0
  81. toolkit/workspace/precompiled/Files.mpy +0 -0
  82. toolkit/workspace/precompiled/Hooks.mpy +0 -0
  83. toolkit/workspace/precompiled/IO_esp32c6.mpy +0 -0
  84. toolkit/workspace/precompiled/IO_esp32s3.mpy +0 -0
  85. toolkit/workspace/precompiled/IO_m5stamp.mpy +0 -0
  86. toolkit/workspace/precompiled/IO_qtpy.mpy +0 -0
  87. toolkit/workspace/precompiled/IO_s3matrix.mpy +0 -0
  88. toolkit/workspace/precompiled/IO_tinypico.mpy +0 -0
  89. toolkit/workspace/precompiled/InterConnect.mpy +0 -0
  90. toolkit/workspace/precompiled/Interrupts.mpy +0 -0
  91. toolkit/workspace/precompiled/LM_VL53L0X.py +1 -1
  92. toolkit/workspace/precompiled/LM_buzzer.mpy +0 -0
  93. toolkit/workspace/precompiled/LM_cct.mpy +0 -0
  94. toolkit/workspace/precompiled/LM_dashboard_be.py +2 -2
  95. toolkit/workspace/precompiled/LM_dimmer.mpy +0 -0
  96. toolkit/workspace/precompiled/LM_espnow.py +15 -10
  97. toolkit/workspace/precompiled/LM_i2c.py +3 -2
  98. toolkit/workspace/precompiled/LM_neoeffects.mpy +0 -0
  99. toolkit/workspace/precompiled/LM_neomatrix.mpy +0 -0
  100. toolkit/workspace/precompiled/LM_neopixel.mpy +0 -0
  101. toolkit/workspace/precompiled/LM_pacman.mpy +0 -0
  102. toolkit/workspace/precompiled/LM_qmi8658.py +204 -0
  103. toolkit/workspace/precompiled/LM_rgb.mpy +0 -0
  104. toolkit/workspace/precompiled/LM_roboarm.mpy +0 -0
  105. toolkit/workspace/precompiled/LM_switch.mpy +0 -0
  106. toolkit/workspace/precompiled/LM_tcs3472.py +75 -0
  107. toolkit/workspace/precompiled/LM_telegram.mpy +0 -0
  108. toolkit/workspace/precompiled/Logger.cpython-312.pyc +0 -0
  109. toolkit/workspace/precompiled/Logger.mpy +0 -0
  110. toolkit/workspace/precompiled/Network.mpy +0 -0
  111. toolkit/workspace/precompiled/Notify.mpy +0 -0
  112. toolkit/workspace/precompiled/Scheduler.mpy +0 -0
  113. toolkit/workspace/precompiled/Server.cpython-312.pyc +0 -0
  114. toolkit/workspace/precompiled/Server.mpy +0 -0
  115. toolkit/workspace/precompiled/Shell.mpy +0 -0
  116. toolkit/workspace/precompiled/Tasks.mpy +0 -0
  117. toolkit/workspace/precompiled/Time.mpy +0 -0
  118. toolkit/workspace/precompiled/Types.mpy +0 -0
  119. toolkit/workspace/precompiled/Web.mpy +0 -0
  120. toolkit/workspace/precompiled/micrOS.mpy +0 -0
  121. toolkit/workspace/precompiled/micrOSloader.mpy +0 -0
  122. toolkit/workspace/precompiled/microIO.mpy +0 -0
  123. toolkit/workspace/precompiled/urequests.mpy +0 -0
  124. micrOS/micropython/esp32s3-20240105-v1.22.1.bin +0 -0
  125. micrOS/source/LM_catgame.py +0 -75
  126. micrOS/source/LM_demo.py +0 -97
  127. micrOS/source/LM_intercon.py +0 -60
  128. micrOS/source/LM_ph_sensor.py +0 -51
  129. toolkit/workspace/precompiled/LM_catgame.py +0 -75
  130. toolkit/workspace/precompiled/LM_demo.py +0 -97
  131. toolkit/workspace/precompiled/LM_intercon.mpy +0 -0
  132. toolkit/workspace/precompiled/LM_ph_sensor.py +0 -51
  133. /micrOS/micropython/{esp32s3-20241129-v1.24.1.bin → esp32s3-8MBflash-20241129-v1.24.1.bin} +0 -0
  134. /micrOS/source/{dashboard.html → web/dashboard.html} +0 -0
  135. /micrOS/source/{index.html → web/index.html} +0 -0
  136. /micrOS/source/{uapi.js → web/uapi.js} +0 -0
  137. /micrOS/source/{udashboard.js → web/udashboard.js} +0 -0
  138. /micrOS/source/{ustyle.css → web/ustyle.css} +0 -0
  139. /micrOS/source/{uwidgets.js → web/uwidgets.js} +0 -0
  140. /micrOS/source/{uwidgets_pro.js → web/uwidgets_pro.js} +0 -0
  141. {microsdevtoolkit-2.10.6.data → microsdevtoolkit-2.13.0.data}/scripts/devToolKit.py +0 -0
  142. {microsdevtoolkit-2.10.6.dist-info → microsdevtoolkit-2.13.0.dist-info}/WHEEL +0 -0
  143. {microsdevtoolkit-2.10.6.dist-info → microsdevtoolkit-2.13.0.dist-info}/licenses/LICENSE +0 -0
  144. {microsdevtoolkit-2.10.6.dist-info → microsdevtoolkit-2.13.0.dist-info}/top_level.txt +0 -0
  145. /toolkit/workspace/precompiled/{dashboard.html → web/dashboard.html} +0 -0
  146. /toolkit/workspace/precompiled/{index.html → web/index.html} +0 -0
  147. /toolkit/workspace/precompiled/{uapi.js → web/uapi.js} +0 -0
  148. /toolkit/workspace/precompiled/{udashboard.js → web/udashboard.js} +0 -0
  149. /toolkit/workspace/precompiled/{ustyle.css → web/ustyle.css} +0 -0
  150. /toolkit/workspace/precompiled/{uwidgets.js → web/uwidgets.js} +0 -0
  151. /toolkit/workspace/precompiled/{uwidgets_pro.js → web/uwidgets_pro.js} +0 -0
toolkit/DevEnvCompile.py CHANGED
@@ -133,12 +133,13 @@ class Compile:
133
133
 
134
134
  def __cleanup_precompiled_dir(self):
135
135
  self.console("Delete precompiled components: {}".format(self.precompiled_micrOS_dir_path))
136
- for source in [pysource for pysource in LocalMachine.FileHandler.list_dir(self.precompiled_micrOS_dir_path)
137
- if check_all_extensions(pysource)]:
136
+ for source in LocalMachine.FileHandler.list_dir(self.precompiled_micrOS_dir_path):
138
137
  to_remove_path = os.path.join(self.precompiled_micrOS_dir_path, source)
139
- self.console("\t|-remove: {}".format(to_remove_path), state='imp')
140
- if not self.dry_run:
141
- LocalMachine.FileHandler.remove(to_remove_path)
138
+ if check_all_extensions(source) or LocalMachine.FileHandler.path_is_exists(to_remove_path)[1] == "d":
139
+ self.console("\t|-remove: {}".format(to_remove_path), state='imp')
140
+ if not self.dry_run:
141
+ if not LocalMachine.FileHandler.remove(to_remove_path):
142
+ self.console(f"\t\t|-ERROR: Failed to remove {to_remove_path}", state="err")
142
143
 
143
144
  def get_micros_version_from_repo(self):
144
145
  # Get repo version
@@ -235,17 +236,21 @@ class Compile:
235
236
  workdir_handler = LocalMachine.SimplePopPushd()
236
237
  workdir_handler.pushd(self.micrOS_dir_path)
237
238
 
238
- self.console("COPY additional resources")
239
- # Filter component source
240
- for source in [pysource for pysource in LocalMachine.FileHandler.list_dir(self.micrOS_dir_path) if
241
- check_web_extensions(pysource)]:
239
+ self.console("COPY additional resources...", state="ok")
240
+ for source in LocalMachine.FileHandler.list_dir(self.micrOS_dir_path):
242
241
  source_path = os.path.join(self.micrOS_dir_path, source)
243
- if self.dry_run:
244
- state = True
245
- else:
246
- state = LocalMachine.FileHandler.copy(source_path, self.precompiled_micrOS_dir_path)
247
- if not state:
248
- self.console("Copy error", state='err')
242
+ # COPY DIRECTORY RESOURCES (/web)
243
+ if (LocalMachine.FileHandler.path_is_exists(source_path)[1] == 'd' and
244
+ not (source.startswith("_") or source.startswith("."))):
245
+ if self.dry_run:
246
+ state = True
247
+ else:
248
+ target_dir = os.path.join(self.precompiled_micrOS_dir_path, source)
249
+ self.console(f"|- COPY DIR: {source_path} -> {target_dir}", state="ok")
250
+ state = LocalMachine.FileHandler.copy(source_path, target_dir)
251
+ if not state:
252
+ self.console("Copy error", state='err')
253
+
249
254
  workdir_handler.popd()
250
255
 
251
256
 
toolkit/DevEnvOTA.py CHANGED
@@ -5,22 +5,26 @@ MYPATH = os.path.dirname(__file__)
5
5
  print("Module [DevEnvOTA] path: {} __package__: {} __name__: {} __file__: {}".format(
6
6
  sys.path[0], __package__, __name__, MYPATH))
7
7
 
8
+ from pprint import pprint
9
+
8
10
  try:
9
11
  from .DevEnvCompile import Compile
10
12
  from . import socketClient
11
13
  from .lib import LocalMachine
12
14
  from .lib.TerminalColors import Colors
13
15
  from .lib.SafeInput import input_with_timeout
14
- from .lib.file_extensions import check_all_extensions
16
+ from .lib.file_extensions import check_all_extensions, check_web_extensions, check_python_extensions
15
17
  from .lib.Repository import git_clone_archive, git_clone
18
+ from .MicrosFiles import micros_resource_list
16
19
  except Exception as e:
17
20
  print("Import warning __name__:{}: {}".format(__name__, e))
18
21
  from DevEnvCompile import Compile
19
22
  from lib import LocalMachine
20
23
  from lib.TerminalColors import Colors
21
24
  from lib.SafeInput import input_with_timeout
22
- from lib.file_extensions import check_all_extensions
25
+ from lib.file_extensions import check_all_extensions, check_web_extensions, check_python_extensions
23
26
  from lib.Repository import git_clone_archive, git_clone
27
+ from MicrosFiles import micros_resource_list
24
28
 
25
29
  sys.path.append(MYPATH)
26
30
  import socketClient
@@ -241,9 +245,9 @@ class OTA(Compile):
241
245
  self.console(" loader update: {}".format(force_mode), state='OK')
242
246
 
243
247
  # Parse files from precompiled dir
244
- resource_list_to_upload = [os.path.join(self.precompiled_micrOS_dir_path, pysource) for pysource in
245
- LocalMachine.FileHandler.list_dir(self.precompiled_micrOS_dir_path)
246
- if check_all_extensions(pysource)]
248
+ resource_list_to_upload, dir_list_to_create = micros_resource_list(self.precompiled_micrOS_dir_path)
249
+ # LIMITATION: WEBREPL Cannot create directories with remote command...
250
+
247
251
  # Apply upload settings on parsed resources
248
252
  for index, source in enumerate(resource_list_to_upload):
249
253
  source_name = os.path.basename(source)
@@ -268,7 +272,8 @@ class OTA(Compile):
268
272
  # Add source to upload
269
273
  upload_path_list.append(source)
270
274
  # Upload files / sources
271
- return self.ota_webrepl_update_core(device, upload_path_list=upload_path_list, ota_password=webrepl_password)
275
+ return self.ota_webrepl_update_core(device, upload_path_list=upload_path_list,
276
+ ota_password=webrepl_password, upload_root_dir=self.precompiled_micrOS_dir_path)
272
277
 
273
278
  def _enable_micros_ota_update_via_webrepl(self, device=None, ota_password=None):
274
279
  # Get specific device from device list
@@ -401,7 +406,8 @@ class OTA(Compile):
401
406
  print(f"[SIM] 'OTA' COPY FILES... {source} -> {target}")
402
407
  LocalMachine.FileHandler().copy(source, target)
403
408
 
404
- def ota_webrepl_update_core(self, device=None, upload_path_list=[], ota_password='ADmin123', force_lm=False):
409
+ def ota_webrepl_update_core(self, device=None, upload_path_list=None, ota_password='ADmin123',
410
+ force_lm=False, upload_root_dir=None):
405
411
  """
406
412
  Generic file uploader for micrOS - over webrepl
407
413
  info: https://techoverflow.net/2020/02/22/how-to-upload-files-to-micropython-using-webrepl-using-webrepl_cli-py/
@@ -410,7 +416,11 @@ class OTA(Compile):
410
416
  upload_path_list: file path list to upload
411
417
  ota_password - accessing webrepl to upload files
412
418
  force_lm - use prefix as 'LM_' for every file - for user file upload / GUI drag n drop
419
+ upload_root_dir - root directory to upload files (subdir support)
413
420
  """
421
+ if upload_path_list is None:
422
+ upload_path_list = []
423
+
414
424
  if device[0] == "__simulator__":
415
425
  OTA.sim_ota_update(upload_path_list, force_lm)
416
426
  return
@@ -457,7 +467,18 @@ class OTA(Compile):
457
467
  # Copy retry mechanism
458
468
  exitcode = -1
459
469
  source_name = os.path.basename(source)
460
- source_name_target = source_name
470
+ if upload_root_dir is None:
471
+ # Drag-n-Drop file upload file type check and folder adjustment
472
+ if check_web_extensions(source_name):
473
+ source_name_target = os.path.join('web', source_name)
474
+ elif not check_python_extensions(source_name) and not source_name.endswith("node_config.json"):
475
+ source_name_target = os.path.join('data', source_name)
476
+ else:
477
+ # Copy file to micrOS root folder (.mpy and .py or node_config.json)
478
+ source_name_target = source_name
479
+ else:
480
+ # MAIN USE-CASE
481
+ source_name_target = source.replace(upload_root_dir, '')
461
482
 
462
483
  # Force LM update - user load modules - drag n drop files
463
484
  if force_lm and not source_name.startswith('LM_') and source_name.endswith('.py'):
toolkit/DevEnvUSB.py CHANGED
@@ -13,12 +13,14 @@ try:
13
13
  from .lib import LocalMachine
14
14
  from .lib.TerminalColors import Colors
15
15
  from .lib.SerialDriverHandler import install_usb_serial_driver
16
+ from .MicrosFiles import micros_resource_list
16
17
  except Exception as e:
17
18
  print("Import warning __name__:{}: {}".format(__name__, e))
18
19
  from DevEnvCompile import Compile
19
20
  from lib import LocalMachine
20
21
  from lib.TerminalColors import Colors
21
22
  from lib.SerialDriverHandler import install_usb_serial_driver
23
+ from MicrosFiles import micros_resource_list
22
24
 
23
25
 
24
26
  class USB(Compile):
@@ -77,6 +79,11 @@ class USB(Compile):
77
79
  'deploy': '{esptool_interface} --chip esp32c3 --port {dev} --baud 460800 write_flash -z 0x0 {micropython}',
78
80
  'mpremote_cmd': 'mpremote',
79
81
  'cmd_line_info': '[!HINT!] Fully automatic deployment...'},
82
+ 'esp32c6':
83
+ {'erase': '{esptool_interface} --chip esp32c6 --port {dev} erase_flash',
84
+ 'deploy': '{esptool_interface} --chip esp32c6 --port {dev} --baud 460800 write_flash -z 0x0 {micropython}',
85
+ 'mpremote_cmd': 'mpremote',
86
+ 'cmd_line_info': '[!HINT!] Fully automatic deployment...'},
80
87
  }
81
88
  if not USB.usb_driver_ok:
82
89
  # Optimization - driver check
@@ -202,6 +209,38 @@ class USB(Compile):
202
209
  self.console("Deployment failed.\n{} - {}".format(stdout, stderr), state='err')
203
210
  return False
204
211
 
212
+ def _mkdir_on_dev(self, folders:list):
213
+ mpremote_cmd = self.dev_types_and_cmds[self.selected_device_type]['mpremote_cmd']
214
+ device = self.get_devices()[0]
215
+ if mpremote_cmd is None:
216
+ # Legacy ampy command (esp32 auto reboot tolerance...)
217
+ mkdir_cmd = self.dev_types_and_cmds[self.selected_device_type]['ampy_cmd'].format(dev=device, args=f'mkdir')
218
+ else:
219
+ mkdir_cmd = f'{mpremote_cmd} fs mkdir'
220
+
221
+ status = 0
222
+ for folder in folders:
223
+ _mkdir_cmd = f"{mkdir_cmd} {folder}"
224
+ self.console(f"Create directory on device: {_mkdir_cmd}")
225
+ if self.dry_run:
226
+ pass
227
+ else:
228
+ try:
229
+ exitcode, stdout, stderr = LocalMachine.CommandHandler.run_command(_mkdir_cmd, shell=True)
230
+ if exitcode != 0:
231
+ verdict = stdout + stderr
232
+ if "File exists" in verdict or "Directory already exists" in verdict:
233
+ exitcode = 0
234
+ else:
235
+ self.console(f"MKDIR ERROR:\n{stdout}\n{stderr}", state="err")
236
+ except Exception as e:
237
+ self.console(f"MKDIR ERROR {_mkdir_cmd}: {e}", state="err")
238
+ exitcode = 1
239
+ status += exitcode
240
+
241
+ return True if status == 0 else False
242
+
243
+
205
244
  def put_micros_to_dev(self):
206
245
  self.select_board_n_micropython()
207
246
  status = True
@@ -218,17 +257,20 @@ class USB(Compile):
218
257
  self.console(f"... wait for reset {10-k} sec", state='imp')
219
258
  time.sleep(1)
220
259
 
221
- mpremote_cmd = self.dev_types_and_cmds[self.selected_device_type]['mpremote_cmd']
222
- device = self.get_devices()[0]
223
- source_to_put_device = LocalMachine.FileHandler.list_dir(self.precompiled_micrOS_dir_path)
260
+ # Parse micrOS resources with folders
261
+ _source_to_put_device, dir_list_to_create = micros_resource_list(self.precompiled_micrOS_dir_path)
262
+ self.console(f"CREATE FOLDERS: {dir_list_to_create}", state="ok")
263
+ # Create sub folders
264
+ if not self._mkdir_on_dev(dir_list_to_create):
265
+ self.console(f"Error creating directories on device: {dir_list_to_create}")
266
+ sys.exit(1)
267
+ # Generate resource list to be put on the device
268
+ source_to_put_device = list([s.replace(self.precompiled_micrOS_dir_path + "/", '') for s in _source_to_put_device])
224
269
  # Set source order - main, boot
225
- source_to_put_device.append(source_to_put_device.pop(source_to_put_device.index('main.py')))
226
- try:
227
- # PIP deployment generates this ...
228
- source_to_put_device.remove('__pycache__') # remove if accidentally left here
229
- except:
230
- pass
270
+ source_to_put_device.append(source_to_put_device.pop(source_to_put_device.index("main.py")))
231
271
 
272
+ mpremote_cmd = self.dev_types_and_cmds[self.selected_device_type]['mpremote_cmd']
273
+ device = self.get_devices()[0]
232
274
  # Change workdir
233
275
  workdir_handler = LocalMachine.SimplePopPushd()
234
276
  workdir_handler.pushd(self.precompiled_micrOS_dir_path)
@@ -238,7 +280,7 @@ class USB(Compile):
238
280
  self.console("[{}%] micrOS deploy via USB - {}".format(percent, device))
239
281
  if mpremote_cmd is None:
240
282
  # Legacy ampy command (esp32 auto reboot tolerance...)
241
- command = self.dev_types_and_cmds[self.selected_device_type]['ampy_cmd'].format(dev=device, args=f'put {source}')
283
+ command = self.dev_types_and_cmds[self.selected_device_type]['ampy_cmd'].format(dev=device, args=f'put {source} /{source}')
242
284
  else:
243
285
  command = f'{mpremote_cmd} fs cp {source} :{source}' # new mpremote <1.24.1
244
286
  if ' ' in source:
toolkit/LM_to_compile.dat CHANGED
@@ -40,3 +40,4 @@ LM_oledui.py
40
40
  LM_haptic.py
41
41
  LM_distance.py
42
42
  LM_veml7700.py
43
+ LM_neomatrix.py
toolkit/MicrOSDevEnv.py CHANGED
@@ -62,8 +62,16 @@ class MicrOSDevTool(OTA, USB):
62
62
  if f.endswith('.json'):
63
63
  continue
64
64
  f_path = os.path.join(self.micrOS_dir_path, f)
65
- self.console("[SIM] Copy micrOS resources: {} -> {}".format(f_path, self.micros_sim_workspace))
66
- LocalMachine.FileHandler().copy(f_path, self.micros_sim_workspace)
65
+ if f.startswith("_") or f.startswith("."):
66
+ # SKIP files startswith `_` and `.`
67
+ continue
68
+ _, f_type = LocalMachine.FileHandler.path_is_exists(f_path)
69
+ target_dir = self.micros_sim_workspace
70
+ if f_type == "d":
71
+ target_dir = os.path.join(self.micros_sim_workspace, f)
72
+ self.console(f"[SIM] Copy micrOS resources: {f_path} -> {target_dir}")
73
+ if not LocalMachine.FileHandler().copy(f_path, target_dir):
74
+ self.console(f"[ERROR] Failed to copy: {f_path}")
67
75
 
68
76
  if prepare_only:
69
77
  # In case of automatic node_conf creation
toolkit/MicrosFiles.py ADDED
@@ -0,0 +1,26 @@
1
+ import os
2
+
3
+ try:
4
+ from .lib import LocalMachine
5
+ from .lib.file_extensions import check_all_extensions, check_web_extensions
6
+ except Exception as e:
7
+ print("Import warning __name__:{}: {}".format(__name__, e))
8
+ from lib import LocalMachine
9
+ from lib.file_extensions import check_all_extensions, check_web_extensions
10
+
11
+ def micros_resource_list(root_folder):
12
+ resources_path = []
13
+ subfolders = []
14
+ for source in LocalMachine.FileHandler.list_dir(root_folder):
15
+ source_full_path = os.path.join(root_folder, source)
16
+ # [1] / Root directory source files and folders.
17
+ if check_all_extensions(source):
18
+ resources_path.append(source_full_path)
19
+ # [2] /dir Handle sub dictionary sources
20
+ elif LocalMachine.FileHandler.path_is_exists(source_full_path)[1] == 'd':
21
+ subfolders.append(source)
22
+ for sub_source in LocalMachine.FileHandler.list_dir(source_full_path):
23
+ sub_source_full_path = os.path.join(source_full_path, sub_source)
24
+ if check_all_extensions(sub_source):
25
+ resources_path.append(sub_source_full_path)
26
+ return resources_path, subfolders
@@ -25,40 +25,33 @@ def app(devfid=None, pwd=None):
25
25
  status, answer = CLIENT.run(args)
26
26
  time.sleep(2)
27
27
 
28
- status, answer = CLIENT.run(['neoeffects rainbow &&'])
28
+ status, answer = CLIENT.run(['neoeffects rainbow'])
29
29
  time.sleep(2)
30
- status, answer = CLIENT.run(['task kill neoeffects.rainbow'])
31
30
 
32
31
  status, answer = CLIENT.run(['neoeffects color 122 18 0'])
33
32
 
34
- status, answer = CLIENT.run(['neoeffects cycle &&'])
33
+ status, answer = CLIENT.run(['neoeffects cycle'])
35
34
  time.sleep(2)
36
- status, answer = CLIENT.run(['task kill neoeffects.cycle'])
37
35
 
38
- status, answer = CLIENT.run(['neoeffects meteor &&'])
36
+ status, answer = CLIENT.run(['neoeffects meteor'])
39
37
  time.sleep(2)
40
- status, answer = CLIENT.run(['task kill neoeffects.meteor'])
41
38
 
42
- status, answer = CLIENT.run(['neoeffects fire &&'])
39
+ status, answer = CLIENT.run(['neoeffects fire'])
43
40
  time.sleep(2)
44
- status, answer = CLIENT.run(['task kill neoeffects.fire'])
45
41
 
46
- time.sleep(1)
47
42
 
48
43
  status, answer = CLIENT.run(['neoeffects random &&500'])
49
44
 
50
- status, answer = CLIENT.run(['neoeffects cycle &&'])
45
+ status, answer = CLIENT.run(['neoeffects cycle'])
51
46
  time.sleep(3)
52
- status, answer = CLIENT.run(['task kill neoeffects.cycle'])
53
47
 
54
- status, answer = CLIENT.run(['neoeffects meteor &&'])
48
+ status, answer = CLIENT.run(['neoeffects meteor'])
55
49
  time.sleep(3)
56
- status, answer = CLIENT.run(['task kill neoeffects.meteor'])
57
50
 
58
- status, answer = CLIENT.run(['neoeffects fire &&'])
51
+ status, answer = CLIENT.run(['neoeffects fire'])
59
52
  time.sleep(3)
60
- status, answer = CLIENT.run(['task kill neoeffects.fire'])
61
53
 
54
+ status, answer = CLIENT.run(['task kill neoeffects.player'])
62
55
  status, answer = CLIENT.run(['task kill neoeffects.random'])
63
56
  status, answer = CLIENT.run(['neopixel color 122 18 0'])
64
57
 
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env python3
2
+
3
+ import os
4
+ import sys
5
+ import json
6
+ import time
7
+ import multiprocessing as mp
8
+
9
+ MYPATH = os.path.dirname(os.path.abspath(__file__))
10
+ sys.path.append(os.path.join(MYPATH, '../lib/'))
11
+
12
+ try:
13
+ from ._app_base import AppBase
14
+ except ImportError:
15
+ from _app_base import AppBase
16
+
17
+ def print_table(data):
18
+ os.system('cls' if os.name == 'nt' else 'clear')
19
+ print(f"{'Sensor':<10} {'X':>10} {'Y':>10} {'Z':>10}")
20
+ for sensor in ['accel', 'gyro']:
21
+ x, y, z = data[sensor]
22
+ print(f"{sensor:<10} {x:10.2f} {y:10.2f} {z:10.2f}")
23
+ if 'temp' in data:
24
+ print(f"{'temp':<10} {data['temp']:>10.2f}")
25
+
26
+
27
+ def app(devfid=None, pwd=None):
28
+ CLIENT = AppBase(device=devfid, password=pwd)
29
+ measure_cmd = 'qmi8685 measure >json'
30
+
31
+ mp.set_start_method('spawn', force=True)
32
+ queue = mp.Queue()
33
+
34
+ # Start GUI process
35
+ from ._gyro_visualizer import visualizer_main
36
+ p = mp.Process(target=visualizer_main, args=(queue,))
37
+ p.start()
38
+
39
+ try:
40
+ for _ in range(10000):
41
+ output = CLIENT.execute([measure_cmd])
42
+ status, result = output[0], output[1]
43
+
44
+ if status:
45
+ try:
46
+ parsed = json.loads(result)
47
+ print_table(parsed)
48
+ queue.put(parsed)
49
+ except Exception as e:
50
+ print(f"[Visualizer queue issue] {e}")
51
+ break
52
+ else:
53
+ print(f"[WARN] {result}")
54
+
55
+ time.sleep(0.05)
56
+
57
+ except KeyboardInterrupt:
58
+ print("Interrupted by user.")
59
+
60
+ finally:
61
+ if p.is_alive():
62
+ p.terminate()
63
+ p.join()
64
+
65
+
66
+
67
+ if __name__ == "__main__":
68
+ app()
@@ -20,10 +20,10 @@ class AppBase:
20
20
  def get_device(self):
21
21
  return self.device
22
22
 
23
- def execute(self, cmd_list, tout=5):
23
+ def execute(self, cmd_list, tout=5, verbose=False):
24
24
  cmd_args = self.base_cmd() + cmd_list
25
25
  print(f"Execute: {cmd_args}")
26
- return socketClient.run(cmd_args, timeout=tout)
26
+ return socketClient.run(cmd_args, timeout=tout, verbose=verbose)
27
27
 
28
28
  def run(self, cmd_list):
29
29
  """Legacy"""
@@ -0,0 +1,78 @@
1
+ import matplotlib.pyplot as plt
2
+ import matplotlib.animation as animation
3
+ import multiprocessing as mp
4
+ from collections import deque
5
+ from datetime import datetime
6
+ import matplotlib.dates as mdates
7
+
8
+ def visualizer_main(queue):
9
+ # Make figure wider and a bit taller
10
+ fig, (ax_accel, ax_gyro) = plt.subplots(2, 1, figsize=(14, 8))
11
+ plt.subplots_adjust(top=0.88, bottom=0.12, hspace=0.3)
12
+
13
+ history = 100
14
+ accel_data = {'x': deque([0] * history, maxlen=history),
15
+ 'y': deque([0] * history, maxlen=history),
16
+ 'z': deque([0] * history, maxlen=history)}
17
+ gyro_data = {'x': deque([0] * history, maxlen=history),
18
+ 'y': deque([0] * history, maxlen=history),
19
+ 'z': deque([0] * history, maxlen=history)}
20
+ time_axis = deque([datetime.now()] * history, maxlen=history)
21
+
22
+ # Increase line width here
23
+ line_width = 2.5
24
+
25
+ accel_lines = {
26
+ axis: ax_accel.plot([], [], label=f'accel_{axis}', linewidth=line_width)[0]
27
+ for axis in 'xyz'
28
+ }
29
+ gyro_lines = {
30
+ axis: ax_gyro.plot([], [], label=f'gyro_{axis}', linewidth=line_width)[0]
31
+ for axis in 'xyz'
32
+ }
33
+
34
+ ax_accel.set_ylim(-2, 2)
35
+ ax_gyro.set_ylim(-300, 300)
36
+
37
+ for ax in [ax_accel, ax_gyro]:
38
+ ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M:%S'))
39
+ ax.legend()
40
+ ax.grid(True)
41
+ ax.set_xlabel("Time (H:M:S)")
42
+
43
+ ax_accel.set_title("Acceleration")
44
+ ax_gyro.set_title("Gyroscope")
45
+
46
+ def update(_):
47
+ try:
48
+ while not queue.empty():
49
+ data = queue.get_nowait()
50
+ current_time = datetime.now()
51
+ time_axis.append(current_time)
52
+
53
+ for axis, val in zip('xyz', data['accel']):
54
+ accel_data[axis].append(val)
55
+ for axis, val in zip('xyz', data['gyro']):
56
+ gyro_data[axis].append(val)
57
+ except Exception as e:
58
+ print(f"Visualizer error: {e}")
59
+ return
60
+
61
+ for axis in 'xyz':
62
+ accel_lines[axis].set_data(time_axis, accel_data[axis])
63
+ gyro_lines[axis].set_data(time_axis, gyro_data[axis])
64
+
65
+ for ax in [ax_accel, ax_gyro]:
66
+ ax.set_xlim(time_axis[0], time_axis[-1])
67
+ ax.figure.autofmt_xdate()
68
+
69
+ return list(accel_lines.values()) + list(gyro_lines.values())
70
+
71
+ ani = animation.FuncAnimation(fig, update, interval=50)
72
+ plt.show()
73
+
74
+
75
+ if __name__ == "__main__":
76
+ mp.set_start_method('spawn')
77
+ queue = mp.Queue()
78
+ visualizer_main(queue)
@@ -186,11 +186,13 @@ class FileHandler:
186
186
  os.remove(path)
187
187
  elif type_ == 'd':
188
188
  shutil.rmtree(path)
189
+ return True
189
190
  except Exception as e:
190
191
  if ignore:
191
192
  debug_print("[DEBUG] Removing " + path + " is forced to ignore failure: " + str(e))
192
193
  else:
193
194
  raise Exception("Cannot remove " + path + ": " + str(e))
195
+ return False
194
196
 
195
197
  @staticmethod
196
198
  def extract_tar(targz, extract_path):
@@ -210,7 +212,10 @@ class FileHandler:
210
212
  def copy(from_path, to_path):
211
213
  debug_print("[DEBUG] Copy " + from_path + " to " + to_path)
212
214
  try:
213
- shutil.copy(from_path, to_path)
215
+ if os.path.isdir(from_path):
216
+ shutil.copytree(from_path, to_path, dirs_exist_ok=True)
217
+ else:
218
+ shutil.copy(from_path, to_path)
214
219
  return True
215
220
  except Exception as e:
216
221
  debug_print("Copy error: {}".format(e))
@@ -1,7 +1,7 @@
1
1
 
2
-
3
- ENABLED_EXTENSIONS = ('py', 'mpy', 'js', 'css', 'html')
4
- WEB_ONLY = ('js', 'html', 'css')
2
+ PYTHON_EXTENSIONS = ('py', 'mpy')
3
+ WEB_ONLY = ('js', 'html', 'css', 'json', 'ico', 'jpeg', 'png')
4
+ ENABLED_EXTENSIONS = PYTHON_EXTENSIONS + WEB_ONLY
5
5
 
6
6
  def check_all_extensions(path):
7
7
  extension = path.split('.')[-1]
@@ -13,4 +13,10 @@ def check_web_extensions(path):
13
13
  extension = path.split('.')[-1]
14
14
  if extension in WEB_ONLY:
15
15
  return True
16
+ return False
17
+
18
+ def check_python_extensions(path):
19
+ extension = path.split('.')[-1]
20
+ if extension in PYTHON_EXTENSIONS:
21
+ return True
16
22
  return False
toolkit/micrOSlint.py CHANGED
@@ -222,7 +222,9 @@ def _run_pylint(file_name):
222
222
  '--disable=broad-exception-caught', # Disable BROAD exception
223
223
  '--disable=broad-exception-raised', # Disable BROAD exception
224
224
  '--disable=too-many-return-statements', # :D I don't think so :D
225
- '--disable=too-many-branches' # :D I don't think so :D
225
+ '--disable=too-many-branches', # :D I don't think so :D
226
+ '--disable=too-many-positional-arguments', # :D I don't think so :D
227
+ '--disable=too-many-instance-attributes' # :D I don't think so :D
226
228
  ]
227
229
  if file_name in ['Tasks.py', 'microIO.py', 'Types.py']:
228
230
  pylint_opts.append('--disable=exec-used') # Disable micrOS execution core exec/eval warning
@@ -2,7 +2,6 @@ from threading import Thread
2
2
  import time
3
3
  import micropython
4
4
  from sim_console import console
5
- import sys
6
5
 
7
6
 
8
7
  def machine(*args, **kwargs):
@@ -1,4 +1,4 @@
1
-
1
+ from sim_console import console
2
2
 
3
3
  class NeoPixel:
4
4
  __instance = None
@@ -17,9 +17,10 @@ class NeoPixel:
17
17
  return cls.__pix_list[key]
18
18
 
19
19
  def __setitem__(cls, key, value):
20
+ console(f"Update NeoPixel at index {key} to {value}")
20
21
  cls.__pix_list[key] = value
21
22
 
22
23
  def write(cls):
23
- pass
24
+ console(f"Neopixel write: {cls.__pix_list}")
24
25
 
25
26
 
toolkit/socketClient.py CHANGED
@@ -424,7 +424,7 @@ def socket_commandline_args(arg_list):
424
424
  return ' <a> '.join(command_buffer), return_action_dict
425
425
 
426
426
 
427
- def run(arg_list=[], timeout=10):
427
+ def run(arg_list=[], timeout=10, verbose=False):
428
428
  """ Run from code
429
429
  - Handles extra command line arguments
430
430
  """
@@ -434,7 +434,8 @@ def run(arg_list=[], timeout=10):
434
434
  output = False, ''
435
435
  try:
436
436
  #print("Socket run (args): {}".format(args))
437
- output = main(args, host=host, port=port, timeout=timeout, pwd=action['password'], verbose=action['verbose'])
437
+ verbose = verbose or action['verbose']
438
+ output = main(args, host=host, port=port, timeout=timeout, pwd=action['password'], verbose=verbose)
438
439
  except Exception as e:
439
440
  if "TimeOut" in str(e):
440
441
  print("Resolve device by host ... {}.local {}:{}:{}".format(fid, host, port, uid))
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file