diff --git a/Meshtastic/Enums/DeviceRoles.swift b/Meshtastic/Enums/DeviceRoles.swift index c1e8d18c..f0c2876f 100644 --- a/Meshtastic/Enums/DeviceRoles.swift +++ b/Meshtastic/Enums/DeviceRoles.swift @@ -14,8 +14,29 @@ enum DeviceRoles: Int, CaseIterable, Identifiable { case clientMute = 1 case router = 2 case routerClient = 3 + case repeater = 4 + case tracker = 5 var id: Int { self.rawValue } + var name: String { + get { + switch self { + + case .client: + return "Client" + case .clientMute: + return "Muted Client" + case .router: + return "Router" + case .routerClient: + return "Router & Client" + case .repeater: + return "Repeater" + case .tracker: + return "Tracker" + } + } + } var description: String { get { switch self { @@ -28,6 +49,10 @@ enum DeviceRoles: Int, CaseIterable, Identifiable { return NSLocalizedString("device.role.router", comment: "Router - Mesh packets will prefer to be routed over this node. This node will not be used by client apps. The wifi/ble radios and the oled screen will be put to sleep.") case .routerClient: return NSLocalizedString("device.role.routerclient", comment: "Router Client - Mesh packets will prefer to be routed over this node. The Router Client can be used as both a Router and an app connected Client.") + case .repeater: + return "Mesh packets will simply be rebroadcasted over this node. Nodes configured with this role will not originate NodeInfo, Position, Telemetry or any other packet type. They will simply rebroadcast any mesh packets on the same frequency, channel num, spread factor, and coding rate." + case .tracker: + return "Position Mesh packets will be prioritized higher and sent more frequently by default." } } } @@ -43,6 +68,10 @@ enum DeviceRoles: Int, CaseIterable, Identifiable { return Config.DeviceConfig.Role.router case .routerClient: return Config.DeviceConfig.Role.routerClient + case .repeater: + return Config.DeviceConfig.Role.repeater + case .tracker: + return Config.DeviceConfig.Role.tracker } } } diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index f9335922..5370b12b 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -1419,10 +1419,62 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject { let messageDescription = "πŸ›ŽοΈ Requested Bluetooth Config on admin channel \(adminIndex) for node: \(String(connectedPeripheral.num))" if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) { - return true } + return false + } + + public func requestDeviceConfig(fromUser: UserEntity, toUser: UserEntity, adminIndex: Int32) -> Bool { + var adminPacket = AdminMessage() + adminPacket.getConfigRequest = AdminMessage.ConfigType.deviceConfig + + var meshPacket: MeshPacket = MeshPacket() + meshPacket.to = UInt32(toUser.num) + meshPacket.from = UInt32(fromUser.num) + meshPacket.id = UInt32.random(in: UInt32(UInt8.max).. Bool { + + var adminPacket = AdminMessage() + adminPacket.getConfigRequest = AdminMessage.ConfigType.displayConfig + + var meshPacket: MeshPacket = MeshPacket() + meshPacket.to = UInt32(toUser.num) + meshPacket.from = UInt32(fromUser.num) + meshPacket.id = UInt32.random(in: UInt32(UInt8.max).. Bool { + + var adminPacket = AdminMessage() + adminPacket.getConfigRequest = AdminMessage.ConfigType.networkConfig + + var meshPacket: MeshPacket = MeshPacket() + meshPacket.to = UInt32(toUser.num) + meshPacket.from = UInt32(fromUser.num) + meshPacket.id = UInt32.random(in: UInt32(UInt8.max).. Bool { + + var adminPacket = AdminMessage() + adminPacket.getConfigRequest = AdminMessage.ConfigType.positionConfig + + var meshPacket: MeshPacket = MeshPacket() + meshPacket.to = UInt32(toUser.num) + meshPacket.from = UInt32(fromUser.num) + meshPacket.id = UInt32.random(in: UInt32(UInt8.max).. Int64 { var adminPacket = AdminMessage() @@ -1499,12 +1603,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject { meshPacket.decoded = dataMessage let messageDescription = "Saved WiFi Config for \(toUser.longName ?? NSLocalizedString("unknown", comment: "Unknown"))" - if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) { - return Int64(meshPacket.id) } - return 0 } diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index e98df340..9c58e2f3 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -40,11 +40,11 @@ func localConfig (config: Config, context:NSManagedObjectContext, nodeNum: Int64 // We don't care about any of the Power settings, config is available for everything else if config.payloadVariant == Config.OneOf_PayloadVariant.bluetooth(config.bluetooth) { - upsertBluetoothConfigPacket(config: config, nodeNum: nodeNum, context: context) + upsertBluetoothConfigPacket(config: config.bluetooth, nodeNum: nodeNum, context: context) } else if config.payloadVariant == Config.OneOf_PayloadVariant.device(config.device) { - upsertDeviceConfigPacket(config: config, nodeNum: nodeNum, context: context) + upsertDeviceConfigPacket(config: config.device, nodeNum: nodeNum, context: context) } else if config.payloadVariant == Config.OneOf_PayloadVariant.display(config.display) { - upsertDisplayConfigPacket(config: config, nodeNum: nodeNum, context: context) + upsertDisplayConfigPacket(config: config.display, nodeNum: nodeNum, context: context) } else if config.payloadVariant == Config.OneOf_PayloadVariant.lora(config.lora) { upsertLoRaConfigPacket(config: config.lora, nodeNum: nodeNum, context: context) } else if config.payloadVariant == Config.OneOf_PayloadVariant.network(config.network) { @@ -800,26 +800,24 @@ func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) { deviceMetadataPacket(metadata: adminMessage.getDeviceMetadataResponse, fromNum: Int64(packet.from), context: context) } else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getConfigResponse(adminMessage.getConfigResponse) { - if let config = try? Config(serializedData: packet.decoded.payload) { + + let config = adminMessage.getConfigResponse + + if config.payloadVariant == Config.OneOf_PayloadVariant.bluetooth(config.bluetooth) { + upsertBluetoothConfigPacket(config: config.bluetooth, nodeNum: Int64(packet.from), context: context) - if config.payloadVariant == Config.OneOf_PayloadVariant.bluetooth(config.bluetooth) { - upsertBluetoothConfigPacket(config: config, nodeNum: Int64(packet.from), context: context) - - } else if config.payloadVariant == Config.OneOf_PayloadVariant.device(config.device) { - upsertDeviceConfigPacket(config: config, nodeNum: Int64(packet.from), context: context) - - } else if config.payloadVariant == Config.OneOf_PayloadVariant.lora(config.lora) { - - let lc = try? Config.LoRaConfig(serializedData: packet.decoded.payload) - upsertLoRaConfigPacket(config: lc!, nodeNum: Int64(packet.from), context: context) - - } else if config.payloadVariant == Config.OneOf_PayloadVariant.network(config.network) { - upsertNetworkConfigPacket(config: config, nodeNum: Int64(packet.from), context: context) - - } else if config.payloadVariant == Config.OneOf_PayloadVariant.position(config.position) { - upsertPositionConfigPacket(config: config, nodeNum: Int64(packet.from), context: context) - - } + } else if config.payloadVariant == Config.OneOf_PayloadVariant.device(config.device) { + upsertDeviceConfigPacket(config: config.device, nodeNum: Int64(packet.from), context: context) + + } else if config.payloadVariant == Config.OneOf_PayloadVariant.lora(config.lora) { + upsertLoRaConfigPacket(config: config.lora, nodeNum: Int64(packet.from), context: context) + + } else if config.payloadVariant == Config.OneOf_PayloadVariant.network(config.network) { + upsertNetworkConfigPacket(config: config, nodeNum: Int64(packet.from), context: context) + + } else if config.payloadVariant == Config.OneOf_PayloadVariant.position(config.position) { + upsertPositionConfigPacket(config: config, nodeNum: Int64(packet.from), context: context) + } } else { MeshLogger.log("πŸ•ΈοΈ MESH PACKET received for Admin App \(try! packet.decoded.jsonString())") diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index 77eda04e..24bf4868 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -159,7 +159,7 @@ func upsertPositionPacket (packet: MeshPacket, context: NSManagedObjectContext) } } -func upsertBluetoothConfigPacket(config: Config, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertBluetoothConfigPacket(config: Meshtastic.Config.BluetoothConfig, nodeNum: Int64, context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.bluetooth.config %@", comment: "Bluetooth config received: %@"), String(nodeNum)) MeshLogger.log("πŸ“Ά \(logString)") @@ -174,14 +174,14 @@ func upsertBluetoothConfigPacket(config: Config, nodeNum: Int64, context: NSMana if !fetchedNode.isEmpty { if fetchedNode[0].bluetoothConfig == nil { let newBluetoothConfig = BluetoothConfigEntity(context: context) - newBluetoothConfig.enabled = config.bluetooth.enabled - newBluetoothConfig.mode = Int32(config.bluetooth.mode.rawValue) - newBluetoothConfig.fixedPin = Int32(config.bluetooth.fixedPin) + newBluetoothConfig.enabled = config.enabled + newBluetoothConfig.mode = Int32(config.mode.rawValue) + newBluetoothConfig.fixedPin = Int32(config.fixedPin) fetchedNode[0].bluetoothConfig = newBluetoothConfig } else { - fetchedNode[0].bluetoothConfig?.enabled = config.bluetooth.enabled - fetchedNode[0].bluetoothConfig?.mode = Int32(config.bluetooth.mode.rawValue) - fetchedNode[0].bluetoothConfig?.fixedPin = Int32(config.bluetooth.fixedPin) + fetchedNode[0].bluetoothConfig?.enabled = config.enabled + fetchedNode[0].bluetoothConfig?.mode = Int32(config.mode.rawValue) + fetchedNode[0].bluetoothConfig?.fixedPin = Int32(config.fixedPin) } do { try context.save() @@ -200,7 +200,7 @@ func upsertBluetoothConfigPacket(config: Config, nodeNum: Int64, context: NSMana } } -func upsertDeviceConfigPacket(config: Config, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertDeviceConfigPacket(config: Meshtastic.Config.DeviceConfig, nodeNum: Int64, context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.device.config %@", comment: "Device config received: %@"), String(nodeNum)) MeshLogger.log("πŸ“Ÿ \(logString)") @@ -214,18 +214,18 @@ func upsertDeviceConfigPacket(config: Config, nodeNum: Int64, context: NSManaged if !fetchedNode.isEmpty { if fetchedNode[0].deviceConfig == nil { let newDeviceConfig = DeviceConfigEntity(context: context) - newDeviceConfig.role = Int32(config.device.role.rawValue) - newDeviceConfig.serialEnabled = config.device.serialEnabled - newDeviceConfig.debugLogEnabled = config.device.debugLogEnabled - newDeviceConfig.buttonGpio = Int32(config.device.buttonGpio) - newDeviceConfig.buzzerGpio = Int32(config.device.buzzerGpio) + newDeviceConfig.role = Int32(config.role.rawValue) + newDeviceConfig.serialEnabled = config.serialEnabled + newDeviceConfig.debugLogEnabled = config.debugLogEnabled + newDeviceConfig.buttonGpio = Int32(config.buttonGpio) + newDeviceConfig.buzzerGpio = Int32(config.buzzerGpio) fetchedNode[0].deviceConfig = newDeviceConfig } else { - fetchedNode[0].deviceConfig?.role = Int32(config.device.role.rawValue) - fetchedNode[0].deviceConfig?.serialEnabled = config.device.serialEnabled - fetchedNode[0].deviceConfig?.debugLogEnabled = config.device.debugLogEnabled - fetchedNode[0].deviceConfig?.buttonGpio = Int32(config.device.buttonGpio) - fetchedNode[0].deviceConfig?.buzzerGpio = Int32(config.device.buzzerGpio) + fetchedNode[0].deviceConfig?.role = Int32(config.role.rawValue) + fetchedNode[0].deviceConfig?.serialEnabled = config.serialEnabled + fetchedNode[0].deviceConfig?.debugLogEnabled = config.debugLogEnabled + fetchedNode[0].deviceConfig?.buttonGpio = Int32(config.buttonGpio) + fetchedNode[0].deviceConfig?.buzzerGpio = Int32(config.buzzerGpio) } do { try context.save() @@ -242,7 +242,7 @@ func upsertDeviceConfigPacket(config: Config, nodeNum: Int64, context: NSManaged } } -func upsertDisplayConfigPacket(config: Config, nodeNum: Int64, context: NSManagedObjectContext) { +func upsertDisplayConfigPacket(config: Meshtastic.Config.DisplayConfig, nodeNum: Int64, context: NSManagedObjectContext) { let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.display.config %@", comment: "Display config received: %@"), String(nodeNum)) MeshLogger.log("πŸ–₯️ \(logString)") @@ -260,24 +260,24 @@ func upsertDisplayConfigPacket(config: Config, nodeNum: Int64, context: NSManage if fetchedNode[0].displayConfig == nil { let newDisplayConfig = DisplayConfigEntity(context: context) - newDisplayConfig.gpsFormat = Int32(config.display.gpsFormat.rawValue) - newDisplayConfig.screenOnSeconds = Int32(config.display.screenOnSecs) - newDisplayConfig.screenCarouselInterval = Int32(config.display.autoScreenCarouselSecs) - newDisplayConfig.compassNorthTop = config.display.compassNorthTop - newDisplayConfig.flipScreen = config.display.flipScreen - newDisplayConfig.oledType = Int32(config.display.oled.rawValue) - newDisplayConfig.displayMode = Int32(config.display.displaymode.rawValue) + newDisplayConfig.gpsFormat = Int32(config.gpsFormat.rawValue) + newDisplayConfig.screenOnSeconds = Int32(config.screenOnSecs) + newDisplayConfig.screenCarouselInterval = Int32(config.autoScreenCarouselSecs) + newDisplayConfig.compassNorthTop = config.compassNorthTop + newDisplayConfig.flipScreen = config.flipScreen + newDisplayConfig.oledType = Int32(config.oled.rawValue) + newDisplayConfig.displayMode = Int32(config.displaymode.rawValue) fetchedNode[0].displayConfig = newDisplayConfig } else { - fetchedNode[0].displayConfig?.gpsFormat = Int32(config.display.gpsFormat.rawValue) - fetchedNode[0].displayConfig?.screenOnSeconds = Int32(config.display.screenOnSecs) - fetchedNode[0].displayConfig?.screenCarouselInterval = Int32(config.display.autoScreenCarouselSecs) - fetchedNode[0].displayConfig?.compassNorthTop = config.display.compassNorthTop - fetchedNode[0].displayConfig?.flipScreen = config.display.flipScreen - fetchedNode[0].displayConfig?.oledType = Int32(config.display.oled.rawValue) - fetchedNode[0].displayConfig?.displayMode = Int32(config.display.displaymode.rawValue) + fetchedNode[0].displayConfig?.gpsFormat = Int32(config.gpsFormat.rawValue) + fetchedNode[0].displayConfig?.screenOnSeconds = Int32(config.screenOnSecs) + fetchedNode[0].displayConfig?.screenCarouselInterval = Int32(config.autoScreenCarouselSecs) + fetchedNode[0].displayConfig?.compassNorthTop = config.compassNorthTop + fetchedNode[0].displayConfig?.flipScreen = config.flipScreen + fetchedNode[0].displayConfig?.oledType = Int32(config.oled.rawValue) + fetchedNode[0].displayConfig?.displayMode = Int32(config.displaymode.rawValue) } do { diff --git a/Meshtastic/Views/Settings/Config/BluetoothConfig.swift b/Meshtastic/Views/Settings/Config/BluetoothConfig.swift index ffeb291d..1d2f5ec3 100644 --- a/Meshtastic/Views/Settings/Config/BluetoothConfig.swift +++ b/Meshtastic/Views/Settings/Config/BluetoothConfig.swift @@ -14,7 +14,6 @@ struct BluetoothConfig: View { @Environment(\.dismiss) private var goBack var node: NodeInfoEntity? - var connectedNode: NodeInfoEntity? @State private var isPresentingSaveConfirm: Bool = false @State var hasChanges = false @@ -80,7 +79,7 @@ struct BluetoothConfig: View { } } } - .disabled(bleManager.connectedPeripheral == nil) + .disabled(self.bleManager.connectedPeripheral == nil || node?.loRaConfig == nil) Button { isPresentingSaveConfirm = true @@ -97,14 +96,15 @@ struct BluetoothConfig: View { isPresented: $isPresentingSaveConfirm, titleVisibility: .visible ) { - let nodeName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : NSLocalizedString("unknown", comment: "Unknown") + let nodeName = node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown") let buttonText = String.localizedStringWithFormat(NSLocalizedString("save.config %@", comment: "Save Config for %@"), nodeName) Button(buttonText) { + let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context) var bc = Config.BluetoothConfig() bc.enabled = enabled bc.mode = BluetoothModes(rawValue: mode)?.protoEnumValue() ?? Config.BluetoothConfig.PairingMode.randomPin bc.fixedPin = UInt32(fixedPin) ?? 123456 - let adminMessageId = bleManager.saveBluetoothConfig(config: bc, fromUser: node!.user!, toUser: node!.user!) + let adminMessageId = bleManager.saveBluetoothConfig(config: bc, fromUser: connectedNode.user!, toUser: node!.user!) if adminMessageId > 0 { // Should show a saved successfully alert once I know that to be true // for now just disable the button after a successful save @@ -127,15 +127,13 @@ struct BluetoothConfig: View { self.fixedPin = String(node?.bluetoothConfig?.fixedPin ?? 123456) self.hasChanges = false - // Need to request a LoRaConfig from the remote node before allowing changes - if node?.bluetoothConfig == nil { - print("empty bluetooth config") - - } - // Need to request a BluetoothConfig from the remote node before allowing changes - if connectedNode != nil && node?.bluetoothConfig == nil { - _ = bleManager.requestBluetoothConfig(fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0) + if bleManager.connectedPeripheral != nil && node?.loRaConfig == nil { + print("empty bluetooth config") + let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context) + if connectedNode.id > 0 { + _ = bleManager.requestBluetoothConfig(fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) + } } } .onChange(of: enabled) { newEnabled in diff --git a/Meshtastic/Views/Settings/Config/DeviceConfig.swift b/Meshtastic/Views/Settings/Config/DeviceConfig.swift index fcb55ad1..c58f9ce9 100644 --- a/Meshtastic/Views/Settings/Config/DeviceConfig.swift +++ b/Meshtastic/Views/Settings/Config/DeviceConfig.swift @@ -35,12 +35,14 @@ struct DeviceConfig: View { Picker("Device Role", selection: $deviceRole ) { ForEach(DeviceRoles.allCases) { dr in - Text(dr.description) + Text(dr.name) } } .pickerStyle(DefaultPickerStyle()) .padding(.top, 10) - .padding(.bottom, 10) + Text(DeviceRoles(rawValue: deviceRole)?.description ?? "") + .foregroundColor(.gray) + .font(.caption) } Section(header: Text("Debug")) { @@ -83,7 +85,7 @@ struct DeviceConfig: View { } } - .disabled(bleManager.connectedPeripheral == nil) + .disabled(self.bleManager.connectedPeripheral == nil || node?.loRaConfig == nil) HStack { @@ -138,11 +140,9 @@ struct DeviceConfig: View { HStack { Button { - isPresentingSaveConfirm = true } label: { - Label("save", systemImage: "square.and.arrow.down") } .disabled(bleManager.connectedPeripheral == nil || !hasChanges) @@ -156,10 +156,10 @@ struct DeviceConfig: View { isPresented: $isPresentingSaveConfirm, titleVisibility: .visible ) { - let nodeName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : NSLocalizedString("unknown", comment: "Unknown") + let nodeName = node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown") let buttonText = String.localizedStringWithFormat(NSLocalizedString("save.config %@", comment: "Save Config for %@"), nodeName) Button(buttonText) { - + let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context) var dc = Config.DeviceConfig() dc.role = DeviceRoles(rawValue: deviceRole)!.protoEnumValue() dc.serialEnabled = serialEnabled @@ -167,7 +167,7 @@ struct DeviceConfig: View { dc.buttonGpio = UInt32(buttonGPIO) dc.buzzerGpio = UInt32(buzzerGPIO) - let adminMessageId = bleManager.saveDeviceConfig(config: dc, fromUser: node!.user!, toUser: node!.user!) + let adminMessageId = bleManager.saveDeviceConfig(config: dc, fromUser: connectedNode.user!, toUser: node!.user!) if adminMessageId > 0 { // Should show a saved successfully alert once I know that to be true // for now just disable the button after a successful save @@ -195,6 +195,15 @@ struct DeviceConfig: View { self.buttonGPIO = Int(node?.deviceConfig?.buttonGpio ?? 0) self.buzzerGPIO = Int(node?.deviceConfig?.buzzerGpio ?? 0) self.hasChanges = false + + // Need to request a LoRaConfig from the remote node before allowing changes + if bleManager.connectedPeripheral != nil && node?.deviceConfig == nil { + print("empty device config") + let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context) + if connectedNode.id > 0 { + _ = bleManager.requestDeviceConfig(fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) + } + } } .onChange(of: deviceRole) { newRole in diff --git a/Meshtastic/Views/Settings/Config/DisplayConfig.swift b/Meshtastic/Views/Settings/Config/DisplayConfig.swift index 1554b536..dc595819 100644 --- a/Meshtastic/Views/Settings/Config/DisplayConfig.swift +++ b/Meshtastic/Views/Settings/Config/DisplayConfig.swift @@ -97,7 +97,7 @@ struct DisplayConfig: View { .listRowSeparator(.visible) } } - .disabled(bleManager.connectedPeripheral == nil) + .disabled(self.bleManager.connectedPeripheral == nil || node?.loRaConfig == nil) Button { @@ -116,9 +116,10 @@ struct DisplayConfig: View { "are.you.sure", isPresented: $isPresentingSaveConfirm ) { - let nodeName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : NSLocalizedString("unknown", comment: "Unknown") + let nodeName = node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown") let buttonText = String.localizedStringWithFormat(NSLocalizedString("save.config %@", comment: "Save Config for %@"), nodeName) Button(buttonText) { + let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context) var dc = Config.DisplayConfig() dc.gpsFormat = GpsFormats(rawValue: gpsFormat)!.protoEnumValue() dc.screenOnSecs = UInt32(screenOnSeconds) @@ -128,7 +129,7 @@ struct DisplayConfig: View { dc.oled = OledTypes(rawValue: oledType)!.protoEnumValue() dc.displaymode = DisplayModes(rawValue: displayMode)!.protoEnumValue() - let adminMessageId = bleManager.saveDisplayConfig(config: dc, fromUser: node!.user!, toUser: node!.user!) + let adminMessageId = bleManager.saveDisplayConfig(config: dc, fromUser: connectedNode.user!, toUser: node!.user!) if adminMessageId > 0 { // Should show a saved successfully alert once I know that to be true @@ -156,6 +157,15 @@ struct DisplayConfig: View { self.oledType = Int(node?.displayConfig?.oledType ?? 0) self.displayMode = Int(node?.displayConfig?.displayMode ?? 0) self.hasChanges = false + + // Need to request a LoRaConfig from the remote node before allowing changes + if bleManager.connectedPeripheral != nil && node?.displayConfig == nil { + print("empty display config") + let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context) + if connectedNode.id > 0 { + _ = bleManager.requestDisplayConfig(fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) + } + } } .onChange(of: screenOnSeconds) { newScreenSecs in if node != nil && node!.displayConfig != nil { diff --git a/Meshtastic/Views/Settings/Config/LoRaConfig.swift b/Meshtastic/Views/Settings/Config/LoRaConfig.swift index 8efb83ef..40ef0ea0 100644 --- a/Meshtastic/Views/Settings/Config/LoRaConfig.swift +++ b/Meshtastic/Views/Settings/Config/LoRaConfig.swift @@ -61,7 +61,7 @@ struct LoRaConfig: View { .font(.caption) } } - .disabled(self.bleManager.connectedPeripheral == nil) + .disabled(self.bleManager.connectedPeripheral == nil || node?.loRaConfig == nil) Button { isPresentingSaveConfirm = true } label: { diff --git a/Meshtastic/Views/Settings/Config/NetworkConfig.swift b/Meshtastic/Views/Settings/Config/NetworkConfig.swift index 58710789..26d8fa03 100644 --- a/Meshtastic/Views/Settings/Config/NetworkConfig.swift +++ b/Meshtastic/Views/Settings/Config/NetworkConfig.swift @@ -25,7 +25,6 @@ struct NetworkConfig: View { @State var ethEnabled = false @State var ethMode = 0 - var body: some View { VStack { @@ -108,9 +107,10 @@ struct NetworkConfig: View { isPresented: $isPresentingSaveConfirm, titleVisibility: .visible ) { - let nodeName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : NSLocalizedString("unknown", comment: "Unknown") + let nodeName = node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown") let buttonText = String.localizedStringWithFormat(NSLocalizedString("save.config %@", comment: "Save Config for %@"), nodeName) Button(buttonText) { + let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context) var network = Config.NetworkConfig() network.wifiEnabled = self.wifiEnabled network.wifiSsid = self.wifiSsid @@ -118,7 +118,7 @@ struct NetworkConfig: View { network.ethEnabled = self.ethEnabled //network.addressMode = Config.NetworkConfig.AddressMode.dhcp - let adminMessageId = bleManager.saveNetworkConfig(config: network, fromUser: node!.user!, toUser: node!.user!) + let adminMessageId = bleManager.saveNetworkConfig(config: network, fromUser: connectedNode.user!, toUser: node!.user!) if adminMessageId > 0 { // Should show a saved successfully alert once I know that to be true // for now just disable the button after a successful save @@ -143,6 +143,15 @@ struct NetworkConfig: View { self.wifiMode = Int(node?.networkConfig?.wifiMode ?? 0) self.ethEnabled = node?.networkConfig?.ethEnabled ?? false self.hasChanges = false + + // Need to request a NetworkConfig from the remote node before allowing changes + if bleManager.connectedPeripheral != nil && node?.positionConfig == nil { + print("empty network config") + let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context) + if connectedNode.id > 0 { + _ = bleManager.requestNetworkConfig(fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) + } + } } .onChange(of: wifiEnabled) { newEnabled in if node != nil && node!.networkConfig != nil { diff --git a/Meshtastic/Views/Settings/Config/PositionConfig.swift b/Meshtastic/Views/Settings/Config/PositionConfig.swift index 8600dd53..4e2261a6 100644 --- a/Meshtastic/Views/Settings/Config/PositionConfig.swift +++ b/Meshtastic/Views/Settings/Config/PositionConfig.swift @@ -185,14 +185,11 @@ struct PositionConfig: View { } } } - .disabled(bleManager.connectedPeripheral == nil) + .disabled(self.bleManager.connectedPeripheral == nil || node?.loRaConfig == nil) Button { - isPresentingSaveConfirm = true - } label: { - Label("save", systemImage: "square.and.arrow.down") } .disabled(bleManager.connectedPeripheral == nil || !hasChanges) @@ -205,14 +202,14 @@ struct PositionConfig: View { isPresented: $isPresentingSaveConfirm, titleVisibility: .visible ) { - let nodeName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : NSLocalizedString("unknown", comment: "Unknown") + let nodeName = node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown") let buttonText = String.localizedStringWithFormat(NSLocalizedString("save.config %@", comment: "Save Config for %@"), nodeName) Button(buttonText) { if fixedPosition { _ = bleManager.sendPosition(destNum: bleManager.connectedPeripheral.num, wantResponse: false) } - + let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context) var pc = Config.PositionConfig() pc.positionBroadcastSmartEnabled = smartPositionEnabled pc.gpsEnabled = deviceGpsEnabled @@ -232,7 +229,7 @@ struct PositionConfig: View { if includeSpeed { pf.insert(.Speed) } if includeHeading { pf.insert(.Heading) } pc.positionFlags = UInt32(pf.rawValue) - let adminMessageId = bleManager.savePositionConfig(config: pc, fromUser: node!.user!, toUser: node!.user!) + let adminMessageId = bleManager.savePositionConfig(config: pc, fromUser: connectedNode.user!, toUser: node!.user!) if adminMessageId > 0 { // Should show a saved successfully alert once I know that to be true // for now just disable the button after a successful save @@ -278,6 +275,14 @@ struct PositionConfig: View { self.hasChanges = false + // Need to request a PositionConfig from the remote node before allowing changes + if bleManager.connectedPeripheral != nil && node?.positionConfig == nil { + print("empty position config") + let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context) + if connectedNode.id > 0 { + _ = bleManager.requestPositionConfig(fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0) + } + } } .onChange(of: deviceGpsEnabled) { newDeviceGps in if node != nil && node!.positionConfig != nil { diff --git a/Meshtastic/Views/Settings/Settings.swift b/Meshtastic/Views/Settings/Settings.swift index fcbd2bcd..603202b2 100644 --- a/Meshtastic/Views/Settings/Settings.swift +++ b/Meshtastic/Views/Settings/Settings.swift @@ -135,14 +135,13 @@ struct Settings: View { .disabled(selectedNode > 0 && selectedNode != connectedNodeNum) NavigationLink() { - BluetoothConfig(node: nodes.first(where: { $0.num == selectedNode }), connectedNode: nodes.first(where: { $0.num == connectedNodeNum })) + BluetoothConfig(node: nodes.first(where: { $0.num == selectedNode })) } label: { Image(systemName: "antenna.radiowaves.left.and.right") .symbolRenderingMode(.hierarchical) Text("bluetooth") } .tag(SettingsSidebar.bluetoothConfig) - .disabled(selectedNode > 0 && selectedNode != connectedNodeNum) NavigationLink { DeviceConfig(node: nodes.first(where: { $0.num == selectedNode })) @@ -152,7 +151,6 @@ struct Settings: View { Text("device") } .tag(SettingsSidebar.deviceConfig) - .disabled(selectedNode > 0 && selectedNode != connectedNodeNum) NavigationLink { DisplayConfig(node: nodes.first(where: { $0.num == selectedNode })) @@ -162,7 +160,6 @@ struct Settings: View { Text("display") } .tag(SettingsSidebar.displayConfig) - .disabled(selectedNode > 0 && selectedNode != connectedNodeNum) NavigationLink { NetworkConfig(node: nodes.first(where: { $0.num == selectedNode })) @@ -173,7 +170,6 @@ struct Settings: View { Text("network") } .tag(SettingsSidebar.networkConfig) - .disabled(selectedNode > 0 && selectedNode != connectedNodeNum) NavigationLink { PositionConfig(node: nodes.first(where: { $0.num == selectedNode })) @@ -184,7 +180,6 @@ struct Settings: View { Text("position") } .tag(SettingsSidebar.positionConfig) - .disabled(selectedNode > 0 && selectedNode != connectedNodeNum) } Section("module.configuration") {