Merge pull request #301 from meshtastic/add_weatherkit

Hook up Admin Channel
This commit is contained in:
Garth Vander Houwen 2023-02-01 09:26:31 -08:00 committed by GitHub
commit 6533234730
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 1124 additions and 537 deletions

View file

@ -14,8 +14,29 @@ enum DeviceRoles: Int, CaseIterable, Identifiable {
case clientMute = 1
case router = 2
case routerClient = 3
case repeater = 4
case tracker = 5
var id: Int { self.rawValue }
var name: String {
get {
switch self {
case .client:
return "Client"
case .clientMute:
return "Muted Client"
case .router:
return "Router"
case .routerClient:
return "Router & Client"
case .repeater:
return "Repeater"
case .tracker:
return "Tracker"
}
}
}
var description: String {
get {
switch self {
@ -28,6 +49,10 @@ enum DeviceRoles: Int, CaseIterable, Identifiable {
return NSLocalizedString("device.role.router", comment: "Router - Mesh packets will prefer to be routed over this node. This node will not be used by client apps. The wifi/ble radios and the oled screen will be put to sleep.")
case .routerClient:
return NSLocalizedString("device.role.routerclient", comment: "Router Client - Mesh packets will prefer to be routed over this node. The Router Client can be used as both a Router and an app connected Client.")
case .repeater:
return "Mesh packets will simply be rebroadcasted over this node. Nodes configured with this role will not originate NodeInfo, Position, Telemetry or any other packet type. They will simply rebroadcast any mesh packets on the same frequency, channel num, spread factor, and coding rate."
case .tracker:
return "Position Mesh packets will be prioritized higher and sent more frequently by default."
}
}
}
@ -43,6 +68,10 @@ enum DeviceRoles: Int, CaseIterable, Identifiable {
return Config.DeviceConfig.Role.router
case .routerClient:
return Config.DeviceConfig.Role.routerClient
case .repeater:
return Config.DeviceConfig.Role.repeater
case .tracker:
return Config.DeviceConfig.Role.tracker
}
}
}

View file

@ -22,6 +22,8 @@ enum RegionCodes : Int, CaseIterable, Identifiable {
case `in` = 10
case nz865 = 11
case th = 12
case ua433 = 14
case ua868 = 15
case lora24 = 13
var id: Int { self.rawValue }
@ -54,6 +56,10 @@ enum RegionCodes : Int, CaseIterable, Identifiable {
return "New Zealand 865mhz"
case .th:
return "Thailand"
case .ua433:
return "Ukraine 433mhz"
case .ua868:
return "Ukraine 868mhz"
case .lora24:
return "2.4 GHZ"
}
@ -90,6 +96,10 @@ enum RegionCodes : Int, CaseIterable, Identifiable {
return Config.LoRaConfig.RegionCode.nz865
case .th:
return Config.LoRaConfig.RegionCode.th
case .ua433:
return Config.LoRaConfig.RegionCode.ua433
case .ua868:
return Config.LoRaConfig.RegionCode.ua868
case .lora24:
return Config.LoRaConfig.RegionCode.lora24
}
@ -100,6 +110,7 @@ enum ModemPresets : Int, CaseIterable, Identifiable {
case LongFast = 0
case LongSlow = 1
case LongModerate = 7
case VLongSlow = 2
case MedSlow = 3
case MedFast = 4
@ -115,6 +126,8 @@ enum ModemPresets : Int, CaseIterable, Identifiable {
return "Long Range - Fast"
case .LongSlow:
return "Long Range - Slow"
case .LongModerate:
return "Long Range - Moderate"
case .VLongSlow:
return "Very Long Range - Slow"
case .MedSlow:
@ -136,10 +149,12 @@ enum ModemPresets : Int, CaseIterable, Identifiable {
return Config.LoRaConfig.ModemPreset.longFast
case .LongSlow:
return Config.LoRaConfig.ModemPreset.longSlow
case .LongModerate:
return Config.LoRaConfig.ModemPreset.longModerate
case .VLongSlow:
return Config.LoRaConfig.ModemPreset.veryLongSlow
return Config.LoRaConfig.ModemPreset.veryLongSlow
case .MedSlow:
return Config.LoRaConfig.ModemPreset.mediumSlow
return Config.LoRaConfig.ModemPreset.mediumSlow
case .MedFast:
return Config.LoRaConfig.ModemPreset.mediumFast
case .ShortSlow:

View file

@ -1419,10 +1419,62 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject {
let messageDescription = "🛎️ Requested Bluetooth Config on admin channel \(adminIndex) for node: \(String(connectedPeripheral.num))"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
return true
}
return false
}
public func requestDeviceConfig(fromUser: UserEntity, toUser: UserEntity, adminIndex: Int32) -> Bool {
var adminPacket = AdminMessage()
adminPacket.getConfigRequest = AdminMessage.ConfigType.deviceConfig
var meshPacket: MeshPacket = MeshPacket()
meshPacket.to = UInt32(toUser.num)
meshPacket.from = UInt32(fromUser.num)
meshPacket.id = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
meshPacket.priority = MeshPacket.Priority.reliable
meshPacket.channel = UInt32(adminIndex)
var dataMessage = DataMessage()
dataMessage.payload = try! adminPacket.serializedData()
dataMessage.portnum = PortNum.adminApp
dataMessage.wantResponse = true
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested Device Config on admin channel \(adminIndex) for node: \(String(connectedPeripheral.num))"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
return true
}
return false
}
public func requestDisplayConfig(fromUser: UserEntity, toUser: UserEntity, adminIndex: Int32) -> Bool {
var adminPacket = AdminMessage()
adminPacket.getConfigRequest = AdminMessage.ConfigType.displayConfig
var meshPacket: MeshPacket = MeshPacket()
meshPacket.to = UInt32(toUser.num)
meshPacket.from = UInt32(fromUser.num)
meshPacket.id = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
meshPacket.priority = MeshPacket.Priority.reliable
meshPacket.channel = UInt32(adminIndex)
var dataMessage = DataMessage()
dataMessage.payload = try! adminPacket.serializedData()
dataMessage.portnum = PortNum.adminApp
dataMessage.wantResponse = true
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested Display Config on admin channel \(adminIndex) for node: \(String(connectedPeripheral.num))"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
return true
}
return false
}
@ -1455,6 +1507,214 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject {
return false
}
public func requestNetworkConfig(fromUser: UserEntity, toUser: UserEntity, adminIndex: Int32) -> Bool {
var adminPacket = AdminMessage()
adminPacket.getConfigRequest = AdminMessage.ConfigType.networkConfig
var meshPacket: MeshPacket = MeshPacket()
meshPacket.to = UInt32(toUser.num)
meshPacket.from = UInt32(fromUser.num)
meshPacket.id = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
meshPacket.priority = MeshPacket.Priority.reliable
meshPacket.channel = UInt32(adminIndex)
var dataMessage = DataMessage()
dataMessage.payload = try! adminPacket.serializedData()
dataMessage.portnum = PortNum.adminApp
dataMessage.wantResponse = true
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested Network Config on admin channel \(adminIndex) for node: \(String(connectedPeripheral.num))"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
return true
}
return false
}
public func requestPositionConfig(fromUser: UserEntity, toUser: UserEntity, adminIndex: Int32) -> Bool {
var adminPacket = AdminMessage()
adminPacket.getConfigRequest = AdminMessage.ConfigType.positionConfig
var meshPacket: MeshPacket = MeshPacket()
meshPacket.to = UInt32(toUser.num)
meshPacket.from = UInt32(fromUser.num)
meshPacket.id = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
meshPacket.priority = MeshPacket.Priority.reliable
meshPacket.channel = UInt32(adminIndex)
var dataMessage = DataMessage()
dataMessage.payload = try! adminPacket.serializedData()
dataMessage.portnum = PortNum.adminApp
dataMessage.wantResponse = true
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested Position Config on admin channel \(adminIndex) for node: \(String(connectedPeripheral.num))"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
return true
}
return false
}
public func requestCannedMessagesModuleConfig(fromUser: UserEntity, toUser: UserEntity, adminIndex: Int32) -> Bool {
var adminPacket = AdminMessage()
adminPacket.getModuleConfigRequest = AdminMessage.ModuleConfigType.cannedmsgConfig
var meshPacket: MeshPacket = MeshPacket()
meshPacket.to = UInt32(toUser.num)
meshPacket.from = UInt32(fromUser.num)
meshPacket.id = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
meshPacket.priority = MeshPacket.Priority.reliable
meshPacket.channel = UInt32(adminIndex)
var dataMessage = DataMessage()
dataMessage.payload = try! adminPacket.serializedData()
dataMessage.portnum = PortNum.adminApp
dataMessage.wantResponse = true
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested Canned Messages Module Config on admin channel \(adminIndex) for node: \(String(connectedPeripheral.num))"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
return true
}
return false
}
public func requestExternalNotificationModuleConfig(fromUser: UserEntity, toUser: UserEntity, adminIndex: Int32) -> Bool {
var adminPacket = AdminMessage()
adminPacket.getModuleConfigRequest = AdminMessage.ModuleConfigType.extnotifConfig
var meshPacket: MeshPacket = MeshPacket()
meshPacket.to = UInt32(toUser.num)
meshPacket.from = UInt32(fromUser.num)
meshPacket.id = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
meshPacket.priority = MeshPacket.Priority.reliable
meshPacket.channel = UInt32(adminIndex)
var dataMessage = DataMessage()
dataMessage.payload = try! adminPacket.serializedData()
dataMessage.portnum = PortNum.adminApp
dataMessage.wantResponse = true
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested External Notificaiton Module Config on admin channel \(adminIndex) for node: \(String(connectedPeripheral.num))"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
return true
}
return false
}
public func requestRangeTestModuleConfig(fromUser: UserEntity, toUser: UserEntity, adminIndex: Int32) -> Bool {
var adminPacket = AdminMessage()
adminPacket.getModuleConfigRequest = AdminMessage.ModuleConfigType.rangetestConfig
var meshPacket: MeshPacket = MeshPacket()
meshPacket.to = UInt32(toUser.num)
meshPacket.from = UInt32(fromUser.num)
meshPacket.id = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
meshPacket.priority = MeshPacket.Priority.reliable
meshPacket.channel = UInt32(adminIndex)
var dataMessage = DataMessage()
dataMessage.payload = try! adminPacket.serializedData()
dataMessage.portnum = PortNum.adminApp
dataMessage.wantResponse = true
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested Range Test Module Config on admin channel \(adminIndex) for node: \(String(connectedPeripheral.num))"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
return true
}
return false
}
public func requestMqttModuleConfig(fromUser: UserEntity, toUser: UserEntity, adminIndex: Int32) -> Bool {
var adminPacket = AdminMessage()
adminPacket.getModuleConfigRequest = AdminMessage.ModuleConfigType.mqttConfig
var meshPacket: MeshPacket = MeshPacket()
meshPacket.to = UInt32(toUser.num)
meshPacket.from = UInt32(fromUser.num)
meshPacket.id = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
meshPacket.priority = MeshPacket.Priority.reliable
meshPacket.channel = UInt32(adminIndex)
var dataMessage = DataMessage()
dataMessage.payload = try! adminPacket.serializedData()
dataMessage.portnum = PortNum.adminApp
dataMessage.wantResponse = true
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested MQTT Module Config on admin channel \(adminIndex) for node: \(String(connectedPeripheral.num))"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
return true
}
return false
}
public func requestSerialModuleConfig(fromUser: UserEntity, toUser: UserEntity, adminIndex: Int32) -> Bool {
var adminPacket = AdminMessage()
adminPacket.getModuleConfigRequest = AdminMessage.ModuleConfigType.serialConfig
var meshPacket: MeshPacket = MeshPacket()
meshPacket.to = UInt32(toUser.num)
meshPacket.from = UInt32(fromUser.num)
meshPacket.id = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
meshPacket.priority = MeshPacket.Priority.reliable
meshPacket.channel = UInt32(adminIndex)
var dataMessage = DataMessage()
dataMessage.payload = try! adminPacket.serializedData()
dataMessage.portnum = PortNum.adminApp
dataMessage.wantResponse = true
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested Serial Module Config on admin channel \(adminIndex) for node: \(String(connectedPeripheral.num))"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
return true
}
return false
}
public func requestTelemetryModuleConfig(fromUser: UserEntity, toUser: UserEntity, adminIndex: Int32) -> Bool {
var adminPacket = AdminMessage()
adminPacket.getModuleConfigRequest = AdminMessage.ModuleConfigType.telemetryConfig
var meshPacket: MeshPacket = MeshPacket()
meshPacket.to = UInt32(toUser.num)
meshPacket.from = UInt32(fromUser.num)
meshPacket.id = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
meshPacket.priority = MeshPacket.Priority.reliable
meshPacket.channel = UInt32(adminIndex)
var dataMessage = DataMessage()
dataMessage.payload = try! adminPacket.serializedData()
dataMessage.portnum = PortNum.adminApp
dataMessage.wantResponse = true
meshPacket.decoded = dataMessage
let messageDescription = "🛎️ Requested Telemetry Module Config on admin channel \(adminIndex) for node: \(String(connectedPeripheral.num))"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
return true
}
return false
}
public func saveExternalNotificationModuleConfig(config: ModuleConfig.ExternalNotificationConfig, fromUser: UserEntity, toUser: UserEntity) -> Int64 {
var adminPacket = AdminMessage()
@ -1499,12 +1759,9 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject {
meshPacket.decoded = dataMessage
let messageDescription = "Saved WiFi Config for \(toUser.longName ?? NSLocalizedString("unknown", comment: "Unknown"))"
if sendAdminMessageToRadio(meshPacket: meshPacket, adminDescription: messageDescription, fromUser: fromUser, toUser: toUser) {
return Int64(meshPacket.id)
}
return 0
}

View file

@ -40,355 +40,34 @@ func localConfig (config: Config, context:NSManagedObjectContext, nodeNum: Int64
// We don't care about any of the Power settings, config is available for everything else
if config.payloadVariant == Config.OneOf_PayloadVariant.bluetooth(config.bluetooth) {
upsertBluetoothConfigPacket(config: config, nodeNum: nodeNum, context: context)
upsertBluetoothConfigPacket(config: config.bluetooth, nodeNum: nodeNum, context: context)
} else if config.payloadVariant == Config.OneOf_PayloadVariant.device(config.device) {
upsertDeviceConfigPacket(config: config, nodeNum: nodeNum, context: context)
upsertDeviceConfigPacket(config: config.device, nodeNum: nodeNum, context: context)
} else if config.payloadVariant == Config.OneOf_PayloadVariant.display(config.display) {
upsertDisplayConfigPacket(config: config, nodeNum: nodeNum, context: context)
upsertDisplayConfigPacket(config: config.display, nodeNum: nodeNum, context: context)
} else if config.payloadVariant == Config.OneOf_PayloadVariant.lora(config.lora) {
upsertLoRaConfigPacket(config: config, nodeNum: nodeNum, context: context)
upsertLoRaConfigPacket(config: config.lora, nodeNum: nodeNum, context: context)
} else if config.payloadVariant == Config.OneOf_PayloadVariant.network(config.network) {
upsertNetworkConfigPacket(config: config, nodeNum: nodeNum, context: context)
upsertNetworkConfigPacket(config: config.network, nodeNum: nodeNum, context: context)
} else if config.payloadVariant == Config.OneOf_PayloadVariant.position(config.position) {
upsertPositionConfigPacket(config: config, nodeNum: nodeNum, context: context)
upsertPositionConfigPacket(config: config.position, nodeNum: nodeNum, context: context)
}
}
func moduleConfig (config: ModuleConfig, context:NSManagedObjectContext, nodeNum: Int64, nodeLongName: String) {
if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.cannedMessage(config.cannedMessage) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.cannedmessage.config %@", comment: "Canned Message module config received: %@"), String(nodeNum))
MeshLogger.log("🥫 \(logString)")
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
do {
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
// Found a node, save Canned Message Config
if !fetchedNode.isEmpty {
if fetchedNode[0].cannedMessageConfig == nil {
let newCannedMessageConfig = CannedMessageConfigEntity(context: context)
newCannedMessageConfig.enabled = config.cannedMessage.enabled
newCannedMessageConfig.sendBell = config.cannedMessage.sendBell
newCannedMessageConfig.rotary1Enabled = config.cannedMessage.rotary1Enabled
newCannedMessageConfig.updown1Enabled = config.cannedMessage.updown1Enabled
newCannedMessageConfig.inputbrokerPinA = Int32(config.cannedMessage.inputbrokerPinA)
newCannedMessageConfig.inputbrokerPinB = Int32(config.cannedMessage.inputbrokerPinB)
newCannedMessageConfig.inputbrokerPinPress = Int32(config.cannedMessage.inputbrokerPinPress)
newCannedMessageConfig.inputbrokerEventCw = Int32(config.cannedMessage.inputbrokerEventCw.rawValue)
newCannedMessageConfig.inputbrokerEventCcw = Int32(config.cannedMessage.inputbrokerEventCcw.rawValue)
newCannedMessageConfig.inputbrokerEventPress = Int32(config.cannedMessage.inputbrokerEventPress.rawValue)
fetchedNode[0].cannedMessageConfig = newCannedMessageConfig
} else {
fetchedNode[0].cannedMessageConfig?.enabled = config.cannedMessage.enabled
fetchedNode[0].cannedMessageConfig?.sendBell = config.cannedMessage.sendBell
fetchedNode[0].cannedMessageConfig?.rotary1Enabled = config.cannedMessage.rotary1Enabled
fetchedNode[0].cannedMessageConfig?.updown1Enabled = config.cannedMessage.updown1Enabled
fetchedNode[0].cannedMessageConfig?.inputbrokerPinA = Int32(config.cannedMessage.inputbrokerPinA)
fetchedNode[0].cannedMessageConfig?.inputbrokerPinB = Int32(config.cannedMessage.inputbrokerPinB)
fetchedNode[0].cannedMessageConfig?.inputbrokerPinPress = Int32(config.cannedMessage.inputbrokerPinPress)
fetchedNode[0].cannedMessageConfig?.inputbrokerEventCw = Int32(config.cannedMessage.inputbrokerEventCw.rawValue)
fetchedNode[0].cannedMessageConfig?.inputbrokerEventCcw = Int32(config.cannedMessage.inputbrokerEventCcw.rawValue)
fetchedNode[0].cannedMessageConfig?.inputbrokerEventPress = Int32(config.cannedMessage.inputbrokerEventPress.rawValue)
}
do {
try context.save()
print("💾 Updated Canned Message Module Config for node number: \(String(nodeNum))")
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Updating Core Data CannedMessageConfigEntity: \(nsError)")
}
} else {
print("💥 No Nodes found in local database matching node number \(nodeNum) unable to save Canned Message Module Config")
}
} catch {
let nsError = error as NSError
print("💥 Fetching node for core data CannedMessageConfigEntity failed: \(nsError)")
}
}
if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.externalNotification(config.externalNotification) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.externalnotification.config %@", comment: "External Notifiation module config received: %@"), String(nodeNum))
MeshLogger.log("📣 \(logString)")
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
do {
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
// Found a node, save External Notificaitone Config
if !fetchedNode.isEmpty {
if fetchedNode[0].externalNotificationConfig == nil {
let newExternalNotificationConfig = ExternalNotificationConfigEntity(context: context)
newExternalNotificationConfig.enabled = config.externalNotification.enabled
newExternalNotificationConfig.usePWM = config.externalNotification.usePwm
newExternalNotificationConfig.alertBell = config.externalNotification.alertBell
newExternalNotificationConfig.alertBellBuzzer = config.externalNotification.alertBellBuzzer
newExternalNotificationConfig.alertBellVibra = config.externalNotification.alertBellVibra
newExternalNotificationConfig.alertMessage = config.externalNotification.alertMessage
newExternalNotificationConfig.alertMessageBuzzer = config.externalNotification.alertMessageBuzzer
newExternalNotificationConfig.alertMessageVibra = config.externalNotification.alertMessageVibra
newExternalNotificationConfig.active = config.externalNotification.active
newExternalNotificationConfig.output = Int32(config.externalNotification.output)
newExternalNotificationConfig.outputBuzzer = Int32(config.externalNotification.outputBuzzer)
newExternalNotificationConfig.outputVibra = Int32(config.externalNotification.outputVibra)
newExternalNotificationConfig.outputMilliseconds = Int32(config.externalNotification.outputMs)
newExternalNotificationConfig.nagTimeout = Int32(config.externalNotification.nagTimeout)
fetchedNode[0].externalNotificationConfig = newExternalNotificationConfig
} else {
fetchedNode[0].externalNotificationConfig?.enabled = config.externalNotification.enabled
fetchedNode[0].externalNotificationConfig?.usePWM = config.externalNotification.usePwm
fetchedNode[0].externalNotificationConfig?.alertBell = config.externalNotification.alertBell
fetchedNode[0].externalNotificationConfig?.alertBellBuzzer = config.externalNotification.alertBellBuzzer
fetchedNode[0].externalNotificationConfig?.alertBellVibra = config.externalNotification.alertBellVibra
fetchedNode[0].externalNotificationConfig?.alertMessage = config.externalNotification.alertMessage
fetchedNode[0].externalNotificationConfig?.alertMessageBuzzer = config.externalNotification.alertMessageBuzzer
fetchedNode[0].externalNotificationConfig?.alertMessageVibra = config.externalNotification.alertMessageVibra
fetchedNode[0].externalNotificationConfig?.active = config.externalNotification.active
fetchedNode[0].externalNotificationConfig?.output = Int32(config.externalNotification.output)
fetchedNode[0].externalNotificationConfig?.outputBuzzer = Int32(config.externalNotification.outputBuzzer)
fetchedNode[0].externalNotificationConfig?.outputVibra = Int32(config.externalNotification.outputVibra)
fetchedNode[0].externalNotificationConfig?.outputMilliseconds = Int32(config.externalNotification.outputMs)
fetchedNode[0].externalNotificationConfig?.nagTimeout = Int32(config.externalNotification.nagTimeout)
}
do {
try context.save()
print("💾 Updated External Notification Module Config for node number: \(String(nodeNum))")
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Updating Core Data ExternalNotificationConfigEntity: \(nsError)")
}
} else {
print("💥 No Nodes found in local database matching node number \(nodeNum) unable to save External Notifiation Module Config")
}
} catch {
let nsError = error as NSError
print("💥 Fetching node for core data ExternalNotificationConfigEntity failed: \(nsError)")
}
}
if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.mqtt(config.mqtt) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.mqtt.config %@", comment: "MQTT module config received: %@"), String(nodeNum))
MeshLogger.log("🌉 \(logString)")
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
do {
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
// Found a node, save MQTT Config
if !fetchedNode.isEmpty {
if fetchedNode[0].mqttConfig == nil {
let newMQTTConfig = MQTTConfigEntity(context: context)
newMQTTConfig.enabled = config.mqtt.enabled
newMQTTConfig.address = config.mqtt.address
newMQTTConfig.address = config.mqtt.username
newMQTTConfig.password = config.mqtt.password
newMQTTConfig.encryptionEnabled = config.mqtt.encryptionEnabled
newMQTTConfig.jsonEnabled = config.mqtt.jsonEnabled
fetchedNode[0].mqttConfig = newMQTTConfig
} else {
fetchedNode[0].mqttConfig?.enabled = config.mqtt.enabled
fetchedNode[0].mqttConfig?.address = config.mqtt.address
fetchedNode[0].mqttConfig?.address = config.mqtt.username
fetchedNode[0].mqttConfig?.password = config.mqtt.password
fetchedNode[0].mqttConfig?.encryptionEnabled = config.mqtt.encryptionEnabled
fetchedNode[0].mqttConfig?.jsonEnabled = config.mqtt.jsonEnabled
}
do {
try context.save()
print("💾 Updated MQTT Config for node number: \(String(nodeNum))")
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Updating Core Data MQTTConfigEntity: \(nsError)")
}
} else {
print("💥 No Nodes found in local database matching node number \(nodeNum) unable to save MQTT Module Config")
}
} catch {
let nsError = error as NSError
print("💥 Fetching node for core data MQTTConfigEntity failed: \(nsError)")
}
}
if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.rangeTest(config.rangeTest) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.rangetest.config %@", comment: "Range Test module config received: %@"), String(nodeNum))
MeshLogger.log("⛰️ \(logString)")
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
do {
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
// Found a node, save Device Config
if !fetchedNode.isEmpty {
if fetchedNode[0].rangeTestConfig == nil {
let newRangeTestConfig = RangeTestConfigEntity(context: context)
newRangeTestConfig.sender = Int32(config.rangeTest.sender)
newRangeTestConfig.enabled = config.rangeTest.enabled
newRangeTestConfig.save = config.rangeTest.save
fetchedNode[0].rangeTestConfig = newRangeTestConfig
} else {
fetchedNode[0].rangeTestConfig?.sender = Int32(config.rangeTest.sender)
fetchedNode[0].rangeTestConfig?.enabled = config.rangeTest.enabled
fetchedNode[0].rangeTestConfig?.save = config.rangeTest.save
}
do {
try context.save()
print("💾 Updated Range Test Config for node number: \(String(nodeNum))")
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Updating Core Data RangeTestConfigEntity: \(nsError)")
}
} else {
print("💥 No Nodes found in local database matching node number \(nodeNum) unable to save Range Test Module Config")
}
} catch {
let nsError = error as NSError
print("💥 Fetching node for core data RangeTestConfigEntity failed: \(nsError)")
}
}
if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.serial(config.serial) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.serial.config %@", comment: "Serial module config received: %@"), String(nodeNum))
MeshLogger.log("🤖 \(logString)")
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
do {
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
// Found a node, save Device Config
if !fetchedNode.isEmpty {
if fetchedNode[0].serialConfig == nil {
let newSerialConfig = SerialConfigEntity(context: context)
newSerialConfig.enabled = config.serial.enabled
newSerialConfig.echo = config.serial.echo
newSerialConfig.rxd = Int32(config.serial.rxd)
newSerialConfig.txd = Int32(config.serial.txd)
newSerialConfig.baudRate = Int32(config.serial.baud.rawValue)
newSerialConfig.timeout = Int32(config.serial.timeout)
newSerialConfig.mode = Int32(config.serial.mode.rawValue)
fetchedNode[0].serialConfig = newSerialConfig
} else {
fetchedNode[0].serialConfig?.enabled = config.serial.enabled
fetchedNode[0].serialConfig?.echo = config.serial.echo
fetchedNode[0].serialConfig?.rxd = Int32(config.serial.rxd)
fetchedNode[0].serialConfig?.txd = Int32(config.serial.txd)
fetchedNode[0].serialConfig?.baudRate = Int32(config.serial.baud.rawValue)
fetchedNode[0].serialConfig?.timeout = Int32(config.serial.timeout)
fetchedNode[0].serialConfig?.mode = Int32(config.serial.mode.rawValue)
}
do {
try context.save()
print("💾 Updated Serial Module Config for node number: \(String(nodeNum))")
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Updating Core Data SerialConfigEntity: \(nsError)")
}
} else {
print("💥 No Nodes found in local database matching node number \(nodeNum) unable to save Serial Module Config")
}
} catch {
let nsError = error as NSError
print("💥 Fetching node for core data SerialConfigEntity failed: \(nsError)")
}
}
if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.telemetry(config.telemetry) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.telemetry.config %@", comment: "Telemetry module config received: %@"), String(nodeNum))
MeshLogger.log("📈 \(logString)")
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
do {
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
// Found a node, save Telemetry Config
if !fetchedNode.isEmpty {
if fetchedNode[0].telemetryConfig == nil {
let newTelemetryConfig = TelemetryConfigEntity(context: context)
newTelemetryConfig.deviceUpdateInterval = Int32(config.telemetry.deviceUpdateInterval)
newTelemetryConfig.environmentUpdateInterval = Int32(config.telemetry.environmentUpdateInterval)
newTelemetryConfig.environmentMeasurementEnabled = config.telemetry.environmentMeasurementEnabled
newTelemetryConfig.environmentScreenEnabled = config.telemetry.environmentScreenEnabled
newTelemetryConfig.environmentDisplayFahrenheit = config.telemetry.environmentDisplayFahrenheit
fetchedNode[0].telemetryConfig = newTelemetryConfig
} else {
fetchedNode[0].telemetryConfig?.deviceUpdateInterval = Int32(config.telemetry.deviceUpdateInterval)
fetchedNode[0].telemetryConfig?.environmentUpdateInterval = Int32(config.telemetry.environmentUpdateInterval)
fetchedNode[0].telemetryConfig?.environmentMeasurementEnabled = config.telemetry.environmentMeasurementEnabled
fetchedNode[0].telemetryConfig?.environmentScreenEnabled = config.telemetry.environmentScreenEnabled
fetchedNode[0].telemetryConfig?.environmentDisplayFahrenheit = config.telemetry.environmentDisplayFahrenheit
}
do {
try context.save()
print("💾 Updated Telemetry Module Config for node number: \(String(nodeNum))")
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Updating Core Data TelemetryConfigEntity: \(nsError)")
}
} else {
print("💥 No Nodes found in local database matching node number \(nodeNum) unable to save Telemetry Module Config")
}
} catch {
let nsError = error as NSError
print("💥 Fetching node for core data TelemetryConfigEntity failed: \(nsError)")
}
upsertCannedMessagesModuleConfigPacket(config: config.cannedMessage, nodeNum: nodeNum, context: context)
} else if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.externalNotification(config.externalNotification) {
upsertExternalNotificationModuleConfigPacket(config: config.externalNotification, nodeNum: nodeNum, context: context)
} else if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.mqtt(config.mqtt) {
upsertMqttModuleConfigPacket(config: config.mqtt, nodeNum: nodeNum, context: context)
} else if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.rangeTest(config.rangeTest) {
upsertRangeTestModuleConfigPacket(config: config.rangeTest, nodeNum: nodeNum, context: context)
} else if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.serial(config.serial) {
upsertSerialModuleConfigPacket(config: config.serial, nodeNum: nodeNum, context: context)
} else if config.payloadVariant == ModuleConfig.OneOf_PayloadVariant.telemetry(config.telemetry) {
upsertTelemetryModuleConfigPacket(config: config.telemetry, nodeNum: nodeNum, context: context)
}
}
@ -759,8 +438,6 @@ func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) {
if let adminMessage = try? AdminMessage(serializedData: packet.decoded.payload) {
if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getCannedMessageModuleMessagesResponse(adminMessage.getCannedMessageModuleMessagesResponse) {
if let cmmc = try? CannedMessageModuleConfig(serializedData: packet.decoded.payload) {
@ -802,25 +479,49 @@ func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) {
deviceMetadataPacket(metadata: adminMessage.getDeviceMetadataResponse, fromNum: Int64(packet.from), context: context)
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getConfigResponse(adminMessage.getConfigResponse) {
if let config = try? Config(serializedData: packet.decoded.payload) {
let config = adminMessage.getConfigResponse
if config.payloadVariant == Config.OneOf_PayloadVariant.bluetooth(config.bluetooth) {
upsertBluetoothConfigPacket(config: config.bluetooth, nodeNum: Int64(packet.from), context: context)
} else if config.payloadVariant == Config.OneOf_PayloadVariant.device(config.device) {
upsertDeviceConfigPacket(config: config.device, nodeNum: Int64(packet.from), context: context)
} else if config.payloadVariant == Config.OneOf_PayloadVariant.lora(config.lora) {
upsertLoRaConfigPacket(config: config.lora, nodeNum: Int64(packet.from), context: context)
} else if config.payloadVariant == Config.OneOf_PayloadVariant.network(config.network) {
upsertNetworkConfigPacket(config: config.network, nodeNum: Int64(packet.from), context: context)
} else if config.payloadVariant == Config.OneOf_PayloadVariant.position(config.position) {
upsertPositionConfigPacket(config: config.position, nodeNum: Int64(packet.from), context: context)
if config.payloadVariant == Config.OneOf_PayloadVariant.bluetooth(config.bluetooth) {
upsertBluetoothConfigPacket(config: config, nodeNum: Int64(packet.from), context: context)
} else if config.payloadVariant == Config.OneOf_PayloadVariant.device(config.device) {
upsertDeviceConfigPacket(config: config, nodeNum: Int64(packet.from), context: context)
} else if config.payloadVariant == Config.OneOf_PayloadVariant.lora(config.lora) {
upsertLoRaConfigPacket(config: config, nodeNum: Int64(packet.from), context: context)
} else if config.payloadVariant == Config.OneOf_PayloadVariant.network(config.network) {
upsertNetworkConfigPacket(config: config, nodeNum: Int64(packet.from), context: context)
} else if config.payloadVariant == Config.OneOf_PayloadVariant.position(config.position) {
upsertPositionConfigPacket(config: config, nodeNum: Int64(packet.from), context: context)
}
}
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getModuleConfigResponse(adminMessage.getModuleConfigResponse) {
let moduleConfig = adminMessage.getModuleConfigResponse
if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.cannedMessage(moduleConfig.cannedMessage) {
upsertCannedMessagesModuleConfigPacket(config: moduleConfig.cannedMessage, nodeNum: Int64(packet.from), context: context)
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.externalNotification(moduleConfig.externalNotification) {
upsertExternalNotificationModuleConfigPacket(config: moduleConfig.externalNotification, nodeNum: Int64(packet.from), context: context)
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.mqtt(moduleConfig.mqtt) {
upsertMqttModuleConfigPacket(config: moduleConfig.mqtt, nodeNum: Int64(packet.from), context: context)
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.rangeTest(moduleConfig.rangeTest) {
upsertRangeTestModuleConfigPacket(config: moduleConfig.rangeTest, nodeNum: Int64(packet.from), context: context)
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.serial(moduleConfig.serial) {
upsertSerialModuleConfigPacket(config: moduleConfig.serial, nodeNum: Int64(packet.from), context: context)
} else if moduleConfig.payloadVariant == ModuleConfig.OneOf_PayloadVariant.telemetry(moduleConfig.telemetry) {
upsertTelemetryModuleConfigPacket(config: moduleConfig.telemetry, nodeNum: Int64(packet.from), context: context)
}
} else {
MeshLogger.log("🕸️ MESH PACKET received for Admin App \(try! packet.decoded.jsonString())")
}

View file

@ -7,6 +7,38 @@
import CoreData
public func getNodeInfo(id: Int64, context: NSManagedObjectContext) -> NodeInfoEntity {
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(id))
do {
let fetchNodeInfo = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
if fetchNodeInfo.count == 1 {
return fetchNodeInfo[0]
}
} catch {
return NodeInfoEntity(context: context)
}
return NodeInfoEntity(context: context)
}
public func getUser(id: Int64, context: NSManagedObjectContext) -> UserEntity {
let fetchUserRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "UserEntity")
fetchUserRequest.predicate = NSPredicate(format: "num == %lld", Int64(id))
do {
let fetchedUser = try context.fetch(fetchUserRequest) as! [UserEntity]
if fetchedUser.count == 1 {
return fetchedUser[0]
}
} catch {
return UserEntity(context: context)
}
return UserEntity(context: context)
}
public func getWaypoint(id: Int64, context: NSManagedObjectContext) -> WaypointEntity {
let fetchWaypointRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "WaypointEntity")

View file

@ -7,14 +7,14 @@
import CoreData
public func clearPositions(destNum: Int64, context: NSManagedObjectContext) -> Bool {
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(destNum))
do {
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
let newPostions = [PositionEntity]()
fetchedNode[0].positions? = NSOrderedSet(array: newPostions)
@ -26,7 +26,7 @@ public func clearPositions(destNum: Int64, context: NSManagedObjectContext) -> B
context.rollback()
return false
}
} catch {
print("💥 Fetch NodeInfoEntity Error")
return false
@ -37,11 +37,11 @@ public func clearTelemetry(destNum: Int64, metricsType: Int32, context: NSManage
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(destNum))
do {
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
let emptyTelemetry = [TelemetryEntity]()
fetchedNode[0].telemetries? = NSOrderedSet(array: emptyTelemetry)
@ -53,7 +53,7 @@ public func clearTelemetry(destNum: Int64, metricsType: Int32, context: NSManage
context.rollback()
return false
}
} catch {
print("💥 Fetch NodeInfoEntity Error")
return false
@ -63,9 +63,9 @@ public func clearTelemetry(destNum: Int64, metricsType: Int32, context: NSManage
public func deleteChannelMessages(channel: ChannelEntity, context: NSManagedObjectContext) {
do {
let objects = channel.allPrivateMessages
for object in objects {
context.delete(object)
}
for object in objects {
context.delete(object)
}
try context.save()
} catch let error as NSError {
print("Error: \(error.localizedDescription)")
@ -73,12 +73,12 @@ public func deleteChannelMessages(channel: ChannelEntity, context: NSManagedObje
}
public func deleteUserMessages(user: UserEntity, context: NSManagedObjectContext) {
do {
let objects = user.messageList
for object in objects {
context.delete(object)
}
for object in objects {
context.delete(object)
}
try context.save()
} catch let error as NSError {
print("Error: \(error.localizedDescription)")
@ -92,11 +92,11 @@ public func clearCoreDataDatabase(context: NSManagedObjectContext) {
let entity = persistenceController.managedObjectModel.entities[i]
let query = NSFetchRequest<NSFetchRequestResult>(entityName: entity.name!)
let deleteRequest = NSBatchDeleteRequest(fetchRequest: query)
do {
try context.executeAndMergeChanges(using: deleteRequest)
} catch let error as NSError {
print(error)
print(error)
}
}
}
@ -112,7 +112,7 @@ func upsertPositionPacket (packet: MeshPacket, context: NSManagedObjectContext)
do {
if let positionMessage = try? Position(serializedData: packet.decoded.payload) {
// Don't save empty position packets
if positionMessage.longitudeI > 0 || positionMessage.latitudeI > 0 && (positionMessage.latitudeI != 373346000 && positionMessage.longitudeI != -1220090000)
{
@ -159,7 +159,7 @@ func upsertPositionPacket (packet: MeshPacket, context: NSManagedObjectContext)
}
}
func upsertBluetoothConfigPacket(config: Config, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertBluetoothConfigPacket(config: Meshtastic.Config.BluetoothConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.bluetooth.config %@", comment: "Bluetooth config received: %@"), String(nodeNum))
MeshLogger.log("📶 \(logString)")
@ -174,14 +174,14 @@ func upsertBluetoothConfigPacket(config: Config, nodeNum: Int64, context: NSMana
if !fetchedNode.isEmpty {
if fetchedNode[0].bluetoothConfig == nil {
let newBluetoothConfig = BluetoothConfigEntity(context: context)
newBluetoothConfig.enabled = config.bluetooth.enabled
newBluetoothConfig.mode = Int32(config.bluetooth.mode.rawValue)
newBluetoothConfig.fixedPin = Int32(config.bluetooth.fixedPin)
newBluetoothConfig.enabled = config.enabled
newBluetoothConfig.mode = Int32(config.mode.rawValue)
newBluetoothConfig.fixedPin = Int32(config.fixedPin)
fetchedNode[0].bluetoothConfig = newBluetoothConfig
} else {
fetchedNode[0].bluetoothConfig?.enabled = config.bluetooth.enabled
fetchedNode[0].bluetoothConfig?.mode = Int32(config.bluetooth.mode.rawValue)
fetchedNode[0].bluetoothConfig?.fixedPin = Int32(config.bluetooth.fixedPin)
fetchedNode[0].bluetoothConfig?.enabled = config.enabled
fetchedNode[0].bluetoothConfig?.mode = Int32(config.mode.rawValue)
fetchedNode[0].bluetoothConfig?.fixedPin = Int32(config.fixedPin)
}
do {
try context.save()
@ -200,7 +200,7 @@ func upsertBluetoothConfigPacket(config: Config, nodeNum: Int64, context: NSMana
}
}
func upsertDeviceConfigPacket(config: Config, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertDeviceConfigPacket(config: Meshtastic.Config.DeviceConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.device.config %@", comment: "Device config received: %@"), String(nodeNum))
MeshLogger.log("📟 \(logString)")
@ -214,18 +214,18 @@ func upsertDeviceConfigPacket(config: Config, nodeNum: Int64, context: NSManaged
if !fetchedNode.isEmpty {
if fetchedNode[0].deviceConfig == nil {
let newDeviceConfig = DeviceConfigEntity(context: context)
newDeviceConfig.role = Int32(config.device.role.rawValue)
newDeviceConfig.serialEnabled = config.device.serialEnabled
newDeviceConfig.debugLogEnabled = config.device.debugLogEnabled
newDeviceConfig.buttonGpio = Int32(config.device.buttonGpio)
newDeviceConfig.buzzerGpio = Int32(config.device.buzzerGpio)
newDeviceConfig.role = Int32(config.role.rawValue)
newDeviceConfig.serialEnabled = config.serialEnabled
newDeviceConfig.debugLogEnabled = config.debugLogEnabled
newDeviceConfig.buttonGpio = Int32(config.buttonGpio)
newDeviceConfig.buzzerGpio = Int32(config.buzzerGpio)
fetchedNode[0].deviceConfig = newDeviceConfig
} else {
fetchedNode[0].deviceConfig?.role = Int32(config.device.role.rawValue)
fetchedNode[0].deviceConfig?.serialEnabled = config.device.serialEnabled
fetchedNode[0].deviceConfig?.debugLogEnabled = config.device.debugLogEnabled
fetchedNode[0].deviceConfig?.buttonGpio = Int32(config.device.buttonGpio)
fetchedNode[0].deviceConfig?.buzzerGpio = Int32(config.device.buzzerGpio)
fetchedNode[0].deviceConfig?.role = Int32(config.role.rawValue)
fetchedNode[0].deviceConfig?.serialEnabled = config.serialEnabled
fetchedNode[0].deviceConfig?.debugLogEnabled = config.debugLogEnabled
fetchedNode[0].deviceConfig?.buttonGpio = Int32(config.buttonGpio)
fetchedNode[0].deviceConfig?.buzzerGpio = Int32(config.buzzerGpio)
}
do {
try context.save()
@ -242,7 +242,7 @@ func upsertDeviceConfigPacket(config: Config, nodeNum: Int64, context: NSManaged
}
}
func upsertDisplayConfigPacket(config: Config, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertDisplayConfigPacket(config: Meshtastic.Config.DisplayConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.display.config %@", comment: "Display config received: %@"), String(nodeNum))
MeshLogger.log("🖥️ \(logString)")
@ -260,24 +260,24 @@ func upsertDisplayConfigPacket(config: Config, nodeNum: Int64, context: NSManage
if fetchedNode[0].displayConfig == nil {
let newDisplayConfig = DisplayConfigEntity(context: context)
newDisplayConfig.gpsFormat = Int32(config.display.gpsFormat.rawValue)
newDisplayConfig.screenOnSeconds = Int32(config.display.screenOnSecs)
newDisplayConfig.screenCarouselInterval = Int32(config.display.autoScreenCarouselSecs)
newDisplayConfig.compassNorthTop = config.display.compassNorthTop
newDisplayConfig.flipScreen = config.display.flipScreen
newDisplayConfig.oledType = Int32(config.display.oled.rawValue)
newDisplayConfig.displayMode = Int32(config.display.displaymode.rawValue)
newDisplayConfig.gpsFormat = Int32(config.gpsFormat.rawValue)
newDisplayConfig.screenOnSeconds = Int32(config.screenOnSecs)
newDisplayConfig.screenCarouselInterval = Int32(config.autoScreenCarouselSecs)
newDisplayConfig.compassNorthTop = config.compassNorthTop
newDisplayConfig.flipScreen = config.flipScreen
newDisplayConfig.oledType = Int32(config.oled.rawValue)
newDisplayConfig.displayMode = Int32(config.displaymode.rawValue)
fetchedNode[0].displayConfig = newDisplayConfig
} else {
fetchedNode[0].displayConfig?.gpsFormat = Int32(config.display.gpsFormat.rawValue)
fetchedNode[0].displayConfig?.screenOnSeconds = Int32(config.display.screenOnSecs)
fetchedNode[0].displayConfig?.screenCarouselInterval = Int32(config.display.autoScreenCarouselSecs)
fetchedNode[0].displayConfig?.compassNorthTop = config.display.compassNorthTop
fetchedNode[0].displayConfig?.flipScreen = config.display.flipScreen
fetchedNode[0].displayConfig?.oledType = Int32(config.display.oled.rawValue)
fetchedNode[0].displayConfig?.displayMode = Int32(config.display.displaymode.rawValue)
fetchedNode[0].displayConfig?.gpsFormat = Int32(config.gpsFormat.rawValue)
fetchedNode[0].displayConfig?.screenOnSeconds = Int32(config.screenOnSecs)
fetchedNode[0].displayConfig?.screenCarouselInterval = Int32(config.autoScreenCarouselSecs)
fetchedNode[0].displayConfig?.compassNorthTop = config.compassNorthTop
fetchedNode[0].displayConfig?.flipScreen = config.flipScreen
fetchedNode[0].displayConfig?.oledType = Int32(config.oled.rawValue)
fetchedNode[0].displayConfig?.displayMode = Int32(config.displaymode.rawValue)
}
do {
@ -304,7 +304,7 @@ func upsertDisplayConfigPacket(config: Config, nodeNum: Int64, context: NSManage
}
}
func upsertLoRaConfigPacket(config: Config, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertLoRaConfigPacket(config: Meshtastic.Config.LoRaConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.lora.config %@", comment: "LoRa config received: %@"), String(nodeNum))
MeshLogger.log("📻 \(logString)")
@ -320,33 +320,34 @@ func upsertLoRaConfigPacket(config: Config, nodeNum: Int64, context: NSManagedOb
if fetchedNode[0].loRaConfig == nil {
// No lora config for node, save a new lora config
let newLoRaConfig = LoRaConfigEntity(context: context)
newLoRaConfig.regionCode = Int32(config.lora.region.rawValue)
newLoRaConfig.usePreset = config.lora.usePreset
newLoRaConfig.modemPreset = Int32(config.lora.modemPreset.rawValue)
newLoRaConfig.bandwidth = Int32(config.lora.bandwidth)
newLoRaConfig.spreadFactor = Int32(config.lora.spreadFactor)
newLoRaConfig.codingRate = Int32(config.lora.codingRate)
newLoRaConfig.frequencyOffset = config.lora.frequencyOffset
newLoRaConfig.hopLimit = Int32(config.lora.hopLimit)
newLoRaConfig.txPower = Int32(config.lora.txPower)
newLoRaConfig.txEnabled = config.lora.txEnabled
newLoRaConfig.channelNum = Int32(config.lora.channelNum)
newLoRaConfig.regionCode = Int32(config.region.rawValue)
newLoRaConfig.usePreset = config.usePreset
newLoRaConfig.modemPreset = Int32(config.modemPreset.rawValue)
newLoRaConfig.bandwidth = Int32(config.bandwidth)
newLoRaConfig.spreadFactor = Int32(config.spreadFactor)
newLoRaConfig.codingRate = Int32(config.codingRate)
newLoRaConfig.frequencyOffset = config.frequencyOffset
newLoRaConfig.hopLimit = Int32(config.hopLimit)
newLoRaConfig.txPower = Int32(config.txPower)
newLoRaConfig.txEnabled = config.txEnabled
newLoRaConfig.channelNum = Int32(config.channelNum)
fetchedNode[0].loRaConfig = newLoRaConfig
} else {
fetchedNode[0].loRaConfig?.regionCode = Int32(config.lora.region.rawValue)
fetchedNode[0].loRaConfig?.usePreset = config.lora.usePreset
fetchedNode[0].loRaConfig?.modemPreset = Int32(config.lora.modemPreset.rawValue)
fetchedNode[0].loRaConfig?.bandwidth = Int32(config.lora.bandwidth)
fetchedNode[0].loRaConfig?.spreadFactor = Int32(config.lora.spreadFactor)
fetchedNode[0].loRaConfig?.codingRate = Int32(config.lora.codingRate)
fetchedNode[0].loRaConfig?.frequencyOffset = config.lora.frequencyOffset
fetchedNode[0].loRaConfig?.hopLimit = Int32(config.lora.hopLimit)
fetchedNode[0].loRaConfig?.txPower = Int32(config.lora.txPower)
fetchedNode[0].loRaConfig?.txEnabled = config.lora.txEnabled
fetchedNode[0].loRaConfig?.channelNum = Int32(config.lora.channelNum)
fetchedNode[0].loRaConfig?.regionCode = Int32(config.region.rawValue)
fetchedNode[0].loRaConfig?.usePreset = config.usePreset
fetchedNode[0].loRaConfig?.modemPreset = Int32(config.modemPreset.rawValue)
fetchedNode[0].loRaConfig?.bandwidth = Int32(config.bandwidth)
fetchedNode[0].loRaConfig?.spreadFactor = Int32(config.spreadFactor)
fetchedNode[0].loRaConfig?.codingRate = Int32(config.codingRate)
fetchedNode[0].loRaConfig?.frequencyOffset = config.frequencyOffset
fetchedNode[0].loRaConfig?.hopLimit = Int32(config.hopLimit)
fetchedNode[0].loRaConfig?.txPower = Int32(config.txPower)
fetchedNode[0].loRaConfig?.txEnabled = config.txEnabled
fetchedNode[0].loRaConfig?.channelNum = Int32(config.channelNum)
}
do {
try context.save()
context.refresh(fetchedNode[0], mergeChanges: true)
print("💾 Updated LoRa Config for node number: \(String(nodeNum))")
} catch {
context.rollback()
@ -362,7 +363,7 @@ func upsertLoRaConfigPacket(config: Config, nodeNum: Int64, context: NSManagedOb
}
}
func upsertNetworkConfigPacket(config: Config, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertNetworkConfigPacket(config: Meshtastic.Config.NetworkConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.network.config %@", comment: "Network config received: %@"), String(nodeNum))
MeshLogger.log("🌐 \(logString)")
@ -377,12 +378,16 @@ func upsertNetworkConfigPacket(config: Config, nodeNum: Int64, context: NSManage
if !fetchedNode.isEmpty {
if fetchedNode[0].networkConfig == nil {
let newNetworkConfig = NetworkConfigEntity(context: context)
newNetworkConfig.wifiSsid = config.network.wifiSsid
newNetworkConfig.wifiPsk = config.network.wifiPsk
newNetworkConfig.wifiEnabled = config.wifiEnabled
newNetworkConfig.wifiSsid = config.wifiSsid
newNetworkConfig.wifiPsk = config.wifiPsk
newNetworkConfig.ethEnabled = config.ethEnabled
fetchedNode[0].networkConfig = newNetworkConfig
} else {
fetchedNode[0].networkConfig?.wifiSsid = config.network.wifiSsid
fetchedNode[0].networkConfig?.wifiPsk = config.network.wifiPsk
fetchedNode[0].networkConfig?.ethEnabled = config.ethEnabled
fetchedNode[0].networkConfig?.wifiEnabled = config.wifiEnabled
fetchedNode[0].networkConfig?.wifiSsid = config.wifiSsid
fetchedNode[0].networkConfig?.wifiPsk = config.wifiPsk
}
do {
@ -403,7 +408,7 @@ func upsertNetworkConfigPacket(config: Config, nodeNum: Int64, context: NSManage
}
}
func upsertPositionConfigPacket(config: Config, nodeNum: Int64, context: NSManagedObjectContext) {
func upsertPositionConfigPacket(config: Meshtastic.Config.PositionConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.position.config %@", comment: "Positon config received: %@"), String(nodeNum))
MeshLogger.log("🗺️ \(logString)")
@ -418,22 +423,22 @@ func upsertPositionConfigPacket(config: Config, nodeNum: Int64, context: NSManag
if !fetchedNode.isEmpty {
if fetchedNode[0].positionConfig == nil {
let newPositionConfig = PositionConfigEntity(context: context)
newPositionConfig.smartPositionEnabled = config.position.positionBroadcastSmartEnabled
newPositionConfig.deviceGpsEnabled = config.position.gpsEnabled
newPositionConfig.fixedPosition = config.position.fixedPosition
newPositionConfig.gpsUpdateInterval = Int32(config.position.gpsUpdateInterval)
newPositionConfig.gpsAttemptTime = Int32(config.position.gpsAttemptTime)
newPositionConfig.positionBroadcastSeconds = Int32(config.position.positionBroadcastSecs)
newPositionConfig.positionFlags = Int32(config.position.positionFlags)
newPositionConfig.smartPositionEnabled = config.positionBroadcastSmartEnabled
newPositionConfig.deviceGpsEnabled = config.gpsEnabled
newPositionConfig.fixedPosition = config.fixedPosition
newPositionConfig.gpsUpdateInterval = Int32(config.gpsUpdateInterval)
newPositionConfig.gpsAttemptTime = Int32(config.gpsAttemptTime)
newPositionConfig.positionBroadcastSeconds = Int32(config.positionBroadcastSecs)
newPositionConfig.positionFlags = Int32(config.positionFlags)
fetchedNode[0].positionConfig = newPositionConfig
} else {
fetchedNode[0].positionConfig?.smartPositionEnabled = config.position.positionBroadcastSmartEnabled
fetchedNode[0].positionConfig?.deviceGpsEnabled = config.position.gpsEnabled
fetchedNode[0].positionConfig?.fixedPosition = config.position.fixedPosition
fetchedNode[0].positionConfig?.gpsUpdateInterval = Int32(config.position.gpsUpdateInterval)
fetchedNode[0].positionConfig?.gpsAttemptTime = Int32(config.position.gpsAttemptTime)
fetchedNode[0].positionConfig?.positionBroadcastSeconds = Int32(config.position.positionBroadcastSecs)
fetchedNode[0].positionConfig?.positionFlags = Int32(config.position.positionFlags)
fetchedNode[0].positionConfig?.smartPositionEnabled = config.positionBroadcastSmartEnabled
fetchedNode[0].positionConfig?.deviceGpsEnabled = config.gpsEnabled
fetchedNode[0].positionConfig?.fixedPosition = config.fixedPosition
fetchedNode[0].positionConfig?.gpsUpdateInterval = Int32(config.gpsUpdateInterval)
fetchedNode[0].positionConfig?.gpsAttemptTime = Int32(config.gpsAttemptTime)
fetchedNode[0].positionConfig?.positionBroadcastSeconds = Int32(config.positionBroadcastSecs)
fetchedNode[0].positionConfig?.positionFlags = Int32(config.positionFlags)
}
do {
try context.save()
@ -451,3 +456,337 @@ func upsertPositionConfigPacket(config: Config, nodeNum: Int64, context: NSManag
print("💥 Fetching node for core data PositionConfigEntity failed: \(nsError)")
}
}
func upsertCannedMessagesModuleConfigPacket(config: Meshtastic.ModuleConfig.CannedMessageConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.cannedmessage.config %@", comment: "Canned Message module config received: %@"), String(nodeNum))
MeshLogger.log("🥫 \(logString)")
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
do {
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
// Found a node, save Canned Message Config
if !fetchedNode.isEmpty {
if fetchedNode[0].cannedMessageConfig == nil {
let newCannedMessageConfig = CannedMessageConfigEntity(context: context)
newCannedMessageConfig.enabled = config.enabled
newCannedMessageConfig.sendBell = config.sendBell
newCannedMessageConfig.rotary1Enabled = config.rotary1Enabled
newCannedMessageConfig.updown1Enabled = config.updown1Enabled
newCannedMessageConfig.inputbrokerPinA = Int32(config.inputbrokerPinA)
newCannedMessageConfig.inputbrokerPinB = Int32(config.inputbrokerPinB)
newCannedMessageConfig.inputbrokerPinPress = Int32(config.inputbrokerPinPress)
newCannedMessageConfig.inputbrokerEventCw = Int32(config.inputbrokerEventCw.rawValue)
newCannedMessageConfig.inputbrokerEventCcw = Int32(config.inputbrokerEventCcw.rawValue)
newCannedMessageConfig.inputbrokerEventPress = Int32(config.inputbrokerEventPress.rawValue)
fetchedNode[0].cannedMessageConfig = newCannedMessageConfig
} else {
fetchedNode[0].cannedMessageConfig?.enabled = config.enabled
fetchedNode[0].cannedMessageConfig?.sendBell = config.sendBell
fetchedNode[0].cannedMessageConfig?.rotary1Enabled = config.rotary1Enabled
fetchedNode[0].cannedMessageConfig?.updown1Enabled = config.updown1Enabled
fetchedNode[0].cannedMessageConfig?.inputbrokerPinA = Int32(config.inputbrokerPinA)
fetchedNode[0].cannedMessageConfig?.inputbrokerPinB = Int32(config.inputbrokerPinB)
fetchedNode[0].cannedMessageConfig?.inputbrokerPinPress = Int32(config.inputbrokerPinPress)
fetchedNode[0].cannedMessageConfig?.inputbrokerEventCw = Int32(config.inputbrokerEventCw.rawValue)
fetchedNode[0].cannedMessageConfig?.inputbrokerEventCcw = Int32(config.inputbrokerEventCcw.rawValue)
fetchedNode[0].cannedMessageConfig?.inputbrokerEventPress = Int32(config.inputbrokerEventPress.rawValue)
}
do {
try context.save()
print("💾 Updated Canned Message Module Config for node number: \(String(nodeNum))")
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Updating Core Data CannedMessageConfigEntity: \(nsError)")
}
} else {
print("💥 No Nodes found in local database matching node number \(nodeNum) unable to save Canned Message Module Config")
}
} catch {
let nsError = error as NSError
print("💥 Fetching node for core data CannedMessageConfigEntity failed: \(nsError)")
}
}
func upsertExternalNotificationModuleConfigPacket(config: Meshtastic.ModuleConfig.ExternalNotificationConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.externalnotification.config %@", comment: "External Notifiation module config received: %@"), String(nodeNum))
MeshLogger.log("📣 \(logString)")
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
do {
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
// Found a node, save External Notificaitone Config
if !fetchedNode.isEmpty {
if fetchedNode[0].externalNotificationConfig == nil {
let newExternalNotificationConfig = ExternalNotificationConfigEntity(context: context)
newExternalNotificationConfig.enabled = config.enabled
newExternalNotificationConfig.usePWM = config.usePwm
newExternalNotificationConfig.alertBell = config.alertBell
newExternalNotificationConfig.alertBellBuzzer = config.alertBellBuzzer
newExternalNotificationConfig.alertBellVibra = config.alertBellVibra
newExternalNotificationConfig.alertMessage = config.alertMessage
newExternalNotificationConfig.alertMessageBuzzer = config.alertMessageBuzzer
newExternalNotificationConfig.alertMessageVibra = config.alertMessageVibra
newExternalNotificationConfig.active = config.active
newExternalNotificationConfig.output = Int32(config.output)
newExternalNotificationConfig.outputBuzzer = Int32(config.outputBuzzer)
newExternalNotificationConfig.outputVibra = Int32(config.outputVibra)
newExternalNotificationConfig.outputMilliseconds = Int32(config.outputMs)
newExternalNotificationConfig.nagTimeout = Int32(config.nagTimeout)
fetchedNode[0].externalNotificationConfig = newExternalNotificationConfig
} else {
fetchedNode[0].externalNotificationConfig?.enabled = config.enabled
fetchedNode[0].externalNotificationConfig?.usePWM = config.usePwm
fetchedNode[0].externalNotificationConfig?.alertBell = config.alertBell
fetchedNode[0].externalNotificationConfig?.alertBellBuzzer = config.alertBellBuzzer
fetchedNode[0].externalNotificationConfig?.alertBellVibra = config.alertBellVibra
fetchedNode[0].externalNotificationConfig?.alertMessage = config.alertMessage
fetchedNode[0].externalNotificationConfig?.alertMessageBuzzer = config.alertMessageBuzzer
fetchedNode[0].externalNotificationConfig?.alertMessageVibra = config.alertMessageVibra
fetchedNode[0].externalNotificationConfig?.active = config.active
fetchedNode[0].externalNotificationConfig?.output = Int32(config.output)
fetchedNode[0].externalNotificationConfig?.outputBuzzer = Int32(config.outputBuzzer)
fetchedNode[0].externalNotificationConfig?.outputVibra = Int32(config.outputVibra)
fetchedNode[0].externalNotificationConfig?.outputMilliseconds = Int32(config.outputMs)
fetchedNode[0].externalNotificationConfig?.nagTimeout = Int32(config.nagTimeout)
}
do {
try context.save()
print("💾 Updated External Notification Module Config for node number: \(String(nodeNum))")
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Updating Core Data ExternalNotificationConfigEntity: \(nsError)")
}
} else {
print("💥 No Nodes found in local database matching node number \(nodeNum) unable to save External Notifiation Module Config")
}
} catch {
let nsError = error as NSError
print("💥 Fetching node for core data ExternalNotificationConfigEntity failed: \(nsError)")
}
}
func upsertMqttModuleConfigPacket(config: Meshtastic.ModuleConfig.MQTTConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.mqtt.config %@", comment: "MQTT module config received: %@"), String(nodeNum))
MeshLogger.log("🌉 \(logString)")
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
do {
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
// Found a node, save MQTT Config
if !fetchedNode.isEmpty {
if fetchedNode[0].mqttConfig == nil {
let newMQTTConfig = MQTTConfigEntity(context: context)
newMQTTConfig.enabled = config.enabled
newMQTTConfig.address = config.address
newMQTTConfig.address = config.username
newMQTTConfig.password = config.password
newMQTTConfig.encryptionEnabled = config.encryptionEnabled
newMQTTConfig.jsonEnabled = config.jsonEnabled
fetchedNode[0].mqttConfig = newMQTTConfig
} else {
fetchedNode[0].mqttConfig?.enabled = config.enabled
fetchedNode[0].mqttConfig?.address = config.address
fetchedNode[0].mqttConfig?.address = config.username
fetchedNode[0].mqttConfig?.password = config.password
fetchedNode[0].mqttConfig?.encryptionEnabled = config.encryptionEnabled
fetchedNode[0].mqttConfig?.jsonEnabled = config.jsonEnabled
}
do {
try context.save()
print("💾 Updated MQTT Config for node number: \(String(nodeNum))")
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Updating Core Data MQTTConfigEntity: \(nsError)")
}
} else {
print("💥 No Nodes found in local database matching node number \(nodeNum) unable to save MQTT Module Config")
}
} catch {
let nsError = error as NSError
print("💥 Fetching node for core data MQTTConfigEntity failed: \(nsError)")
}
}
func upsertRangeTestModuleConfigPacket(config: Meshtastic.ModuleConfig.RangeTestConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.rangetest.config %@", comment: "Range Test module config received: %@"), String(nodeNum))
MeshLogger.log("⛰️ \(logString)")
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
do {
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
// Found a node, save Device Config
if !fetchedNode.isEmpty {
if fetchedNode[0].rangeTestConfig == nil {
let newRangeTestConfig = RangeTestConfigEntity(context: context)
newRangeTestConfig.sender = Int32(config.sender)
newRangeTestConfig.enabled = config.enabled
newRangeTestConfig.save = config.save
fetchedNode[0].rangeTestConfig = newRangeTestConfig
} else {
fetchedNode[0].rangeTestConfig?.sender = Int32(config.sender)
fetchedNode[0].rangeTestConfig?.enabled = config.enabled
fetchedNode[0].rangeTestConfig?.save = config.save
}
do {
try context.save()
print("💾 Updated Range Test Config for node number: \(String(nodeNum))")
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Updating Core Data RangeTestConfigEntity: \(nsError)")
}
} else {
print("💥 No Nodes found in local database matching node number \(nodeNum) unable to save Range Test Module Config")
}
} catch {
let nsError = error as NSError
print("💥 Fetching node for core data RangeTestConfigEntity failed: \(nsError)")
}
}
func upsertSerialModuleConfigPacket(config: Meshtastic.ModuleConfig.SerialConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.serial.config %@", comment: "Serial module config received: %@"), String(nodeNum))
MeshLogger.log("🤖 \(logString)")
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
do {
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
// Found a node, save Device Config
if !fetchedNode.isEmpty {
if fetchedNode[0].serialConfig == nil {
let newSerialConfig = SerialConfigEntity(context: context)
newSerialConfig.enabled = config.enabled
newSerialConfig.echo = config.echo
newSerialConfig.rxd = Int32(config.rxd)
newSerialConfig.txd = Int32(config.txd)
newSerialConfig.baudRate = Int32(config.baud.rawValue)
newSerialConfig.timeout = Int32(config.timeout)
newSerialConfig.mode = Int32(config.mode.rawValue)
fetchedNode[0].serialConfig = newSerialConfig
} else {
fetchedNode[0].serialConfig?.enabled = config.enabled
fetchedNode[0].serialConfig?.echo = config.echo
fetchedNode[0].serialConfig?.rxd = Int32(config.rxd)
fetchedNode[0].serialConfig?.txd = Int32(config.txd)
fetchedNode[0].serialConfig?.baudRate = Int32(config.baud.rawValue)
fetchedNode[0].serialConfig?.timeout = Int32(config.timeout)
fetchedNode[0].serialConfig?.mode = Int32(config.mode.rawValue)
}
do {
try context.save()
print("💾 Updated Serial Module Config for node number: \(String(nodeNum))")
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Updating Core Data SerialConfigEntity: \(nsError)")
}
} else {
print("💥 No Nodes found in local database matching node number \(nodeNum) unable to save Serial Module Config")
}
} catch {
let nsError = error as NSError
print("💥 Fetching node for core data SerialConfigEntity failed: \(nsError)")
}
}
func upsertTelemetryModuleConfigPacket(config: Meshtastic.ModuleConfig.TelemetryConfig, nodeNum: Int64, context: NSManagedObjectContext) {
let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.telemetry.config %@", comment: "Telemetry module config received: %@"), String(nodeNum))
MeshLogger.log("📈 \(logString)")
let fetchNodeInfoRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest.init(entityName: "NodeInfoEntity")
fetchNodeInfoRequest.predicate = NSPredicate(format: "num == %lld", Int64(nodeNum))
do {
let fetchedNode = try context.fetch(fetchNodeInfoRequest) as! [NodeInfoEntity]
// Found a node, save Telemetry Config
if !fetchedNode.isEmpty {
if fetchedNode[0].telemetryConfig == nil {
let newTelemetryConfig = TelemetryConfigEntity(context: context)
newTelemetryConfig.deviceUpdateInterval = Int32(config.deviceUpdateInterval)
newTelemetryConfig.environmentUpdateInterval = Int32(config.environmentUpdateInterval)
newTelemetryConfig.environmentMeasurementEnabled = config.environmentMeasurementEnabled
newTelemetryConfig.environmentScreenEnabled = config.environmentScreenEnabled
newTelemetryConfig.environmentDisplayFahrenheit = config.environmentDisplayFahrenheit
fetchedNode[0].telemetryConfig = newTelemetryConfig
} else {
fetchedNode[0].telemetryConfig?.deviceUpdateInterval = Int32(config.deviceUpdateInterval)
fetchedNode[0].telemetryConfig?.environmentUpdateInterval = Int32(config.environmentUpdateInterval)
fetchedNode[0].telemetryConfig?.environmentMeasurementEnabled = config.environmentMeasurementEnabled
fetchedNode[0].telemetryConfig?.environmentScreenEnabled = config.environmentScreenEnabled
fetchedNode[0].telemetryConfig?.environmentDisplayFahrenheit = config.environmentDisplayFahrenheit
}
do {
try context.save()
print("💾 Updated Telemetry Module Config for node number: \(String(nodeNum))")
} catch {
context.rollback()
let nsError = error as NSError
print("💥 Error Updating Core Data TelemetryConfigEntity: \(nsError)")
}
} else {
print("💥 No Nodes found in local database matching node number \(nodeNum) unable to save Telemetry Module Config")
}
} catch {
let nsError = error as NSError
print("💥 Fetching node for core data TelemetryConfigEntity failed: \(nsError)")
}
}

View file

@ -168,6 +168,10 @@ struct Config {
/// Defaults to PIN_BUZZER if defined.
var buzzerGpio: UInt32 = 0
///
/// Sets the role of node
var rebroadcastMode: Config.DeviceConfig.RebroadcastMode = .all
var unknownFields = SwiftProtobuf.UnknownStorage()
///
@ -198,13 +202,13 @@ struct Config {
///
/// Repeater device role
/// Mesh packets will simply be rebroadcasted over this node. Nodes under this role node will not originate NodeInfo, Position, Telemetry
/// or any other packet type. They will simply rebroadcast any mesh packets on the same frequency, channel num, spread factory, and coding rate.
/// Mesh packets will simply be rebroadcasted over this node. Nodes configured with this role will not originate NodeInfo, Position, Telemetry
/// or any other packet type. They will simply rebroadcast any mesh packets on the same frequency, channel num, spread factor, and coding rate.
case repeater // = 4
///
/// Tracker device role
/// Position Mesh packets for will be higher priority and sent more frequently by default.
/// Position Mesh packets will be prioritized higher and sent more frequently by default.
case tracker // = 5
case UNRECOGNIZED(Int)
@ -238,6 +242,51 @@ struct Config {
}
///
/// Defines the device's behavior for how messages are rebroadcast
enum RebroadcastMode: SwiftProtobuf.Enum {
typealias RawValue = Int
///
/// Default behavior.
/// Rebroadcast any observed message, if it was on our private channel or from another mesh with the same lora params.
case all // = 0
///
/// Same as behavior as ALL but skips packet decoding and simply rebroadcasts them.
/// Only available in Repeater role. Setting this on any other roles will result in ALL behavior.
case allSkipDecoding // = 1
///
/// Ignores observed messages from foreign meshes that are open or those which it cannot decrypt.
/// Only rebroadcasts message on the nodes local primary / secondary channels.
case localOnly // = 2
case UNRECOGNIZED(Int)
init() {
self = .all
}
init?(rawValue: Int) {
switch rawValue {
case 0: self = .all
case 1: self = .allSkipDecoding
case 2: self = .localOnly
default: self = .UNRECOGNIZED(rawValue)
}
}
var rawValue: Int {
switch self {
case .all: return 0
case .allSkipDecoding: return 1
case .localOnly: return 2
case .UNRECOGNIZED(let i): return i
}
}
}
init() {}
}
@ -905,6 +954,14 @@ struct Config {
/// If true, sets RX boosted gain mode on SX126X based radios
var sx126XRxBoostedGain: Bool = false
///
/// This parameter is for advanced users and licensed HAM radio operators.
/// Ignore Channel Calculation and use this frequency instead. The frequency_offset
/// will still be applied. This will allow you to use out-of-band frequencies.
/// Please respect your local laws and regulations. If you are a HAM, make sure you
/// enable HAM mode and turn off encryption.
var overrideFrequency: Float = 0
///
/// For testing it is useful sometimes to force a node to never listen to
/// particular other nodes (simulating radio out of range). All nodenums listed
@ -1186,6 +1243,15 @@ extension Config.DeviceConfig.Role: CaseIterable {
]
}
extension Config.DeviceConfig.RebroadcastMode: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Config.DeviceConfig.RebroadcastMode] = [
.all,
.allSkipDecoding,
.localOnly,
]
}
extension Config.PositionConfig.PositionFlags: CaseIterable {
// The compiler won't synthesize support with the UNRECOGNIZED case.
static var allCases: [Config.PositionConfig.PositionFlags] = [
@ -1303,6 +1369,7 @@ extension Config: @unchecked Sendable {}
extension Config.OneOf_PayloadVariant: @unchecked Sendable {}
extension Config.DeviceConfig: @unchecked Sendable {}
extension Config.DeviceConfig.Role: @unchecked Sendable {}
extension Config.DeviceConfig.RebroadcastMode: @unchecked Sendable {}
extension Config.PositionConfig: @unchecked Sendable {}
extension Config.PositionConfig.PositionFlags: @unchecked Sendable {}
extension Config.PowerConfig: @unchecked Sendable {}
@ -1491,6 +1558,7 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl
3: .standard(proto: "debug_log_enabled"),
4: .standard(proto: "button_gpio"),
5: .standard(proto: "buzzer_gpio"),
6: .standard(proto: "rebroadcast_mode"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
@ -1504,6 +1572,7 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl
case 3: try { try decoder.decodeSingularBoolField(value: &self.debugLogEnabled) }()
case 4: try { try decoder.decodeSingularUInt32Field(value: &self.buttonGpio) }()
case 5: try { try decoder.decodeSingularUInt32Field(value: &self.buzzerGpio) }()
case 6: try { try decoder.decodeSingularEnumField(value: &self.rebroadcastMode) }()
default: break
}
}
@ -1525,6 +1594,9 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl
if self.buzzerGpio != 0 {
try visitor.visitSingularUInt32Field(value: self.buzzerGpio, fieldNumber: 5)
}
if self.rebroadcastMode != .all {
try visitor.visitSingularEnumField(value: self.rebroadcastMode, fieldNumber: 6)
}
try unknownFields.traverse(visitor: &visitor)
}
@ -1534,6 +1606,7 @@ extension Config.DeviceConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImpl
if lhs.debugLogEnabled != rhs.debugLogEnabled {return false}
if lhs.buttonGpio != rhs.buttonGpio {return false}
if lhs.buzzerGpio != rhs.buzzerGpio {return false}
if lhs.rebroadcastMode != rhs.rebroadcastMode {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}
@ -1550,6 +1623,14 @@ extension Config.DeviceConfig.Role: SwiftProtobuf._ProtoNameProviding {
]
}
extension Config.DeviceConfig.RebroadcastMode: SwiftProtobuf._ProtoNameProviding {
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
0: .same(proto: "ALL"),
1: .same(proto: "ALL_SKIP_DECODING"),
2: .same(proto: "LOCAL_ONLY"),
]
}
extension Config.PositionConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
static let protoMessageName: String = Config.protoMessageName + ".PositionConfig"
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
@ -1987,6 +2068,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem
11: .standard(proto: "channel_num"),
12: .standard(proto: "override_duty_cycle"),
13: .standard(proto: "sx126x_rx_boosted_gain"),
14: .standard(proto: "override_frequency"),
103: .standard(proto: "ignore_incoming"),
]
@ -2009,6 +2091,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem
case 11: try { try decoder.decodeSingularUInt32Field(value: &self.channelNum) }()
case 12: try { try decoder.decodeSingularBoolField(value: &self.overrideDutyCycle) }()
case 13: try { try decoder.decodeSingularBoolField(value: &self.sx126XRxBoostedGain) }()
case 14: try { try decoder.decodeSingularFloatField(value: &self.overrideFrequency) }()
case 103: try { try decoder.decodeRepeatedUInt32Field(value: &self.ignoreIncoming) }()
default: break
}
@ -2055,6 +2138,9 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem
if self.sx126XRxBoostedGain != false {
try visitor.visitSingularBoolField(value: self.sx126XRxBoostedGain, fieldNumber: 13)
}
if self.overrideFrequency != 0 {
try visitor.visitSingularFloatField(value: self.overrideFrequency, fieldNumber: 14)
}
if !self.ignoreIncoming.isEmpty {
try visitor.visitPackedUInt32Field(value: self.ignoreIncoming, fieldNumber: 103)
}
@ -2075,6 +2161,7 @@ extension Config.LoRaConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplem
if lhs.channelNum != rhs.channelNum {return false}
if lhs.overrideDutyCycle != rhs.overrideDutyCycle {return false}
if lhs.sx126XRxBoostedGain != rhs.sx126XRxBoostedGain {return false}
if lhs.overrideFrequency != rhs.overrideFrequency {return false}
if lhs.ignoreIncoming != rhs.ignoreIncoming {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true

View file

@ -220,9 +220,34 @@ struct OEMStore {
/// The default device encryption key, 16 or 32 byte
var oemAesKey: Data = Data()
///
/// A Preset LocalConfig to apply during factory reset
var oemLocalConfig: LocalConfig {
get {return _oemLocalConfig ?? LocalConfig()}
set {_oemLocalConfig = newValue}
}
/// Returns true if `oemLocalConfig` has been explicitly set.
var hasOemLocalConfig: Bool {return self._oemLocalConfig != nil}
/// Clears the value of `oemLocalConfig`. Subsequent reads from it will return its default value.
mutating func clearOemLocalConfig() {self._oemLocalConfig = nil}
///
/// A Preset LocalModuleConfig to apply during factory reset
var oemLocalModuleConfig: LocalModuleConfig {
get {return _oemLocalModuleConfig ?? LocalModuleConfig()}
set {_oemLocalModuleConfig = newValue}
}
/// Returns true if `oemLocalModuleConfig` has been explicitly set.
var hasOemLocalModuleConfig: Bool {return self._oemLocalModuleConfig != nil}
/// Clears the value of `oemLocalModuleConfig`. Subsequent reads from it will return its default value.
mutating func clearOemLocalModuleConfig() {self._oemLocalModuleConfig = nil}
var unknownFields = SwiftProtobuf.UnknownStorage()
init() {}
fileprivate var _oemLocalConfig: LocalConfig? = nil
fileprivate var _oemLocalModuleConfig: LocalModuleConfig? = nil
}
#if swift(>=5.5) && canImport(_Concurrency)
@ -413,6 +438,8 @@ extension OEMStore: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
4: .standard(proto: "oem_font"),
5: .standard(proto: "oem_text"),
6: .standard(proto: "oem_aes_key"),
7: .standard(proto: "oem_local_config"),
8: .standard(proto: "oem_local_module_config"),
]
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
@ -427,12 +454,18 @@ extension OEMStore: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
case 4: try { try decoder.decodeSingularEnumField(value: &self.oemFont) }()
case 5: try { try decoder.decodeSingularStringField(value: &self.oemText) }()
case 6: try { try decoder.decodeSingularBytesField(value: &self.oemAesKey) }()
case 7: try { try decoder.decodeSingularMessageField(value: &self._oemLocalConfig) }()
case 8: try { try decoder.decodeSingularMessageField(value: &self._oemLocalModuleConfig) }()
default: break
}
}
}
func traverse<V: SwiftProtobuf.Visitor>(visitor: inout V) throws {
// The use of inline closures is to circumvent an issue where the compiler
// allocates stack space for every if/case branch local when no optimizations
// are enabled. https://github.com/apple/swift-protobuf/issues/1034 and
// https://github.com/apple/swift-protobuf/issues/1182
if self.oemIconWidth != 0 {
try visitor.visitSingularUInt32Field(value: self.oemIconWidth, fieldNumber: 1)
}
@ -451,6 +484,12 @@ extension OEMStore: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
if !self.oemAesKey.isEmpty {
try visitor.visitSingularBytesField(value: self.oemAesKey, fieldNumber: 6)
}
try { if let v = self._oemLocalConfig {
try visitor.visitSingularMessageField(value: v, fieldNumber: 7)
} }()
try { if let v = self._oemLocalModuleConfig {
try visitor.visitSingularMessageField(value: v, fieldNumber: 8)
} }()
try unknownFields.traverse(visitor: &visitor)
}
@ -461,6 +500,8 @@ extension OEMStore: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationB
if lhs.oemFont != rhs.oemFont {return false}
if lhs.oemText != rhs.oemText {return false}
if lhs.oemAesKey != rhs.oemAesKey {return false}
if lhs._oemLocalConfig != rhs._oemLocalConfig {return false}
if lhs._oemLocalModuleConfig != rhs._oemLocalModuleConfig {return false}
if lhs.unknownFields != rhs.unknownFields {return false}
return true
}

View file

@ -111,7 +111,7 @@ struct Connect: View {
if isUnsetRegion {
HStack {
NavigationLink {
LoRaConfig(node: node, connectedNode: node)
LoRaConfig(node: node)
} label: {
Label("set.region", systemImage: "globe.americas.fill")
.foregroundColor(.red)

View file

@ -15,7 +15,7 @@ struct NodeMap: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
@EnvironmentObject var userSettings: UserSettings
@AppStorage("meshMapType") var type: String = "hybrid"
@AppStorage("meshMapCustomTileServer") var customTileServer: String = "" {
didSet {
if customTileServer == "" {
@ -39,7 +39,7 @@ struct NodeMap: View {
), animation: .easeIn)
private var waypoints: FetchedResults<WaypointEntity>
@State private var mapType: MKMapType = .standard
@State private var mapType: MKMapType?
@State var waypointCoordinate: CLLocationCoordinate2D = LocationHelper.DefaultLocation
@State var editingWaypoint: Int = 0
@State private var presentingWaypointForm = false
@ -68,7 +68,9 @@ struct NodeMap: View {
editingWaypoint = wpId
presentingWaypointForm = true
}
}, positions: Array(positions), waypoints: Array(waypoints), mapViewType: mapType,
}, positions: Array(positions),
waypoints: Array(waypoints),
mapViewType: mapType ?? MKMapType.standard,
centerOnPositionsOnly: false,
customMapOverlay: self.customMapOverlay,
overlays: self.overlays

View file

@ -14,7 +14,6 @@ struct BluetoothConfig: View {
@Environment(\.dismiss) private var goBack
var node: NodeInfoEntity?
var connectedNode: NodeInfoEntity?
@State private var isPresentingSaveConfirm: Bool = false
@State var hasChanges = false
@ -80,7 +79,7 @@ struct BluetoothConfig: View {
}
}
}
.disabled(bleManager.connectedPeripheral == nil)
.disabled(self.bleManager.connectedPeripheral == nil || node?.bluetoothConfig == nil)
Button {
isPresentingSaveConfirm = true
@ -97,14 +96,15 @@ struct BluetoothConfig: View {
isPresented: $isPresentingSaveConfirm,
titleVisibility: .visible
) {
let nodeName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : NSLocalizedString("unknown", comment: "Unknown")
let nodeName = node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown")
let buttonText = String.localizedStringWithFormat(NSLocalizedString("save.config %@", comment: "Save Config for %@"), nodeName)
Button(buttonText) {
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
var bc = Config.BluetoothConfig()
bc.enabled = enabled
bc.mode = BluetoothModes(rawValue: mode)?.protoEnumValue() ?? Config.BluetoothConfig.PairingMode.randomPin
bc.fixedPin = UInt32(fixedPin) ?? 123456
let adminMessageId = bleManager.saveBluetoothConfig(config: bc, fromUser: node!.user!, toUser: node!.user!)
let adminMessageId = bleManager.saveBluetoothConfig(config: bc, 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
@ -127,15 +127,13 @@ struct BluetoothConfig: View {
self.fixedPin = String(node?.bluetoothConfig?.fixedPin ?? 123456)
self.hasChanges = false
// Need to request a LoRaConfig from the remote node before allowing changes
if node?.bluetoothConfig == nil {
print("empty bluetooth config")
}
// Need to request a BluetoothConfig from the remote node before allowing changes
if connectedNode != nil && node?.bluetoothConfig == nil {
_ = bleManager.requestBluetoothConfig(fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0)
if bleManager.connectedPeripheral != nil && node?.loRaConfig == nil {
print("empty bluetooth config")
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
if connectedNode.id > 0 {
_ = bleManager.requestBluetoothConfig(fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0)
}
}
}
.onChange(of: enabled) { newEnabled in

View file

@ -35,12 +35,14 @@ struct DeviceConfig: View {
Picker("Device Role", selection: $deviceRole ) {
ForEach(DeviceRoles.allCases) { dr in
Text(dr.description)
Text(dr.name)
}
}
.pickerStyle(DefaultPickerStyle())
.padding(.top, 10)
.padding(.bottom, 10)
Text(DeviceRoles(rawValue: deviceRole)?.description ?? "")
.foregroundColor(.gray)
.font(.caption)
}
Section(header: Text("Debug")) {
@ -83,7 +85,7 @@ struct DeviceConfig: View {
}
}
.disabled(bleManager.connectedPeripheral == nil)
.disabled(self.bleManager.connectedPeripheral == nil || node?.deviceConfig == nil)
HStack {
@ -138,11 +140,9 @@ struct DeviceConfig: View {
HStack {
Button {
isPresentingSaveConfirm = true
} label: {
Label("save", systemImage: "square.and.arrow.down")
}
.disabled(bleManager.connectedPeripheral == nil || !hasChanges)
@ -156,10 +156,10 @@ struct DeviceConfig: View {
isPresented: $isPresentingSaveConfirm,
titleVisibility: .visible
) {
let nodeName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : NSLocalizedString("unknown", comment: "Unknown")
let nodeName = node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown")
let buttonText = String.localizedStringWithFormat(NSLocalizedString("save.config %@", comment: "Save Config for %@"), nodeName)
Button(buttonText) {
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
var dc = Config.DeviceConfig()
dc.role = DeviceRoles(rawValue: deviceRole)!.protoEnumValue()
dc.serialEnabled = serialEnabled
@ -167,7 +167,7 @@ struct DeviceConfig: View {
dc.buttonGpio = UInt32(buttonGPIO)
dc.buzzerGpio = UInt32(buzzerGPIO)
let adminMessageId = bleManager.saveDeviceConfig(config: dc, fromUser: node!.user!, toUser: node!.user!)
let adminMessageId = bleManager.saveDeviceConfig(config: dc, 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
@ -195,6 +195,15 @@ struct DeviceConfig: View {
self.buttonGPIO = Int(node?.deviceConfig?.buttonGpio ?? 0)
self.buzzerGPIO = Int(node?.deviceConfig?.buzzerGpio ?? 0)
self.hasChanges = false
// Need to request a LoRaConfig from the remote node before allowing changes
if bleManager.connectedPeripheral != nil && node?.deviceConfig == nil {
print("empty device config")
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
if connectedNode.id > 0 {
_ = bleManager.requestDeviceConfig(fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0)
}
}
}
.onChange(of: deviceRole) { newRole in

View file

@ -97,7 +97,7 @@ struct DisplayConfig: View {
.listRowSeparator(.visible)
}
}
.disabled(bleManager.connectedPeripheral == nil)
.disabled(self.bleManager.connectedPeripheral == nil || node?.displayConfig == nil)
Button {
@ -116,9 +116,10 @@ struct DisplayConfig: View {
"are.you.sure",
isPresented: $isPresentingSaveConfirm
) {
let nodeName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : NSLocalizedString("unknown", comment: "Unknown")
let nodeName = node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown")
let buttonText = String.localizedStringWithFormat(NSLocalizedString("save.config %@", comment: "Save Config for %@"), nodeName)
Button(buttonText) {
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
var dc = Config.DisplayConfig()
dc.gpsFormat = GpsFormats(rawValue: gpsFormat)!.protoEnumValue()
dc.screenOnSecs = UInt32(screenOnSeconds)
@ -128,7 +129,7 @@ struct DisplayConfig: View {
dc.oled = OledTypes(rawValue: oledType)!.protoEnumValue()
dc.displaymode = DisplayModes(rawValue: displayMode)!.protoEnumValue()
let adminMessageId = bleManager.saveDisplayConfig(config: dc, fromUser: node!.user!, toUser: node!.user!)
let adminMessageId = bleManager.saveDisplayConfig(config: dc, fromUser: connectedNode.user!, toUser: node!.user!)
if adminMessageId > 0 {
// Should show a saved successfully alert once I know that to be true
@ -156,6 +157,15 @@ struct DisplayConfig: View {
self.oledType = Int(node?.displayConfig?.oledType ?? 0)
self.displayMode = Int(node?.displayConfig?.displayMode ?? 0)
self.hasChanges = false
// Need to request a LoRaConfig from the remote node before allowing changes
if bleManager.connectedPeripheral != nil && node?.displayConfig == nil {
print("empty display config")
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
if connectedNode.id > 0 {
_ = bleManager.requestDisplayConfig(fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0)
}
}
}
.onChange(of: screenOnSeconds) { newScreenSecs in
if node != nil && node!.displayConfig != nil {

View file

@ -14,7 +14,6 @@ struct LoRaConfig: View {
@Environment(\.dismiss) private var goBack
var node: NodeInfoEntity?
var connectedNode: NodeInfoEntity?
@State var isPresentingSaveConfirm = false
@State var hasChanges = false
@ -62,7 +61,7 @@ struct LoRaConfig: View {
.font(.caption)
}
}
.disabled(self.bleManager.connectedPeripheral == nil)
.disabled(self.bleManager.connectedPeripheral == nil || node?.loRaConfig == nil)
Button {
isPresentingSaveConfirm = true
} label: {
@ -81,13 +80,14 @@ struct LoRaConfig: View {
let nodeName = node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown")
let buttonText = String.localizedStringWithFormat(NSLocalizedString("save.config %@", comment: "Save Config for %@"), nodeName)
Button(buttonText) {
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
var lc = Config.LoRaConfig()
lc.hopLimit = UInt32(hopLimit)
lc.region = RegionCodes(rawValue: region)!.protoEnumValue()
lc.modemPreset = ModemPresets(rawValue: modemPreset)!.protoEnumValue()
lc.usePreset = true
lc.txEnabled = true
let adminMessageId = bleManager.saveLoRaConfig(config: lc, fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: node?.myInfo?.adminIndex ?? 0)
let adminMessageId = bleManager.saveLoRaConfig(config: lc, fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: node?.myInfo?.adminIndex ?? 0)
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
@ -116,9 +116,12 @@ struct LoRaConfig: View {
self.hasChanges = false
// Need to request a LoRaConfig from the remote node before allowing changes
if connectedNode != nil && node?.loRaConfig == nil {
if bleManager.connectedPeripheral != nil && node?.loRaConfig == nil {
print("empty lora config")
_ = bleManager.requestLoRaConfig(fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0)
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
if connectedNode.id > 0 {
_ = bleManager.requestLoRaConfig(fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0)
}
}
}
.onChange(of: region) { newRegion in

View file

@ -200,7 +200,7 @@ struct CannedMessagesConfig: View {
.disabled(configPreset > 0)
}
.scrollDismissesKeyboard(.immediately)
.disabled(bleManager.connectedPeripheral == nil)
.disabled(self.bleManager.connectedPeripheral == nil || node?.cannedMessageConfig == nil)
Button {
isPresentingSaveConfirm = true
@ -287,6 +287,15 @@ struct CannedMessagesConfig: View {
self.messages = node?.cannedMessageConfig?.messages ?? ""
self.hasChanges = false
self.hasMessagesChanges = false
// Need to request a CannedMessagesModuleConfig from the remote node before allowing changes
if bleManager.connectedPeripheral != nil && node?.cannedMessageConfig == nil {
print("empty canned messages module config")
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
if connectedNode.id > 0 {
_ = bleManager.requestCannedMessagesModuleConfig(fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0)
}
}
}
.onChange(of: configPreset) { newPreset in

View file

@ -138,7 +138,7 @@ struct ExternalNotificationConfig: View {
}
}
}
.disabled(bleManager.connectedPeripheral == nil)
.disabled(self.bleManager.connectedPeripheral == nil || node?.externalNotificationConfig == nil)
Button {
isPresentingSaveConfirm = true
} label: {
@ -154,7 +154,8 @@ struct ExternalNotificationConfig: View {
isPresented: $isPresentingSaveConfirm,
titleVisibility: .visible
) {
let nodeName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : NSLocalizedString("unknown", comment: "Unknown")
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
let nodeName = node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown")
let buttonText = String.localizedStringWithFormat(NSLocalizedString("save.config %@", comment: "Save Config for %@"), nodeName)
Button(buttonText) {
var enc = ModuleConfig.ExternalNotificationConfig()
@ -171,7 +172,7 @@ struct ExternalNotificationConfig: View {
enc.outputVibra = UInt32(outputVibra)
enc.outputMs = UInt32(outputMilliseconds)
enc.usePwm = usePWM
let adminMessageId = bleManager.saveExternalNotificationModuleConfig(config: enc, fromUser: node!.user!, toUser: node!.user!)
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
@ -205,6 +206,15 @@ struct ExternalNotificationConfig: View {
self.nagTimeout = Int(node?.externalNotificationConfig?.nagTimeout ?? 0)
self.usePWM = node?.externalNotificationConfig?.usePWM ?? false
self.hasChanges = false
// Need to request a TelemetryModuleConfig from the remote node before allowing changes
if bleManager.connectedPeripheral != nil && node?.externalNotificationConfig == nil {
print("empty external notification module config")
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
if connectedNode.id > 0 {
_ = bleManager.requestExternalNotificationModuleConfig(fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0)
}
}
}
.onChange(of: enabled) { newEnabled in
if node != nil && node!.externalNotificationConfig != nil {

View file

@ -126,7 +126,7 @@ struct MQTTConfig: View {
.font(.callout)
}
.scrollDismissesKeyboard(.interactively)
.disabled(!(node != nil))
.disabled(self.bleManager.connectedPeripheral == nil || node?.mqttConfig == nil)
Button {
isPresentingSaveConfirm = true
@ -143,7 +143,8 @@ struct MQTTConfig: View {
isPresented: $isPresentingSaveConfirm,
titleVisibility: .visible
) {
let nodeName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : NSLocalizedString("unknown", comment: "Unknown")
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
let nodeName = node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown")
let buttonText = String.localizedStringWithFormat(NSLocalizedString("save.config %@", comment: "Save Config for %@"), nodeName)
Button(buttonText) {
var mqtt = ModuleConfig.MQTTConfig()
@ -153,7 +154,7 @@ struct MQTTConfig: View {
mqtt.password = self.password
mqtt.encryptionEnabled = self.encryptionEnabled
mqtt.jsonEnabled = self.jsonEnabled
let adminMessageId = bleManager.saveMQTTConfig(config: mqtt, fromUser: node!.user!, toUser: node!.user!)
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
@ -179,6 +180,15 @@ struct MQTTConfig: View {
self.encryptionEnabled = (node?.mqttConfig?.encryptionEnabled ?? false)
self.jsonEnabled = (node?.mqttConfig?.jsonEnabled ?? false)
self.hasChanges = false
// Need to request a TelemetryModuleConfig from the remote node before allowing changes
if bleManager.connectedPeripheral != nil && node?.telemetryConfig == nil {
print("empty mqtt module config")
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
if connectedNode.id > 0 {
_ = bleManager.requestMqttModuleConfig(fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0)
}
}
}
.onChange(of: enabled) { newEnabled in
if node != nil && node?.mqttConfig != nil {

View file

@ -46,7 +46,7 @@ struct RangeTestConfig: View {
.font(.caption)
}
}
.disabled(!(node != nil && node!.myInfo?.hasWifi ?? false))
.disabled(self.bleManager.connectedPeripheral == nil || node?.positionConfig == nil || !(node != nil && node!.myInfo?.hasWifi ?? false))
Button {
isPresentingSaveConfirm = true
} label: {
@ -62,14 +62,16 @@ struct RangeTestConfig: View {
isPresented: $isPresentingSaveConfirm,
titleVisibility: .visible
) {
let nodeName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : NSLocalizedString("unknown", comment: "Unknown")
let nodeName = node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown")
let buttonText = String.localizedStringWithFormat(NSLocalizedString("save.config %@", comment: "Save Config for %@"), nodeName)
Button(buttonText) {
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
var rtc = ModuleConfig.RangeTestConfig()
rtc.enabled = enabled
rtc.save = save
rtc.sender = UInt32(sender)
let adminMessageId = bleManager.saveRangeTestModuleConfig(config: rtc, fromUser: node!.user!, toUser: node!.user!)
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
@ -92,6 +94,15 @@ struct RangeTestConfig: View {
self.save = node?.rangeTestConfig?.save ?? false
self.sender = Int(node?.rangeTestConfig?.sender ?? 0)
self.hasChanges = false
// Need to request a RangeTestModule Config from the remote node before allowing changes
if bleManager.connectedPeripheral != nil && node?.rangeTestConfig == nil {
print("empty range test module config")
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
if connectedNode.id > 0 {
_ = bleManager.requestRangeTestModuleConfig(fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0)
}
}
}
.onChange(of: enabled) { newEnabled in
if node != nil && node!.rangeTestConfig != nil {

View file

@ -97,7 +97,7 @@ struct SerialConfig: View {
.font(.caption)
}
}
.disabled(node == nil)
.disabled(self.bleManager.connectedPeripheral == nil || node?.serialConfig == nil)
Button {
@ -118,9 +118,10 @@ struct SerialConfig: View {
isPresented: $isPresentingSaveConfirm,
titleVisibility: .visible
) {
let nodeName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : NSLocalizedString("unknown", comment: "Unknown")
let nodeName = node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown")
let buttonText = String.localizedStringWithFormat(NSLocalizedString("save.config %@", comment: "Save Config for %@"), nodeName)
Button(buttonText) {
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
var sc = ModuleConfig.SerialConfig()
sc.enabled = enabled
sc.echo = echo
@ -130,7 +131,7 @@ struct SerialConfig: View {
sc.timeout = UInt32(timeout)
sc.mode = SerialModeTypes(rawValue: mode)!.protoEnumValue()
let adminMessageId = bleManager.saveSerialModuleConfig(config: sc, fromUser: node!.user!, toUser: node!.user!)
let adminMessageId = bleManager.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
@ -160,6 +161,15 @@ struct SerialConfig: View {
self.timeout = Int(node?.serialConfig?.timeout ?? 0)
self.mode = Int(node?.serialConfig?.mode ?? 0)
self.hasChanges = false
// Need to request a SerialModuleConfig from the remote node before allowing changes
if bleManager.connectedPeripheral != nil && node?.serialConfig == nil {
print("empty serial module config")
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
if connectedNode.id > 0 {
_ = bleManager.requestSerialModuleConfig(fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0)
}
}
}
.onChange(of: enabled) { newEnabled in

View file

@ -61,7 +61,7 @@ struct TelemetryConfig: View {
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
}
}
.disabled(bleManager.connectedPeripheral == nil)
.disabled(self.bleManager.connectedPeripheral == nil || node?.positionConfig == nil)
Button {
isPresentingSaveConfirm = true
} label: {
@ -77,7 +77,8 @@ struct TelemetryConfig: View {
isPresented: $isPresentingSaveConfirm,
titleVisibility: .visible
) {
let nodeName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : NSLocalizedString("unknown", comment: "Unknown")
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
let nodeName = node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown")
let buttonText = String.localizedStringWithFormat(NSLocalizedString("save.config %@", comment: "Save Config for %@"), nodeName)
Button(buttonText) {
var tc = ModuleConfig.TelemetryConfig()
@ -86,7 +87,7 @@ struct TelemetryConfig: View {
tc.environmentMeasurementEnabled = environmentMeasurementEnabled
tc.environmentScreenEnabled = environmentScreenEnabled
tc.environmentDisplayFahrenheit = environmentDisplayFahrenheit
let adminMessageId = bleManager.saveTelemetryModuleConfig(config: tc, fromUser: node!.user!, toUser: node!.user!)
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
@ -111,6 +112,15 @@ struct TelemetryConfig: View {
self.environmentScreenEnabled = node?.telemetryConfig?.environmentScreenEnabled ?? false
self.environmentDisplayFahrenheit = node?.telemetryConfig?.environmentDisplayFahrenheit ?? false
self.hasChanges = false
// Need to request a TelemetryModuleConfig from the remote node before allowing changes
if bleManager.connectedPeripheral != nil && node?.telemetryConfig == nil {
print("empty telemetry module config")
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
if connectedNode.id > 0 {
_ = bleManager.requestTelemetryModuleConfig(fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0)
}
}
}
.onChange(of: deviceUpdateInterval) { newDeviceInterval in
if node != nil && node!.telemetryConfig != nil {

View file

@ -25,7 +25,6 @@ struct NetworkConfig: View {
@State var ethEnabled = false
@State var ethMode = 0
var body: some View {
VStack {
@ -92,7 +91,7 @@ struct NetworkConfig: View {
}
}
.scrollDismissesKeyboard(.interactively)
.disabled(!(node != nil))
.disabled(self.bleManager.connectedPeripheral == nil || node?.networkConfig == nil)
Button {
isPresentingSaveConfirm = true
} label: {
@ -108,9 +107,10 @@ struct NetworkConfig: View {
isPresented: $isPresentingSaveConfirm,
titleVisibility: .visible
) {
let nodeName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : NSLocalizedString("unknown", comment: "Unknown")
let nodeName = node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown")
let buttonText = String.localizedStringWithFormat(NSLocalizedString("save.config %@", comment: "Save Config for %@"), nodeName)
Button(buttonText) {
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
var network = Config.NetworkConfig()
network.wifiEnabled = self.wifiEnabled
network.wifiSsid = self.wifiSsid
@ -118,7 +118,7 @@ struct NetworkConfig: View {
network.ethEnabled = self.ethEnabled
//network.addressMode = Config.NetworkConfig.AddressMode.dhcp
let adminMessageId = bleManager.saveNetworkConfig(config: network, fromUser: node!.user!, toUser: node!.user!)
let adminMessageId = bleManager.saveNetworkConfig(config: network, 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
@ -143,6 +143,15 @@ struct NetworkConfig: View {
self.wifiMode = Int(node?.networkConfig?.wifiMode ?? 0)
self.ethEnabled = node?.networkConfig?.ethEnabled ?? false
self.hasChanges = false
// Need to request a NetworkConfig from the remote node before allowing changes
if bleManager.connectedPeripheral != nil && node?.positionConfig == nil {
print("empty network config")
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
if connectedNode.id > 0 {
_ = bleManager.requestNetworkConfig(fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0)
}
}
}
.onChange(of: wifiEnabled) { newEnabled in
if node != nil && node!.networkConfig != nil {

View file

@ -185,14 +185,11 @@ struct PositionConfig: View {
}
}
}
.disabled(bleManager.connectedPeripheral == nil)
.disabled(self.bleManager.connectedPeripheral == nil || node?.positionConfig == nil)
Button {
isPresentingSaveConfirm = true
} label: {
Label("save", systemImage: "square.and.arrow.down")
}
.disabled(bleManager.connectedPeripheral == nil || !hasChanges)
@ -205,14 +202,14 @@ struct PositionConfig: View {
isPresented: $isPresentingSaveConfirm,
titleVisibility: .visible
) {
let nodeName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : NSLocalizedString("unknown", comment: "Unknown")
let nodeName = node?.user?.longName ?? NSLocalizedString("unknown", comment: "Unknown")
let buttonText = String.localizedStringWithFormat(NSLocalizedString("save.config %@", comment: "Save Config for %@"), nodeName)
Button(buttonText) {
if fixedPosition {
_ = bleManager.sendPosition(destNum: bleManager.connectedPeripheral.num, wantResponse: false)
}
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
var pc = Config.PositionConfig()
pc.positionBroadcastSmartEnabled = smartPositionEnabled
pc.gpsEnabled = deviceGpsEnabled
@ -232,7 +229,7 @@ struct PositionConfig: View {
if includeSpeed { pf.insert(.Speed) }
if includeHeading { pf.insert(.Heading) }
pc.positionFlags = UInt32(pf.rawValue)
let adminMessageId = bleManager.savePositionConfig(config: pc, fromUser: node!.user!, toUser: node!.user!)
let adminMessageId = bleManager.savePositionConfig(config: pc, 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
@ -278,6 +275,14 @@ struct PositionConfig: View {
self.hasChanges = false
// Need to request a PositionConfig from the remote node before allowing changes
if bleManager.connectedPeripheral != nil && node?.positionConfig == nil {
print("empty position config")
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
if connectedNode.id > 0 {
_ = bleManager.requestPositionConfig(fromUser: connectedNode.user!, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0)
}
}
}
.onChange(of: deviceGpsEnabled) { newDeviceGps in
if node != nil && node!.positionConfig != nil {

View file

@ -106,7 +106,7 @@ struct Settings: View {
.disabled(selectedNode > 0 && selectedNode != connectedNodeNum)
NavigationLink {
UserConfig(node: nodes.first(where: { $0.num == selectedNode }), connectedNode: nodes.first(where: { $0.num == connectedNodeNum }))
UserConfig(node: nodes.first(where: { $0.num == selectedNode }))
} label: {
Image(systemName: "person.crop.rectangle.fill")
@ -116,14 +116,13 @@ struct Settings: View {
.tag(SettingsSidebar.userConfig)
NavigationLink() {
LoRaConfig(node: nodes.first(where: { $0.num == selectedNode }), connectedNode: nodes.first(where: { $0.num == connectedNodeNum }))
LoRaConfig(node: nodes.first(where: { $0.num == selectedNode }))
} label: {
Image(systemName: "dot.radiowaves.left.and.right")
.symbolRenderingMode(.hierarchical)
Text("lora")
}
.tag(SettingsSidebar.loraConfig)
.disabled(selectedNode > 0 && selectedNode != connectedNodeNum)
NavigationLink() {
Channels(node: nodes.first(where: { $0.num == connectedNodeNum }))
@ -136,14 +135,13 @@ struct Settings: View {
.disabled(selectedNode > 0 && selectedNode != connectedNodeNum)
NavigationLink() {
BluetoothConfig(node: nodes.first(where: { $0.num == selectedNode }), connectedNode: nodes.first(where: { $0.num == connectedNodeNum }))
BluetoothConfig(node: nodes.first(where: { $0.num == selectedNode }))
} label: {
Image(systemName: "antenna.radiowaves.left.and.right")
.symbolRenderingMode(.hierarchical)
Text("bluetooth")
}
.tag(SettingsSidebar.bluetoothConfig)
.disabled(selectedNode > 0 && selectedNode != connectedNodeNum)
NavigationLink {
DeviceConfig(node: nodes.first(where: { $0.num == selectedNode }))
@ -153,7 +151,6 @@ struct Settings: View {
Text("device")
}
.tag(SettingsSidebar.deviceConfig)
.disabled(selectedNode > 0 && selectedNode != connectedNodeNum)
NavigationLink {
DisplayConfig(node: nodes.first(where: { $0.num == selectedNode }))
@ -163,7 +160,6 @@ struct Settings: View {
Text("display")
}
.tag(SettingsSidebar.displayConfig)
.disabled(selectedNode > 0 && selectedNode != connectedNodeNum)
NavigationLink {
NetworkConfig(node: nodes.first(where: { $0.num == selectedNode }))
@ -174,7 +170,6 @@ struct Settings: View {
Text("network")
}
.tag(SettingsSidebar.networkConfig)
.disabled(selectedNode > 0 && selectedNode != connectedNodeNum)
NavigationLink {
PositionConfig(node: nodes.first(where: { $0.num == selectedNode }))
@ -185,7 +180,6 @@ struct Settings: View {
Text("position")
}
.tag(SettingsSidebar.positionConfig)
.disabled(selectedNode > 0 && selectedNode != connectedNodeNum)
}
Section("module.configuration") {
@ -200,7 +194,6 @@ struct Settings: View {
Text("canned.messages")
}
.tag(SettingsSidebar.cannedMessagesConfig)
.disabled(selectedNode > 0 && selectedNode != connectedNodeNum)
NavigationLink {
ExternalNotificationConfig(node: nodes.first(where: { $0.num == selectedNode }))
@ -210,7 +203,6 @@ struct Settings: View {
Text("external.notification")
}
.tag(SettingsSidebar.externalNotificationConfig)
.disabled(selectedNode > 0 && selectedNode != connectedNodeNum)
NavigationLink {
MQTTConfig(node: nodes.first(where: { $0.num == selectedNode }))
@ -220,7 +212,6 @@ struct Settings: View {
Text("mqtt")
}
.tag(SettingsSidebar.mqttConfig)
.disabled(selectedNode > 0 && selectedNode != connectedNodeNum)
NavigationLink {
RangeTestConfig(node: nodes.first(where: { $0.num == selectedNode }))
@ -230,7 +221,6 @@ struct Settings: View {
Text("range.test")
}
.tag(SettingsSidebar.rangeTestConfig)
.disabled(selectedNode > 0 && selectedNode != connectedNodeNum)
NavigationLink {
SerialConfig(node: nodes.first(where: { $0.num == selectedNode }))
@ -240,7 +230,6 @@ struct Settings: View {
Text("serial")
}
.tag(SettingsSidebar.serialConfig)
.disabled(selectedNode > 0 && selectedNode != connectedNodeNum)
NavigationLink {
TelemetryConfig(node: nodes.first(where: { $0.num == selectedNode }))
@ -250,7 +239,6 @@ struct Settings: View {
Text("telemetry")
}
.tag(SettingsSidebar.telemetryConfig)
.disabled(selectedNode > 0 && selectedNode != connectedNodeNum)
}
Section(header: Text("logging")) {
NavigationLink {

View file

@ -13,7 +13,6 @@ struct UserConfig: View {
@Environment(\.dismiss) private var goBack
var node: NodeInfoEntity?
var connectedNode: NodeInfoEntity?
@State private var isPresentingFactoryResetConfirm: Bool = false
@State private var isPresentingSaveConfirm: Bool = false
@ -86,10 +85,13 @@ struct UserConfig: View {
titleVisibility: .visible
) {
Button("Save User Config to \(node?.user?.longName ?? "Unknown")?") {
let connectedUser = getUser(id: bleManager.connectedPeripheral.num, context: context)
let connectedNode = getNodeInfo(id: bleManager.connectedPeripheral.num, context: context)
var u = User()
u.shortName = shortName
u.longName = longName
let adminMessageId = bleManager.saveUser(config: u, fromUser: connectedNode!.user!, toUser: node!.user!, adminIndex: connectedNode?.myInfo?.adminIndex ?? 0)
let adminMessageId = bleManager.saveUser(config: u, fromUser: connectedUser, toUser: node!.user!, adminIndex: connectedNode.myInfo?.adminIndex ?? 0)
if adminMessageId > 0 {
hasChanges = false
goBack()