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
micrOS/source/Shell.py CHANGED
@@ -11,8 +11,8 @@ Designed by Marcell Ban aka BxNxM
11
11
  #################################################################
12
12
  # IMPORTS #
13
13
  #################################################################
14
- from os import listdir
15
14
  from sys import modules
15
+ from uos import listdir
16
16
  from machine import reset as hard_reset, soft_reset
17
17
  from Config import cfgget, cfgput
18
18
  from Tasks import lm_exec
@@ -25,7 +25,7 @@ from Debug import errlog_add
25
25
 
26
26
  class Shell:
27
27
  __slots__ = ['__devfid', '__auth_mode', '__hwuid', '__auth_ok', '__conf_mode']
28
- MICROS_VERSION = '2.9.1-0'
28
+ MICROS_VERSION = '2.9.6-0'
29
29
 
30
30
  def __init__(self):
31
31
  """
@@ -45,10 +45,8 @@ class Shell:
45
45
  except Exception as e:
46
46
  errlog_add(f"[ERR] micrOS version export failed (config): {e}")
47
47
 
48
- def send(self, msg):
49
- """
50
- Must be defined by child class...
51
- """
48
+ async def a_send(self, msg):
49
+ """ Must be defined by parent class... """
52
50
  pass
53
51
 
54
52
  def reset(self):
@@ -56,44 +54,43 @@ class Shell:
56
54
  self.__auth_ok = False
57
55
  self.__conf_mode = False
58
56
 
59
- def reboot(self, hard=False):
60
- """Reboot micropython VM"""
61
- self.send(f"{'[HARD] ' if hard else ''}Reboot micrOS system.")
62
- self.send("Bye!")
57
+ async def reboot(self, hard=False):
58
+ """ Reboot micropython VM """
59
+ await self.a_send(f"{'[HARD] ' if hard else ''}Reboot micrOS system.\nBye!")
63
60
  if hard:
64
61
  hard_reset()
65
62
  soft_reset()
66
63
 
67
64
  def prompt(self):
68
- """Generate prompt"""
65
+ """ Generate prompt """
69
66
  auth = "[password] " if self.__auth_mode and not self.__auth_ok else ""
70
67
  mode = "[configure] " if self.__conf_mode else ""
71
68
  return f"{auth}{mode}{self.__devfid} $ "
72
69
 
73
- def __auth(self, msg_list):
74
- """Authorize user"""
70
+ async def __auth(self, msg_list):
71
+ """ Authorize user """
75
72
  # Set user auth state
76
73
  if self.__auth_mode and not self.__auth_ok:
77
74
  # check password
78
75
  usrpwd = cfgget('appwd')
79
76
  if usrpwd == msg_list[0].strip():
80
77
  self.__auth_ok = True
81
- self.send("AuthOk")
78
+ await self.a_send("AuthOk")
82
79
  return True, []
83
- self.send("AuthFailed\nBye!")
80
+ await self.a_send("AuthFailed\nBye!")
84
81
  return False, []
85
82
  return True, msg_list
86
83
 
87
- def shell(self, msg):
84
+ async def shell(self, msg):
88
85
  """
89
86
  micrOS Shell main - input string handling
90
87
  :param msg: incoming shell command (command or load module call)
91
88
  """
92
- state = self.__shell(msg)
93
- self.send(self.prompt())
89
+ state = await self.__shell(msg)
90
+ await self.a_send(self.prompt())
94
91
  return state
95
92
 
96
- def __shell(self, msg):
93
+ async def __shell(self, msg):
97
94
  """
98
95
  Socket server - interpreter shell
99
96
  :param msg: socket input string
@@ -118,11 +115,11 @@ class Shell:
118
115
  # Hello message
119
116
  if msg_list[0] == 'hello':
120
117
  # For low level device identification - hello msg
121
- self.send(f"hello:{self.__devfid}:{self.__hwuid}")
118
+ await self.a_send(f"hello:{self.__devfid}:{self.__hwuid}")
122
119
  return True
123
120
 
124
121
  # [!] AUTH
125
- state, msg_list = self.__auth(msg_list)
122
+ state, msg_list = await self.__auth(msg_list)
126
123
  if not state:
127
124
  return False
128
125
  if len(msg_list) == 0:
@@ -131,7 +128,7 @@ class Shell:
131
128
  # Version handling
132
129
  if msg_list[0] == 'version':
133
130
  # For micrOS system version info
134
- self.send(str(Shell.MICROS_VERSION))
131
+ await self.a_send(str(Shell.MICROS_VERSION))
135
132
  return True
136
133
 
137
134
  # Reboot micropython VM
@@ -140,12 +137,12 @@ class Shell:
140
137
  if len(msg_list) >= 2 and "-h" in msg_list[1]:
141
138
  # reboot / reboot -h
142
139
  hard = True
143
- self.reboot(hard)
140
+ await self.reboot(hard)
144
141
 
145
142
  if msg_list[0].startswith('webrepl'):
146
143
  if len(msg_list) == 2 and '-u' in msg_list[1]:
147
- Shell.webrepl(msg_obj=self.send, update=True)
148
- Shell.webrepl(msg_obj=self.send)
144
+ await Shell.webrepl(msg_obj=self.a_send, update=True)
145
+ return await Shell.webrepl(msg_obj=self.a_send)
149
146
 
150
147
  # CONFIGURE MODE STATE: ACCESS FOR NODE_CONFIG.JSON
151
148
  if msg_list[0].startswith('conf'):
@@ -157,34 +154,34 @@ class Shell:
157
154
 
158
155
  # HELP MSG
159
156
  if msg_list[0] == "help":
160
- self.send("[MICROS] - built-in shell commands")
161
- self.send(" hello - hello msg - for device identification")
162
- self.send(" modules - show active Load Modules")
163
- self.send(" version - returns micrOS version")
164
- self.send(" exit - exit from shell socket prompt")
165
- self.send(" reboot - system soft reboot (vm), hard reboot (hw): reboot -h")
166
- self.send(" webrepl - start webrepl, for file transfers use with --update")
167
- self.send("[CONF] Configure mode - built-in shell commands")
168
- self.send(" conf - Enter conf mode")
169
- self.send(" dump - Dump all data")
170
- self.send(" key - Get value")
171
- self.send(" key value - Set value")
172
- self.send(" noconf - Exit conf mode")
173
- self.send("[TASK] postfix: &x - one-time, &&x - periodic, x: wait ms [x min: 20ms]")
174
- self.send(" task list - list tasks with <tag>s")
175
- self.send(" task kill <tag> - stop task")
176
- self.send(" task show <tag> - show task output")
177
- self.send("[EXEC] Command mode (LMs):")
178
- self.send(" help lm - list ALL LoadModules")
157
+ await self.a_send("[MICROS] - built-in shell commands")
158
+ await self.a_send(" hello - hello msg - for device identification")
159
+ await self.a_send(" modules - show active Load Modules")
160
+ await self.a_send(" version - returns micrOS version")
161
+ await self.a_send(" exit - exit from shell socket prompt")
162
+ await self.a_send(" reboot - system soft reboot (vm), hard reboot (hw): reboot -h")
163
+ await self.a_send(" webrepl - start webrepl, for file transfers use with --update")
164
+ await self.a_send("[CONF] Configure mode - built-in shell commands")
165
+ await self.a_send(" conf - Enter conf mode")
166
+ await self.a_send(" dump - Dump all data")
167
+ await self.a_send(" key - Get value")
168
+ await self.a_send(" key value - Set value")
169
+ await self.a_send(" noconf - Exit conf mode")
170
+ await self.a_send("[TASK] postfix: &x - one-time, &&x - periodic, x: wait ms [x min: 20ms]")
171
+ await self.a_send(" task list - list tasks with <tag>s")
172
+ await self.a_send(" task kill <tag> - stop task")
173
+ await self.a_send(" task show <tag> - show task output")
174
+ await self.a_send("[EXEC] Command mode (LMs):")
175
+ await self.a_send(" help lm - list ALL LoadModules")
179
176
  if "lm" in str(msg_list):
