micrOSDevToolKit 2.10.2__py3-none-any.whl → 2.10.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 (44) hide show
  1. micrOS/release_info/micrOS_ReleaseInfo/system_analysis_sum.json +28 -20
  2. micrOS/source/Common.py +2 -2
  3. micrOS/source/Espnow.py +245 -123
  4. micrOS/source/Files.py +101 -0
  5. micrOS/source/LM_espnow.py +10 -7
  6. micrOS/source/LM_mqtt_pro.py +211 -0
  7. micrOS/source/LM_oled_ui.py +18 -5
  8. micrOS/source/LM_pacman.py +37 -57
  9. micrOS/source/LM_rest.py +3 -3
  10. micrOS/source/LM_system.py +1 -1
  11. micrOS/source/Logger.py +5 -11
  12. micrOS/source/Shell.py +33 -28
  13. micrOS/source/Tasks.py +2 -2
  14. micrOS/source/__pycache__/Common.cpython-312.pyc +0 -0
  15. micrOS/source/__pycache__/Logger.cpython-312.pyc +0 -0
  16. micrOS/source/microIO.py +3 -2
  17. micrOS/source/urequests.py +10 -1
  18. {micrOSDevToolKit-2.10.2.dist-info → microsdevtoolkit-2.10.6.dist-info}/METADATA +3 -2
  19. {micrOSDevToolKit-2.10.2.dist-info → microsdevtoolkit-2.10.6.dist-info}/RECORD +44 -40
  20. {micrOSDevToolKit-2.10.2.dist-info → microsdevtoolkit-2.10.6.dist-info}/WHEEL +1 -1
  21. toolkit/Gateway.py +3 -3
  22. toolkit/simulator_lib/__pycache__/machine.cpython-312.pyc +0 -0
  23. toolkit/simulator_lib/__pycache__/sim_console.cpython-312.pyc +0 -0
  24. toolkit/simulator_lib/__pycache__/uos.cpython-312.pyc +0 -0
  25. toolkit/simulator_lib/uos.py +5 -5
  26. toolkit/user_data/webhooks/generic.py +1 -1
  27. toolkit/user_data/webhooks/macro.py +1 -1
  28. toolkit/user_data/webhooks/template.py +1 -1
  29. toolkit/workspace/precompiled/Espnow.mpy +0 -0
  30. toolkit/workspace/precompiled/Files.mpy +0 -0
  31. toolkit/workspace/precompiled/LM_espnow.py +10 -7
  32. toolkit/workspace/precompiled/LM_mqtt_pro.py +211 -0
  33. toolkit/workspace/precompiled/LM_oled_ui.mpy +0 -0
  34. toolkit/workspace/precompiled/LM_pacman.mpy +0 -0
  35. toolkit/workspace/precompiled/LM_rest.mpy +0 -0
  36. toolkit/workspace/precompiled/LM_system.mpy +0 -0
  37. toolkit/workspace/precompiled/Logger.mpy +0 -0
  38. toolkit/workspace/precompiled/Shell.mpy +0 -0
  39. toolkit/workspace/precompiled/Tasks.mpy +0 -0
  40. toolkit/workspace/precompiled/microIO.mpy +0 -0
  41. toolkit/workspace/precompiled/urequests.mpy +0 -0
  42. {micrOSDevToolKit-2.10.2.data → microsdevtoolkit-2.10.6.data}/scripts/devToolKit.py +0 -0
  43. {micrOSDevToolKit-2.10.2.dist-info → microsdevtoolkit-2.10.6.dist-info/licenses}/LICENSE +0 -0
  44. {micrOSDevToolKit-2.10.2.dist-info → microsdevtoolkit-2.10.6.dist-info}/top_level.txt +0 -0
@@ -6,13 +6,14 @@ def load():
6
6
  """
7
7
  return Espnow.initialize()
8
8
 
9
- def send(peer, msg='modules'):
9
+ def send(peer:bytes|str, msg:str='modules'):
10
10
  """
11
11
  Send message to peer (by mac address)
