Meshtastic-Apple/Meshtastic/Helpers/LocationHelper.swift
2023-04-08 00:34:39 -07:00

92 lines
3.5 KiB
Swift

import CoreLocation
class LocationHelper: NSObject, ObservableObject, CLLocationManagerDelegate {
private let locationManager = CLLocationManager()
static let shared = LocationHelper()
@Published var lastLocation: CLLocation?
override init() {
super.init()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.pausesLocationUpdatesAutomatically = true
locationManager.allowsBackgroundLocationUpdates = true
locationManager.activityType = .otherNavigation
locationManager.requestWhenInUseAuthorization()
locationManager.distanceFilter = 5
locationManager.startUpdatingLocation()
}
// Apple Park
static let DefaultLocation = CLLocation(latitude: 37.3346, longitude: -122.0090)
//static let DefaultAltitude = CLLocationDistance(integerLiteral: 0)
//static let DefaultSpeed = CLLocationSpeed(integerLiteral: 0)
//static let DefaultHeading = CLLocationDirection(integerLiteral: 0)
static var currentLocation: CLLocation {
guard let location = shared.locationManager.location else {
return DefaultLocation
}
return location
}
/// Sats In View Estimator using horizontal and vertical accuracy since
/// CoreLocation does not have number of sats available
static var satsInView: Int {
// Invalid Coordinates
if shared.locationManager.location?.verticalAccuracy ?? 0 < 0 || shared.locationManager.location?.horizontalAccuracy ?? 0 < 0 {
return 0
}
// If we have a position we have a sat
var sats = 1
// If we have a 3D fix we have at least 4 sats
if shared.locationManager.location?.verticalAccuracy ?? 0 > 0 {
sats = 4
if 0...5 ~= shared.locationManager.location?.horizontalAccuracy ?? 0 {
sats = 12
} else if 6...15 ~= shared.locationManager.location?.horizontalAccuracy ?? 0 {
sats = 10
} else if 16...30 ~= shared.locationManager.location?.horizontalAccuracy ?? 0 {
sats = 9
} else if 31...45 ~= shared.locationManager.location?.horizontalAccuracy ?? 0 {
sats = 7
} else if 46...60 ~= shared.locationManager.location?.horizontalAccuracy ?? 0 {
sats = 5
}
} else if shared.locationManager.location?.horizontalAccuracy ?? 0 <= 300 {
// Need at least 3 sats to be under 300, over that could be wifi or cell triangulation
sats = 3
} else if shared.locationManager.location?.horizontalAccuracy ?? 0 > 300 {
sats = 2
}
return sats
}
public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let mostRecentLocation = locations.last else {
return
}
// Extra Smart positioning logic throwing out bad readings from the phone GPS
let age = -mostRecentLocation.timestamp.timeIntervalSinceNow
print("Location: HA-\(mostRecentLocation.horizontalAccuracy) VA-\(mostRecentLocation.verticalAccuracy) AGE-\(age)")
manager.stopUpdatingLocation()
if age > 10 || mostRecentLocation.horizontalAccuracy < 0 || mostRecentLocation.horizontalAccuracy > 100 {
print("Bad Location: HA-\(mostRecentLocation.horizontalAccuracy) VA-\(mostRecentLocation.verticalAccuracy) AGE-\(age)")
manager.startUpdatingLocation()
} else {
lastLocation = mostRecentLocation
}
}
public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Location manager failed with error: \(error.localizedDescription)")
}
public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
print("Location manager changed the status: \(status)")
}
}