180
- return Shell._show_lm_funcs(msg_obj=self.send)
181
- return Shell._show_lm_funcs(msg_obj=self.send, active_only=True)
177
+ return await Shell._show_lm_funcs(msg_obj=self.a_send)
178
+ return await Shell._show_lm_funcs(msg_obj=self.a_send, active_only=True)
182
179
 
183
180
  # [2] EXECUTE:
184
181
  # @1 Configure mode
185
182
  if self.__conf_mode and len(msg_list) > 0:
186
183
  # Lock thread under config handling is threads available
187
- return Shell._configure(self.send, msg_list)
184
+ return await Shell._configure(self.a_send, msg_list)
188
185
  # @2 Command mode
189
186
  """
190
187
  INPUT MSG STRUCTURE
@@ -193,43 +190,43 @@ class Shell:
193
190
  """
194
191
  try:
195
192
  # Execute command via InterpreterCore
196
- self.send(lm_exec(arg_list=msg_list)[1])
193
+ await self.a_send(lm_exec(arg_list=msg_list)[1])
197
194
  return True
198
195
  except Exception as e:
199
- self.send(f"[ERROR] shell.lm_exec internal error: {e}")
196
+ await self.a_send(f"[ERROR] shell.lm_exec internal error: {e}")
200
197
  return False
201
198
 
202
199
  #################################################################
203
200
  # CONFIGURE MODE HANDLER #
204
201
  #################################################################
205
202
  @staticmethod
206
- def _configure(msg_obj, msg_list):
203
+ async def _configure(msg_obj, msg_list):
207
204
  """
208
205
  :param msg_obj: shell output stream function reference (write object)
209
206
  :param msg_list: socket input param list
210
207
  :return: execution status
211
208
  """
212
- def dump():
209
+ async def dump():
213
210
  nonlocal msg_obj, msg_list
214
211
  if msg_list[0] == 'dump':
215
212
  search = msg_list[1] if len(msg_list) == 2 else None
216
213
  # DUMP DATA
217
214
  for _key, value in cfgget().items():
218
215
  if search is None or search in _key:
219
- msg_obj(f" {_key}{' ' * (10 - len(_key))}:{' ' * 7} {value}")
216
+ await msg_obj(f" {_key}{' ' * (10 - len(_key))}:{' ' * 7} {value}")
220
217
  return True
221
218
  return False
222
219
 
223
220
  # [CONFIG] Get value
224
221
  if len(msg_list) == 1:
225
- if dump(): # Simple dump without param filter
222
+ if await dump(): # Simple dump without param filter
226
223
  return True
227
224
  # GET SINGLE PARAMETER VALUE
228
- msg_obj(cfgget(msg_list[0]))
225
+ await msg_obj(cfgget(msg_list[0]))
229
226
  return True
230
227
  # [CONFIG] Set value
231
228
  if len(msg_list) >= 2:
232
- if dump(): # Dump with search option
229
+ if await dump(): # Dump with search option
233
230
  return True
234
231
  # Deserialize params
235
232
  key = msg_list[0]
@@ -237,28 +234,28 @@ class Shell:
237
234
  try:
238
235
  output = cfgput(key, " ".join(msg_list[1:]), type_check=True)
239
236
  except Exception as e:
240
- msg_obj(f"node_config write error: {e}")
237
+ await msg_obj(f"node_config write error: {e}")
241
238
  output = False
242
239
  # Evaluation and reply
243
- msg_obj('Saved' if output else 'Invalid key' if cfgget(key) is None else 'Failed to save')
240
+ await msg_obj('Saved' if output else 'Invalid key' if cfgget(key) is None else 'Failed to save')
244
241
  return True
245
242
 
246
243
  #################################################################
247
244
  # COMMAND MODE & LMS HANDLER #
248
245
  #################################################################
249
246
  @staticmethod
250
- def _show_lm_funcs(msg_obj, active_only=False):
247
+ async def _show_lm_funcs(msg_obj, active_only=False):
251
248
  """
252
249
  Dump LM modules with functions - in case of [py] files
253
250
  Dump LM module with help function call - in case of [mpy] files
254
251
  """
255
- def _help(mod):
252
+ async def _help(mod):
256
253
  for lm_path in (i for i in mod if i.startswith('LM_') and (i.endswith('py'))):
257
254
  lm_name = lm_path.replace('LM_', '').split('.')[0]
258
255
  try:
259
- msg_obj(f" {lm_name}")
256
+ await msg_obj(f" {lm_name}")
260
257
  if lm_path.endswith('.mpy'):
261
- msg_obj(f" {' ' * len(lm_path.replace('LM_', '').split('.')[0])}help")
258
+ await msg_obj(f" {' ' * len(lm_path.replace('LM_', '').split('.')[0])}help")
262
259
  continue
263
260
  with open(lm_path, 'r') as f:
264
261
  line = "micrOSisTheBest"
@@ -266,9 +263,9 @@ class Shell:
266
263
  line = f.readline()
267
264
  ldata = line.strip()
268
265
  if ldata.startswith('def ') and not ldata.split()[1].startswith("_") and 'self' not in ldata:
269
- msg_obj(f" {' ' * len(lm_name)}{ldata.replace('def ', '').split('(')[0]}")
266
+ await msg_obj(f" {' ' * len(lm_name)}{ldata.replace('def ', '').split('(')[0]}")
270
267
  except Exception as e:
271
- msg_obj(f"[{lm_path}] SHOW LM PARSER WARNING: {e}")
268
+ await msg_obj(f"[{lm_path}] SHOW LM PARSER WARNING: {e}")
272
269
  return False
273
270
  return True
274
271
 
@@ -276,29 +273,30 @@ class Shell:
276
273
  if active_only:
277
274
  mod_keys = modules.keys()
278
275
  active_modules = (dir_mod for dir_mod in listdir() if dir_mod.split('.')[0] in mod_keys)
279
- return _help(active_modules)
276
+ return await _help(active_modules)
280
277
  # [2] list all LMs on file system (ALL - help lm) - manual
281
- return _help(listdir())
278
+ return await _help(listdir())
282
279
 
283
280
  @staticmethod
284
- def webrepl(msg_obj, update=False):
281
+ async def webrepl(msg_obj, update=False):
285
282
  from Network import ifconfig
286
283
 
287
- msg_obj(" Start micropython WEBREPL - file transfer and debugging")
288
- msg_obj(" [i] restart machine shortcut: import reset")
289
- msg_obj(f" Connect over http://micropython.org/webrepl/#{ifconfig()[1][0]}:8266/")
290
- msg_obj(f" \t[!] webrepl password: {cfgget('appwd')}")
284
+ await msg_obj(" Start micropython WEBREPL - file transfer and debugging")
285
+ await msg_obj(" [i] restart machine shortcut: import reset")
286
+ await msg_obj(f" Connect over http://micropython.org/webrepl/#{ifconfig()[1][0]}:8266/")
287
+ await msg_obj(f" \t[!] webrepl password: {cfgget('appwd')}")
291
288
  if update:
292
- msg_obj(" Restart node then start webrepl...")
293
- msg_obj(" Bye!")
289
+ await msg_obj(" Restart node then start webrepl...")
290
+ await msg_obj(" Bye!")
294
291
  # Set .if_mode->webrepl (start webrepl after reboot and poll update status...)
295
292
  with open('.if_mode', 'w') as f:
296
293
  f.write('webrepl')
297
294
  hard_reset()
