mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Swift Lint
This commit is contained in:
parent
a0f44acfb6
commit
93006b258d
22 changed files with 242 additions and 243 deletions
|
|
@ -31,7 +31,7 @@ enum HardwareModels: String, CaseIterable, Identifiable {
|
|||
case M5STACK
|
||||
case HELTEC_V3
|
||||
case HELTEC_WSL_V3
|
||||
|
||||
|
||||
var id: String { self.rawValue }
|
||||
var description: String {
|
||||
switch self {
|
||||
|
|
@ -81,7 +81,7 @@ enum HardwareModels: String, CaseIterable, Identifiable {
|
|||
case .HELTEC_WSL_V3:
|
||||
return "Heltec wireless stick lite V3"
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
var firmwareStrings: [String] {
|
||||
switch self {
|
||||
|
|
@ -131,7 +131,7 @@ enum HardwareModels: String, CaseIterable, Identifiable {
|
|||
case .HELTEC_WSL_V3:
|
||||
return ["firmware-heltec-wsl-v3-"]
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
func protoEnumValue() -> HardwareModel {
|
||||
|
||||
|
|
|
|||
|
|
@ -873,7 +873,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject {
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
public func sendRebootOta(fromUser: UserEntity, toUser: UserEntity, adminIndex: Int32) -> Bool {
|
||||
var adminPacket = AdminMessage()
|
||||
adminPacket.rebootOtaSeconds = 5
|
||||
|
|
@ -1897,7 +1897,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject {
|
|||
}
|
||||
|
||||
public func tryClearExistingChannels() {
|
||||
//Before we get started delete the existing channels from the myNodeInfo
|
||||
// Before we get started delete the existing channels from the myNodeInfo
|
||||
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
||||
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(connectedPeripheral.num))
|
||||
|
||||
|
|
|
|||
|
|
@ -13,13 +13,11 @@ import ActivityKit
|
|||
#endif
|
||||
|
||||
func generateMessageMarkdown (message: String) -> String {
|
||||
|
||||
let types: NSTextCheckingResult.CheckingType = [.address, .link, .phoneNumber]
|
||||
let detector = try! NSDataDetector(types: types.rawValue)
|
||||
let matches = detector.matches(in: message, options: [], range: NSRange(location: 0, length: message.utf16.count))
|
||||
var messageWithMarkdown = message
|
||||
if matches.count > 0 {
|
||||
|
||||
for match in matches {
|
||||
guard let range = Range(match.range, in: message) else { continue }
|
||||
if match.resultType == .address {
|
||||
|
|
@ -40,7 +38,6 @@ func generateMessageMarkdown (message: String) -> String {
|
|||
}
|
||||
|
||||
func localConfig (config: Config, context: NSManagedObjectContext, nodeNum: Int64, nodeLongName: String) {
|
||||
|
||||
// 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.bluetooth, nodeNum: nodeNum, context: context)
|
||||
|
|
@ -58,7 +55,7 @@ func localConfig (config: Config, context: NSManagedObjectContext, nodeNum: Int6
|
|||
}
|
||||
|
||||
func moduleConfig (config: ModuleConfig, context: NSManagedObjectContext, nodeNum: Int64, nodeLongName: String) {
|
||||
|
||||
|
||||
if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.cannedMessage(config.cannedMessage) {
|
||||
upsertCannedMessagesModuleConfigPacket(config: config.cannedMessage, nodeNum: nodeNum, context: context)
|
||||
} else if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.externalNotification(config.externalNotification) {
|
||||
|
|
@ -75,20 +72,20 @@ func moduleConfig (config: ModuleConfig, context: NSManagedObjectContext, nodeNu
|
|||
}
|
||||
|
||||
func myInfoPacket (myInfo: MyNodeInfo, peripheralId: String, context: NSManagedObjectContext) -> MyInfoEntity? {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.myinfo %@", comment: "MyInfo received: %@"), String(myInfo.myNodeNum))
|
||||
MeshLogger.log("ℹ️ \(logString)")
|
||||
|
||||
|
||||
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
||||
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(myInfo.myNodeNum))
|
||||
|
||||
|
||||
do {
|
||||
guard let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as? [MyInfoEntity] else {
|
||||
return nil
|
||||
}
|
||||
// Not Found Insert
|
||||
if fetchedMyInfo.isEmpty {
|
||||
|
||||
|
||||
let myInfoEntity = MyInfoEntity(context: context)
|
||||
myInfoEntity.peripheralId = peripheralId
|
||||
myInfoEntity.myNodeNum = Int64(myInfo.myNodeNum)
|
||||
|
|
@ -113,7 +110,7 @@ func myInfoPacket (myInfo: MyNodeInfo, peripheralId: String, context: NSManagedO
|
|||
print("💥 Error Inserting New Core Data MyInfoEntity: \(nsError)")
|
||||
}
|
||||
} else {
|
||||
|
||||
|
||||
fetchedMyInfo[0].peripheralId = peripheralId
|
||||
fetchedMyInfo[0].myNodeNum = Int64(myInfo.myNodeNum)
|
||||
fetchedMyInfo[0].hasGps = myInfo.hasGps_p
|
||||
|
|
@ -125,7 +122,7 @@ func myInfoPacket (myInfo: MyNodeInfo, peripheralId: String, context: NSManagedO
|
|||
fetchedMyInfo[0].messageTimeoutMsec = Int32(bitPattern: myInfo.messageTimeoutMsec)
|
||||
fetchedMyInfo[0].minAppVersion = Int32(bitPattern: myInfo.minAppVersion)
|
||||
fetchedMyInfo[0].maxChannels = Int32(bitPattern: myInfo.maxChannels)
|
||||
|
||||
|
||||
do {
|
||||
try context.save()
|
||||
print("💾 Updated myInfo for node number: \(String(myInfo.myNodeNum))")
|
||||
|
|
@ -143,15 +140,15 @@ func myInfoPacket (myInfo: MyNodeInfo, peripheralId: String, context: NSManagedO
|
|||
}
|
||||
|
||||
func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
if channel.isInitialized && channel.hasSettings && channel.role != Channel.Role.disabled {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.channel.received %d %@", comment: "Channel %d received from: %@"), channel.index, String(fromNum))
|
||||
MeshLogger.log("🎛️ \(logString)")
|
||||
|
||||
|
||||
let fetchedMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
||||
fetchedMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", fromNum)
|
||||
|
||||
|
||||
do {
|
||||
guard let fetchedMyInfo = try context.fetch(fetchedMyInfoRequest) as? [MyInfoEntity] else {
|
||||
return
|
||||
|
|
@ -195,14 +192,14 @@ func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectCo
|
|||
}
|
||||
|
||||
func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
if metadata.isInitialized {
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.device.metadata.received %@", comment: "Device Metadata admin message received from: %@"), String(fromNum))
|
||||
MeshLogger.log("🏷️ \(logString)")
|
||||
|
||||
|
||||
let fetchedNodeRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchedNodeRequest.predicate = NSPredicate(format: "num == %lld", fromNum)
|
||||
|
||||
|
||||
do {
|
||||
guard let fetchedNode = try context.fetch(fetchedNodeRequest) as? [NodeInfoEntity] else {
|
||||
return
|
||||
|
|
@ -218,7 +215,7 @@ func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, context: NS
|
|||
newMetadata.role = Int32(metadata.role.rawValue)
|
||||
newMetadata.positionFlags = Int32(metadata.positionFlags)
|
||||
fetchedNode[0].metadata = newMetadata
|
||||
|
||||
|
||||
do {
|
||||
try context.save()
|
||||
} catch {
|
||||
|
|
@ -235,27 +232,27 @@ func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, context: NS
|
|||
}
|
||||
|
||||
func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObjectContext) -> NodeInfoEntity? {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.nodeinfo.received %@", comment: "Node info received for: %@"), String(nodeInfo.num))
|
||||
MeshLogger.log("📟 \(logString)")
|
||||
|
||||
|
||||
guard nodeInfo.num > 0 else { return nil }
|
||||
|
||||
|
||||
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeInfo.num))
|
||||
|
||||
|
||||
do {
|
||||
guard let fetchedNode = try context.fetch(fetchNodeInfoRequest) as? [NodeInfoEntity] else {
|
||||
return nil
|
||||
}
|
||||
// Not Found Insert
|
||||
if fetchedNode.isEmpty && nodeInfo.hasUser {
|
||||
|
||||
|
||||
let newNode = NodeInfoEntity(context: context)
|
||||
newNode.id = Int64(nodeInfo.num)
|
||||
newNode.num = Int64(nodeInfo.num)
|
||||
newNode.channel = Int32(channel)
|
||||
|
||||
|
||||
if nodeInfo.hasDeviceMetrics {
|
||||
let telemetry = TelemetryEntity(context: context)
|
||||
telemetry.batteryLevel = Int32(nodeInfo.deviceMetrics.batteryLevel)
|
||||
|
|
@ -266,7 +263,7 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
newTelemetries.append(telemetry)
|
||||
newNode.telemetries? = NSOrderedSet(array: newTelemetries)
|
||||
}
|
||||
|
||||
|
||||
newNode.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.lastHeard)))
|
||||
newNode.snr = nodeInfo.snr
|
||||
if nodeInfo.hasUser {
|
||||
|
|
@ -279,7 +276,7 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
newUser.hwModel = String(describing: nodeInfo.user.hwModel).uppercased()
|
||||
newNode.user = newUser
|
||||
}
|
||||
|
||||
|
||||
if nodeInfo.position.longitudeI > 0 || nodeInfo.position.latitudeI > 0 && (nodeInfo.position.latitudeI != 373346000 && nodeInfo.position.longitudeI != -1220090000) {
|
||||
let position = PositionEntity(context: context)
|
||||
position.seqNo = Int32(nodeInfo.position.seqNumber)
|
||||
|
|
@ -294,11 +291,11 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
newPostions.append(position)
|
||||
newNode.positions? = NSOrderedSet(array: newPostions)
|
||||
}
|
||||
|
||||
|
||||
// Look for a MyInfo
|
||||
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
||||
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(nodeInfo.num))
|
||||
|
||||
|
||||
do {
|
||||
guard let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as? [MyInfoEntity] else {
|
||||
return nil
|
||||
|
|
@ -318,15 +315,15 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
print("💥 Fetch MyInfo Error")
|
||||
}
|
||||
} else if nodeInfo.hasUser && nodeInfo.num > 0 {
|
||||
|
||||
|
||||
fetchedNode[0].id = Int64(nodeInfo.num)
|
||||
fetchedNode[0].num = Int64(nodeInfo.num)
|
||||
fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.lastHeard)))
|
||||
fetchedNode[0].snr = nodeInfo.snr
|
||||
fetchedNode[0].channel = Int32(channel)
|
||||
|
||||
|
||||
if nodeInfo.hasUser {
|
||||
|
||||
|
||||
fetchedNode[0].user!.userId = nodeInfo.user.id
|
||||
fetchedNode[0].user!.num = Int64(nodeInfo.num)
|
||||
fetchedNode[0].user!.longName = nodeInfo.user.longName
|
||||
|
|
@ -334,9 +331,9 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
fetchedNode[0].user!.macaddr = nodeInfo.user.macaddr
|
||||
fetchedNode[0].user!.hwModel = String(describing: nodeInfo.user.hwModel).uppercased()
|
||||
}
|
||||
|
||||
|
||||
if nodeInfo.hasDeviceMetrics {
|
||||
|
||||
|
||||
let newTelemetry = TelemetryEntity(context: context)
|
||||
newTelemetry.batteryLevel = Int32(nodeInfo.deviceMetrics.batteryLevel)
|
||||
newTelemetry.voltage = nodeInfo.deviceMetrics.voltage
|
||||
|
|
@ -347,11 +344,11 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
}
|
||||
fetchedNode[0].telemetries = mutableTelemetries.copy() as? NSOrderedSet
|
||||
}
|
||||
|
||||
|
||||
if nodeInfo.hasPosition {
|
||||
|
||||
|
||||
if nodeInfo.position.longitudeI > 0 || nodeInfo.position.latitudeI > 0 && (nodeInfo.position.latitudeI != 373346000 && nodeInfo.position.longitudeI != -1220090000) {
|
||||
|
||||
|
||||
let position = PositionEntity(context: context)
|
||||
position.latitudeI = nodeInfo.position.latitudeI
|
||||
position.longitudeI = nodeInfo.position.longitudeI
|
||||
|
|
@ -363,13 +360,13 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
}
|
||||
fetchedNode[0].positions = mutablePositions.copy() as? NSOrderedSet
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Look for a MyInfo
|
||||
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
||||
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(nodeInfo.num))
|
||||
|
||||
|
||||
do {
|
||||
guard let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as? [MyInfoEntity] else {
|
||||
return nil
|
||||
|
|
@ -397,21 +394,21 @@ func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObje
|
|||
}
|
||||
|
||||
func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
if let adminMessage = try? AdminMessage(serializedData: packet.decoded.payload) {
|
||||
|
||||
|
||||
if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getCannedMessageModuleMessagesResponse(adminMessage.getCannedMessageModuleMessagesResponse) {
|
||||
|
||||
|
||||
if let cmmc = try? CannedMessageModuleConfig(serializedData: packet.decoded.payload) {
|
||||
|
||||
|
||||
if !cmmc.messages.isEmpty {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.cannedmessages.messages.received %@", comment: "Canned Messages Messages Received For: %@"), String(packet.from))
|
||||
MeshLogger.log("🥫 \(logString)")
|
||||
|
||||
|
||||
let fetchNodeRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeRequest.predicate = NSPredicate(format: "num == %lld", Int64(packet.from))
|
||||
|
||||
|
||||
do {
|
||||
guard let fetchedNode = try context.fetch(fetchNodeRequest) as? [NodeInfoEntity] else {
|
||||
return
|
||||
|
|
@ -438,65 +435,65 @@ func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
|||
}
|
||||
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getChannelResponse(adminMessage.getChannelResponse) {
|
||||
channelPacket(channel: adminMessage.getChannelResponse, fromNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getDeviceMetadataResponse(adminMessage.getDeviceMetadataResponse) {
|
||||
deviceMetadataPacket(metadata: adminMessage.getDeviceMetadataResponse, fromNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getConfigResponse(adminMessage.getConfigResponse) {
|
||||
|
||||
|
||||
let config = adminMessage.getConfigResponse
|
||||
|
||||
|
||||
if config.payloadVariant == Config.OneOf_PayloadVariant.bluetooth(config.bluetooth) {
|
||||
upsertBluetoothConfigPacket(config: config.bluetooth, 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.network, nodeNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
} else if config.payloadVariant == Config.OneOf_PayloadVariant.position(config.position) {
|
||||
upsertPositionConfigPacket(config: config.position, nodeNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
}
|
||||
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getModuleConfigResponse(adminMessage.getModuleConfigResponse) {
|
||||
|
||||
|
||||
let moduleConfig = adminMessage.getModuleConfigResponse
|
||||
|
||||
|
||||
if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.cannedMessage(moduleConfig.cannedMessage) {
|
||||
upsertCannedMessagesModuleConfigPacket(config: moduleConfig.cannedMessage, nodeNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.externalNotification(moduleConfig.externalNotification) {
|
||||
upsertExternalNotificationModuleConfigPacket(config: moduleConfig.externalNotification, nodeNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.mqtt(moduleConfig.mqtt) {
|
||||
upsertMqttModuleConfigPacket(config: moduleConfig.mqtt, nodeNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.rangeTest(moduleConfig.rangeTest) {
|
||||
upsertRangeTestModuleConfigPacket(config: moduleConfig.rangeTest, nodeNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.serial(moduleConfig.serial) {
|
||||
upsertSerialModuleConfigPacket(config: moduleConfig.serial, nodeNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.telemetry(moduleConfig.telemetry) {
|
||||
upsertTelemetryModuleConfigPacket(config: moduleConfig.telemetry, nodeNum: Int64(packet.from), context: context)
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
MeshLogger.log("🕸️ MESH PACKET received for Admin App \(try! packet.decoded.jsonString())")
|
||||
}
|
||||
|
||||
|
||||
// Save an ack for the admin message log for each admin message response received as we stopped sending acks if there is also a response to reduce airtime.
|
||||
adminResponseAck(packet: packet, context: context)
|
||||
}
|
||||
}
|
||||
|
||||
func adminResponseAck (packet: MeshPacket, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
let fetchedAdminMessageRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MessageEntity")
|
||||
fetchedAdminMessageRequest.predicate = NSPredicate(format: "messageId == %lld", packet.decoded.requestID)
|
||||
do {
|
||||
|
|
@ -524,22 +521,22 @@ func adminResponseAck (packet: MeshPacket, context: NSManagedObjectContext) {
|
|||
}
|
||||
|
||||
func routingPacket (packet: MeshPacket, connectedNodeNum: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
if let routingMessage = try? Routing(serializedData: packet.decoded.payload) {
|
||||
|
||||
|
||||
let routingError = RoutingError(rawValue: routingMessage.errorReason.rawValue)
|
||||
|
||||
|
||||
let routingErrorString = routingError?.display ?? NSLocalizedString("unknown", comment: "")
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.routing.message %@ %@", comment: "Routing received for RequestID: %@ Ack Status: %@"), String(packet.decoded.requestID), routingErrorString)
|
||||
MeshLogger.log("🕸️ \(logString)")
|
||||
|
||||
|
||||
let fetchMessageRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MessageEntity")
|
||||
fetchMessageRequest.predicate = NSPredicate(format: "messageId == %lld", Int64(packet.decoded.requestID))
|
||||
|
||||
|
||||
do {
|
||||
let fetchedMessage = try context.fetch(fetchMessageRequest) as? [MessageEntity]
|
||||
if fetchedMessage?.count ?? 0 > 0 {
|
||||
|
||||
|
||||
if fetchedMessage![0].toUser != nil {
|
||||
// Real ACK from DM Recipient
|
||||
if packet.to != packet.from {
|
||||
|
|
@ -547,14 +544,14 @@ func routingPacket (packet: MeshPacket, connectedNodeNum: Int64, context: NSMana
|
|||
}
|
||||
}
|
||||
fetchedMessage![0].ackError = Int32(routingMessage.errorReason.rawValue)
|
||||
|
||||
|
||||
if routingMessage.errorReason == Routing.Error.none {
|
||||
|
||||
|
||||
fetchedMessage![0].receivedACK = true
|
||||
}
|
||||
fetchedMessage![0].ackSNR = packet.rxSnr
|
||||
fetchedMessage![0].ackTimestamp = Int32(packet.rxTime)
|
||||
|
||||
|
||||
if fetchedMessage![0].toUser != nil {
|
||||
fetchedMessage![0].toUser?.objectWillChange.send()
|
||||
} else {
|
||||
|
|
@ -563,19 +560,19 @@ func routingPacket (packet: MeshPacket, connectedNodeNum: Int64, context: NSMana
|
|||
do {
|
||||
let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as? [MyInfoEntity]
|
||||
if fetchedMyInfo?.count ?? 0 > 0 {
|
||||
|
||||
|
||||
for ch in fetchedMyInfo![0].channels!.array as! [ChannelEntity] {
|
||||
|
||||
|
||||
if ch.index == packet.channel {
|
||||
ch.objectWillChange.send()
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
|
@ -590,25 +587,25 @@ func routingPacket (packet: MeshPacket, connectedNodeNum: Int64, context: NSMana
|
|||
}
|
||||
|
||||
func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
if let telemetryMessage = try? Telemetry(serializedData: packet.decoded.payload) {
|
||||
|
||||
|
||||
// Only log telemetry from the mesh not the connected device
|
||||
if connectedNode != Int64(packet.from) {
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.telemetry.received %@", comment: "Telemetry received for: %@"), String(packet.from))
|
||||
MeshLogger.log("📈 \(logString)")
|
||||
} else {
|
||||
// If it is the connected node
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
let telemetry = TelemetryEntity(context: context)
|
||||
|
||||
|
||||
let fetchNodeTelemetryRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeTelemetryRequest.predicate = NSPredicate(format: "num == %lld", Int64(packet.from))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
guard let fetchedNode = try context.fetch(fetchNodeTelemetryRequest) as? [NodeInfoEntity] else {
|
||||
return
|
||||
}
|
||||
|
|
@ -667,13 +664,13 @@ func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManage
|
|||
// Update our live activity if there is one running, not available on mac iOS >= 16.2
|
||||
#if !targetEnvironment(macCatalyst)
|
||||
if #available(iOS 16.2, *) {
|
||||
|
||||
|
||||
let oneMinuteLater = Calendar.current.date(byAdding: .minute, value: (Int(1) ), to: Date())!
|
||||
let date = Date.now...oneMinuteLater
|
||||
let updatedMeshStatus = MeshActivityAttributes.MeshActivityStatus(timerRange: date, connected: true, channelUtilization: telemetry.channelUtilization, airtime: telemetry.airUtilTx, batteryLevel: UInt32(telemetry.batteryLevel))
|
||||
let alertConfiguration = AlertConfiguration(title: "Mesh activity update", body: "Updated Device Metrics Data.", sound: .default)
|
||||
let updatedContent = ActivityContent(state: updatedMeshStatus, staleDate: nil)
|
||||
|
||||
|
||||
let meshActivity = Activity<MeshActivityAttributes>.activities.first(where: { $0.attributes.nodeNum == connectedNode })
|
||||
if meshActivity != nil {
|
||||
Task {
|
||||
|
|
@ -696,11 +693,11 @@ func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManage
|
|||
}
|
||||
|
||||
func textMessageAppPacket(packet: MeshPacket, connectedNode: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
if let messageText = String(bytes: packet.decoded.payload, encoding: .utf8) {
|
||||
|
||||
|
||||
MeshLogger.log("💬 \(NSLocalizedString("mesh.log.textmessage.received", comment: "Message received from the text message app"))")
|
||||
|
||||
|
||||
let messageUsers: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "UserEntity")
|
||||
messageUsers.predicate = NSPredicate(format: "num IN %@", [packet.to, packet.from])
|
||||
do {
|
||||
|
|
@ -714,11 +711,11 @@ func textMessageAppPacket(packet: MeshPacket, connectedNode: Int64, context: NSM
|
|||
newMessage.snr = packet.rxSnr
|
||||
newMessage.isEmoji = packet.decoded.emoji == 1
|
||||
newMessage.channel = Int32(packet.channel)
|
||||
|
||||
|
||||
if packet.decoded.replyID > 0 {
|
||||
newMessage.replyID = Int64(packet.decoded.replyID)
|
||||
}
|
||||
|
||||
|
||||
if fetchedUsers.first(where: { $0.num == packet.to }) != nil && packet.to != 4294967295 {
|
||||
newMessage.toUser = fetchedUsers.first(where: { $0.num == packet.to })
|
||||
}
|
||||
|
|
@ -727,20 +724,20 @@ func textMessageAppPacket(packet: MeshPacket, connectedNode: Int64, context: NSM
|
|||
}
|
||||
newMessage.messagePayload = messageText
|
||||
newMessage.messagePayloadMarkdown = generateMessageMarkdown(message: messageText)
|
||||
|
||||
|
||||
newMessage.fromUser?.objectWillChange.send()
|
||||
newMessage.toUser?.objectWillChange.send()
|
||||
|
||||
|
||||
var messageSaved = false
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
try context.save()
|
||||
print("💾 Saved a new message for \(newMessage.messageId)")
|
||||
messageSaved = true
|
||||
|
||||
|
||||
if messageSaved {
|
||||
|
||||
|
||||
if newMessage.fromUser != nil && newMessage.toUser != nil && !(newMessage.fromUser?.mute ?? false) {
|
||||
// Create an iOS Notification for the received DM message and schedule it immediately
|
||||
let manager = LocalNotificationManager()
|
||||
|
|
@ -754,10 +751,10 @@ func textMessageAppPacket(packet: MeshPacket, connectedNode: Int64, context: NSM
|
|||
manager.schedule()
|
||||
print("💬 iOS Notification Scheduled for text message from \(newMessage.fromUser?.longName ?? NSLocalizedString("unknown", comment: "Unknown"))")
|
||||
} else if newMessage.fromUser != nil && newMessage.toUser == nil {
|
||||
|
||||
|
||||
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
||||
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(connectedNode))
|
||||
|
||||
|
||||
do {
|
||||
guard let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as? [MyInfoEntity] else {
|
||||
return
|
||||
|
|
@ -766,7 +763,7 @@ func textMessageAppPacket(packet: MeshPacket, connectedNode: Int64, context: NSM
|
|||
if channel.index == newMessage.channel {
|
||||
context.refresh(channel, mergeChanges: true)
|
||||
}
|
||||
|
||||
|
||||
if channel.index == newMessage.channel && !channel.mute {
|
||||
// Create an iOS Notification for the received private channel message and schedule it immediately
|
||||
let manager = LocalNotificationManager()
|
||||
|
|
@ -782,7 +779,7 @@ func textMessageAppPacket(packet: MeshPacket, connectedNode: Int64, context: NSM
|
|||
}
|
||||
}
|
||||
} catch {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -798,22 +795,22 @@ func textMessageAppPacket(packet: MeshPacket, connectedNode: Int64, context: NSM
|
|||
}
|
||||
|
||||
func waypointPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.waypoint.received %@", comment: "Waypoint Packet received from node: %@"), String(packet.from))
|
||||
MeshLogger.log("📍 \(logString)")
|
||||
|
||||
|
||||
let fetchWaypointRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "WaypointEntity")
|
||||
fetchWaypointRequest.predicate = NSPredicate(format: "id == %lld", Int64(packet.id))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
if let waypointMessage = try? Waypoint(serializedData: packet.decoded.payload) {
|
||||
guard let fetchedWaypoint = try context.fetch(fetchWaypointRequest) as? [WaypointEntity] else {
|
||||
return
|
||||
}
|
||||
if fetchedWaypoint.isEmpty {
|
||||
let waypoint = WaypointEntity(context: context)
|
||||
|
||||
|
||||
waypoint.id = Int64(packet.id)
|
||||
waypoint.name = waypointMessage.name
|
||||
waypoint.longDescription = waypointMessage.description_p
|
||||
|
|
|
|||
|
|
@ -98,17 +98,17 @@ public func clearCoreDataDatabase(context: NSManagedObjectContext) {
|
|||
}
|
||||
|
||||
func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
||||
|
||||
|
||||
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.nodeinfo.received %@", comment: "Node info received for: %@"), String(packet.from))
|
||||
MeshLogger.log("📟 \(logString)")
|
||||
|
||||
|
||||
guard packet.from > 0 else { return }
|
||||
|
||||
|
||||
let fetchNodeInfoAppRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
||||
fetchNodeInfoAppRequest.predicate = NSPredicate(format: "num == %lld", Int64(packet.from))
|
||||
|
||||
|
||||
do {
|
||||
|
||||
|
||||
let fetchedNode = try context.fetch(fetchNodeInfoAppRequest) as? [NodeInfoEntity] ?? []
|
||||
if fetchedNode.count == 0 {
|
||||
// Not Found Insert
|
||||
|
|
@ -135,7 +135,7 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext)
|
|||
fetchedNode[0].lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(packet.rxTime)))
|
||||
fetchedNode[0].snr = packet.rxSnr
|
||||
fetchedNode[0].channel = Int32(packet.channel)
|
||||
|
||||
|
||||
if let nodeInfoMessage = try? NodeInfo(serializedData: packet.decoded.payload) {
|
||||
if nodeInfoMessage.hasDeviceMetrics {
|
||||
let telemetry = TelemetryEntity(context: context)
|
||||
|
|
@ -192,7 +192,7 @@ func upsertPositionPacket (packet: MeshPacket, context: NSManagedObjectContext)
|
|||
// Unset the current latest position for this node
|
||||
let fetchCurrentLatestPositionsRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "PositionEntity")
|
||||
fetchCurrentLatestPositionsRequest.predicate = NSPredicate(format: "nodePosition.num == %lld && latest = true", Int64(packet.from))
|
||||
|
||||
|
||||
guard let fetchedPositions = try context.fetch(fetchCurrentLatestPositionsRequest) as? [PositionEntity] else {
|
||||
return
|
||||
}
|
||||
|
|
@ -237,8 +237,13 @@ func upsertPositionPacket (packet: MeshPacket, context: NSManagedObjectContext)
|
|||
}
|
||||
}
|
||||
} else {
|
||||
print("💥 Empty POSITION_APP Packet")
|
||||
print((try? packet.jsonString()) ?? "JSON Decode Failure")
|
||||
|
||||
if (try? NodeInfo(serializedData: packet.decoded.payload)) != nil {
|
||||
upsertNodeInfoPacket(packet: packet, context: context)
|
||||
} else {
|
||||
print("💥 Empty POSITION_APP Packet")
|
||||
print((try? packet.jsonString()) ?? "JSON Decode Failure")
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ struct NodeDetail: View {
|
|||
VStack {
|
||||
if node.positions?.count ?? 0 > 0 {
|
||||
ZStack {
|
||||
let annotations = node.positions?.array as? [PositionEntity] ?? []
|
||||
let annotations = node.positions?.array as? [PositionEntity] ?? []
|
||||
ZStack {
|
||||
MapViewSwiftUI(onLongPress: { coord in
|
||||
waypointCoordinate = coord
|
||||
|
|
@ -105,7 +105,7 @@ struct NodeDetail: View {
|
|||
.font(.title)
|
||||
.padding()
|
||||
let nodeLocation = node.positions?.lastObject as! PositionEntity
|
||||
|
||||
|
||||
NodeWeatherForecastView(location: CLLocation(latitude: nodeLocation.nodeCoordinate!.latitude, longitude: nodeLocation.nodeCoordinate!.longitude) )
|
||||
.frame(height: 250)
|
||||
}
|
||||
|
|
@ -114,7 +114,7 @@ struct NodeDetail: View {
|
|||
Text("Today's Weather Forecast")
|
||||
.font(.title)
|
||||
.padding()
|
||||
|
||||
|
||||
let nodeLocation = node.positions?.lastObject as! PositionEntity
|
||||
NodeWeatherForecastView(location: CLLocation(latitude: nodeLocation.nodeCoordinate!.latitude, longitude: nodeLocation.nodeCoordinate!.longitude) )
|
||||
.frame(height: 250)
|
||||
|
|
|
|||
|
|
@ -60,10 +60,8 @@ struct NodeMap: View {
|
|||
// init() {
|
||||
// _positions = FetchRequest<PositionEntity>(sortDescriptors: [NSSortDescriptor(key: "time", ascending: true)], predicate: NSPredicate(format: "time >= %@ && nodePosition != nil", Calendar.current.startOfDay(for: Date()) as NSDate), animation: .none)
|
||||
// }
|
||||
|
||||
|
||||
var body: some View {
|
||||
|
||||
|
||||
|
||||
NavigationStack {
|
||||
ZStack {
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ struct AdminMessageList: View {
|
|||
|
||||
if am.ackTimestamp > 0 {
|
||||
if am.realACK {
|
||||
|
||||
|
||||
Text(ackErrorVal?.display ?? "Empty Ack Error")
|
||||
.foregroundColor(am.receivedACK ? .gray : .red)
|
||||
.font(.caption2)
|
||||
|
|
|
|||
|
|
@ -123,7 +123,6 @@ struct Channels: View {
|
|||
.disableAutocorrection(true)
|
||||
.keyboardType(.alphabet)
|
||||
.foregroundColor(Color.gray)
|
||||
.disabled(channelRole == 1 && channelName.count > 0)
|
||||
.onChange(of: channelName, perform: { _ in
|
||||
channelName = channelName.replacing(" ", with: "")
|
||||
let totalBytes = channelName.utf8.count
|
||||
|
|
|
|||
|
|
@ -30,10 +30,10 @@ struct BluetoothConfig: View {
|
|||
Text("There has been no response to a request for device metadata over the admin channel for this node.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
||||
|
||||
} else if node != nil && node?.num ?? 0 != bleManager.connectedPeripheral?.num ?? 0 {
|
||||
// Let users know what is going on if they are using remote admin and don't have the config yet
|
||||
if node?.bluetoothConfig == nil {
|
||||
if node?.bluetoothConfig == nil {
|
||||
Text("Bluetooth config data was requested over the admin channel but no response has been returned from the remote node. You can check the status of admin message requests in the admin message log.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
|
@ -41,7 +41,7 @@ struct BluetoothConfig: View {
|
|||
Text("Remote administration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
}
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0{
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0 {
|
||||
Text("Configuration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -35,10 +35,10 @@ struct DeviceConfig: View {
|
|||
Text("There has been no response to a request for device metadata over the admin channel for this node.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
||||
|
||||
} else if node != nil && node?.num ?? 0 != bleManager.connectedPeripheral?.num ?? 0 {
|
||||
// Let users know what is going on if they are using remote admin and don't have the config yet
|
||||
if node?.deviceConfig == nil {
|
||||
if node?.deviceConfig == nil {
|
||||
Text("Device config data was requested over the admin channel but no response has been returned from the remote node. You can check the status of admin message requests in the admin message log.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
|
@ -46,7 +46,7 @@ struct DeviceConfig: View {
|
|||
Text("Remote administration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
}
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0{
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0 {
|
||||
Text("Configuration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -33,10 +33,10 @@ struct DisplayConfig: View {
|
|||
Text("There has been no response to a request for device metadata over the admin channel for this node.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
||||
|
||||
} else if node != nil && node?.num ?? 0 != bleManager.connectedPeripheral?.num ?? 0 {
|
||||
// Let users know what is going on if they are using remote admin and don't have the config yet
|
||||
if node?.displayConfig == nil {
|
||||
if node?.displayConfig == nil {
|
||||
Text("Display config data was requested over the admin channel but no response has been returned from the remote node. You can check the status of admin message requests in the admin message log.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
|
@ -44,7 +44,7 @@ struct DisplayConfig: View {
|
|||
Text("Remote administration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
}
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0{
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0 {
|
||||
Text("Configuration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -50,10 +50,10 @@ struct LoRaConfig: View {
|
|||
Text("There has been no response to a request for device metadata over the admin channel for this node.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
||||
|
||||
} else if node != nil && node?.num ?? 0 != bleManager.connectedPeripheral?.num ?? 0 {
|
||||
// Let users know what is going on if they are using remote admin and don't have the config yet
|
||||
if node?.loRaConfig == nil {
|
||||
if node?.loRaConfig == nil {
|
||||
Text("LoRa config data was requested over the admin channel but no response has been returned from the remote node. You can check the status of admin message requests in the admin message log.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
|
@ -61,7 +61,7 @@ struct LoRaConfig: View {
|
|||
Text("Remote administration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
}
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0{
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0 {
|
||||
Text("Configuration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -43,10 +43,10 @@ struct CannedMessagesConfig: View {
|
|||
Text("There has been no response to a request for device metadata over the admin channel for this node.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
||||
|
||||
} else if node != nil && node?.num ?? 0 != bleManager.connectedPeripheral?.num ?? 0 {
|
||||
// Let users know what is going on if they are using remote admin and don't have the config yet
|
||||
if node?.cannedMessageConfig == nil {
|
||||
if node?.cannedMessageConfig == nil {
|
||||
Text("Canned messages config data was requested over the admin channel but no response has been returned from the remote node. You can check the status of admin message requests in the admin message log.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
|
@ -54,7 +54,7 @@ struct CannedMessagesConfig: View {
|
|||
Text("Remote administration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
}
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0{
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0 {
|
||||
Text("Configuration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -38,10 +38,10 @@ struct ExternalNotificationConfig: View {
|
|||
Text("There has been no response to a request for device metadata over the admin channel for this node.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
||||
|
||||
} else if node != nil && node?.num ?? 0 != bleManager.connectedPeripheral?.num ?? 0 {
|
||||
// Let users know what is going on if they are using remote admin and don't have the config yet
|
||||
if node?.externalNotificationConfig == nil {
|
||||
if node?.externalNotificationConfig == nil {
|
||||
Text("External notification config data was requested over the admin channel but no response has been returned from the remote node. You can check the status of admin message requests in the admin message log.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
|
@ -49,7 +49,7 @@ struct ExternalNotificationConfig: View {
|
|||
Text("Remote administration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
}
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0{
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0 {
|
||||
Text("Configuration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -28,10 +28,10 @@ struct MQTTConfig: View {
|
|||
Text("There has been no response to a request for device metadata over the admin channel for this node.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
||||
|
||||
} else if node != nil && node?.num ?? 0 != bleManager.connectedPeripheral?.num ?? 0 {
|
||||
// Let users know what is going on if they are using remote admin and don't have the config yet
|
||||
if node?.mqttConfig == nil {
|
||||
if node?.mqttConfig == nil {
|
||||
Text("MQTT config data was requested over the admin channel but no response has been returned from the remote node. You can check the status of admin message requests in the admin message log.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
|
@ -39,7 +39,7 @@ struct MQTTConfig: View {
|
|||
Text("Remote administration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
}
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0{
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0 {
|
||||
Text("Configuration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@ struct RangeTestConfig: View {
|
|||
Text("There has been no response to a request for device metadata over the admin channel for this node.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
||||
|
||||
} else if node != nil && node?.num ?? 0 != bleManager.connectedPeripheral?.num ?? 0 {
|
||||
// Let users know what is going on if they are using remote admin and don't have the config yet
|
||||
if node?.rangeTestConfig == nil {
|
||||
if node?.rangeTestConfig == nil {
|
||||
Text("Range test config data was requested over the admin channel but no response has been returned from the remote node. You can check the status of admin message requests in the admin message log.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
|
@ -38,7 +38,7 @@ struct RangeTestConfig: View {
|
|||
Text("Remote administration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
}
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0{
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0 {
|
||||
Text("Configuration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -34,10 +34,10 @@ struct SerialConfig: View {
|
|||
Text("There has been no response to a request for device metadata over the admin channel for this node.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
||||
|
||||
} else if node != nil && node?.num ?? 0 != bleManager.connectedPeripheral?.num ?? 0 {
|
||||
// Let users know what is going on if they are using remote admin and don't have the config yet
|
||||
if node?.serialConfig == nil {
|
||||
if node?.serialConfig == nil {
|
||||
Text("Serial config data was requested over the admin channel but no response has been returned from the remote node. You can check the status of admin message requests in the admin message log.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
|
@ -45,7 +45,7 @@ struct SerialConfig: View {
|
|||
Text("Remote administration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
}
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0{
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0 {
|
||||
Text("Configuration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -30,10 +30,10 @@ struct TelemetryConfig: View {
|
|||
Text("There has been no response to a request for device metadata over the admin channel for this node.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
||||
|
||||
} else if node != nil && node?.num ?? 0 != bleManager.connectedPeripheral?.num ?? 0 {
|
||||
// Let users know what is going on if they are using remote admin and don't have the config yet
|
||||
if node?.telemetryConfig == nil {
|
||||
if node?.telemetryConfig == nil {
|
||||
Text("Telemetry config data was requested over the admin channel but no response has been returned from the remote node. You can check the status of admin message requests in the admin message log.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
|
@ -41,7 +41,7 @@ struct TelemetryConfig: View {
|
|||
Text("Remote administration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
}
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0{
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0 {
|
||||
Text("Configuration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -33,10 +33,10 @@ struct NetworkConfig: View {
|
|||
Text("There has been no response to a request for device metadata over the admin channel for this node.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
||||
|
||||
} else if node != nil && node?.num ?? 0 != bleManager.connectedPeripheral?.num ?? 0 {
|
||||
// Let users know what is going on if they are using remote admin and don't have the config yet
|
||||
if node?.networkConfig == nil {
|
||||
if node?.networkConfig == nil {
|
||||
Text("Network config data was requested over the admin channel but no response has been returned from the remote node. You can check the status of admin message requests in the admin message log.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
|
@ -44,7 +44,7 @@ struct NetworkConfig: View {
|
|||
Text("Remote administration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
}
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0{
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0 {
|
||||
Text("Configuration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -76,10 +76,10 @@ struct PositionConfig: View {
|
|||
Text("There has been no response to a request for device metadata over the admin channel for this node.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
||||
|
||||
} else if node != nil && node?.num ?? 0 != bleManager.connectedPeripheral?.num ?? 0 {
|
||||
// Let users know what is going on if they are using remote admin and don't have the config yet
|
||||
if node?.positionConfig == nil {
|
||||
if node?.positionConfig == nil {
|
||||
Text("Position config data was requested over the admin channel but no response has been returned from the remote node. You can check the status of admin message requests in the admin message log.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.orange)
|
||||
|
|
@ -87,7 +87,7 @@ struct PositionConfig: View {
|
|||
Text("Remote administration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
}
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0{
|
||||
} else if node != nil && node?.num ?? 0 == bleManager.connectedPeripheral?.num ?? 0 {
|
||||
Text("Configuration for: \(node?.user?.longName ?? "Unknown")")
|
||||
.font(.title3)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -15,22 +15,22 @@ import SwiftUI
|
|||
import StoreKit
|
||||
|
||||
struct Firmware: View {
|
||||
|
||||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
|
||||
|
||||
var node: NodeInfoEntity?
|
||||
|
||||
|
||||
@State private var firmwareReleaseData: FirmwareRelease = FirmwareRelease()
|
||||
|
||||
|
||||
var body: some View {
|
||||
//NavigationSplitView {
|
||||
// NavigationSplitView {
|
||||
NavigationStack {
|
||||
|
||||
let hwModel: HardwareModels = HardwareModels.allCases.first(where: { $0.rawValue == node?.user?.hwModel ?? "UNSET" } ) ?? HardwareModels.UNSET
|
||||
|
||||
let hwModel: HardwareModels = HardwareModels.allCases.first(where: { $0.rawValue == node?.user?.hwModel ?? "UNSET" }) ?? HardwareModels.UNSET
|
||||
Text(hwModel.firmwareStrings[0] + (node?.metadata?.firmwareVersion ?? "Unknown") )
|
||||
.font(.title3)
|
||||
VStack (alignment: .leading) {
|
||||
VStack(alignment: .leading) {
|
||||
Text("nRF Device Firmware Update App")
|
||||
.font(.title3)
|
||||
Text("You can update your Meshtastic device over bluetooth using the Nordic DFU app. This currently works for RAK NRF devices.")
|
||||
|
|
@ -39,7 +39,7 @@ struct Firmware: View {
|
|||
.font(.callout)
|
||||
}
|
||||
.padding([.leading, .trailing, .bottom])
|
||||
VStack (alignment: .leading) {
|
||||
VStack(alignment: .leading) {
|
||||
Text("ESP32 Device Firmware Update")
|
||||
.font(.title3)
|
||||
Text("Currently the reccomended way to update ESP32 devices is using the web flasher from a chrome based browser. It does not work on mobile devices or over BLE.")
|
||||
|
|
@ -49,7 +49,7 @@ struct Firmware: View {
|
|||
.padding(.bottom)
|
||||
Text("ESP 32 OTA update is a work in progress, click the button below to sent your device a reboot into ota admin message.")
|
||||
.font(.caption)
|
||||
HStack(alignment: .center){
|
||||
HStack(alignment: .center) {
|
||||
Spacer()
|
||||
Button {
|
||||
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
|
||||
|
|
@ -72,7 +72,7 @@ struct Firmware: View {
|
|||
}
|
||||
.padding([.leading, .trailing, .bottom])
|
||||
.padding(.bottom, 5)
|
||||
VStack (alignment: .leading) {
|
||||
VStack(alignment: .leading) {
|
||||
Text("Firmware Releases")
|
||||
.font(.title3)
|
||||
.padding([.leading, .trailing])
|
||||
|
|
@ -80,7 +80,7 @@ struct Firmware: View {
|
|||
Section(header: Text("Stable")) {
|
||||
ForEach(firmwareReleaseData.releases?.stable ?? [], id: \.id) { fr in
|
||||
Link(destination: URL(string: fr.zipUrl ?? "")!) {
|
||||
HStack() {
|
||||
HStack {
|
||||
Text(fr.title ?? "Unknown")
|
||||
.font(.caption)
|
||||
Spacer()
|
||||
|
|
@ -93,7 +93,7 @@ struct Firmware: View {
|
|||
Section("Alpha") {
|
||||
ForEach(firmwareReleaseData.releases?.alpha ?? [], id: \.id) { fr in
|
||||
Link(destination: URL(string: fr.zipUrl ?? "")!) {
|
||||
HStack() {
|
||||
HStack {
|
||||
Text(fr.title ?? "Unknown")
|
||||
.font(.caption)
|
||||
Spacer()
|
||||
|
|
@ -106,7 +106,7 @@ struct Firmware: View {
|
|||
Section("Pull Requests") {
|
||||
ForEach(firmwareReleaseData.pullRequests ?? [], id: \.id) { fr in
|
||||
Link(destination: URL(string: fr.zipUrl ?? "")!) {
|
||||
HStack() {
|
||||
HStack {
|
||||
Text(fr.title ?? "Unknown")
|
||||
.font(.caption)
|
||||
Spacer()
|
||||
|
|
@ -123,142 +123,142 @@ struct Firmware: View {
|
|||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func loadData() {
|
||||
|
||||
|
||||
guard let url = URL(string: "https://api.meshtastic.org/github/firmware/list") else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
let request = URLRequest(url: url)
|
||||
URLSession.shared.dataTask(with: request) { data, response, error in
|
||||
|
||||
URLSession.shared.dataTask(with: request) { data, _, _ in
|
||||
|
||||
if let data = data {
|
||||
if let response_obj = try? JSONDecoder().decode(FirmwareRelease.self, from: data) {
|
||||
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.firmwareReleaseData = response_obj
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}.resume()
|
||||
}
|
||||
}
|
||||
|
||||
struct FirmwareRelease: Codable {
|
||||
|
||||
var releases : Releases? = Releases()
|
||||
var pullRequests : [PullRequests]? = []
|
||||
|
||||
|
||||
var releases: Releases? = Releases()
|
||||
var pullRequests: [PullRequests]? = []
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
|
||||
|
||||
case releases = "releases"
|
||||
case pullRequests = "pullRequests"
|
||||
}
|
||||
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
releases = try values.decodeIfPresent(Releases.self , forKey: .releases )
|
||||
pullRequests = try values.decodeIfPresent([PullRequests].self , forKey: .pullRequests )
|
||||
|
||||
releases = try values.decodeIfPresent(Releases.self, forKey: .releases )
|
||||
pullRequests = try values.decodeIfPresent([PullRequests].self, forKey: .pullRequests )
|
||||
}
|
||||
|
||||
|
||||
init() {
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
struct Releases: Codable {
|
||||
|
||||
var stable : [Stable]? = []
|
||||
var alpha : [Alpha]? = []
|
||||
|
||||
|
||||
var stable: [Stable]? = []
|
||||
var alpha: [Alpha]? = []
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case stable = "stable"
|
||||
case alpha = "alpha"
|
||||
}
|
||||
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
stable = try values.decodeIfPresent([Stable].self , forKey: .stable )
|
||||
alpha = try values.decodeIfPresent([Alpha].self , forKey: .alpha )
|
||||
stable = try values.decodeIfPresent([Stable].self, forKey: .stable )
|
||||
alpha = try values.decodeIfPresent([Alpha].self, forKey: .alpha )
|
||||
}
|
||||
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
struct Alpha: Codable {
|
||||
|
||||
var id : String? = nil
|
||||
var title : String? = nil
|
||||
var pageUrl : String? = nil
|
||||
var zipUrl : String? = nil
|
||||
|
||||
|
||||
var id: String?
|
||||
var title: String?
|
||||
var pageUrl: String?
|
||||
var zipUrl: String?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id = "id"
|
||||
case title = "title"
|
||||
case pageUrl = "page_url"
|
||||
case zipUrl = "zip_url"
|
||||
}
|
||||
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
id = try values.decodeIfPresent(String.self , forKey: .id )
|
||||
title = try values.decodeIfPresent(String.self , forKey: .title )
|
||||
pageUrl = try values.decodeIfPresent(String.self , forKey: .pageUrl )
|
||||
zipUrl = try values.decodeIfPresent(String.self , forKey: .zipUrl )
|
||||
id = try values.decodeIfPresent(String.self, forKey: .id )
|
||||
title = try values.decodeIfPresent(String.self, forKey: .title )
|
||||
pageUrl = try values.decodeIfPresent(String.self, forKey: .pageUrl )
|
||||
zipUrl = try values.decodeIfPresent(String.self, forKey: .zipUrl )
|
||||
}
|
||||
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
struct Stable: Codable {
|
||||
|
||||
var id : String? = nil
|
||||
var title : String? = nil
|
||||
var pageUrl : String? = nil
|
||||
var zipUrl : String? = nil
|
||||
|
||||
|
||||
var id: String?
|
||||
var title: String?
|
||||
var pageUrl: String?
|
||||
var zipUrl: String?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id = "id"
|
||||
case title = "title"
|
||||
case pageUrl = "page_url"
|
||||
case zipUrl = "zip_url"
|
||||
}
|
||||
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
id = try values.decodeIfPresent(String.self , forKey: .id )
|
||||
title = try values.decodeIfPresent(String.self , forKey: .title )
|
||||
pageUrl = try values.decodeIfPresent(String.self , forKey: .pageUrl )
|
||||
zipUrl = try values.decodeIfPresent(String.self , forKey: .zipUrl )
|
||||
id = try values.decodeIfPresent(String.self, forKey: .id )
|
||||
title = try values.decodeIfPresent(String.self, forKey: .title )
|
||||
pageUrl = try values.decodeIfPresent(String.self, forKey: .pageUrl )
|
||||
zipUrl = try values.decodeIfPresent(String.self, forKey: .zipUrl )
|
||||
}
|
||||
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
struct PullRequests: Codable {
|
||||
|
||||
var id : String? = nil
|
||||
var title : String? = nil
|
||||
var pageUrl : String? = nil
|
||||
var zipUrl : String? = nil
|
||||
|
||||
|
||||
var id: String?
|
||||
var title: String?
|
||||
var pageUrl: String?
|
||||
var zipUrl: String?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id = "id"
|
||||
case title = "title"
|
||||
case pageUrl = "page_url"
|
||||
case zipUrl = "zip_url"
|
||||
}
|
||||
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
id = try values.decodeIfPresent(String.self , forKey: .id )
|
||||
title = try values.decodeIfPresent(String.self , forKey: .title )
|
||||
pageUrl = try values.decodeIfPresent(String.self , forKey: .pageUrl )
|
||||
zipUrl = try values.decodeIfPresent(String.self , forKey: .zipUrl )
|
||||
id = try values.decodeIfPresent(String.self, forKey: .id )
|
||||
title = try values.decodeIfPresent(String.self, forKey: .title )
|
||||
pageUrl = try values.decodeIfPresent(String.self, forKey: .pageUrl )
|
||||
zipUrl = try values.decodeIfPresent(String.self, forKey: .zipUrl )
|
||||
}
|
||||
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ struct ShareChannels: View {
|
|||
.font(.caption)
|
||||
.fontWeight(.bold)
|
||||
}
|
||||
ForEach(node!.myInfo!.channels?.array as! [ChannelEntity], id: \.self) { (channel: ChannelEntity) in
|
||||
ForEach(node?.myInfo?.channels?.array as? [ChannelEntity] ?? [], id: \.self) { (channel: ChannelEntity) in
|
||||
GridRow {
|
||||
Spacer()
|
||||
if channel.index == 0 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue