micrOSDevToolKit 2.13.1__py3-none-any.whl → 2.17.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.

Potentially problematic release.


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

Files changed (220) hide show
  1. micrOS/release_info/micrOS_ReleaseInfo/system_analysis_sum.json +125 -121
  2. micrOS/source/Common.py +48 -26
  3. micrOS/source/Config.py +13 -5
  4. micrOS/source/Espnow.py +100 -58
  5. micrOS/source/Files.py +77 -41
  6. micrOS/source/Hooks.py +18 -34
  7. micrOS/source/Logger.py +2 -7
  8. micrOS/source/Network.py +36 -16
  9. micrOS/source/Server.py +22 -8
  10. micrOS/source/Shell.py +9 -6
  11. micrOS/source/Tasks.py +34 -13
  12. micrOS/source/Web.py +69 -31
  13. micrOS/source/__pycache__/Common.cpython-312.pyc +0 -0
  14. micrOS/source/__pycache__/Files.cpython-312.pyc +0 -0
  15. micrOS/source/__pycache__/Logger.cpython-312.pyc +0 -0
  16. micrOS/source/__pycache__/Server.cpython-312.pyc +0 -0
  17. micrOS/source/config/_git.keep +0 -0
  18. micrOS/source/micrOS.py +7 -0
  19. micrOS/source/micrOSloader.py +4 -10
  20. micrOS/source/microIO.py +2 -2
  21. micrOS/source/modules/IO_esp32c6.py +38 -0
  22. micrOS/source/modules/LM_L298N.py +161 -0
  23. micrOS/source/modules/LM_cluster.py +255 -0
  24. {toolkit/workspace/precompiled → micrOS/source/modules}/LM_esp32.py +5 -0
  25. micrOS/source/modules/LM_espnow.py +36 -0
  26. micrOS/source/{LM_i2c.py → modules/LM_i2c.py} +1 -1
  27. micrOS/source/{LM_light_sensor.py → modules/LM_light_sensor.py} +2 -2
  28. micrOS/source/modules/LM_mqtt_client.py +246 -0
  29. micrOS/source/{LM_neoeffects.py → modules/LM_neoeffects.py} +14 -4
  30. micrOS/source/{LM_neomatrix.py → modules/LM_neomatrix.py} +140 -38
  31. micrOS/source/{LM_oled_ui.py → modules/LM_oled_ui.py} +2 -2
  32. micrOS/source/{LM_oledui.py → modules/LM_oledui.py} +2 -2
  33. micrOS/source/{LM_pacman.py → modules/LM_pacman.py} +74 -29
  34. micrOS/source/{LM_presence.py → modules/LM_presence.py} +2 -2
  35. micrOS/source/{LM_robustness.py → modules/LM_robustness.py} +49 -2
  36. micrOS/source/{LM_tcs3472.py → modules/LM_tcs3472.py} +4 -6
  37. micrOS/source/web/dashboard.html +2 -0
  38. micrOS/source/web/matrix_draw.html +390 -0
  39. micrOS/source/web/uapi.js +9 -6
  40. {microsdevtoolkit-2.13.1.dist-info → microsdevtoolkit-2.17.1.dist-info}/METADATA +30 -37
  41. {microsdevtoolkit-2.13.1.dist-info → microsdevtoolkit-2.17.1.dist-info}/RECORD +200 -190
  42. toolkit/DevEnvCompile.py +21 -12
  43. toolkit/DevEnvOTA.py +27 -16
  44. toolkit/DevEnvUSB.py +35 -21
  45. toolkit/LM_to_compile.dat +3 -1
  46. toolkit/MicrOSDevEnv.py +37 -21
  47. toolkit/dashboard_apps/QMI8685_GYRO.py +1 -1
  48. toolkit/dashboard_apps/SystemTest.py +8 -5
  49. toolkit/{MicrosFiles.py → lib/MicrosFiles.py} +24 -4
  50. toolkit/micrOSdashboard.py +2 -2
  51. toolkit/micrOSlint.py +17 -7
  52. toolkit/simulator_lib/__pycache__/simulator.cpython-312.pyc +0 -0
  53. toolkit/simulator_lib/__pycache__/uos.cpython-312.pyc +0 -0
  54. toolkit/simulator_lib/mqtt_as/Note.md +15 -0
  55. toolkit/simulator_lib/mqtt_as/__init__.py +950 -0
  56. toolkit/simulator_lib/mqtt_as/__pycache__/__init__.cpython-312.pyc +0 -0
  57. toolkit/simulator_lib/mqtt_as/clean.py +69 -0
  58. toolkit/simulator_lib/mqtt_as/mqtt_v5_properties.py +239 -0
  59. toolkit/simulator_lib/mqtt_as/range.py +90 -0
  60. toolkit/simulator_lib/mqtt_as/range_ex.py +119 -0
  61. toolkit/simulator_lib/simulator.py +14 -1
  62. toolkit/simulator_lib/uos.py +2 -0
  63. toolkit/workspace/precompiled/Common.mpy +0 -0
  64. toolkit/workspace/precompiled/Config.mpy +0 -0
  65. toolkit/workspace/precompiled/Espnow.mpy +0 -0
  66. toolkit/workspace/precompiled/Files.mpy +0 -0
  67. toolkit/workspace/precompiled/Hooks.mpy +0 -0
  68. toolkit/workspace/precompiled/Logger.mpy +0 -0
  69. toolkit/workspace/precompiled/Network.mpy +0 -0
  70. toolkit/workspace/precompiled/Server.mpy +0 -0
  71. toolkit/workspace/precompiled/Shell.mpy +0 -0
  72. toolkit/workspace/precompiled/Tasks.mpy +0 -0
  73. toolkit/workspace/precompiled/Web.mpy +0 -0
  74. toolkit/workspace/precompiled/config/_git.keep +0 -0
  75. toolkit/workspace/precompiled/micrOS.mpy +0 -0
  76. toolkit/workspace/precompiled/micrOSloader.mpy +0 -0
  77. toolkit/workspace/precompiled/microIO.mpy +0 -0
  78. toolkit/workspace/precompiled/{IO_esp32.mpy → modules/IO_esp32.mpy} +0 -0
  79. toolkit/workspace/precompiled/{IO_esp32c3.mpy → modules/IO_esp32c3.mpy} +0 -0
  80. toolkit/workspace/precompiled/modules/IO_esp32c6.mpy +0 -0
  81. toolkit/workspace/precompiled/{IO_esp32s2.mpy → modules/IO_esp32s2.mpy} +0 -0
  82. toolkit/workspace/precompiled/{IO_esp32s3.mpy → modules/IO_esp32s3.mpy} +0 -0
  83. toolkit/workspace/precompiled/{IO_m5stamp.mpy → modules/IO_m5stamp.mpy} +0 -0
  84. toolkit/workspace/precompiled/{IO_qtpy.mpy → modules/IO_qtpy.mpy} +0 -0
  85. toolkit/workspace/precompiled/modules/IO_rp2.mpy +0 -0
  86. toolkit/workspace/precompiled/modules/IO_s3matrix.mpy +0 -0
  87. toolkit/workspace/precompiled/{IO_tinypico.mpy → modules/IO_tinypico.mpy} +0 -0
  88. toolkit/workspace/precompiled/modules/LM_L298N.mpy +0 -0
  89. toolkit/workspace/precompiled/{LM_OV2640.mpy → modules/LM_OV2640.mpy} +0 -0
  90. toolkit/workspace/precompiled/{LM_aht10.mpy → modules/LM_aht10.mpy} +0 -0
  91. toolkit/workspace/precompiled/{LM_bme280.mpy → modules/LM_bme280.mpy} +0 -0
  92. toolkit/workspace/precompiled/{LM_buzzer.mpy → modules/LM_buzzer.mpy} +0 -0
  93. toolkit/workspace/precompiled/{LM_cct.mpy → modules/LM_cct.mpy} +0 -0
  94. toolkit/workspace/precompiled/modules/LM_cluster.mpy +0 -0
  95. toolkit/workspace/precompiled/{LM_co2.mpy → modules/LM_co2.mpy} +0 -0
  96. toolkit/workspace/precompiled/{LM_dht11.mpy → modules/LM_dht11.mpy} +0 -0
  97. toolkit/workspace/precompiled/{LM_dht22.mpy → modules/LM_dht22.mpy} +0 -0
  98. toolkit/workspace/precompiled/{LM_dimmer.mpy → modules/LM_dimmer.mpy} +0 -0
  99. toolkit/workspace/precompiled/{LM_distance.mpy → modules/LM_distance.mpy} +0 -0
  100. toolkit/workspace/precompiled/{LM_ds18.mpy → modules/LM_ds18.mpy} +0 -0
  101. {micrOS/source → toolkit/workspace/precompiled/modules}/LM_esp32.py +5 -0
  102. toolkit/workspace/precompiled/modules/LM_espnow.py +36 -0
  103. toolkit/workspace/precompiled/{LM_gameOfLife.mpy → modules/LM_gameOfLife.mpy} +0 -0
  104. toolkit/workspace/precompiled/{LM_genIO.mpy → modules/LM_genIO.mpy} +0 -0
  105. toolkit/workspace/precompiled/{LM_haptic.mpy → modules/LM_haptic.mpy} +0 -0
  106. toolkit/workspace/precompiled/{LM_i2c.py → modules/LM_i2c.py} +1 -1
  107. toolkit/workspace/precompiled/{LM_i2s_mic.mpy → modules/LM_i2s_mic.mpy} +0 -0
  108. toolkit/workspace/precompiled/{LM_keychain.mpy → modules/LM_keychain.mpy} +0 -0
  109. toolkit/workspace/precompiled/{LM_ld2410.mpy → modules/LM_ld2410.mpy} +0 -0
  110. toolkit/workspace/precompiled/modules/LM_light_sensor.mpy +0 -0
  111. toolkit/workspace/precompiled/modules/LM_mqtt_client.mpy +0 -0
  112. toolkit/workspace/precompiled/{LM_neoeffects.mpy → modules/LM_neoeffects.mpy} +0 -0
  113. toolkit/workspace/precompiled/modules/LM_neomatrix.mpy +0 -0
  114. toolkit/workspace/precompiled/{LM_neopixel.mpy → modules/LM_neopixel.mpy} +0 -0
  115. toolkit/workspace/precompiled/{LM_oled.mpy → modules/LM_oled.mpy} +0 -0
  116. toolkit/workspace/precompiled/{LM_oled_sh1106.mpy → modules/LM_oled_sh1106.mpy} +0 -0
  117. toolkit/workspace/precompiled/modules/LM_oled_ui.mpy +0 -0
  118. toolkit/workspace/precompiled/modules/LM_oledui.mpy +0 -0
  119. toolkit/workspace/precompiled/modules/LM_pacman.mpy +0 -0
  120. toolkit/workspace/precompiled/modules/LM_presence.mpy +0 -0
  121. toolkit/workspace/precompiled/{LM_rest.mpy → modules/LM_rest.mpy} +0 -0
  122. toolkit/workspace/precompiled/{LM_rgb.mpy → modules/LM_rgb.mpy} +0 -0
  123. toolkit/workspace/precompiled/{LM_rgbcct.mpy → modules/LM_rgbcct.mpy} +0 -0
  124. toolkit/workspace/precompiled/{LM_roboarm.mpy → modules/LM_roboarm.mpy} +0 -0
  125. toolkit/workspace/precompiled/{LM_robustness.py → modules/LM_robustness.py} +49 -2
  126. toolkit/workspace/precompiled/{LM_servo.mpy → modules/LM_servo.mpy} +0 -0
  127. toolkit/workspace/precompiled/{LM_sound_event.mpy → modules/LM_sound_event.mpy} +0 -0
  128. toolkit/workspace/precompiled/{LM_stepper.mpy → modules/LM_stepper.mpy} +0 -0
  129. toolkit/workspace/precompiled/{LM_switch.mpy → modules/LM_switch.mpy} +0 -0
  130. toolkit/workspace/precompiled/{LM_system.mpy → modules/LM_system.mpy} +0 -0
  131. toolkit/workspace/precompiled/{LM_tcs3472.py → modules/LM_tcs3472.py} +4 -6
  132. toolkit/workspace/precompiled/{LM_telegram.mpy → modules/LM_telegram.mpy} +0 -0
  133. toolkit/workspace/precompiled/{LM_tinyrgb.mpy → modules/LM_tinyrgb.mpy} +0 -0
  134. toolkit/workspace/precompiled/{LM_trackball.mpy → modules/LM_trackball.mpy} +0 -0
  135. toolkit/workspace/precompiled/{LM_veml7700.mpy → modules/LM_veml7700.mpy} +0 -0
  136. toolkit/workspace/precompiled/web/dashboard.html +2 -0
  137. toolkit/workspace/precompiled/web/matrix_draw.html +390 -0
  138. toolkit/workspace/precompiled/web/uapi.js +9 -6
  139. micrOS/source/IO_esp32c6.py +0 -16
  140. micrOS/source/LM_L298N_DCmotor.py +0 -86
  141. micrOS/source/LM_espnow.py +0 -57
  142. micrOS/source/LM_mqtt_pro.py +0 -211
  143. toolkit/lib/file_extensions.py +0 -22
  144. toolkit/workspace/precompiled/Common.cpython-312.pyc +0 -0
  145. toolkit/workspace/precompiled/IO_esp32c6.mpy +0 -0
  146. toolkit/workspace/precompiled/IO_rp2.mpy +0 -0
  147. toolkit/workspace/precompiled/IO_s3matrix.mpy +0 -0
  148. toolkit/workspace/precompiled/LM_L298N_DCmotor.mpy +0 -0
  149. toolkit/workspace/precompiled/LM_espnow.py +0 -57
  150. toolkit/workspace/precompiled/LM_light_sensor.mpy +0 -0
  151. toolkit/workspace/precompiled/LM_mqtt_pro.py +0 -211
  152. toolkit/workspace/precompiled/LM_neomatrix.mpy +0 -0
  153. toolkit/workspace/precompiled/LM_oled_ui.mpy +0 -0
  154. toolkit/workspace/precompiled/LM_oledui.mpy +0 -0
  155. toolkit/workspace/precompiled/LM_pacman.mpy +0 -0
  156. toolkit/workspace/precompiled/LM_presence.mpy +0 -0
  157. toolkit/workspace/precompiled/Logger.cpython-312.pyc +0 -0
  158. toolkit/workspace/precompiled/Server.cpython-312.pyc +0 -0
  159. /micrOS/source/{IO_esp32.py → modules/IO_esp32.py} +0 -0
  160. /micrOS/source/{IO_esp32c3.py → modules/IO_esp32c3.py} +0 -0
  161. /micrOS/source/{IO_esp32s2.py → modules/IO_esp32s2.py} +0 -0
  162. /micrOS/source/{IO_esp32s3.py → modules/IO_esp32s3.py} +0 -0
  163. /micrOS/source/{IO_m5stamp.py → modules/IO_m5stamp.py} +0 -0
  164. /micrOS/source/{IO_qtpy.py → modules/IO_qtpy.py} +0 -0
  165. /micrOS/source/{IO_rp2.py → modules/IO_rp2.py} +0 -0
  166. /micrOS/source/{IO_s3matrix.py → modules/IO_s3matrix.py} +0 -0
  167. /micrOS/source/{IO_tinypico.py → modules/IO_tinypico.py} +0 -0
  168. /micrOS/source/{LM_L9110_DCmotor.py → modules/LM_L9110_DCmotor.py} +0 -0
  169. /micrOS/source/{LM_OV2640.py → modules/LM_OV2640.py} +0 -0
  170. /micrOS/source/{LM_VL53L0X.py → modules/LM_VL53L0X.py} +0 -0
  171. /micrOS/source/{LM_aht10.py → modules/LM_aht10.py} +0 -0
  172. /micrOS/source/{LM_bme280.py → modules/LM_bme280.py} +0 -0
  173. /micrOS/source/{LM_buzzer.py → modules/LM_buzzer.py} +0 -0
  174. /micrOS/source/{LM_cct.py → modules/LM_cct.py} +0 -0
  175. /micrOS/source/{LM_co2.py → modules/LM_co2.py} +0 -0
  176. /micrOS/source/{LM_dashboard_be.py → modules/LM_dashboard_be.py} +0 -0
  177. /micrOS/source/{LM_dht11.py → modules/LM_dht11.py} +0 -0
  178. /micrOS/source/{LM_dht22.py → modules/LM_dht22.py} +0 -0
  179. /micrOS/source/{LM_dimmer.py → modules/LM_dimmer.py} +0 -0
  180. /micrOS/source/{LM_distance.py → modules/LM_distance.py} +0 -0
  181. /micrOS/source/{LM_ds18.py → modules/LM_ds18.py} +0 -0
  182. /micrOS/source/{LM_gameOfLife.py → modules/LM_gameOfLife.py} +0 -0
  183. /micrOS/source/{LM_genIO.py → modules/LM_genIO.py} +0 -0
  184. /micrOS/source/{LM_haptic.py → modules/LM_haptic.py} +0 -0
  185. /micrOS/source/{LM_i2s_mic.py → modules/LM_i2s_mic.py} +0 -0
  186. /micrOS/source/{LM_keychain.py → modules/LM_keychain.py} +0 -0
  187. /micrOS/source/{LM_ld2410.py → modules/LM_ld2410.py} +0 -0
  188. /micrOS/source/{LM_neopixel.py → modules/LM_neopixel.py} +0 -0
  189. /micrOS/source/{LM_oled.py → modules/LM_oled.py} +0 -0
  190. /micrOS/source/{LM_oled_sh1106.py → modules/LM_oled_sh1106.py} +0 -0
  191. /micrOS/source/{LM_pet_feeder.py → modules/LM_pet_feeder.py} +0 -0
  192. /micrOS/source/{LM_qmi8658.py → modules/LM_qmi8658.py} +0 -0
  193. /micrOS/source/{LM_rencoder.py → modules/LM_rencoder.py} +0 -0
  194. /micrOS/source/{LM_rest.py → modules/LM_rest.py} +0 -0
  195. /micrOS/source/{LM_rgb.py → modules/LM_rgb.py} +0 -0
  196. /micrOS/source/{LM_rgbcct.py → modules/LM_rgbcct.py} +0 -0
  197. /micrOS/source/{LM_roboarm.py → modules/LM_roboarm.py} +0 -0
  198. /micrOS/source/{LM_rp2w.py → modules/LM_rp2w.py} +0 -0
  199. /micrOS/source/{LM_sdcard.py → modules/LM_sdcard.py} +0 -0
  200. /micrOS/source/{LM_servo.py → modules/LM_servo.py} +0 -0
  201. /micrOS/source/{LM_sound_event.py → modules/LM_sound_event.py} +0 -0
  202. /micrOS/source/{LM_stepper.py → modules/LM_stepper.py} +0 -0
  203. /micrOS/source/{LM_switch.py → modules/LM_switch.py} +0 -0
  204. /micrOS/source/{LM_system.py → modules/LM_system.py} +0 -0
  205. /micrOS/source/{LM_telegram.py → modules/LM_telegram.py} +0 -0
  206. /micrOS/source/{LM_tinyrgb.py → modules/LM_tinyrgb.py} +0 -0
  207. /micrOS/source/{LM_trackball.py → modules/LM_trackball.py} +0 -0
  208. /micrOS/source/{LM_veml7700.py → modules/LM_veml7700.py} +0 -0
  209. {microsdevtoolkit-2.13.1.data → microsdevtoolkit-2.17.1.data}/scripts/devToolKit.py +0 -0
  210. {microsdevtoolkit-2.13.1.dist-info → microsdevtoolkit-2.17.1.dist-info}/WHEEL +0 -0
  211. {microsdevtoolkit-2.13.1.dist-info → microsdevtoolkit-2.17.1.dist-info}/licenses/LICENSE +0 -0
  212. {microsdevtoolkit-2.13.1.dist-info → microsdevtoolkit-2.17.1.dist-info}/top_level.txt +0 -0
  213. /toolkit/workspace/precompiled/{LM_L9110_DCmotor.py → modules/LM_L9110_DCmotor.py} +0 -0
  214. /toolkit/workspace/precompiled/{LM_VL53L0X.py → modules/LM_VL53L0X.py} +0 -0
  215. /toolkit/workspace/precompiled/{LM_dashboard_be.py → modules/LM_dashboard_be.py} +0 -0
  216. /toolkit/workspace/precompiled/{LM_pet_feeder.py → modules/LM_pet_feeder.py} +0 -0
  217. /toolkit/workspace/precompiled/{LM_qmi8658.py → modules/LM_qmi8658.py} +0 -0
  218. /toolkit/workspace/precompiled/{LM_rencoder.py → modules/LM_rencoder.py} +0 -0
  219. /toolkit/workspace/precompiled/{LM_rp2w.py → modules/LM_rp2w.py} +0 -0
  220. /toolkit/workspace/precompiled/{LM_sdcard.py → modules/LM_sdcard.py} +0 -0
micrOS/source/Network.py CHANGED
@@ -20,6 +20,7 @@ from network import AP_IF, STA_IF, WLAN
20
20
  from machine import unique_id
21
21
  from Config import cfgget, cfgput
22
22
  from Debug import console_write, syslog
23
+ from microIO import detect_platform
23
24
 
24
25
 
25
26
  class NW:
@@ -48,23 +49,36 @@ def ifconfig():
48
49
 
49
50
 
50
51
  def set_dev_uid():
52
+ if detect_platform() == "esp32c6":
53
+ # ESP32-C6: unique_id() not unique (can return same ID on different boards)
54
+ try:
55
+ sta = WLAN(STA_IF)
56
+ was = sta.active()
57
+ if not was: sta.active(True)
58
+ uid = hexlify(sta.config('mac')).decode()
59
+ if not was: sta.active(False)
60
+ cfgput('hwuid', f"micr{uid}OS")
61
+ return
62
+ except Exception as e:
63
+ syslog(f"[ERR] set_dev_uid (esp32c6): {e}")
64
+ # Legacy micrOS device UID generation (+fallback)
51
65
  try:
52
66
  cfgput('hwuid', f'micr{hexlify(unique_id()).decode("utf-8")}OS')
53
67
  except Exception as e:
54
- syslog(f"[ERR] set_dev_uid error: {e}")
68
+ syslog(f"[ERR] set_dev_uid: {e}")
55
69
 
56
70
 
57
71
  def get_mac():
58
- return WLAN().config('mac')
72
+ """ Get AP/STA mac address as raw binary data"""
73
+ return NW.NIF.config('mac')
59
74
 
60
75
  #################################################################
61
76
  # SET WIFI STA MODE #
62
77
  #################################################################
63
78
 
64
79
 
65
- def __select_available_wifi_nw(sta_if, raw_essid, raw_pwd):
80
+ def _select_available_wifi_nw(raw_essid:str, raw_pwd:str):
66
81
  """
67
- raw_essid: essid parameter, in case of multiple values separator is ;
68
82
  raw_pwd: essid pwd parameter, in case of multiple values separator is ;
69
83
  return detected essid with corresponding password
70
84
  """
@@ -72,7 +86,7 @@ def __select_available_wifi_nw(sta_if, raw_essid, raw_pwd):
72
86
  essid = essid.strip()
73
87
  # Scan wifi network - retry workaround
74
88
  for _ in range(0, 2):
75
- if essid in (wifispot[0].decode('utf-8') for wifispot in sta_if.scan()):
89
+ if essid in (wifispot[0].decode('utf-8') for wifispot in NW.NIF.scan()):
76
90
  console_write(f'\t| - [NW: STA] ESSID WAS FOUND: {essid}')
77
91
  try:
78
92
  return essid, str(raw_pwd.split(';')[idx]).strip()
@@ -82,8 +96,8 @@ def __select_available_wifi_nw(sta_if, raw_essid, raw_pwd):
82
96
  return None, ''
83
97
 
84
98
 
85
- def set_wifi(essid, pwd, timeout=60):
86
- console_write(f'[NW: STA] SET WIFI STA NW {essid}')
99
+ def set_wifi(essid:str, pwd:str, timeout=60):
100
+ console_write('[NW: STA] Enable')
87
101
 
88
102
  # Disable AP mode
89
103
  ap_if = WLAN(AP_IF)
@@ -94,18 +108,25 @@ def set_wifi(essid, pwd, timeout=60):
94
108
  # Set STA and Connect
95
109
  sta_if = WLAN(STA_IF)
96
110
  sta_if.active(True)
111
+ NW.NIF = sta_if
97
112
  # Handle rsp2-w limitation (try)
98
113
  try:
99
114
  # Set custom DHCP hostname for dhcp name resolve
100
115
  sta_if.config(dhcp_hostname=cfgget('devfid'))
101
116
  except Exception as e:
102
- console_write(f"dhcp_hostname conf error: {e}")
117
+ syslog(f"[ERR] STA dhcp_hostname: {e}")
118
+ if cfgget("espnow"):
119
+ try:
120
+ # prevents Wi-Fi PS from dropping ESP-NOW frames while STA is connected.
121
+ sta_if.config(pm=sta_if.PM_NONE)
122
+ except Exception as e:
123
+ syslog(f"[ERR] ESPNow STA PM_NONE: {e}")
103
124
  # Check are we already connected
104
125
  if sta_if.isconnected():
105
126
  console_write(f"\t| [NW: STA] ALREADY CONNECTED TO {essid}")
106
127
  else:
107
128
  # Multiple essid and pwd handling with retry mechanism
108
- essid, pwd = __select_available_wifi_nw(sta_if, essid, pwd)
129
+ essid, pwd = _select_available_wifi_nw(essid, pwd)
109
130
 
110
131
  # Connect to the located wifi network
111
132
  if essid is not None:
@@ -118,7 +139,7 @@ def set_wifi(essid, pwd, timeout=60):
118
139
  timeout -= 1
119
140
  sleep_ms(500)
120
141
  # Set static IP - here because some data comes from connection. (subnet, etc.)
121
- if sta_if.isconnected() and __set_wifi_dev_static_ip(sta_if):
142
+ if sta_if.isconnected() and _set_wifi_dev_static_ip(sta_if):
122
143
  sta_if.disconnect()
123
144
  del sta_if
124
145
  return set_wifi(essid, pwd)
@@ -131,11 +152,10 @@ def set_wifi(essid, pwd, timeout=60):
131
152
  # Store STA IP (make it static ip)
132
153
  cfgput("devip", str(sta_if.ifconfig()[0]))
133
154
  set_dev_uid()
134
- NW.NIF = sta_if
135
155
  return sta_if.isconnected()
136
156
 
137
157
 
138
- def __set_wifi_dev_static_ip(sta_if):
158
+ def _set_wifi_dev_static_ip(sta_if:STA_IF):
139
159
  console_write("[NW: STA] Set device static IP.")
140
160
  stored_ip = cfgget('devip')
141
161
  if 'n/a' not in stored_ip.lower() and '.' in stored_ip:
@@ -162,7 +182,7 @@ def __set_wifi_dev_static_ip(sta_if):
162
182
  #################################################################
163
183
 
164
184
 
165
- def set_access_point(_essid, _pwd, _authmode=3):
185
+ def set_access_point(_essid:str, _pwd:str, _authmode:int=3):
166
186
  console_write(f"[NW: AP] SET AP MODE: {_essid} - {_pwd} - auth mode: {_authmode} (if possible)")
167
187
 
168
188
  sta_if = WLAN(STA_IF)
@@ -171,6 +191,7 @@ def set_access_point(_essid, _pwd, _authmode=3):
171
191
 
172
192
  ap_if = WLAN(AP_IF)
173
193
  ap_if.active(True)
194
+ NW.NIF = ap_if
174
195
  # Set WiFi access point name (formally known as ESSID) and WiFi authmode (3): WPA2-PSK
175
196
  try:
176
197
  # Config #1 (esp)
@@ -189,7 +210,6 @@ def set_access_point(_essid, _pwd, _authmode=3):
189
210
  syslog("[ERR][AP] error")
190
211
  console_write(f"\t|\t| [NW: AP] network config: {str(ap_if.ifconfig())}")
191
212
  set_dev_uid()
192
- NW.NIF = ap_if
193
213
  return ap_if.active()
194
214
 
195
215
  #################################################################
@@ -228,7 +248,7 @@ def sta_high_avail():
228
248
  raw_essid = cfgget("staessid")
229
249
  wifi_avail = False
230
250
  # [CHECK 2] check known network is available
231
- for idx, essid in enumerate(raw_essid.split(';')):
251
+ for essid in raw_essid.split(';'):
232
252
  essid = essid.strip()
233
253
  # Scan wifi network - retry workaround
234
254
  for _ in range(0, 2):
@@ -241,7 +261,7 @@ def sta_high_avail():
241
261
  if wifi_avail or not ap_if.active():
242
262
  # ACTION: Restart micrOS node (boot phase automatically detects nw mode)
243
263
  from machine import reset
244
- console_write("[Restart] network repair")
264
+ syslog("[WARN] Restart, network repair")
245
265
  reset()
246
266
  return f'{cfgget("nwmd")} mode NOK, wifi avail: {wifi_avail}'
247
267
  return f'{cfgget("nwmd")} mode OK'
micrOS/source/Server.py CHANGED
@@ -27,7 +27,7 @@ except:
27
27
  if cfgget('webui'):
28
28
  from Web import WebEngine
29
29
  else:
30
- # Create dummy web engine - Laizy loading
30
+ # Create dummy web engine - Lazy loading
31
31
  class WebEngine:
32
32
  __slots__ = []
33
33
  def __init__(self, *args, **kwargs):
@@ -142,7 +142,7 @@ class Client:
142
142
  if Client.ACTIVE_CLIS.get(client_id, None) is not None:
143
143
  Client.ACTIVE_CLIS.pop(client_id)
144
144
  # Update server task output (? test ?)
145
- Manager().server_task_msg(','.join(list(Client.ACTIVE_CLIS)))
145
+ Manager().task_msg('server', ','.join(list(Client.ACTIVE_CLIS)))
146
146
 
147
147
  def __del__(self):
148
148
  """Client GC collect"""
@@ -158,7 +158,7 @@ class WebCli(Client, WebEngine):
158
158
 
159
159
  async def run_web(self):
160
160
  # Update server task output
161
- Manager().server_task_msg(','.join(list(Client.ACTIVE_CLIS)))
161
+ Manager().task_msg('server', ','.join(list(Client.ACTIVE_CLIS)))
162
162
 
163
163
  # Run async connection handling
164
164
  while self.connected:
@@ -167,7 +167,8 @@ class WebCli(Client, WebEngine):
167
167
  state, request = await self.read()
168
168
  if state:
169
169
  break
170
- await self.response(request)
170
+ if not await self.response(request):
171
+ break
171
172
  except Exception as e:
172
173
  syslog(f"[ERR] Client.run_web: {e}")
173
174
  break
@@ -175,14 +176,27 @@ class WebCli(Client, WebEngine):
175
176
  await self.close()
176
177
 
177
178
  @staticmethod
178
- def register(endpoint, callback):
179
+ def register(endpoint:str, callback:callable, method:str='GET', auto_enable:bool=True):
180
+ """
181
+ :param endpoint: name of the endpoint
182
+ :param callback: callback function (WebEngine compatible: return: html_type, content)
183
+ :param method: HTTP method name
184
+ :param auto_enable: enable webui when register (endpoint)
185
+ """
186
+ if method not in WebEngine.METHODS:
187
+ raise ValueError(f"method must be one of {WebEngine.METHODS}")
188
+
189
+ if cfgget('webui'):
190
+ if not endpoint in WebEngine.ENDPOINTS:
191
+ WebEngine.ENDPOINTS[endpoint] = {}
192
+ WebEngine.ENDPOINTS[endpoint][method] = callback
193
+ return
179
194
  # AUTO ENABLE webui when register (endpoint) called and webui is False
180
- if not cfgget('webui'):
195
+ if auto_enable:
181
196
  from Config import cfgput
182
197
  if cfgput('webui', True): # SET webui to True
183
198
  from machine import reset
184
199
  reset() # HARD RESET (REBOOT)
185
- WebEngine.ENDPOINTS[endpoint] = callback
186
200
 
187
201
 
188
202
  class ShellCli(Client, Shell):
@@ -245,7 +259,7 @@ class ShellCli(Client, Shell):
245
259
 
246
260
  async def run_shell(self):
247
261
  # Update server task output
248
- Manager().server_task_msg(','.join(list(Client.ACTIVE_CLIS)))
262
+ Manager().task_msg('server', ','.join(list(Client.ACTIVE_CLIS)))
249
263
  # Init prompt
250
264
  await self.a_send(self.prompt())
251
265
  # Run async connection handling
micrOS/source/Shell.py CHANGED
@@ -14,7 +14,7 @@ Designed by Marcell Ban aka BxNxM
14
14
  from sys import modules
15
15
  from machine import reset as hard_reset, soft_reset
16
16
  from Config import cfgget, cfgput
17
- from Files import ilist_fs
17
+ from Files import OSPath, ilist_fs, path_join
18
18
  from Tasks import lm_exec
19
19
  from Debug import syslog
20
20
 
@@ -25,7 +25,7 @@ from Debug import syslog
25
25
 
26
26
  class Shell:
27
27
  __slots__ = ['__devfid', '__auth_mode', '__hwuid', '__auth_ok', '__conf_mode']
28
- MICROS_VERSION = '2.13.0-0'
28
+ MICROS_VERSION = '2.17.1-0'
29
29
 
30
30
  def __init__(self):
31
31
  """
@@ -177,8 +177,8 @@ class Shell:
177
177
  await self.a_send(" Postfix hints:")
178
178
  await self.a_send(" ... &<x> - start one-shot task")
179
179
  await self.a_send(" ... &&<x> - start periodic task, where <x>: delay ms [x min: 20ms]")
180
- await self.a_send(" ... >>hostname - remote command execution (intercon)")
181
180
  await self.a_send(" ... >json - request json formatted output")
181
+ await self.a_send(" ... >>hostname - remote command execution (intercon)")
182
182
  await self.a_send(" help lm - list ALL available LoadModules")
183
183
  if "lm" in str(msg_list):
184
184
  return await Shell._show_lm_funcs(msg_obj=self.a_send)
@@ -257,6 +257,7 @@ class Shell:
257
257
  Dump LM module with help function call - in case of [mpy] files
258
258
  """
259
259
  async def _help(mods):
260
+ nonlocal mpath
260
261
  for lm_path in mods:
261
262
  lm_name = lm_path.replace('LM_', '').split('.')[0]
262
263
  try:
@@ -264,7 +265,7 @@ class Shell:
264
265
  if lm_path.endswith('.mpy'):
265
266
  await msg_obj(f" {' ' * len(lm_path.replace('LM_', '').split('.')[0])}help")
266
267
  continue
267
- with open(lm_path, 'r') as f:
268
+ with open(path_join(mpath, lm_path), 'r') as f:
268
269
  line = "micrOSisTheBest"
269
270
  while line:
270
271
  line = f.readline()
@@ -278,12 +279,14 @@ class Shell:
278
279
 
279
280
  await msg_obj("")
280
281
  # [1] list active modules (default in shell)
282
+ mpath = OSPath.MODULES
281
283
  if active_only:
282
284
  mod_keys = modules.keys()
283
- active_modules = (dir_mod for dir_mod in ilist_fs(type_filter='f', select="LM") if dir_mod.split('.')[0] in mod_keys)
285
+ active_modules = (dir_mod for dir_mod in ilist_fs(path=mpath, type_filter='f', select="LM")
286
+ if dir_mod.split('.')[0] in mod_keys)
284
287
  return await _help(active_modules)
285
288
  # [2] list all LMs on file system (ALL - help lm) - manual
286
- return await _help(ilist_fs(type_filter='f', select="LM"))
289
+ return await _help(ilist_fs(path=mpath, type_filter='f', select="LM"))
287
290
 
288
291
  @staticmethod
289
292
  async def webrepl(msg_obj, update=False):
micrOS/source/Tasks.py CHANGED
@@ -65,6 +65,17 @@ class TaskBase:
65
65
  del TaskBase.TASKS[passive[i]]
66
66
  collect() # GC collect
67
67
 
68
+ @staticmethod
69
+ async def feed(sleep_ms=1):
70
+ """
71
+ Feed event loop
72
+ :param sleep_ms: in millisecond
73
+ """
74
+ # TODO: feed WDT - preemptive cooperative multitasking aka reboot if no feed until X time period
75
+ if sleep_ms <= 0:
76
+ return await asyncio.sleep(0.000_000_1) # 0 means: 100ns (Absolute minimum)
77
+ return await asyncio.sleep_ms(sleep_ms)
78
+
68
79
  def cancel(self) -> bool:
69
80
  """
70
81
  Cancel task (+cleanup)
@@ -94,16 +105,16 @@ class TaskBase:
94
105
  del TaskBase.TASKS[self.tag]
95
106
  collect() # GC collect
96
107
 
97
- @staticmethod
98
- async def feed(sleep_ms=1):
108
+ async def await_result(self, timeout:int=5):
99
109
  """
100
- Feed event loop
101
- :param sleep_ms: in millisecond
110
+ Wait for task completion with timeout
111
+ :param timeout: in seconds
102
112
  """
103
- # TODO: feed WDT - preemptive cooperative multitasking aka reboot if no feed until X time period
104
- if sleep_ms <= 0:
105
- return await asyncio.sleep(0.000_000_1) # 0 means: 100ns (Absolute minimum)
106
- return await asyncio.sleep_ms(sleep_ms)
113
+ try:
114
+ await asyncio.wait_for(self.done.wait(), timeout)
115
+ except asyncio.TimeoutError:
116
+ return "Timeout has beed exceeded"
117
+ return self.out
107
118
 
108
119
  def __del__(self):
109
120
  try:
@@ -404,11 +415,19 @@ class Manager:
404
415
  asyncio.get_event_loop().close()
405
416
 
406
417
  @staticmethod
407
- def server_task_msg(msg):
408
- server_task = TaskBase.TASKS.get('server', None)
409
- if server_task is None:
410
- return
411
- server_task.out = msg
418
+ def task_msg(tag:str, msg:str=None) -> bool|str:
419
+ """
420
+ Set/Get task message (for server virtual task, etc.)
421
+ """
422
+ _task = TaskBase.TASKS.get(tag, None)
423
+ if _task is None:
424
+ return False
425
+ # Get task output
426
+ if tag is None:
427
+ return _task.out
428
+ # Set task output
429
+ _task.out = msg
430
+ return True
412
431
 
413
432
 
414
433
  #################################################################
@@ -467,6 +486,8 @@ def exec_builtins(func):
467
486
 
468
487
  # Call the decorated function with the additional flag
469
488
  return func(arg_list, json_flag)
489
+ return False, None
490
+
470
491
  return wrapper
471
492
 
472
493
 
micrOS/source/Web.py CHANGED
@@ -9,7 +9,7 @@ Built-in-function:
9
9
  - "virtual" endpoints - to reply from script on a defined endpoint
10
10
  - stream - stream data (jpeg) function
11
11
 
12
- Designed by Marcell Ban aka BxNxM
12
+ Designed by Marcell Ban aka BxNxM and szeka9 (GitHub)
13
13
  """
14
14
 
15
15
  from json import dumps, loads
@@ -18,6 +18,10 @@ from Tasks import lm_exec, NativeTask, lm_is_loaded
18
18
  from Debug import syslog, console_write
19
19
  from Config import cfgget
20
20
  from Files import OSPath, path_join
21
+ try:
22
+ from gc import mem_free, collect
23
+ except:
24
+ from simgc import mem_free, collect # simulator mode
21
25
 
22
26
 
23
27
  class WebEngine:
@@ -36,13 +40,18 @@ class WebEngine:
36
40
  "jpeg": "image/jpeg",
37
41
  "png": "image/png",
38
42
  "gif": "image/gif"}
43
+ METHODS = ("GET", "POST")
44
+ MEM_LIMITED = (None, 0)
39
45
 
40
46
  def __init__(self, client, version):
41
47
  self.client = client
42
48
  WebEngine.VERSION = version
43
49
 
50
+ async def a_send(self, response:str, encode:str='utf8'):
51
+ raise NotImplementedError("Child class must implement a_send coroutine.")
52
+
44
53
  @staticmethod
45
- def file_type(path):
54
+ def file_type(path:str):
46
55
  """File dynamic Content-Type handling"""
47
56
  default_type = "text/plain"
48
57
  # Extract the file extension
@@ -50,58 +59,78 @@ class WebEngine:
50
59
  # Return the content type based on the file extension
51
60
  return WebEngine.CONTENT_TYPES.get(ext, default_type)
52
61
 
53
- async def response(self, request):
54
- """HTTP GET REQUEST - WEB INTERFACE"""
55
- # Parse request line (first line)
56
- _method, url, _version = request.split('\n')[0].split()
57
- # Protocol validation
58
- if _method != "GET" and _version.startswith('HTTP'):
59
- _err = f"Bad Request: not GET HTTP but {_version}"
60
- await self.client.a_send(self.REQ400.format(len=len(_err), data=_err))
61
- return
62
+ @staticmethod
63
+ def is_mem_limited() -> (bool, int):
64
+ """Check if memory is limited for the FE"""
65
+ if WebEngine.MEM_LIMITED[0] is None:
66
+ collect()
67
+ mfree = int(mem_free() * 0.001)
68
+ WebEngine.MEM_LIMITED = (mfree < 50, mfree) # 50 kb memory requirement
69
+ return WebEngine.MEM_LIMITED
70
+
71
+ async def response(self, request:str) -> bool:
72
+ """HTTP GET/POST REQUEST - WEB INTERFACE"""
73
+ # [0] PROTOCOL VALIDATION AND PARSING
74
+ lines = request.splitlines()
75
+ if not lines:
76
+ _err = "Empty request"
77
+ await self.a_send(self.REQ400.format(len=len(_err), data=_err))
78
+ return True
79
+ request_parts = lines[0].split()
80
+ if len(request_parts) != 3:
81
+ if request_parts[0] not in self.METHODS:
82
+ # INVALID REQUEST - REQUEST OVERFLOW - NO RESPONSE
83
+ syslog(f"[WARN] WebCli REQ Overflow: {len(lines[0])}")
84
+ return False # Close connection...
85
+ _err = "Malformed request line"
86
+ await self.a_send(self.REQ400.format(len=len(_err), data=_err))
87
+ return True
88
+ _method, url, _version = request_parts
89
+ if _method not in self.METHODS or not _version.startswith('HTTP/'):
90
+ _err = f"Unsupported method: {_method} {_version}"
91
+ await self.a_send(self.REQ400.format(len=len(_err), data=_err))
92
+ return True
62
93
 
63
94
  # [1] REST API GET ENDPOINT [/rest]
64
- if url.startswith('/rest'):
95
+ if url.startswith('/rest') and _method == "GET":
65
96
  self.client.console("[WebCli] --- /rest ACCEPT")
66
97
  try:
67
98
  await self.client.a_send(WebEngine.rest(url))
68
99
  except Exception as e:
69
100
  await self.client.a_send(self.REQ404.format(len=len(str(e)), data=e))
70
- return
101
+ return True
71
102
  # [2] DYNAMIC/USER ENDPOINTS (from Load Modules)
72
- if await self.endpoints(url):
73
- return
103
+ payload = lines if _method == "POST" else []
104
+ if await self.endpoints(url, _method, payload):
105
+ return True
106
+ mem_limited, free = self.is_mem_limited()
107
+ if mem_limited:
108
+ _err = f"Low memory ({free} kb): serving API only."
109
+ await self.a_send(self.REQ400.format(len=len(_err), data=_err))
110
+ return True
74
111
  # [3] HOME/PAGE ENDPOINT(s) [default: / -> /index.html]
75
- if url.startswith('/'):
112
+ if url.startswith('/') and _method == "GET":
76
113
  resource = 'index.html' if url == '/' else url.replace('/', '')
77
114
  web_resource = path_join(OSPath.WEB, resource) # Redirect path to web folder
78
115
  self.client.console(f"[WebCli] --- {url} ACCEPT -> {web_resource}")
79
116
  if resource.split('.')[-1] not in tuple(self.CONTENT_TYPES.keys()):
80
117
  await self.client.a_send(self.REQ404.format(len=27, data='404 Not supported file type'))
81
- return
118
+ return True
82
119
  try:
83
120
  # SEND RESOURCE CONTENT: HTML, JS, CSS (WebEngine.CONTENT_TYPES)
84
121
  with open(web_resource, 'r') as file:
85
122
  data = file.read()
86
123
  response = self.REQ200.format(dtype=WebEngine.file_type(resource), len=len(data), data=data)
87
- # Send entire response data
124
+ # Send entire response data (implement chunking if necessary)
88
125
  await self.client.a_send(response)
89
-
90
- # Send chunks of response data (experimental)
91
- #response_len, chunk_size, position = len(response), 300, 0
92
- #while position < response_len:
93
- # # Calculate the size of the next chunk
94
- # next_chunk_size = min(chunk_size, response_len - position)
95
- # chunk = response[position:position + next_chunk_size]
96
- # await self.client.a_send(chunk)
97
- # position += next_chunk_size
98
126
  except Exception as e:
99
127
  if 'memory allocation failed' in str(e):
100
128
  syslog(f"[ERR] WebCli {resource}: {e}")
101
129
  await self.client.a_send(self.REQ404.format(len=13, data='404 Not Found'))
102
- return
130
+ return True
103
131
  # INVALID/BAD REQUEST
104
132
  await self.client.a_send(self.REQ400.format(len=15, data='400 Bad Request'))
133
+ return True
105
134
 
106
135
  @staticmethod
107
136
  def rest(url):
@@ -130,9 +159,9 @@ class WebEngine:
130
159
  response = dumps(resp_schema)
131
160
  return WebEngine.REQ200.format(dtype='text/html', len=len(response), data=response)
132
161
 
133
- async def endpoints(self, url):
162
+ async def endpoints(self, url:str, method:str, payload:list):
134
163
  url = url[1:] # Cut first / char
135
- if url in WebEngine.ENDPOINTS:
164
+ if url in WebEngine.ENDPOINTS and method in WebEngine.ENDPOINTS[url]:
136
165
  console_write(f"[WebCli] endpoint: {url}")
137
166
  # Registered endpoint was found - exec callback
138
167
  try:
@@ -141,7 +170,16 @@ class WebEngine:
141
170
  # one-shot (simple MIME types): image/jpeg | text/html | text/plain - data: raw
142
171
  # task (streaming MIME types): multipart/x-mixed-replace | multipart/form-data - data: dict{callback,content-type}
143
172
  # content-type: image/jpeg | audio/l16;*
144
- dtype, data = WebEngine.ENDPOINTS[url]()
173
+ if method == "POST":
174
+ try:
175
+ blank_index = payload.index("")
176
+ body_lines = payload[blank_index + 1:]
177
+ except ValueError:
178
+ body_lines = []
179
+ dtype, data = WebEngine.ENDPOINTS[url][method]("\n".join(body_lines))
180
+ else:
181
+ dtype, data = WebEngine.ENDPOINTS[url][method]()
182
+
145
183
  if dtype == 'image/jpeg':
146
184
  resp = f"HTTP/1.1 200 OK\r\nContent-Type: {dtype}\r\nContent-Length:{len(data)}\r\n\r\n".encode('utf8') + data
147
185
  await self.client.a_send(resp, encode=None)
File without changes
micrOS/source/micrOS.py CHANGED
@@ -4,6 +4,13 @@ dedicated to micrOS framework.
4
4
 
5
5
  Designed by Marcell Ban aka BxNxM
6
6
  """
7
+
8
+ #################################################################
9
+ # INIT FS #
10
+ #################################################################
11
+ from Files import init_micros_dirs
12
+ init_micros_dirs()
13
+
7
14
  #################################################################
8
15
  # IMPORTS #
9
16
  #################################################################
@@ -1,5 +1,6 @@
1
1
  """
2
2
  Module is responsible for invoke micrOS or recovery webrepl mode
3
+ [IMPORTANT] This module must never use any micrOS specific functions in main scope.
3
4
 
4
5
  Designed by Marcell Ban aka BxNxM
5
6
  """
@@ -11,11 +12,6 @@ try:
11
12
  import traceback
12
13
  except:
13
14
  traceback = None
14
- try:
15
- from Debug import syslog
16
- except Exception as e:
17
- print(f"[loader] Import error: {e}")
18
- syslog = None
19
15
  from machine import reset
20
16
 
21
17
 
@@ -59,6 +55,8 @@ def _is_micrOS():
59
55
 
60
56
  def __recovery_mode():
61
57
  # Recovery/Update mode (webrepl) - dependencies: Network, ConfigHandler
58
+ from sys import path
59
+ path.insert(0, "/modules")
62
60
  from Network import auto_nw_config
63
61
  from Config import cfgget
64
62
  pwd = cfgget('appwd') # Get pwd from config
@@ -70,9 +68,7 @@ def __recovery_mode():
70
68
  import webrepl
71
69
  webrepl.start(password=pwd)
72
70
  except Exception as e:
73
- if callable(syslog):
74
- syslog(f"[ERR][micrOSloader] webrepl failed: {e}")
75
- print("[loader] Reset .if_mode to micros and reboot")
71
+ print(f"[loader] webrepl failed: {e} - Reset .if_mode to micros and reboot")
76
72
  with open('.if_mode', 'w') as f:
77
73
  f.write("micros")
78
74
  # Reboot machine
@@ -126,8 +122,6 @@ def main():
126
122
  # Handle micrOS system crash (never happened...but) -> webrepl mode default pwd: ADmin123
127
123
  print(f"[loader][main mode] micrOS start failed: {e}")
128
124
  print("[loader][main mode] -> [recovery mode]")
129
- if callable(syslog):
130
- syslog(f"[ERR][micrOSloader] start failed: {e}")
131
125
  # Recovery aka webrepl mode
132
126
  __recovery_mode()
133
127
  __auto_restart_event()
micrOS/source/microIO.py CHANGED
@@ -11,7 +11,7 @@ Designed by Marcell Ban aka BxNxM
11
11
  #################################################################
12
12
  from sys import platform
13
13
  from uos import uname
14
- from Files import ilist_fs
14
+ from Files import ilist_fs, OSPath
15
15
  from Logger import syslog
16
16
 
17
17
  #################################################################
@@ -68,7 +68,7 @@ def set_pinmap(map_data=None):
68
68
 
69
69
  # SELECT LOOKUP TABLE BASED ON PLATFORM / User input
70
70
  if isinstance(io_file, str) and io_file != 'n/a':
71
- if f"IO_{io_file}" in [io.split('.')[0] for io in ilist_fs(type_filter='f', select="IO")]:
71
+ if f"IO_{io_file}" in [io.split('.')[0] for io in ilist_fs(OSPath.MODULES, type_filter='f', select="IO")]:
72
72
  PinMap.MAPPING_LUT = io_file
73
73
  return PinMap.MAPPING_LUT
74
74
  PinMap.MAPPING_LUT = detect_platform()