Skip to content

feat: USP WiFi settings, network diagnostics & codegen updates - #689

Closed
AustinChangLinksys wants to merge 2 commits into
dev-2.2.0from
feat/usp-m2-wifi-diagnostics
Closed

feat: USP WiFi settings, network diagnostics & codegen updates#689
AustinChangLinksys wants to merge 2 commits into
dev-2.2.0from
feat/usp-m2-wifi-diagnostics

Conversation

@AustinChangLinksys

Copy link
Copy Markdown
Collaborator

Summary

  • Add WiFi channel bonding service with comprehensive band/standard-aware logic for channel width and DFS support
  • Add network diagnostics YAML definition and generated code for ping/traceroute operations
  • Enhance WiFi settings UI with radio info integration, channel bonding, and network card improvements
  • Add PreservableNotifierMixin for state preservation across provider rebuilds
  • Comprehensive unit tests for WiFi channel bonding (268+ lines) and WiFi settings service (577+ lines)

Changes

  • New: definitions/network/network_diagnostics.yaml — ping/traceroute operate definitions
  • New: lib/usp_page/wifi_settings/services/wifi_channel_bonding.dart — band-aware channel width/DFS logic
  • New: lib/usp_page/wifi_settings/models/wifi_network_ui_model.dart — UI model for WiFi networks
  • Updated: wi_fi_radios.yaml — added subscribe block
  • Updated: WiFi settings provider/service/views — integrated radio info and channel bonding
  • Updated: Dashboard notifier — refined data fetch flow
  • Updated: USP service & WASM client — improved operate/response handling
  • Tests: wifi_channel_bonding_test.dart, usp_wifi_settings_service_test.dart

Test plan

  • Unit tests for WiFi channel bonding logic (all bands, standards, DFS scenarios)
  • Unit tests for WiFi settings service (fetch, save, radio integration)
  • Manual verification of WiFi settings page with real device
  • Verify network diagnostics (ping/traceroute) operate commands

🤖 Generated with Claude Code

- WiFi settings: channel bonding service, network card UI improvements,
  quick setup model, preservable notifier dirty-check integration
- Network diagnostics: YAML definition + codegen output
- WiFi radios: added SupportedOperatingChannelBandwidths field
- WAN operations: updated codegen output
- Dashboard notifier: bridge port map fetch, firmware images
- SSE operation awaiter & UspService: minor refinements
- Test console: updated for new client API
- Preservable notifier mixin: added generic save callback support
- Added unit tests for WiFi settings service and channel bonding

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@qodo-code-review

Copy link
Copy Markdown

Review Summary by Qodo

WiFi channel bonding, network diagnostics codegen, and USP response simplification

✨ Enhancement 🧪 Tests

Grey Divider

Walkthroughs

Description
• Add WiFi channel bonding service with IEEE 802.11 bonding rules for 2.4GHz/5GHz/6GHz bands
• Integrate SupportedOperatingChannelBandwidths field into WiFi radio model and UI
• Add network diagnostics YAML definition and generated code for ping/traceroute operations
• Simplify USP Operate response to flat map instead of wrapper class
• Enhance WiFi settings provider with auto-reset channel when bandwidth invalidates current
  selection
• Add comprehensive unit tests for channel bonding (268 lines) and WiFi settings service (577 lines)
Diagram
flowchart LR
  A["WiFi Radio Data<br/>PossibleChannels<br/>SupportedBandwidths"] -->|IEEE 802.11 Rules| B["Channel Bonding<br/>Utility"]
  B -->|Compute Map| C["ChannelsPerBandwidth<br/>Auto/20MHz/40MHz/80MHz"]
  C -->|Populate Model| D["WifiNetworkUIModel<br/>availableChannelsPerBandwidth"]
  D -->|Filter Options| E["WiFi Network Card<br/>Channel Selector"]
  F["Network Diagnostics<br/>YAML Definition"] -->|Codegen| G["NetworkDiagnostics<br/>Class"]
  G -->|Ping/Traceroute| H["USP Service<br/>Operate Command"]
  I["UspResponse Wrapper"] -->|Flatten| J["Map&lt;String, dynamic&gt;<br/>commandKey + outputs"]
Loading

Grey Divider

File Changes

1. lib/generated/network_diagnostics.g.dart Code generation +34/-0

Auto-generated network diagnostics operations code

lib/generated/network_diagnostics.g.dart


2. lib/generated/wan_operations.g.dart ✨ Enhancement +5/-4

Update DHCP renewal to return operation response map

lib/generated/wan_operations.g.dart


3. lib/generated/wi_fi_radios.g.dart ✨ Enhancement +8/-1

Add supportedOperatingChannelBandwidths field to WiFiRadio

lib/generated/wi_fi_radios.g.dart


View more (21)
4. lib/generated/index.dart Code generation +1/-0

Export network diagnostics generated code

lib/generated/index.dart


5. lib/usp/models/usp_response.dart Refactoring +0/-20

Remove UspResponse wrapper class entirely

lib/usp/models/usp_response.dart


6. lib/usp/services/usp_service.dart ✨ Enhancement +6/-6

Simplify operate method to return flat map

lib/usp/services/usp_service.dart


7. lib/usp/services/sse_operation_awaiter.dart ✨ Enhancement +1/-1

Update to access commandKey from flat map response

lib/usp/services/sse_operation_awaiter.dart


8. lib/usp/stub/usp_client_stub.dart ✨ Enhancement +1/-3

Update stub operate signature to return flat map

lib/usp/stub/usp_client_stub.dart


9. lib/usp/web/usp_client_wasm.dart ✨ Enhancement +13/-12

Flatten operate response to single map with commandKey

lib/usp/web/usp_client_wasm.dart


10. lib/usp_page/wifi_settings/services/wifi_channel_bonding.dart ✨ Enhancement +203/-0

New IEEE 802.11 channel bonding utility service

lib/usp_page/wifi_settings/services/wifi_channel_bonding.dart


11. lib/usp_page/wifi_settings/models/wifi_network_ui_model.dart ✨ Enhancement +29/-0

Add supportedBandwidths and availableChannelsPerBandwidth fields

lib/usp_page/wifi_settings/models/wifi_network_ui_model.dart


12. lib/usp_page/wifi_settings/services/usp_wifi_settings_service.dart ✨ Enhancement +28/-2

Integrate channel bonding computation into network building

lib/usp_page/wifi_settings/services/usp_wifi_settings_service.dart


13. lib/usp_page/wifi_settings/providers/usp_wifi_settings_provider.dart ✨ Enhancement +15/-1

Auto-reset channel to auto when bandwidth invalidates selection

lib/usp_page/wifi_settings/providers/usp_wifi_settings_provider.dart


14. lib/usp_page/wifi_settings/views/components/wifi_network_card.dart ✨ Enhancement +16/-6

Use dynamic supported bandwidths and per-bandwidth channel filtering

lib/usp_page/wifi_settings/views/components/wifi_network_card.dart


15. lib/usp_page/wifi_settings/views/tabs/wifi_list_tab.dart ✨ Enhancement +25/-21

Improve loading and error state handling in WiFi list

lib/usp_page/wifi_settings/views/tabs/wifi_list_tab.dart


16. lib/usp_page/dashboard/providers/usp_dashboard_notifier.dart ✨ Enhancement +13/-9

Add timeouts to async operations and use WanOperations helper

lib/usp_page/dashboard/providers/usp_dashboard_notifier.dart


17. lib/page/usp_test/usp_test_page.dart ✨ Enhancement +3/-3

Update test console to work with flat map response

lib/page/usp_test/usp_test_page.dart


18. lib/usp_page/test_console/views/usp_test_console_view.dart ✨ Enhancement +3/-3

Update test console to work with flat map response

lib/usp_page/test_console/views/usp_test_console_view.dart


19. lib/providers/preservable_notifier_mixin.dart 🐞 Bug fix +8/-0

Handle status-only updates when settings unavailable

lib/providers/preservable_notifier_mixin.dart


20. test/usp_page/wifi_settings/services/wifi_channel_bonding_test.dart 🧪 Tests +268/-0

Comprehensive unit tests for IEEE 802.11 bonding rules

test/usp_page/wifi_settings/services/wifi_channel_bonding_test.dart


21. test/usp_page/wifi_settings/services/usp_wifi_settings_service_test.dart 🧪 Tests +577/-0

Unit tests for WiFi settings service and network building

test/usp_page/wifi_settings/services/usp_wifi_settings_service_test.dart


22. definitions/network/network_diagnostics.yaml ⚙️ Configuration changes +33/-0

YAML definition for ping and traceroute operations

definitions/network/network_diagnostics.yaml


23. definitions/wifi/wi_fi_radios.yaml ⚙️ Configuration changes +5/-0

Add supportedOperatingChannelBandwidths parameter definition

definitions/wifi/wi_fi_radios.yaml


24. doc/usp/integration/roadmap_m2.md 📝 Documentation +101/-90

Update M2 roadmap with completed features and findings

doc/usp/integration/roadmap_m2.md


Grey Divider

Qodo Logo

@qodo-code-review

