micrOSDevToolKit 2.9.11__py3-none-any.whl → 2.10.5__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 (54) hide show
  1. micrOS/release_info/micrOS_ReleaseInfo/system_analysis_sum.json +37 -29
  2. micrOS/source/Common.py +5 -5
  3. micrOS/source/Espnow.py +245 -123
  4. micrOS/source/Files.py +101 -0
  5. micrOS/source/InterConnect.py +14 -11
  6. micrOS/source/LM_espnow.py +10 -7
  7. micrOS/source/LM_intercon.py +3 -0
  8. micrOS/source/LM_light_sensor.py +7 -15
  9. micrOS/source/LM_mqtt_pro.py +211 -0
  10. micrOS/source/LM_oled_ui.py +18 -22
  11. micrOS/source/LM_oledui.py +13 -16
  12. micrOS/source/LM_pacman.py +37 -57
  13. micrOS/source/LM_presence.py +8 -11
  14. micrOS/source/LM_system.py +8 -7
  15. micrOS/source/LM_telegram.py +21 -16
  16. micrOS/source/Logger.py +5 -11
  17. micrOS/source/Shell.py +37 -30
  18. micrOS/source/Tasks.py +32 -17
  19. micrOS/source/Web.py +3 -2
  20. micrOS/source/__pycache__/Common.cpython-312.pyc +0 -0
  21. micrOS/source/__pycache__/Logger.cpython-312.pyc +0 -0
  22. micrOS/source/microIO.py +3 -2
  23. micrOS/source/urequests.py +10 -1
  24. {micrOSDevToolKit-2.9.11.dist-info → microsdevtoolkit-2.10.5.dist-info}/METADATA +13 -15
  25. {micrOSDevToolKit-2.9.11.dist-info → microsdevtoolkit-2.10.5.dist-info}/RECORD +54 -50
  26. {micrOSDevToolKit-2.9.11.dist-info → microsdevtoolkit-2.10.5.dist-info}/WHEEL +1 -1
  27. toolkit/dashboard_apps/SystemTest.py +17 -6
  28. toolkit/lib/micrOSClient.py +25 -6
  29. toolkit/simulator_lib/__pycache__/uos.cpython-312.pyc +0 -0
  30. toolkit/simulator_lib/uos.py +5 -5
  31. toolkit/socketClient.py +2 -3
  32. toolkit/workspace/precompiled/Common.mpy +0 -0
  33. toolkit/workspace/precompiled/Espnow.mpy +0 -0
  34. toolkit/workspace/precompiled/Files.mpy +0 -0
  35. toolkit/workspace/precompiled/InterConnect.mpy +0 -0
  36. toolkit/workspace/precompiled/LM_espnow.py +10 -7
  37. toolkit/workspace/precompiled/LM_intercon.mpy +0 -0
  38. toolkit/workspace/precompiled/LM_light_sensor.mpy +0 -0
  39. toolkit/workspace/precompiled/LM_mqtt_pro.py +211 -0
  40. toolkit/workspace/precompiled/LM_oled_ui.mpy +0 -0
  41. toolkit/workspace/precompiled/LM_oledui.mpy +0 -0
  42. toolkit/workspace/precompiled/LM_pacman.mpy +0 -0
  43. toolkit/workspace/precompiled/LM_presence.mpy +0 -0
  44. toolkit/workspace/precompiled/LM_system.mpy +0 -0
  45. toolkit/workspace/precompiled/LM_telegram.mpy +0 -0
  46. toolkit/workspace/precompiled/Logger.mpy +0 -0
  47. toolkit/workspace/precompiled/Shell.mpy +0 -0
  48. toolkit/workspace/precompiled/Tasks.mpy +0 -0
  49. toolkit/workspace/precompiled/Web.mpy +0 -0
  50. toolkit/workspace/precompiled/microIO.mpy +0 -0
  51. toolkit/workspace/precompiled/urequests.mpy +0 -0
  52. {micrOSDevToolKit-2.9.11.data → microsdevtoolkit-2.10.5.data}/scripts/devToolKit.py +0 -0
  53. {micrOSDevToolKit-2.9.11.dist-info → microsdevtoolkit-2.10.5.dist-info/licenses}/LICENSE +0 -0
  54. {micrOSDevToolKit-2.9.11.dist-info → microsdevtoolkit-2.10.5.dist-info}/top_level.txt +0 -0
@@ -4,13 +4,8 @@ from Types import resolve
4
4
  # Core modules
5
5
  from Config import cfgget
6
6
  from Time import uptime
7
-
8
7
  # Load Modules
9
- from LM_system import top, memory_usage, ifconfig, rssi as sta_rssi, list_stations
10
- try:
11
- import LM_intercon as InterCon
12
- except:
13
- InterCon = None # Optional function handling
8
+ from LM_system import top, memory_usage, ifconfig, rssi as sta_rssi, list_stations, hosts
14
9
  try:
15
10
  from LM_esp32 import temp as cpu_temp
16
11
  except Exception as e:
@@ -785,10 +780,13 @@ class PageUI:
785
780
  # Check open host connection
786
781
  try:
787
782
  # Send CMD to other device & show result
788
- data_meta = InterCon.send_cmd(host, cmd)
789
- self._cmd_task_tag = data_meta['tag']
790
- if "Task is Busy" in data_meta['verdict'] and not run:
791
- self.app_frame.press_output = data_meta['verdict'] # Otherwise the task start output not relevant on UI
783
+ state, data_meta = exec_cmd(cmd + [f">>{host}"], jsonify=True, skip_check=True)
784
+ if state:
785
+ self._cmd_task_tag = data_meta['tag']
786
+ if "Task is Busy" in data_meta['verdict'] and not run:
787
+ self.app_frame.press_output = data_meta['verdict'] # Otherwise the task start output not relevant on UI
788
+ else:
789
+ self.app_frame.press_output = f"Error: {data_meta}"
792
790
  except Exception as e:
793
791
  self.app_frame.press_output = str(e)
794
792
 
@@ -803,7 +801,7 @@ class PageUI:
803
801
  self._cmd_task_tag = None
804
802
  PageUI.write_lines(self.app_frame.press_output, display, x, y + 20, line_limit=2)
805
803
 
806
- PageUI.write_lines(f"{host.split(".")[0]}:{cmd}", display, x, y, line_limit=2)
804
+ PageUI.write_lines(f"{host.split(".")[0]}:{' '.join(cmd)}", display, x, y, line_limit=2)
807
805
  if run:
808
806
  if self._cmd_task_tag is None:
809
807
  _execute(display, w, h, x, y)
@@ -829,14 +827,13 @@ def _system_page(display, w, h, x, y):
829
827
  return True
830
828
 
831
829
  def _intercon_nodes_page(display, w, h, x, y):
832
- if InterCon is None:
833
- return False
834
830
  line_limit = 3
835
831
  line_start = y+5
836
832
  line_cnt = 1
837
833
  display.text("InterCon cache", x, line_start)
838
- if sum([1 for _ in InterCon.host_cache()]) > 0:
839
- for key, val in InterCon.host_cache().items():
834
+ cache = hosts()["intercon"]
835
+ if sum([1 for _ in cache]) > 0:
836
+ for key, val in cache.items():
840
837
  key = key.split('.')[0]
841
838
  val = '.'.join(val.split('.')[-2:])
842
839
  display.text(f" {val} {key}", x, line_start + (line_cnt * 10))
@@ -934,7 +931,7 @@ def intercon_genpage(cmd=None, run=False):
934
931
  """
935
932
  raw = cmd.split()
936
933
  host = raw[0]
937
- cmd = ' '.join(raw[1:])
934
+ cmd = raw[1:]
938
935
  try:
939
936
  # Create page for intercon command
940
937
  PageUI.INSTANCE.add_page(lambda display, w, h, x, y: PageUI.INSTANCE.intercon_exec_page(host, cmd, run, display, w, h, x, y))
@@ -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="/"')
@@ -1,10 +1,7 @@
1
1
  from microIO import bind_pin, pinmap_search
2
- from Common import SmartADC, micro_task, notify, syslog
2
+ from Common import SmartADC, micro_task, notify, syslog, exec_cmd
3
3
  from utime import ticks_ms
4
- try:
5
- import LM_intercon as InterCon
6
- except:
7
- InterCon = None
4
+
8
5
 
9
6
  class Data:
10
7
  TASK_TAG = 'presence._capture'
@@ -68,9 +65,9 @@ def __run_intercon(state):
68
65
  try:
69
66
  cmd = Data.ON_INTERCON_CLBK.split()
70
67
  host = cmd[0]
71
- cmd = ' '.join(cmd[1:])
72
- # Send CMD to other device & show result
73
- InterCon.send_cmd(host, cmd)
68
+ cmd = cmd[1:]
69
+ # Send CMD to other device
70
+ state, _ = exec_cmd(cmd + [f">>{host}"], jsonify=True, skip_check=True)
74
71
  except Exception as e:
75
72
  syslog(f"__run_intercon error: {e}")
76
73
  if state.lower() == "off":
@@ -79,9 +76,9 @@ def __run_intercon(state):
79
76
  try:
80
77
  cmd = Data.OFF_INTERCON_CLBK.split()
81
78
  host = cmd[0]
82
- cmd = ' '.join(cmd[1:])
83
- # Send CMD to other device & show result
84
- InterCon.send_cmd(host, cmd)
79
+ cmd = cmd[1:]
80
+ # Send CMD to other device
81
+ state, _ = exec_cmd(cmd + [f">>{host}"], jsonify=True, skip_check=True)
85
82
  except Exception as e:
86
83
  syslog(f"__run_intercon error: {e}")
87
84
 
@@ -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
@@ -212,14 +212,15 @@ def ifconfig():
212
212
  return network_config()
213
213
 
214
214
 
215
- def urequest_hosts():
215
+ def hosts():
216
216
  """
217
- Debug function for urequests address caching
218
- - returns all known http(s) host addresses
219
- - cache only in memory
217
+ Dump cached hosts
218
+ - urequests (only memory cache)
219
+ - intercon connection cache
220
220
  """
221
221
  from urequests import host_cache
222
- return host_cache()
222
+ from InterConnect import host_cache as ihost_cache
223
+ return {"urequests": host_cache(), "intercon": ihost_cache()}
223
224
 
224
225
 
225
226
  def notifications(enable=None):
@@ -246,4 +247,4 @@ def help(widgets=False):
246
247
  'ntp', 'rssi', 'list_stations', 'pinmap key="dhtpin"/None', 'alarms clean=False',
247
248
  'notifications enable=<None,True,False>',
248
249
  'sun refresh=False', 'ifconfig', 'memory_usage',
249
- 'disk_usage', 'urequest_hosts'), widgets=widgets)
250
+ 'disk_usage', 'hosts'), widgets=widgets)
@@ -4,6 +4,11 @@ from Notify import Notify
4
4
  from Config import cfgget
5
5
  from Common import micro_task, syslog, console_write
6
6
  from LM_system import ifconfig
7
+ from utime import localtime
8
+
9
+ def _timestamp():
10
+ _time = [str(k) for k in localtime()[3:6]]
11
+ return ':'.join(_time)
7
12
 
8
13
 
9
14
  class Telegram(Notify):
@@ -106,12 +111,12 @@ class Telegram(Notify):
106
111
  Update known chat_id-s and cache them
107
112
  - return active chat_id frm resp_json
108
113
  """
109
- console_write("[NTFY GET] update chatIDs")
110
114
  _cid = None
111
115
  if resp_json.get("ok", None) and len(resp_json["result"]) > 0:
112
116
  _cid = resp_json["result"][-1]["message"]["chat"]["id"]
113
117
  # LIMIT Telegram._CHAT_IDS NOTIFICATION CACHE TO 3 IDs
114
- if len(Telegram._CHAT_IDS) < 4:
118
+ if len(Telegram._CHAT_IDS) < 4 and _cid not in Telegram._CHAT_IDS:
119
+ console_write("[NTFY GET] update chatIDs")
115
120
  _ids = len(Telegram._CHAT_IDS)
116
121
  Telegram._CHAT_IDS.add(_cid)
117
122
  if len(Telegram._CHAT_IDS) - _ids > 0: # optimized save (slow storage access)
@@ -135,7 +140,7 @@ class Telegram(Notify):
135
140
  return None
136
141
  response = {'sender': None, 'text': None, 'm_id': -1, 'c_id': None}
137
142
  url = f"https://api.telegram.org/bot{bot_token}/getUpdates{Telegram._API_PARAMS}"
138
- console_write(f"\t1/2[GET] request: {url}")
143
+ console_write(f"\t[GET] request: {url}")
139
144
 
140
145
  _, resp_json = urequests.get(url, jsonify=True, sock_size=128)
141
146
 
@@ -145,7 +150,7 @@ class Telegram(Notify):
145
150
  response['sender'] = f"{resp['chat']['first_name']}{resp['chat']['last_name']}" if resp['chat'].get(
146
151
  'username', None) is None else resp['chat']['username']
147
152
  response['text'], response['m_id'] = resp['text'], resp['message_id']
148
- console_write(f"\t2/2[GET] response: {response}")
153
+ console_write(f"\t\t[GET] response: {response}")
149
154
  return response
150
155
 
151
156
  @staticmethod
@@ -160,7 +165,7 @@ class Telegram(Notify):
160
165
  return None
161
166
  response = {'sender': None, 'text': None, 'm_id': -1, 'c_id': None}
162
167
  url = f"https://api.telegram.org/bot{bot_token}/getUpdates{Telegram._API_PARAMS}"
163
- console_write(f"\t1/2[GET] request: {url}")
168
+ console_write(f"\t[aGET] request: {url}")
164
169
 
165
170
  _, resp_json = await urequests.aget(url, jsonify=True, sock_size=128)
166
171
 
@@ -170,7 +175,7 @@ class Telegram(Notify):
170
175
  response['sender'] = f"{resp['chat']['first_name']}{resp['chat']['last_name']}" if resp['chat'].get(
171
176
  'username', None) is None else resp['chat']['username']
172
177
  response['text'], response['m_id'] = resp['text'], resp['message_id']
173
- console_write(f"\t2/2[GET] response: {response}")
178
+ console_write(f"\t\t[aGET] response: {response}")
174
179
  return response
175
180
 
176
181
  @staticmethod
@@ -183,14 +188,14 @@ class Telegram(Notify):
183
188
  console_write("[NTFY] EVAL sequence")
184
189
  verdict = None
185
190
 
186
- def lm_execute(cmd_args):
191
+ def _lm_execute(cmd_args):
187
192
  nonlocal verdict, m_id
188
193
  access, output = Telegram.lm_execute(cmd_args)
189
194
  if access:
190
- verdict = f'[UP] Exec: {" ".join(cmd_args[0])}'
195
+ verdict = f'{_timestamp()} [UP] Exec: {" ".join(cmd_args[0])}'
191
196
  Telegram.send_msg(output, reply_to=m_id)
192
197
  else:
193
- verdict = f'[UP] NoAccess: {cmd_args[0]}'
198
+ verdict = f'{_timestamp()} [UP] NoAccess: {cmd_args[0]}'
194
199
  Telegram._IN_MSG_ID = m_id
195
200
 
196
201
  # -------------------------- FUNCTION MAIN -------------------------- #
@@ -211,12 +216,12 @@ class Telegram(Notify):
211
216
  cmd_lm = msg_in.strip().split()[1:]
212
217
  # [Compare] cmd selected device param with DEVFID (device/prompt name)
213
218
  if cmd_lm[0] in Telegram._DEVFID:
214
- lm_execute(cmd_lm[1:])
219
+ _lm_execute(cmd_lm[1:])
215
220
  else:
216
- verdict = f'[UP] NoSelected: {cmd_lm[0]}'
221
+ verdict = f'{_timestamp()} [UP] NoSelected: {cmd_lm[0]}'
217
222
  elif msg_in.startswith('/cmd'):
218
223
  cmd_lm = msg_in.strip().split()[1:]
219
- lm_execute(cmd_lm)
224
+ _lm_execute(cmd_lm)
220
225
  elif msg_in.startswith('/notify'):
221
226
  param = msg_in.strip().split()[1:]
222
227
  if len(param) > 0:
@@ -226,8 +231,7 @@ class Telegram(Notify):
226
231
  # Send is still synchronous (OK)
227
232
  Telegram.send_msg(verdict, reply_to=m_id)
228
233
  else:
229
- verdict = "[UP] NoExec"
230
- console_write(f"\tBOT: {verdict}")
234
+ verdict = f"{_timestamp()} [UP] NoExec"
231
235
  return verdict
232
236
 
233
237
  @staticmethod
@@ -241,11 +245,12 @@ class Telegram(Notify):
241
245
  period = period if period > 0 else 1
242
246
  period_ms = period * 1000
243
247
  with micro_task(tag=tag) as my_task:
244
- my_task.out = "[UP] Running"
248
+ my_task.out = f"{_timestamp()} [UP] Running"
245
249
  while True:
246
250
  # Normal task period
247
251
  await my_task.feed(sleep_ms=period_ms)
248
252
  try:
253
+ # await asyncio.wait_for(Telegram.receive_eval(), 5) # 5 sec timeout???
249
254
  v = await Telegram.receive_eval()
250
255
  my_task.out = "Missing bot token" if v is None else f"{v} ({period}s)"
251
256
  cancel_cnt = 0
@@ -254,7 +259,7 @@ class Telegram(Notify):
254
259
  # Auto scale - blocking nature - in case of serial failures (5) - hibernate task (increase async sleep)
255
260
  cancel_cnt += 1
256
261
  if cancel_cnt > 5:
257
- my_task.out = f"[DOWN] {e} (wait 1min)"
262
+ my_task.out = f"{_timestamp()} [DOWN] {e} (wait 1min)"
258
263
  cancel_cnt = 5
259
264
  # SLOW DOWN - hibernate task
260
265
  await my_task.feed(sleep_ms=60_000)
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: