Created Error handling and a new Node Position Intent

This commit is contained in:
Benjamin Faershtein 2024-08-11 19:13:45 -07:00
parent 0d40e5de5d
commit 3e1c5b6119
6 changed files with 126 additions and 7 deletions

View file

@ -4956,6 +4956,9 @@
}
}
}
},
"Could not find node" : {
},
"Counter Clockwise Rotary Event" : {
@ -6984,6 +6987,9 @@
},
"Erase all device and app data?" : {
},
"Error: %@" : {
},
"ESP 32 OTA update is a work in progress, click the button below to send your device a reboot into ota admin message." : {
@ -7186,7 +7192,7 @@
"Factory reset your device and app? " : {
},
"Failed to encode message content." : {
"Failed to encode message content" : {
},
"Failed to get a valid position to exchange" : {
@ -7200,6 +7206,9 @@
},
"Favorites" : {
},
"Fetch the latest position of a cetain node" : {
},
"Fifteen Minutes" : {
@ -7614,6 +7623,9 @@
},
"Get custom waterproof solar and detection sensor router nodes, aluminium desktop nodes and rugged handsets." : {
},
"Get Node Position" : {
},
"Get NRF DFU from the App Store" : {
@ -15325,6 +15337,9 @@
},
"Newer firmware is available" : {
},
"No Connected Node" : {
},
"No Device Metrics" : {
@ -15406,6 +15421,9 @@
}
}
}
},
"Node does not have positions" : {
},
"Node History" : {
@ -19025,6 +19043,9 @@
},
"Send a channel message" : {
},
"Send a message to a certain meshtastic channel" : {
},
"Send a waypoint" : {

View file

@ -34,6 +34,8 @@
B3E905B12B71F7F300654D07 /* TextMessageField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E905B02B71F7F300654D07 /* TextMessageField.swift */; };
BCB613812C67290800485544 /* SendWaypointIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCB613802C67290800485544 /* SendWaypointIntent.swift */; };
BCB613832C672A2600485544 /* MessageChannelIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCB613822C672A2600485544 /* MessageChannelIntent.swift */; };
BCB613852C68703800485544 /* NodePositionIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCB613842C68703800485544 /* NodePositionIntent.swift */; };
BCB613872C69A0FB00485544 /* AppIntentErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = BCB613862C69A0FB00485544 /* AppIntentErrors.swift */; };
C9697FA527933B8C00250207 /* SQLite in Frameworks */ = {isa = PBXBuildFile; productRef = C9697FA427933B8C00250207 /* SQLite */; };
D93068D32B8129510066FBC8 /* MessageContextMenuItems.swift in Sources */ = {isa = PBXBuildFile; fileRef = D93068D22B8129510066FBC8 /* MessageContextMenuItems.swift */; };
D93068D52B812B700066FBC8 /* MessageDestination.swift in Sources */ = {isa = PBXBuildFile; fileRef = D93068D42B812B700066FBC8 /* MessageDestination.swift */; };
@ -266,6 +268,8 @@
B3E905B02B71F7F300654D07 /* TextMessageField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextMessageField.swift; sourceTree = "<group>"; };
BCB613802C67290800485544 /* SendWaypointIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendWaypointIntent.swift; sourceTree = "<group>"; };
BCB613822C672A2600485544 /* MessageChannelIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageChannelIntent.swift; sourceTree = "<group>"; };
BCB613842C68703800485544 /* NodePositionIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodePositionIntent.swift; sourceTree = "<group>"; };
BCB613862C69A0FB00485544 /* AppIntentErrors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIntentErrors.swift; sourceTree = "<group>"; };
D93068D22B8129510066FBC8 /* MessageContextMenuItems.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageContextMenuItems.swift; sourceTree = "<group>"; };
D93068D42B812B700066FBC8 /* MessageDestination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageDestination.swift; sourceTree = "<group>"; };
D93068D62B8146690066FBC8 /* MessageText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageText.swift; sourceTree = "<group>"; };
@ -557,6 +561,8 @@
children = (
BCB613802C67290800485544 /* SendWaypointIntent.swift */,
BCB613822C672A2600485544 /* MessageChannelIntent.swift */,
BCB613842C68703800485544 /* NodePositionIntent.swift */,
BCB613862C69A0FB00485544 /* AppIntentErrors.swift */,
);
path = AppIntents;
sourceTree = "<group>";
@ -1368,6 +1374,7 @@
DDB75A1E2A0B0CD0006ED576 /* LoRaSignalStrengthIndicator.swift in Sources */,
DDA6B2E928419CF2003E8C16 /* MeshPackets.swift in Sources */,
DDCE4E2C2869F92900BE9F8F /* UserConfig.swift in Sources */,
BCB613852C68703800485544 /* NodePositionIntent.swift in Sources */,
DDB75A212A12B954006ED576 /* LoRaSignalStrength.swift in Sources */,
DD6193752862F6E600E59241 /* ExternalNotificationConfig.swift in Sources */,
DD268D8E2BCC90E2008073AE /* RouteEnums.swift in Sources */,
@ -1384,6 +1391,7 @@
DD1933762B0835D500771CD5 /* PositionAltitudeChart.swift in Sources */,
DD415828285859C4009B0E59 /* TelemetryConfig.swift in Sources */,
DDB6CCFB2AAF805100945AF6 /* NodeMapSwiftUI.swift in Sources */,
BCB613872C69A0FB00485544 /* AppIntentErrors.swift in Sources */,
DD73FD1128750779000852D6 /* PositionLog.swift in Sources */,
DD15E4F52B8BFC8E00654F61 /* PaxCounterLog.swift in Sources */,
25F5D5C22C3F6E4B008036E3 /* AppState.swift in Sources */,

