diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 2836e221..9c794975 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -30,7 +30,6 @@ DD3CC6BE28E4CD9800FA9159 /* BatteryGauge.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3CC6BD28E4CD9800FA9159 /* BatteryGauge.swift */; }; DD3CC6C028E7A60700FA9159 /* MessagingEnums.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3CC6BF28E7A60700FA9159 /* MessagingEnums.swift */; }; DD3CC6C228EB9D4900FA9159 /* UpdateCoreData.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3CC6C128EB9D4900FA9159 /* UpdateCoreData.swift */; }; - DD4033C228B286B70096A444 /* Onboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD4033C128B286B70096A444 /* Onboarding.swift */; }; DD41582628582E9B009B0E59 /* DeviceConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD41582528582E9B009B0E59 /* DeviceConfig.swift */; }; DD415828285859C4009B0E59 /* TelemetryConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD415827285859C4009B0E59 /* TelemetryConfig.swift */; }; DD41582A28585C32009B0E59 /* RangeTestConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD41582928585C32009B0E59 /* RangeTestConfig.swift */; }; @@ -144,7 +143,6 @@ DD3CC6BD28E4CD9800FA9159 /* BatteryGauge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatteryGauge.swift; sourceTree = ""; }; DD3CC6BF28E7A60700FA9159 /* MessagingEnums.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessagingEnums.swift; sourceTree = ""; }; DD3CC6C128EB9D4900FA9159 /* UpdateCoreData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateCoreData.swift; sourceTree = ""; }; - DD4033C128B286B70096A444 /* Onboarding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Onboarding.swift; sourceTree = ""; }; DD41582528582E9B009B0E59 /* DeviceConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceConfig.swift; sourceTree = ""; }; DD415827285859C4009B0E59 /* TelemetryConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryConfig.swift; sourceTree = ""; }; DD41582928585C32009B0E59 /* RangeTestConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RangeTestConfig.swift; sourceTree = ""; }; @@ -497,7 +495,6 @@ children = ( DD882F5C2772E4640005BF05 /* Contacts.swift */, DD1BF2F82776FE2E008C8D2F /* MessageList.swift */, - DD4033C128B286B70096A444 /* Onboarding.swift */, ); path = Messages; sourceTree = ""; @@ -768,7 +765,6 @@ DDA6B2E928419CF2003E8C16 /* MeshPackets.swift in Sources */, DDCE4E2C2869F92900BE9F8F /* UserConfig.swift in Sources */, DD6193752862F6E600E59241 /* ExternalNotificationConfig.swift in Sources */, - DD4033C228B286B70096A444 /* Onboarding.swift in Sources */, DDB6ABE428B13FFF00384BA1 /* DisplayEnums.swift in Sources */, DD86D40A287F04F100BAEB7A /* InvalidVersion.swift in Sources */, DDD94A502845C8F5004A87A0 /* DateTimeText.swift in Sources */, diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index eca59b9b..6f03dbe1 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -38,6 +38,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph @Published var isScanning: Bool = false @Published var isConnecting: Bool = false @Published var isConnected: Bool = false + @Published var isSubscribed: Bool = false /// Used to make sure we never get foold by old BLE packets private var configNonce: UInt32 = 1 @@ -184,6 +185,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph centralManager?.cancelPeripheralConnection(connectedPeripheral.peripheral) FROMRADIO_characteristic = nil isConnected = false + isSubscribed = false invalidVersion = false connectedVersion = "0.0.0" startScanning() @@ -199,7 +201,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph peripheralName = name } - let newPeripheral = Peripheral(id: peripheral.identifier.uuidString, num: 0, name: peripheralName, shortName: last4Code, longName: peripheralName, lastFourCode: last4Code, firmwareVersion: "Unknown", rssi: RSSI.intValue, bitrate: nil, channelUtilization: nil, airTime: nil, maxChannels: 0, lastUpdate: Date(), subscribed: false, peripheral: peripheral) + let newPeripheral = Peripheral(id: peripheral.identifier.uuidString, num: 0, name: peripheralName, shortName: last4Code, longName: peripheralName, lastFourCode: last4Code, firmwareVersion: "Unknown", rssi: RSSI.intValue, bitrate: nil, channelUtilization: nil, airTime: nil, lastUpdate: Date(), peripheral: peripheral) let peripheralIndex = peripherals.firstIndex(where: { $0.id == newPeripheral.id }) if peripheralIndex != nil && newPeripheral.peripheral.state != CBPeripheralState.connected { @@ -270,6 +272,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph self.startScanning() self.connectedPeripheral = nil self.isConnecting = false + self.isSubscribed = false if let e = error { // https://developer.apple.com/documentation/corebluetooth/cberror/code let errorCode = (e as NSError).code @@ -521,8 +524,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph self.connectedPeripheral.firmwareVersion = myInfo!.firmwareVersion ?? "Unknown" self.connectedPeripheral.name = myInfo!.bleName ?? "Unknown" self.connectedPeripheral.longName = myInfo!.bleName ?? "Unknown" - self.connectedPeripheral.maxChannels = myInfo!.maxChannels - } } } @@ -651,7 +652,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph invalidVersion = false lastConnectionError = "" MeshLogger.log("🤜 BLE Config Complete Packet Id: \(decodedInfo.configCompleteID)") - self.connectedPeripheral.subscribed = true + self.isSubscribed = true peripherals.removeAll(where: { $0.peripheral.state == CBPeripheralState.disconnected }) // Config conplete returns so we don't read the characteristic again return diff --git a/Meshtastic/Model/PeripheralModel.swift b/Meshtastic/Model/PeripheralModel.swift index 8587a795..4b4cb3db 100644 --- a/Meshtastic/Model/PeripheralModel.swift +++ b/Meshtastic/Model/PeripheralModel.swift @@ -13,12 +13,10 @@ struct Peripheral: Identifiable { var bitrate: Float? var channelUtilization: Float? var airTime: Float? - var maxChannels: Int32 var lastUpdate: Date - var subscribed: Bool var peripheral: CBPeripheral - init(id: String, num: Int64, name: String, shortName: String, longName: String, lastFourCode: String, firmwareVersion: String, rssi: Int, bitrate: Float?, channelUtilization: Float?, airTime: Float?, maxChannels: Int32, lastUpdate: Date, subscribed: Bool, peripheral: CBPeripheral) { + init(id: String, num: Int64, name: String, shortName: String, longName: String, lastFourCode: String, firmwareVersion: String, rssi: Int, bitrate: Float?, channelUtilization: Float?, airTime: Float?, lastUpdate: Date, peripheral: CBPeripheral) { self.id = id self.num = num self.name = name @@ -30,9 +28,7 @@ struct Peripheral: Identifiable { self.bitrate = bitrate self.channelUtilization = channelUtilization self.airTime = airTime - self.maxChannels = maxChannels self.lastUpdate = lastUpdate - self.subscribed = subscribed self.peripheral = peripheral } } diff --git a/Meshtastic/Views/Bluetooth/Connect.swift b/Meshtastic/Views/Bluetooth/Connect.swift index b9bc8021..964a6918 100644 --- a/Meshtastic/Views/Bluetooth/Connect.swift +++ b/Meshtastic/Views/Bluetooth/Connect.swift @@ -7,6 +7,7 @@ import SwiftUI import MapKit +import CoreData import CoreLocation import CoreBluetooth @@ -15,58 +16,47 @@ struct Connect: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager @EnvironmentObject var userSettings: UserSettings + @State var node: NodeInfoEntity? = nil @State var isPreferredRadio: Bool = false - + @State var isUnsetRegion = false @State var invalidFirmwareVersion = false var body: some View { NavigationStack { - VStack { - List { - if bleManager.isSwitchedOn { - Section(header: Text("Connected Radio").font(.title)) { if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == .connected { - + HStack { - Image(systemName: "antenna.radiowaves.left.and.right") .symbolRenderingMode(.hierarchical) .imageScale(.large).foregroundColor(.green) .padding(.trailing) - VStack(alignment: .leading) { - - if bleManager.connectedPeripheral != nil { - + if node != nil { Text(bleManager.connectedPeripheral.longName).font(.title2) - } Text("BLE Name: ").font(.caption)+Text(bleManager.connectedPeripheral.peripheral.name ?? "Unknown") .font(.caption).foregroundColor(Color.gray) - if bleManager.connectedPeripheral != nil { - Text("FW Version: ").font(.caption)+Text(bleManager.connectedPeripheral.firmwareVersion) + if node != nil { + Text("FW Version: ").font(.caption)+Text(node?.myInfo?.firmwareVersion ?? "Unknown") .font(.caption).foregroundColor(Color.gray) } - if bleManager.connectedPeripheral.subscribed { + if bleManager.isSubscribed { Text("Subscribed to mesh").font(.caption) .foregroundColor(.green) } else { Text("Communicating with device. . . ").font(.caption) .foregroundColor(.orange) - } } Spacer() - VStack(alignment: .center) { - Text("Preferred").font(.caption2) Text("Radio").font(.caption2) Toggle("Preferred Radio", isOn: $bleManager.preferredPeripheral) @@ -74,18 +64,12 @@ struct Connect: View { .labelsHidden() .onChange(of: bleManager.preferredPeripheral) { value in if value { - if bleManager.connectedPeripheral != nil { - - userSettings.preferredPeripheralId = bleManager.connectedPeripheral!.peripheral.identifier.uuidString userSettings.preferredNodeNum = bleManager.connectedPeripheral!.num bleManager.preferredPeripheral = true isPreferredRadio = true - } - - } else { if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.identifier.uuidString == userSettings.preferredPeripheralId { @@ -98,7 +82,6 @@ struct Connect: View { } } } - } .font(.caption).foregroundColor(Color.gray) .padding([.top, .bottom]) @@ -114,18 +97,32 @@ struct Connect: View { } } .contextMenu{ - - Text("Num: \(String(bleManager.connectedPeripheral.num))") - Text("Short Name: \(bleManager.connectedPeripheral.shortName)") - Text("Long Name: \(bleManager.connectedPeripheral.longName)") - Text("Unique Code: \(bleManager.connectedPeripheral.lastFourCode)") - Text("Max Channels: \(String(bleManager.connectedPeripheral.maxChannels))") - Text("Bitrate: \(String(format: "%.2f", bleManager.connectedPeripheral.bitrate ?? 0.00))") - Text("Ch. Utilization: \(String(format: "%.2f", bleManager.connectedPeripheral.channelUtilization ?? 0.00))") - Text("Air Time: \(String(format: "%.2f", bleManager.connectedPeripheral.airTime ?? 0.00))") - Text("BLE RSSI: \(bleManager.connectedPeripheral.rssi)") + + if node != nil { + + Text("Num: \(String(node!.num))") + Text("Short Name: \(bleManager.connectedPeripheral.shortName)") + Text("Long Name: \(bleManager.connectedPeripheral.longName)") + Text("Unique Code: \(bleManager.connectedPeripheral.lastFourCode)") + Text("Max Channels: \(String(node!.myInfo!.maxChannels))") + Text("Bitrate: \(String(format: "%.2f", bleManager.connectedPeripheral.bitrate ?? 0.00))") + Text("Ch. Utilization: \(String(format: "%.2f", bleManager.connectedPeripheral.channelUtilization ?? 0.00))") + Text("Air Time: \(String(format: "%.2f", bleManager.connectedPeripheral.airTime ?? 0.00))") + Text("BLE RSSI: \(bleManager.connectedPeripheral.rssi)") + + } + } + if isUnsetRegion { + HStack { + NavigationLink { + LoRaConfig(node: node) + } label: { + Label("Set LoRa Region", systemImage: "globe.americas.fill") + .foregroundColor(.red) + .font(.title) + } + } } - } else { if bleManager.isConnecting { @@ -269,14 +266,12 @@ struct Connect: View { .padding(.bottom, 10) } .navigationTitle("Bluetooth") - .navigationBarItems(leading: MeshtasticLogo(), trailing: ZStack { ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????") }) } .sheet(isPresented: $invalidFirmwareVersion, onDismiss: didDismissSheet) { - InvalidVersion(minimumVersion: self.bleManager.minimumVersion, version: self.bleManager.connectedVersion) .presentationDetents([.large]) .presentationDragIndicator(.automatic) @@ -284,8 +279,31 @@ struct Connect: View { .onChange(of: (self.bleManager.invalidVersion)) { cv in invalidFirmwareVersion = self.bleManager.invalidVersion } + .onChange(of: (self.bleManager.isSubscribed)) { sub in + + if userSettings.preferredNodeNum > 0 && sub { + + let fetchNodeInfoRequest: NSFetchRequest = NSFetchRequest.init(entityName: "NodeInfoEntity") + fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(userSettings.preferredNodeNum)) + + do { + + let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity] + // Found a node, check it for a region + if !fetchedNode.isEmpty { + node = fetchedNode[0] + if node!.loRaConfig != nil && node!.loRaConfig?.regionCode ?? 0 == RegionCodes.unset.rawValue { + isUnsetRegion = true + } else { + isUnsetRegion = false + } + } + } catch { + + } + } + } .onAppear(perform: { - self.bleManager.context = context self.bleManager.userSettings = userSettings @@ -297,18 +315,8 @@ struct Connect: View { print(error.localizedDescription) } } - - if self.bleManager.connectedPeripheral != nil { - print(self.bleManager.connectedPeripheral.id) - print(userSettings.preferredPeripheralId) - } if self.bleManager.connectedPeripheral != nil && userSettings.preferredPeripheralId == self.bleManager.connectedPeripheral.id { isPreferredRadio = true - if userSettings.preferredNodeNum > 0 { - - print("I wanna set my prefered node") - } - } else { isPreferredRadio = false } diff --git a/Meshtastic/Views/Messages/Contacts.swift b/Meshtastic/Views/Messages/Contacts.swift index 7308201a..dd802a0f 100644 --- a/Meshtastic/Views/Messages/Contacts.swift +++ b/Meshtastic/Views/Messages/Contacts.swift @@ -82,7 +82,7 @@ struct Contacts: View { } HStack(alignment: .top) { Text("\(mostRecent != nil ? mostRecent!.messagePayload! : " ")") - .frame(height: 60) + .frame(height: 50) .truncationMode(.tail) .foregroundColor(Color.gray) .frame(maxWidth: .infinity, alignment: .leading) @@ -108,7 +108,7 @@ struct Contacts: View { } HStack(alignment: .top) { Text(" ") - .frame(height: 60) + .frame(height: 50 ) .truncationMode(.tail) .foregroundColor(Color.gray) .frame(maxWidth: .infinity, alignment: .leading) diff --git a/Meshtastic/Views/Messages/Onboarding.swift b/Meshtastic/Views/Messages/Onboarding.swift deleted file mode 100644 index 911dba3b..00000000 --- a/Meshtastic/Views/Messages/Onboarding.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// Onboarding.swift -// Meshtastic -// -// Copyright(c) Garth Vander Houwen 8/21/22. -// - -import SwiftUI - -struct Onboarding: View { - - var body: some View { - - VStack { - - Text("🗺️ Set Your Region to Mesh and Message") - .font(.largeTitle) - .foregroundColor(.red) - - Text("Your region is currently set to UNSET, please set your device to the appropriate region under Settings > LoRa, after you set your region your Meshtastic device will reboot.") - .font(.callout) - .padding() - - NavigationLink() { - - LoRaConfig(node: nil) - - } label: { - Image(systemName: "dot.radiowaves.left.and.right") - .symbolRenderingMode(.hierarchical) - Text("LoRa") - } - } - } -} diff --git a/Meshtastic/Views/Settings/Config/DisplayConfig.swift b/Meshtastic/Views/Settings/Config/DisplayConfig.swift index 576aaca2..edea736f 100644 --- a/Meshtastic/Views/Settings/Config/DisplayConfig.swift +++ b/Meshtastic/Views/Settings/Config/DisplayConfig.swift @@ -15,7 +15,6 @@ struct DisplayConfig: View { var node: NodeInfoEntity? @State private var isPresentingSaveConfirm: Bool = false - @State var initialLoad: Bool = true @State var hasChanges = false @State var screenOnSeconds = 0 @@ -116,50 +115,34 @@ struct DisplayConfig: View { } .navigationTitle("Display Config") .navigationBarItems(trailing: - ZStack { - ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????") }) .onAppear { - - if self.initialLoad{ - - self.bleManager.context = context - - self.gpsFormat = Int(node?.displayConfig?.gpsFormat ?? 0) - self.screenOnSeconds = Int(node?.displayConfig?.screenOnSeconds ?? 0) - self.screenCarouselInterval = Int(node?.displayConfig?.screenCarouselInterval ?? 0) - self.compassNorthTop = node?.displayConfig?.compassNorthTop ?? false - self.hasChanges = false - self.initialLoad = false - } + self.bleManager.context = context + self.gpsFormat = Int(node?.displayConfig?.gpsFormat ?? 0) + self.screenOnSeconds = Int(node?.displayConfig?.screenOnSeconds ?? 0) + self.screenCarouselInterval = Int(node?.displayConfig?.screenCarouselInterval ?? 0) + self.compassNorthTop = node?.displayConfig?.compassNorthTop ?? false + self.hasChanges = false } .onChange(of: screenOnSeconds) { newScreenSecs in - if node != nil && node!.displayConfig != nil { - if newScreenSecs != node!.displayConfig!.screenOnSeconds { hasChanges = true } } } .onChange(of: screenCarouselInterval) { newCarouselSecs in - if node != nil && node!.displayConfig != nil { - if newCarouselSecs != node!.displayConfig!.screenCarouselInterval { hasChanges = true } } } .onChange(of: compassNorthTop) { newCompassNorthTop in - if node != nil && node!.displayConfig != nil { - if newCompassNorthTop != node!.displayConfig!.compassNorthTop { hasChanges = true } } } .onChange(of: gpsFormat) { newGpsFormat in - if node != nil && node!.displayConfig != nil { - if newGpsFormat != node!.displayConfig!.gpsFormat { hasChanges = true } } }