298
295
  try:
299
296
  import webrepl
300
- msg_obj(webrepl.start(password=cfgget('appwd')))
297
+ await msg_obj(webrepl.start(password=cfgget('appwd')))
301
298
  except Exception as e:
302
299
  _err_msg = f"[ERR] while starting webrepl: {e}"
303
- msg_obj(_err_msg)
300
+ await msg_obj(_err_msg)
304
301
  errlog_add(_err_msg)
302
+ return True
micrOS/source/Web.py CHANGED
@@ -5,7 +5,7 @@ Built-in-function:
5
5
  - response
6
6
  - landing page: index.html
7
7
  - rest/ - call load modules, e.x.: system/top
8
- - file response (.html, .css, .js, .jped) - generic file server feature
8
+ - file response (.html, .css, .js, .jpeg) - generic file server feature
9
9
  - "virtual" endpoints - to reply from script on a defined endpoint
10
10
  - stream - stream data (jpeg) function
11
11
 
@@ -21,7 +21,7 @@ from Config import cfgget
21
21
 
22
22
  class WebEngine:
23
23
  __slots__ = ["client"]
24
- REST_ENDPOINTS = {}
24
+ ENDPOINTS = {}
25
25
  AUTH = cfgget('auth')
26
26
  VERSION = "n/a"
27
27
  REQ200 = "HTTP/1.1 200 OK\r\nContent-Type: {dtype}\r\nContent-Length:{len}\r\n\r\n{data}"
@@ -37,7 +37,8 @@ class WebEngine:
37
37
  """File dynamic Content-Type handling"""
38
38
  content_types = {".html": "text/html",
39
39
  ".css": "text/css",
40
- ".js": "application/javascript"}
40
+ ".js": "application/javascript",
41
+ ".jpeg": "image/jpeg"}
41
42
  # Extract the file extension
42
43
  ext = path.rsplit('.', 1)[-1]
43
44
  # Return the content type based on the file extension
@@ -49,7 +50,7 @@ class WebEngine:
49
50
  _method, url, _version = request.split('\n')[0].split()
50
51
  # Protocol validation
51
52
  if _method != "GET" and _version.startswith('HTTP'):
52
- _err = "Bad Request: not GET HTTP/1.1"
53
+ _err = f"Bad Request: not GET HTTP but {_version}"
53
54
  await self.client.a_send(self.REQ400.format(len=len(_err), data=_err))
54
55
  return
55
56
 
@@ -109,46 +110,42 @@ class WebEngine:
109
110
  else:
110
111
  state, out = lm_exec(cmd, jsonify=True)
111
112
  try:
112
- resp_schema['result'] = loads(out) # Load again ... hack for embedded shell json converter...
113
+ resp_schema['result'] = loads(out) # Load again ... hack for embedded json converter...
113
114
  except:
114
115
  resp_schema['result'] = out
115
116
  resp_schema['state'] = state
116
117
  else:
117
118
  resp_schema['result'] = {"micrOS": WebEngine.VERSION, 'node': cfgget('devfid'), 'auth': WebEngine.AUTH}
118
- if len(tuple(WebEngine.REST_ENDPOINTS.keys())) > 0:
119
- resp_schema['result']['usr_endpoints'] = tuple(WebEngine.REST_ENDPOINTS)
119
+ if len(tuple(WebEngine.ENDPOINTS.keys())) > 0:
120
+ resp_schema['result']['usr_endpoints'] = tuple(WebEngine.ENDPOINTS)
120
121
  resp_schema['state'] = True
121
122
  response = dumps(resp_schema)
122
123
  return WebEngine.REQ200.format(dtype='text/html', len=len(response), data=response)
123
124
 
124
125
  async def endpoints(self, url):
125
126
  url = url[1:] # Cut first / char
126
- if url in WebEngine.REST_ENDPOINTS:
127
+ if url in WebEngine.ENDPOINTS:
127
128
  console_write(f"[WebCli] endpoint: {url}")
128
129
  # Registered endpoint was found - exec callback
129
130
  try:
130
131
  # RESOLVE ENDPOINT CALLBACK
131
132
  # dtype:
132
- # one-shot: image/jpeg | text/html | text/plain - data: raw
133
- # task: multipart/x-mixed-replace | multipart/form-data - data: dict=callback,content-type
134
- # content-type: image/jpeg | audio/l16;*
135
- dtype, data = WebEngine.REST_ENDPOINTS[url]()
133
+ # one-shot (simple MIME types): image/jpeg | text/html | text/plain - data: raw
134
+ # task (streaming MIME types): multipart/x-mixed-replace | multipart/form-data - data: dict{callback,content-type}
135
+ # content-type: image/jpeg | audio/l16;*
136
+ dtype, data = WebEngine.ENDPOINTS[url]()
136
137
  if dtype == 'image/jpeg':
137
- resp = f"HTTP/1.1 200 OK\r\nContent-Type: {dtype}\r\nContent-Length:{len(data)}\r\n\r\n".encode(
138
- 'utf8') + data
138
+ resp = f"HTTP/1.1 200 OK\r\nContent-Type: {dtype}\r\nContent-Length:{len(data)}\r\n\r\n".encode('utf8') + data
139
139
  await self.client.a_send(resp, encode=None)
140
140
  elif dtype in ('multipart/x-mixed-replace', 'multipart/form-data'):
141
- headers = (
142
- f"HTTP/1.1 200 OK\r\nContent-Type: {dtype}; boundary=\"micrOS_boundary\"\r\n\r\n").encode(
143
- 'utf-8')
144
- await self.client.a_send(headers, encode=None)
141
+ headers = f"HTTP/1.1 200 OK\r\nContent-Type: {dtype}; boundary=\"micrOS_boundary\"\r\n\r\n"
142
+ await self.client.a_send(headers)
145
143
  # Start Native stream async task
146
144
  task = NativeTask()
147
- task.create(callback=self.stream(data['callback'], task, data['content-type']),
148
- tag=f"web.stream_{self.client.client_id.replace('W', '')}")
145
+ tag=f"web.stream_{self.client.client_id.replace('W', '')}"
146
+ task.create(callback=self.stream(data['callback'], task, data['content-type']), tag=tag)
149
147
  else: # dtype: text/html or text/plain
150
- await self.client.a_send(
151
- f"HTTP/1.1 200 OK\r\nContent-Type: {dtype}\r\nContent-Length:{len(data)}\r\n\r\n{data}")
148
+ await self.client.a_send(WebEngine.REQ200.format(dtype=dtype, len=len(data), data=data))
152
149
  except Exception as e:
153
150
  await self.client.a_send(self.REQ404.format(len=len(str(e)), data=e))
154
151
  errlog_add(f"[ERR] WebCli endpoints {url}: {e}")
@@ -159,6 +156,8 @@ class WebEngine:
159
156
  """
160
157
  Async stream method
161
158
  :param callback: sync or async function callback (auto-detect) WARNING: works for functions only (not methods!)
159
+ :param task: NativeTask instance (that the stream runs in)
160
+ :param content_type: image/jpeg | audio/l16;*
162
161
  """
163
162
  is_coroutine = 'generator' in str(type(callback)) # async function callback auto-detect
164
163
  with task:
@@ -175,6 +174,6 @@ class WebEngine:
175
174
  # Gracefully terminate the stream
176
175
  if self.client.connected:
177
176
  closing_boundary = '\r\n--micrOS_boundary--\r\n'
178
- await self.client.a_send(closing_boundary, encode=None)
177
+ await self.client.a_send(closing_boundary)
179
178
  await self.client.close()
180
179
  task.out = 'Finished stream'
micrOS/source/microIO.py CHANGED
@@ -9,7 +9,7 @@ Designed by Marcell Ban aka BxNxM
9
9
  # IMPORTS #
10
10
  #################################################################
11
11
  from sys import platform
12
- from os import listdir
12
+ from uos import listdir, uname
13
13
  from Logger import syslog
14
14
 
15
15
  #################################################################
@@ -29,7 +29,6 @@ def detect_platform():
29
29
  Unified platform detection for micrOS
30
30
  """
31
31
  if 'esp32' in platform:
32
- from os import uname
33
32
  board = str(uname()[-1]).lower()
34
33
  if 'tinypico' in board:
35
34
  return 'tinypico' # esp32 family - tinypico
micrOS/source/reset.py CHANGED
@@ -1,5 +1,9 @@
1
- from os import listdir
1
+ """
2
+ Easy reset for webrepl terminal
3
+ """
4
+
2
5
  from time import sleep
6
+ from uos import listdir
3
7
  from machine import soft_reset, reset
4
8
 
5
9
  print('Device reboot now, boot micrOSloader...')
@@ -1,9 +1,16 @@
1
+ """
2
+ This module implements an optimized version of requests module
3
+ for async and sync http get and post requests.
4
+
5
+ Designed by Marcell Ban aka BxNxM GitHub
6
+ """
7
+
8
+ from json import loads, dumps
1
9
  from usocket import socket, getaddrinfo
2
10
  try:
3
- from ussl import wrap_socket # Legacy micropython ssl usage
11
+ from ussl import wrap_socket # Legacy micropython ssl usage (+simulator mode)
4
12
  except ImportError:
5
13
  from ssl import wrap_socket # From micropython 1.23...
6
- from json import loads, dumps
7
14
  from Debug import errlog_add
8
15
  import uasyncio as asyncio
9
16
 
@@ -39,7 +46,7 @@ def _chunked(_body):
39
46
  chunk_size_str = _body[:line_end]
40
47
  try:
41
48
  chunk_size = int(chunk_size_str, 16)
42
- except ValueError as e:
49
+ except ValueError:
43
50
  chunk_size = 0
44
51
 
45
52
  # Check chunk size
@@ -213,7 +220,8 @@ async def arequest(method, url, data=None, json=None, headers=None, sock_size=25
213
220
  status_code, body = _parse_response(response)
214
221
  except Exception as e:
215
222
  status_code = 500
216
- body = f'[ERR] arequest failed: {e}'
223
+ # https://github.com/micropython/micropython/blob/8785645a952c03315dbf93667b5f7c7eec49762f/cc3200/simplelink/include/device.h
224
+ body = "[WARN] arequest ASSOC_REJECT" if "-104" == str(e) else f"[ERR] arequest failed: {e}"
217
225
  errlog_add(body)
218
226
  finally:
219
227
  if writer:
@@ -10,8 +10,9 @@ if len(sys.argv) > 1 and sys.argv[1] in ['light', '--light']:
10
10
  else:
11
11
  # INSTALL OPTIONAL DEPENDENCIES - PIP HACK
12
12
  from toolkit.lib import pip_package_installer as pip_install
13
- pip_install.install_optional_dependencies(['PyQt5', 'opencv-python', 'PyAudio', 'mpy-cross==1.20.0', 'matplotlib'])
14
-
13
+ pip_install.install_optional_dependencies(['PyQt5', 'opencv-python', 'PyAudio', 'mpy-cross==1.24.1.post2', 'matplotlib'])
14
+ if sys.platform.startswith("win"):
15
+ pip_install.install_optional_dependencies(['pyreadline3'])
15
16
 
16
17
  # NORMAL CODE ...
17
18
  MYPATH = os.path.dirname(__file__)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: micrOSDevToolKit
3
- Version: 2.9.1
3
+ Version: 2.9.6
4
4
  Summary: Development and deployment environment for micrOS, the diy micropython automation OS (IoT)
5
5
  Home-page: https://github.com/BxNxM/micrOS
6
6
  Author: Marcell Ban