View file

@ -0,0 +1,22 @@
//
// AppIntentErrors.swift
// Meshtastic
//
// Created by Benjamin Faershtein on 8/11/24.
//
import Foundation
class AppIntentErrors {
enum AppIntentError: Swift.Error, CustomLocalizedStringResourceConvertible {
case notConnected
case message(_ message: String)
var localizedStringResource: LocalizedStringResource {
switch self {
case let .message(message): return "Error: \(message)"
case .notConnected: return "No Connected Node"
}
}
}
}

View file

@ -11,6 +11,8 @@ import AppIntents
struct MessageChannelIntent: AppIntent {
static var title: LocalizedStringResource = "Send a channel message"
static var description: IntentDescription = "Send a message to a certain meshtastic channel"
@Parameter(title: "Message")
var messageContent: String
@ -22,6 +24,10 @@ struct MessageChannelIntent: AppIntent {
Summary("Send \(\.$messageContent) to \(\.$channelNumber)")
}
func perform() async throws -> some IntentResult {
if (!BLEManager.shared.isConnected){
throw AppIntentErrors.AppIntentError.notConnected
}
// Check if channel number is between 1 and 7
guard (0...7).contains(channelNumber) else {
throw $channelNumber.needsValueError("Channel number must be between 0 and 7.")
@ -29,15 +35,17 @@ struct MessageChannelIntent: AppIntent {
// Convert messageContent to data and check its length
guard let messageData = messageContent.data(using: .utf8) else {
throw $messageContent.needsValueError("Failed to encode message content.")
throw AppIntentErrors.AppIntentError.message("Failed to encode message content")
}
if messageData.count > 228 {
throw $messageContent.needsValueError("Message content exceeds 228 bytes.")
}
if (BLEManager.shared.isConnected){
BLEManager.shared.sendMessage(message: messageContent, toUserNum: 0, channel: Int32(channelNumber), isEmoji: false, replyID: 0)
if(!BLEManager.shared.sendMessage(message: messageContent, toUserNum: 0, channel: Int32(channelNumber), isEmoji: false, replyID: 0)){
throw AppIntentErrors.AppIntentError.message("Failed to send message")
}
return .result()
}
}

View file

@ -0,0 +1,56 @@
//
// NodePositionIntent.swift
// Meshtastic
//
// Created by Benjamin Faershtein on 8/10/24.
//
import Foundation
import AppIntents
import CoreLocation
import CoreData
struct NodePositionIntent: AppIntent {
@Parameter(title: "Node Number")
var nodeNum: Int
static var title: LocalizedStringResource = "Get Node Position"
static var description: IntentDescription = "Fetch the latest position of a cetain node"
func perform() async throws -> some IntentResult & ReturnsValue<CLPlacemark> {
if (!BLEManager.shared.isConnected) {
throw AppIntentErrors.AppIntentError.notConnected
}
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "NodeInfoEntity")
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
do {
guard let fetchedNode = try PersistenceController.shared.container.viewContext.fetch(fetchNodeInfoRequest) as? [NodeInfoEntity], fetchedNode.count == 1 else {
throw $nodeNum.needsValueError("Could not find node")
}
let nodeInfo = fetchedNode[0]
if let latitude = nodeInfo.latestPosition?.coordinate.latitude,
let longitude = nodeInfo.latestPosition?.coordinate.longitude {
let nodeLocation = CLLocation(latitude: latitude, longitude: longitude)
// Reverse geocode the CLLocation to get a CLPlacemark
let geocoder = CLGeocoder()
let placemarks = try await geocoder.reverseGeocodeLocation(nodeLocation)
if let placemark = placemarks.first {
return .result(value: placemark)
} else {
throw AppIntentErrors.AppIntentError.message("Error Reverse Geocoding Location")
}
} else {
throw AppIntentErrors.AppIntentError.message("Node does not have positions")
}
} catch {
throw AppIntentErrors.AppIntentError.message("Fetch Failure")
}
}
}

View file

@ -27,7 +27,9 @@ struct SendWaypointIntent: AppIntent {
var locationParameter: CLPlacemark
func perform() async throws -> some IntentResult {
if (!BLEManager.shared.isConnected){
throw AppIntentErrors.AppIntentError.notConnected
}
// Provide default values if parameters are nil
let name = nameParameter ?? "Dropped Pin"
let description = descriptionParameter ?? ""
@ -67,10 +69,12 @@ struct SendWaypointIntent: AppIntent {
newWaypoint.icon = unicode
newWaypoint.name = name
newWaypoint.description_p = description
if (BLEManager.shared.isConnected){
BLEManager.shared.sendWaypoint(waypoint: newWaypoint)
if(!BLEManager.shared.sendWaypoint(waypoint: newWaypoint)){
throw AppIntentErrors.AppIntentError.message("Failed to Send Waypoint")
}
return .result()
}