Transports Interface to Support TCP for all Platforms and Serial on Mac (#1341)

* Initial implementation of transports

* Initial LogRadio implementation

* Fixes for Settings view (caused by debug commenting)

* Refinement of the object and actor model

* Connect view text and tab updates

* Fix mac catalyst and tests

* Warning and logging clean-up

* In progress commit

* Serial Transport and Reconnect draft work

* Serial transport and reconnection draft work

* Quick fix for BLE - still more work to do

* interim commit

* More in progress changes

* Minor improvements

* Pretty good initial implementation

* Bump version beyond the app store

* Fix for disconnection swipeAction

* Tweaks to TCPConnection implementation

* Retry for NONCE_ONLY_DB

* Revert json string change

* Simplified some of the API + "Anti-discovery"

* Tweaks for devices leaving the discovery process

* Bump version

* iOS26 Tweaks

* Tweaks and bug fixes

* Add link with slash sf symbol

* update symbol image on connect view

* BLE disconnect handling

* Log privacy attributes

* Onboarding and minor fixes.

* change database to nodes, add emoji to tcp logs

* Error handling improvements

* More logging emojis

* Suppressed unnecessary errors on disconnect

* Heartbeat emoji

* Add bluetooth symbol

* add privacy attributes to [TCP] logs, add custom bluetooth logo

* Improve routing logs

* Emoji for connect logs

* Heartbeat emoji

* Add CBCentralManagerScanOptionAllowDuplicatesKey options to central for bluetooth

* fix nav errors by switching from observableobject to state

* Update connection indicator icon

* fix for BLE disconnects

* Connection process fixes

* More fixes/tweaks to connection process

* Strict concurrency

* Fix some warnings, remove wifi warning

* delete stale keys

* interim commit

* Update privacy for log, fix wrong space

* fix a couple of linting items

* Switch to targeted

* interim commit

* BLE Signal strenth on connect view

* Remove BLE RSSI from long press menu

* Modem lights

* minor spacing tweak

* Additional BLE logging and a scanning fix.

* Discovery and BLE RSSI improvements

* Background suspension

* Update isConnected to enable UI during db load

* update protobufs

* Replace config if statements with switches, Fix unknown module config logging, make dark mode modem circle stroke color white so they are visible

* Additional logging cleanup

* hast

* Set unmessagable to true if the longname has the unmessagable emoji

* Connect error handling improvements

* Admin popup list icon and activity lights updates

* Revert use of .toolbar back to .navigationBarItems

* More public logging

* Better BLE error handling

* Node DB progress meter

* minor tweak to activity light interaction timing

* Fix comment linting, remove stale keys

* Remove stale keys

* Easy linting fixes

* Two more simple linting fixes

* clean up meshtasticapp

* More public logging

* Replay config

* Logging

* Fix for unselected node on Settings

* Tweak to progress meter based on device idiom

* Update protos

* Session replay redaction of messages

* Serial fix for old devices, and a let statement

* Mask text too

* Fix typo

* BLE poweredOff is now an auto-reconnectable error

* Update logging

* Fix for peerRemovedPairingInformation

* Logging for BLE peripheral:didUpdateValueFor errors.

* Fix for inconsistent swipe disconnect behavior

* periperal:didUpdateValueFor error handling

* Fix for BLEConnection continuation guarding

* BLEConnection actor deadlock on disconnect

* Heartbeat nonce

* Fix for swipe disconnect and task cancellation

* Fix for swipe actions not honoring .disabled()

* Tell BLETransport when BLEConnection is cancelled

* Update navigation logging

* Logging updates

* Bump version to 2.7.0

* Organize into folders and heartbeat stuff

* Minor improvements to manual TCP connection

* Auto-connect toggle

* Possible BLE bug, still waiting to see in logs

* Concurrency tweaks

* Concurrency improvements

* requestDeviceMetadata fix. fixes remote admin

* Minor typo fixes

* "All" button for log filters: category and level

* More robust continuation handling for BLE

* @FetchRequest based ChannelMessageList

* Update info.plist and device hardware file

* Move auto connect toggle to app settings and debug mode, tint properly with the accent color

* Add label to auto connect toggle

* Update log for node info received from ourselves over the mesh

* Remove unused scrollViewProxy

* Update Meshtastic/Views/Onboarding/DeviceOnboarding.swift

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update target for connect view

* Properly Set datadog environment

* Comment out ble manager

* Adjust cyclomatic complexity thresholds in .swiftlint.yml

* Linting fixes, delete ble manager

* Make session replay debug only

---------

Co-authored-by: jake-b <jake-b@users.noreply.github.com>
Co-authored-by: jake <jake@jakes-Mac-mini.local>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Garth Vander Houwen 2025-08-27 08:09:02 -07:00 committed by GitHub
parent 85c6c1f58a
commit 026bb80fba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
138 changed files with 9463 additions and 6381 deletions

View file

@ -11,7 +11,7 @@ import OSLog
struct AmbientLightingConfig: View {
@Environment(\.self) var environment
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
@EnvironmentObject var accessoryManager: AccessoryManager
@Environment(\.dismiss) private var goBack
var node: NodeInfoEntity?
@ -49,10 +49,13 @@ struct AmbientLightingConfig: View {
}
}
}
.disabled(self.bleManager.connectedPeripheral == nil || node?.ambientLightingConfig == nil)
.disabled(!self.accessoryManager.isConnected || node?.ambientLightingConfig == nil)
SaveConfigButton(node: node, hasChanges: $hasChanges) {
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
guard let deviceNum = accessoryManager.activeDeviceNum else {
return
}
let connectedNode = getNodeInfo(id: deviceNum, context: context)
if connectedNode != nil {
var al = ModuleConfig.AmbientLightingConfig()
al.ledState = ledState
@ -64,37 +67,43 @@ struct AmbientLightingConfig: View {
al.blue = UInt32(components.blue * 255)
}
let adminMessageId = bleManager.saveAmbientLightingModuleConfig(config: al, fromUser: connectedNode!.user!, toUser: node!.user!)
if adminMessageId > 0 {
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
goBack()
Task {
do {
_ = try await accessoryManager.saveAmbientLightingModuleConfig(config: al, fromUser: connectedNode!.user!, toUser: node!.user!)
Task { @MainActor in
hasChanges = false
goBack()
}
} catch {
Logger.mesh.warning("Unable to send ambient lighting module config")
}
}
}
}
.navigationTitle("Ambient Lighting Config")
.navigationBarItems(
trailing: ZStack {
ConnectedDevice(
bluetoothOn: bleManager.isSwitchedOn,
deviceConnected: bleManager.connectedPeripheral != nil,
name: bleManager.connectedPeripheral?.shortName ?? "?"
)
ConnectedDevice(deviceConnected: accessoryManager.isConnected, name: accessoryManager.activeConnection?.device.shortName ?? "?")
}
)
.onFirstAppear {
// Need to request a Ambient Lighting Config from the remote node before allowing changes
if let connectedPeripheral = bleManager.connectedPeripheral, let node {
let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context)
if let deviceNum = accessoryManager.activeDeviceNum, let node {
let connectedNode = getNodeInfo(id: deviceNum, context: context)
if let connectedNode {
if node.num != connectedNode.num {
if node.num != deviceNum {
if UserDefaults.enableAdministration {
/// 2.5 Administration with session passkey
let expiration = node.sessionExpiration ?? Date()
if expiration < Date() || node.ambientLightingConfig == nil {
Logger.mesh.info("⚙️ Empty or expired ambient lighting module config requesting via PKI admin")
_ = bleManager.requestAmbientLightingConfig(fromUser: connectedNode.user!, toUser: node.user!)
Task {
do {
Logger.mesh.info("⚙️ Empty or expired ambient lighting module config requesting via PKI admin")
try await accessoryManager.requestAmbientLightingConfig(fromUser: connectedNode.user!, toUser: node.user!)
} catch {
Logger.mesh.info("🚨 Unable to send ambient lighting config request")
}
}
}
} else {
/// Legacy Administration

View file

@ -10,7 +10,7 @@ import SwiftUI
struct CannedMessagesConfig: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
@EnvironmentObject var accessoryManager: AccessoryManager
@Environment(\.dismiss) private var goBack
var node: NodeInfoEntity?
@State private var isPresentingSaveConfirm: Bool = false
@ -178,10 +178,10 @@ struct CannedMessagesConfig: View {
.disabled(configPreset > 0)
}
.scrollDismissesKeyboard(.immediately)
.disabled(self.bleManager.connectedPeripheral == nil || node?.cannedMessageConfig == nil)
.disabled(!accessoryManager.isConnected || node?.cannedMessageConfig == nil)
SaveConfigButton(node: node, hasChanges: $hasChanges) {
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral?.num ?? -1, context: context)
let connectedNode = getNodeInfo(id: accessoryManager.activeDeviceNum ?? -1, context: context)
if hasChanges {
if connectedNode != nil {
var cmc = ModuleConfig.CannedMessageConfig()
@ -204,17 +204,39 @@ struct CannedMessagesConfig: View {
cmc.inputbrokerEventCw = InputEventChars(rawValue: inputbrokerEventCw)!.protoEnumValue()
cmc.inputbrokerEventCcw = InputEventChars(rawValue: inputbrokerEventCcw)!.protoEnumValue()
cmc.inputbrokerEventPress = InputEventChars(rawValue: inputbrokerEventPress)!.protoEnumValue()
let messagesAdminMessageId = bleManager.saveCannedMessageModuleMessages(messages: messages, fromUser: node!.user!, toUser: node!.user!)
if messagesAdminMessageId > 0 {
// Fire off the message update every time
hasMessagesChanges = false
Task {
do {
_ = try await accessoryManager.saveCannedMessageModuleConfig(config: cmc, fromUser: node!.user!, toUser: node!.user!)
Task { @MainActor in
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
goBack()
}
} catch {
Logger.mesh.error("Unable to save canned message module config")
}
}
let adminMessageId = bleManager.saveCannedMessageModuleConfig(config: cmc, fromUser: node!.user!, toUser: node!.user!)
if adminMessageId > 0 {
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
goBack()
}
}
if hasMessagesChanges {
Task {
do {
_ = try await accessoryManager.saveCannedMessageModuleMessages(messages: messages, fromUser: node!.user!, toUser: node!.user!)
Task { @MainActor in
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasMessagesChanges = false
if !hasChanges {
Task {
Logger.transport.debug("[CannedMessagesConfig] sending wantConfig for save cannedMessagesConfig")
}
goBack()
}
}
} catch {
Logger.mesh.error("Unable to save canned message module messages")
}
}
}
@ -223,24 +245,29 @@ struct CannedMessagesConfig: View {
.navigationBarItems(
trailing: ZStack {
ConnectedDevice(
bluetoothOn: bleManager.isSwitchedOn,
deviceConnected: bleManager.connectedPeripheral != nil,
name: bleManager.connectedPeripheral?.shortName ?? "?"
deviceConnected: accessoryManager.isConnected,
name: accessoryManager.activeConnection?.device.shortName ?? "?"
)
}
)
.onFirstAppear {
// Need to request a CannedMessagesModuleConfig from the remote node before allowing changes
if let connectedPeripheral = bleManager.connectedPeripheral, let node {
let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context)
if let deviceNum = accessoryManager.activeDeviceNum, let node {
let connectedNode = getNodeInfo(id: deviceNum, context: context)
if let connectedNode {
if node.num != connectedNode.num {
if node.num != deviceNum {
if UserDefaults.enableAdministration && node.num != connectedNode.num {
/// 2.5 Administration with session passkey
let expiration = node.sessionExpiration ?? Date()
if expiration < Date() || node.cannedMessageConfig == nil {
Logger.mesh.info("⚙️ Empty or expired canned messages module config requesting via PKI admin")
_ = bleManager.requestCannedMessagesModuleConfig(fromUser: connectedNode.user!, toUser: node.user!)
Task {
do {
Logger.mesh.info("⚙️ Empty or expired canned messages module config requesting via PKI admin")
try await accessoryManager.requestCannedMessagesModuleConfig(fromUser: connectedNode.user!, toUser: node.user!)
} catch {
Logger.mesh.info("🚨 Unable to send canned message module config request")
}
}
}
} else {
/// Legacy Administration

View file

@ -25,7 +25,7 @@ enum DetectionSensorRole: String, CaseIterable, Equatable, Decodable {
struct DetectionSensorConfig: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
@EnvironmentObject var accessoryManager: AccessoryManager
@Environment(\.dismiss) private var goBack
var node: NodeInfoEntity?
@State private var isPresentingSaveConfirm: Bool = false
@ -158,10 +158,10 @@ struct DetectionSensorConfig: View {
}
}
.scrollDismissesKeyboard(.interactively)
.disabled(self.bleManager.connectedPeripheral == nil || node?.detectionSensorConfig == nil)
.disabled(!accessoryManager.isConnected || node?.detectionSensorConfig == nil)
SaveConfigButton(node: node, hasChanges: $hasChanges) {
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral?.num ?? -1, context: context)
let connectedNode = getNodeInfo(id: accessoryManager.activeDeviceNum ?? -1, context: context)
if connectedNode != nil {
var dsc = ModuleConfig.DetectionSensorConfig()
dsc.enabled = self.enabled
@ -172,12 +172,18 @@ struct DetectionSensorConfig: View {
dsc.usePullup = self.usePullup
dsc.minimumBroadcastSecs = UInt32(self.minimumBroadcastSecs)
dsc.stateBroadcastSecs = UInt32(self.stateBroadcastSecs)
let adminMessageId = bleManager.saveDetectionSensorModuleConfig(config: dsc, fromUser: connectedNode!.user!, toUser: node!.user!)
if adminMessageId > 0 {
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
goBack()
Task {
do {
_ = try await accessoryManager.saveDetectionSensorModuleConfig(config: dsc, fromUser: connectedNode!.user!, toUser: node!.user!)
Task { @MainActor in
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
goBack()
}
} catch {
Logger.mesh.error("Unable to save detection sensor module config")
}
}
}
}
@ -185,24 +191,30 @@ struct DetectionSensorConfig: View {
.navigationBarItems(
trailing: ZStack {
ConnectedDevice(
bluetoothOn: bleManager.isSwitchedOn,
deviceConnected: bleManager.connectedPeripheral != nil,
name: bleManager.connectedPeripheral?.shortName ?? "?"
deviceConnected: accessoryManager.isConnected,
name: accessoryManager.activeConnection?.device.shortName ?? "?"
)
}
)
.onFirstAppear {
// Need to request a DetectionSensorModuleConfig from the remote node before allowing changes
if let connectedPeripheral = bleManager.connectedPeripheral, let node {
let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context)
if let deviceNum = accessoryManager.activeDeviceNum, let node {
let connectedNode = getNodeInfo(id: deviceNum, context: context)
if let connectedNode {
if node.num != connectedNode.num {
if node.num != deviceNum {
if UserDefaults.enableAdministration && node.num != connectedNode.num {
/// 2.5 Administration with session passkey
let expiration = node.sessionExpiration ?? Date()
if expiration < Date() || node.detectionSensorConfig == nil {
Logger.mesh.info("⚙️ Empty or expired detection sensor module config requesting via PKI admin")
_ = bleManager.requestDetectionSensorModuleConfig(fromUser: connectedNode.user!, toUser: node.user!)
Task {
do {
Logger.mesh.info("⚙️ Empty or expired detection sensor module config requesting via PKI admin")
try await accessoryManager.requestDetectionSensorModuleConfig(fromUser: connectedNode.user!, toUser: node.user!)
} catch {
Logger.mesh.info("🚨 Unable to send detection sensor module config request")
}
}
}
} else {
/// Legacy Administration

View file

@ -11,7 +11,7 @@ import SwiftUI
struct ExternalNotificationConfig: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
@EnvironmentObject var accessoryManager: AccessoryManager
@Environment(\.dismiss) private var goBack
var node: NodeInfoEntity?
@ -158,11 +158,11 @@ struct ExternalNotificationConfig: View {
}
}
}
.disabled(self.bleManager.connectedPeripheral == nil || node?.externalNotificationConfig == nil)
.disabled(!accessoryManager.isConnected || node?.externalNotificationConfig == nil)
}
SaveConfigButton(node: node, hasChanges: $hasChanges) {
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral?.num ?? -1, context: context)
let connectedNode = getNodeInfo(id: accessoryManager.activeDeviceNum ?? -1, context: context)
if connectedNode != nil {
var enc = ModuleConfig.ExternalNotificationConfig()
enc.enabled = enabled
@ -180,12 +180,16 @@ struct ExternalNotificationConfig: View {
enc.outputMs = UInt32(outputMilliseconds)
enc.usePwm = usePWM
enc.useI2SAsBuzzer = useI2SAsBuzzer
let adminMessageId = bleManager.saveExternalNotificationModuleConfig(config: enc, fromUser: connectedNode!.user!, toUser: node!.user!)
if adminMessageId > 0 {
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
goBack()
Task {
do {
_ = try await accessoryManager.saveExternalNotificationModuleConfig(config: enc, fromUser: connectedNode!.user!, toUser: node!.user!)
Task { @MainActor in
hasChanges = false
goBack()
}
} catch {
Logger.mesh.error("Unable to save external notiication module config")
}
}
}
}
@ -193,24 +197,29 @@ struct ExternalNotificationConfig: View {
.navigationBarItems(
trailing: ZStack {
ConnectedDevice(
bluetoothOn: bleManager.isSwitchedOn,
deviceConnected: bleManager.connectedPeripheral != nil,
name: bleManager.connectedPeripheral?.shortName ?? "?"
deviceConnected: accessoryManager.isConnected,
name: accessoryManager.activeConnection?.device.shortName ?? "?"
)
}
)
.onFirstAppear {
// Need to request a ExternalNotificationModuleConfig from the remote node before allowing changes
if let connectedPeripheral = bleManager.connectedPeripheral, let node {
let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context)
if let deviceNum = accessoryManager.activeDeviceNum, let node {
let connectedNode = getNodeInfo(id: deviceNum, context: context)
if let connectedNode {
if node.num != connectedNode.num {
if node.num != deviceNum {
if UserDefaults.enableAdministration && node.num != connectedNode.num {
/// 2.5 Administration with session passkey
let expiration = node.sessionExpiration ?? Date()
if expiration < Date() || node.externalNotificationConfig == nil {
Logger.mesh.info("⚙️ Empty or expired external notificaiton module config requesting via PKI admin")
_ = bleManager.requestExternalNotificationModuleConfig(fromUser: connectedNode.user!, toUser: node.user!)
Task {
do {
Logger.mesh.info("⚙️ Empty or expired external notificaiton module config requesting via PKI admin")
try await accessoryManager.requestExternalNotificationModuleConfig(fromUser: connectedNode.user!, toUser: node.user!)
} catch {
Logger.mesh.info("🚨 Unable to send external ntoification module config request")
}
}
}
} else {
/// Legacy Administration

View file

@ -12,7 +12,7 @@ import SwiftUI
struct MQTTConfig: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
@EnvironmentObject var accessoryManager: AccessoryManager
@Environment(\.dismiss) private var goBack
var node: NodeInfoEntity?
@State private var isPresentingSaveConfirm: Bool = false
@ -68,8 +68,8 @@ struct MQTTConfig: View {
if enabled && proxyToClientEnabled && node?.mqttConfig?.proxyToClientEnabled ?? false == true {
Toggle(isOn: $mqttConnected) {
Label("Connect to MQTT via Proxy", systemImage: "server.rack")
if bleManager.mqttError.count > 0 {
Text(bleManager.mqttError)
if accessoryManager.mqttError.count > 0 {
Text(accessoryManager.mqttError)
.fixedSize(horizontal: false, vertical: true)
.foregroundColor(.red)
}
@ -250,10 +250,10 @@ struct MQTTConfig: View {
.font(.callout)
}
.scrollDismissesKeyboard(.interactively)
.disabled(self.bleManager.connectedPeripheral == nil || node?.mqttConfig == nil)
.disabled(!accessoryManager.isConnected || node?.mqttConfig == nil)
SaveConfigButton(node: node, hasChanges: $hasChanges) {
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral?.num ?? -1, context: context)
let connectedNode = getNodeInfo(id: accessoryManager.activeDeviceNum ?? -1, context: context)
if connectedNode != nil {
var mqtt = ModuleConfig.MQTTConfig()
mqtt.enabled = self.enabled
@ -268,12 +268,16 @@ struct MQTTConfig: View {
mqtt.mapReportingEnabled = self.mapReportingEnabled
mqtt.mapReportSettings.positionPrecision = UInt32(self.mapPositionPrecision)
mqtt.mapReportSettings.publishIntervalSecs = UInt32(self.mapPublishIntervalSecs)
let adminMessageId = bleManager.saveMQTTConfig(config: mqtt, fromUser: connectedNode!.user!, toUser: node!.user!)
if adminMessageId > 0 {
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
goBack()
Task {
do {
_ = try await accessoryManager.saveMQTTConfig(config: mqtt, fromUser: connectedNode!.user!, toUser: node!.user!)
Task { @MainActor in
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
goBack()
}
}
}
}
}.onChange(of: enabled) { _, newEnabled in
@ -323,12 +327,12 @@ struct MQTTConfig: View {
}
.onChange(of: mqttConnected) { _, newMqttConnected in
if newMqttConnected == false {
if bleManager.mqttProxyConnected {
bleManager.mqttManager.disconnect()
if accessoryManager.mqttProxyConnected {
accessoryManager.mqttManager.disconnect()
}
} else {
if !bleManager.mqttProxyConnected && node != nil {
bleManager.mqttManager.connectFromConfigSettings(node: node!)
if !accessoryManager.mqttProxyConnected && node != nil {
accessoryManager.mqttManager.connectFromConfigSettings(node: node!)
}
}
}
@ -343,24 +347,29 @@ struct MQTTConfig: View {
.navigationBarItems(
trailing: ZStack {
ConnectedDevice(
bluetoothOn: bleManager.isSwitchedOn,
deviceConnected: bleManager.connectedPeripheral != nil,
name: bleManager.connectedPeripheral?.shortName ?? "?"
deviceConnected: accessoryManager.isConnected,
name: accessoryManager.activeConnection?.device.shortName ?? "?"
)
}
)
.onFirstAppear {
// Need to request a MqttModuleConfig from the remote node before allowing changes
if let connectedPeripheral = bleManager.connectedPeripheral, let node {
let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context)
if let deviceNum = accessoryManager.activeDeviceNum, let node {
let connectedNode = getNodeInfo(id: deviceNum, context: context)
if let connectedNode {
if node.num != connectedNode.num {
if UserDefaults.enableAdministration && node.num != connectedNode.num {
if node.num != deviceNum {
if UserDefaults.enableAdministration && node.num != deviceNum {
/// 2.5 Administration with session passkey
let expiration = node.sessionExpiration ?? Date()
if expiration < Date() || node.mqttConfig == nil {
Logger.mesh.info("⚙️ Empty or expired mqtt module config requesting via PKI admin")
_ = bleManager.requestMqttModuleConfig(fromUser: connectedNode.user!, toUser: node.user!)
Task {
do {
Logger.mesh.info("⚙️ Empty or expired mqtt module config requesting via PKI admin")
try await accessoryManager.requestMqttModuleConfig(fromUser: connectedNode.user!, toUser: node.user!)
} catch {
Logger.mesh.error("🚨 Mqtt module config request failed")
}
}
}
} else {
/// Legacy Administration
@ -426,7 +435,7 @@ struct MQTTConfig: View {
self.encryptionEnabled = node?.mqttConfig?.encryptionEnabled ?? false
self.jsonEnabled = node?.mqttConfig?.jsonEnabled ?? false
self.tlsEnabled = node?.mqttConfig?.tlsEnabled ?? false
self.mqttConnected = bleManager.mqttProxyConnected
self.mqttConnected = accessoryManager.mqttProxyConnected
self.mapReportingEnabled = node?.mqttConfig?.mapReportingEnabled ?? false
if node?.mqttConfig?.mapPublishIntervalSecs ?? 0 < 3600 {
self.mapPublishIntervalSecs = 3600

View file

@ -11,7 +11,7 @@ import OSLog
struct PaxCounterConfig: View {
@Environment(\.managedObjectContext) private var context
@EnvironmentObject private var bleManager: BLEManager
@EnvironmentObject private var accessoryManager: AccessoryManager
@Environment(\.dismiss) private var goBack
let node: NodeInfoEntity?
@ -49,27 +49,32 @@ struct PaxCounterConfig: View {
Text("Options")
}
}
.disabled(self.bleManager.connectedPeripheral == nil || node?.powerConfig == nil)
.disabled(!accessoryManager.isConnected || node?.powerConfig == nil)
.navigationTitle("PAX Counter Config")
.navigationBarItems(trailing: ZStack {
ConnectedDevice(
bluetoothOn: bleManager.isSwitchedOn,
deviceConnected: bleManager.connectedPeripheral != nil,
name: "\(bleManager.connectedPeripheral?.shortName ?? "?")"
deviceConnected: accessoryManager.isConnected,
name: "\(accessoryManager.activeConnection?.device.shortName ?? "?")"
)
})
.onFirstAppear {
// Need to request a PaxCounterModuleConfig from the remote node before allowing changes
if let connectedPeripheral = bleManager.connectedPeripheral, let node {
let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context)
if let deviceNum = accessoryManager.activeDeviceNum, let node {
let connectedNode = getNodeInfo(id: deviceNum, context: context)
if let connectedNode {
if node.num != connectedNode.num {
if node.num != deviceNum {
if UserDefaults.enableAdministration && node.num != connectedNode.num {
/// 2.5 Administration with session passkey
let expiration = node.sessionExpiration ?? Date()
if expiration < Date() || node.paxCounterConfig == nil {
Logger.mesh.info("⚙️ Empty or expired pax counter module config requesting via PKI admin")
_ = bleManager.requestPaxCounterModuleConfig(fromUser: connectedNode.user!, toUser: node.user!)
Task {
do {
Logger.mesh.info("⚙️ Empty or expired pax counter module config requesting via PKI admin")
try await accessoryManager.requestPaxCounterModuleConfig(fromUser: connectedNode.user!, toUser: node.user!)
} catch {
Logger.mesh.info("🚨 Request for pax counter module config failed")
}
}
}
} else {
/// Legacy Administration
@ -87,7 +92,7 @@ struct PaxCounterConfig: View {
}
SaveConfigButton(node: node, hasChanges: $hasChanges) {
guard let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context),
guard let connectedNode = getNodeInfo(id: accessoryManager.activeDeviceNum ?? -1, context: context),
let fromUser = connectedNode.user,
let toUser = node?.user else {
return
@ -97,16 +102,18 @@ struct PaxCounterConfig: View {
config.enabled = enabled
config.paxcounterUpdateInterval = UInt32(paxcounterUpdateInterval)
let adminMessageId = bleManager.savePaxcounterModuleConfig(
config: config,
fromUser: fromUser,
toUser: toUser
)
if adminMessageId > 0 {
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
goBack()
Task {
_ = try await accessoryManager.savePaxcounterModuleConfig(
config: config,
fromUser: fromUser,
toUser: toUser
)
Task { @MainActor in
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
goBack()
}
}
}
}

View file

@ -11,7 +11,7 @@ import SwiftUI
struct RangeTestConfig: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
@EnvironmentObject var accessoryManager: AccessoryManager
@Environment(\.dismiss) private var goBack
var node: NodeInfoEntity?
@ -53,21 +53,23 @@ struct RangeTestConfig: View {
}
}
.disabled(self.bleManager.connectedPeripheral == nil || node?.rangeTestConfig == nil)
.disabled(!accessoryManager.isConnected || node?.rangeTestConfig == nil)
SaveConfigButton(node: node, hasChanges: $hasChanges) {
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
let connectedNode = getNodeInfo(id: accessoryManager.activeDeviceNum ?? -1, context: context)
if connectedNode != nil {
var rtc = ModuleConfig.RangeTestConfig()
rtc.enabled = enabled
rtc.save = save
rtc.sender = UInt32(sender)
let adminMessageId = bleManager.saveRangeTestModuleConfig(config: rtc, fromUser: connectedNode!.user!, toUser: node!.user!)
if adminMessageId > 0 {
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
goBack()
Task {
_ = try await accessoryManager.saveRangeTestModuleConfig(config: rtc, fromUser: connectedNode!.user!, toUser: node!.user!)
Task { @MainActor in
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
goBack()
}
}
}
}
@ -75,24 +77,29 @@ struct RangeTestConfig: View {
.navigationBarItems(
trailing: ZStack {
ConnectedDevice(
bluetoothOn: bleManager.isSwitchedOn,
deviceConnected: bleManager.connectedPeripheral != nil,
name: bleManager.connectedPeripheral?.shortName ?? "?"
deviceConnected: accessoryManager.isConnected,
name: accessoryManager.activeConnection?.device.shortName ?? "?"
)
}
)
.onFirstAppear {
// Need to request a RangeTestModuleConfig from the remote node before allowing changes
if let connectedPeripheral = bleManager.connectedPeripheral, let node {
let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context)
if let deviceNum = accessoryManager.activeDeviceNum, let node {
let connectedNode = getNodeInfo(id: deviceNum, context: context)
if let connectedNode {
if node.num != connectedNode.num {
if node.num != deviceNum {
if UserDefaults.enableAdministration && node.num != connectedNode.num {
/// 2.5 Administration with session passkey
let expiration = node.sessionExpiration ?? Date()
if expiration < Date() || node.rangeTestConfig == nil {
Logger.mesh.info("⚙️ Empty or expired range test module config requesting via PKI admin")
_ = bleManager.requestRangeTestModuleConfig(fromUser: connectedNode.user!, toUser: node.user!)
Task {
do {
Logger.mesh.info("⚙️ Empty or expired range test module config requesting via PKI admin")
try await accessoryManager.requestRangeTestModuleConfig(fromUser: connectedNode.user!, toUser: node.user!)
} catch {
Logger.mesh.error("🚨 Request Range test module config failed")
}
}
}
} else {
/// Legacy Administration

View file

@ -10,7 +10,7 @@ import OSLog
struct RtttlConfig: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
@EnvironmentObject var accessoryManager: AccessoryManager
@Environment(\.dismiss) private var goBack
var node: NodeInfoEntity?
@ -48,17 +48,19 @@ struct RtttlConfig: View {
.font(.callout)
}
}
.disabled(self.bleManager.connectedPeripheral == nil || node?.rtttlConfig == nil)
.disabled(!accessoryManager.isConnected || node?.rtttlConfig == nil)
SaveConfigButton(node: node, hasChanges: $hasChanges) {
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
let connectedNode = getNodeInfo(id: accessoryManager.activeDeviceNum ?? -1, context: context)
if connectedNode != nil {
let adminMessageId = bleManager.saveRtttlConfig(ringtone: ringtone.trimmingCharacters(in: .whitespacesAndNewlines), fromUser: connectedNode!.user!, toUser: node!.user!)
if adminMessageId > 0 {
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
goBack()
Task {
_ = try await accessoryManager.saveRtttlConfig(ringtone: ringtone.trimmingCharacters(in: .whitespacesAndNewlines), fromUser: connectedNode!.user!, toUser: node!.user!)
Task { @MainActor in
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
goBack()
}
}
}
}
@ -66,24 +68,29 @@ struct RtttlConfig: View {
.navigationBarItems(
trailing: ZStack {
ConnectedDevice(
bluetoothOn: bleManager.isSwitchedOn,
deviceConnected: bleManager.connectedPeripheral != nil,
name: bleManager.connectedPeripheral?.shortName ?? "?"
deviceConnected: accessoryManager.isConnected,
name: accessoryManager.activeConnection?.device.shortName ?? "?"
)
}
)
.onFirstAppear {
// Need to request a RtttlConfig from the remote node before allowing changes
if let connectedPeripheral = bleManager.connectedPeripheral, let node {
let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context)
if let deviceNum = accessoryManager.activeDeviceNum, let node {
let connectedNode = getNodeInfo(id: deviceNum, context: context)
if let connectedNode {
if node.num != connectedNode.num {
if node.num != deviceNum {
if UserDefaults.enableAdministration && node.num != connectedNode.num {
/// 2.5 Administration with session passkey
let expiration = node.sessionExpiration ?? Date()
if expiration < Date() || node.rtttlConfig == nil {
Logger.mesh.info("⚙️ Empty or expired ringtone module config requesting via PKI admin")
_ = bleManager.requestRtttlConfig(fromUser: connectedNode.user!, toUser: node.user!)
Task {
do {
Logger.mesh.info("⚙️ Empty or expired ringtone module config requesting via PKI admin")
try await accessoryManager.requestRtttlConfig(fromUser: connectedNode.user!, toUser: node.user!)
} catch {
Logger.mesh.info("🚨 Request for ringtone module config failed")
}
}
}
} else {
/// Legacy Administration

View file

@ -11,7 +11,7 @@ import SwiftUI
struct SerialConfig: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
@EnvironmentObject var accessoryManager: AccessoryManager
@Environment(\.dismiss) private var goBack
var node: NodeInfoEntity?
@ -101,10 +101,10 @@ struct SerialConfig: View {
.font(.callout)
}
}
.disabled(self.bleManager.connectedPeripheral == nil || node?.serialConfig == nil)
.disabled(!accessoryManager.isConnected || node?.serialConfig == nil)
SaveConfigButton(node: node, hasChanges: $hasChanges) {
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
let connectedNode = getNodeInfo(id: accessoryManager.activeDeviceNum ?? -1, context: context)
if connectedNode != nil {
var sc = ModuleConfig.SerialConfig()
sc.enabled = enabled
@ -116,13 +116,15 @@ struct SerialConfig: View {
sc.overrideConsoleSerialPort = overrideConsoleSerialPort
sc.mode = SerialModeTypes(rawValue: mode)!.protoEnumValue()
let adminMessageId = bleManager.saveSerialModuleConfig(config: sc, fromUser: connectedNode!.user!, toUser: node!.user!)
Task {
_ = try await accessoryManager.saveSerialModuleConfig(config: sc, fromUser: connectedNode!.user!, toUser: node!.user!)
if adminMessageId > 0 {
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
goBack()
Task { @MainActor in
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
goBack()
}
}
}
}
@ -130,24 +132,29 @@ struct SerialConfig: View {
.navigationBarItems(
trailing: ZStack {
ConnectedDevice(
bluetoothOn: bleManager.isSwitchedOn,
deviceConnected: bleManager.connectedPeripheral != nil,
name: bleManager.connectedPeripheral?.shortName ?? "?"
deviceConnected: accessoryManager.isConnected,
name: accessoryManager.activeConnection?.device.shortName ?? "?"
)
}
)
.onFirstAppear {
// Need to request a SerialModuleConfig from the remote node before allowing changes
if let connectedPeripheral = bleManager.connectedPeripheral, let node {
let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context)
if let deviceNum = accessoryManager.activeDeviceNum, let node {
let connectedNode = getNodeInfo(id: deviceNum, context: context)
if let connectedNode {
if node.num != connectedNode.num {
if UserDefaults.enableAdministration && node.num != connectedNode.num {
if node.num != deviceNum {
if UserDefaults.enableAdministration && node.num != deviceNum {
/// 2.5 Administration with session passkey
let expiration = node.sessionExpiration ?? Date()
if expiration < Date() || node.serialConfig == nil {
Logger.mesh.info("⚙️ Empty or expired serial module config requesting via PKI admin")
_ = bleManager.requestSerialModuleConfig(fromUser: connectedNode.user!, toUser: node.user!)
Task {
do {
Logger.mesh.info("⚙️ Empty or expired serial module config requesting via PKI admin")
try await accessoryManager.requestSerialModuleConfig(fromUser: connectedNode.user!, toUser: node.user!)
} catch {
Logger.mesh.info("🚨 Request for serial module config failed")
}
}
}
} else {
/// Legacy Administration

View file

@ -11,7 +11,7 @@ import SwiftUI
struct StoreForwardConfig: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
@EnvironmentObject var accessoryManager: AccessoryManager
@Environment(\.dismiss) private var goBack
var node: NodeInfoEntity?
@State private var isPresentingSaveConfirm: Bool = false
@ -94,11 +94,11 @@ struct StoreForwardConfig: View {
}
}
.scrollDismissesKeyboard(.interactively)
.disabled(self.bleManager.connectedPeripheral == nil || node?.storeForwardConfig == nil)
.disabled(!accessoryManager.isConnected || node?.storeForwardConfig == nil)
}
SaveConfigButton(node: node, hasChanges: $hasChanges) {
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral?.num ?? -1, context: context)
let connectedNode = getNodeInfo(id: accessoryManager.activeDeviceNum ?? -1, context: context)
if connectedNode != nil {
/// Let the user set isServer for the connected node, for nodes on the mesh set isServer based
/// on receipt of a primary heartbeat
@ -118,12 +118,15 @@ struct StoreForwardConfig: View {
sfc.records = UInt32(self.records)
sfc.historyReturnMax = UInt32(self.historyReturnMax)
sfc.historyReturnWindow = UInt32(self.historyReturnWindow)
let adminMessageId = bleManager.saveStoreForwardModuleConfig(config: sfc, fromUser: connectedNode!.user!, toUser: node!.user!)
if adminMessageId > 0 {
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
goBack()
Task {
_ = try await accessoryManager.saveStoreForwardModuleConfig(config: sfc, fromUser: connectedNode!.user!, toUser: node!.user!)
Task { @MainActor in
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
goBack()
}
}
}
}
@ -131,24 +134,29 @@ struct StoreForwardConfig: View {
.navigationBarItems(
trailing: ZStack {
ConnectedDevice(
bluetoothOn: bleManager.isSwitchedOn,
deviceConnected: bleManager.connectedPeripheral != nil,
name: bleManager.connectedPeripheral?.shortName ?? "?"
deviceConnected: accessoryManager.isConnected,
name: accessoryManager.activeConnection?.device.shortName ?? "?"
)
}
)
.onFirstAppear {
// Need to request a StoreForwardModuleConfig from the remote node before allowing changes
if let connectedPeripheral = bleManager.connectedPeripheral, let node {
let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context)
if let deviceNum = accessoryManager.activeDeviceNum, let node {
let connectedNode = getNodeInfo(id: deviceNum, context: context)
if let connectedNode {
if node.num != connectedNode.num {
if UserDefaults.enableAdministration && node.num != connectedNode.num {
if node.num != deviceNum {
if UserDefaults.enableAdministration && node.num != deviceNum {
/// 2.5 Administration with session passkey
let expiration = node.sessionExpiration ?? Date()
if expiration < Date() || node.storeForwardConfig == nil {
Logger.mesh.info("⚙️ Empty or expired store & forward module config requesting via PKI admin")
_ = bleManager.requestStoreAndForwardModuleConfig(fromUser: connectedNode.user!, toUser: node.user!)
Task {
do {
Logger.mesh.info("⚙️ Empty or expired store & forward module config requesting via PKI admin")
try await accessoryManager.requestStoreAndForwardModuleConfig(fromUser: connectedNode.user!, toUser: node.user!)
} catch {
Logger.mesh.info("🚨 Request for store & forward module config failed")
}
}
}
} else {
/// Legacy Administration

View file

@ -11,7 +11,7 @@ import SwiftUI
struct TelemetryConfig: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
@EnvironmentObject var accessoryManager: AccessoryManager
@Environment(\.dismiss) private var goBack
var node: NodeInfoEntity?
@ -101,10 +101,10 @@ struct TelemetryConfig: View {
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
}
}
.disabled(self.bleManager.connectedPeripheral == nil || node?.telemetryConfig == nil)
.disabled(!accessoryManager.isConnected || node?.telemetryConfig == nil)
SaveConfigButton(node: node, hasChanges: $hasChanges) {
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral?.num ?? -1, context: context)
let connectedNode = getNodeInfo(id: accessoryManager.activeDeviceNum ?? -1, context: context)
if connectedNode != nil {
var tc = ModuleConfig.TelemetryConfig()
tc.deviceUpdateInterval = UInt32(deviceUpdateInterval)
@ -115,37 +115,43 @@ struct TelemetryConfig: View {
tc.powerMeasurementEnabled = powerMeasurementEnabled
tc.powerUpdateInterval = UInt32(powerUpdateInterval)
tc.powerScreenEnabled = powerScreenEnabled
let adminMessageId = bleManager.saveTelemetryModuleConfig(config: tc, fromUser: connectedNode!.user!, toUser: node!.user!)
if adminMessageId > 0 {
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
goBack()
Task {
_ = try await accessoryManager.saveTelemetryModuleConfig(config: tc, fromUser: connectedNode!.user!, toUser: node!.user!)
Task { @MainActor in
// Should show a saved successfully alert once I know that to be true
// for now just disable the button after a successful save
hasChanges = false
goBack()
}
}
}
}
.navigationTitle("Telemetry Config")
.navigationBarItems(
trailing: ZStack {
ConnectedDevice(
bluetoothOn: bleManager.isSwitchedOn,
deviceConnected: bleManager.connectedPeripheral != nil,
name: bleManager.connectedPeripheral?.shortName ?? "?"
)
ConnectedDevice(deviceConnected: accessoryManager.isConnected, name: accessoryManager.activeConnection?.device.shortName ?? "?")
}
)
.onFirstAppear {
// Need to request a TelemetryModuleConfig from the remote node before allowing changes
if let connectedPeripheral = bleManager.connectedPeripheral, let node {
let connectedNode = getNodeInfo(id: connectedPeripheral.num, context: context)
if let deviceNum = accessoryManager.activeDeviceNum, let node {
let connectedNode = getNodeInfo(id: deviceNum, context: context)
if let connectedNode {
if node.num != connectedNode.num {
if UserDefaults.enableAdministration && node.num != connectedNode.num {
if node.num != deviceNum {
if UserDefaults.enableAdministration && node.num != deviceNum {
/// 2.5 Administration with session passkey
let expiration = node.sessionExpiration ?? Date()
if expiration < Date() || node.telemetryConfig == nil {
Logger.mesh.info("⚙️ Empty or expired telemetry module config requesting via PKI admin")
_ = bleManager.requestTelemetryModuleConfig(fromUser: connectedNode.user!, toUser: node.user!)
Task {
do {
Logger.mesh.info("⚙️ Empty or expired telemetry module config requesting via PKI admin")
try await accessoryManager.requestTelemetryModuleConfig(fromUser: connectedNode.user!, toUser: node.user!)
} catch {
Logger.mesh.info("🚨 Telemetry module config request failed: \(error.localizedDescription)")
}
}
}
} else {
/// Legacy Administration