From e9ae0c66d9f180100130372c3197122ea42a0b5f Mon Sep 17 00:00:00 2001 From: andrekir Date: Sat, 5 Aug 2023 07:04:37 -0300 Subject: [PATCH] refactor: updates for 2.2 release reference https://github.com/meshtastic/protobufs/pull/368 --- .../mesh/repository/radio/MockInterface.kt | 3 - .../geeksville/mesh/service/MeshService.kt | 51 ++++++------ .../mesh/ui/DeviceSettingsFragment.kt | 71 ++++++++++------- .../config/NeighborInfoConfigItemList.kt | 79 +++++++++++++++++++ .../components/config/PowerConfigItemList.kt | 8 -- 5 files changed, 150 insertions(+), 62 deletions(-) create mode 100644 app/src/main/java/com/geeksville/mesh/ui/components/config/NeighborInfoConfigItemList.kt diff --git a/app/src/main/java/com/geeksville/mesh/repository/radio/MockInterface.kt b/app/src/main/java/com/geeksville/mesh/repository/radio/MockInterface.kt index 5ddaa07c2..7747b4109 100644 --- a/app/src/main/java/com/geeksville/mesh/repository/radio/MockInterface.kt +++ b/app/src/main/java/com/geeksville/mesh/repository/radio/MockInterface.kt @@ -178,9 +178,6 @@ class MockInterface(private val service: RadioInterfaceService) : Logging, IRadi MeshProtos.FromRadio.newBuilder().apply { myInfo = MeshProtos.MyNodeInfo.newBuilder().apply { myNodeNum = MY_NODE - messageTimeoutMsec = 5 * 60 * 1000 - firmwareVersion = "1.3.8" // Pretend to be running an older 1.3 version - maxChannels = 8 }.build() }, 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 4e8410f67..4c59442e6 100644 --- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt +++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt @@ -123,9 +123,10 @@ class MeshService : Service(), Logging { "com.geeksville.mesh.service.MeshService" ) - /** The minimmum firmware version we know how to talk to. We'll still be able to talk to 1.0 firmwares but only well enough to ask them to firmware update + /** The minimum firmware version we know how to talk to. We'll still be able + * to talk to 2.0 firmwares but only well enough to ask them to firmware update. */ - val minDeviceVersion = DeviceVersion("1.3.43") + val minDeviceVersion = DeviceVersion("2.0.21") } enum class ConnectionState { @@ -1156,6 +1157,7 @@ class MeshService : Service(), Logging { MeshProtos.FromRadio.CONFIG_FIELD_NUMBER -> handleDeviceConfig(proto.config) MeshProtos.FromRadio.MODULECONFIG_FIELD_NUMBER -> handleModuleConfig(proto.moduleConfig) MeshProtos.FromRadio.QUEUESTATUS_FIELD_NUMBER -> handleQueueStatus(proto.queueStatus) + MeshProtos.FromRadio.METADATA_FIELD_NUMBER -> handleMetadata(proto.metadata) else -> errormsg("Unexpected FromRadio variant") } } catch (ex: InvalidProtocolBufferException) { @@ -1265,6 +1267,7 @@ class MeshService : Service(), Logging { private var rawMyNodeInfo: MeshProtos.MyNodeInfo? = null + private var rawDeviceMetadata: MeshProtos.DeviceMetadata? = null /** Regenerate the myNodeInfo model. We call this twice. Once after we receive myNodeInfo from the device * and again after we have the node DB (which might allow us a better notion of our HwModel. @@ -1274,6 +1277,7 @@ class MeshService : Service(), Logging { if (myInfo != null) { val a = radioInterfaceService.getBondedDeviceAddress() val isBluetoothInterface = a != null && a.startsWith("x") + val firmwareVersion = rawDeviceMetadata?.firmwareVersion.orEmpty() val nodeNum = myInfo.myNodeNum // Note: can't use the normal property because myNodeInfo not yet setup @@ -1283,7 +1287,7 @@ class MeshService : Service(), Logging { val mi = with(myInfo) { MyNodeInfo( myNodeNum, - hasGps, + false, hwModelStr, firmwareVersion, firmwareUpdateFilename?.appLoad != null && firmwareUpdateFilename?.littlefs != null, @@ -1292,12 +1296,12 @@ class MeshService : Service(), Logging { DeviceVersion(firmwareVersion) ), currentPacketId and 0xffffffffL, - if (messageTimeoutMsec == 0) 5 * 60 * 1000 else messageTimeoutMsec, // constants from current device code + 5 * 60 * 1000, // constants from current device code minAppVersion, - maxChannels, - hasWifi, - channelUtilization, - airUtilTx + 8, + false, + 0f, + 0f, ) } newMyNodeInfo = mi @@ -1311,27 +1315,13 @@ class MeshService : Service(), Logging { /// Track types of devices and firmware versions in use GeeksvilleApplication.analytics.setUserInfo( DataPair("firmware", mi.firmwareVersion), - DataPair("has_gps", mi.hasGPS), DataPair("hw_model", mi.model), - DataPair("dev_error_count", myInfo.errorCount) ) - - if (myInfo.errorCode != MeshProtos.CriticalErrorCode.UNSPECIFIED && myInfo.errorCode != MeshProtos.CriticalErrorCode.NONE) { - GeeksvilleApplication.analytics.track( - "dev_error", - DataPair("code", myInfo.errorCode.number), - DataPair("address", myInfo.errorAddress), - - // We also include this info, because it is required to correctly decode address from the map file - DataPair("firmware", mi.firmwareVersion), - DataPair("hw_model", mi.model) - ) - } } } /** - * Update the nodeinfo (called from either new API version or the old one) + * Update MyNodeInfo (called from either new API version or the old one) */ private fun handleMyInfo(myInfo: MeshProtos.MyNodeInfo) { val packetToSave = MeshLog( @@ -1353,6 +1343,21 @@ class MeshService : Service(), Logging { } } + /** + * Update our DeviceMetadata + */ + private fun handleMetadata(metadata: MeshProtos.DeviceMetadata) { + val packetToSave = MeshLog( + UUID.randomUUID().toString(), + "DeviceMetadata", + System.currentTimeMillis(), + metadata.toString() + ) + insertMeshLog(packetToSave) + + rawDeviceMetadata = metadata + } + /// If we've received our initial config, our radio settings and all of our channels, send any queued packets and broadcast connected to clients private fun onHasSettings() { diff --git a/app/src/main/java/com/geeksville/mesh/ui/DeviceSettingsFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/DeviceSettingsFragment.kt index 896c94eb0..2721ba84c 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/DeviceSettingsFragment.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/DeviceSettingsFragment.kt @@ -86,6 +86,7 @@ import com.geeksville.mesh.ui.components.config.EditDeviceProfileDialog import com.geeksville.mesh.ui.components.config.ExternalNotificationConfigItemList import com.geeksville.mesh.ui.components.config.LoRaConfigItemList import com.geeksville.mesh.ui.components.config.MQTTConfigItemList +import com.geeksville.mesh.ui.components.config.NeighborInfoConfigItemList import com.geeksville.mesh.ui.components.config.NetworkConfigItemList import com.geeksville.mesh.ui.components.config.PacketResponseStateDialog import com.geeksville.mesh.ui.components.config.PositionConfigItemList @@ -121,26 +122,27 @@ class DeviceSettingsFragment(val node: NodeInfo) : ScreenFragment("Radio Configu } } -enum class ConfigDest(val title: String, val route: String, val config: ConfigType) { - DEVICE("Device", "device", ConfigType.DEVICE_CONFIG), - POSITION("Position", "position", ConfigType.POSITION_CONFIG), - POWER("Power", "power", ConfigType.POWER_CONFIG), - NETWORK("Network", "network", ConfigType.NETWORK_CONFIG), - DISPLAY("Display", "display", ConfigType.DISPLAY_CONFIG), - LORA("LoRa", "lora", ConfigType.LORA_CONFIG), - BLUETOOTH("Bluetooth", "bluetooth", ConfigType.BLUETOOTH_CONFIG); +enum class ConfigDest(val title: String, val route: String) { + DEVICE("Device", "device"), + POSITION("Position", "position"), + POWER("Power", "power"), + NETWORK("Network", "network"), + DISPLAY("Display", "display"), + LORA("LoRa", "lora"), + BLUETOOTH("Bluetooth", "bluetooth"); } -enum class ModuleDest(val title: String, val route: String, val config: ModuleConfigType) { - MQTT("MQTT", "mqtt", ModuleConfigType.MQTT_CONFIG), - SERIAL("Serial", "serial", ModuleConfigType.SERIAL_CONFIG), - EXTERNAL_NOTIFICATION("External Notification", "ext_not", ModuleConfigType.EXTNOTIF_CONFIG), - STORE_FORWARD("Store & Forward", "store_forward", ModuleConfigType.STOREFORWARD_CONFIG), - RANGE_TEST("Range Test", "range_test", ModuleConfigType.RANGETEST_CONFIG), - TELEMETRY("Telemetry", "telemetry", ModuleConfigType.TELEMETRY_CONFIG), - CANNED_MESSAGE("Canned Message", "canned_message", ModuleConfigType.CANNEDMSG_CONFIG), - AUDIO("Audio", "audio", ModuleConfigType.AUDIO_CONFIG), - REMOTE_HARDWARE("Remote Hardware", "remote_hardware", ModuleConfigType.REMOTEHARDWARE_CONFIG); +enum class ModuleDest(val title: String, val route: String) { + MQTT("MQTT", "mqtt"), + SERIAL("Serial", "serial"), + EXTERNAL_NOTIFICATION("External Notification", "ext_not"), + STORE_FORWARD("Store & Forward", "store_forward"), + RANGE_TEST("Range Test", "range_test"), + TELEMETRY("Telemetry", "telemetry"), + CANNED_MESSAGE("Canned Message", "canned_message"), + AUDIO("Audio", "audio"), + REMOTE_HARDWARE("Remote Hardware", "remote_hardware"), + NEIGHBOR_INFO("Neighbor Info", "neighbor_info"); } /** @@ -375,19 +377,19 @@ fun RadioConfigNavHost(node: NodeInfo, viewModel: UIViewModel = viewModel()) { channelList.clear() viewModel.getChannel(destNum, 0) } - is ConfigType -> { - viewModel.getConfig(destNum, configType.number) + is ConfigDest -> { + viewModel.getConfig(destNum, configType.ordinal) } - ModuleConfigType.CANNEDMSG_CONFIG -> { + ModuleDest.CANNED_MESSAGE -> { (packetResponseState as PacketResponseState.Loading).total = 2 viewModel.getCannedMessages(destNum) } - ModuleConfigType.EXTNOTIF_CONFIG -> { + ModuleDest.EXTERNAL_NOTIFICATION -> { (packetResponseState as PacketResponseState.Loading).total = 2 viewModel.getRingtone(destNum) } - is ModuleConfigType -> { - viewModel.getModuleConfig(destNum, configType.number) + is ModuleDest -> { + viewModel.getModuleConfig(destNum, configType.ordinal) } } }, @@ -651,6 +653,19 @@ fun RadioConfigNavHost(node: NodeInfo, viewModel: UIViewModel = viewModel()) { } ) } + composable("neighbor_info") { + NeighborInfoConfigItemList( + neighborInfoConfig = moduleConfig.neighborInfo, + enabled = connected, + focusManager = focusManager, + onSaveClicked = { neighborInfoInput -> + focusManager.clearFocus() + val config = moduleConfig { neighborInfo = neighborInfoInput } + viewModel.setModuleConfig(destNum, config) + moduleConfig = config + } + ) + } } } @@ -769,13 +784,13 @@ fun RadioSettingsScreen( item { PreferenceCategory(stringResource(R.string.device_settings)) } item { NavCard("User", enabled = enabled) { onRouteClick("USER") } } item { NavCard("Channels", enabled = enabled) { onRouteClick("CHANNELS") } } - items(ConfigDest.values()) { configs -> - NavCard(configs.title, enabled = enabled) { onRouteClick(configs.config) } + items(ConfigDest.values()) { config -> + NavCard(config.title, enabled = enabled) { onRouteClick(config) } } item { PreferenceCategory(stringResource(R.string.module_settings)) } - items(ModuleDest.values()) { modules -> - NavCard(modules.title, enabled = enabled) { onRouteClick(modules.config) } + items(ModuleDest.values()) { module -> + NavCard(module.title, enabled = enabled) { onRouteClick(module) } } if (isLocal) { diff --git a/app/src/main/java/com/geeksville/mesh/ui/components/config/NeighborInfoConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/components/config/NeighborInfoConfigItemList.kt new file mode 100644 index 000000000..25f60c5bf --- /dev/null +++ b/app/src/main/java/com/geeksville/mesh/ui/components/config/NeighborInfoConfigItemList.kt @@ -0,0 +1,79 @@ +package com.geeksville.mesh.ui.components.config + +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.text.KeyboardActions +import androidx.compose.material.Divider +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.focus.FocusManager +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.tooling.preview.Preview +import com.geeksville.mesh.ModuleConfigProtos +import com.geeksville.mesh.copy +import com.geeksville.mesh.ui.components.EditTextPreference +import com.geeksville.mesh.ui.components.PreferenceCategory +import com.geeksville.mesh.ui.components.PreferenceFooter +import com.geeksville.mesh.ui.components.SwitchPreference + +@Composable +fun NeighborInfoConfigItemList( + neighborInfoConfig: ModuleConfigProtos.ModuleConfig.NeighborInfoConfig, + enabled: Boolean, + focusManager: FocusManager, + onSaveClicked: (ModuleConfigProtos.ModuleConfig.NeighborInfoConfig) -> Unit, +) { + var neighborInfoInput by remember(neighborInfoConfig) { mutableStateOf(neighborInfoConfig) } + + LazyColumn( + modifier = Modifier.fillMaxSize() + ) { + item { PreferenceCategory(text = "Neighbor Info Config") } + + item { + SwitchPreference(title = "Neighbor Info enabled", + checked = neighborInfoInput.enabled, + enabled = enabled, + onCheckedChange = { + neighborInfoInput = neighborInfoInput.copy { this.enabled = it } + }) + } + item { Divider() } + + item { + EditTextPreference(title = "Update interval (seconds)", + value = neighborInfoInput.updateInterval, + enabled = enabled, + keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), + onValueChanged = { + neighborInfoInput = neighborInfoInput.copy { updateInterval = it } + }) + } + + item { + PreferenceFooter( + enabled = neighborInfoInput != neighborInfoConfig, + onCancelClicked = { + focusManager.clearFocus() + neighborInfoInput = neighborInfoConfig + }, + onSaveClicked = { onSaveClicked(neighborInfoInput) } + ) + } + } +} + +@Preview(showBackground = true) +@Composable +fun NeighborInfoConfigPreview(){ + NeighborInfoConfigItemList( + neighborInfoConfig = ModuleConfigProtos.ModuleConfig.NeighborInfoConfig.getDefaultInstance(), + enabled = true, + focusManager = LocalFocusManager.current, + onSaveClicked = { }, + ) +} diff --git a/app/src/main/java/com/geeksville/mesh/ui/components/config/PowerConfigItemList.kt b/app/src/main/java/com/geeksville/mesh/ui/components/config/PowerConfigItemList.kt index 2c8d9d296..0a94e15ab 100644 --- a/app/src/main/java/com/geeksville/mesh/ui/components/config/PowerConfigItemList.kt +++ b/app/src/main/java/com/geeksville/mesh/ui/components/config/PowerConfigItemList.kt @@ -68,14 +68,6 @@ fun PowerConfigItemList( onValueChanged = { powerInput = powerInput.copy { waitBluetoothSecs = it } }) } - item { - EditTextPreference(title = "Mesh SDS timeout (seconds)", - value = powerInput.meshSdsTimeoutSecs, - enabled = enabled, - keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus() }), - onValueChanged = { powerInput = powerInput.copy { meshSdsTimeoutSecs = it } }) - } - item { EditTextPreference(title = "Super deep sleep duration (seconds)", value = powerInput.sdsSecs,