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.
- micrOS/release_info/micrOS_ReleaseInfo/system_analysis_sum.json +28 -20
- micrOS/source/Common.py +2 -2
- micrOS/source/Espnow.py +245 -123
- micrOS/source/Files.py +101 -0
- micrOS/source/LM_espnow.py +10 -7
- micrOS/source/LM_mqtt_pro.py +211 -0
- micrOS/source/LM_oled_ui.py +18 -5
- micrOS/source/LM_pacman.py +37 -57
- micrOS/source/LM_rest.py +3 -3
- micrOS/source/LM_system.py +1 -1
- micrOS/source/Logger.py +5 -11
- micrOS/source/Shell.py +33 -28
- micrOS/source/Tasks.py +2 -2
- micrOS/source/__pycache__/Common.cpython-312.pyc +0 -0
- micrOS/source/__pycache__/Logger.cpython-312.pyc +0 -0
- micrOS/source/microIO.py +3 -2
- micrOS/source/urequests.py +10 -1
- {micrOSDevToolKit-2.10.2.dist-info → microsdevtoolkit-2.10.6.dist-info}/METADATA +3 -2
- {micrOSDevToolKit-2.10.2.dist-info → microsdevtoolkit-2.10.6.dist-info}/RECORD +44 -40
- {micrOSDevToolKit-2.10.2.dist-info → microsdevtoolkit-2.10.6.dist-info}/WHEEL +1 -1
- toolkit/Gateway.py +3 -3
- toolkit/simulator_lib/__pycache__/machine.cpython-312.pyc +0 -0
- toolkit/simulator_lib/__pycache__/sim_console.cpython-312.pyc +0 -0
- toolkit/simulator_lib/__pycache__/uos.cpython-312.pyc +0 -0
- toolkit/simulator_lib/uos.py +5 -5
- toolkit/user_data/webhooks/generic.py +1 -1
- toolkit/user_data/webhooks/macro.py +1 -1
- toolkit/user_data/webhooks/template.py +1 -1
- toolkit/workspace/precompiled/Espnow.mpy +0 -0
- toolkit/workspace/precompiled/Files.mpy +0 -0
- toolkit/workspace/precompiled/LM_espnow.py +10 -7
- toolkit/workspace/precompiled/LM_mqtt_pro.py +211 -0
- toolkit/workspace/precompiled/LM_oled_ui.mpy +0 -0
- toolkit/workspace/precompiled/LM_pacman.mpy +0 -0
- toolkit/workspace/precompiled/LM_rest.mpy +0 -0
- toolkit/workspace/precompiled/LM_system.mpy +0 -0
- toolkit/workspace/precompiled/Logger.mpy +0 -0
- toolkit/workspace/precompiled/Shell.mpy +0 -0
- toolkit/workspace/precompiled/Tasks.mpy +0 -0
- toolkit/workspace/precompiled/microIO.mpy +0 -0
- toolkit/workspace/precompiled/urequests.mpy +0 -0
- {micrOSDevToolKit-2.10.2.data → microsdevtoolkit-2.10.6.data}/scripts/devToolKit.py +0 -0
- {micrOSDevToolKit-2.10.2.dist-info → microsdevtoolkit-2.10.6.dist-info/licenses}/LICENSE +0 -0
- {micrOSDevToolKit-2.10.2.dist-info → microsdevtoolkit-2.10.6.dist-info}/top_level.txt +0 -0
micrOS/source/LM_espnow.py
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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.*")
|
micrOS/source/LM_oled_ui.py
CHANGED
|
@@ -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
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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):
|
micrOS/source/LM_pacman.py
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
spacer = " " * (4 - len(str(i)))
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
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
|
|
63
|
-
folder_contents = {folder:
|
|
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
|
-
|
|
112
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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.
|
|
213
|
-
|
|
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 (
|
|
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:
|
|
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:
|
|
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>')
|
micrOS/source/LM_system.py
CHANGED
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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:
|