mpflash 1.24.8__py3-none-any.whl → 1.25.0__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.
- mpflash/basicgit.py +3 -2
- mpflash/cli_flash.py +1 -1
- mpflash/cli_list.py +5 -6
- mpflash/cli_main.py +1 -1
- mpflash/config.py +6 -1
- mpflash/db/boards.py +63 -0
- mpflash/db/downloads.py +87 -0
- mpflash/download/__init__.py +221 -0
- mpflash/download/from_web.py +204 -0
- mpflash/downloaded.py +8 -29
- mpflash/flash/worklist.py +3 -3
- mpflash/mpboard_id/board.py +5 -2
- mpflash/mpboard_id/board_id.py +67 -6
- mpflash/mpboard_id/board_info.zip +0 -0
- mpflash/mpboard_id/known.py +32 -18
- mpflash/mpboard_id/store.py +2 -1
- mpflash/mpremoteboard/__init__.py +81 -17
- mpflash/mpremoteboard/mpy_fw_info.py +13 -9
- mpflash/vendor/board_database.py +86 -1
- mpflash/versions.py +7 -0
- {mpflash-1.24.8.dist-info → mpflash-1.25.0.dist-info}/METADATA +1 -1
- {mpflash-1.24.8.dist-info → mpflash-1.25.0.dist-info}/RECORD +25 -22
- mpflash/download.py +0 -397
- {mpflash-1.24.8.dist-info → mpflash-1.25.0.dist-info}/LICENSE +0 -0
- {mpflash-1.24.8.dist-info → mpflash-1.25.0.dist-info}/WHEEL +0 -0
- {mpflash-1.24.8.dist-info → mpflash-1.25.0.dist-info}/entry_points.txt +0 -0
mpflash/downloaded.py
CHANGED
@@ -5,27 +5,12 @@ import jsonlines
|
|
5
5
|
from loguru import logger as log
|
6
6
|
|
7
7
|
from mpflash.common import PORT_FWTYPES, FWInfo
|
8
|
+
from mpflash.db.downloads import downloaded
|
8
9
|
from mpflash.versions import clean_version
|
9
10
|
|
10
11
|
from .config import config
|
11
12
|
|
12
|
-
|
13
13
|
# #########################################################################################################
|
14
|
-
def downloaded_firmwares(fw_folder: Path) -> List[FWInfo]:
|
15
|
-
"""Load a list of locally downloaded firmwares from the jsonl file"""
|
16
|
-
firmwares: List[FWInfo] = []
|
17
|
-
log.debug(f"Reading {fw_folder / 'firmware.jsonl' }")
|
18
|
-
try:
|
19
|
-
with jsonlines.open(fw_folder / "firmware.jsonl") as reader:
|
20
|
-
firmwares = [FWInfo.from_dict(item) for item in reader]
|
21
|
-
except FileNotFoundError:
|
22
|
-
log.error(f"No firmware.jsonl found in {fw_folder}")
|
23
|
-
except jsonlines.InvalidLineError as e:
|
24
|
-
log.error(f"Invalid firmware.jsonl found in {fw_folder} : {e}")
|
25
|
-
|
26
|
-
# sort by filename
|
27
|
-
firmwares.sort(key=lambda x: x.filename)
|
28
|
-
return firmwares
|
29
14
|
|
30
15
|
|
31
16
|
def clean_downloaded_firmwares(fw_folder: Path) -> None:
|
@@ -33,15 +18,9 @@ def clean_downloaded_firmwares(fw_folder: Path) -> None:
|
|
33
18
|
Remove duplicate entries from the firmware.jsonl file, keeping the latest one
|
34
19
|
uniqueness is based on the filename
|
35
20
|
"""
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
# keep the latest entry
|
40
|
-
unique_fw = {fw.filename: fw for fw in firmwares}
|
41
|
-
with jsonlines.open(fw_folder / "firmware.jsonl", "w") as writer:
|
42
|
-
for fw in unique_fw.values():
|
43
|
-
writer.write(fw.to_dict())
|
44
|
-
log.info(f"Removed duplicate entries from firmware.jsonl in {fw_folder}")
|
21
|
+
# Duplication should no longer happen,
|
22
|
+
# but is would be a good idea to check the consistence between the DB and the downloads folder sometimes
|
23
|
+
pass
|
45
24
|
|
46
25
|
|
47
26
|
def find_downloaded_firmware(
|
@@ -50,16 +29,16 @@ def find_downloaded_firmware(
|
|
50
29
|
version: str = "", # v1.2.3
|
51
30
|
port: str = "",
|
52
31
|
variants: bool = False,
|
53
|
-
|
32
|
+
db_path: Optional[Path] = None,
|
54
33
|
trie: int = 1,
|
55
34
|
selector: Optional[Dict[str, str]] = None,
|
56
35
|
) -> List[FWInfo]:
|
57
36
|
if selector is None:
|
58
37
|
selector = {}
|
59
|
-
|
38
|
+
|
60
39
|
# Use the information in firmwares.jsonl to find the firmware file
|
61
40
|
log.debug(f"{trie}] Looking for firmware for {board_id} {version} ")
|
62
|
-
fw_list =
|
41
|
+
fw_list = downloaded()
|
63
42
|
if not fw_list:
|
64
43
|
log.error("No firmware files found. Please download the firmware first.")
|
65
44
|
return []
|
@@ -80,7 +59,7 @@ def find_downloaded_firmware(
|
|
80
59
|
board_id = board_id.replace("_", "-")
|
81
60
|
|
82
61
|
fw_list = find_downloaded_firmware(
|
83
|
-
|
62
|
+
db_path=db_path,
|
84
63
|
board_id=board_id,
|
85
64
|
version=version,
|
86
65
|
port=port,
|
mpflash/flash/worklist.py
CHANGED
@@ -43,7 +43,7 @@ def auto_update(
|
|
43
43
|
log.warning(f"Skipping flashing {mcu.family} {mcu.port} {mcu.board} on {mcu.serialport} as it is not a MicroPython firmware")
|
44
44
|
continue
|
45
45
|
board_firmwares = find_downloaded_firmware(
|
46
|
-
|
46
|
+
db_path=fw_folder,
|
47
47
|
board_id=mcu.board if not mcu.variant else f"{mcu.board}-{mcu.variant}",
|
48
48
|
version=target_version,
|
49
49
|
port=mcu.port,
|
@@ -91,11 +91,11 @@ def manual_worklist(
|
|
91
91
|
# need the CPU type for the esptool
|
92
92
|
mcu.cpu = info.cpu
|
93
93
|
except (LookupError, MPFlashError) as e:
|
94
|
-
log.error(f"Board {board_id} not found in
|
94
|
+
log.error(f"Board {board_id} not found in board database")
|
95
95
|
log.exception(e)
|
96
96
|
return []
|
97
97
|
mcu.board = board_id
|
98
|
-
firmwares = find_downloaded_firmware(
|
98
|
+
firmwares = find_downloaded_firmware(db_path=fw_folder, board_id=board_id, version=version, port=mcu.port)
|
99
99
|
if not firmwares:
|
100
100
|
log.error(f"No firmware found for {mcu.port} {board_id} version {version}")
|
101
101
|
return []
|
mpflash/mpboard_id/board.py
CHANGED
@@ -21,17 +21,20 @@ class Board:
|
|
21
21
|
mcu_name: str = field(default="")
|
22
22
|
cpu: str = field(default="")
|
23
23
|
variant: str = field(default="")
|
24
|
+
mcu: str = field(default="")
|
24
25
|
|
25
26
|
def __post_init__(self):
|
26
27
|
if not self.cpu:
|
27
28
|
if " with " in self.description:
|
28
|
-
self.cpu = self.description.
|
29
|
+
self.cpu = self.description.rsplit(" with ")[-1]
|
29
30
|
else:
|
30
31
|
self.cpu = self.port
|
31
32
|
|
32
33
|
@staticmethod
|
33
34
|
def from_dict(data: dict) -> "Board":
|
34
|
-
|
35
|
+
valid_keys = {field.name for field in Board.__dataclass_fields__.values()}
|
36
|
+
filtered_data = {k: v for k, v in data.items() if k in valid_keys}
|
37
|
+
return Board(**filtered_data)
|
35
38
|
|
36
39
|
def to_dict(self) -> dict:
|
37
40
|
return self.__dict__
|
mpflash/mpboard_id/board_id.py
CHANGED
@@ -3,11 +3,15 @@ Translate board description to board designator
|
|
3
3
|
"""
|
4
4
|
|
5
5
|
import functools
|
6
|
+
import re
|
7
|
+
import sqlite3
|
6
8
|
from pathlib import Path
|
7
|
-
from typing import Optional
|
9
|
+
from typing import List, Optional
|
8
10
|
|
11
|
+
from mpflash.config import config
|
9
12
|
from mpflash.errors import MPFlashError
|
10
13
|
from mpflash.logger import log
|
14
|
+
from mpflash.mpboard_id.board import Board
|
11
15
|
from mpflash.mpboard_id.store import read_known_boardinfo
|
12
16
|
from mpflash.versions import clean_version, get_preview_mp_version, get_stable_mp_version
|
13
17
|
|
@@ -20,21 +24,78 @@ def find_board_id_by_description(
|
|
20
24
|
board_info: Optional[Path] = None,
|
21
25
|
) -> Optional[str]:
|
22
26
|
"""Find the MicroPython BOARD_ID based on the description in the firmware"""
|
23
|
-
|
27
|
+
version = clean_version(version) if version else ""
|
24
28
|
try:
|
25
29
|
boards = _find_board_id_by_description(
|
26
30
|
descr=descr,
|
27
31
|
short_descr=short_descr,
|
28
|
-
|
29
|
-
version=
|
32
|
+
db_path=board_info,
|
33
|
+
version=version,
|
30
34
|
)
|
31
|
-
|
35
|
+
if not boards:
|
36
|
+
log.debug(f"Version {version} not found in board info, using any version")
|
37
|
+
boards = _find_board_id_by_description(
|
38
|
+
descr=descr,
|
39
|
+
short_descr=short_descr,
|
40
|
+
db_path=board_info,
|
41
|
+
version="%", # any version
|
42
|
+
)
|
43
|
+
return boards[0].board_id if boards else None
|
32
44
|
except MPFlashError:
|
33
45
|
return "UNKNOWN_BOARD"
|
34
46
|
|
35
47
|
|
36
|
-
@functools.lru_cache(maxsize=20)
|
37
48
|
def _find_board_id_by_description(
|
49
|
+
*,
|
50
|
+
descr: str,
|
51
|
+
short_descr: str,
|
52
|
+
version: Optional[str] = None,
|
53
|
+
variant: str = "",
|
54
|
+
db_path: Optional[Path] = None,
|
55
|
+
):
|
56
|
+
short_descr = short_descr or ""
|
57
|
+
boards: List[Board] = []
|
58
|
+
version = clean_version(version) if version else "%"
|
59
|
+
if "-preview" in version:
|
60
|
+
version = version.replace("-preview", "%")
|
61
|
+
descriptions = [descr, short_descr]
|
62
|
+
if descr.startswith("Generic"):
|
63
|
+
descriptions.append(descr[8:])
|
64
|
+
descriptions.append(short_descr[8:])
|
65
|
+
|
66
|
+
try:
|
67
|
+
with sqlite3.connect(db_path or config.db_path) as conn:
|
68
|
+
conn.row_factory = sqlite3.Row
|
69
|
+
cursor = conn.cursor()
|
70
|
+
|
71
|
+
qry = f"""
|
72
|
+
SELECT
|
73
|
+
*
|
74
|
+
FROM board_downloaded
|
75
|
+
WHERE
|
76
|
+
board_id IN (
|
77
|
+
SELECT DISTINCT board_id
|
78
|
+
FROM board_downloaded
|
79
|
+
WHERE description IN {str(tuple(descriptions))}
|
80
|
+
)
|
81
|
+
AND version like '{version}'
|
82
|
+
AND variant like '{variant}'
|
83
|
+
"""
|
84
|
+
cursor.execute(qry)
|
85
|
+
rows = cursor.fetchall()
|
86
|
+
for row in rows:
|
87
|
+
r = dict(row)
|
88
|
+
|
89
|
+
boards.append(Board.from_dict(dict(row)))
|
90
|
+
except sqlite3.OperationalError as e:
|
91
|
+
raise MPFlashError("Database error") from e
|
92
|
+
if not boards:
|
93
|
+
raise MPFlashError(f"No board info found for description '{descr}' or '{short_descr}'")
|
94
|
+
return boards
|
95
|
+
|
96
|
+
|
97
|
+
@functools.lru_cache(maxsize=20)
|
98
|
+
def _find_board_id_by_description_xx(
|
38
99
|
*,
|
39
100
|
descr: str,
|
40
101
|
short_descr: str,
|
Binary file
|
mpflash/mpboard_id/known.py
CHANGED
@@ -7,8 +7,10 @@ This module provides access to the board info and the known ports and boards."""
|
|
7
7
|
from functools import lru_cache
|
8
8
|
from typing import List, Optional, Tuple
|
9
9
|
|
10
|
+
from mpflash.db.boards import find_board_id, find_board_info
|
10
11
|
from mpflash.errors import MPFlashError
|
11
12
|
from mpflash.versions import clean_version
|
13
|
+
from mpflash.logger import log
|
12
14
|
|
13
15
|
from .board import Board
|
14
16
|
from .store import read_known_boardinfo
|
@@ -16,6 +18,7 @@ from .store import read_known_boardinfo
|
|
16
18
|
|
17
19
|
def get_known_ports() -> List[str]:
|
18
20
|
# TODO: Filter for Version
|
21
|
+
log.warning("get_known_ports() is deprecated")
|
19
22
|
mp_boards = read_known_boardinfo()
|
20
23
|
# select the unique ports from info
|
21
24
|
ports = set({board.port for board in mp_boards if board.port})
|
@@ -41,6 +44,9 @@ def get_known_boards_for_port(port: Optional[str] = "", versions: Optional[List[
|
|
41
44
|
if "preview" in versions:
|
42
45
|
versions.remove("preview")
|
43
46
|
versions.append("stable")
|
47
|
+
# filter for the port
|
48
|
+
if port:
|
49
|
+
mp_boards = [board for board in mp_boards if board.port == port]
|
44
50
|
if versions:
|
45
51
|
# make sure of the v prefix
|
46
52
|
versions = [clean_version(v) for v in versions]
|
@@ -53,9 +59,6 @@ def get_known_boards_for_port(port: Optional[str] = "", versions: Optional[List[
|
|
53
59
|
last_known_version = sorted({b.version for b in mp_boards})[-1]
|
54
60
|
mp_boards = [board for board in mp_boards if board.version == last_known_version]
|
55
61
|
|
56
|
-
# filter for the port
|
57
|
-
if port:
|
58
|
-
mp_boards = [board for board in mp_boards if board.port == port]
|
59
62
|
return mp_boards
|
60
63
|
|
61
64
|
|
@@ -73,22 +76,33 @@ def known_stored_boards(port: str, versions: Optional[List[str]] = None) -> List
|
|
73
76
|
|
74
77
|
|
75
78
|
@lru_cache(maxsize=20)
|
76
|
-
def find_known_board(board_id: str) -> Board:
|
79
|
+
def find_known_board(board_id: str, version ="") -> Board:
|
77
80
|
"""Find the board for the given BOARD_ID or 'board description' and return the board info as a Board object"""
|
78
81
|
# Some functional overlap with:
|
79
82
|
# mpboard_id\board_id.py _find_board_id_by_description
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
83
|
+
# TODO: Refactor to search the SQLite DB instead of the JSON file
|
84
|
+
board_ids = find_board_id(board_id = board_id, version = version or "%")
|
85
|
+
boards = []
|
86
|
+
for board_id in board_ids:
|
87
|
+
# if we have a board_id, use it to find the board info
|
88
|
+
boards += [Board.from_dict(dict(r)) for r in find_board_info(board_id = board_id)]
|
89
|
+
|
90
|
+
|
91
|
+
# if board_ids:
|
92
|
+
# # if we have a board_id, use it to find the board info
|
93
|
+
# board_id = board_ids[0]
|
94
|
+
# info = read_known_boardinfo()
|
95
|
+
# for board_info in info:
|
96
|
+
# if board_id in (
|
97
|
+
# board_info.board_id,
|
98
|
+
# board_info.description,
|
99
|
+
# ) or board_info.description.startswith(board_id):
|
100
|
+
# if not board_info.cpu:
|
101
|
+
# # failsafe for older board_info.json files
|
102
|
+
# print(f"Board {board_id} has no CPU info, using port as CPU")
|
103
|
+
# if " with " in board_info.description:
|
104
|
+
# board_info.cpu = board_info.description.split(" with ")[-1]
|
105
|
+
# else:
|
106
|
+
# board_info.cpu = board_info.port
|
107
|
+
# return board_info
|
94
108
|
raise MPFlashError(f"Board {board_id} not found")
|
mpflash/mpboard_id/store.py
CHANGED
@@ -2,6 +2,7 @@ import functools
|
|
2
2
|
import zipfile
|
3
3
|
from pathlib import Path
|
4
4
|
from typing import Final, List, Optional
|
5
|
+
from mpflash.logger import log
|
5
6
|
|
6
7
|
import jsons
|
7
8
|
|
@@ -32,7 +33,7 @@ def write_boardinfo_json(board_list: List[Board], *, folder: Optional[Path] = No
|
|
32
33
|
@functools.lru_cache(maxsize=20)
|
33
34
|
def read_known_boardinfo(board_info: Optional[Path] = None) -> List[Board]:
|
34
35
|
"""Reads the board information from a JSON file in a zip file."""
|
35
|
-
|
36
|
+
log.warning("read_known_boardinfo() is deprecated")
|
36
37
|
|
37
38
|
if not board_info:
|
38
39
|
board_info = HERE / "board_info.zip"
|
@@ -2,7 +2,6 @@
|
|
2
2
|
Module to run mpremote commands, and retry on failure or timeout
|
3
3
|
"""
|
4
4
|
|
5
|
-
|
6
5
|
import contextlib
|
7
6
|
import sys
|
8
7
|
import time
|
@@ -35,7 +34,9 @@ RETRIES = 3
|
|
35
34
|
class MPRemoteBoard:
|
36
35
|
"""Class to run mpremote commands"""
|
37
36
|
|
38
|
-
def __init__(
|
37
|
+
def __init__(
|
38
|
+
self, serialport: str = "", update: bool = False, *, location: str = ""
|
39
|
+
):
|
39
40
|
"""
|
40
41
|
Initialize MPRemoteBoard object.
|
41
42
|
|
@@ -43,6 +44,8 @@ class MPRemoteBoard:
|
|
43
44
|
- serialport (str): The serial port to connect to. Default is an empty string.
|
44
45
|
- update (bool): Whether to update the MCU information. Default is False.
|
45
46
|
"""
|
47
|
+
self._board_id = ""
|
48
|
+
|
46
49
|
self.serialport: str = serialport
|
47
50
|
self.firmware = {}
|
48
51
|
|
@@ -52,8 +55,6 @@ class MPRemoteBoard:
|
|
52
55
|
self.description = ""
|
53
56
|
self.version = ""
|
54
57
|
self.port = ""
|
55
|
-
self.board = ""
|
56
|
-
self.variant= ""
|
57
58
|
self.cpu = ""
|
58
59
|
self.arch = ""
|
59
60
|
self.mpy = ""
|
@@ -63,6 +64,33 @@ class MPRemoteBoard:
|
|
63
64
|
if update:
|
64
65
|
self.get_mcu_info()
|
65
66
|
|
67
|
+
###################################
|
68
|
+
# board_id := board[-variant]
|
69
|
+
@property
|
70
|
+
def board_id(self) -> str:
|
71
|
+
return self._board_id
|
72
|
+
|
73
|
+
@board_id.setter
|
74
|
+
def board_id(self, value: str) -> None:
|
75
|
+
self._board_id = value.rstrip("-")
|
76
|
+
|
77
|
+
@property
|
78
|
+
def board(self) -> str:
|
79
|
+
return self._board_id.split("-")[0]
|
80
|
+
|
81
|
+
@board.setter
|
82
|
+
def board(self, value: str) -> None:
|
83
|
+
self.board_id = f"{value}-{self.variant}" if self.variant else value
|
84
|
+
|
85
|
+
@property
|
86
|
+
def variant(self) -> str:
|
87
|
+
return self._board_id.split("-")[1] if "-" in self._board_id else ""
|
88
|
+
|
89
|
+
@variant.setter
|
90
|
+
def variant(self, value: str) -> None:
|
91
|
+
self.board_id = f"{self.board}-{value}"
|
92
|
+
|
93
|
+
###################################
|
66
94
|
def __str__(self):
|
67
95
|
"""
|
68
96
|
Return a string representation of the MPRemoteBoard object.
|
@@ -73,7 +101,9 @@ class MPRemoteBoard:
|
|
73
101
|
return f"MPRemoteBoard({self.serialport}, {self.family} {self.port}, {self.board}{f'-{self.variant}' if self.variant else ''}, {self.version})"
|
74
102
|
|
75
103
|
@staticmethod
|
76
|
-
def connected_boards(
|
104
|
+
def connected_boards(
|
105
|
+
bluetooth: bool = False, description: bool = False
|
106
|
+
) -> List[str]:
|
77
107
|
# TODO: rename to connected_comports
|
78
108
|
"""
|
79
109
|
Get a list of connected comports.
|
@@ -101,7 +131,10 @@ class MPRemoteBoard:
|
|
101
131
|
if sys.platform == "win32":
|
102
132
|
# Windows sort of comports by number - but fallback to device name
|
103
133
|
return sorted(
|
104
|
-
output,
|
134
|
+
output,
|
135
|
+
key=lambda x: int(x.split()[0][3:])
|
136
|
+
if x.split()[0][3:].isdigit()
|
137
|
+
else x,
|
105
138
|
)
|
106
139
|
# sort by device name
|
107
140
|
return sorted(output)
|
@@ -123,11 +156,11 @@ class MPRemoteBoard:
|
|
123
156
|
timeout=timeout,
|
124
157
|
resume=False, # Avoid restarts
|
125
158
|
)
|
126
|
-
if rc:
|
159
|
+
if rc not in (0, 1): ## WORKAROUND - SUDDEN RETURN OF 1 on success
|
127
160
|
log.debug(f"rc: {rc}, result: {result}")
|
128
161
|
raise ConnectionError(f"Failed to get mcu_info for {self.serialport}")
|
129
162
|
# Ok we have the info, now parse it
|
130
|
-
raw_info = result[0].strip()
|
163
|
+
raw_info = result[0].strip() if result else ""
|
131
164
|
if raw_info.startswith("{") and raw_info.endswith("}"):
|
132
165
|
info = eval(raw_info)
|
133
166
|
self.family = info["family"]
|
@@ -140,17 +173,19 @@ class MPRemoteBoard:
|
|
140
173
|
self.description = descr = info["board"]
|
141
174
|
pos = descr.rfind(" with")
|
142
175
|
short_descr = descr[:pos].strip() if pos != -1 else ""
|
143
|
-
if info
|
144
|
-
|
145
|
-
self.
|
146
|
-
elif board_name := find_board_id_by_description(
|
147
|
-
descr, short_descr, version=self.version
|
148
|
-
):
|
149
|
-
self.board = board_name
|
176
|
+
if info.get("board_id", None):
|
177
|
+
# we have a board_id - so use that to get the board name
|
178
|
+
self.board_id = info["board_id"]
|
150
179
|
else:
|
151
|
-
self.
|
180
|
+
self.board_id = f"{info['board']}-{info.get('variant', '')}"
|
181
|
+
board_name = find_board_id_by_description(
|
182
|
+
descr, short_descr, version=self.version
|
183
|
+
)
|
184
|
+
self.board_id = board_name or "UNKNOWN_BOARD"
|
185
|
+
# TODO: Get the variant as well
|
152
186
|
# get the board_info.toml
|
153
187
|
self.get_board_info_toml()
|
188
|
+
# TODO: get board_id from the toml file if it exists
|
154
189
|
# now we know the board is connected
|
155
190
|
self.connected = True
|
156
191
|
|
@@ -174,7 +209,9 @@ class MPRemoteBoard:
|
|
174
209
|
log_errors=False,
|
175
210
|
)
|
176
211
|
except Exception as e:
|
177
|
-
raise ConnectionError(
|
212
|
+
raise ConnectionError(
|
213
|
+
f"Failed to get board_info.toml for {self.serialport}:"
|
214
|
+
) from e
|
178
215
|
# this is optional - so only parse if we got the file
|
179
216
|
self.toml = {}
|
180
217
|
if rc in [OK]: # sometimes we get an -9 ???
|
@@ -273,3 +310,30 @@ class MPRemoteBoard:
|
|
273
310
|
with contextlib.suppress(ConnectionError, MPFlashError):
|
274
311
|
self.get_mcu_info()
|
275
312
|
break
|
313
|
+
|
314
|
+
def to_dict(self) -> dict:
|
315
|
+
"""
|
316
|
+
Serialize the MPRemoteBoard object to JSON, including all attributes and readable properties.
|
317
|
+
|
318
|
+
Returns:
|
319
|
+
- str: A JSON string representation of the object.
|
320
|
+
"""
|
321
|
+
|
322
|
+
def get_properties(obj):
|
323
|
+
"""Helper function to get all readable properties."""
|
324
|
+
return {
|
325
|
+
name: getattr(obj, name)
|
326
|
+
for name in dir(obj.__class__)
|
327
|
+
if isinstance(getattr(obj.__class__, name, None), property)
|
328
|
+
}
|
329
|
+
|
330
|
+
# Combine instance attributes, readable properties, and private attributes
|
331
|
+
data = {**self.__dict__, **get_properties(self)}
|
332
|
+
|
333
|
+
# remove the path and firmware attibutes from the json output as they are always empty
|
334
|
+
del data["_board_id"] # dup of board_id
|
335
|
+
del data["connected"]
|
336
|
+
del data["path"]
|
337
|
+
del data["firmware"]
|
338
|
+
|
339
|
+
return data
|
@@ -3,7 +3,7 @@ import os
|
|
3
3
|
import sys
|
4
4
|
|
5
5
|
|
6
|
-
def
|
6
|
+
def get_build(s):
|
7
7
|
# extract build from sys.version or os.uname().version if available
|
8
8
|
# sys.version: 'MicroPython v1.23.0-preview.6.g3d0b6276f'
|
9
9
|
# sys.implementation.version: 'v1.13-103-gb137d064e'
|
@@ -49,10 +49,14 @@ def _info(): # type:() -> dict[str, str]
|
|
49
49
|
except AttributeError:
|
50
50
|
pass
|
51
51
|
try:
|
52
|
-
|
53
|
-
info["board"] =
|
54
|
-
|
55
|
-
|
52
|
+
_machine = sys.implementation._machine if "_machine" in dir(sys.implementation) else os.uname().machine # type: ignore
|
53
|
+
info["board"] = _machine.strip()
|
54
|
+
si_build = sys.implementation._build if "_build" in dir(sys.implementation) else ""
|
55
|
+
if si_build:
|
56
|
+
info["board"] = si_build.split("-")[0]
|
57
|
+
info["variant"] = si_build.split("-")[1] if "-" in si_build else ""
|
58
|
+
info["board_id"] = si_build
|
59
|
+
info["cpu"] = _machine.split("with")[-1].strip() if "with" in _machine else ""
|
56
60
|
info["mpy"] = (
|
57
61
|
sys.implementation._mpy
|
58
62
|
if "_mpy" in dir(sys.implementation)
|
@@ -65,12 +69,12 @@ def _info(): # type:() -> dict[str, str]
|
|
65
69
|
|
66
70
|
try:
|
67
71
|
if hasattr(sys, "version"):
|
68
|
-
info["build"] =
|
72
|
+
info["build"] = get_build(sys.version)
|
69
73
|
elif hasattr(os, "uname"):
|
70
|
-
info["build"] =
|
74
|
+
info["build"] = get_build(os.uname()[3]) # type: ignore
|
71
75
|
if not info["build"]:
|
72
76
|
# extract build from uname().release if available
|
73
|
-
info["build"] =
|
77
|
+
info["build"] = get_build(os.uname()[2]) # type: ignore
|
74
78
|
except (AttributeError, IndexError):
|
75
79
|
pass
|
76
80
|
# avoid build hashes
|
@@ -146,4 +150,4 @@ def _info(): # type:() -> dict[str, str]
|
|
146
150
|
|
147
151
|
|
148
152
|
print(_info())
|
149
|
-
del _info,
|
153
|
+
del _info, get_build, _version_str
|