qodo-code-review Bot commented Mar 17, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (3) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Missing braces in ping() 📘 Rule violation ✓ Correctness
Description
The generated NetworkDiagnostics.ping() uses an if statement without curly braces, which is
likely to violate flutter_lints (e.g., curly_braces_in_flow_control_structures). This can cause
flutter analyze to fail for the PR.
Code

lib/generated/network_diagnostics.g.dart[R17-18]

+    if (numberOfRepetitions != null)
+      inputs['NumberOfRepetitions'] = numberOfRepetitions;
Evidence
analysis_options.yaml includes package:flutter_lints/flutter.yaml, and the newly added code
contains an if without braces, which commonly triggers flutter_lints failures.

CLAUDE.md
analysis_options.yaml[10-14]
lib/generated/network_diagnostics.g.dart[15-20]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The generated file `lib/generated/network_diagnostics.g.dart` contains an `if` statement without curly braces, which is likely to fail `flutter analyze` under `flutter_lints`.

## Issue Context
This file is marked as auto-generated, so fixing the generator/template is preferable to manual edits (otherwise the issue will return on the next codegen run).

## Fix Focus Areas
- lib/generated/network_diagnostics.g.dart[15-20]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Feature code under lib/usp_page 📘 Rule violation ⛯ Reliability
Description
New feature implementation files were added under lib/usp_page/... instead of the required feature
organization under lib/page/[feature_name]/. This violates the repository feature structure
requirement and makes navigation/ownership inconsistent with the documented layout.
Code

lib/usp_page/wifi_settings/services/wifi_channel_bonding.dart[R1-6]

+/// IEEE 802.11 channel bonding rules for computing valid primary channels
+/// per bandwidth.
+///
+/// This is a pure utility with no Flutter or provider dependencies.
+/// All group tables are IEEE 802.11 standard constants.
+
Evidence
The compliance checklist requires new feature code (pages and related code) to follow the
lib/page/[feature_name]/ organization, but this PR introduces new feature logic under
lib/usp_page/....

CLAUDE.md
lib/usp_page/wifi_settings/services/wifi_channel_bonding.dart[1-6]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New feature logic was added under `lib/usp_page/...`, but the compliance checklist requires new features to follow the documented structure under `lib/page/[feature_name]/` (with providers under `lib/providers/` and routes under `lib/route/`).

## Issue Context
This PR adds new feature behavior via a new bonding utility and associated model/provider changes; the placement should align with the repository’s documented organization (or the rule/docs need an explicit exception for `usp_page`).

## Fix Focus Areas
- lib/usp_page/wifi_settings/services/wifi_channel_bonding.dart[1-203]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Renew return type mismatch 🐞 Bug ✓ Correctness
Description
UspInternetSettingsService.renewDhcpLease() / renewDhcpv6Lease() are declared as Future<void>
but directly return WanOperations.renewDhcpLease() / renewDhcpv6Lease(), which now return
Future<Map<String,dynamic>>. This introduces a Dart static type error and will fail compilation
for USP Internet Settings.
Code

lib/generated/wan_operations.g.dart[R10-18]

+  static Future<Map<String, dynamic>> renewDhcpLease(UspService client) async {
+    return await client.operate('Device.DHCPv4.Client.1.Renew()');
  }

  /// Renew DHCPv6 WAN lease
-  static Future<void> renewDhcpv6Lease(UspService client) async {
-    await client.operate('Device.DHCPv6.Client.1.Renew()');
+  static Future<Map<String, dynamic>> renewDhcpv6Lease(
+      UspService client) async {
+    return await client.operate('Device.DHCPv6.Client.1.Renew()');
  }
Evidence
The generated WAN operations changed to return Future<Map<String,dynamic>>, but the Internet
Settings service still exposes Future<void> wrappers that return these futures directly, which is
not assignable in Dart.

lib/generated/wan_operations.g.dart[8-18]
lib/usp_page/internet_settings/services/usp_internet_settings_service.dart[89-93]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`WanOperations.renewDhcpLease()` and `renewDhcpv6Lease()` now return `Future&lt;Map&lt;String,dynamic&gt;&gt;`, but `UspInternetSettingsService.renewDhcpLease()` / `renewDhcpv6Lease()` still declare `Future&lt;void&gt;` and return the generated futures directly, which is a compile-time type error.

### Issue Context
Internet Settings UI/notifier code expects `Future&lt;void&gt;` semantics for renew operations.

### Fix Focus Areas
- lib/usp_page/internet_settings/services/usp_internet_settings_service.dart[89-93]

### Suggested change
Convert the wrappers to `async` and `await` the generated operations, ignoring the returned map:
```dart
Future&lt;void&gt; renewDhcpLease() async {
 await WanOperations.renewDhcpLease(_usp);
}

Future&lt;void&gt; renewDhcpv6Lease() async {
 await WanOperations.renewDhcpv6Lease(_usp);
}
```
(Alternatively, change wrapper + all callers to return/handle the `Map`.)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

4. New tests lack tags 📘 Rule violation ⛯ Reliability
Description
New WiFi unit tests were added without any tag categorization, despite the repository using a
tag-based approach (e.g., ui, loc) and the compliance requirement calling out tagged
categorization. This can make it harder to filter/target test suites in CI.
Code

test/usp_page/wifi_settings/services/wifi_channel_bonding_test.dart[R4-16]

+void main() {
+  group('computeChannelsPerBandwidth', () {
+    // -----------------------------------------------------------------------
+    // Edge cases
+    // -----------------------------------------------------------------------
+
+    test('returns empty map when possibleChannels is empty', () {
+      final result = computeChannelsPerBandwidth(
+        band: '5GHz',
+        possibleChannels: [],
+        supportedBandwidths: ['Auto', '20MHz', '40MHz'],
+      );
+      expect(result, isEmpty);
Evidence
The checklist requires tests to be categorized with appropriate tags when applicable; the new tests
are added with plain test(...) calls and no tags: configuration, while the repo already
demonstrates tag usage in its test helpers.

CLAUDE.md
test/usp_page/wifi_settings/services/wifi_channel_bonding_test.dart[4-16]
test/common/test_responsive_widget.dart[35-71]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New WiFi tests were added without tag categorization, but the compliance checklist expects tests to use the repository’s tag-based approach when applicable.

## Issue Context
The repository already demonstrates tag usage (e.g., `ui`, `loc`) in its testing utilities; adding tags to new tests improves CI filtering and test suite targeting.

## Fix Focus Areas
- test/usp_page/wifi_settings/services/wifi_channel_bonding_test.dart[4-268]
- test/usp_page/wifi_settings/services/usp_wifi_settings_service_test.dart[1-577]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Operate SSE miscorrelation 🐞 Bug ⛯ Reliability
Description
When the Operate response omits commandKey, SseOperationAwaiter falls back to correlating
OperationComplete events by commandName only. If two operations of the same command run
concurrently without a commandKey, the first completion can satisfy the wrong awaiter and the
other can timeout or report incorrect results.
Code

lib/usp/web/usp_client_wasm.dart[R159-179]

+  /// Returns a flat map containing:
+  ///   - `commandKey`: UUID correlator from the USP agent (may be absent)
+  ///   - all output arguments from the Operate response
+  Future<Map<String, dynamic>> operate(String command,
      {Map<String, String> args = const {}}) async {
    final result = await _client.operate(command, args.jsify()!).toDart;
-    if (result == null || result.isUndefinedOrNull) {
-      return UspResponse(data: {});
-    }
+    if (result == null || result.isUndefinedOrNull) return {};
    final map = result.dartify() as Map?;
-    if (map == null) return UspResponse(data: {});
+    if (map == null) return {};

+    final output = <String, dynamic>{};
    final commandKey = map['commandKey']?.toString();
+    if (commandKey != null && commandKey.isNotEmpty) {
+      output['commandKey'] = commandKey;
+    }
    final rawOutputArgs = map['outputArgs'];
-    final outputArgs = <String, String>{};
    if (rawOutputArgs is Map) {
      for (final entry in rawOutputArgs.entries) {
-        outputArgs[entry.key.toString()] = entry.value.toString();
+        output[entry.key.toString()] = entry.value.toString();
      }
    }
-
-    return UspResponse(data: outputArgs, commandKey: commandKey);
Evidence
The WASM client explicitly allows commandKey to be absent and only includes it in the returned map
when present/non-empty. The awaiter claims to support concurrent operations, but its fallback
matching uses only commandName, which is not unique across concurrent executions.

lib/usp/web/usp_client_wasm.dart[157-180]
lib/usp/services/sse_operation_awaiter.dart[24-106]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
`SseOperationAwaiter` correlates OperationComplete notifications to an in-flight operation using `commandKey` when available, but falls back to `commandName`-only matching when `commandKey` is absent. Since the Operate client contract allows `commandKey` to be absent, two concurrent operations of the same command can be mis-correlated.

### Issue Context
The awaiter explicitly claims to support concurrent operations via unique subscription IDs, but the fallback path ignores uniqueness.

### Fix Focus Areas
- lib/usp/services/sse_operation_awaiter.dart[72-115]
- lib/usp/web/usp_client_wasm.dart[157-180]

### Suggested fix direction
- Keep `commandKey` matching as the primary strategy.
- When `expectedKey` is null/empty, do **not** match by `commandName` alone.
 - Prefer matching on `notification.subscriptionId` against the per-operation subscription id created in `_sseBasedExecute` (and optionally also `commandName`).
 - If subscriptionId matching is not reliable in your SSE stream, then consider making `commandKey` mandatory in the Operate return contract (always include the key in the response map when present on the wire), or prevent concurrent executes of the same `operateCommand` when correlation cannot be made unique.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +17 to +18
if (numberOfRepetitions != null)
inputs['NumberOfRepetitions'] = numberOfRepetitions;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Missing braces in ping() 📘 Rule violation ✓ Correctness

The generated NetworkDiagnostics.ping() uses an if statement without curly braces, which is
likely to violate flutter_lints (e.g., curly_braces_in_flow_control_structures). This can cause
flutter analyze to fail for the PR.
Agent Prompt
## Issue description
The generated file `lib/generated/network_diagnostics.g.dart` contains an `if` statement without curly braces, which is likely to fail `flutter analyze` under `flutter_lints`.

## Issue Context
This file is marked as auto-generated, so fixing the generator/template is preferable to manual edits (otherwise the issue will return on the next codegen run).

## Fix Focus Areas
- lib/generated/network_diagnostics.g.dart[15-20]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +1 to +6
/// IEEE 802.11 channel bonding rules for computing valid primary channels
/// per bandwidth.
///
/// This is a pure utility with no Flutter or provider dependencies.
/// All group tables are IEEE 802.11 standard constants.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. Feature code under lib/usp_page 📘 Rule violation ⛯ Reliability

New feature implementation files were added under lib/usp_page/... instead of the required feature
organization under lib/page/[feature_name]/. This violates the repository feature structure
requirement and makes navigation/ownership inconsistent with the documented layout.
Agent Prompt
## Issue description
New feature logic was added under `lib/usp_page/...`, but the compliance checklist requires new features to follow the documented structure under `lib/page/[feature_name]/` (with providers under `lib/providers/` and routes under `lib/route/`).

## Issue Context
This PR adds new feature behavior via a new bonding utility and associated model/provider changes; the placement should align with the repository’s documented organization (or the rule/docs need an explicit exception for `usp_page`).

## Fix Focus Areas
- lib/usp_page/wifi_settings/services/wifi_channel_bonding.dart[1-203]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +10 to 18
static Future<Map<String, dynamic>> renewDhcpLease(UspService client) async {
return await client.operate('Device.DHCPv4.Client.1.Renew()');
}

/// Renew DHCPv6 WAN lease
static Future<void> renewDhcpv6Lease(UspService client) async {
await client.operate('Device.DHCPv6.Client.1.Renew()');
static Future<Map<String, dynamic>> renewDhcpv6Lease(
UspService client) async {
return await client.operate('Device.DHCPv6.Client.1.Renew()');
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

3. Renew return type mismatch 🐞 Bug ✓ Correctness

UspInternetSettingsService.renewDhcpLease() / renewDhcpv6Lease() are declared as Future<void>
but directly return WanOperations.renewDhcpLease() / renewDhcpv6Lease(), which now return
Future<Map<String,dynamic>>. This introduces a Dart static type error and will fail compilation
for USP Internet Settings.
Agent Prompt
### Issue description
`WanOperations.renewDhcpLease()` and `renewDhcpv6Lease()` now return `Future<Map<String,dynamic>>`, but `UspInternetSettingsService.renewDhcpLease()` / `renewDhcpv6Lease()` still declare `Future<void>` and return the generated futures directly, which is a compile-time type error.

### Issue Context
Internet Settings UI/notifier code expects `Future<void>` semantics for renew operations.

### Fix Focus Areas
- lib/usp_page/internet_settings/services/usp_internet_settings_service.dart[89-93]

### Suggested change
Convert the wrappers to `async` and `await` the generated operations, ignoring the returned map:
```dart
Future<void> renewDhcpLease() async {
  await WanOperations.renewDhcpLease(_usp);
}

Future<void> renewDhcpv6Lease() async {
  await WanOperations.renewDhcpv6Lease(_usp);
}
```
(Alternatively, change wrapper + all callers to return/handle the `Map`.)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Remove obsolete UspResponse import and use Map<String, dynamic>
to match the current UspService.operate() signature.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@AustinChangLinksys

Copy link
Copy Markdown
Collaborator Author

Close and re-create again with other changes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant