mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Merge pull request #1085 from meshtastic/AppIntents
Add App Intents Save Channel Settings and Message node
This commit is contained in:
commit
85dcc3b890
4 changed files with 400 additions and 1 deletions
|
|
@ -18191,6 +18191,52 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Channel" : {
|
||||
|
||||
},
|
||||
"Channel 0 Included" : {
|
||||
|
||||
},
|
||||
"Channel 1 Included" : {
|
||||
|
||||
},
|
||||
"Channel 2 Included" : {
|
||||
|
||||
},
|
||||
"Channel 3 Included" : {
|
||||
|
||||
},
|
||||
"Channel 4 Included" : {
|
||||
|
||||
},
|
||||
"Channel 5 Included" : {
|
||||
|
||||
},
|
||||
"Channel 6 Included" : {
|
||||
|
||||
},
|
||||
"Channel 7 Included" : {
|
||||
|
||||
},
|
||||
"channel details" : {
|
||||
|
||||
},
|
||||
"Channel Name" : {
|
||||
|
||||
},
|
||||
"Channel number must be between 0 and 7." : {
|
||||
|
||||
},
|
||||
"Channel Role" : {
|
||||
|
||||
},
|
||||
"Channel URL" : {
|
||||
|
||||
},
|
||||
"Channel Utilization %@%% " : {
|
||||
|
||||
},
|
||||
"channel.role.disabled" : {
|
||||
"interval.twentyfour.hours" : {
|
||||
"extractionState" : "migrated",
|
||||
"localizations" : {
|
||||
|
|
@ -34769,6 +34815,17 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Save" : {
|
||||
|
||||
},
|
||||
"Save Channel Settings" : {
|
||||
|
||||
},
|
||||
"Save User Config to %@?" : {
|
||||
|
||||
},
|
||||
"save.config %@" : {
|
||||
"extractionState" : "migrated",
|
||||
"telemetry.config" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
|
|
@ -35048,6 +35105,70 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Send" : {
|
||||
|
||||
},
|
||||
"Send ${messageContent} to ${channelNumber}" : {
|
||||
|
||||
},
|
||||
"Send ${messageContent} to ${nodeNumber}" : {
|
||||
|
||||
},
|
||||
"Send a Direct Message" : {
|
||||
|
||||
},
|
||||
"Send a Group Message" : {
|
||||
|
||||
},
|
||||
"Send a message to a certain meshtastic channel" : {
|
||||
|
||||
},
|
||||
"Send a message to a certain meshtastic node" : {
|
||||
|
||||
},
|
||||
"Send a position on the primary channel when the user button is triple clicked." : {
|
||||
|
||||
},
|
||||
"Send a shutdown to the node you are connected to" : {
|
||||
|
||||
},
|
||||
"Send a Waypoint" : {
|
||||
|
||||
},
|
||||
"Send ASCII bell with alert message. Useful for triggering external notification on bell." : {
|
||||
|
||||
},
|
||||
"Send Bell" : {
|
||||
|
||||
},
|
||||
"Send Reboot OTA" : {
|
||||
|
||||
},
|
||||
"Sender Interval" : {
|
||||
|
||||
},
|
||||
"Sensor" : {
|
||||
|
||||
},
|
||||
"Sensor Metrics" : {
|
||||
|
||||
},
|
||||
"Sensor options" : {
|
||||
|
||||
},
|
||||
"Sensor Options" : {
|
||||
|
||||
},
|
||||
"Sent out to other nodes on the mesh to allow them to compute a shared secret key." : {
|
||||
|
||||
},
|
||||
"Sequence number" : {
|
||||
|
||||
},
|
||||
"Sequence: %@" : {
|
||||
|
||||
},
|
||||
"serial" : {
|
||||
"The amount of time to wait before we consider your packet as done." : {
|
||||
"localizations" : {
|
||||
"sr" : {
|
||||
|
|
@ -36378,6 +36499,16 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Supported" : {
|
||||
|
||||
},
|
||||
"Supported I2C Connected sensors will be detected automatically, sensors are BMP280, BME280, BME680, MCP9808, INA219, INA260, LPS22 and SHTC3." : {
|
||||
|
||||
},
|
||||
"Takes a Meshtastic channel URL and saves the channel settings." : {
|
||||
|
||||
},
|
||||
"tapback" : {
|
||||
"tip.messages.message" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
|
|
@ -37138,6 +37269,118 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Temp" : {
|
||||
|
||||
},
|
||||
"Temperature" : {
|
||||
|
||||
},
|
||||
"Ten Minutes" : {
|
||||
|
||||
},
|
||||
"Tertiary Admin Key" : {
|
||||
|
||||
},
|
||||
"The amount of time to wait before we consider your packet as done." : {
|
||||
|
||||
},
|
||||
"The compass heading on the screen outside of the circle will always point north." : {
|
||||
|
||||
},
|
||||
"The dew point is %@ right now." : {
|
||||
|
||||
},
|
||||
"The fastest that position updates will be sent if the minimum distance has been satisfied" : {
|
||||
|
||||
},
|
||||
"The format used to display GPS coordinates on the device screen." : {
|
||||
|
||||
},
|
||||
"The last 4 of the device MAC address will be appended to the short name to set the device's BLE Name. Short name can be up to 4 bytes long." : {
|
||||
|
||||
},
|
||||
"The maximum interval that can elapse without a node broadcasting a position" : {
|
||||
|
||||
},
|
||||
"The Meshtastic Apple apps support firmware version %@ and above." : {
|
||||
|
||||
},
|
||||
"The minimum distance change in meters to be considered for a smart position broadcast." : {
|
||||
|
||||
},
|
||||
"The most recent public key for this node does not match the previously recorded key. You can delete the node and let it exchange keys again, but this also may indicate a more serious security problem. Contact the user through another trusted channel to determine if the key change was due to a factory reset or other intentional action." : {
|
||||
|
||||
},
|
||||
"The primary public key authorized to send admin messages to this node." : {
|
||||
|
||||
},
|
||||
"The public key does not match the recorded key. You may delete the node and let it exchange keys again, but this may indicate a more serious security problem. Contact the user through another trusted channel, to determine if the key change was due to a factory reset or other intentional action." : {
|
||||
|
||||
},
|
||||
"The region where you will be using your radios." : {
|
||||
|
||||
},
|
||||
"The root topic to use for MQTT." : {
|
||||
|
||||
},
|
||||
"The secondary public key authorized to send admin messages to this node." : {
|
||||
|
||||
},
|
||||
"The state of the LED (on/off)" : {
|
||||
|
||||
},
|
||||
"The tertiary public key authorized to send admin messages to this node." : {
|
||||
|
||||
},
|
||||
"The URL for the channel settings" : {
|
||||
|
||||
},
|
||||
"There has been no response to a request for device metadata over the admin channel for this node." : {
|
||||
|
||||
},
|
||||
"These settings will %@ channels. The current LoRa Config will be replaced, if there are substantial changes to the LoRa config the device will reboot" : {
|
||||
|
||||
},
|
||||
"Thirty Minutes" : {
|
||||
|
||||
},
|
||||
"This conversation will be deleted." : {
|
||||
|
||||
},
|
||||
"This could take a while, response will appear in the trace route log for the node it was sent to." : {
|
||||
|
||||
},
|
||||
"This could take a while. The response will appear in the trace route log for the node it was sent to." : {
|
||||
|
||||
},
|
||||
"This determines the actual frequency you are transmitting on in the band. If set to 0 this value will be calculated automatically based on the primary channel name." : {
|
||||
|
||||
},
|
||||
"This device will send out range test messages on the selected interval." : {
|
||||
|
||||
},
|
||||
"This message was likely not delivered." : {
|
||||
|
||||
},
|
||||
"This will disable fixed position and remove the currently set position." : {
|
||||
|
||||
},
|
||||
"This will send a current position from your phone and enable fixed position." : {
|
||||
|
||||
},
|
||||
"Time" : {
|
||||
|
||||
},
|
||||
"Time Stamp" : {
|
||||
|
||||
},
|
||||
"Time Zone" : {
|
||||
|
||||
},
|
||||
"Time zone for dates on the device screen and log." : {
|
||||
|
||||
},
|
||||
"timeout" : {
|
||||
"unset" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
|
|
@ -38087,6 +38330,44 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"Trace Route Sent" : {
|
||||
|
||||
},
|
||||
"Trace route sent to %@" : {
|
||||
|
||||
},
|
||||
"Trace route to %@ was not sent." : {
|
||||
|
||||
},
|
||||
"Trace Route was rate limited. You can send a trace route a maximum of once every thirty seconds." : {
|
||||
|
||||
},
|
||||
"Tracker" : {
|
||||
|
||||
},
|
||||
"Traffic" : {
|
||||
|
||||
},
|
||||
"Transmit data (txd) GPIO pin" : {
|
||||
|
||||
},
|
||||
"Transmit Enabled" : {
|
||||
|
||||
},
|
||||
"Treat double tap on supported accelerometers as a user button press." : {
|
||||
|
||||
},
|
||||
"TriggerType" : {
|
||||
|
||||
},
|
||||
"Triple Click Ad Hoc Ping" : {
|
||||
|
||||
},
|
||||
"Try Again" : {
|
||||
|
||||
},
|
||||
"twitter" : {
|
||||
"extractionState" : "manual",
|
||||
"waiting" : {
|
||||
"localizations" : {
|
||||
"de" : {
|
||||
|
|
@ -38824,4 +39105,4 @@
|
|||
}
|
||||
},
|
||||
"version" : "1.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@
|
|||
8D3F8A412D44C2A6009EAAA4 /* PowerMetricsLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D3F8A402D44C2A6009EAAA4 /* PowerMetricsLog.swift */; };
|
||||
B399E8A42B6F486400E4488E /* RetryButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B399E8A32B6F486400E4488E /* RetryButton.swift */; };
|
||||
B3E905B12B71F7F300654D07 /* TextMessageField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E905B02B71F7F300654D07 /* TextMessageField.swift */; };
|
||||
BC47C2EF2CE0017D008245CA /* MessageNodeIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC47C2EE2CE0017D008245CA /* MessageNodeIntent.swift */; };
|
||||
BC5EBA3C2D002A2000C442FF /* MessageNodeIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC5EBA3B2D002A2000C442FF /* MessageNodeIntent.swift */; };
|
||||
BC6B45FF2CB2F98900723CEB /* SaveChannelSettingsIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC6B45FE2CB2F98900723CEB /* SaveChannelSettingsIntent.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 */; };
|
||||
|
|
@ -296,6 +299,9 @@
|
|||
8D3F8A402D44C2A6009EAAA4 /* PowerMetricsLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PowerMetricsLog.swift; sourceTree = "<group>"; };
|
||||
B399E8A32B6F486400E4488E /* RetryButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RetryButton.swift; sourceTree = "<group>"; };
|
||||
B3E905B02B71F7F300654D07 /* TextMessageField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextMessageField.swift; sourceTree = "<group>"; };
|
||||
BC47C2EE2CE0017D008245CA /* MessageNodeIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageNodeIntent.swift; sourceTree = "<group>"; };
|
||||
BC5EBA3B2D002A2000C442FF /* MessageNodeIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageNodeIntent.swift; sourceTree = "<group>"; };
|
||||
BC6B45FE2CB2F98900723CEB /* SaveChannelSettingsIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveChannelSettingsIntent.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>"; };
|
||||
|
|
@ -633,6 +639,7 @@
|
|||
BCB6137F2C6728E700485544 /* AppIntents */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BC5EBA3B2D002A2000C442FF /* MessageNodeIntent.swift */,
|
||||
BCB613802C67290800485544 /* SendWaypointIntent.swift */,
|
||||
BCB613822C672A2600485544 /* MessageChannelIntent.swift */,
|
||||
BCB613842C68703800485544 /* NodePositionIntent.swift */,
|
||||
|
|
@ -641,6 +648,8 @@
|
|||
BCE2D3C42C7AE369008E6199 /* RestartNodeIntent.swift */,
|
||||
BCE2D3C82C7C377F008E6199 /* FactoryResetNodeIntent.swift */,
|
||||
BCE2D3C62C7B0D0A008E6199 /* ShortcutsProvider.swift */,
|
||||
BC6B45FE2CB2F98900723CEB /* SaveChannelSettingsIntent.swift */,
|
||||
BC47C2EE2CE0017D008245CA /* MessageNodeIntent.swift */,
|
||||
);
|
||||
path = AppIntents;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -1367,6 +1376,7 @@
|
|||
DDFFA7472B3A7F3C004730DB /* Bundle.swift in Sources */,
|
||||
DD457188293C7E63000C49FB /* BLESignalStrengthIndicator.swift in Sources */,
|
||||
DDA9515C2BC6631200CEA535 /* TelemetryEnums.swift in Sources */,
|
||||
BC47C2EF2CE0017D008245CA /* MessageNodeIntent.swift in Sources */,
|
||||
DDFEB3BB29900C1200EE7472 /* CurrentConditionsCompact.swift in Sources */,
|
||||
DD836AE726F6B38600ABCC23 /* Connect.swift in Sources */,
|
||||
D93069082B81DF040066FBC8 /* SaveConfigButton.swift in Sources */,
|
||||
|
|
@ -1489,6 +1499,7 @@
|
|||
DDA1C48E28DB49D3009933EC /* ChannelRoles.swift in Sources */,
|
||||
D9BC22DB2B7DE8E2006A37D5 /* TileDownloadStatus.swift in Sources */,
|
||||
DDD5BB092C285DDC007E03CA /* AppLog.swift in Sources */,
|
||||
BC5EBA3C2D002A2000C442FF /* MessageNodeIntent.swift in Sources */,
|
||||
DD8ED9C8289CE4B900B3B0AB /* RoutingError.swift in Sources */,
|
||||
DDC1B81A2AB5377B00C71E39 /* MessagesTips.swift in Sources */,
|
||||
DD964FC62975DBFD007C176F /* QueryCoreData.swift in Sources */,
|
||||
|
|
@ -1561,6 +1572,7 @@
|
|||
DDDB444429F8A8DD00EE2349 /* Float.swift in Sources */,
|
||||
DDAB580F2B0DAFBC00147258 /* LocationEntityExtension.swift in Sources */,
|
||||
B3E905B12B71F7F300654D07 /* TextMessageField.swift in Sources */,
|
||||
BC6B45FF2CB2F98900723CEB /* SaveChannelSettingsIntent.swift in Sources */,
|
||||
D93068D72B8146690066FBC8 /* MessageText.swift in Sources */,
|
||||
DDC2E15826CE248E0042C5E4 /* MeshtasticApp.swift in Sources */,
|
||||
);
|
||||
|
|
|
|||
45
Meshtastic/AppIntents/MessageNodeIntent.swift
Normal file
45
Meshtastic/AppIntents/MessageNodeIntent.swift
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// MessageNodeIntent.swift
|
||||
// Meshtastic
|
||||
//
|
||||
// Created by Benjamin Faershtein on 11/9/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import AppIntents
|
||||
|
||||
struct MessageNodeIntent: AppIntent {
|
||||
static var title: LocalizedStringResource = "Send a Direct Message"
|
||||
|
||||
static var description: IntentDescription = "Send a message to a certain meshtastic node"
|
||||
|
||||
@Parameter(title: "Message")
|
||||
var messageContent: String
|
||||
|
||||
@Parameter(title: "Node Number")
|
||||
var nodeNumber: Int
|
||||
|
||||
static var parameterSummary: some ParameterSummary {
|
||||
Summary("Send \(\.$messageContent) to \(\.$nodeNumber)")
|
||||
}
|
||||
func perform() async throws -> some IntentResult {
|
||||
if !BLEManager.shared.isConnected {
|
||||
throw AppIntentErrors.AppIntentError.notConnected
|
||||
}
|
||||
|
||||
// Convert messageContent to data and check its length
|
||||
guard let messageData = messageContent.data(using: .utf8) else {
|
||||
throw AppIntentErrors.AppIntentError.message("Failed to encode message content")
|
||||
}
|
||||
|
||||
if messageData.count > 200 {
|
||||
throw $messageContent.needsValueError("Message content exceeds 200 bytes.")
|
||||
}
|
||||
|
||||
if !BLEManager.shared.sendMessage(message: messageContent, toUserNum: Int64(nodeNumber), channel: 0, isEmoji: false, replyID: 0) {
|
||||
throw AppIntentErrors.AppIntentError.message("Failed to send message")
|
||||
}
|
||||
|
||||
return .result()
|
||||
}
|
||||
}
|
||||
61
Meshtastic/AppIntents/SaveChannelSettingsIntent.swift
Normal file
61
Meshtastic/AppIntents/SaveChannelSettingsIntent.swift
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
//
|
||||
// SaveChannelSettingsIntent.swift
|
||||
// Meshtastic
|
||||
//
|
||||
// Created by Benjamin Faershtein on 10/6/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import AppIntents
|
||||
|
||||
// Define the AppIntent for saving channel settings from a URL
|
||||
struct SaveChannelSettingsIntent: AppIntent {
|
||||
// Define a title and description for the intent
|
||||
static var title: LocalizedStringResource = "Save Channel Settings"
|
||||
static var description: IntentDescription = "Takes a Meshtastic channel URL and saves the channel settings."
|
||||
|
||||
// Define the input for the intent (the channel URL)
|
||||
@Parameter(title: "Channel URL", description: "The URL for the channel settings")
|
||||
var channelUrl: URL
|
||||
|
||||
// Define the function that performs the main logic
|
||||
func perform() async throws -> some IntentResult {
|
||||
// Ensure the BLE Manager is connected
|
||||
if !BLEManager.shared.isConnected {
|
||||
throw AppIntentErrors.AppIntentError.notConnected
|
||||
}
|
||||
|
||||
// Ensure the URL contains the expected "meshtastic.org/e/#" structure
|
||||
if channelUrl.absoluteString.lowercased().contains("meshtastic.org/e/#") {
|
||||
// Split the URL to get the portion after "#"
|
||||
let components = channelUrl.absoluteString.components(separatedBy: "#")
|
||||
|
||||
// Add channels flag based on the URL query parameter (if present)
|
||||
let addChannels = Bool(channelUrl["add"] ?? "false") ?? false
|
||||
|
||||
var channelSettings: String?
|
||||
|
||||
// Extract the Base64 encoded channel settings (after "#")
|
||||
if let lastComponent = components.last {
|
||||
channelSettings = lastComponent.components(separatedBy: "?").first // Ignore any query parameters
|
||||
}
|
||||
|
||||
// If valid channel settings are extracted, attempt to save them
|
||||
if let channelSettings = channelSettings {
|
||||
// Call the BLEManager to save the channel settings
|
||||
let saveResult = BLEManager.shared.saveChannelSet(base64UrlString: channelSettings, addChannels: addChannels)
|
||||
|
||||
if !saveResult {
|
||||
throw AppIntentErrors.AppIntentError.message("Failed to save the channel settings.")
|
||||
}
|
||||
} else {
|
||||
throw AppIntentErrors.AppIntentError.message("Invalid Channel URL: Unable to extract settings.")
|
||||
}
|
||||
|
||||
// Return a success result
|
||||
return .result()
|
||||
} else {
|
||||
throw AppIntentErrors.AppIntentError.message("The URL is not a valid Meshtastic channel link.")
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue