Skip to content

Commit 6d2715d

Browse files
committed
feat(component editor): Re-oder component data
More important components first, less important and/or optional components last Product's Manufacturer, Model and version are now on consecutive fields
1 parent e7036af commit 6d2715d

29 files changed

Lines changed: 2260 additions & 1921 deletions

ardupilot_methodic_configurator/backend_filesystem.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,10 @@ def re_init(self, vehicle_dir: str, vehicle_type: str, blank_component_data: boo
121121
if not self.file_parameters:
122122
return # No files intermediate parameters files found, no need to continue, the rest needs them
123123

124+
fw_version = re_compile(r"[ _-]").split(self.fw_version, 1)[0]
124125
# Read ArduPilot parameter documentation
125-
xml_url = get_xml_url(vehicle_type, self.fw_version)
126-
fallback_xml_url = get_fallback_xml_url(vehicle_type, self.fw_version)
126+
xml_url = get_xml_url(vehicle_type, fw_version)
127+
fallback_xml_url = get_fallback_xml_url(vehicle_type, fw_version)
127128
xml_dir = get_xml_dir(vehicle_dir)
128129
self.doc_dict = parse_parameter_metadata(
129130
xml_url, xml_dir, PARAM_DEFINITION_XML_FILE, vehicle_type, TOOLTIP_MAX_LENGTH, fallback_xml_url

ardupilot_methodic_configurator/data_model_par_dict.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ def export_to_param(
255255
256256
"""
257257
formatted_params = self._format_params(file_format)
258-
with open(filename_out, "w", encoding="utf-8") as output_file:
258+
with open(filename_out, "w", encoding="utf-8", newline="\n") as output_file: # use Linux line endings even on windows
259259
if content_header:
260260
output_file.write("\n".join(content_header) + "\n")
261261
output_file.writelines(line + "\n" for line in formatted_params)

ardupilot_methodic_configurator/data_model_vehicle_components_base.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ def update_json_structure(self) -> None:
263263

264264
# Merge existing data onto default structure (preserves existing values)
265265
self._data = self._deep_merge_dicts(default_structure, self._data)
266+
self._data["Components"] = self._reorder_components(self._data.get("Components", {}))
266267
self._data["Program version"] = __version__
267268

268269
def _deep_merge_dicts(self, default: dict[str, Any], existing: dict[str, Any]) -> dict[str, Any]:
@@ -292,6 +293,63 @@ def _deep_merge_dicts(self, default: dict[str, Any], existing: dict[str, Any]) -
292293

293294
return result
294295

296+
def _reorder_components(self, existing_components: ComponentData) -> ComponentData:
297+
"""
298+
Reorder components according to the desired structure while preserving existing data.
299+
300+
Args:
301+
existing_components: The existing components dictionary
302+
303+
Returns:
304+
A new dictionary with components reordered according to the desired structure
305+
306+
"""
307+
desired_component_order = [
308+
"Flight Controller",
309+
"Frame",
310+
"Battery Monitor",
311+
"Battery",
312+
"ESC",
313+
"Motors",
314+
"Propellers",
315+
"GNSS Receiver",
316+
"RC Controller",
317+
"RC Transmitter",
318+
"RC Receiver",
319+
"Telemetry",
320+
]
321+
322+
# Create reordered components dict
323+
reordered_components = {}
324+
remaining_components = existing_components.copy()
325+
326+
# First, add components in the desired order
327+
for component_name in desired_component_order:
328+
if component_name in remaining_components:
329+
reordered_components[component_name] = remaining_components.pop(component_name)
330+
331+
# Then add any remaining unknown components at the end
332+
reordered_components.update(remaining_components)
333+
334+
# Second step: for each component, ensure Product fields are in correct order (Version before URL)
335+
for component_name, component_data in reordered_components.items():
336+
if "Product" in component_data and isinstance(component_data["Product"], dict):
337+
product = component_data["Product"]
338+
if "Version" in product and "URL" in product:
339+
# Create new ordered product dict
340+
ordered_product = {}
341+
# Add fields in desired order
342+
for field in ["Manufacturer", "Model", "Version", "URL"]:
343+
if field in product:
344+
ordered_product[field] = product[field]
345+
# Add any remaining fields
346+
for field, value in product.items():
347+
if field not in ordered_product:
348+
ordered_product[field] = value
349+
reordered_components[component_name]["Product"] = ordered_product
350+
351+
return reordered_components
352+
295353
def init_battery_chemistry(self) -> None:
296354
self._battery_chemistry = (
297355
self._data.get("Components", {}).get("Battery", {}).get("Specifications", {}).get("Chemistry", "")

ardupilot_methodic_configurator/vehicle_templates/ArduCopter/AirCar_v1/vehicle_components.json

Lines changed: 76 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
"Product": {
66
"Manufacturer": "CubePilot",
77
"Model": "CubeOrange",
8-
"URL": "https://www.robotshop.com/products/cubepilot-the-cube-orange-standard-set-ads-b-carrier-board",
9-
"Version": "1.0"
8+
"Version": "1.0",
9+
"URL": "https://www.robotshop.com/products/cubepilot-the-cube-orange-standard-set-ads-b-carrier-board"
1010
},
1111
"Firmware": {
1212
"Type": "ArduCopter",
@@ -21,81 +21,21 @@
2121
"Product": {
2222
"Manufacturer": "Aircar Technology and Aviation ",
2323
"Model": "prototype",
24-
"URL": "https://www.aircar.aero/",
25-
"Version": "v1"
24+
"Version": "v1",
25+
"URL": "https://www.aircar.aero/"
2626
},
2727
"Specifications": {
2828
"TOW min Kg": 320,
2929
"TOW max Kg": 500
3030
},
3131
"Notes": "Frame is custom, X type frame. Arm length is 2650mm."
3232
},
33-
"RC Controller": {
34-
"Product": {
35-
"Manufacturer": "",
36-
"Model": "",
37-
"URL": "",
38-
"Version": ""
39-
},
40-
"Firmware": {
41-
"Type": "",
42-
"Version": ""
43-
},
44-
"Notes": ""
45-
},
46-
"RC Transmitter": {
47-
"Product": {
48-
"Manufacturer": "",
49-
"Model": "",
50-
"URL": "",
51-
"Version": ""
52-
},
53-
"Firmware": {
54-
"Type": "",
55-
"Version": ""
56-
},
57-
"Notes": "integrated in RC controller"
58-
},
59-
"RC Receiver": {
60-
"Product": {
61-
"Manufacturer": "",
62-
"Model": "",
63-
"URL": "",
64-
"Version": ""
65-
},
66-
"Firmware": {
67-
"Type": "",
68-
"Version": ""
69-
},
70-
"FC Connection": {
71-
"Type": "RCin/SBUS",
72-
"Protocol": "All"
73-
},
74-
"Notes": "This receiver is on the vehicle and is connected to the flight controller"
75-
},
76-
"Telemetry": {
77-
"Product": {
78-
"Manufacturer": "",
79-
"Model": "",
80-
"URL": "",
81-
"Version": ""
82-
},
83-
"Firmware": {
84-
"Type": "",
85-
"Version": ""
86-
},
87-
"FC Connection": {
88-
"Type": "SERIAL1",
89-
"Protocol": "MAVLink2"
90-
},
91-
"Notes": ""
92-
},
9333
"Battery Monitor": {
9434
"Product": {
9535
"Manufacturer": "CubePilot",
9636
"Model": "HX4-06008",
97-
"URL": "https://docs.cubepilot.org/user-guides/autopilot/the-cube-user-manual#power-module-connection",
98-
"Version": "PB01A21"
37+
"Version": "PB01A21",
38+
"URL": "https://docs.cubepilot.org/user-guides/autopilot/the-cube-user-manual#power-module-connection"
9939
},
10040
"Firmware": {
10141
"Type": "",
@@ -111,8 +51,8 @@
11151
"Product": {
11252
"Manufacturer": "",
11353
"Model": "",
114-
"URL": "",
115-
"Version": ""
54+
"Version": "",
55+
"URL": ""
11656
},
11757
"Specifications": {
11858
"Chemistry": "LipoHV",
@@ -128,8 +68,8 @@
12868
"Product": {
12969
"Manufacturer": "",
13070
"Model": "",
131-
"URL": "",
132-
"Version": ""
71+
"Version": "",
72+
"URL": ""
13373
},
13474
"Firmware": {
13575
"Type": "",
@@ -145,8 +85,8 @@
14585
"Product": {
14686
"Manufacturer": "",
14787
"Model": "",
148-
"URL": "",
149-
"Version": ""
88+
"Version": "",
89+
"URL": ""
15090
},
15191
"Specifications": {
15292
"Poles": 14
@@ -157,8 +97,8 @@
15797
"Product": {
15898
"Manufacturer": "",
15999
"Model": "",
160-
"URL": "",
161-
"Version": ""
100+
"Version": "",
101+
"URL": ""
162102
},
163103
"Specifications": {
164104
"Diameter_inches": 52
@@ -169,8 +109,8 @@
169109
"Product": {
170110
"Manufacturer": "CubePilot",
171111
"Model": "Here 3",
172-
"URL": "https://docs.cubepilot.org/user-guides/here-3/here-3-manual",
173-
"Version": "1"
112+
"Version": "1",
113+
"URL": "https://docs.cubepilot.org/user-guides/here-3/here-3-manual"
174114
},
175115
"Firmware": {
176116
"Type": "UBlox",
@@ -181,6 +121,66 @@
181121
"Protocol": "DroneCAN"
182122
},
183123
"Notes": "uBlox M8P GNSS with a patch antenna."
124+
},
125+
"RC Controller": {
126+
"Product": {
127+
"Manufacturer": "",
128+
"Model": "",
129+
"Version": "",
130+
"URL": ""
131+
},
132+
"Firmware": {
133+
"Type": "",
134+
"Version": ""
135+
},
136+
"Notes": ""
137+
},
138+
"RC Transmitter": {
139+
"Product": {
140+
"Manufacturer": "",
141+
"Model": "",
142+
"Version": "",
143+
"URL": ""
144+
},
145+
"Firmware": {
146+
"Type": "",
147+
"Version": ""
148+
},
149+
"Notes": "integrated in RC controller"
150+
},
151+
"RC Receiver": {
152+
"Product": {
153+
"Manufacturer": "",
154+
"Model": "",
155+
"Version": "",
156+
"URL": ""
157+
},
158+
"Firmware": {
159+
"Type": "",
160+
"Version": ""
161+
},
162+
"FC Connection": {
163+
"Type": "RCin/SBUS",
164+
"Protocol": "All"
165+
},
166+
"Notes": "This receiver is on the vehicle and is connected to the flight controller"
167+
},
168+
"Telemetry": {
169+
"Product": {
170+
"Manufacturer": "",
171+
"Model": "",
172+
"Version": "",
173+
"URL": ""
174+
},
175+
"Firmware": {
176+
"Type": "",
177+
"Version": ""
178+
},
179+
"FC Connection": {
180+
"Type": "SERIAL1",
181+
"Protocol": "MAVLink2"
182+
},
183+
"Notes": ""
184184
}
185185
},
186186
"Program version": "2.0.1"

0 commit comments

Comments
 (0)