micrOSDevToolKit 2.9.1__py3-none-any.whl → 2.9.6__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 (59) hide show
  1. micrOS/release_info/micrOS_ReleaseInfo/system_analysis_sum.json +19 -19
  2. micrOS/source/Common.py +1 -1
  3. micrOS/source/Config.py +6 -6
  4. micrOS/source/LM_pacman.py +248 -0
  5. micrOS/source/LM_rest.py +0 -1
  6. micrOS/source/LM_robustness.py +2 -2
  7. micrOS/source/LM_system.py +4 -16
  8. micrOS/source/LM_telegram.py +95 -61
  9. micrOS/source/Logger.py +51 -17
  10. micrOS/source/Notify.py +4 -3
  11. micrOS/source/Server.py +33 -39
  12. micrOS/source/Shell.py +72 -74
  13. micrOS/source/Web.py +22 -23
  14. micrOS/source/microIO.py +1 -2
  15. micrOS/source/reset.py +5 -1
  16. micrOS/source/urequests.py +12 -4
  17. {micrOSDevToolKit-2.9.1.data → micrOSDevToolKit-2.9.6.data}/scripts/devToolKit.py +3 -2
  18. {micrOSDevToolKit-2.9.1.dist-info → micrOSDevToolKit-2.9.6.dist-info}/METADATA +1 -1
  19. {micrOSDevToolKit-2.9.1.dist-info → micrOSDevToolKit-2.9.6.dist-info}/RECORD +57 -54
  20. toolkit/Gateway.py +2 -2
  21. toolkit/dashboard_apps/SystemTest.py +14 -12
  22. toolkit/index.html +4 -4
  23. toolkit/lib/TerminalColors.py +4 -0
  24. toolkit/lib/macroScript.py +6 -0
  25. toolkit/lib/micrOSClient.py +48 -21
  26. toolkit/lib/micrOSClientHistory.py +122 -0
  27. toolkit/micrOSlint.py +1 -1
  28. toolkit/simulator_lib/__pycache__/machine.cpython-312.pyc +0 -0
  29. toolkit/simulator_lib/__pycache__/uasyncio.cpython-312.pyc +0 -0
  30. toolkit/simulator_lib/__pycache__/uos.cpython-312.pyc +0 -0
  31. toolkit/simulator_lib/__pycache__/ussl.cpython-312.pyc +0 -0
  32. toolkit/simulator_lib/machine.py +4 -0
  33. toolkit/simulator_lib/node_config.json +1 -1
  34. toolkit/simulator_lib/uasyncio.py +7 -1
  35. toolkit/simulator_lib/uos.py +138 -0
  36. toolkit/socketClient.py +4 -4
  37. toolkit/workspace/precompiled/Common.mpy +0 -0
  38. toolkit/workspace/precompiled/Config.mpy +0 -0
  39. toolkit/workspace/precompiled/Espnow.mpy +0 -0
  40. toolkit/workspace/precompiled/LM_pacman.py +248 -0
  41. toolkit/workspace/precompiled/LM_rest.mpy +0 -0
  42. toolkit/workspace/precompiled/LM_robustness.py +2 -2
  43. toolkit/workspace/precompiled/LM_system.mpy +0 -0
  44. toolkit/workspace/precompiled/LM_telegram.mpy +0 -0
  45. toolkit/workspace/precompiled/Logger.mpy +0 -0
  46. toolkit/workspace/precompiled/Notify.mpy +0 -0
  47. toolkit/workspace/precompiled/Server.mpy +0 -0
  48. toolkit/workspace/precompiled/Shell.mpy +0 -0
  49. toolkit/workspace/precompiled/Web.mpy +0 -0
  50. toolkit/workspace/precompiled/_mpy.version +1 -1
  51. toolkit/workspace/precompiled/microIO.mpy +0 -0
  52. toolkit/workspace/precompiled/node_config.json +1 -1
  53. toolkit/workspace/precompiled/reset.mpy +0 -0
  54. toolkit/workspace/precompiled/urequests.mpy +0 -0
  55. micrOS/source/LM_lmpacman.py +0 -126
  56. toolkit/workspace/precompiled/LM_lmpacman.mpy +0 -0
  57. {micrOSDevToolKit-2.9.1.dist-info → micrOSDevToolKit-2.9.6.dist-info}/LICENSE +0 -0
  58. {micrOSDevToolKit-2.9.1.dist-info → micrOSDevToolKit-2.9.6.dist-info}/WHEEL +0 -0
  59. {micrOSDevToolKit-2.9.1.dist-info → micrOSDevToolKit-2.9.6.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,122 @@
1
+ import sys
2
+ import os
3
+
4
+ try:
5
+ import readline # Linux/macOS
6
+ except ImportError:
7
+ import pyreadline3 as readline # Windows (PowerShell, CMD)
8
+
9
+ try:
10
+ from .TerminalColors import Colors as color
11
+ except:
12
+ from TerminalColors import Colors as color
13
+
14
+
15
+ class CommandInterface:
16
+ def __init__(self, prompt):
17
+ self.prompt = prompt
18
+ self.command_history = ["help"]
19
+ self.history_file = os.path.expanduser("~/.micrOS_cmd_history") # History file (Linux/macOS)
20
+
21
+ # Configure readline
22
+ self.load_history()
23
+ readline.set_completer_delims("") # Ensure entire command is considered
24
+ readline.set_completer(self.autocomplete)
25
+ # Check if we're running on macOS using libedit
26
+ if "libedit" in readline.__doc__:
27
+ readline.parse_and_bind("bind ^I rl_complete") # macOS alternative
28
+ else:
29
+ readline.parse_and_bind("tab: complete") # Linux/GNU readline
30
+ readline.set_pre_input_hook(self.pre_input_hook)
31
+ readline.set_completion_display_matches_hook(self.completion_display)
32
+
33
+ def __auto_clear_history(self):
34
+ cmd_history = []
35
+ # Load file history in order - skip duplicates
36
+ if os.path.exists(self.history_file):
37
+ with open(self.history_file, "r") as f:
38
+ for line in reversed(f.readlines()):
39
+ if line in cmd_history:
40
+ continue
41
+ cmd_history.append(line)
42
+ # Save cleaned history to file
43
+ with open(self.history_file, "w") as f:
44
+ f.writelines(f"{item}\n" for item in reversed(cmd_history))
45
+
46
+ def load_history(self):
47
+ """Loads command history from a file if available."""
48
+ print(f"Command history: {self.history_file}")
49
+ try:
50
+ self.__auto_clear_history()
51
+ except Exception as e:
52
+ print(f"Auto clean history error: {e}")
53
+ if os.path.exists(self.history_file):
54
+ with open(self.history_file, "r") as f:
55
+ for line in f:
56
+ clean_line = line.strip()
57
+ if clean_line: # Avoid empty lines
58
+ self.command_history.append(clean_line)
59
+ readline.add_history(clean_line)
60
+
61
+ def save_history(self):
62
+ """Saves command history to a file."""
63
+ with open(self.history_file, "w") as f:
64
+ for cmd in self.command_history:
65
+ f.write(cmd + "\n")
66
+
67
+ def add_history(self, cmd):
68
+ """Updates readline history and command_history."""
69
+ cmd = cmd.strip()
70
+ if cmd and cmd != self.command_history[-1]: # Avoid duplicate last command
71
+ self.command_history.append(cmd)
72
+ readline.add_history(cmd)
73
+
74
+ def autocomplete(self, text, state):
75
+ """Autocomplete function: suggests previous commands."""
76
+ matches = list(dict.fromkeys(cmd for cmd in self.command_history if cmd.startswith(text)))
77
+ return matches[state] if state < len(matches) else None
78
+
79
+ def pre_input_hook(self):
80
+ """Ensures prompt visibility when scrolling through history."""
81
+ sys.stdout.write(f"\r{self.prompt}{readline.get_line_buffer()}")
82
+ sys.stdout.flush()
83
+ readline.redisplay() # Ensures history navigation does not erase prompt
84
+
85
+ def completion_display(self, substitutions, matches, longest_match_length):
86
+ print("\nSuggestions:", ", ".join(matches))
87
+
88
+ #####################################
89
+ # STANDALONE TEST METHODS #
90
+ #####################################
91
+
92
+ def dummy_send_cmd(self, cmd, stream):
93
+ """TEST FUNCTION - OUTPUT STRUCTURE SIMULATION (Must remain unchanged)."""
94
+ dummy_reply = "Bye!" if cmd.strip() in ["exit", "reboot"] else f"Dummy reply for {cmd}"
95
+ if stream:
96
+ print(dummy_reply) # micrOS protocol: return response data
97
+ print(self.prompt, end="") # micrOS protocol: return prompt -> indicating ready state
98
+ else:
99
+ dummy_reply = f"{dummy_reply}\n{self.prompt}"
100
+ return dummy_reply
101
+
102
+ def dummy_run(self):
103
+ """TEST FUNCTION - Simulated interactive terminal."""
104
+ print(f"{self.prompt}", end="", flush=True)
105
+ while True:
106
+ try:
107
+ cmd = input()
108
+ output = self.dummy_send_cmd(cmd, stream=True)
109
+ self.add_history(cmd)
110
+ if 'Bye!' in str(output):
111
+ break
112
+ except KeyboardInterrupt:
113
+ print("\nExiting...")
114
+ break
115
+
116
+ self.save_history()
117
+ print("Session closed.")
118
+
119
+
120
+ if __name__ == "__main__":
121
+ shell = CommandInterface(prompt="<prompt_placeholder>$ ")
122
+ shell.dummy_run()
toolkit/micrOSlint.py CHANGED
@@ -179,7 +179,7 @@ def load_module_checker(categories, verbose=True):
179
179
  _allowed.append(_allow)
180
180
  return _relation, _allowed
181
181
 
182
- lm_god_mode = ['LM_system.py', 'LM_lmpacman.py', 'LM_intercon.py']
182
+ lm_god_mode = ['LM_system.py', 'LM_pacman.py', 'LM_intercon.py']
183
183
  state_lm_dep = True
184
184
  verdict = []
185
185
  lm_resources = categories['load_module']
@@ -214,3 +214,7 @@ def unique_id():
214
214
 
215
215
  def time_pulse_us():
216
216
  return time.time_ns()*1000
217
+
218
+
219
+ def SDCard():
220
+ pass
@@ -2,6 +2,6 @@
2
2
  "devfid": "simulator",
3
3
  "appwd": "ADmin123",
4
4
  "webui": true,
5
- "boothook": "dashboard_be load; neopixel load; #system top",
5
+ "boothook": "dashboard_be load; neopixel load; #telegram receiver_loop &2000",
6
6
  "aioqueue": 4,
7
7
  "telegram": "6185435843:AAH71wEyoOil8bRKecQHp4zazTQ_MmE7bvE"}
@@ -1,8 +1,14 @@
1
1
  import asyncio
2
+ import ssl
3
+
4
+ ssl_context = ssl.create_default_context()
5
+ ssl_context.check_hostname = False # Disable hostname check
6
+ ssl_context.verify_mode = ssl.CERT_NONE # Disable certificate verification
2
7
 
3
8
 
4
9
  def open_connection(host, port, ssl=False):
5
- return asyncio.open_connection(host, port, ssl=ssl)
10
+ #return asyncio.open_connection(host, port, ssl=ssl)
11
+ return asyncio.open_connection(host, port, ssl=ssl_context if ssl else None)
6
12
 
7
13
 
8
14
  class Lock(asyncio.Lock):
@@ -0,0 +1,138 @@
1
+ import os
2
+ import stat as py_fs_stat
3
+
4
+ # https://docs.micropython.org/en/v1.9.2/pyboard/library/uos.html
5
+ # https://docs.micropython.org/en/v1.18/library/os.html
6
+
7
+ MOCK_SIM = False
8
+
9
+ def listdir(path=None):
10
+ if path is None:
11
+ return os.listdir()
12
+ path = __mock_sim_dir(path)
13
+ print(f"[uos.SIM] listdir: {path}")
14
+ return os.listdir(path)
15
+
16
+
17
+ def getcwd():
18
+ _cwd = os.getcwd()
19
+ if MOCK_SIM:
20
+ cwd = f"{_cwd}/../workspace/simulator/"
21
+ print(f"MOCK PATH: {cwd}")
22
+ elif "workspace/simulator" not in _cwd:
23
+ cwd = f"{_cwd}/toolkit/workspace/simulator/"
24
+ print(f"[uos.SIM] MOCK PATH: {_cwd} -> {cwd}")
25
+ else:
26
+ cwd = _cwd
27
+ return cwd
28
+
29
+
30
+ def __mock_sim_dir(path):
31
+ """
32
+ micropython sim hack
33
+ """
34
+ if MOCK_SIM:
35
+ cwd = getcwd()
36
+ path = f"{cwd}{path}"
37
+ print(f"[!!!] [uos.SIM] CWD PATH HACK: {path}")
38
+ elif "workspace/simulator" not in path:
39
+ path = f"{getcwd()}{path}"
40
+ return path
41
+
42
+
43
+ def ilistdir(path):
44
+ buffer = []
45
+ for filename in listdir(path):
46
+ _name, _type, _inode = filename, stat(f"{path}/{filename}")[0], 0
47
+ print(f"[uos.SIM] ilistdir {path}: ({_name}, {_type:#x}, {_inode}")
48
+ buffer.append((_name, _type, _inode))
49
+ return tuple(buffer)
50
+
51
+
52
+ def mkdir(path):
53
+ print(f"[uos.SIM] mkdir: {path}")
54
+ return os.mkdir(path)
55
+
56
+
57
+ def remove(path):
58
+ path = __mock_sim_dir(path)
59
+ print(f"[uos.SIM] remove: {path}")
60
+ if "simulator" in path and path.replace('/', '').endswith('simulator'):
61
+ print(f"\t[uos.SIM] rmdir: Invalid path! {path}")
62
+ return False
63
+ return os.remove(path)
64
+
65
+
66
+ def rename(old_path, new_path):
67
+ old_path, new_path = __mock_sim_dir(old_path), __mock_sim_dir(new_path)
68
+ print(f"[uos.SIM] rename: {old_path} -> {new_path}")
69
+ os.rename(old_path, new_path)
70
+
71
+ def _stat_eval(stat_result):
72
+ """
73
+ micropython converter
74
+ """
75
+ micropython_file_identifier = {'dir': 0x4000, 'file': 0x8000}
76
+ # Check if it's a file
77
+ if py_fs_stat.S_ISREG(stat_result.st_mode):
78
+ # FILE
79
+ return (micropython_file_identifier['file'],)
80
+ if py_fs_stat.S_ISDIR(stat_result.st_mode):
81
+ # DIRECTORY
82
+ return (micropython_file_identifier['dir'],)
83
+ return (0x0,)
84
+
85
+ def stat(path):
86
+ path = __mock_sim_dir(path)
87
+ stat_result = os.stat(path)
88
+ micropython_stat_result = _stat_eval(stat_result)
89
+ path_type = 'dir' if micropython_stat_result[0] & 0x4000 else 'file'
90
+ print(f"[uos.SIM] stat: {path} {path_type}({micropython_stat_result[0]:#x})")
91
+ return micropython_stat_result
92
+
93
+
94
+ def rmdir(path):
95
+ print(f"[uos.SIM] rmdir: {path}")
96
+ if "simulator" in path and path.replace('/', '').endswith('simulator'):
97
+ print(f"\t[uos.SIM] rmdir: Invalid path! {path}")
98
+ return False
99
+ return os.rmdir(path)
100
+
101
+
102
+ def statvfs(path=None):
103
+ if path is None:
104
+ return os.statvfs(__mock_sim_dir(path))
105
+ return os.statvfs(path)
106
+
107
+
108
+ def uname():
109
+ return os.uname()
110
+
111
+
112
+ def sync():
113
+ print("[uos.SIM] sync - dummy")
114
+
115
+
116
+ def urandom(n):
117
+ print(f"[uos.SIM] sync {n}")
118
+ return os.urandom(n)
119
+
120
+
121
+ def dupterm(stream_object):
122
+ print("[uos.SIM] dupterm - dummy")
123
+
124
+
125
+ def mount(*args, **kwargs):
126
+ print("[uos.SIM] mount - dummy")
127
+
128
+
129
+ def umount(*args, **kwargs):
130
+ print("[uos.SIM] unmount - dummy")
131
+
132
+
133
+ if __name__ == "__main__":
134
+ MOCK_SIM = True
135
+ print(f"SIM root (mock: {MOCK_SIM}): {__mock_sim_dir('/')}\ngetcwd: {getcwd()}")
136
+ print(listdir("/"))
137
+ print(stat('/'))
138
+ print(ilistdir('/'))
toolkit/socketClient.py CHANGED
@@ -210,8 +210,8 @@ class ConnectionData:
210
210
  start_comm = time.time()
211
211
  version_data = SocketDictClient(host=ip, port=port, silent_mode=True, tout=3).non_interactive(['version'])
212
212
  elapsed_time = "{:.3f}".format(time.time() - start_comm)
213
- except:
214
- pass
213
+ except Exception as e:
214
+ print(f"Getting device version {fuid}:{uid} error: {e}")
215
215
 
216
216
  # Generate line printout
217
217
  base_info = "{uid}{spr1}{fuid}".format(uid=uid, spr1=spacer1, fuid=fuid)
@@ -341,7 +341,7 @@ class SocketDictClient:
341
341
  #########################################################
342
342
 
343
343
 
344
- def main(args, host='127.0.0.1', port=9008, timeout=3, pwd=None, verbose=False):
344
+ def main(args, host='127.0.0.1', port=9008, timeout=5, pwd=None, verbose=False):
345
345
  """ main connection wrapper function """
346
346
  answer_msg = None
347
347
 
@@ -426,7 +426,7 @@ def socket_commandline_args(arg_list):
426
426
  return ' <a> '.join(command_buffer), return_action_dict
427
427
 
428
428
 
429
- def run(arg_list=[], timeout=5):
429
+ def run(arg_list=[], timeout=10):
430
430
  """ Run from code
431
431
  - Handles extra command line arguments
432
432
  """
Binary file
Binary file
Binary file
@@ -0,0 +1,248 @@
1
+ from uos import listdir, remove, stat
2
+ from sys import modules
3
+ from Common import socket_stream
4
+
5
+ WEB_EXT = ('html', 'js', 'css')
6
+ DATA_TYPES = ('log', 'pds', 'dat')
7
+
8
+ def _is_app_resource(path='/'):
9
+ if stat(path)[0] & 0x4000: # Dir check
10
+ return True, 'd'
11
+ file_name = path.split("/")[-1]
12
+ if file_name.startswith('LM_') or file_name.split('.')[-1] in WEB_EXT + DATA_TYPES:
13
+ return True, 'f'
14
+ return False, '?'
15
+
16
+
17
+ #############################################
18
+ # Safe file system handler functions #
19
+ #############################################
20
+
21
+ def ls(path="/", content='*', raw=False):
22
+ """
23
+ Linux like ls command - list app resources and app folders
24
+ :param path: path to list, default: /
25
+ :param content: content type, default all, f-file, d-dir can be selected
26
+ :param raw: keep raw output [(is_app, type), ...]
27
+ """
28
+ path = path if path.endswith('/') else f"{path}/"
29
+ items = []
30
+ for item in listdir(path):
31
+ is_app, item_type = _is_app_resource(path + item)
32
+ if is_app and (content == "*" or item_type == content):
33
+ items.append((item_type, item))
34
+ if raw:
35
+ return items
36
+ formatted_output = ""
37
+ i = 0
38
+ for f in items:
39
+ i += 1
40
+ spacer = " " * (4 - len(str(i)))
41
+ formatted_output += f"{i}{spacer}{f[0]} {f[1]}\n"
42
+ return formatted_output
43
+
44
+
45
+ def rm(path):
46
+ """
47
+ Linux like rm command - delete app resources and folders
48
+ :param path: app resource name/path, ex.: LM_robustness.py
49
+ """
50
+ if 'pacman.' in path or 'system.' in path or "/" == path.strip():
51
+ return f'Load module {path} is protected, skip delete.'
52
+ is_app, item_type = _is_app_resource(path)
53
+ if is_app:
54
+ remove(path)
55
+ return f"Remove: {path} {'dir' if item_type == 'd' else 'file'}"
56
+ return f"Invalid path {path}"
57
+
58
+
59
+ def dirtree(path="/", raw=False):
60
+ """Return only directories from a given path."""
61
+ path = path if path.endswith('/') else f"{path}/"
62
+ folders = [f"{path}/{item}" for item in listdir(path) if _is_app_resource(f"{path}{item}")[1] == 'd']
63
+ folder_contents = {folder:listdir(folder) for folder in folders}
64
+ if raw:
65
+ return folder_contents
66
+ formatted_output = ""
67
+ for k, v in folder_contents.items():
68
+ formatted_output += f"{k}\n"
69
+ for val in v:
70
+ formatted_output += f"\t{val}\n"
71
+ return formatted_output
72
+
73
+
74
+ def download(url=None, package=None):
75
+ """
76
+ [BETA] Load Module downloader with mip
77
+ :param url: github url path, ex. BxNxM/micrOS/master/toolkit/workspace/precompiled/LM_robustness.py
78
+ :param package: mip package name or raw url (hack)
79
+ """
80
+ if url is None and package is None:
81
+ return "Nothing to download, url=None package=None"
82
+ if package is None:
83
+ base_url = "https://raw.githubusercontent.com/"
84
+ file_name = url.split("/")[-1]
85
+ if not(file_name.endswith("py") and file_name.startswith("LM_")):
86
+ return "Invalid file name in url ending, hint: /LM_*.mpy or /LM_*.py"
87
+ # Convert GitHub URL to raw content URL
88
+ if "github.com" in url and "blob" in url:
89
+ url = url.replace("https://github.com/", base_url).replace("/blob", "")
90
+ else:
91
+ url = f"{base_url}{url}"
92
+ else:
93
+ url = package
94
+ from mip import install
95
+ verdict = ""
96
+ try:
97
+ verdict += f"Install {url}\n"
98
+ install(url)
99
+ verdict += "\n|- Done"
100
+ except Exception as e:
101
+ verdict += f"|- Cannot install: {url}\n{e}"
102
+ return verdict
103
+
104
+
105
+ def del_duplicates():
106
+ """
107
+ Load module package manager (Not just load modules)
108
+ - delete duplicated .mpy and .py resources, keep .mpy resource!
109
+ """
110
+ msg_buf = []
111
+ py = list((res.split('.')[0] for res in listdir() if res.endswith('.py'))) # Normally smaller list
112
+ mpy = (res.split('.')[0] for res in listdir() if res.endswith('.mpy'))
113
+ for m in mpy:
114
+ # Iterate over mpy resources
115
+ state = True
116
+ if m in py and m != 'main':
117
+ to_delete = f'{m}.py'
118
+ try:
119
+ remove(to_delete)
120
+ except:
121
+ state = False
122
+ msg_buf.append(f' Delete {to_delete} {state}')
123
+ return '\n'.join(msg_buf) if len(msg_buf) > 0 else 'Nothing to delete.'
124
+
125
+
126
+ def moduls(unload=None):
127
+ """
128
+ List / unload loaded upython Load Modules
129
+ :param unload: module name to unload
130
+ :param unload: None - list active modules
131
+ :return str: verdict
132
+ """
133
+ if unload is None:
134
+ return list(modules.keys())
135
+ if unload in modules.keys():
136
+ del modules[unload]
137
+ return f"Module unload {unload} done."
138
+ return f"Module unload {unload} failed."
139
+
140
+
141
+ @socket_stream
142
+ def cachedump(delpds=None, msgobj=None):
143
+ """
144
+ Cache system persistent data storage files (.pds)
145
+ :param delpds: cache name to delete
146
+ """
147
+ if delpds is None:
148
+ # List pds files aka application cache
149
+ msg_buf = []
150
+ for pds in (_pds for _pds in listdir() if _pds.endswith('.pds')):
151
+ with open(pds, 'r') as f:
152
+ if msgobj is None:
153
+ msg_buf.append(f'{pds}: {f.read()}')
154
+ else:
155
+ msgobj(f'{pds}: {f.read()}')
156
+ return msg_buf if len(msg_buf) > 0 else ''
157
+ # Remove given pds file
158
+ try:
159
+ remove(f'{delpds}.pds')
160
+ return f'{delpds}.pds delete done.'
161
+ except:
162
+ return f'{delpds}.pds not exists'
163
+
164
+
165
+ def dat_dump():
166
+ """
167
+ Generic .dat file dump
168
+ - logged data from LMs, sensor datat, etc...
169
+ """
170
+ logs_dir = "/logs/"
171
+ dats = (f for f in listdir(logs_dir) if f.endswith('.dat'))
172
+ out = {}
173
+ for dat in dats:
174
+ with open(f"{logs_dir}{dat}", 'r') as f:
175
+ out[dat] = f.read()
176
+ return out
177
+
178
+ #############################################
179
+ # Legacy features #
180
+ #############################################
181
+
182
+
183
+ @socket_stream
184
+ def listmods(msgobj=None):
185
+ """
186
+ Load module package manager
187
+ - list all load modules
188
+ """
189
+ # Dump available LMs
190
+ msg_buf = []
191
+ for k in (res.replace('LM_', '') for res in listdir("/")
192
+ if res.startswith('LM_') or res.split('.')[-1] in WEB_EXT):
193
+ if msgobj is None:
194
+ msg_buf.append(f' {k}')
195
+ else:
196
+ msgobj(f' {k}')
197
+ return msg_buf if len(msg_buf) > 0 else ''
198
+
199
+
200
+ def delmod(mod=None):
201
+ """
202
+ Module package manager
203
+ :param mod:
204
+ Delete Load Module with full name: module.py or module.mpy
205
+ OR delete any web resource: *.js, *.css, *.html
206
+ """
207
+ if mod is not None and (mod.endswith('py') or mod.split('.')[-1] in WEB_EXT):
208
+ # LM exception list - system and pacman cannot be deleted
209
+ if 'pacman.' in mod or 'system.' in mod:
210
+ return f'Load module {mod} is in use, skip delete.'
211
+ try:
212
+ to_remove = mod if mod.split('.')[-1] in WEB_EXT else f'LM_{mod}'
213
+ remove(to_remove)
214
+ return f'Delete module: {mod}'
215
+ except Exception as e:
216
+ return f'Cannot delete: {mod}: {e}'
217
+ return f'Invalid value: {mod}'
218
+
219
+
220
+ @socket_stream
221
+ def micros_checksum(msgobj=None):
222
+ from hashlib import sha1
223
+ from binascii import hexlify
224
+ from Config import cfgget
225
+
226
+ for f_name in (_pds for _pds in listdir() if _pds.endswith('py')):
227
+ with open(f_name, 'rb') as f:
228
+ cs = hexlify(sha1(f.read()).digest()).decode('utf-8')
229
+ msgobj(f"{cs} {f_name}")
230
+ # GC collect?
231
+ return f"micrOS version: {cfgget('version')}"
232
+
233
+
234
+ def help(widgets=False):
235
+ """
236
+ [i] micrOS LM naming convention - built-in help message
237
+ :return tuple:
238
+ (widgets=False) list of functions implemented by this application
239
+ (widgets=True) list of widget json for UI generation
240
+ """
241
+ return ('listmods', 'delmod mod=<module>.py/.mpy or .js/.html/.css', 'del_duplicates',
242
+ 'moduls unload="LM_rgb/None"',
243
+ 'cachedump delpds="rgb/None"',
244
+ 'dat_dump',
245
+ 'download url="BxNxM/micrOS/master/toolkit/workspace/precompiled/LM_robustness.py"',
246
+ 'micros_checksum',
247
+ 'ls path="/" content="*/f/d"',
248
+ 'rm <path>', 'dirtree path="/"')
Binary file
@@ -9,8 +9,8 @@ def raise_error(msgobj=None):
9
9
  """
10
10
  if msgobj is not None:
11
11
  msgobj("Raise test exception")
12
- syslog('Robustness TeSt ErRoR')
13
- raise Exception("Test exception")
12
+ state = syslog('Robustness TeSt ErRoR')
13
+ raise Exception(f"Test exception: {'OK' if state else 'NOK'}")
14
14
 
15
15
 
16
16
  @socket_stream
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -1 +1 @@
1
- 1.20.0
1
+ 1.24.1
Binary file
@@ -1 +1 @@
1
- {"stapwd": "BNM3,1415", "cron": false, "crontasks": "n/a", "timirq": false, "timirqcbf": "n/a", "irq1": false, "irq1_cbf": "n/a", "irq2": true, "appwd": "ADmin123", "auth": false, "webui": true, "irq2_cbf": "basic_led toggle", "irq2_trig": "n/a", "irq3": false, "irq3_cbf": "n/a", "irq3_trig": "n/a", "irq_prell_ms": 300, "boothook": "types_demo load", "aioqueue": 5, "utc": 60, "boostmd": true, "espnow": false, "irq1_trig": "n/a", "irq4_cbf": "n/a", "guimeta": "...", "devip": "10.0.1.179", "timirqseq": 1000, "cstmpmap": "n/a", "telegram": "n/a", "dbg": true, "hwuid": "micr7c9ebd6147c4OS", "devfid": "TestBird", "staessid": "elektroncsakpozitivan_2G", "soctout": 30, "irq4_trig": "n/a", "irq4": false, "version": "2.8.1-0", "nwmd": "STA", "socport": 9008}
1
+ {"irq2": false, "irq2_cbf": "n/a", "irq3_cbf": "n/a", "timirq": true, "irq4": false, "auth": false, "irq4_cbf": "n/a", "devip": "10.0.1.129", "soctout": 100, "appwd": "ADmin123", "timirqcbf": "rgb run_transition", "timirqseq": 800, "hwuid": "micr8caab594e9d4OS", "staessid": "T-3588F3;elektroncsakpozitivan_2G", "irq1_cbf": "rgb toggle", "cron": true, "irq4_trig": "n/a", "nwmd": "STA", "boothook": "rgb load_n_init", "version": "1.41.0-0", "irq_prell_ms": 300, "crontasks": "sunrise!rgb set_transition 400 0 0 3600;sunset!rgb run_transition 143 330 0 300;*:9:0:0!rgb set_transition 0 300 300 1800;*:12:0:0!rgb toggle False;*:20:0:0!rgb set_transition 600 211 2 3600;*:21:2:0!rgb rgb 100 30 0;*:23:0:0!rgb toggle False", "aioqueue": 3, "utc": 60, "boostmd": true, "irq1_trig": "n/a", "guimeta": "...", "socport": 9008, "webui": true, "cstmpmap": "n/a", "telegram": "n/a", "irq3_trig": "n/a", "dbg": true, "irq2_trig": "n/a", "irq3": false, "devfid": "ujelet", "stapwd": "jBRU7SJmreae8n5p;BNM3,1415", "irq1": false}
Binary file
Binary file