12
12
  :param peer: mac address of espnow device
13
13
  :param msg: message string/load module call
14
14
  """
15
- return Espnow.espnow_send(peer, msg)
15
+ now = Espnow.initialize()
16
+ return now.send(peer, msg)
16
17
 
17
18
  def start_server():
18
19
  """
@@ -20,21 +21,23 @@ def start_server():
20
21
  - this can receive espnow messages
21
22
  - it includes Load Module execution logic (beta)
22
23
  """
23
- return Espnow.espnow_server()
24
+ now = Espnow.initialize()
25
+ return now.start_server()
24
26
 
25
27
  def stats():
26
28
  """
27
29
  Get ESPNOW stats
28
30
  """
29
- return Espnow.stats()
31
+ now = Espnow.initialize()
32
+ return now.stats()
30
33
 
31
- def add_peer(peer):
34
+ def add_peer(peer:bytes, dev_name:str=None):
32
35
  """
33
36
  Add ESPNOW peer to known hosts
34
37
  - It is needed before first send(...)
35
38
  """
36
39
  now = Espnow.initialize()
37
- return Espnow.add_peer(now, peer)
40
+ return now.add_peer(peer, dev_name)
38
41
 
39
42
  def mac_address():
40
43
  """
@@ -46,4 +49,4 @@ def help():
46
49
  """
47
50
  [beta] ESPNOW sender/receiver with LM execution
48
51
  """
49
- return 'load', 'send <peer> "ping"', 'start_server', 'add_peer <peer>', 'stats', 'mac_address'
52
+ return 'load', 'send <peer> "ping"', 'start_server', 'add_peer <peer> dev_name=None', 'stats', 'mac_address'
@@ -0,0 +1,211 @@
1
+ # async_message.py Test of asynchronous mqtt client with async Broker class
2
+ # (C) Copyright Peter Hinch 2024.
3
+ # Released under the MIT licence.
4
+ # Public brokers https://github.com/mqtt/mqtt.github.io/wiki/public_brokers
5
+ # mip command: ???
6
+
7
+ from Config import cfgget
8
+ from mqtt_as import MQTTClient, config
9
+ from Common import micro_task, console, syslog, exec_cmd
10
+
11
+
12
+ # Set up MQTT
13
+ class MQTT:
14
+ CLIENT:MQTTClient = None # MQTT Client (broker) instance
15
+ TOPIC = "micros" # Default topic
16
+ TOPIC_COMMAND_LUT = {} # Lookup table for command/topic pairs
17
+ # Example:
18
+ # {"topic1": ["mod func", "mod2 func"], "topic2": []}
19
+
20
+
21
+ async def _receiver(task):
22
+ """
23
+ MQTT AS receiver loop
24
+ """
25
+ async for topic, msg, retained in MQTT.CLIENT.queue:
26
+ topic, msg = topic.decode(), msg.decode()
27
+ console(f'Topic: "{topic}" Message: "{msg}" Retained: {retained}')
28
+
29
+ # Command execution... use MQTT.TOPIC_COMMAND_LUT
30
+ topic_commands:list = MQTT.TOPIC_COMMAND_LUT.get(topic, None)
31
+ output_struct:list = []
32
+ if topic_commands is None:
33
+ syslog(f"[WARN] mqtt Unknown topic: {topic}")
34
+ elif len(topic_commands) == 0:
35
+ syslog(f"[WARN] mqtt No commands for {topic}")
36
+ else:
37
+ task.out = f"Handle topic: {topic}"
38
+ for cmd in topic_commands:
39
+ single_command = cmd.split()
40
+ if len(single_command) > 0:
41
+ state, output = exec_cmd(single_command, jsonify=True, skip_check=True)
42
+ output_struct.append({"state": state, "result": output, "cmd": cmd})
43
+ if len(output_struct) > 0:
44
+ console(f'\tMQTT Publish: {output_struct}')
45
+ task.out = f"Publish {topic}"
46
+ MQTT.CLIENT.publish(topic, str(output_struct))
47
+ else:
48
+ task.out = f"Nothing to publish {topic}"
49
+ task.feed()
50
+
51
+
52
+ async def _subscribe():
53
+ """
54
+ MQTT AS Topic subscribe towards server
55
+ """
56
+ with micro_task(tag="mqtt.subscribe") as my_task:
57
+ my_task.out = "Started"
58
+ try:
59
+ for t in MQTT.TOPIC_COMMAND_LUT:
60
+ console(f"Subscribe topic: {t}")
61
+ await MQTT.CLIENT.subscribe(t, 1)
62
+ my_task.out = "Done"
63
+ except Exception as e:
64
+ my_task.out = f"Error: {e}"
65
+
66
+
67
+ async def _publish(message, topic):
68
+ """
69
+ Send message to topic with mqtt
70
+ """
71
+ tag = f"mqtt.publish.{topic}"
72
+ with micro_task(tag=tag) as my_task:
73
+ console(f"mqtt send: [{topic}] {message}")
74
+ await MQTT.CLIENT.publish(topic, message, qos=1)
75
+ my_task.out = "Sent"
76
+
77
+
78
+ async def _up():
79
+ """
80
+ UP Listener - resubscribe
81
+ """
82
+ with micro_task(tag="mqtt.up") as my_task:
83
+ while True:
84
+ # Wait for UP Event - (re)subscribe
85
+ my_task.out = "Wait"
86
+ await MQTT.CLIENT.up.wait()
87
+ MQTT.CLIENT.up.clear()
88
+ micro_task(tag="mqtt.subscribe", task=_subscribe())
89
+ my_task.out = "Re-Subscription"
90
+ my_task.feed()
91
+
92
+
93
+ async def _init_client(topic:str=None, commands:str=None, raw_dict:dict|None=None):
94
+ """
95
+ Initialize main mqtt receiver and topics
96
+ :param topic: topic string, ex.: 'lights'
97
+ :param commands: semicolon separated commands. ex.: 'rgb toggle; cct toggle'
98
+ OR
99
+ :param raw_dict: python dict string for multi topic subscription, ex.: {"lights": ["rgb toggle", "cct toggle"], ...}
100
+ """
101
+ with micro_task(tag="mqtt.client") as my_task:
102
+ try:
103
+ await MQTT.CLIENT.connect()
104
+ my_task.out = "Connection successful."
105
+ except OSError:
106
+ my_task.out = "Connection failed."
107
+ return
108
+ # Wait for mqtt client connected successfully
109
+ await MQTT.CLIENT.up.wait()
110
+ MQTT.CLIENT.up.clear()
111
+ # Initialize mqtt topics, ha
112
+ subscribe(topic, commands, raw_dict)
113
+ micro_task(tag="mqtt.up", task=_up())
114
+ # Async listener loop
115
+ await _receiver(my_task)
116
+ my_task.out = "Receiver closed"
117
+ # Close when listener exits
118
+ MQTT.CLIENT.close()
119
+
120
+ #########################################
121
+ # PUBLIC FUNCTIONS #
122
+ #########################################
123
+
124
+ def publish(message:str, topic:str=MQTT.TOPIC):
125
+ """
126
+ Publish message
127
+ :param message: string to be sent
128
+ :param topic: topic for message
129
+ """
130
+ state = micro_task(tag=f"mqtt.publish.{topic}", task=_publish(message, topic))
131
+ state = "starting" if state else "already running"
132
+ return f"Message send, {state}"
133
+
134
+
135
+ def subscribe(topic:str=None, commands:str=None, raw_dict:dict|None=None):
136
+ """
137
+ Subscribe for single topics and set callback function(s) aka command(s)
138
+ :param topic: topic string, ex.: 'lights'
139
+ :param commands: semicolon separated commands. ex.: 'rgb toggle; cct toggle'
140
+ OR
141
+ :param raw_dict: python dict string for multi topic subscription, ex.: {"lights": ["rgb toggle", "cct toggle"], ...}
142
+
143
+ return: all or selected topics command
144
+ """
145
+ updated = False
146
+ topic = topic.strip()
147
+ # Register single topic
148
+ if topic and commands:
149
+ # raw commands structure: 'rgb toggle; cct toggle'
150
+ commands = [ c.strip() for c in commands.split(";") ]
151
+ # commands: Topic LUT structure: {'topic': ['mod func'], ..., 'lights': ['rgb toggle', 'cct toggle']}
152
+ updated = True if MQTT.TOPIC_COMMAND_LUT.get(topic, None) is None else False
153
+ MQTT.TOPIC_COMMAND_LUT[topic] = commands
154
+ # Register multiple topics at once
155
+ elif isinstance(raw_dict, dict):
156
+ updated = True
157
+ MQTT.TOPIC_COMMAND_LUT.update(raw_dict)
158
+ # Start subscribe task
159
+ if updated:
160
+ state = micro_task(tag="mqtt.subscribe", task=_subscribe())
161
+ state = "starting" if state else "already running"
162
+ return f"Subscribe, {state}"
163
+
164
+ # Return handling
165
+ if topic is not None:
166
+ # Return selected topic commands
167
+ return MQTT.TOPIC_COMMAND_LUT.get(topic, None)
168
+ # Return registered topics
169
+ return MQTT.TOPIC_COMMAND_LUT
170
+
171
+
172
+ def _configure(server_ip:str, username:str, password:str):
173
+ # Define configuration
174
+ config["keepalive"] = 120
175
+ config["queue_len"] = 1 # Use event interface with default queue
176
+ # Define configuration
177
+ config['client_id'] = cfgget("devfid")
178
+ config['ssid'] = cfgget("staessid")
179
+ config['wifi_pw'] = cfgget("stapwd")
180
+ config['port'] = 1883 # expose????
181
+ config['server'] = server_ip # '172.20.10.2'
182
+ config['user'] = username # test
183
+ config['password'] = password # '12345'
184
+ return config
185
+
186
+
187
+ def load(server_ip:str, username:str, password:str, topic:str=None, commands:str=None, raw_dict:dict|None=None):
188
+ """
189
+ Load MQTT_AS receiver...
190
+ :param server_ip: server IP address
191
+ :param username: server user
192
+ :param password: server user password
193
+
194
+ :param topic: topic string, ex.: 'lights'
195
+ :param commands: semicolon separated commands. ex.: 'rgb toggle; cct toggle'
196
+ OR
197
+ :param raw_dict: python dict string for multi topic subscription, ex.: {"lights": ["rgb toggle", "cct toggle"], ...}
198
+ """
199
+ MQTTClient.DEBUG = True
200
+ MQTT.CLIENT = MQTTClient(_configure(server_ip, username, password))
201
+
202
+ state = micro_task(tag="mqtt.client", task=_init_client(topic, commands, raw_dict))
203
+ return "Starting" if state else "Already running"
204
+
205
+
206
+ def help():
207
+ return ("load <server_ip> <username> <password> topic='micros', commands='rgb toggle; cct toggle'",
208
+ "subscribe topic='micros', commands='rgb toggle; cct toggle'",
209
+ "subscribe #without params dumps the topic-command data structure",
210
+ "publish message='hello' topic='micros'",
211
+ "HINT: task show mqtt.*")
@@ -15,6 +15,7 @@ try:
15
15
  except:
16
16
  gol_nextgen = None # Optional function handling
17
17
 
18
+ from utime import ticks_ms, ticks_diff # For IRQ joystick handling
18
19
 
19
20
  #################################
20
21
  # PAGE MANAGER CLASS DEFINITION #
@@ -157,11 +158,23 @@ class PageUI:
157
158
  # [IRQ] - event type setup
158
159
  pin_obj.irq(trigger=Pin.IRQ_FALLING, handler=callback)
159
160
 
160
- _set("js_right", lambda pin: self.control('next'))
161
- _set("js_left", lambda pin: self.control('prev'))
162
- _set("js_up", lambda pin: self.control('on'))
163
- _set("js_down", lambda pin: self.control('off'))
164
- _set("js_press", lambda pin: self.control('press'))
161
+ def _event_handler(control_command, prell_ms=150):
162
+ nonlocal _p_last
163
+ _last = _p_last.get(control_command)
164
+ last = 0 if _last is None else _last
165
+ # Calculate time difference between last trigger action and now tick.
166
+ diff = ticks_diff(ticks_ms(), last)
167
+ if abs(diff) > prell_ms:
168
+ # Save now tick - last trigger action
169
+ _p_last[control_command] = ticks_ms()
170
+ self.control(control_command)
171
+
172
+ _p_last = {}
173
+ _set("js_right", lambda pin: _event_handler('next'))
174
+ _set("js_left", lambda pin: _event_handler('prev'))
175
+ _set("js_up", lambda pin: _event_handler('on'))
176
+ _set("js_down", lambda pin: _event_handler('off'))
177
+ _set("js_press", lambda pin: _event_handler('press'))
165
178
  self.irq_ok = True
166
179
 
167
180
  def __power_save(self):
@@ -1,73 +1,56 @@
1
- from uos import listdir, remove, stat
2
1
  from sys import modules
3
2
  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, '?'
3
+ from Files import _is_module, list_fs, ilist_fs, remove_fs
15
4
 
16
5
 
17
6
  #############################################
18
7
  # Safe file system handler functions #
19
8
  #############################################
20
9
 
21
- def ls(path="/", content='*', raw=False):
10
+ def ls(path="/", content='*', raw=False, select='*'):
22
11
  """
23
12
  Linux like ls command - list app resources and app folders
24
13
  :param path: path to list, default: /
25
14
  :param content: content type, default all, f-file, d-dir can be selected
26
15
  :param raw: keep raw output [(is_app, type), ...]
16
+ :param select: select specific app resource: LM or IO, default: all
27
17
  """
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))
18
+ items = list_fs(path, content, select=select)
34
19
  if raw:
35
20
  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
21
+
22
+ # Build a formatted output (just like `ls -l` style index)
23
+ lines = ""
24
+ for i, f in enumerate(items):
25
+ spacer = " " * (4 - len(str(i+1)))
26
+ if content == "*":
27
+ lines += f"{i+1}{spacer}{f[0]} {f[1]}\n"
28
+ else:
29
+ lines += f"{i + 1}{spacer}{f}\n"
30
+ return lines
43
31
 
44
32
 
45
- def rm(path):
33
+ def rm(path, allow_dir=False):
46
34
  """
47
35
  Linux like rm command - delete app resources and folders
48
36
  :param path: app resource name/path, ex.: LM_robustness.py
37
+ :param allow_dir: enable directory deletion, default: False
49
38
  """
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}"
39
+ return remove_fs(path, allow_dir)
57
40
 
58
41
 
59
42
  def dirtree(path="/", raw=False):
60
43
  """Return only directories from a given path."""
61
44
  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}
45
+ folders = [f"{path}/{item}" for item in ilist_fs(path, type_filter='d')]
46
+ folder_contents = {folder:list_fs(folder) for folder in folders}
64
47
  if raw:
65
48
  return folder_contents
66
49
  formatted_output = ""
67
50
  for k, v in folder_contents.items():
68
51
  formatted_output += f"{k}\n"
69
52
  for val in v:
70
- formatted_output += f"\t{val}\n"
53
+ formatted_output += f"\t{val[0]} {val[1]}\n"
71
54
  return formatted_output
72
55
 
73
56
 
@@ -108,18 +91,20 @@ def del_duplicates():
108
91
  - delete duplicated .mpy and .py resources, keep .mpy resource!
109
92
  """
110
93
  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'))
94
+ files = list_fs(type_filter='f', select='LM')
95
+ py = list((res.split('.')[0] for res in files if res.endswith('.py'))) # Normally smaller list
96
+ mpy = (res.split('.')[0] for res in files if res.endswith('.mpy'))
113
97
  for m in mpy:
114
98
  # Iterate over mpy resources
115
99
  state = True
116
100
  if m in py and m != 'main':
117
101
  to_delete = f'{m}.py'
118
102
  try:
119
- remove(to_delete)
103
+ verdict = remove_fs(to_delete)
120
104
  except:
105
+ verdict = "n/a"
121
106
  state = False
122
- msg_buf.append(f' Delete {to_delete} {state}')
107
+ msg_buf.append(f' Delete {to_delete} {state} - {verdict}')
123
108
  return '\n'.join(msg_buf) if len(msg_buf) > 0 else 'Nothing to delete.'
124
109
 
125
110
 
@@ -147,7 +132,7 @@ def cachedump(delpds=None, msgobj=None):
147
132
  if delpds is None:
148
133
  # List pds files aka application cache
149
134
  msg_buf = []
150
- for pds in (_pds for _pds in listdir() if _pds.endswith('.pds')):
135
+ for pds in (_pds for _pds in ilist_fs(type_filter='f') if _pds.endswith('.pds')):
151
136
  with open(pds, 'r') as f:
152
137
  if msgobj is None:
153
138
  msg_buf.append(f'{pds}: {f.read()}')
@@ -156,8 +141,8 @@ def cachedump(delpds=None, msgobj=None):
156
141
  return msg_buf if len(msg_buf) > 0 else ''
157
142
  # Remove given pds file
158
143
  try:
159
- remove(f'{delpds}.pds')
160
- return f'{delpds}.pds delete done.'
144
+ verdict = remove_fs(f'{delpds}.pds')
145
+ return f'{delpds}.pds delete done.: {verdict}'
161
146
  except:
162
147
  return f'{delpds}.pds not exists'
163
148
 
@@ -168,7 +153,7 @@ def dat_dump():
168
153
  - logged data from LMs, sensor datat, etc...
169
154
  """
170
155
  logs_dir = "/logs/"
171
- dats = (f for f in listdir(logs_dir) if f.endswith('.dat'))
156
+ dats = (f for f in ilist_fs(type_filter='f') if f.endswith('.dat'))
172
157
  out = {}
173
158
  for dat in dats:
174
159
  with open(f"{logs_dir}{dat}", 'r') as f:
@@ -188,8 +173,7 @@ def listmods(msgobj=None):
188
173
  """
189
174
  # Dump available LMs
190
175
  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):
176
+ for k in (res.replace('LM_', '') for res in ilist_fs(type_filter='f', select='LM')):
193
177
  if msgobj is None:
194
178
  msg_buf.append(f' {k}')
195
179
  else:
@@ -197,21 +181,17 @@ def listmods(msgobj=None):
197
181
  return msg_buf if len(msg_buf) > 0 else ''
198
182
 
199
183
 
200
- def delmod(mod=None):
184
+ def delmod(mod):
201
185
  """
202
186
  Module package manager
203
187
  :param mod:
204
188
  Delete Load Module with full name: module.py or module.mpy
205
189
  OR delete any web resource: *.js, *.css, *.html
206
190
  """
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.'
191
+ if mod.endswith('py') or _is_module(mod):
211
192
  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}'
193
+ to_remove = f'LM_{mod}' if mod.endswith('py') else mod
194
+ return remove_fs(to_remove)
215
195
  except Exception as e:
216
196
  return f'Cannot delete: {mod}: {e}'
217
197
  return f'Invalid value: {mod}'
@@ -223,7 +203,7 @@ def micros_checksum(msgobj=None):
223
203
  from binascii import hexlify
224
204
  from Config import cfgget
225
205
 
226
- for f_name in (_pds for _pds in listdir() if _pds.endswith('py')):
206
+ for f_name in ilist_fs(type_filter='f', select='LM'):
227
207
  with open(f_name, 'rb') as f:
228
208
  cs = hexlify(sha1(f.read()).digest()).decode('utf-8')
229
209
  msgobj(f"{cs} {f_name}")
@@ -244,5 +224,5 @@ def help(widgets=False):
244
224
  'dat_dump',
245
225
  'download url="BxNxM/micrOS/master/toolkit/workspace/precompiled/LM_robustness.py"',
246
226
  'micros_checksum',
247
- 'ls path="/" content="*/f/d"',
227
+ 'ls path="/" content="*/f/d" select="*/LM/IO"',
248
228
  'rm <path>', 'dirtree path="/"')
micrOS/source/LM_rest.py CHANGED
@@ -10,7 +10,7 @@ class Rest:
10
10
  def load(gateway_url=None):
11
11
  """
12
12
  Set gateway url aka main domain
13
- :param gateway_url: base url of gateway, like: http://gateway.local:5000
13
+ :param gateway_url: base url of gateway, like: http://gateway.local:5005
14
14
  """
15
15
  if gateway_url is None:
16
16
  if Rest.GATEWAY_HOST is None:
@@ -77,6 +77,6 @@ def help(widgets=False):
77
77
  (widgets=False) list of functions implemented by this application
78
78
  (widgets=True) list of widget json for UI generation
79
79
  """
80
- return ('load gateway_url=<http://gateway.local:5000>',
80
+ return ('load gateway_url=<http://gateway.local:5005>',
81
81
  'url subdomain=</webhooks/template>',
82
- 'aurl subdomain=</webhooks/template>')
82
+ 'aurl subdomain=</webhooks/template>')
@@ -1,4 +1,4 @@
1
- from uos import statvfs, getcwd, listdir, uname
1
+ from uos import statvfs, getcwd, uname
2
2
  from utime import localtime
3
3
  from network import WLAN, STA_IF, AP_IF
4
4
  from binascii import hexlify
micrOS/source/Logger.py CHANGED
@@ -6,7 +6,8 @@ Designed by Marcell Ban aka BxNxM
6
6
  """
7
7
  from time import localtime
8
8
  from re import match
9
- from uos import listdir, remove, stat, mkdir, getcwd
9
+ from uos import remove, mkdir, getcwd
10
+ from Files import ilist_fs, is_dir
10
11
 
11
12
  #############################################
12
13
  # LOGGING WITH DATA ROTATION #
@@ -18,14 +19,7 @@ def _init_logger():
18
19
  global LOG_FOLDER
19
20
  if LOG_FOLDER is None:
20
21
  LOG_FOLDER = f"{getcwd()}logs"
21
- do_create = True
22
- try:
23
- if stat(LOG_FOLDER)[0] & 0x4000:
24
- # Dir exists - skip create
25
- do_create = False
26
- except:
27
- pass
28
- if do_create:
22
+ if not is_dir(LOG_FOLDER):
29
23
  try:
30
24
  mkdir(LOG_FOLDER)
31
25
  syslog(f"[BOOT] log dir {LOG_FOLDER} init")
@@ -107,7 +101,7 @@ def log_get(f_name, msgobj=None):
107
101
 
108
102
  def syslog(data=None, msgobj=None):
109
103
  if data is None:
110
- err_cnt = sum([log_get(f, msgobj) for f in listdir(LOG_FOLDER) if f.endswith(".sys.log")])
104
+ err_cnt = sum([log_get(f, msgobj) for f in ilist_fs(LOG_FOLDER, type_filter='f') if f.endswith(".sys.log")])
111
105
  return err_cnt
112
106
 
113
107
  _match = match(r"^\[([^\[\]]+)\]", data)
@@ -117,7 +111,7 @@ def syslog(data=None, msgobj=None):
117
111
 
118
112
 
119
113
  def log_clean(msgobj=None):
120
- to_del = [file for file in listdir(LOG_FOLDER) if file.endswith('.log')]
114
+ to_del = [file for file in ilist_fs(LOG_FOLDER, type_filter='f') if file.endswith('.log')]
121
115
  for _del in to_del:
122
116
  _del = f"{LOG_FOLDER}/{_del}"
123
117
  if msgobj is not None: