micrOSDevToolKit 2.11.0__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 (84) hide show
  1. micrOS/release_info/micrOS_ReleaseInfo/system_analysis_sum.json +25 -25
  2. micrOS/source/Common.py +34 -14
  3. micrOS/source/Config.py +7 -7
  4. micrOS/source/Debug.py +9 -9
  5. micrOS/source/Espnow.py +6 -6
  6. micrOS/source/Files.py +5 -3
  7. micrOS/source/Hooks.py +5 -5
  8. micrOS/source/InterConnect.py +5 -5
  9. micrOS/source/Interrupts.py +2 -2
  10. micrOS/source/LM_dashboard_be.py +2 -2
  11. micrOS/source/LM_neomatrix.py +42 -12
  12. micrOS/source/LM_pacman.py +16 -3
  13. micrOS/source/Logger.py +1 -1
  14. micrOS/source/Network.py +6 -6
  15. micrOS/source/Notify.py +2 -2
  16. micrOS/source/Scheduler.py +5 -5
  17. micrOS/source/Server.py +6 -6
  18. micrOS/source/Shell.py +4 -4
  19. micrOS/source/Tasks.py +13 -13
  20. micrOS/source/Time.py +7 -7
  21. micrOS/source/Types.py +2 -2
  22. micrOS/source/Web.py +20 -13
  23. micrOS/source/__pycache__/Common.cpython-312.pyc +0 -0
  24. micrOS/source/__pycache__/Debug.cpython-312.pyc +0 -0
  25. micrOS/source/__pycache__/Logger.cpython-312.pyc +0 -0
  26. micrOS/source/__pycache__/Server.cpython-312.pyc +0 -0
  27. micrOS/source/micrOS.py +5 -5
  28. micrOS/source/micrOSloader.py +6 -6
  29. micrOS/source/urequests.py +4 -4
  30. {microsdevtoolkit-2.11.0.dist-info → microsdevtoolkit-2.13.0.dist-info}/METADATA +23 -22
  31. {microsdevtoolkit-2.11.0.dist-info → microsdevtoolkit-2.13.0.dist-info}/RECORD +84 -79
  32. toolkit/DevEnvCompile.py +20 -15
  33. toolkit/DevEnvOTA.py +29 -8
  34. toolkit/DevEnvUSB.py +47 -10
  35. toolkit/MicrOSDevEnv.py +10 -2
  36. toolkit/MicrosFiles.py +26 -0
  37. toolkit/lib/LocalMachine.py +6 -1
  38. toolkit/lib/file_extensions.py +9 -3
  39. toolkit/micrOSlint.py +3 -1
  40. toolkit/workspace/precompiled/Common.cpython-312.pyc +0 -0
  41. toolkit/workspace/precompiled/Common.mpy +0 -0
  42. toolkit/workspace/precompiled/Config.mpy +0 -0
  43. toolkit/workspace/precompiled/Debug.mpy +0 -0
  44. toolkit/workspace/precompiled/Espnow.mpy +0 -0
  45. toolkit/workspace/precompiled/Files.mpy +0 -0
  46. toolkit/workspace/precompiled/Hooks.mpy +0 -0
  47. toolkit/workspace/precompiled/InterConnect.mpy +0 -0
  48. toolkit/workspace/precompiled/Interrupts.mpy +0 -0
  49. toolkit/workspace/precompiled/LM_dashboard_be.py +2 -2
  50. toolkit/workspace/precompiled/LM_neomatrix.mpy +0 -0
  51. toolkit/workspace/precompiled/LM_pacman.mpy +0 -0
  52. toolkit/workspace/precompiled/Logger.cpython-312.pyc +0 -0
  53. toolkit/workspace/precompiled/Logger.mpy +0 -0
  54. toolkit/workspace/precompiled/Network.mpy +0 -0
  55. toolkit/workspace/precompiled/Notify.mpy +0 -0
  56. toolkit/workspace/precompiled/Scheduler.mpy +0 -0
  57. toolkit/workspace/precompiled/Server.cpython-312.pyc +0 -0
  58. toolkit/workspace/precompiled/Server.mpy +0 -0
  59. toolkit/workspace/precompiled/Shell.mpy +0 -0
  60. toolkit/workspace/precompiled/Tasks.mpy +0 -0
  61. toolkit/workspace/precompiled/Time.mpy +0 -0
  62. toolkit/workspace/precompiled/Types.mpy +0 -0
  63. toolkit/workspace/precompiled/Web.mpy +0 -0
  64. toolkit/workspace/precompiled/micrOS.mpy +0 -0
  65. toolkit/workspace/precompiled/micrOSloader.mpy +0 -0
  66. toolkit/workspace/precompiled/urequests.mpy +0 -0
  67. /micrOS/source/{dashboard.html → web/dashboard.html} +0 -0
  68. /micrOS/source/{index.html → web/index.html} +0 -0
  69. /micrOS/source/{uapi.js → web/uapi.js} +0 -0
  70. /micrOS/source/{udashboard.js → web/udashboard.js} +0 -0
  71. /micrOS/source/{ustyle.css → web/ustyle.css} +0 -0
  72. /micrOS/source/{uwidgets.js → web/uwidgets.js} +0 -0
  73. /micrOS/source/{uwidgets_pro.js → web/uwidgets_pro.js} +0 -0
  74. {microsdevtoolkit-2.11.0.data → microsdevtoolkit-2.13.0.data}/scripts/devToolKit.py +0 -0
  75. {microsdevtoolkit-2.11.0.dist-info → microsdevtoolkit-2.13.0.dist-info}/WHEEL +0 -0
  76. {microsdevtoolkit-2.11.0.dist-info → microsdevtoolkit-2.13.0.dist-info}/licenses/LICENSE +0 -0
  77. {microsdevtoolkit-2.11.0.dist-info → microsdevtoolkit-2.13.0.dist-info}/top_level.txt +0 -0
  78. /toolkit/workspace/precompiled/{dashboard.html → web/dashboard.html} +0 -0
  79. /toolkit/workspace/precompiled/{index.html → web/index.html} +0 -0
  80. /toolkit/workspace/precompiled/{uapi.js → web/uapi.js} +0 -0
  81. /toolkit/workspace/precompiled/{udashboard.js → web/udashboard.js} +0 -0
  82. /toolkit/workspace/precompiled/{ustyle.css → web/ustyle.css} +0 -0
  83. /toolkit/workspace/precompiled/{uwidgets.js → web/uwidgets.js} +0 -0
  84. /toolkit/workspace/precompiled/{uwidgets_pro.js → web/uwidgets_pro.js} +0 -0
@@ -45,6 +45,17 @@ class NeoPixelMatrix(AnimationPlayer):
45
45
  return y * self.width + x
46
46
  return y * self.width + (self.width - 1 - x)
47
47
 
48
+ def _index_to_coord(self, index: int, zigzag:bool=True) -> tuple[int, int]:
49
+ """
50
+ Converts a linear index to (x, y) coordinates.
51
+ Zigzag layout: even rows left-to-right, odd rows right-to-left.
52
+ """
53
+ y = index // self.width
54
+ x = index % self.width
55
+ if (zigzag is None or zigzag) and y % 2 == 1:
56
+ x = self.width - 1 - x
57
+ return x, y
58
+
48
59
  def _rgb_to_grb_with_br(self, color: tuple[int, int, int]):
49
60
  """
50
61
  Converts RGB to GRB with brightness adjustment.
@@ -95,7 +106,6 @@ class NeoPixelMatrix(AnimationPlayer):
95
106
  self.draw()
96
107
  return f"Set brightness to {br}%"
97
108
 
98
-
99
109
  def draw_colormap(self, bitmap:list):
100
110
  """
101
111
  Draw a bitmap on the Neopixel
@@ -110,6 +120,15 @@ class NeoPixelMatrix(AnimationPlayer):
110
120
  self.set_pixel(x, y, color, zigzag=False)
111
121
  self.draw()
112
122
 
123
+ def export_colormap(self):
124
+ """
125
+ Export the current screen as bitmap
126
+ """
127
+ colormap = []
128
+ for i, color in enumerate(self._color_buffer):
129
+ x, y = self._index_to_coord(i, zigzag=False)
130
+ colormap.append((x, y, color))
131
+ return colormap
113
132
 
114
133
  ##########################################################################################################
115
134
  ##########################################################################################################
@@ -191,10 +210,14 @@ def draw_colormap(bitmap):
191
210
  except Exception as e:
192
211
  return str(e)
193
212
  return "Done."
213
+
214
+
215
+ def get_colormap():
216
+ return load().export_colormap()
217
+
194
218
  # -----------------------------------------------------------------------------
195
219
  # -----------------------------------------------------------------------------
196
220
 
197
-
198
221
  def rainbow(speed_ms=0):
199
222
  def effect_rainbow():
200
223
  def hsv_to_rgb(h, s, v):
@@ -237,10 +260,11 @@ def rainbow(speed_ms=0):
237
260
  return load().play(effect_rainbow, speed_ms=speed_ms, bt_draw=True, bt_size=8)
238
261
 
239
262
 
240
- def snake(speed_ms:int=50, length:int=5):
263
+ def snake(speed_ms:int=30, length:int=5):
241
264
  def effect_snake():
242
265
  clear_color = (0, 0, 0)
243
- total_steps = 8 * 8 + length # run just past the end to clear tail
266
+ total_pixels = 8 * 8
267
+ total_steps = total_pixels + length # run just past the end to clear tail
244
268
 
245
269
  for step in range(total_steps):
246
270
  # 1) clear the tail pixel once the snake is longer than `length`
@@ -249,12 +273,17 @@ def snake(speed_ms:int=50, length:int=5):
249
273
  tx, ty = tail_idx % 8, tail_idx // 8
250
274
  yield tx, ty, clear_color
251
275
 
252
- # 2) move the head (only while head index < 64)
253
- if step < 8 * 8:
254
- hx, hy = step % 8, step // 8
255
- yield hx, hy, NeoPixelMatrix.DEFAULT_COLOR
276
+ # 2) draw the snake segments with decreasing brightness
277
+ for i in range(length):
278
+ seg_idx = step - i
279
+ if 0 <= seg_idx < total_pixels:
280
+ x, y = seg_idx % 8, seg_idx // 8
281
+ br = 1.0 - (i / length) ** 0.6
282
+ r, g, b = NeoPixelMatrix.DEFAULT_COLOR
283
+ color = (int(r * br), int(g * br), int(b * br))
284
+ yield x, y, color
256
285
 
257
- return load().play(effect_snake, speed_ms=speed_ms)
286
+ return load().play(effect_snake, speed_ms=speed_ms, bt_draw=False)
258
287
 
259
288
 
260
289
  def cube(speed_ms=10):
@@ -287,7 +316,7 @@ def cube(speed_ms=10):
287
316
  if 0 <= x < width and 0 <= y < height:
288
317
  yield x, y, NeoPixelMatrix.DEFAULT_COLOR
289
318
 
290
- return load().play(effect_cube, speed_ms=speed_ms)
319
+ return load().play(effect_cube, speed_ms=speed_ms, bt_draw=False)
291
320
 
292
321
 
293
322
  def help(widgets=False):
@@ -300,6 +329,7 @@ def help(widgets=False):
300
329
  'BUTTON snake speed_ms=50 length=5',
301
330
  'BUTTON rainbow',
302
331
  'BUTTON cube speed_ms=10',
303
- 'SLIDER control speed_ms=<2-200-2> bt_draw=None',
304
- 'draw_colormap bitmap=[(0,0,(10,2,0)),(x,y,color),...]'
332
+ 'SLIDER control speed_ms=<1-200-2> bt_draw=None',
333
+ 'draw_colormap bitmap=[(0,0,(10,2,0)),(x,y,color),...]',
334
+ 'get_colormap'
305
335
  ), widgets=widgets)
@@ -1,7 +1,6 @@
1
1
  from sys import modules
2
2
  from Common import socket_stream
3
- from Files import _is_module, list_fs, ilist_fs, remove_fs
4
- from Files import OSPath, path_join
3
+ from Files import _is_module, list_fs, ilist_fs, remove_fs, OSPath, path_join
5
4
 
6
5
 
7
6
  #############################################
@@ -164,6 +163,18 @@ def datdump():
164
163
  out[dat] = f.read()
165
164
  return out
166
165
 
166
+
167
+ def makedir(path):
168
+ """
169
+ Create directory command
170
+ """
171
+ from uos import mkdir
172
+ try:
173
+ mkdir(path)
174
+ return f"{path} dir created."
175
+ except Exception as e:
176
+ return f"{path} failed to create: {e}"
177
+
167
178
  #############################################
168
179
  # Legacy features #
169
180
  #############################################
@@ -229,4 +240,6 @@ def help(widgets=False):
229
240
  'download url="BxNxM/micrOS/master/toolkit/workspace/precompiled/LM_robustness.py"',
230
241
  'micros_checksum',
231
242
  'ls path="/" content="*/f/d" select="*/LM/IO"',
232
- 'rm <path>', 'dirtree path="/"')
243
+ 'rm <path>',
244
+ 'dirtree path="/"',
245
+ 'makedir <path>')
micrOS/source/Logger.py CHANGED
@@ -116,7 +116,7 @@ def syslog(data=None, msgobj=None):
116
116
  # WRITE LOGS - [target].sys.log automatic log level detection
117
117
  _match = match(r"^\[([^\[\]]+)\]", data)
118
118
  log_lvl = _match.group(1).lower() if _match else 'user'
119
- f_name = f"{log_lvl}.sys.log" if log_lvl in ("err", "warn", "boot") else 'user.sys.log'
119
+ f_name = f"{log_lvl}.sys.log" if log_lvl in ("err", "warn", "boot", "info") else 'user.sys.log'
120
120
  return logger(data, f_name, limit=4)
121
121
 
122
122
 
micrOS/source/Network.py CHANGED
@@ -19,7 +19,7 @@ from utime import sleep_ms
19
19
  from network import AP_IF, STA_IF, WLAN
20
20
  from machine import unique_id
21
21
  from Config import cfgget, cfgput
22
- from Debug import console_write, errlog_add
22
+ from Debug import console_write, syslog
23
23
 
24
24
 
25
25
  class NW:
@@ -51,7 +51,7 @@ def set_dev_uid():
51
51
  try:
52
52
  cfgput('hwuid', f'micr{hexlify(unique_id()).decode("utf-8")}OS')
53
53
  except Exception as e:
54
- errlog_add(f"[ERR] set_dev_uid error: {e}")
54
+ syslog(f"[ERR] set_dev_uid error: {e}")
55
55
 
56
56
 
57
57
  def get_mac():
@@ -77,7 +77,7 @@ def __select_available_wifi_nw(sta_if, raw_essid, raw_pwd):
77
77
  try:
78
78
  return essid, str(raw_pwd.split(';')[idx]).strip()
79
79
  except Exception as e:
80
- errlog_add(f'[ERR][SET STA] stapwd config error: {e}')
80
+ syslog(f'[ERR][SET STA] stapwd config error: {e}')
81
81
  sleep_ms(400)
82
82
  return None, ''
83
83
 
@@ -149,7 +149,7 @@ def __set_wifi_dev_static_ip(sta_if):
149
149
  sta_if.ifconfig(tuple(conn_ips))
150
150
  return True # was reconfigured
151
151
  except Exception as e:
152
- errlog_add(f"[ERR][STA] StaticIP conf failed: {e}")
152
+ syslog(f"[ERR][STA] StaticIP conf failed: {e}")
153
153
  else:
154
154
  console_write(f"[NW: STA][SKIP] StaticIP conf.: {stored_ip} ? {conn_ips[0]}")
155
155
  else:
@@ -184,9 +184,9 @@ def set_access_point(_essid, _pwd, _authmode=3):
184
184
  # Config #2 (rp2-w)???
185
185
  ap_if.config(essid=_essid, password=_pwd)
186
186
  except Exception as e2:
187
- errlog_add(f"[ERR][AP] config failed: {e2}")
187
+ syslog(f"[ERR][AP] config failed: {e2}")
188
188
  if not (ap_if.active() and str(ap_if.config('essid')) == str(_essid)):
189
- errlog_add("[ERR][AP] error")
189
+ syslog("[ERR][AP] error")
190
190
  console_write(f"\t|\t| [NW: AP] network config: {str(ap_if.ifconfig())}")
191
191
  set_dev_uid()
192
192
  NW.NIF = ap_if
micrOS/source/Notify.py CHANGED
@@ -11,7 +11,7 @@ Designed by Marcell Ban aka BxNxM
11
11
 
12
12
  from Config import cfgget
13
13
  from Tasks import lm_exec, lm_is_loaded
14
- from Debug import errlog_add
14
+ from Debug import syslog
15
15
 
16
16
  #########################################
17
17
  # micrOS Notifications #
@@ -47,7 +47,7 @@ class Notify:
47
47
  # !!! SUBSCRIBER HAS TO DEFINE send_msg(text, reply_to, chat_id) method !!!
48
48
  s.send_msg(text, reply_to, chat_id)
49
49
  except Exception as e:
50
- errlog_add(f"[ERR] Notify: {e}")
50
+ syslog(f"[ERR] Notify: {e}")
51
51
  exit_code+=1
52
52
  return f"Sent for {len(Notify._SUBSCRIBERS)} client(s), errors: ({exit_code})"
53
53
 
@@ -1,7 +1,7 @@
1
1
  from time import localtime
2
2
  from re import compile
3
3
  from Tasks import exec_lm_pipe_schedule
4
- from Debug import console_write, errlog_add
4
+ from Debug import console_write, syslog
5
5
  from Time import Sun, suntime, ntp_time
6
6
 
7
7
  """
@@ -101,7 +101,7 @@ def __resolve_time_tag(check_time, crontask):
101
101
  # Resolve tag
102
102
  value = Sun.TIME.get(tag, None)
103
103
  if value is None or len(value) < 3:
104
- errlog_add(f'[ERR] cron syntax error: {tag}:{value}')
104
+ syslog(f'[ERR] cron syntax error: {tag}:{value}')
105
105
  return ()
106
106
 
107
107
  # Update check_time with resolved value by tag
@@ -186,7 +186,7 @@ def __scheduler_trigger(cron_time_now, crontask, deltasec=2):
186
186
  console_write(f"[builtin cron] {crontask[1]()}")
187
187
  lm_state = True
188
188
  except Exception as e:
189
- errlog_add(f"[ERR] cron function exec error: {e}")
189
+ syslog(f"[ERR] cron function exec error: {e}")
190
190
  if not lm_state:
191
191
  console_write(f"[cron]now[{cron_time_now}] \
192
192
  {__convert_sec_to_time(tolerance_min_sec)} <-> {__convert_sec_to_time(tolerance_max_sec)} \
@@ -224,7 +224,7 @@ def deserialize_raw_input(cron_data):
224
224
  sep = ';;' if ';;' in cd else ';' # support multi command with ;;
225
225
  return (tuple(cron.split('!')) for cron in cd.split(sep))
226
226
  except Exception as e:
227
- errlog_add(f"[ERR] cron deserialize - syntax error: {e}")
227
+ syslog(f"[ERR] cron deserialize - syntax error: {e}")
228
228
  return ()
229
229
 
230
230
 
@@ -256,5 +256,5 @@ def scheduler(cron_data, irqperiod):
256
256
  state |= __scheduler_trigger(cron_time_now, cron, deltasec=irqperiod)
257
257
  return state
258
258
  except Exception as e:
259
- errlog_add(f'[ERR] cron callback error: {e}')
259
+ syslog(f'[ERR] cron callback error: {e}')
260
260
  return False
micrOS/source/Server.py CHANGED
@@ -13,7 +13,7 @@ Designed by Marcell Ban aka BxNxM GitHub
13
13
  import uasyncio as asyncio
14
14
  from utime import ticks_ms, ticks_diff
15
15
  from Config import cfgget
16
- from Debug import console_write, errlog_add
16
+ from Debug import console_write, syslog
17
17
  from Network import ifconfig
18
18
  from Tasks import Manager
19
19
  from Shell import Shell
@@ -99,7 +99,7 @@ class Client:
99
99
  except Exception as e:
100
100
  # Maintain ACTIVE_CLIS - remove closed connection by peer.
101
101
  await self.close()
102
- errlog_add(f"[WARN] Client.a_send (auto-drop) {self.client_id}: {e}")
102
+ syslog(f"[WARN] Client.a_send (auto-drop) {self.client_id}: {e}")
103
103
  return # Abort async send (no drain)
104
104
  # Send buffered data with async task - hacky
105
105
  try:
@@ -169,7 +169,7 @@ class WebCli(Client, WebEngine):
169
169
  break
170
170
  await self.response(request)
171
171
  except Exception as e:
172
- errlog_add(f"[ERR] Client.run_web: {e}")
172
+ syslog(f"[ERR] Client.run_web: {e}")
173
173
  break
174
174
  # Close connection
175
175
  await self.close()
@@ -211,7 +211,7 @@ class ShellCli(Client, Shell):
211
211
  except:
212
212
  # Maintain ACTIVE_CLIS - remove closed connection by peer.
213
213
  Client.drop_client(self.client_id)
214
- errlog_add(f"[WARN] ShellCli.send (auto-drop) {self.client_id}")
214
+ syslog(f"[WARN] ShellCli.send (auto-drop) {self.client_id}")
215
215
  # Send buffered data with async task - hacky
216
216
  if self.drain_event.is_set():
217
217
  self.drain_event.clear() # set drain busy (False)
@@ -261,12 +261,12 @@ class ShellCli(Client, Shell):
261
261
  # Shell -> True (OK) or False (NOK) -> NOK->Close session (auth Failed, etc.)
262
262
  _exit = not await self.shell(request)
263
263
  except Exception as e:
264
- errlog_add(f"[ERR] Shell client: {e}")
264
+ syslog(f"[ERR] Shell client: {e}")
265
265
  if "ECONNRESET" in str(e):
266
266
  _exit = True # exit_loop
267
267
  else:
268
268
  await self.a_send("[HA] Critical error - disconnect & hard reset")
269
- errlog_add("[ERR] Socket critical error - reboot")
269
+ syslog("[ERR] Socket critical error - reboot")
270
270
  await self.reboot()
271
271
  if _exit:
272
272
  collect()
micrOS/source/Shell.py CHANGED
@@ -16,7 +16,7 @@ from machine import reset as hard_reset, soft_reset
16
16
  from Config import cfgget, cfgput
17
17
  from Files import ilist_fs
18
18
  from Tasks import lm_exec
19
- from Debug import errlog_add
19
+ from Debug import syslog
20
20
 
21
21
 
22
22
  #################################################################
@@ -25,7 +25,7 @@ from Debug import errlog_add
25
25
 
26
26
  class Shell:
27
27
  __slots__ = ['__devfid', '__auth_mode', '__hwuid', '__auth_ok', '__conf_mode']
28
- MICROS_VERSION = '2.11.0-0'
28
+ MICROS_VERSION = '2.13.0-0'
29
29
 
30
30
  def __init__(self):
31
31
  """
@@ -43,7 +43,7 @@ class Shell:
43
43
  try:
44
44
  cfgput('version', Shell.MICROS_VERSION)
45
45
  except Exception as e:
46
- errlog_add(f"[ERR] micrOS version export failed (config): {e}")
46
+ syslog(f"[ERR] micrOS version export failed (config): {e}")
47
47
 
48
48
  async def a_send(self, msg):
49
49
  """ Must be defined by child class... """
@@ -306,5 +306,5 @@ class Shell:
306
306
  except Exception as e:
307
307
  _err_msg = f"[ERR] while starting webrepl: {e}"
308
308
  await msg_obj(_err_msg)
309
- errlog_add(_err_msg)
309
+ syslog(_err_msg)
310
310
  return True
micrOS/source/Tasks.py CHANGED
@@ -13,7 +13,7 @@ from json import dumps
13
13
  import uasyncio as asyncio
14
14
  from micropython import schedule
15
15
  from utime import ticks_ms, ticks_diff
16
- from Debug import console_write, errlog_add
16
+ from Debug import console_write, syslog
17
17
  from Config import cfgget
18
18
  from Network import sta_high_avail
19
19
 
@@ -75,12 +75,12 @@ class TaskBase:
75
75
  self.task.cancel() # Try to cancel task by asyncio
76
76
  except Exception as e:
77
77
  if "can't cancel self" != str(e):
78
- errlog_add(f"[WARN] IRQ Task cancel: {e}")
78
+ syslog(f"[WARN] IRQ Task cancel: {e}")
79
79
  self.__task_del()
80
80
  else:
81
81
  return False
82
82
  except Exception as e:
83
- errlog_add(f"[ERR] Task kill: {e}")
83
+ syslog(f"[ERR] Task kill: {e}")
84
84
  return False
85
85
  return True
86
86
 
@@ -109,7 +109,7 @@ class TaskBase:
109
109
  try:
110
110
  self.__task_del(keep_cache=True)
111
111
  except Exception as e:
112
- errlog_add(f"[ERR] TaskBase.__del__: {e}")
112
+ syslog(f"[ERR] TaskBase.__del__: {e}")
113
113
 
114
114
 
115
115
  class NativeTask(TaskBase):
@@ -240,7 +240,7 @@ class Manager:
240
240
  cls.INSTANCE._initialized = False
241
241
  # Set async event loop exception handler
242
242
  asyncio.get_event_loop().set_exception_handler(lambda loop=None, context=None:
243
- errlog_add(f"[aio] exception: {loop}:{context}"))
243
+ syslog(f"[aio] exception: {loop}:{context}"))
244
244
  return cls.INSTANCE
245
245
 
246
246
  def __init__(self):
@@ -265,7 +265,7 @@ class Manager:
265
265
  """
266
266
  if Manager._queue_len() >= TaskBase.QUEUE_SIZE:
267
267
  msg = f"[aio] Task queue full: {TaskBase.QUEUE_SIZE}"
268
- errlog_add(msg)
268
+ syslog(msg)
269
269
  raise Exception(msg)
270
270
 
271
271
  async def idle_task(self):
@@ -293,7 +293,7 @@ class Manager:
293
293
  sta_high_avail()
294
294
  self.idle_counter += 1 # Increase counter
295
295
  except Exception as e:
296
- errlog_add(f"[ERR] Idle task exists: {e}")
296
+ syslog(f"[ERR] Idle task exists: {e}")
297
297
  my_task.done.set()
298
298
 
299
299
  @staticmethod
@@ -374,7 +374,7 @@ class Manager:
374
374
  try:
375
375
  return False if to_kill is None else to_kill.cancel()
376
376
  except Exception as e:
377
- errlog_add(f"[ERR] Task kill: {e}")
377
+ syslog(f"[ERR] Task kill: {e}")
378
378
  return False
379
379
 
380
380
  # Handle task group kill (module.*)
@@ -400,7 +400,7 @@ class Manager:
400
400
  try:
401
401
  asyncio.get_event_loop().run_forever()
402
402
  except Exception as e:
403
- errlog_add(f"[aio] loop stopped: {e}")
403
+ syslog(f"[aio] loop stopped: {e}")
404
404
  asyncio.get_event_loop().close()
405
405
 
406
406
  @staticmethod
@@ -441,7 +441,7 @@ def exec_builtins(func):
441
441
  out = Manager.INTERCON(host=intercon_target, cmd=arg_list)
442
442
  except Exception as e:
443
443
  out = {}
444
- errlog_add(f"[ERR] Intercon: {e}")
444
+ syslog(f"[ERR] Intercon: {e}")
445
445
  return True, out
446
446
 
447
447
  # MODULES
@@ -602,9 +602,9 @@ def exec_lm_pipe(taskstr):
602
602
  console_write(f"[SKIP] exec_lm_pipe: {' '.join(cmd)}")
603
603
  continue
604
604
  if not lm_exec(cmd)[0]:
605
- errlog_add(f"[WARN] exec_lm_pipe: {cmd}")
605
+ syslog(f"[WARN] exec_lm_pipe: {cmd}")
606
606
  except Exception as e:
607
- errlog_add(f"[ERR] exec_lm_pipe {taskstr}: {e}")
607
+ syslog(f"[ERR] exec_lm_pipe {taskstr}: {e}")
608
608
  return False
609
609
  return True
610
610
 
@@ -617,5 +617,5 @@ def exec_lm_pipe_schedule(taskstr):
617
617
  schedule(exec_lm_pipe, taskstr)
618
618
  return True
619
619
  except Exception as e:
620
- errlog_add(f"[ERR] exec_lm_pipe_schedule: {e}")
620
+ syslog(f"[ERR] exec_lm_pipe_schedule: {e}")
621
621
  return False
micrOS/source/Time.py CHANGED
@@ -14,7 +14,7 @@ from network import WLAN, STA_IF
14
14
  from utime import sleep_ms, time, mktime, localtime
15
15
 
16
16
  from Config import cfgput, cfgget
17
- from Debug import errlog_add, console_write
17
+ from Debug import syslog, console_write
18
18
  from urequests import get as http_get
19
19
  from Files import OSPath, path_join
20
20
 
@@ -49,7 +49,7 @@ def ntp_time():
49
49
  :return: ntp date struct
50
50
  """
51
51
  if not WLAN(STA_IF).isconnected():
52
- errlog_add("STA not connected: ntptime")
52
+ syslog("[WARN] STA not connected: ntptime")
53
53
  return False
54
54
 
55
55
  def get_ntp():
@@ -85,7 +85,7 @@ def ntp_time():
85
85
  console_write(f"ntptime error.:{e}")
86
86
  err = e
87
87
  sleep_ms(100)
88
- errlog_add(f"[ERR] ntptime: {err}")
88
+ syslog(f"[ERR] ntptime: {err}")
89
89
  return False
90
90
 
91
91
 
@@ -102,7 +102,7 @@ def __sun_cache(mode):
102
102
  cache = {k:tuple([str(t) for t in v]) for k, v in Sun.TIME.items()}
103
103
  f.write(';'.join([f'{k}:{"-".join(v)}' for k, v in cache.items()]))
104
104
  except:
105
- errlog_add("[ERR] Cannot write sun cache")
105
+ syslog("[ERR] Cannot write sun cache")
106
106
  return
107
107
  try:
108
108
  # RESTORE CACHE
@@ -141,7 +141,7 @@ def suntime():
141
141
  Sun.UTC = int(response.get('offset') / 60) # IN MINUTE
142
142
  cfgput('utc', Sun.UTC, True)
143
143
  except Exception as e:
144
- errlog_add(f'[ERR] ip-api: {e} data: {response}')
144
+ syslog(f'[ERR] ip-api: {e} data: {response}')
145
145
  return Sun.TIME
146
146
 
147
147
  # SUNSET-SUNRISE API REQUEST HANDLING
@@ -156,7 +156,7 @@ def suntime():
156
156
  sun = {'sunrise': time_regex.search(results.get('sunrise')).group(1).split(':'),
157
157
  'sunset': time_regex.search(results.get('sunset')).group(1).split(':')}
158
158
  except Exception as e:
159
- errlog_add(f'[ERR] sunrise-api: {e} data: {response}')
159
+ syslog(f'[ERR] sunrise-api: {e} data: {response}')
160
160
  # Try to parse response by expected sun_keys
161
161
  try:
162
162
  for key in sun:
@@ -164,7 +164,7 @@ def suntime():
164
164
  sun[key][0] += int(Sun.UTC / 60)
165
165
  sun[key] = tuple(sun[key])
166
166
  except Exception as e:
167
- errlog_add(f'sunrise-api parse error: {e} sun: {sun}')
167
+ syslog(f'[WARN] sunrise-api parse error: {e} sun: {sun}')
168
168
  # Retrieve cached data and return
169
169
  __sun_cache('r') # Using Sun.TIME
170
170
  console_write('[suntime] loaded from cache')
micrOS/source/Types.py CHANGED
@@ -12,7 +12,7 @@ USAGE:
12
12
  SLIDER brightness br=<0-100-5>
13
13
  """
14
14
  from json import dumps
15
- from Debug import errlog_add
15
+ from Debug import syslog
16
16
 
17
17
  ########################################################
18
18
  # HELP TUPLE RESOLVER #
@@ -90,7 +90,7 @@ def resolve(help_data, widgets=False):
90
90
  try:
91
91
  help_msg.append(_generate(resolved_tag, msg))
92
92
  except Exception as e:
93
- errlog_add(f"[ERR] resolve {tag} help msg: {e}")
93
+ syslog(f"[ERR] resolve {tag} help msg: {e}")
94
94
  continue
95
95
  help_msg.append(msg.replace(tag, '').strip())
96
96
  elif not widgets:
micrOS/source/Web.py CHANGED
@@ -15,8 +15,9 @@ Designed by Marcell Ban aka BxNxM
15
15
  from json import dumps, loads
16
16
  import uasyncio as asyncio
17
17
  from Tasks import lm_exec, NativeTask, lm_is_loaded
18
- from Debug import errlog_add, console_write
18
+ from Debug import syslog, console_write
19
19
  from Config import cfgget
20
+ from Files import OSPath, path_join
20
21
 
21
22
 
22
23
  class WebEngine:
@@ -27,6 +28,14 @@ class WebEngine:
27
28
  REQ200 = "HTTP/1.1 200 OK\r\nContent-Type: {dtype}\r\nContent-Length:{len}\r\n\r\n{data}"
28
29
  REQ400 = "HTTP/1.1 400 Bad Request\r\nContent-Type: text/plain\r\nContent-Length: {len}\r\n\r\n{data}"
29
30
  REQ404 = "HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: {len}\r\n\r\n{data}"
31
+ CONTENT_TYPES = {"html": "text/html",
32
+ "css": "text/css",
33
+ "js": "application/javascript",
34
+ "json": "application/json",
35
+ "ico": "image/x-icon", # favicon
36
+ "jpeg": "image/jpeg",
37
+ "png": "image/png",
38
+ "gif": "image/gif"}
30
39
 
31
40
  def __init__(self, client, version):
32
41
  self.client = client
@@ -35,14 +44,11 @@ class WebEngine:
35
44
  @staticmethod
36
45
  def file_type(path):
37
46
  """File dynamic Content-Type handling"""
38
- content_types = {".html": "text/html",
39
- ".css": "text/css",
40
- ".js": "application/javascript",
41
- ".jpeg": "image/jpeg"}
47
+ default_type = "text/plain"
42
48
  # Extract the file extension
43
49
  ext = path.rsplit('.', 1)[-1]
44
50
  # Return the content type based on the file extension
45
- return content_types.get(f".{ext}", "text/plain")
51
+ return WebEngine.CONTENT_TYPES.get(ext, default_type)
46
52
 
47
53
  async def response(self, request):
48
54
  """HTTP GET REQUEST - WEB INTERFACE"""
@@ -68,13 +74,14 @@ class WebEngine:
68
74
  # [3] HOME/PAGE ENDPOINT(s) [default: / -> /index.html]
69
75
  if url.startswith('/'):
70
76
  resource = 'index.html' if url == '/' else url.replace('/', '')
71
- self.client.console(f"[WebCli] --- {url} ACCEPT")
72
- if resource.split('.')[-1] not in ('html', 'js', 'css'):
77
+ web_resource = path_join(OSPath.WEB, resource) # Redirect path to web folder
78
+ self.client.console(f"[WebCli] --- {url} ACCEPT -> {web_resource}")
79
+ if resource.split('.')[-1] not in tuple(self.CONTENT_TYPES.keys()):
73
80
  await self.client.a_send(self.REQ404.format(len=27, data='404 Not supported file type'))
74
81
  return
75
82
  try:
76
- # SEND RESOURCE CONTENT: HTML, JS, CSS
77
- with open(resource, 'r') as file:
83
+ # SEND RESOURCE CONTENT: HTML, JS, CSS (WebEngine.CONTENT_TYPES)
84
+ with open(web_resource, 'r') as file:
78
85
  data = file.read()
79
86
  response = self.REQ200.format(dtype=WebEngine.file_type(resource), len=len(data), data=data)
80
87
  # Send entire response data
@@ -90,7 +97,7 @@ class WebEngine:
90
97
  # position += next_chunk_size
91
98
  except Exception as e:
92
99
  if 'memory allocation failed' in str(e):
93
- errlog_add(f"[ERR] WebCli {resource}: {e}")
100
+ syslog(f"[ERR] WebCli {resource}: {e}")
94
101
  await self.client.a_send(self.REQ404.format(len=13, data='404 Not Found'))
95
102
  return
96
103
  # INVALID/BAD REQUEST
@@ -98,7 +105,7 @@ class WebEngine:
98
105
 
99
106
  @staticmethod
100
107
  def rest(url):
101
- resp_schema = {'result': None, 'state': False}
108
+ resp_schema = {'result': {}, 'state': False}
102
109
  cmd = url.replace('/rest', '')
103
110
  if len(cmd) > 1:
104
111
  # REST sub-parameter handling (rest commands)
@@ -149,7 +156,7 @@ class WebEngine:
149
156
  await self.client.a_send(WebEngine.REQ200.format(dtype=dtype, len=len(data), data=data))
150
157
  except Exception as e:
151
158
  await self.client.a_send(self.REQ404.format(len=len(str(e)), data=e))
152
- errlog_add(f"[ERR] WebCli endpoints {url}: {e}")
159
+ syslog(f"[ERR] WebCli endpoints {url}: {e}")
153
160
  return True # Registered endpoint was found and executed
154
161
  return False # Not registered endpoint
155
162