diff --git a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt
index 81d64d0d7..56b093822 100644
--- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt
+++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt
@@ -2296,5 +2296,13 @@ class MeshService : Service() {
override fun requestNodedbReset(requestId: Int, destNum: Int) = toRemoteExceptions {
packetHandler.sendToRadio(newMeshPacketTo(destNum).buildAdminPacket(id = requestId) { nodedbReset = 1 })
}
+
+ override fun getDeviceConnectionStatus(requestId: Int, destNum: Int) = toRemoteExceptions {
+ packetHandler.sendToRadio(
+ newMeshPacketTo(destNum).buildAdminPacket(id = requestId, wantResponse = true) {
+ getDeviceConnectionStatusRequest = true
+ },
+ )
+ }
}
}
diff --git a/core/service/src/main/aidl/org/meshtastic/core/service/IMeshService.aidl b/core/service/src/main/aidl/org/meshtastic/core/service/IMeshService.aidl
index 13ab9cef7..754794ee5 100644
--- a/core/service/src/main/aidl/org/meshtastic/core/service/IMeshService.aidl
+++ b/core/service/src/main/aidl/org/meshtastic/core/service/IMeshService.aidl
@@ -170,4 +170,7 @@ interface IMeshService {
/// Send request for node UserInfo
void requestUserInfo(in int destNum);
+
+ /// Request device connection status from the radio
+ void getDeviceConnectionStatus(in int requestId, in int destNum);
}
diff --git a/core/strings/src/main/res/values/strings.xml b/core/strings/src/main/res/values/strings.xml
index c6be10f50..421442047 100644
--- a/core/strings/src/main/res/values/strings.xml
+++ b/core/strings/src/main/res/values/strings.xml
@@ -207,6 +207,9 @@
Port:
Connected
Connected to radio (%s)
+ Current connections:
+ Wifi IP:
+ Ethernet IP:
Not connected
Connected to radio, but it is sleeping
Application update required
diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/RadioConfigViewModel.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/RadioConfigViewModel.kt
index 946e7cddf..591338ea8 100644
--- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/RadioConfigViewModel.kt
+++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/RadioConfigViewModel.kt
@@ -71,6 +71,7 @@ import org.meshtastic.proto.ChannelProtos
import org.meshtastic.proto.ClientOnlyProtos.DeviceProfile
import org.meshtastic.proto.ConfigProtos
import org.meshtastic.proto.ConfigProtos.Config.SecurityConfig
+import org.meshtastic.proto.ConnStatusProtos
import org.meshtastic.proto.MeshProtos
import org.meshtastic.proto.ModuleConfigProtos
import org.meshtastic.proto.Portnums
@@ -93,6 +94,7 @@ data class RadioConfigState(
val moduleConfig: ModuleConfigProtos.ModuleConfig = moduleConfig {},
val ringtone: String = "",
val cannedMessageMessages: String = "",
+ val deviceConnectionStatus: ConnStatusProtos.DeviceConnectionStatus? = null,
val responseState: ResponseState = ResponseState.Empty,
val analyticsAvailable: Boolean = true,
val analyticsEnabled: Boolean = false,
@@ -329,6 +331,12 @@ constructor(
"Request getCannedMessages error",
)
+ private fun getDeviceConnectionStatus(destNum: Int) = request(
+ destNum,
+ { service, packetId, dest -> service.getDeviceConnectionStatus(packetId, dest) },
+ "Request getDeviceConnectionStatus error",
+ )
+
private fun requestShutdown(destNum: Int) = request(
destNum,
{ service, packetId, dest -> service.requestShutdown(packetId, dest) },
@@ -542,6 +550,9 @@ constructor(
if (route == ConfigRoute.LORA) {
getChannel(destNum, 0)
}
+ if (route == ConfigRoute.NETWORK) {
+ getDeviceConnectionStatus(destNum)
+ }
getConfig(destNum, route.type)
}
@@ -696,6 +707,13 @@ constructor(
incrementCompleted()
}
+ AdminProtos.AdminMessage.PayloadVariantCase.GET_DEVICE_CONNECTION_STATUS_RESPONSE -> {
+ _radioConfigState.update {
+ it.copy(deviceConnectionStatus = parsed.getDeviceConnectionStatusResponse)
+ }
+ incrementCompleted()
+ }
+
else -> Timber.d("No custom processing needed for ${parsed.payloadVariantCase}")
}
diff --git a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/NetworkConfigItemList.kt b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/NetworkConfigItemList.kt
index 19f57e50a..274f280ef 100644
--- a/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/NetworkConfigItemList.kt
+++ b/feature/settings/src/main/kotlin/org/meshtastic/feature/settings/radio/component/NetworkConfigItemList.kt
@@ -47,6 +47,7 @@ import org.meshtastic.core.ui.component.DropDownPreference
import org.meshtastic.core.ui.component.EditIPv4Preference
import org.meshtastic.core.ui.component.EditPasswordPreference
import org.meshtastic.core.ui.component.EditTextPreference
+import org.meshtastic.core.ui.component.ListItem
import org.meshtastic.core.ui.component.SimpleAlertDialog
import org.meshtastic.core.ui.component.SwitchPreference
import org.meshtastic.core.ui.component.TitledCard
@@ -110,6 +111,36 @@ fun NetworkConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBac
viewModel.setConfig(config)
},
) {
+ // Display device connection status
+ state.deviceConnectionStatus?.let { connectionStatus ->
+ if (
+ connectionStatus.wifi?.status?.isConnected == true ||
+ connectionStatus.ethernet?.status?.isConnected == true
+ ) {
+ item {
+ TitledCard(title = stringResource(R.string.connection_status)) {
+ connectionStatus.wifi?.let { wifiStatus ->
+ if (wifiStatus.status.isConnected) {
+ ListItem(
+ text = stringResource(R.string.wifi_ip),
+ supportingText = formatIpAddress(wifiStatus.status.ipAddress),
+ trailingIcon = null,
+ )
+ }
+ }
+ connectionStatus.ethernet?.let { ethernetStatus ->
+ if (ethernetStatus.status.isConnected) {
+ ListItem(
+ text = stringResource(R.string.ethernet_ip),
+ supportingText = formatIpAddress(ethernetStatus.status.ipAddress),
+ trailingIcon = null,
+ )
+ }
+ }
+ }
+ }
+ }
+ }
if (state.metadata?.hasWifi == true) {
item {
TitledCard(title = stringResource(R.string.wifi_config)) {
@@ -274,3 +305,9 @@ fun NetworkConfigScreen(viewModel: RadioConfigViewModel = hiltViewModel(), onBac
private fun extractWifiCredentials(qrCode: String) =
Regex("""WIFI:S:(.*?);.*?P:(.*?);""").find(qrCode)?.destructured?.let { (ssid, password) -> ssid to password }
?: (null to null)
+
+@Suppress("detekt:MagicNumber")
+private fun formatIpAddress(ipAddress: Int): String = "${(ipAddress) and 0xFF}." +
+ "${(ipAddress shr 8) and 0xFF}." +
+ "${(ipAddress shr 16) and 0xFF}." +
+ "${(ipAddress shr 24) and 0xFF}"