Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion USECASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@ If something is not clear, read the [ArduPilot Methodic Configurator user manual
1. Select the vehicle template that better resembles your vehicle.
![AMC template selection1](images/App_screenshot_Vehicle_directory_vehicle_params0.png)
![AMC template selection2](images/App_screenshot_Vehicle_overview.png)
1. **select the `Use parameter values from connected FC, not from template files` checkbox**
1. **select the `Infer component specifications and FC connections from FC Parameters, not from template files`
and the `Use parameter values from connected FC, not from template files` checkboxes**
![AMC template selection1](images/App_screenshot_Vehicle_directory_vehicle_params1.png)
1. Give a name to your vehicle.
![AMC new vehicle name](images/App_screenshot_Vehicle_directory_vehicle_params2.png)
Expand Down
4 changes: 3 additions & 1 deletion ardupilot_methodic_configurator/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,9 @@ def initialize_filesystem(state: ApplicationState) -> None:

# Write parameter default values if available
if state.param_default_values:
state.param_default_values_dirty = state.local_filesystem.write_param_default_values(state.param_default_values)
state.param_default_values_dirty = state.local_filesystem.set_param_default_values_if_different(
state.param_default_values
)


def initialize_flight_controller_and_filesystem(state: ApplicationState) -> None:
Expand Down
19 changes: 14 additions & 5 deletions ardupilot_methodic_configurator/backend_filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -984,17 +984,26 @@ def merge_forced_or_derived_parameters(
dest[param_name] = param
return at_least_one_param_changed

def write_param_default_values(self, param_default_values: ParDict) -> bool:
def set_param_default_values_if_different(self, param_default_values: ParDict) -> bool:
"""
Set the default parameter values if they are different from the current ones.

Args: param_default_values: A ParDict containing the default parameter values to compare against the current ones.
Returns: bool: True if the default parameter values were updated, False if they were the same as the current ones.
Comment thread
amilcarlucas marked this conversation as resolved.
"""
param_default_values = ParDict(dict(sorted(param_default_values.items())))
if self.param_default_dict != param_default_values:
self.param_default_dict = param_default_values
return True
return False

def write_param_default_values_to_file(self, param_default_values: ParDict, filename: str = "00_default.param") -> None:
if self.write_param_default_values(param_default_values):
self.file_parameters[filename] = param_default_values
self.param_default_dict.export_to_param(os_path.join(self.vehicle_dir, filename))
def write_param_default_values_to_file(
self, param_default_values: ParDict, filename: str = "00_default.param", vehicle_dir: str = ""
) -> None:
if self.set_param_default_values_if_different(param_default_values):
if len(vehicle_dir) == 0:
vehicle_dir = self.vehicle_dir
Comment on lines +1001 to +1005

Copilot AI Apr 27, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using an empty string sentinel plus len(vehicle_dir) == 0 is brittle and non-idiomatic. Prefer vehicle_dir: Optional[str] = None (or a Path | None) and a simple vehicle_dir = vehicle_dir or self.vehicle_dir check; this also avoids a hard failure if a caller ever passes None.

Suggested change
self, param_default_values: ParDict, filename: str = "00_default.param", vehicle_dir: str = ""
) -> None:
if self.set_param_default_values_if_different(param_default_values):
if len(vehicle_dir) == 0:
vehicle_dir = self.vehicle_dir
self, param_default_values: ParDict, filename: str = "00_default.param", vehicle_dir: Optional[str] = None
) -> None:
if self.set_param_default_values_if_different(param_default_values):
vehicle_dir = vehicle_dir or self.vehicle_dir

Copilot uses AI. Check for mistakes.
self.param_default_dict.export_to_param(os_path.join(vehicle_dir, filename))

@staticmethod
def _safe_path_join(base_dir: str, untrusted_path: str) -> str:
Expand Down
3 changes: 2 additions & 1 deletion tests/test__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,7 +354,7 @@ def test_user_can_initialize_with_connected_hardware(
mock_fc_info = MagicMock()
mock_fc_info.get_param_default_values.return_value = default_params
mock_fc_window.return_value = mock_fc_info
mock_local_filesystem.write_param_default_values.return_value = True
mock_local_filesystem.set_param_default_values_if_different.return_value = True

# Act: User initializes with connected hardware
initialize_flight_controller_and_filesystem(application_state)
Expand All @@ -364,6 +364,7 @@ def test_user_can_initialize_with_connected_hardware(
assert application_state.vehicle_type == "ArduCopter"
assert application_state.local_filesystem is mock_local_filesystem
assert application_state.param_default_values == default_params
mock_local_filesystem.set_param_default_values_if_different.assert_called_once_with(default_params)
assert application_state.param_default_values_dirty is True

def test_user_can_work_in_simulation_mode(self, application_state: ApplicationState) -> None:
Expand Down
6 changes: 3 additions & 3 deletions tests/test_backend_filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -580,19 +580,19 @@ def test_tolerance_check_with_zero_values(self) -> None:
assert result == test_filename
mock_file.assert_called_once_with(expected_path, encoding="utf-8")

def test_write_param_default_values(self) -> None:
def test_set_param_default_values_if_different(self) -> None:
lfs = LocalFilesystem(
"vehicle_dir", "vehicle_type", None, allow_editing_template_files=False, save_component_to_system_templates=False
)

# Test with new values
new_values = {"PARAM1": MagicMock(value=1.0)}
result = lfs.write_param_default_values(new_values)
result = lfs.set_param_default_values_if_different(new_values)
assert result is True
assert lfs.param_default_dict == new_values

# Test with same values (no change)
result = lfs.write_param_default_values(new_values)
result = lfs.set_param_default_values_if_different(new_values)
assert result is False

def test_get_start_file(self) -> None:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_data_model_vehicle_project.py
Original file line number Diff line number Diff line change
Expand Up @@ -1080,7 +1080,7 @@ def test_user_can_create_project_from_bin_log_successfully(self) -> None:
assert kwargs.get("fc_connected") is False
# Assert: vehicle directory opened immediately after creation
mock_open.assert_called_once_with("/vehicles/my_flight")
# Assert: extracted defaults written (replacing the template's 00_default.param)
# Assert: extracted defaults written (target path/filename come from LocalFilesystem state after re_init)
mock_write.assert_called_once_with(fake_defaults)

def test_bin_log_defaults_are_written_to_vehicle_directory(self) -> None:
Expand Down
Loading