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
18 changes: 8 additions & 10 deletions lib/ai/providers/usp_command_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -364,16 +364,15 @@ class UspCommandProvider implements IRouterCommandProvider {
' - ${d['name']} (${d['ip']}) ${d['connectionType']} signal=${d['signalStrength']}');
}

// Mesh extenders (non-master nodes)
final extenders = data.nodeModels
.where((n) => !n.isMaster)
// Mesh extenders (slave nodes)
final extenders = data.slaves
.map((node) => {
'name': node.displayName,
'mac': node.deviceId,
'model': node.model,
'backhaulMediaType': node.backhaulMediaType,
'backhaulSignalStrength': node.backhaulSignalStrength,
'backhaulUplinkRate': node.backhaulUplinkRate,
'backhaulMediaType': node.backhaul.mediaType,
'backhaulSignalStrength': node.backhaul.signalStrength,
'backhaulUplinkRate': node.backhaul.uplinkRate,
})
.toList();

Expand Down Expand Up @@ -870,16 +869,15 @@ String buildRouterContext(ProviderReader read) {
buffer.writeln('- Currently online: ${devices.onlineClientCount}');
buffer.writeln();

// Mesh nodes (extenders)
final nodeModels = devices.nodeModels;
final extenders = nodeModels.where((n) => !n.isMaster).toList();
// Mesh nodes (slave extenders)
final extenders = devices.slaves;
if (extenders.isNotEmpty) {
_log('buildRouterContext: extenders=${extenders.length}');
buffer.writeln('## Mesh Extenders');
for (final ext in extenders) {
_log('buildRouterContext: - ${ext.displayName} (${ext.deviceId})');
buffer.writeln(
'- ${ext.displayName}: ${ext.model}, backhaul=${ext.backhaulMediaType}, rssi=${ext.backhaulSignalStrength ?? "N/A"}');
'- ${ext.displayName}: ${ext.model}, backhaul=${ext.backhaul.mediaType}, rssi=${ext.backhaul.signalStrength ?? "N/A"}');
}
buffer.writeln();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:privacy_gui/core/session/providers/session_provider.dart';
import 'package:privacy_gui/page/_shared/models/device_ui_model.dart';
import 'package:privacy_gui/page/devices/providers/devices_data_provider.dart';
import 'package:privacy_gui/core/cloud/providers/remote_assistance/remote_client_provider.dart';

Expand All @@ -17,18 +16,17 @@ final deviceCredentialsProvider = Provider<DeviceCredentials?>((ref) {
final deviceInfo = session.deviceInfo;
if (deviceInfo == null) return null;

// Get master node for MAC address (from nodeModels)
final masterNode =
devicesData.nodeModels.where((n) => n.isMaster).firstOrNull;
if (masterNode == null) return null;

// Get master device for hostsDeviceId (UUID) (from deviceModels)
final masterDevice = devicesData.deviceModels.masterNode;
if (masterDevice?.hostsDeviceId == null) return null;
// Get master node for MAC address and hostsDeviceId (UUID)
final master = devicesData.master;
// Master's hostsDeviceId comes from the Hosts table during MeshNetwork build.
// Guardian Remote Assistance requires the Hosts DeviceID/UUID, NOT the MAC —
// without it, session lookup / PIN creation would receive the wrong value.
final hostsDeviceId = master.hostsDeviceId;
if (hostsDeviceId == null || hostsDeviceId.isEmpty) return null;

return DeviceCredentials(
serialNumber: deviceInfo.serialNumber,
macAddress: masterNode.deviceId,
deviceUUID: masterDevice!.hostsDeviceId!,
macAddress: master.deviceId,
deviceUUID: hostsDeviceId,
);
});
10 changes: 0 additions & 10 deletions lib/page/_shared/extensions/device_ui_extensions.dart

This file was deleted.

77 changes: 77 additions & 0 deletions lib/page/_shared/models/backhaul_info.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import 'package:equatable/equatable.dart';

/// Backhaul connection info for slave mesh nodes.
///
/// Describes how a slave node connects to its parent (WiFi or Ethernet).
class BackhaulInfo with EquatableMixin {
/// Media type description, e.g., "IEEE 802.11ax", "Ethernet".
final String mediaType;

/// Link type: "Wi-Fi" or "Ethernet".
final String? linkType;

/// PHY rate in Mbps.
final int phyRate;

/// Signal strength in dBm (RSSI). Null for Ethernet backhaul.
final int? signalStrength;

/// Uplink data rate in kbps.
final int? uplinkRate;

/// Downlink data rate in kbps.
final int? downlinkRate;

/// Parent node's device ID (MAC).
final String? parentNodeId;

/// Parent node's BSSID the slave connects to.
final String? parentBssid;

/// Last contact time in ISO 8601 format.
final String? lastContactTime;

/// Raw AL ID from DataElements (parent node MAC).
final String? backhaulAlId;

/// Backhaul interface MAC address.
final String? backhaulMacAddress;

const BackhaulInfo({
required this.mediaType,
this.linkType,
this.phyRate = 0,
this.signalStrength,
this.uplinkRate,
this.downlinkRate,
this.parentNodeId,
this.parentBssid,
this.lastContactTime,
this.backhaulAlId,
this.backhaulMacAddress,
});

/// Whether the backhaul is Ethernet (wired).
bool get isEthernet => linkType == 'Ethernet';

/// Whether the backhaul is WiFi (wireless).
bool get isWifi => !isEthernet;

/// Whether backhaul info is available.
bool get hasInfo => mediaType.isNotEmpty;

@override
List<Object?> get props => [
mediaType,
linkType,
phyRate,
signalStrength,
uplinkRate,
downlinkRate,
parentNodeId,
parentBssid,
lastContactTime,
backhaulAlId,
backhaulMacAddress,
];
}
Loading
Loading