2022-05-27 19:18:33 -07:00
|
|
|
|
//
|
|
|
|
|
|
// MeshPackets.swift
|
|
|
|
|
|
// Meshtastic Apple
|
|
|
|
|
|
//
|
|
|
|
|
|
// Created by Garth Vander Houwen on 5/27/22.
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
|
|
import CoreData
|
2022-06-12 01:25:42 -07:00
|
|
|
|
import SwiftUI
|
2023-03-02 17:26:29 -08:00
|
|
|
|
#if canImport(ActivityKit)
|
|
|
|
|
|
import ActivityKit
|
|
|
|
|
|
#endif
|
2022-06-12 01:25:42 -07:00
|
|
|
|
|
2022-12-23 23:48:35 -08:00
|
|
|
|
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 {
|
|
|
|
|
|
let address = message[range]
|
|
|
|
|
|
let urlEncodedAddress = address.addingPercentEncoding(withAllowedCharacters: .alphanumerics)
|
|
|
|
|
|
messageWithMarkdown = messageWithMarkdown.replacingOccurrences(of: address, with: "[\(address)](http://maps.apple.com/?address=\(urlEncodedAddress ?? ""))")
|
|
|
|
|
|
} else if match.resultType == .phoneNumber {
|
|
|
|
|
|
let phone = messageWithMarkdown[range]
|
|
|
|
|
|
messageWithMarkdown = messageWithMarkdown.replacingOccurrences(of: phone, with: "[\(phone)](tel:\(phone))")
|
|
|
|
|
|
} else if match.resultType == .link {
|
2022-12-24 21:35:50 -08:00
|
|
|
|
let url = messageWithMarkdown[range]
|
|
|
|
|
|
let absoluteUrl = match.url?.absoluteString ?? ""
|
|
|
|
|
|
messageWithMarkdown = messageWithMarkdown.replacingOccurrences(of: url, with: "[\(String(match.url?.host ?? "Link"))\(String(match.url?.path ?? ""))](\(absoluteUrl))")
|
2022-12-23 23:48:35 -08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return messageWithMarkdown
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-03-06 10:33:18 -08:00
|
|
|
|
func localConfig (config: Config, context: NSManagedObjectContext, nodeNum: Int64, nodeLongName: String) {
|
2023-01-24 20:33:48 -08:00
|
|
|
|
// We don't care about any of the Power settings, config is available for everything else
|
2022-09-10 17:38:10 -07:00
|
|
|
|
if config.payloadVariant == Config.OneOf_PayloadVariant.bluetooth(config.bluetooth) {
|
2023-01-31 22:08:03 -08:00
|
|
|
|
upsertBluetoothConfigPacket(config: config.bluetooth, nodeNum: nodeNum, context: context)
|
2023-01-23 17:56:04 -08:00
|
|
|
|
} else if config.payloadVariant == Config.OneOf_PayloadVariant.device(config.device) {
|
2023-01-31 22:08:03 -08:00
|
|
|
|
upsertDeviceConfigPacket(config: config.device, nodeNum: nodeNum, context: context)
|
2023-01-23 17:56:04 -08:00
|
|
|
|
} else if config.payloadVariant == Config.OneOf_PayloadVariant.display(config.display) {
|
2023-01-31 22:08:03 -08:00
|
|
|
|
upsertDisplayConfigPacket(config: config.display, nodeNum: nodeNum, context: context)
|
2023-01-23 17:56:04 -08:00
|
|
|
|
} else if config.payloadVariant == Config.OneOf_PayloadVariant.lora(config.lora) {
|
2023-01-31 10:50:17 -08:00
|
|
|
|
upsertLoRaConfigPacket(config: config.lora, nodeNum: nodeNum, context: context)
|
2023-01-23 17:56:04 -08:00
|
|
|
|
} else if config.payloadVariant == Config.OneOf_PayloadVariant.network(config.network) {
|
2023-01-31 22:20:16 -08:00
|
|
|
|
upsertNetworkConfigPacket(config: config.network, nodeNum: nodeNum, context: context)
|
2023-01-23 17:56:04 -08:00
|
|
|
|
} else if config.payloadVariant == Config.OneOf_PayloadVariant.position(config.position) {
|
2023-01-31 22:20:16 -08:00
|
|
|
|
upsertPositionConfigPacket(config: config.position, nodeNum: nodeNum, context: context)
|
2022-06-21 13:10:30 -07:00
|
|
|
|
}
|
2022-06-15 22:11:37 -07:00
|
|
|
|
}
|
2022-05-27 19:18:33 -07:00
|
|
|
|
|
2023-03-06 10:33:18 -08:00
|
|
|
|
func moduleConfig (config: ModuleConfig, context: NSManagedObjectContext, nodeNum: Int64, nodeLongName: String) {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-07-02 11:28:25 -07:00
|
|
|
|
if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.cannedMessage(config.cannedMessage) {
|
2023-02-01 09:19:45 -08:00
|
|
|
|
upsertCannedMessagesModuleConfigPacket(config: config.cannedMessage, nodeNum: nodeNum, context: context)
|
|
|
|
|
|
} else if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.externalNotification(config.externalNotification) {
|
|
|
|
|
|
upsertExternalNotificationModuleConfigPacket(config: config.externalNotification, nodeNum: nodeNum, context: context)
|
|
|
|
|
|
} else if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.mqtt(config.mqtt) {
|
|
|
|
|
|
upsertMqttModuleConfigPacket(config: config.mqtt, nodeNum: nodeNum, context: context)
|
|
|
|
|
|
} else if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.rangeTest(config.rangeTest) {
|
|
|
|
|
|
upsertRangeTestModuleConfigPacket(config: config.rangeTest, nodeNum: nodeNum, context: context)
|
|
|
|
|
|
} else if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.serial(config.serial) {
|
|
|
|
|
|
upsertSerialModuleConfigPacket(config: config.serial, nodeNum: nodeNum, context: context)
|
|
|
|
|
|
} else if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.telemetry(config.telemetry) {
|
|
|
|
|
|
upsertTelemetryModuleConfigPacket(config: config.telemetry, nodeNum: nodeNum, context: context)
|
2022-07-02 13:25:34 -07:00
|
|
|
|
}
|
2022-06-28 06:56:50 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-10-15 10:14:08 -07:00
|
|
|
|
func myInfoPacket (myInfo: MyNodeInfo, peripheralId: String, context: NSManagedObjectContext) -> MyInfoEntity? {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-05-05 09:27:24 -07:00
|
|
|
|
let logString = String.localizedStringWithFormat("mesh.log.myinfo %@".localized, String(myInfo.myNodeNum))
|
2023-01-01 22:34:58 -08:00
|
|
|
|
MeshLogger.log("ℹ️ \(logString)")
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
|
|
|
|
|
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(myInfo.myNodeNum))
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
do {
|
2023-03-06 15:30:10 -08:00
|
|
|
|
guard let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as? [MyInfoEntity] else {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
2022-06-01 23:23:02 -07:00
|
|
|
|
// Not Found Insert
|
|
|
|
|
|
if fetchedMyInfo.isEmpty {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
let myInfoEntity = MyInfoEntity(context: context)
|
2022-10-14 22:18:28 -07:00
|
|
|
|
myInfoEntity.peripheralId = peripheralId
|
2022-06-01 23:23:02 -07:00
|
|
|
|
myInfoEntity.myNodeNum = Int64(myInfo.myNodeNum)
|
2023-06-07 17:19:36 -07:00
|
|
|
|
myInfoEntity.rebootCount = Int32(myInfo.rebootCount)
|
2022-06-01 23:23:02 -07:00
|
|
|
|
myInfoEntity.minAppVersion = Int32(bitPattern: myInfo.minAppVersion)
|
|
|
|
|
|
do {
|
|
|
|
|
|
try context.save()
|
2022-12-30 19:21:22 -08:00
|
|
|
|
print("💾 Saved a new myInfo for node number: \(String(myInfo.myNodeNum))")
|
2022-06-01 23:23:02 -07:00
|
|
|
|
return myInfoEntity
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
context.rollback()
|
|
|
|
|
|
let nsError = error as NSError
|
|
|
|
|
|
print("💥 Error Inserting New Core Data MyInfoEntity: \(nsError)")
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-10-14 22:18:28 -07:00
|
|
|
|
fetchedMyInfo[0].peripheralId = peripheralId
|
2022-06-01 23:23:02 -07:00
|
|
|
|
fetchedMyInfo[0].myNodeNum = Int64(myInfo.myNodeNum)
|
2023-06-07 17:19:36 -07:00
|
|
|
|
fetchedMyInfo[0].rebootCount = Int32(myInfo.rebootCount)
|
2022-06-01 23:23:02 -07:00
|
|
|
|
fetchedMyInfo[0].minAppVersion = Int32(bitPattern: myInfo.minAppVersion)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
do {
|
|
|
|
|
|
try context.save()
|
2022-12-30 19:21:22 -08:00
|
|
|
|
print("💾 Updated myInfo for node number: \(String(myInfo.myNodeNum))")
|
2022-06-01 23:23:02 -07:00
|
|
|
|
return fetchedMyInfo[0]
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
context.rollback()
|
|
|
|
|
|
let nsError = error as NSError
|
|
|
|
|
|
print("💥 Error Updating Core Data MyInfoEntity: \(nsError)")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
print("💥 Fetch MyInfo Error")
|
|
|
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-10-15 10:14:08 -07:00
|
|
|
|
func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectContext) {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-03-06 10:33:18 -08:00
|
|
|
|
if channel.isInitialized && channel.hasSettings && channel.role != Channel.Role.disabled {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-05-05 17:46:24 -07:00
|
|
|
|
let logString = String.localizedStringWithFormat("mesh.log.channel.received %d %@".localized, channel.index, String(fromNum))
|
2023-01-01 22:34:58 -08:00
|
|
|
|
MeshLogger.log("🎛️ \(logString)")
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-10-09 18:32:21 -07:00
|
|
|
|
let fetchedMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
2023-01-02 20:11:58 -08:00
|
|
|
|
fetchedMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", fromNum)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-10-09 18:32:21 -07:00
|
|
|
|
do {
|
2023-03-06 15:30:10 -08:00
|
|
|
|
guard let fetchedMyInfo = try context.fetch(fetchedMyInfoRequest) as? [MyInfoEntity] else {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2022-10-28 18:53:10 -07:00
|
|
|
|
if fetchedMyInfo.count == 1 {
|
2022-10-10 07:17:57 -07:00
|
|
|
|
let newChannel = ChannelEntity(context: context)
|
2022-12-17 23:53:06 -08:00
|
|
|
|
newChannel.id = Int32(channel.index)
|
2022-10-10 07:17:57 -07:00
|
|
|
|
newChannel.index = Int32(channel.index)
|
|
|
|
|
|
newChannel.uplinkEnabled = channel.settings.uplinkEnabled
|
|
|
|
|
|
newChannel.downlinkEnabled = channel.settings.downlinkEnabled
|
|
|
|
|
|
newChannel.name = channel.settings.name
|
|
|
|
|
|
newChannel.role = Int32(channel.role.rawValue)
|
2022-10-11 04:32:17 -07:00
|
|
|
|
newChannel.psk = channel.settings.psk
|
2023-03-06 15:30:10 -08:00
|
|
|
|
guard let mutableChannels = fetchedMyInfo[0].channels!.mutableCopy() as? NSMutableOrderedSet else {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2022-11-06 09:21:46 -08:00
|
|
|
|
if mutableChannels.contains(newChannel) {
|
|
|
|
|
|
mutableChannels.replaceObject(at: Int(newChannel.index), with: newChannel)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
mutableChannels.add(newChannel)
|
2022-10-29 07:31:50 -07:00
|
|
|
|
}
|
2022-10-10 07:17:57 -07:00
|
|
|
|
fetchedMyInfo[0].channels = mutableChannels.copy() as? NSOrderedSet
|
2023-01-19 22:04:18 -08:00
|
|
|
|
if newChannel.name?.lowercased() == "admin" {
|
|
|
|
|
|
fetchedMyInfo[0].adminIndex = newChannel.index
|
|
|
|
|
|
}
|
2022-10-28 18:53:10 -07:00
|
|
|
|
do {
|
|
|
|
|
|
try context.save()
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
print("Failed to save channel")
|
|
|
|
|
|
}
|
2022-12-30 19:21:22 -08:00
|
|
|
|
print("💾 Updated MyInfo channel \(channel.index) from Channel App Packet For: \(fetchedMyInfo[0].myNodeNum)")
|
2022-10-22 07:35:55 -07:00
|
|
|
|
} else if channel.role.rawValue > 0 {
|
2022-10-09 18:32:21 -07:00
|
|
|
|
print("💥 Trying to save a channel to a MyInfo that does not exist: \(fromNum)")
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
context.rollback()
|
|
|
|
|
|
let nsError = error as NSError
|
|
|
|
|
|
print("💥 Error Saving MyInfo Channel from ADMIN_APP \(nsError)")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2023-01-19 22:04:18 -08:00
|
|
|
|
func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, context: NSManagedObjectContext) {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-19 22:04:18 -08:00
|
|
|
|
if metadata.isInitialized {
|
2023-05-05 09:27:24 -07:00
|
|
|
|
let logString = String.localizedStringWithFormat("mesh.log.device.metadata.received %@".localized, String(fromNum))
|
2023-01-21 07:28:50 -08:00
|
|
|
|
MeshLogger.log("🏷️ \(logString)")
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-19 22:04:18 -08:00
|
|
|
|
let fetchedNodeRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
|
|
|
|
|
fetchedNodeRequest.predicate = NSPredicate(format: "num == %lld", fromNum)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-19 22:04:18 -08:00
|
|
|
|
do {
|
2023-03-06 15:30:10 -08:00
|
|
|
|
guard let fetchedNode = try context.fetch(fetchedNodeRequest) as? [NodeInfoEntity] else {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2023-01-24 20:33:48 -08:00
|
|
|
|
if fetchedNode.count > 0 {
|
2023-01-19 22:04:18 -08:00
|
|
|
|
let newMetadata = DeviceMetadataEntity(context: context)
|
|
|
|
|
|
newMetadata.firmwareVersion = metadata.firmwareVersion
|
|
|
|
|
|
newMetadata.deviceStateVersion = Int32(metadata.deviceStateVersion)
|
|
|
|
|
|
newMetadata.canShutdown = metadata.canShutdown
|
|
|
|
|
|
newMetadata.hasWifi = metadata.hasWifi_p
|
|
|
|
|
|
newMetadata.hasBluetooth = metadata.hasBluetooth_p
|
|
|
|
|
|
newMetadata.hasEthernet = metadata.hasEthernet_p
|
|
|
|
|
|
newMetadata.role = Int32(metadata.role.rawValue)
|
|
|
|
|
|
newMetadata.positionFlags = Int32(metadata.positionFlags)
|
2023-06-07 17:19:36 -07:00
|
|
|
|
// Swift does strings weird, this does work to get the version without the github hash
|
|
|
|
|
|
let lastDotIndex = metadata.firmwareVersion.lastIndex(of: ".")
|
|
|
|
|
|
var version = metadata.firmwareVersion[...(lastDotIndex ?? String.Index(utf16Offset: 6, in: metadata.firmwareVersion))]
|
|
|
|
|
|
version = version.dropLast()
|
|
|
|
|
|
newMetadata.firmwareVersion = String(version)
|
2023-01-19 22:04:18 -08:00
|
|
|
|
fetchedNode[0].metadata = newMetadata
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-19 22:04:18 -08:00
|
|
|
|
do {
|
|
|
|
|
|
try context.save()
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
print("Failed to save device metadata")
|
|
|
|
|
|
}
|
|
|
|
|
|
print("💾 Updated Device Metadata from Admin App Packet For: \(fromNum)")
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
context.rollback()
|
|
|
|
|
|
let nsError = error as NSError
|
|
|
|
|
|
print("💥 Error Saving MyInfo Channel from ADMIN_APP \(nsError)")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-10-30 19:27:15 -07:00
|
|
|
|
func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObjectContext) -> NodeInfoEntity? {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-05-05 09:27:24 -07:00
|
|
|
|
let logString = String.localizedStringWithFormat("mesh.log.nodeinfo.received %@".localized, String(nodeInfo.num))
|
2023-01-01 22:34:58 -08:00
|
|
|
|
MeshLogger.log("📟 \(logString)")
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-03-06 10:33:18 -08:00
|
|
|
|
guard nodeInfo.num > 0 else { return nil }
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
|
|
|
|
|
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeInfo.num))
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
do {
|
2023-03-06 15:30:10 -08:00
|
|
|
|
guard let fetchedNode = try context.fetch(fetchNodeInfoRequest) as? [NodeInfoEntity] else {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
2022-06-01 23:23:02 -07:00
|
|
|
|
// Not Found Insert
|
|
|
|
|
|
if fetchedNode.isEmpty && nodeInfo.hasUser {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
let newNode = NodeInfoEntity(context: context)
|
|
|
|
|
|
newNode.id = Int64(nodeInfo.num)
|
|
|
|
|
|
newNode.num = Int64(nodeInfo.num)
|
2023-04-02 15:00:15 -07:00
|
|
|
|
newNode.channel = Int32(nodeInfo.channel)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
if nodeInfo.hasDeviceMetrics {
|
|
|
|
|
|
let telemetry = TelemetryEntity(context: context)
|
|
|
|
|
|
telemetry.batteryLevel = Int32(nodeInfo.deviceMetrics.batteryLevel)
|
|
|
|
|
|
telemetry.voltage = nodeInfo.deviceMetrics.voltage
|
|
|
|
|
|
telemetry.channelUtilization = nodeInfo.deviceMetrics.channelUtilization
|
|
|
|
|
|
telemetry.airUtilTx = nodeInfo.deviceMetrics.airUtilTx
|
|
|
|
|
|
var newTelemetries = [TelemetryEntity]()
|
|
|
|
|
|
newTelemetries.append(telemetry)
|
|
|
|
|
|
newNode.telemetries? = NSOrderedSet(array: newTelemetries)
|
|
|
|
|
|
}
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
newNode.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.lastHeard)))
|
|
|
|
|
|
newNode.snr = nodeInfo.snr
|
|
|
|
|
|
if nodeInfo.hasUser {
|
|
|
|
|
|
let newUser = UserEntity(context: context)
|
|
|
|
|
|
newUser.userId = nodeInfo.user.id
|
|
|
|
|
|
newUser.num = Int64(nodeInfo.num)
|
|
|
|
|
|
newUser.longName = nodeInfo.user.longName
|
|
|
|
|
|
newUser.shortName = nodeInfo.user.shortName
|
|
|
|
|
|
newUser.hwModel = String(describing: nodeInfo.user.hwModel).uppercased()
|
|
|
|
|
|
newNode.user = newUser
|
|
|
|
|
|
}
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-03-06 10:33:18 -08:00
|
|
|
|
if nodeInfo.position.longitudeI > 0 || nodeInfo.position.latitudeI > 0 && (nodeInfo.position.latitudeI != 373346000 && nodeInfo.position.longitudeI != -1220090000) {
|
2022-07-07 00:29:52 -07:00
|
|
|
|
let position = PositionEntity(context: context)
|
2023-03-24 23:16:34 -07:00
|
|
|
|
position.latest = true
|
2022-10-02 10:36:14 -07:00
|
|
|
|
position.seqNo = Int32(nodeInfo.position.seqNumber)
|
2022-07-07 00:29:52 -07:00
|
|
|
|
position.latitudeI = nodeInfo.position.latitudeI
|
|
|
|
|
|
position.longitudeI = nodeInfo.position.longitudeI
|
|
|
|
|
|
position.altitude = nodeInfo.position.altitude
|
2022-09-01 11:54:39 -07:00
|
|
|
|
position.satsInView = Int32(nodeInfo.position.satsInView)
|
2022-10-02 10:36:14 -07:00
|
|
|
|
position.speed = Int32(nodeInfo.position.groundSpeed)
|
|
|
|
|
|
position.heading = Int32(nodeInfo.position.groundTrack)
|
2022-07-07 00:29:52 -07:00
|
|
|
|
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.position.time)))
|
|
|
|
|
|
var newPostions = [PositionEntity]()
|
|
|
|
|
|
newPostions.append(position)
|
|
|
|
|
|
newNode.positions? = NSOrderedSet(array: newPostions)
|
|
|
|
|
|
}
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
// Look for a MyInfo
|
|
|
|
|
|
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
|
|
|
|
|
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(nodeInfo.num))
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
do {
|
2023-03-06 15:30:10 -08:00
|
|
|
|
guard let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as? [MyInfoEntity] else {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
2022-06-01 23:23:02 -07:00
|
|
|
|
if fetchedMyInfo.count > 0 {
|
|
|
|
|
|
newNode.myInfo = fetchedMyInfo[0]
|
|
|
|
|
|
}
|
|
|
|
|
|
do {
|
|
|
|
|
|
try context.save()
|
|
|
|
|
|
return newNode
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
context.rollback()
|
|
|
|
|
|
let nsError = error as NSError
|
|
|
|
|
|
print("💥 Error Saving Core Data NodeInfoEntity: \(nsError)")
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
print("💥 Fetch MyInfo Error")
|
|
|
|
|
|
}
|
|
|
|
|
|
} else if nodeInfo.hasUser && nodeInfo.num > 0 {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
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
|
2023-04-02 15:00:15 -07:00
|
|
|
|
fetchedNode[0].channel = Int32(nodeInfo.channel)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
if nodeInfo.hasUser {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
fetchedNode[0].user!.userId = nodeInfo.user.id
|
|
|
|
|
|
fetchedNode[0].user!.num = Int64(nodeInfo.num)
|
|
|
|
|
|
fetchedNode[0].user!.longName = nodeInfo.user.longName
|
|
|
|
|
|
fetchedNode[0].user!.shortName = nodeInfo.user.shortName
|
|
|
|
|
|
fetchedNode[0].user!.hwModel = String(describing: nodeInfo.user.hwModel).uppercased()
|
|
|
|
|
|
}
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
if nodeInfo.hasDeviceMetrics {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
let newTelemetry = TelemetryEntity(context: context)
|
|
|
|
|
|
newTelemetry.batteryLevel = Int32(nodeInfo.deviceMetrics.batteryLevel)
|
|
|
|
|
|
newTelemetry.voltage = nodeInfo.deviceMetrics.voltage
|
|
|
|
|
|
newTelemetry.channelUtilization = nodeInfo.deviceMetrics.channelUtilization
|
|
|
|
|
|
newTelemetry.airUtilTx = nodeInfo.deviceMetrics.airUtilTx
|
2023-03-08 21:32:21 -08:00
|
|
|
|
guard let mutableTelemetries = fetchedNode[0].telemetries!.mutableCopy() as? NSMutableOrderedSet else {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
2022-06-01 23:23:02 -07:00
|
|
|
|
fetchedNode[0].telemetries = mutableTelemetries.copy() as? NSOrderedSet
|
|
|
|
|
|
}
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
if nodeInfo.hasPosition {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-25 23:01:45 -08:00
|
|
|
|
if nodeInfo.position.longitudeI > 0 || nodeInfo.position.latitudeI > 0 && (nodeInfo.position.latitudeI != 373346000 && nodeInfo.position.longitudeI != -1220090000) {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-25 23:01:45 -08:00
|
|
|
|
let position = PositionEntity(context: context)
|
|
|
|
|
|
position.latitudeI = nodeInfo.position.latitudeI
|
|
|
|
|
|
position.longitudeI = nodeInfo.position.longitudeI
|
|
|
|
|
|
position.altitude = nodeInfo.position.altitude
|
|
|
|
|
|
position.satsInView = Int32(nodeInfo.position.satsInView)
|
|
|
|
|
|
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.position.time)))
|
2023-03-08 21:32:21 -08:00
|
|
|
|
guard let mutablePositions = fetchedNode[0].positions!.mutableCopy() as? NSMutableOrderedSet else {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
2023-01-25 23:01:45 -08:00
|
|
|
|
fetchedNode[0].positions = mutablePositions.copy() as? NSOrderedSet
|
|
|
|
|
|
}
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
}
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
// Look for a MyInfo
|
|
|
|
|
|
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
|
|
|
|
|
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(nodeInfo.num))
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
do {
|
2023-03-06 15:30:10 -08:00
|
|
|
|
guard let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as? [MyInfoEntity] else {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
2022-06-01 23:23:02 -07:00
|
|
|
|
if fetchedMyInfo.count > 0 {
|
|
|
|
|
|
fetchedNode[0].myInfo = fetchedMyInfo[0]
|
|
|
|
|
|
}
|
|
|
|
|
|
do {
|
|
|
|
|
|
try context.save()
|
2022-12-30 22:30:15 -08:00
|
|
|
|
print("💾 NodeInfo saved for \(nodeInfo.num)")
|
2022-06-01 23:23:02 -07:00
|
|
|
|
return fetchedNode[0]
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
context.rollback()
|
|
|
|
|
|
let nsError = error as NSError
|
|
|
|
|
|
print("💥 Error Saving Core Data NodeInfoEntity: \(nsError)")
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
print("💥 Fetch MyInfo Error")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
print("💥 Fetch NodeInfoEntity Error")
|
|
|
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-10-15 10:14:08 -07:00
|
|
|
|
func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-06 00:56:44 -08:00
|
|
|
|
if let adminMessage = try? AdminMessage(serializedData: packet.decoded.payload) {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-06 00:56:44 -08:00
|
|
|
|
if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getCannedMessageModuleMessagesResponse(adminMessage.getCannedMessageModuleMessagesResponse) {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-06 00:56:44 -08:00
|
|
|
|
if let cmmc = try? CannedMessageModuleConfig(serializedData: packet.decoded.payload) {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-06 00:56:44 -08:00
|
|
|
|
if !cmmc.messages.isEmpty {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-05-05 09:27:24 -07:00
|
|
|
|
let logString = String.localizedStringWithFormat("mesh.log.cannedmessages.messages.received %@".localized, String(packet.from))
|
2023-01-06 00:56:44 -08:00
|
|
|
|
MeshLogger.log("🥫 \(logString)")
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-06 00:56:44 -08:00
|
|
|
|
let fetchNodeRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
|
|
|
|
|
fetchNodeRequest.predicate = NSPredicate(format: "num == %lld", Int64(packet.from))
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-03 21:45:10 -08:00
|
|
|
|
do {
|
2023-03-06 15:30:10 -08:00
|
|
|
|
guard let fetchedNode = try context.fetch(fetchNodeRequest) as? [NodeInfoEntity] else {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2023-01-06 00:56:44 -08:00
|
|
|
|
if fetchedNode.count == 1 {
|
|
|
|
|
|
let messages = String(cmmc.textFormatString())
|
|
|
|
|
|
.replacingOccurrences(of: "11: ", with: "")
|
|
|
|
|
|
.replacingOccurrences(of: "\"", with: "")
|
|
|
|
|
|
.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
|
|
|
|
fetchedNode[0].cannedMessageConfig?.messages = messages
|
|
|
|
|
|
do {
|
|
|
|
|
|
try context.save()
|
|
|
|
|
|
print("💾 Updated Canned Messages Messages For: \(fetchedNode[0].num)")
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
context.rollback()
|
|
|
|
|
|
let nsError = error as NSError
|
|
|
|
|
|
print("💥 Error Saving NodeInfoEntity from POSITION_APP \(nsError)")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-01-03 21:45:10 -08:00
|
|
|
|
} catch {
|
2023-01-06 00:56:44 -08:00
|
|
|
|
print("💥 Error Deserializing ADMIN_APP packet.")
|
2023-01-03 21:45:10 -08:00
|
|
|
|
}
|
2022-12-29 16:26:00 -08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-01-19 22:04:18 -08:00
|
|
|
|
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getChannelResponse(adminMessage.getChannelResponse) {
|
2023-01-09 16:02:43 -08:00
|
|
|
|
channelPacket(channel: adminMessage.getChannelResponse, fromNum: Int64(packet.from), context: context)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-19 22:04:18 -08:00
|
|
|
|
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getDeviceMetadataResponse(adminMessage.getDeviceMetadataResponse) {
|
|
|
|
|
|
deviceMetadataPacket(metadata: adminMessage.getDeviceMetadataResponse, fromNum: Int64(packet.from), context: context)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-21 07:28:50 -08:00
|
|
|
|
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getConfigResponse(adminMessage.getConfigResponse) {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-31 22:08:03 -08:00
|
|
|
|
let config = adminMessage.getConfigResponse
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-31 22:08:03 -08:00
|
|
|
|
if config.payloadVariant == Config.OneOf_PayloadVariant.bluetooth(config.bluetooth) {
|
|
|
|
|
|
upsertBluetoothConfigPacket(config: config.bluetooth, nodeNum: Int64(packet.from), context: context)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-31 22:08:03 -08:00
|
|
|
|
} else if config.payloadVariant == Config.OneOf_PayloadVariant.device(config.device) {
|
|
|
|
|
|
upsertDeviceConfigPacket(config: config.device, nodeNum: Int64(packet.from), context: context)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-03-19 08:31:16 -07:00
|
|
|
|
} else if config.payloadVariant == Config.OneOf_PayloadVariant.display(config.display) {
|
|
|
|
|
|
upsertDisplayConfigPacket(config: config.display, nodeNum: Int64(packet.from), context: context)
|
|
|
|
|
|
|
2023-01-31 22:08:03 -08:00
|
|
|
|
} else if config.payloadVariant == Config.OneOf_PayloadVariant.lora(config.lora) {
|
|
|
|
|
|
upsertLoRaConfigPacket(config: config.lora, nodeNum: Int64(packet.from), context: context)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-31 22:08:03 -08:00
|
|
|
|
} else if config.payloadVariant == Config.OneOf_PayloadVariant.network(config.network) {
|
2023-01-31 22:20:16 -08:00
|
|
|
|
upsertNetworkConfigPacket(config: config.network, nodeNum: Int64(packet.from), context: context)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-31 22:08:03 -08:00
|
|
|
|
} else if config.payloadVariant == Config.OneOf_PayloadVariant.position(config.position) {
|
2023-01-31 22:20:16 -08:00
|
|
|
|
upsertPositionConfigPacket(config: config.position, nodeNum: Int64(packet.from), context: context)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-20 19:14:49 -08:00
|
|
|
|
}
|
2023-02-01 09:19:45 -08:00
|
|
|
|
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getModuleConfigResponse(adminMessage.getModuleConfigResponse) {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-02-01 09:19:45 -08:00
|
|
|
|
let moduleConfig = adminMessage.getModuleConfigResponse
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-02-01 09:19:45 -08:00
|
|
|
|
if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.cannedMessage(moduleConfig.cannedMessage) {
|
|
|
|
|
|
upsertCannedMessagesModuleConfigPacket(config: moduleConfig.cannedMessage, nodeNum: Int64(packet.from), context: context)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-02-01 09:19:45 -08:00
|
|
|
|
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.externalNotification(moduleConfig.externalNotification) {
|
|
|
|
|
|
upsertExternalNotificationModuleConfigPacket(config: moduleConfig.externalNotification, nodeNum: Int64(packet.from), context: context)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-02-01 09:19:45 -08:00
|
|
|
|
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.mqtt(moduleConfig.mqtt) {
|
|
|
|
|
|
upsertMqttModuleConfigPacket(config: moduleConfig.mqtt, nodeNum: Int64(packet.from), context: context)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-02-01 09:19:45 -08:00
|
|
|
|
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.rangeTest(moduleConfig.rangeTest) {
|
|
|
|
|
|
upsertRangeTestModuleConfigPacket(config: moduleConfig.rangeTest, nodeNum: Int64(packet.from), context: context)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-02-01 09:19:45 -08:00
|
|
|
|
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.serial(moduleConfig.serial) {
|
|
|
|
|
|
upsertSerialModuleConfigPacket(config: moduleConfig.serial, nodeNum: Int64(packet.from), context: context)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-02-01 09:19:45 -08:00
|
|
|
|
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.telemetry(moduleConfig.telemetry) {
|
|
|
|
|
|
upsertTelemetryModuleConfigPacket(config: moduleConfig.telemetry, nodeNum: Int64(packet.from), context: context)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-02-01 09:19:45 -08:00
|
|
|
|
}
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-03-25 22:14:39 -07:00
|
|
|
|
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getRingtoneResponse(adminMessage.getRingtoneResponse) {
|
|
|
|
|
|
let ringtone = adminMessage.getRingtoneResponse
|
|
|
|
|
|
upsertRtttlConfigPacket(ringtone: ringtone, nodeNum: Int64(packet.from), context: context)
|
2023-01-21 07:28:50 -08:00
|
|
|
|
} else {
|
|
|
|
|
|
MeshLogger.log("🕸️ MESH PACKET received for Admin App \(try! packet.decoded.jsonString())")
|
2023-01-06 00:56:44 -08:00
|
|
|
|
}
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-02-02 21:23:42 -08:00
|
|
|
|
// 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) {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-02-02 21:23:42 -08:00
|
|
|
|
let fetchedAdminMessageRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MessageEntity")
|
|
|
|
|
|
fetchedAdminMessageRequest.predicate = NSPredicate(format: "messageId == %lld", packet.decoded.requestID)
|
|
|
|
|
|
do {
|
2023-03-06 15:30:10 -08:00
|
|
|
|
guard let fetchedMessage = try context.fetch(fetchedAdminMessageRequest) as? [MessageEntity] else {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2023-02-02 21:23:42 -08:00
|
|
|
|
if fetchedMessage.count > 0 {
|
|
|
|
|
|
fetchedMessage[0].ackTimestamp = Int32(Date().timeIntervalSince1970)
|
|
|
|
|
|
fetchedMessage[0].ackError = Int32(RoutingError.none.rawValue)
|
|
|
|
|
|
fetchedMessage[0].receivedACK = true
|
|
|
|
|
|
fetchedMessage[0].realACK = true
|
|
|
|
|
|
fetchedMessage[0].ackSNR = packet.rxSnr
|
|
|
|
|
|
if fetchedMessage[0].fromUser != nil {
|
|
|
|
|
|
fetchedMessage[0].fromUser?.objectWillChange.send()
|
|
|
|
|
|
}
|
|
|
|
|
|
do {
|
|
|
|
|
|
try context.save()
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
print("Failed to save admin message response as an ack")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
print("Failed to fetch admin message by requestID")
|
2022-11-13 09:25:00 -08:00
|
|
|
|
}
|
2022-06-12 01:25:42 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
2022-11-10 22:17:38 -08:00
|
|
|
|
func routingPacket (packet: MeshPacket, connectedNodeNum: Int64, context: NSManagedObjectContext) {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-05-27 19:18:33 -07:00
|
|
|
|
if let routingMessage = try? Routing(serializedData: packet.decoded.payload) {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-12-30 21:28:51 -08:00
|
|
|
|
let routingError = RoutingError(rawValue: routingMessage.errorReason.rawValue)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-05-05 09:27:24 -07:00
|
|
|
|
let routingErrorString = routingError?.display ?? "unknown".localized
|
|
|
|
|
|
let logString = String.localizedStringWithFormat("mesh.log.routing.message %@ %@".localized, String(packet.decoded.requestID), routingErrorString)
|
2023-01-01 22:58:54 -08:00
|
|
|
|
MeshLogger.log("🕸️ \(logString)")
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-08-04 19:43:03 -07:00
|
|
|
|
let fetchMessageRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MessageEntity")
|
|
|
|
|
|
fetchMessageRequest.predicate = NSPredicate(format: "messageId == %lld", Int64(packet.decoded.requestID))
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-08-04 19:43:03 -07:00
|
|
|
|
do {
|
|
|
|
|
|
let fetchedMessage = try context.fetch(fetchMessageRequest) as? [MessageEntity]
|
|
|
|
|
|
if fetchedMessage?.count ?? 0 > 0 {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-12-29 16:26:00 -08:00
|
|
|
|
if fetchedMessage![0].toUser != nil {
|
|
|
|
|
|
// Real ACK from DM Recipient
|
|
|
|
|
|
if packet.to != packet.from {
|
|
|
|
|
|
fetchedMessage![0].realACK = true
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-08-04 19:43:03 -07:00
|
|
|
|
fetchedMessage![0].ackError = Int32(routingMessage.errorReason.rawValue)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-08-04 19:43:03 -07:00
|
|
|
|
if routingMessage.errorReason == Routing.Error.none {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-29 20:04:20 -07:00
|
|
|
|
fetchedMessage![0].receivedACK = true
|
2022-05-27 19:18:33 -07:00
|
|
|
|
}
|
2022-08-04 19:43:03 -07:00
|
|
|
|
fetchedMessage![0].ackSNR = packet.rxSnr
|
|
|
|
|
|
fetchedMessage![0].ackTimestamp = Int32(packet.rxTime)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-11-10 22:17:38 -08:00
|
|
|
|
if fetchedMessage![0].toUser != nil {
|
|
|
|
|
|
fetchedMessage![0].toUser?.objectWillChange.send()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
|
|
|
|
|
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", connectedNodeNum)
|
|
|
|
|
|
do {
|
|
|
|
|
|
let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as? [MyInfoEntity]
|
|
|
|
|
|
if fetchedMyInfo?.count ?? 0 > 0 {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-03-14 13:01:35 -07:00
|
|
|
|
for ch in fetchedMyInfo![0].channels!.array as? [ChannelEntity] ?? [] {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-11-10 22:17:38 -08:00
|
|
|
|
if ch.index == packet.channel {
|
|
|
|
|
|
ch.objectWillChange.send()
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-11-10 22:17:38 -08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-08-04 19:43:03 -07:00
|
|
|
|
} else {
|
|
|
|
|
|
return
|
2022-05-27 19:18:33 -07:00
|
|
|
|
}
|
2022-08-04 19:43:03 -07:00
|
|
|
|
try context.save()
|
2022-12-30 21:28:51 -08:00
|
|
|
|
print("💾 ACK Saved for Message: \(packet.decoded.requestID)")
|
2022-08-04 19:43:03 -07:00
|
|
|
|
} catch {
|
|
|
|
|
|
context.rollback()
|
|
|
|
|
|
let nsError = error as NSError
|
2022-12-30 21:28:51 -08:00
|
|
|
|
print("💥 Error Saving ACK for message: \(packet.id) Error: \(nsError)")
|
2022-05-27 19:18:33 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-01-14 20:27:05 -08:00
|
|
|
|
|
2022-12-13 17:47:23 -08:00
|
|
|
|
func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManagedObjectContext) {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-05-27 19:18:33 -07:00
|
|
|
|
if let telemetryMessage = try? Telemetry(serializedData: packet.decoded.payload) {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-12-30 21:28:51 -08:00
|
|
|
|
// Only log telemetry from the mesh not the connected device
|
|
|
|
|
|
if connectedNode != Int64(packet.from) {
|
2023-05-05 09:27:24 -07:00
|
|
|
|
let logString = String.localizedStringWithFormat("mesh.log.telemetry.received %@".localized, String(packet.from))
|
2023-01-01 14:48:50 -08:00
|
|
|
|
MeshLogger.log("📈 \(logString)")
|
2023-03-02 17:26:29 -08:00
|
|
|
|
} else {
|
|
|
|
|
|
// If it is the connected node
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-12-30 21:28:51 -08:00
|
|
|
|
}
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-12-30 21:28:51 -08:00
|
|
|
|
let telemetry = TelemetryEntity(context: context)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
let fetchNodeTelemetryRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
|
|
|
|
|
|
fetchNodeTelemetryRequest.predicate = NSPredicate(format: "num == %lld", Int64(packet.from))
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-01 23:23:02 -07:00
|
|
|
|
do {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-03-06 15:30:10 -08:00
|
|
|
|
guard let fetchedNode = try context.fetch(fetchNodeTelemetryRequest) as? [NodeInfoEntity] else {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2022-06-01 23:23:02 -07:00
|
|
|
|
if fetchedNode.count == 1 {
|
2022-07-08 06:31:47 -07:00
|
|
|
|
if telemetryMessage.variant == Telemetry.OneOf_Variant.deviceMetrics(telemetryMessage.deviceMetrics) {
|
|
|
|
|
|
// Device Metrics
|
|
|
|
|
|
telemetry.airUtilTx = telemetryMessage.deviceMetrics.airUtilTx
|
|
|
|
|
|
telemetry.channelUtilization = telemetryMessage.deviceMetrics.channelUtilization
|
|
|
|
|
|
telemetry.batteryLevel = Int32(telemetryMessage.deviceMetrics.batteryLevel)
|
|
|
|
|
|
telemetry.voltage = telemetryMessage.deviceMetrics.voltage
|
|
|
|
|
|
telemetry.metricsType = 0
|
|
|
|
|
|
} else if telemetryMessage.variant == Telemetry.OneOf_Variant.environmentMetrics(telemetryMessage.environmentMetrics) {
|
|
|
|
|
|
// Environment Metrics
|
|
|
|
|
|
telemetry.barometricPressure = telemetryMessage.environmentMetrics.barometricPressure
|
|
|
|
|
|
telemetry.current = telemetryMessage.environmentMetrics.current
|
|
|
|
|
|
telemetry.gasResistance = telemetryMessage.environmentMetrics.gasResistance
|
|
|
|
|
|
telemetry.relativeHumidity = telemetryMessage.environmentMetrics.relativeHumidity
|
|
|
|
|
|
telemetry.temperature = telemetryMessage.environmentMetrics.temperature
|
2022-07-08 12:05:39 -07:00
|
|
|
|
telemetry.current = telemetryMessage.environmentMetrics.current
|
|
|
|
|
|
telemetry.voltage = telemetryMessage.environmentMetrics.voltage
|
2022-07-08 06:31:47 -07:00
|
|
|
|
telemetry.metricsType = 1
|
|
|
|
|
|
}
|
2023-05-04 22:20:22 -07:00
|
|
|
|
telemetry.snr = packet.rxSnr
|
|
|
|
|
|
telemetry.rssi = packet.rxRssi
|
2022-07-08 06:31:47 -07:00
|
|
|
|
telemetry.time = Date(timeIntervalSince1970: TimeInterval(Int64(telemetryMessage.time)))
|
2023-03-08 21:32:21 -08:00
|
|
|
|
guard let mutableTelemetries = fetchedNode[0].telemetries!.mutableCopy() as? NSMutableOrderedSet else {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2022-06-01 23:23:02 -07:00
|
|
|
|
mutableTelemetries.add(telemetry)
|
2022-07-08 06:31:47 -07:00
|
|
|
|
fetchedNode[0].lastHeard = telemetry.time
|
2022-06-01 23:23:02 -07:00
|
|
|
|
fetchedNode[0].telemetries = mutableTelemetries.copy() as? NSOrderedSet
|
|
|
|
|
|
}
|
|
|
|
|
|
try context.save()
|
2022-12-30 21:28:51 -08:00
|
|
|
|
// Only log telemetry from the mesh not the connected device
|
2022-12-13 17:47:23 -08:00
|
|
|
|
if connectedNode != Int64(packet.from) {
|
2022-12-30 21:28:51 -08:00
|
|
|
|
print("💾 Telemetry Saved for Node: \(packet.from)")
|
2023-03-02 17:26:29 -08:00
|
|
|
|
} else if telemetry.metricsType == 0 {
|
2023-03-04 11:11:34 -08:00
|
|
|
|
// Connected Device Metrics
|
|
|
|
|
|
// ------------------------
|
|
|
|
|
|
// Low Battery notification
|
2023-03-05 13:41:40 -08:00
|
|
|
|
if telemetry.batteryLevel > 0 && telemetry.batteryLevel < 5 {
|
2023-03-04 11:11:34 -08:00
|
|
|
|
let content = UNMutableNotificationContent()
|
|
|
|
|
|
content.title = "Critically Low Battery!"
|
2023-03-05 13:41:40 -08:00
|
|
|
|
content.body = "Time to charge your radio, there is \(telemetry.batteryLevel)% battery remaining."
|
2023-03-04 11:11:34 -08:00
|
|
|
|
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
|
|
|
|
|
|
let uuidString = UUID().uuidString
|
2023-03-06 10:33:18 -08:00
|
|
|
|
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
|
2023-03-04 11:11:34 -08:00
|
|
|
|
let notificationCenter = UNUserNotificationCenter.current()
|
|
|
|
|
|
notificationCenter.add(request) { (error) in
|
|
|
|
|
|
if error != nil {
|
|
|
|
|
|
// Handle any errors.
|
|
|
|
|
|
print("Error creating local low battery notification: \(error?.localizedDescription ?? "no description")")
|
|
|
|
|
|
} else {
|
|
|
|
|
|
print("Created local low battery notification.")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
// Update our live activity if there is one running, not available on mac iOS >= 16.2
|
2023-03-10 08:46:53 -08:00
|
|
|
|
#if !targetEnvironment(macCatalyst)
|
2023-03-02 17:26:29 -08:00
|
|
|
|
if #available(iOS 16.2, *) {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-03-02 22:58:49 -08:00
|
|
|
|
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)
|
2023-03-02 17:26:29 -08:00
|
|
|
|
let updatedContent = ActivityContent(state: updatedMeshStatus, staleDate: nil)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-03-02 22:58:49 -08:00
|
|
|
|
let meshActivity = Activity<MeshActivityAttributes>.activities.first(where: { $0.attributes.nodeNum == connectedNode })
|
|
|
|
|
|
if meshActivity != nil {
|
2023-03-02 17:26:29 -08:00
|
|
|
|
Task {
|
2023-03-02 22:58:49 -08:00
|
|
|
|
await meshActivity?.update(updatedContent, alertConfiguration: alertConfiguration)
|
2023-03-06 10:33:18 -08:00
|
|
|
|
// await meshActivity?.update(updatedContent)
|
2023-03-04 11:11:34 -08:00
|
|
|
|
print("Updated live activity.")
|
2023-03-02 17:26:29 -08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-03-10 08:46:53 -08:00
|
|
|
|
#endif
|
2022-12-13 17:47:23 -08:00
|
|
|
|
}
|
2022-06-01 23:23:02 -07:00
|
|
|
|
} catch {
|
|
|
|
|
|
context.rollback()
|
|
|
|
|
|
let nsError = error as NSError
|
2022-12-30 20:04:43 -08:00
|
|
|
|
print("💥 Error Saving Telemetry for Node \(packet.from) Error: \(nsError)")
|
2022-06-01 23:23:02 -07:00
|
|
|
|
}
|
2022-05-27 19:18:33 -07:00
|
|
|
|
} else {
|
2022-12-30 20:04:43 -08:00
|
|
|
|
print("💥 Error Fetching NodeInfoEntity for Node \(packet.from)")
|
2022-05-27 19:18:33 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2022-10-15 10:14:08 -07:00
|
|
|
|
func textMessageAppPacket(packet: MeshPacket, connectedNode: Int64, context: NSManagedObjectContext) {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-05-27 19:18:33 -07:00
|
|
|
|
if let messageText = String(bytes: packet.decoded.payload, encoding: .utf8) {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-05-05 09:27:24 -07:00
|
|
|
|
MeshLogger.log("💬 \("mesh.log.textmessage.received".localized)")
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-05-27 19:18:33 -07:00
|
|
|
|
let messageUsers: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "UserEntity")
|
|
|
|
|
|
messageUsers.predicate = NSPredicate(format: "num IN %@", [packet.to, packet.from])
|
|
|
|
|
|
do {
|
2023-03-06 15:30:10 -08:00
|
|
|
|
guard let fetchedUsers = try context.fetch(messageUsers) as? [UserEntity] else {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2022-05-27 19:18:33 -07:00
|
|
|
|
let newMessage = MessageEntity(context: context)
|
|
|
|
|
|
newMessage.messageId = Int64(packet.id)
|
|
|
|
|
|
newMessage.messageTimestamp = Int32(bitPattern: packet.rxTime)
|
|
|
|
|
|
newMessage.receivedACK = false
|
2022-11-10 23:27:48 -08:00
|
|
|
|
newMessage.snr = packet.rxSnr
|
2023-05-04 22:20:22 -07:00
|
|
|
|
newMessage.rssi = packet.rxRssi
|
2022-05-27 19:18:33 -07:00
|
|
|
|
newMessage.isEmoji = packet.decoded.emoji == 1
|
2022-10-29 07:31:50 -07:00
|
|
|
|
newMessage.channel = Int32(packet.channel)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-05-27 19:18:33 -07:00
|
|
|
|
if packet.decoded.replyID > 0 {
|
|
|
|
|
|
newMessage.replyID = Int64(packet.decoded.replyID)
|
|
|
|
|
|
}
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-11-08 11:30:08 -08:00
|
|
|
|
if fetchedUsers.first(where: { $0.num == packet.to }) != nil && packet.to != 4294967295 {
|
2022-05-27 19:18:33 -07:00
|
|
|
|
newMessage.toUser = fetchedUsers.first(where: { $0.num == packet.to })
|
|
|
|
|
|
}
|
2022-11-07 18:31:12 -08:00
|
|
|
|
if fetchedUsers.first(where: { $0.num == packet.from }) != nil {
|
|
|
|
|
|
newMessage.fromUser = fetchedUsers.first(where: { $0.num == packet.from })
|
|
|
|
|
|
}
|
2022-12-23 23:48:35 -08:00
|
|
|
|
newMessage.messagePayload = messageText
|
|
|
|
|
|
newMessage.messagePayloadMarkdown = generateMessageMarkdown(message: messageText)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-06-06 22:24:35 -07:00
|
|
|
|
newMessage.fromUser?.objectWillChange.send()
|
|
|
|
|
|
newMessage.toUser?.objectWillChange.send()
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-11-08 11:30:08 -08:00
|
|
|
|
var messageSaved = false
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-11-08 11:30:08 -08:00
|
|
|
|
do {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-11-08 11:30:08 -08:00
|
|
|
|
try context.save()
|
2022-12-30 21:28:51 -08:00
|
|
|
|
print("💾 Saved a new message for \(newMessage.messageId)")
|
2022-11-08 11:30:08 -08:00
|
|
|
|
messageSaved = true
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-11-08 11:30:08 -08:00
|
|
|
|
if messageSaved {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-11-26 10:13:46 -08:00
|
|
|
|
if newMessage.fromUser != nil && newMessage.toUser != nil && !(newMessage.fromUser?.mute ?? false) {
|
2022-11-26 10:22:51 -08:00
|
|
|
|
// Create an iOS Notification for the received DM message and schedule it immediately
|
|
|
|
|
|
let manager = LocalNotificationManager()
|
|
|
|
|
|
manager.notifications = [
|
|
|
|
|
|
Notification(
|
|
|
|
|
|
id: ("notification.id.\(newMessage.messageId)"),
|
2023-05-05 09:27:24 -07:00
|
|
|
|
title: "\(newMessage.fromUser?.longName ?? "unknown".localized)",
|
2022-11-26 10:22:51 -08:00
|
|
|
|
subtitle: "AKA \(newMessage.fromUser?.shortName ?? "???")",
|
|
|
|
|
|
content: messageText)
|
|
|
|
|
|
]
|
|
|
|
|
|
manager.schedule()
|
2023-05-05 09:27:24 -07:00
|
|
|
|
print("💬 iOS Notification Scheduled for text message from \(newMessage.fromUser?.longName ?? "unknown".localized)")
|
2022-12-03 01:08:06 -08:00
|
|
|
|
} else if newMessage.fromUser != nil && newMessage.toUser == nil {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-12-18 00:09:08 -08:00
|
|
|
|
let fetchMyInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "MyInfoEntity")
|
|
|
|
|
|
fetchMyInfoRequest.predicate = NSPredicate(format: "myNodeNum == %lld", Int64(connectedNode))
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-12-18 00:09:08 -08:00
|
|
|
|
do {
|
2023-03-06 15:30:10 -08:00
|
|
|
|
guard let fetchedMyInfo = try context.fetch(fetchMyInfoRequest) as? [MyInfoEntity] else {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2023-03-31 12:08:42 -07:00
|
|
|
|
if !fetchedMyInfo.isEmpty {
|
|
|
|
|
|
for channel in (fetchedMyInfo[0].channels?.array ?? []) as? [ChannelEntity] ?? [] {
|
|
|
|
|
|
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()
|
|
|
|
|
|
manager.notifications = [
|
|
|
|
|
|
Notification(
|
|
|
|
|
|
id: ("notification.id.\(newMessage.messageId)"),
|
2023-05-05 09:27:24 -07:00
|
|
|
|
title: "\(newMessage.fromUser?.longName ?? "unknown".localized)",
|
2023-03-31 12:08:42 -07:00
|
|
|
|
subtitle: "AKA \(newMessage.fromUser?.shortName ?? "???")",
|
|
|
|
|
|
content: messageText)
|
|
|
|
|
|
]
|
|
|
|
|
|
manager.schedule()
|
2023-05-05 09:27:24 -07:00
|
|
|
|
print("💬 iOS Notification Scheduled for text message from \(newMessage.fromUser?.longName ?? "unknown".localized)")
|
2023-03-31 12:08:42 -07:00
|
|
|
|
}
|
2022-12-18 00:09:08 -08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2022-12-18 00:09:08 -08:00
|
|
|
|
}
|
2022-06-24 07:48:25 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-11-08 11:30:08 -08:00
|
|
|
|
} catch {
|
|
|
|
|
|
context.rollback()
|
|
|
|
|
|
let nsError = error as NSError
|
2022-12-30 20:04:43 -08:00
|
|
|
|
print("💥 Failed to save new MessageEntity \(nsError)")
|
2022-11-08 11:30:08 -08:00
|
|
|
|
}
|
2022-10-15 10:14:08 -07:00
|
|
|
|
} catch {
|
2022-12-30 20:04:43 -08:00
|
|
|
|
print("💥 Fetch Message To and From Users Error")
|
2022-05-27 19:18:33 -07:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2023-01-13 22:30:10 -08:00
|
|
|
|
|
|
|
|
|
|
func waypointPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-05-05 09:27:24 -07:00
|
|
|
|
let logString = String.localizedStringWithFormat("mesh.log.waypoint.received %@".localized, String(packet.from))
|
2023-01-13 22:30:10 -08:00
|
|
|
|
MeshLogger.log("📍 \(logString)")
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-13 22:30:10 -08:00
|
|
|
|
let fetchWaypointRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "WaypointEntity")
|
|
|
|
|
|
fetchWaypointRequest.predicate = NSPredicate(format: "id == %lld", Int64(packet.id))
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-13 22:30:10 -08:00
|
|
|
|
do {
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-13 22:30:10 -08:00
|
|
|
|
if let waypointMessage = try? Waypoint(serializedData: packet.decoded.payload) {
|
2023-03-06 15:30:10 -08:00
|
|
|
|
guard let fetchedWaypoint = try context.fetch(fetchWaypointRequest) as? [WaypointEntity] else {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2023-01-14 20:27:05 -08:00
|
|
|
|
if fetchedWaypoint.isEmpty {
|
|
|
|
|
|
let waypoint = WaypointEntity(context: context)
|
2023-03-14 12:44:10 -07:00
|
|
|
|
|
2023-01-14 20:27:05 -08:00
|
|
|
|
waypoint.id = Int64(packet.id)
|
|
|
|
|
|
waypoint.name = waypointMessage.name
|
|
|
|
|
|
waypoint.longDescription = waypointMessage.description_p
|
|
|
|
|
|
waypoint.latitudeI = waypointMessage.latitudeI
|
|
|
|
|
|
waypoint.longitudeI = waypointMessage.longitudeI
|
2023-01-14 21:57:39 -08:00
|
|
|
|
waypoint.icon = Int64(waypointMessage.icon)
|
2023-01-15 19:15:00 -08:00
|
|
|
|
waypoint.locked = Int64(waypointMessage.lockedTo)
|
2023-04-10 19:14:54 -07:00
|
|
|
|
if waypointMessage.expire >= 1 {
|
2023-01-14 20:27:05 -08:00
|
|
|
|
waypoint.expire = Date(timeIntervalSince1970: TimeInterval(Int64(waypointMessage.expire)))
|
2023-03-06 10:33:18 -08:00
|
|
|
|
} else {
|
2023-02-05 20:23:31 -08:00
|
|
|
|
waypoint.expire = nil
|
2023-01-14 20:27:05 -08:00
|
|
|
|
}
|
2023-02-05 18:56:14 -08:00
|
|
|
|
waypoint.created = Date()
|
2023-01-14 20:27:05 -08:00
|
|
|
|
do {
|
|
|
|
|
|
try context.save()
|
|
|
|
|
|
print("💾 Updated Node Waypoint App Packet For: \(waypoint.id)")
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
context.rollback()
|
|
|
|
|
|
let nsError = error as NSError
|
|
|
|
|
|
print("💥 Error Saving WaypointEntity from WAYPOINT_APP \(nsError)")
|
2023-01-13 22:30:10 -08:00
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2023-01-14 20:27:05 -08:00
|
|
|
|
fetchedWaypoint[0].id = Int64(packet.id)
|
|
|
|
|
|
fetchedWaypoint[0].name = waypointMessage.name
|
|
|
|
|
|
fetchedWaypoint[0].longDescription = waypointMessage.description_p
|
|
|
|
|
|
fetchedWaypoint[0].latitudeI = waypointMessage.latitudeI
|
|
|
|
|
|
fetchedWaypoint[0].longitudeI = waypointMessage.longitudeI
|
2023-01-14 21:57:39 -08:00
|
|
|
|
fetchedWaypoint[0].icon = Int64(waypointMessage.icon)
|
2023-01-15 19:15:00 -08:00
|
|
|
|
fetchedWaypoint[0].locked = Int64(waypointMessage.lockedTo)
|
2023-04-10 19:14:54 -07:00
|
|
|
|
if waypointMessage.expire >= 1 {
|
2023-01-14 20:27:05 -08:00
|
|
|
|
fetchedWaypoint[0].expire = Date(timeIntervalSince1970: TimeInterval(Int64(waypointMessage.expire)))
|
2023-02-05 20:23:31 -08:00
|
|
|
|
} else {
|
|
|
|
|
|
fetchedWaypoint[0].expire = nil
|
2023-01-14 20:27:05 -08:00
|
|
|
|
}
|
2023-02-05 18:56:14 -08:00
|
|
|
|
fetchedWaypoint[0].lastUpdated = Date()
|
2023-01-14 20:27:05 -08:00
|
|
|
|
do {
|
|
|
|
|
|
try context.save()
|
|
|
|
|
|
print("💾 Updated Node Waypoint App Packet For: \(fetchedWaypoint[0].id)")
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
context.rollback()
|
|
|
|
|
|
let nsError = error as NSError
|
|
|
|
|
|
print("💥 Error Saving WaypointEntity from WAYPOINT_APP \(nsError)")
|
|
|
|
|
|
}
|
2023-01-13 22:30:10 -08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
print("💥 Error Deserializing WAYPOINT_APP packet.")
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|