micrOSDevToolKit 2.11.0__py3-none-any.whl → 2.13.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.
- micrOS/release_info/micrOS_ReleaseInfo/system_analysis_sum.json +25 -25
- micrOS/source/Common.py +34 -14
- micrOS/source/Config.py +7 -7
- micrOS/source/Debug.py +9 -9
- micrOS/source/Espnow.py +6 -6
- micrOS/source/Files.py +5 -3
- micrOS/source/Hooks.py +5 -5
- micrOS/source/InterConnect.py +5 -5
- micrOS/source/Interrupts.py +2 -2
- micrOS/source/LM_dashboard_be.py +2 -2
- micrOS/source/LM_neomatrix.py +42 -12
- micrOS/source/LM_pacman.py +16 -3
- micrOS/source/Logger.py +1 -1
- micrOS/source/Network.py +6 -6
- micrOS/source/Notify.py +2 -2
- micrOS/source/Scheduler.py +5 -5
- micrOS/source/Server.py +6 -6
- micrOS/source/Shell.py +4 -4
- micrOS/source/Tasks.py +13 -13
- micrOS/source/Time.py +7 -7
- micrOS/source/Types.py +2 -2
- micrOS/source/Web.py +20 -13
- micrOS/source/__pycache__/Common.cpython-312.pyc +0 -0
- micrOS/source/__pycache__/Debug.cpython-312.pyc +0 -0
- micrOS/source/__pycache__/Logger.cpython-312.pyc +0 -0
- micrOS/source/__pycache__/Server.cpython-312.pyc +0 -0
- micrOS/source/micrOS.py +5 -5
- micrOS/source/micrOSloader.py +6 -6
- micrOS/source/urequests.py +4 -4
- {microsdevtoolkit-2.11.0.dist-info → microsdevtoolkit-2.13.1.dist-info}/METADATA +23 -22
- {microsdevtoolkit-2.11.0.dist-info → microsdevtoolkit-2.13.1.dist-info}/RECORD +85 -80
- toolkit/DevEnvCompile.py +20 -15
- toolkit/DevEnvOTA.py +29 -8
- toolkit/DevEnvUSB.py +47 -10
- toolkit/MicrOSDevEnv.py +10 -2
- toolkit/MicrosFiles.py +26 -0
- toolkit/lib/LocalMachine.py +6 -1
- toolkit/lib/file_extensions.py +9 -3
- toolkit/lib/pip_package_installer.py +5 -2
- toolkit/micrOSlint.py +3 -1
- toolkit/workspace/precompiled/Common.cpython-312.pyc +0 -0
- toolkit/workspace/precompiled/Common.mpy +0 -0
- toolkit/workspace/precompiled/Config.mpy +0 -0
- toolkit/workspace/precompiled/Debug.mpy +0 -0
- toolkit/workspace/precompiled/Espnow.mpy +0 -0
- toolkit/workspace/precompiled/Files.mpy +0 -0
- toolkit/workspace/precompiled/Hooks.mpy +0 -0
- toolkit/workspace/precompiled/InterConnect.mpy +0 -0
- toolkit/workspace/precompiled/Interrupts.mpy +0 -0
- toolkit/workspace/precompiled/LM_dashboard_be.py +2 -2
- toolkit/workspace/precompiled/LM_neomatrix.mpy +0 -0
- toolkit/workspace/precompiled/LM_pacman.mpy +0 -0
- toolkit/workspace/precompiled/Logger.cpython-312.pyc +0 -0
- toolkit/workspace/precompiled/Logger.mpy +0 -0
- toolkit/workspace/precompiled/Network.mpy +0 -0
- toolkit/workspace/precompiled/Notify.mpy +0 -0
- toolkit/workspace/precompiled/Scheduler.mpy +0 -0
- toolkit/workspace/precompiled/Server.cpython-312.pyc +0 -0
- toolkit/workspace/precompiled/Server.mpy +0 -0
- toolkit/workspace/precompiled/Shell.mpy +0 -0
- toolkit/workspace/precompiled/Tasks.mpy +0 -0
- toolkit/workspace/precompiled/Time.mpy +0 -0
- toolkit/workspace/precompiled/Types.mpy +0 -0
- toolkit/workspace/precompiled/Web.mpy +0 -0
- toolkit/workspace/precompiled/micrOS.mpy +0 -0
- toolkit/workspace/precompiled/micrOSloader.mpy +0 -0
- toolkit/workspace/precompiled/urequests.mpy +0 -0
- /micrOS/source/{dashboard.html → web/dashboard.html} +0 -0
- /micrOS/source/{index.html → web/index.html} +0 -0
- /micrOS/source/{uapi.js → web/uapi.js} +0 -0
- /micrOS/source/{udashboard.js → web/udashboard.js} +0 -0
- /micrOS/source/{ustyle.css → web/ustyle.css} +0 -0
- /micrOS/source/{uwidgets.js → web/uwidgets.js} +0 -0
- /micrOS/source/{uwidgets_pro.js → web/uwidgets_pro.js} +0 -0
- {microsdevtoolkit-2.11.0.data → microsdevtoolkit-2.13.1.data}/scripts/devToolKit.py +0 -0
- {microsdevtoolkit-2.11.0.dist-info → microsdevtoolkit-2.13.1.dist-info}/WHEEL +0 -0
- {microsdevtoolkit-2.11.0.dist-info → microsdevtoolkit-2.13.1.dist-info}/licenses/LICENSE +0 -0
- {microsdevtoolkit-2.11.0.dist-info → microsdevtoolkit-2.13.1.dist-info}/top_level.txt +0 -0
- /toolkit/workspace/precompiled/{dashboard.html → web/dashboard.html} +0 -0
- /toolkit/workspace/precompiled/{index.html → web/index.html} +0 -0
- /toolkit/workspace/precompiled/{uapi.js → web/uapi.js} +0 -0
- /toolkit/workspace/precompiled/{udashboard.js → web/udashboard.js} +0 -0
- /toolkit/workspace/precompiled/{ustyle.css → web/ustyle.css} +0 -0
- /toolkit/workspace/precompiled/{uwidgets.js → web/uwidgets.js} +0 -0
- /toolkit/workspace/precompiled/{uwidgets_pro.js → web/uwidgets_pro.js} +0 -0
micrOS/source/LM_neomatrix.py
CHANGED
|
@@ -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=
|
|
263
|
+
def snake(speed_ms:int=30, length:int=5):
|
|
241
264
|
def effect_snake():
|
|
242
265
|
clear_color = (0, 0, 0)
|
|
243
|
-
|
|
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)
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
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=<
|
|
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)
|
micrOS/source/LM_pacman.py
CHANGED
|
@@ -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>',
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
187
|
+
syslog(f"[ERR][AP] config failed: {e2}")
|
|
188
188
|
if not (ap_if.active() and str(ap_if.config('essid')) == str(_essid)):
|
|
189
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
micrOS/source/Scheduler.py
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
605
|
+
syslog(f"[WARN] exec_lm_pipe: {cmd}")
|
|
606
606
|
except Exception as e:
|
|
607
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
72
|
-
|
|
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(
|
|
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
|
-
|
|
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':
|
|
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
|
-
|
|
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
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|