diff --git a/Meshtastic Client.xcodeproj/project.pbxproj b/Meshtastic Client.xcodeproj/project.pbxproj index 42abd6c2..e697d7cb 100644 --- a/Meshtastic Client.xcodeproj/project.pbxproj +++ b/Meshtastic Client.xcodeproj/project.pbxproj @@ -738,7 +738,7 @@ CODE_SIGN_ENTITLEMENTS = MeshtasticClient/MeshtasticClient.entitlements; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_ASSET_PATHS = "\"MeshtasticClient/Preview Content\""; DEVELOPMENT_TEAM = GCH7VS5Y9R; ENABLE_PREVIEWS = YES; @@ -769,7 +769,7 @@ CODE_SIGN_ENTITLEMENTS = MeshtasticClient/MeshtasticClient.entitlements; "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 2; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_ASSET_PATHS = "\"MeshtasticClient/Preview Content\""; DEVELOPMENT_TEAM = GCH7VS5Y9R; ENABLE_PREVIEWS = YES; diff --git a/MeshtasticClient/Helpers/BLEManager.swift b/MeshtasticClient/Helpers/BLEManager.swift index bd6d9ae4..fc6643e0 100644 --- a/MeshtasticClient/Helpers/BLEManager.swift +++ b/MeshtasticClient/Helpers/BLEManager.swift @@ -1077,4 +1077,97 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph } return success } + + // Send Message + public func sendPosition(destNum: Int64, wantResponse: Bool) -> Bool { + + var success = false + + let fromNodeNum = connectedPeripheral.num + + if fromNodeNum <= 0 { + + return false + } + + let fetchNode: NSFetchRequest = NSFetchRequest.init(entityName: "NodeInfoEntity") + fetchNode.predicate = NSPredicate(format: "num == %lld", fromNodeNum) + + do { + + let fetchedNode = try context?.fetch(fetchNode) as! [NodeInfoEntity] + + if fetchedNode.count == 1 { + var positionPacket = Position() + positionPacket.latitudeI = Int32(LocationHelper.currentLocation.latitude * 1e7) + positionPacket.longitudeI = Int32(LocationHelper.currentLocation.longitude * 1e7) + positionPacket.time = UInt32(Date().timeIntervalSince1970) + positionPacket.altitude = Int32(LocationHelper.currentAltitude) + let mostRecentPosition = fetchedNode[0].positions?.lastObject as! PositionEntity + positionPacket.batteryLevel = mostRecentPosition.batteryLevel + + var meshPacket = MeshPacket() + meshPacket.to = UInt32(broadcastNodeNum) + meshPacket.from = UInt32(connectedPeripheral.num) + meshPacket.wantAck = wantResponse + + var dataMessage = DataMessage() + dataMessage.payload = try! positionPacket.serializedData() + dataMessage.portnum = PortNum.positionApp + + meshPacket.decoded = dataMessage + + let position = PositionEntity(context: context!) + position.latitudeI = positionPacket.latitudeI + position.longitudeI = positionPacket.longitudeI + position.altitude = positionPacket.altitude + position.batteryLevel = positionPacket.batteryLevel + position.time = Date(timeIntervalSince1970: TimeInterval(Int64(positionPacket.time))) + + let mutablePositions = fetchedNode[0].positions!.mutableCopy() as! NSMutableOrderedSet + mutablePositions.add(position) + + fetchedNode[0].positions = mutablePositions.copy() as? NSOrderedSet + + var toRadio: ToRadio! + toRadio = ToRadio() + toRadio.packet = meshPacket + let binaryData: Data = try! toRadio.serializedData() + + if meshLoggingEnabled { MeshLogger.log("📍 Sent a Position Packet for node: \(fromNodeNum)") } + print("📍 Sent a Position Packet for node: \(fromNodeNum)") + + if connectedPeripheral!.peripheral.state == CBPeripheralState.connected { + connectedPeripheral.peripheral.writeValue(binaryData, for: TORADIO_characteristic, type: .withResponse) + do { + + try context!.save() + print("💾 Saved a new position for the connected node: \(fromNodeNum)") + if meshLoggingEnabled { MeshLogger.log("💾 Saved a new position for the connected node: \(fromNodeNum)") } + success = true + + } catch { + + context!.rollback() + + let nsError = error as NSError + print("🚫 Unresolved Core Data error in Send Position Function \(nsError)") + if meshLoggingEnabled { MeshLogger.log("🚫 Unresolved Core Data error in Send Position Function \(nsError)") } + success = false + } + } + + } + + } catch { + + } + + + + + + return success + } + } diff --git a/MeshtasticClient/Helpers/LocationHelper.swift b/MeshtasticClient/Helpers/LocationHelper.swift index cb06da1c..b3459ef7 100644 --- a/MeshtasticClient/Helpers/LocationHelper.swift +++ b/MeshtasticClient/Helpers/LocationHelper.swift @@ -6,6 +6,8 @@ class LocationHelper: NSObject, ObservableObject { // Mount Rainier static let DefaultLocation = CLLocationCoordinate2D(latitude: 46.879967, longitude: -121.726906) + + static let DefaultAltitude = CLLocationDistance(integerLiteral: 0) static var currentLocation: CLLocationCoordinate2D { @@ -15,6 +17,14 @@ class LocationHelper: NSObject, ObservableObject { return location.coordinate } + static var currentAltitude: CLLocationDistance { + + guard let altitude = shared.locationManager.location?.altitude else { + return DefaultAltitude + } + return altitude + } + private let locationManager = CLLocationManager() private override init() { diff --git a/MeshtasticClient/Info.plist b/MeshtasticClient/Info.plist index 1b569687..1a7b3ab5 100644 --- a/MeshtasticClient/Info.plist +++ b/MeshtasticClient/Info.plist @@ -2,8 +2,6 @@ - NSLocationUsageDescription - We use your location to display it on the mesh map as well as to have GPS coordinatess to send to the connected device. CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName @@ -46,7 +44,9 @@ NSBluetoothAlwaysUsageDescription We use bluetooth to connect to nearby Meshtastic Devices NSBluetoothPeripheralUsageDescription - Bluetooth is used to connect an iPhone to a user's meshtastic device to allow text messaging and location data for the mesh network. + Bluetooth is used to connect an iPhone to a user's meshtastic device to allow text messaging and location data for the mesh network. + NSLocationUsageDescription + We use your location to display it on the mesh map as well as to have GPS coordinatess to send to the connected device. NSLocationWhenInUseUsageDescription We use your location to display it on the mesh map as well as to have GPS coordinatess to send to the connected device. Privacy – Bluetooth Always Usage Description diff --git a/MeshtasticClient/Views/Messages/UserMessageList.swift b/MeshtasticClient/Views/Messages/UserMessageList.swift index c97fcc99..4ba8b7ee 100644 --- a/MeshtasticClient/Views/Messages/UserMessageList.swift +++ b/MeshtasticClient/Views/Messages/UserMessageList.swift @@ -28,6 +28,7 @@ struct UserMessageList: View { @State var showDeleteMessageAlert = false @State private var deleteMessageId: Int64 = 0 @State private var replyMessageId: Int64 = 0 + @State private var sendPositionWithMessage: Bool = false @State var messageCount = 0 @@ -385,6 +386,15 @@ struct UserMessageList: View { .font(.subheadline) Spacer() + + Button { + let userLongName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown" + sendPositionWithMessage = true + typingMessage = "📍 " + userLongName + " Has shared their position with the mesh." + + } label: { + Image(systemName: "mappin") + } ProgressView("Bytes: \(totalBytes) / \(maxbytes)", value: Double(totalBytes), total: Double(maxbytes)) .frame(width: 130) @@ -409,6 +419,11 @@ struct UserMessageList: View { typingMessage = "" focusedField = nil replyMessageId = 0 + if sendPositionWithMessage { + if bleManager.sendPosition(destNum: user.num, wantResponse: false) { + print("Position Sent") + } + } } }) {