Merge remote-tracking branch 'refs/remotes/origin/2.3.11_Working_Changes'

This commit is contained in:
Garth Vander Houwen 2024-06-06 14:06:45 -07:00
commit 52b9a2d4c0
6 changed files with 161 additions and 187 deletions

View file

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
25A978592C124FA70003AAE7 /* NodeInfoExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25A978572C124FA70003AAE7 /* NodeInfoExtensions.swift */; };
6DA39D8E2A92DC52007E311C /* MeshtasticAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DA39D8D2A92DC52007E311C /* MeshtasticAppDelegate.swift */; };
6DEDA55A2A957B8E00321D2E /* DetectionSensorLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEDA5592A957B8E00321D2E /* DetectionSensorLog.swift */; };
6DEDA55C2A9592F900321D2E /* MessageEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEDA55B2A9592F900321D2E /* MessageEntityExtension.swift */; };
@ -240,6 +241,7 @@
/* Begin PBXFileReference section */
258EE1262C0E833D0025A5FB /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
25A978572C124FA70003AAE7 /* NodeInfoExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NodeInfoExtensions.swift; sourceTree = "<group>"; };
6DA39D8D2A92DC52007E311C /* MeshtasticAppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshtasticAppDelegate.swift; sourceTree = "<group>"; };
6DEDA5592A957B8E00321D2E /* DetectionSensorLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetectionSensorLog.swift; sourceTree = "<group>"; };
6DEDA55B2A9592F900321D2E /* MessageEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageEntityExtension.swift; sourceTree = "<group>"; };
@ -513,6 +515,14 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
25A978582C124FA70003AAE7 /* Protobufs */ = {
isa = PBXGroup;
children = (
25A978572C124FA70003AAE7 /* NodeInfoExtensions.swift */,
);
path = Protobufs;
sourceTree = "<group>";
};
C9483F6B2773016700998F6B /* MapKitMap */ = {
isa = PBXGroup;
children = (
@ -951,6 +961,7 @@
DDDB443E29F79A9400EE2349 /* Extensions */ = {
isa = PBXGroup;
children = (
25A978582C124FA70003AAE7 /* Protobufs */,
DD007BB12AA59B9A00F5FA12 /* CoreData */,
DDFFA7462B3A7F3C004730DB /* Bundle.swift */,
DDDB444529F8A96500EE2349 /* Character.swift */,
@ -1314,6 +1325,7 @@
DD0F791B28713C8A00A6FDAD /* AdminMessageList.swift in Sources */,
DD3CC6BC28E366DF00FA9159 /* Meshtastic.xcdatamodeld in Sources */,
DDC4C9FF2A8D982900CE201C /* DetectionSensorConfig.swift in Sources */,
25A978592C124FA70003AAE7 /* NodeInfoExtensions.swift in Sources */,
D9C983A22B79D1A600BDBE6A /* RequestPositionButton.swift in Sources */,
DDDB26442AAC0206003AFCB7 /* NodeDetail.swift in Sources */,
DD5E5210298EE33B00D21B61 /* telemetry.pb.swift in Sources */,

View file

@ -11,7 +11,22 @@ import MapKit
import SwiftUI
extension PositionEntity {
convenience init(
context: NSManagedObjectContext,
nodeInfo: NodeInfo
) {
self.init(context: context)
self.latest = true
self.seqNo = Int32(nodeInfo.position.seqNumber)
self.latitudeI = nodeInfo.position.latitudeI
self.longitudeI = nodeInfo.position.longitudeI
self.altitude = nodeInfo.position.altitude
self.satsInView = Int32(nodeInfo.position.satsInView)
self.speed = Int32(nodeInfo.position.groundSpeed)
self.heading = Int32(nodeInfo.position.groundTrack)
self.time = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.position.time)))
}
static func allPositionsFetchRequest() -> NSFetchRequest<PositionEntity> {
let request: NSFetchRequest<PositionEntity> = PositionEntity.fetchRequest()
request.fetchLimit = 1000

View file

@ -9,6 +9,31 @@ import Foundation
import CoreData
extension UserEntity {
convenience init(
context: NSManagedObjectContext,
user: User,
num: Int
) {
self.init(context: context)
self.userId = user.id
self.num = Int64(num)
self.longName = user.longName
self.shortName = user.shortName
self.hwModel = String(describing: user.hwModel).uppercased()
self.isLicensed = user.isLicensed
self.role = Int32(user.role.rawValue)
}
convenience init(context: NSManagedObjectContext, num: Int) {
self.init(context: context)
self.num = Int64(num)
let userId = String(format: "!%2X", num)
self.userId = userId
let last4 = String(userId.suffix(4))
self.longName = "Meshtastic \(last4)"
self.shortName = last4
self.hwModel = "UNSET"
}
var messageList: [MessageEntity] {
self.value(forKey: "allMessages") as? [MessageEntity] ?? [MessageEntity]()
@ -27,15 +52,3 @@ extension UserEntity {
return unreadMessages.count
}
}
public func createUser(num: Int64, context: NSManagedObjectContext) -> UserEntity {
let newUser = UserEntity(context: context)
newUser.num = Int64(num)
let userId = String(format: "%2X", num)
newUser.userId = "!\(userId)"
let last4 = String(userId.suffix(4))
newUser.longName = "Meshtastic \(last4)"
newUser.shortName = last4
newUser.hwModel = "UNSET"
return newUser
}

View file

@ -0,0 +1,11 @@
import Foundation
extension NodeInfo {
var isValidPosition: Bool {
hasPosition &&
position.longitudeI != 0 &&
position.latitudeI != 0 &&
position.latitudeI != 373346000 &&
position.longitudeI != -1220090000
}
}

View file

@ -251,182 +251,111 @@ func deviceMetadataPacket (metadata: DeviceMetadata, fromNum: Int64, context: NS
func nodeInfoPacket (nodeInfo: NodeInfo, channel: UInt32, context: NSManagedObjectContext) -> NodeInfoEntity? {
let logString = String.localizedStringWithFormat("mesh.log.nodeinfo.received %@".localized, String(nodeInfo.num))
let logString = String.localizedStringWithFormat(
"mesh.log.nodeinfo.received %@ %@".localized,
String(nodeInfo.num),
String(nodeInfo.viaMqtt)
)
MeshLogger.log("📟 \(logString)")
guard nodeInfo.num > 0 else { return nil }
guard nodeInfo.num > 0 else {
Logger.data.error("nodeInfo \(nodeInfo.num) invalid")
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 {
guard let fetchedNodes = try context.fetch(fetchNodeInfoRequest) as? [NodeInfoEntity] else {
return nil
}
// Not Found Insert
if fetchedNode.isEmpty && nodeInfo.num > 0 {
let newNode = NodeInfoEntity(context: context)
newNode.id = Int64(nodeInfo.num)
newNode.num = Int64(nodeInfo.num)
newNode.channel = Int32(nodeInfo.channel)
newNode.favorite = nodeInfo.isFavorite
newNode.hopsAway = Int32(nodeInfo.hopsAway)
newNode.viaMqtt = nodeInfo.viaMqtt
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)
let node: NodeInfoEntity
if let update = fetchedNodes.first {
node = update
} else {
node = NodeInfoEntity(context: context)
}
node.id = Int64(nodeInfo.num)
node.num = Int64(nodeInfo.num)
node.channel = Int32(nodeInfo.channel)
node.favorite = nodeInfo.isFavorite
node.hopsAway = Int32(nodeInfo.hopsAway)
node.viaMqtt = nodeInfo.viaMqtt
if nodeInfo.hasDeviceMetrics {
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
var telemetries: [TelemetryEntity]
if let tele = node.telemetries?.array as? [TelemetryEntity] {
telemetries = tele
telemetries.append(newTelemetry)
} else {
telemetries = [newTelemetry]
}
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()
newUser.isLicensed = nodeInfo.user.isLicensed
newUser.role = Int32(nodeInfo.user.role.rawValue)
newNode.user = newUser
} else if nodeInfo.num > Int16.max {
let newUser = createUser(num: Int64(nodeInfo.num), context: context)
newNode.user = newUser
node.telemetries = NSOrderedSet(array: telemetries)
}
node.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.lastHeard)))
node.snr = nodeInfo.snr
// User
var user: UserEntity?
if nodeInfo.hasUser {
user = UserEntity(
context: context,
user: nodeInfo.user,
num: Int(nodeInfo.num)
)
} else if nodeInfo.num > Int16.max {
user = UserEntity(
context: context,
num: Int(nodeInfo.num)
)
}
node.user = user
// Position
if nodeInfo.isValidPosition {
let position = PositionEntity(
context: context,
nodeInfo: nodeInfo
)
if let positions = node.positions?.mutableCopy() as? NSMutableOrderedSet {
positions.add(position)
node.positions = positions
} else {
node.positions = NSOrderedSet(object: position)
}
}
if (nodeInfo.position.longitudeI != 0 && nodeInfo.position.latitudeI != 0) && (nodeInfo.position.latitudeI != 373346000 && nodeInfo.position.longitudeI != -1220090000) {
let position = PositionEntity(context: context)
position.latest = true
position.seqNo = Int32(nodeInfo.position.seqNumber)
position.latitudeI = nodeInfo.position.latitudeI
position.longitudeI = nodeInfo.position.longitudeI
position.altitude = nodeInfo.position.altitude
position.satsInView = Int32(nodeInfo.position.satsInView)
position.speed = Int32(nodeInfo.position.groundSpeed)
position.heading = Int32(nodeInfo.position.groundTrack)
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.position.time)))
var newPostions = [PositionEntity]()
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
}
if fetchedMyInfo.count > 0 {
newNode.myInfo = fetchedMyInfo[0]
}
// MyInfo
do {
let fetchMyInfoRequest = MyInfoEntity.fetchRequest()
fetchMyInfoRequest.predicate = NSPredicate(
format: "myNodeNum == %lld", Int64(nodeInfo.num)
)
let fetchedMyInfo = try context.fetch(fetchMyInfoRequest)
if let myInfo = fetchedMyInfo.first {
node.myInfo = myInfo
do {
try context.save()
Logger.data.info("💾 Saved a new Node Info For: \(String(nodeInfo.num))")
return newNode
return node
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Saving Core Data NodeInfoEntity: \(nsError)")
}
} catch {
Logger.data.error("Fetch MyInfo Error")
}
} else if 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(nodeInfo.channel)
fetchedNode[0].favorite = nodeInfo.isFavorite
fetchedNode[0].hopsAway = Int32(nodeInfo.hopsAway)
fetchedNode[0].viaMqtt = nodeInfo.viaMqtt
if nodeInfo.hasUser {
if fetchedNode[0].user == nil {
fetchedNode[0].user = UserEntity(context: context)
}
fetchedNode[0].user!.userId = nodeInfo.user.id
fetchedNode[0].user!.num = Int64(nodeInfo.num)
fetchedNode[0].user!.numString = String(nodeInfo.num)
fetchedNode[0].user!.longName = nodeInfo.user.longName
fetchedNode[0].user!.shortName = nodeInfo.user.shortName
fetchedNode[0].user!.isLicensed = nodeInfo.user.isLicensed
fetchedNode[0].user!.role = Int32(nodeInfo.user.role.rawValue)
fetchedNode[0].user!.hwModel = String(describing: nodeInfo.user.hwModel).uppercased()
} else {
if fetchedNode[0].user == nil && nodeInfo.num > Int16.max {
let newUser = createUser(num: Int64(nodeInfo.num), context: context)
fetchedNode[0].user = newUser
Logger.data.error("Error Saving Core Data NodeInfoEntity: \(error.localizedDescription)")
}
}
if nodeInfo.hasDeviceMetrics {
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
guard let mutableTelemetries = fetchedNode[0].telemetries!.mutableCopy() as? NSMutableOrderedSet else {
return nil
}
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
position.altitude = nodeInfo.position.altitude
position.satsInView = Int32(nodeInfo.position.satsInView)
position.time = Date(timeIntervalSince1970: TimeInterval(Int64(nodeInfo.position.time)))
guard let mutablePositions = fetchedNode[0].positions!.mutableCopy() as? NSMutableOrderedSet else {
return nil
}
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
}
if fetchedMyInfo.count > 0 {
fetchedNode[0].myInfo = fetchedMyInfo[0]
}
do {
try context.save()
Logger.data.info("💾 NodeInfo saved for \(nodeInfo.num)")
return fetchedNode[0]
} catch {
context.rollback()
let nsError = error as NSError
Logger.data.error("Error Saving Core Data NodeInfoEntity: \(nsError)")
}
} catch {
Logger.data.error("Fetch MyInfo Error")
}
} catch {
Logger.data.error("Fetch MyInfo Error: \(error.localizedDescription)")
}
} catch {
Logger.data.error("Fetch NodeInfoEntity Error")

View file

@ -166,20 +166,14 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext)
if let newUserMessage = try? User(serializedData: packet.decoded.payload) {
if newUserMessage.id.isEmpty {
if packet.from > Int16.max {
let newUser = createUser(num: Int64(packet.from), context: context)
newNode.user = newUser
}
if newUserMessage.id.isEmpty, packet.from > Int16.max {
newNode.user = UserEntity(context: context, num: Int(packet.from))
} else {
let newUser = UserEntity(context: context)
newUser.userId = newUserMessage.id
newUser.num = Int64(packet.from)
newUser.longName = newUserMessage.longName
newUser.shortName = newUserMessage.shortName
newUser.role = Int32(newUserMessage.role.rawValue)
newUser.hwModel = String(describing: newUserMessage.hwModel).uppercased()
let newUser = UserEntity(
context: context,
user: newUserMessage,
num: Int(packet.from)
)
newNode.user = newUser
if UserDefaults.newNodeNotifications {
@ -199,13 +193,13 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext)
}
} else {
if packet.from > Int16.max {
let newUser = createUser(num: Int64(packet.from), context: context)
let newUser = UserEntity(context: context, num: Int(packet.from))
fetchedNode[0].user = newUser
}
}
if newNode.user == nil && packet.from > Int16.max {
newNode.user = createUser(num: Int64(packet.from), context: context)
newNode.user = UserEntity(context: context, num: Int(packet.from))
}
let myInfoEntity = MyInfoEntity(context: context)
@ -265,8 +259,8 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext)
fetchedNode[0].hopsAway = Int32(packet.hopStart - packet.hopLimit)
}
if fetchedNode[0].user == nil {
let newUser = createUser(num: Int64(packet.from), context: context)
fetchedNode[0].user! = newUser
let newUser = UserEntity(context: context, num: Int(packet.from))
fetchedNode[0].user = newUser
}
do {
try context.save()