mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Merge pull request #214 from meshtastic/share_channel
Hook together SaveChannelQRCode View
This commit is contained in:
commit
1fda757ffb
8 changed files with 92 additions and 95 deletions
|
|
@ -195,13 +195,12 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber) {
|
||||
|
||||
var peripheralName: String = peripheral.name ?? "Unknown"
|
||||
let last4Code: String = (peripheral.name != nil ? String(peripheral.name!.suffix(4)) : "Unknown")
|
||||
|
||||
if let name = advertisementData[CBAdvertisementDataLocalNameKey] as? String {
|
||||
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, lastUpdate: Date(), peripheral: peripheral)
|
||||
let newPeripheral = Peripheral(id: peripheral.identifier.uuidString, num: 0, name: peripheralName, shortName: "????", longName: peripheralName, firmwareVersion: "Unknown", rssi: RSSI.intValue, lastUpdate: Date(), peripheral: peripheral)
|
||||
let peripheralIndex = peripherals.firstIndex(where: { $0.id == newPeripheral.id })
|
||||
|
||||
if peripheralIndex != nil && newPeripheral.peripheral.state != CBPeripheralState.connected {
|
||||
|
|
@ -325,14 +324,12 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
|
||||
|
||||
if let e = error {
|
||||
|
||||
MeshLogger.log("🚫 BLE didDiscoverCharacteristicsFor error by \(peripheral.name ?? "Unknown") \(e)")
|
||||
}
|
||||
|
||||
|
||||
guard let characteristics = service.characteristics else { return }
|
||||
|
||||
for characteristic in characteristics {
|
||||
|
||||
switch characteristic.uuid {
|
||||
|
||||
case TORADIO_UUID:
|
||||
|
|
@ -340,13 +337,11 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
TORADIO_characteristic = characteristic
|
||||
|
||||
case FROMRADIO_UUID:
|
||||
|
||||
MeshLogger.log("✅ BLE did discover FROMRADIO characteristic for Meshtastic by \(peripheral.name ?? "Unknown")")
|
||||
FROMRADIO_characteristic = characteristic
|
||||
peripheral.readValue(for: FROMRADIO_characteristic)
|
||||
|
||||
case FROMNUM_UUID:
|
||||
|
||||
MeshLogger.log("✅ BLE did discover FROMNUM (Notify) characteristic for Meshtastic by \(peripheral.name ?? "Unknown")")
|
||||
FROMNUM_characteristic = characteristic
|
||||
peripheral.setNotifyValue(true, for: characteristic)
|
||||
|
|
@ -368,7 +363,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
DFURESULT_characteristic = characteristic
|
||||
|
||||
case DFUREGION_UUID:
|
||||
|
||||
MeshLogger.log("✅ BLE did discover DFU Region characteristic for Meshtastic DFU by \(peripheral.name ?? "Unknown")")
|
||||
DFUREGION_characteristic = characteristic
|
||||
|
||||
|
|
@ -377,7 +371,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
}
|
||||
}
|
||||
if (![FROMNUM_characteristic, TORADIO_characteristic].contains(nil)) {
|
||||
|
||||
sendWantConfig()
|
||||
}
|
||||
}
|
||||
|
|
@ -395,7 +388,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
meshPacket.priority = MeshPacket.Priority.reliable
|
||||
meshPacket.wantAck = true
|
||||
|
||||
|
||||
var dataMessage = DataMessage()
|
||||
dataMessage.payload = try! adminPacket.serializedData()
|
||||
dataMessage.portnum = PortNum.adminApp
|
||||
|
|
@ -517,10 +509,7 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
self.userSettings?.preferredNodeNum = myInfo?.myNodeNum ?? 0
|
||||
|
||||
if myInfo != nil {
|
||||
|
||||
self.connectedPeripheral.bitrate = myInfo!.bitrate
|
||||
self.connectedPeripheral.num = myInfo!.myNodeNum
|
||||
|
||||
self.connectedPeripheral.firmwareVersion = myInfo!.firmwareVersion ?? "Unknown"
|
||||
self.connectedPeripheral.name = myInfo!.bleName ?? "Unknown"
|
||||
self.connectedPeripheral.longName = myInfo!.bleName ?? "Unknown"
|
||||
|
|
@ -534,14 +523,8 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
let nodeInfo = nodeInfoPacket(nodeInfo: decodedInfo.nodeInfo, context: context!)
|
||||
|
||||
if nodeInfo != nil {
|
||||
|
||||
self.connectedPeripheral.channelUtilization = decodedInfo.nodeInfo.deviceMetrics.channelUtilization
|
||||
self.connectedPeripheral.airTime = decodedInfo.nodeInfo.deviceMetrics.airUtilTx
|
||||
|
||||
if self.connectedPeripheral != nil && self.connectedPeripheral.num == nodeInfo!.num {
|
||||
|
||||
if nodeInfo!.user != nil {
|
||||
|
||||
connectedPeripheral.shortName = nodeInfo!.user!.shortName ?? "????"
|
||||
connectedPeripheral.longName = nodeInfo!.user!.longName ?? "Unknown"
|
||||
}
|
||||
|
|
@ -947,7 +930,6 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
context!.rollback()
|
||||
let nsError = error as NSError
|
||||
MeshLogger.log("💥 Error Inserting New Core Data MessageEntity: \(nsError)")
|
||||
print()
|
||||
}
|
||||
}
|
||||
return false
|
||||
|
|
@ -1057,6 +1039,46 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph
|
|||
return false
|
||||
}
|
||||
|
||||
public func connectToPreferredPeripheral() -> Bool {
|
||||
|
||||
var success = false
|
||||
// Return false if we are not properly connected to a device, handle retry logic in the view for now
|
||||
if connectedPeripheral == nil || connectedPeripheral!.peripheral.state != CBPeripheralState.connected {
|
||||
|
||||
self.disconnectPeripheral()
|
||||
self.startScanning()
|
||||
|
||||
// Try and connect to the preferredPeripherial first
|
||||
let preferredPeripheral = peripherals.filter({ $0.peripheral.identifier.uuidString == UserDefaults.standard.object(forKey: "preferredPeripheralId") as? String ?? "" }).first
|
||||
if preferredPeripheral != nil && preferredPeripheral?.peripheral != nil {
|
||||
connectTo(peripheral: preferredPeripheral!.peripheral)
|
||||
success = true
|
||||
}
|
||||
} else if connectedPeripheral != nil && isSubscribed {
|
||||
success = true
|
||||
}
|
||||
return success
|
||||
}
|
||||
|
||||
public func saveChannelSet(base64UrlString: String) -> Bool {
|
||||
|
||||
if isConnected {
|
||||
var decodedString = base64UrlString.base64urlToBase64()
|
||||
if let decodedData = Data(base64Encoded: decodedString) {
|
||||
do {
|
||||
var channelSet: ChannelSet = try ChannelSet(serializedData: decodedData)
|
||||
|
||||
|
||||
|
||||
print(channelSet)
|
||||
} catch {
|
||||
print("Invalid Meshtastic QR Code Link")
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public func saveUser(config: User, fromUser: UserEntity, toUser: UserEntity) -> Int64 {
|
||||
|
||||
var adminPacket = AdminMessage()
|
||||
|
|
|
|||
|
|
@ -24,12 +24,10 @@ struct MeshtasticAppleApp: App {
|
|||
.environmentObject(bleManager)
|
||||
.environmentObject(userSettings)
|
||||
.sheet(isPresented: $saveChannels) {
|
||||
|
||||
SaveChannelQRCode(channelHash: channelSettings ?? "Empty Channel URL")
|
||||
SaveChannelQRCode(channelSetLink: channelSettings ?? "Empty Channel URL", bleManager: bleManager)
|
||||
.presentationDetents([.medium, .large])
|
||||
.presentationDragIndicator(.visible)
|
||||
}
|
||||
|
||||
.onContinueUserActivity(NSUserActivityTypeBrowsingWeb) { userActivity in
|
||||
|
||||
print("URL received \(userActivity)")
|
||||
|
|
|
|||
|
|
@ -7,27 +7,19 @@ struct Peripheral: Identifiable {
|
|||
var name: String
|
||||
var shortName: String
|
||||
var longName: String
|
||||
var lastFourCode: String
|
||||
var firmwareVersion: String
|
||||
var rssi: Int
|
||||
var bitrate: Float?
|
||||
var channelUtilization: Float?
|
||||
var airTime: Float?
|
||||
var lastUpdate: Date
|
||||
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?, lastUpdate: Date, peripheral: CBPeripheral) {
|
||||
init(id: String, num: Int64, name: String, shortName: String, longName: String, firmwareVersion: String, rssi: Int, lastUpdate: Date, peripheral: CBPeripheral) {
|
||||
self.id = id
|
||||
self.num = num
|
||||
self.name = name
|
||||
self.shortName = shortName
|
||||
self.longName = longName
|
||||
self.lastFourCode = lastFourCode
|
||||
self.firmwareVersion = firmwareVersion
|
||||
self.rssi = rssi
|
||||
self.bitrate = bitrate
|
||||
self.channelUtilization = channelUtilization
|
||||
self.airTime = airTime
|
||||
self.lastUpdate = lastUpdate
|
||||
self.peripheral = peripheral
|
||||
}
|
||||
|
|
|
|||
|
|
@ -216,6 +216,10 @@ struct OEMStore {
|
|||
/// Use this font for the OEM text.
|
||||
var oemText: String = String()
|
||||
|
||||
///
|
||||
/// The default device encryption key, 16 or 32 byte
|
||||
var oemAesKey: Data = Data()
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
init() {}
|
||||
|
|
@ -408,6 +412,7 @@ extension OEMStore: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
|
|||
3: .standard(proto: "oem_icon_bits"),
|
||||
4: .standard(proto: "oem_font"),
|
||||
5: .standard(proto: "oem_text"),
|
||||
6: .standard(proto: "oem_aes_key"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -421,6 +426,7 @@ extension OEMStore: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
|
|||
case 3: try { try decoder.decodeSingularBytesField(value: &self.oemIconBits) }()
|
||||
case 4: try { try decoder.decodeSingularEnumField(value: &self.oemFont) }()
|
||||
case 5: try { try decoder.decodeSingularStringField(value: &self.oemText) }()
|
||||
case 6: try { try decoder.decodeSingularBytesField(value: &self.oemAesKey) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
|
@ -442,6 +448,9 @@ extension OEMStore: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
|
|||
if !self.oemText.isEmpty {
|
||||
try visitor.visitSingularStringField(value: self.oemText, fieldNumber: 5)
|
||||
}
|
||||
if !self.oemAesKey.isEmpty {
|
||||
try visitor.visitSingularBytesField(value: self.oemAesKey, fieldNumber: 6)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
|
|
@ -451,6 +460,7 @@ extension OEMStore: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
|
|||
if lhs.oemIconBits != rhs.oemIconBits {return false}
|
||||
if lhs.oemFont != rhs.oemFont {return false}
|
||||
if lhs.oemText != rhs.oemText {return false}
|
||||
if lhs.oemAesKey != rhs.oemAesKey {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,13 +101,10 @@ struct Connect: View {
|
|||
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("Short Name: \(node?.user?.shortName ?? "????")")
|
||||
Text("Long Name: \(node?.user?.longName ?? "Unknown")")
|
||||
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("Bitrate: \(String(format: "%.2f", node?.myInfo?.bitrate ?? 0.00))")
|
||||
Text("BLE RSSI: \(bleManager.connectedPeripheral.rssi)")
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ struct DeviceConfig: View {
|
|||
@State private var isPresentingNodeDBResetConfirm = false
|
||||
@State private var isPresentingFactoryResetConfirm = false
|
||||
@State private var isPresentingSaveConfirm = false
|
||||
@State var initialLoad: Bool = true
|
||||
@State var hasChanges = false
|
||||
|
||||
@State var deviceRole = 0
|
||||
|
|
@ -166,17 +165,11 @@ struct DeviceConfig: View {
|
|||
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????")
|
||||
})
|
||||
.onAppear {
|
||||
|
||||
if self.initialLoad{
|
||||
|
||||
self.bleManager.context = context
|
||||
|
||||
self.deviceRole = Int(node?.deviceConfig?.role ?? 0)
|
||||
self.serialEnabled = (node?.deviceConfig?.serialEnabled ?? true)
|
||||
self.debugLogEnabled = node?.deviceConfig?.debugLogEnabled ?? false
|
||||
self.hasChanges = false
|
||||
self.initialLoad = false
|
||||
}
|
||||
self.bleManager.context = context
|
||||
self.deviceRole = Int(node?.deviceConfig?.role ?? 0)
|
||||
self.serialEnabled = (node?.deviceConfig?.serialEnabled ?? true)
|
||||
self.debugLogEnabled = node?.deviceConfig?.debugLogEnabled ?? false
|
||||
self.hasChanges = false
|
||||
}
|
||||
.onChange(of: deviceRole) { newRole in
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ struct SerialConfig: View {
|
|||
var node: NodeInfoEntity?
|
||||
|
||||
@State private var isPresentingSaveConfirm: Bool = false
|
||||
@State var initialLoad: Bool = true
|
||||
@State var hasChanges = false
|
||||
|
||||
@State var enabled = false
|
||||
|
|
@ -115,7 +114,7 @@ struct SerialConfig: View {
|
|||
|
||||
Label("Save", systemImage: "square.and.arrow.down")
|
||||
}
|
||||
.disabled(bleManager.connectedPeripheral == nil || !hasChanges || !(node!.myInfo?.hasWifi ?? false))
|
||||
.disabled(bleManager.connectedPeripheral == nil || !hasChanges)
|
||||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
|
|
@ -140,7 +139,6 @@ struct SerialConfig: View {
|
|||
let adminMessageId = bleManager.saveSerialModuleConfig(config: sc, fromUser: node!.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
|
||||
hasChanges = false
|
||||
|
|
@ -155,26 +153,20 @@ struct SerialConfig: View {
|
|||
.navigationBarItems(trailing:
|
||||
|
||||
ZStack {
|
||||
|
||||
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "????")
|
||||
})
|
||||
.onAppear {
|
||||
|
||||
self.bleManager.context = context
|
||||
self.enabled = node?.serialConfig?.enabled ?? false
|
||||
self.echo = node?.serialConfig?.echo ?? false
|
||||
self.rxd = Int(node?.serialConfig?.rxd ?? 0)
|
||||
self.txd = Int(node?.serialConfig?.txd ?? 0)
|
||||
self.baudRate = Int(node?.serialConfig?.baudRate ?? 0)
|
||||
self.timeout = Int(node?.serialConfig?.timeout ?? 0)
|
||||
self.mode = Int(node?.serialConfig?.mode ?? 0)
|
||||
self.hasChanges = false
|
||||
|
||||
if self.initialLoad{
|
||||
|
||||
self.bleManager.context = context
|
||||
|
||||
self.enabled = node?.serialConfig?.enabled ?? false
|
||||
self.echo = node?.serialConfig?.echo ?? false
|
||||
self.rxd = Int(node?.serialConfig?.rxd ?? 0)
|
||||
self.txd = Int(node?.serialConfig?.txd ?? 0)
|
||||
self.baudRate = Int(node?.serialConfig?.baudRate ?? 0)
|
||||
self.timeout = Int(node?.serialConfig?.timeout ?? 0)
|
||||
self.mode = Int(node?.serialConfig?.mode ?? 0)
|
||||
|
||||
self.hasChanges = false
|
||||
self.initialLoad = false
|
||||
}
|
||||
}
|
||||
.onChange(of: enabled) { newEnabled in
|
||||
|
||||
|
|
|
|||
|
|
@ -7,8 +7,10 @@
|
|||
import SwiftUI
|
||||
|
||||
struct SaveChannelQRCode: View {
|
||||
var channelHash: String
|
||||
|
||||
var channelSetLink: String
|
||||
var bleManager: BLEManager
|
||||
@State var connectedToDevice = false
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Text("Save Channel Settings?")
|
||||
|
|
@ -17,32 +19,23 @@ struct SaveChannelQRCode: View {
|
|||
.foregroundColor(.gray)
|
||||
.font(.callout)
|
||||
.padding()
|
||||
Text(channelHash)
|
||||
.font(.caption2)
|
||||
.foregroundColor(.gray)
|
||||
.padding()
|
||||
|
||||
Button {
|
||||
|
||||
} label: {
|
||||
|
||||
Label("Save", systemImage: "square.and.arrow.down")
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding()
|
||||
}
|
||||
.onChange(of: channelHash) { newSettings in
|
||||
var decodedString = newSettings.base64urlToBase64()
|
||||
if let decodedData = Data(base64Encoded: decodedString) {
|
||||
do {
|
||||
var channelSet: ChannelSet = try ChannelSet(serializedData: decodedData)
|
||||
print(channelSet)
|
||||
} catch {
|
||||
print("Invalid Meshtastic QR Code Link")
|
||||
|
||||
Button {
|
||||
let success = bleManager.saveChannelSet(base64UrlString: channelSetLink)
|
||||
|
||||
} label: {
|
||||
Label("Save", systemImage: "square.and.arrow.down")
|
||||
}
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding()
|
||||
.disabled(!connectedToDevice)
|
||||
|
||||
}
|
||||
.onAppear {
|
||||
connectedToDevice = bleManager.connectToPreferredPeripheral()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue