diff --git a/Meshtastic/API/MeshtasticAPI.swift b/Meshtastic/API/MeshtasticAPI.swift index 4f1508e4d..8d93f8b9e 100644 --- a/Meshtastic/API/MeshtasticAPI.swift +++ b/Meshtastic/API/MeshtasticAPI.swift @@ -45,6 +45,7 @@ private struct DeviceHardware: Codable { let hasInkHud: Bool? let partitionScheme: String? let hasMui: Bool? + let hasPaFan: Bool? let key: String? let variant: String? } @@ -243,6 +244,7 @@ class MeshtasticAPI: ObservableObject, @unchecked Sendable { deviceEntity.hasInkHud = device.hasInkHud ?? false deviceEntity.partitionScheme = device.partitionScheme deviceEntity.hasMui = device.hasMui ?? false + deviceEntity.hasPaFan = device.hasPaFan ?? false deviceEntity.key = device.key deviceEntity.variant = device.variant diff --git a/Meshtastic/Model/ConfigModels.swift b/Meshtastic/Model/ConfigModels.swift index e9f4ca629..fb9a9fbf2 100644 --- a/Meshtastic/Model/ConfigModels.swift +++ b/Meshtastic/Model/ConfigModels.swift @@ -150,6 +150,7 @@ final class LoRaConfigEntity { var okToMqtt: Bool = false var overrideDutyCycle: Bool = false var overrideFrequency: Float = 0.0 + var paFanDisabled: Bool = false var regionCode: Int32 = 0 var spreadFactor: Int32 = 0 var sx126xRxBoostedGain: Bool = false diff --git a/Meshtastic/Model/DeviceHardwareEntity.swift b/Meshtastic/Model/DeviceHardwareEntity.swift index 679414368..831f38beb 100644 --- a/Meshtastic/Model/DeviceHardwareEntity.swift +++ b/Meshtastic/Model/DeviceHardwareEntity.swift @@ -15,6 +15,7 @@ final class DeviceHardwareEntity { var displayName: String? var hasInkHud: Bool = false var hasMui: Bool = false + var hasPaFan: Bool = false @Attribute(.unique) var hwModel: Int64 = 0 var hwModelSlug: String? var key: String? diff --git a/Meshtastic/Persistence/UpdateSwiftData.swift b/Meshtastic/Persistence/UpdateSwiftData.swift index 288633ecf..229e44c24 100644 --- a/Meshtastic/Persistence/UpdateSwiftData.swift +++ b/Meshtastic/Persistence/UpdateSwiftData.swift @@ -802,6 +802,7 @@ extension MeshPackets { newLoRaConfig.sx126xRxBoostedGain = config.sx126XRxBoostedGain newLoRaConfig.ignoreMqtt = config.ignoreMqtt newLoRaConfig.okToMqtt = config.configOkToMqtt + newLoRaConfig.paFanDisabled = config.paFanDisabled fetchedNode[0].loRaConfig = newLoRaConfig } else { fetchedNode[0].loRaConfig?.regionCode = Int32(config.region.rawValue) @@ -820,7 +821,7 @@ extension MeshPackets { fetchedNode[0].loRaConfig?.sx126xRxBoostedGain = config.sx126XRxBoostedGain fetchedNode[0].loRaConfig?.ignoreMqtt = config.ignoreMqtt fetchedNode[0].loRaConfig?.okToMqtt = config.configOkToMqtt - fetchedNode[0].loRaConfig?.sx126xRxBoostedGain = config.sx126XRxBoostedGain + fetchedNode[0].loRaConfig?.paFanDisabled = config.paFanDisabled } if sessionPasskey != nil { fetchedNode[0].sessionPasskey = sessionPasskey diff --git a/Meshtastic/Resources/DeviceHardware.json b/Meshtastic/Resources/DeviceHardware.json index e701bbc43..a84f65c12 100644 --- a/Meshtastic/Resources/DeviceHardware.json +++ b/Meshtastic/Resources/DeviceHardware.json @@ -49,7 +49,8 @@ ], "images": [ "tbeam.svg" - ] + ], + "hasPaFan": true }, { "hwModel": 5, @@ -155,7 +156,8 @@ "tbeam-s3-core.svg" ], "requiresDfu": true, - "partitionScheme": "8MB" + "partitionScheme": "8MB", + "hasPaFan": true }, { "hwModel": 13, @@ -346,7 +348,8 @@ "images": [ "station-g2.svg" ], - "partitionScheme": "16MB" + "partitionScheme": "16MB", + "hasPaFan": true }, { "hwModel": 33, @@ -1364,7 +1367,8 @@ "partitionScheme": "8MB", "images": [ "tbeam-1w.svg" - ] + ], + "hasPaFan": true }, { "hwModel": 123, diff --git a/Meshtastic/Views/Settings/Config/LoRaConfig.swift b/Meshtastic/Views/Settings/Config/LoRaConfig.swift index dd50efed8..d60fb4398 100644 --- a/Meshtastic/Views/Settings/Config/LoRaConfig.swift +++ b/Meshtastic/Views/Settings/Config/LoRaConfig.swift @@ -6,7 +6,7 @@ // import SwiftUI -import SwiftData +@preconcurrency import SwiftData import MeshtasticProtobufs import OSLog @@ -46,6 +46,13 @@ struct LoRaConfig: View { @State var overrideFrequency: Float = 0.0 @State var ignoreMqtt = false @State var okToMqtt = false + @State var paFanDisabled = false + + @Query private var hardwareResults: [DeviceHardwareEntity] + + private var hasPaFan: Bool { + hardwareResults.first?.hasPaFan ?? false + } let floatFormatter: NumberFormatter = { let formatter = NumberFormatter() @@ -55,6 +62,14 @@ struct LoRaConfig: View { return formatter }() + init(node: NodeInfoEntity?) { + self.node = node + let hwModel = Int64(node?.user?.hwModelId ?? 0) + _hardwareResults = Query(filter: #Predicate { hw in + hw.hwModel == hwModel + }) + } + var body: some View { Form { ConfigHeader(title: "LoRa", config: \.loRaConfig, node: node, onAppear: setLoRaValues) @@ -180,6 +195,12 @@ struct LoRaConfig: View { Stepper(txPower == 0 ? "Max Transmit Power" : "\(txPower)dBm Transmit Power", value: $txPower, in: 0...30, step: 1) .padding(5) } + if hasPaFan { + Toggle(isOn: $paFanDisabled) { + Label("PA Fan Disabled", systemImage: "fan.slash") + } + .tint(.accentColor) + } } } .scrollDismissesKeyboard(.immediately) @@ -209,6 +230,7 @@ struct LoRaConfig: View { lc.overrideFrequency = overrideFrequency lc.ignoreMqtt = ignoreMqtt lc.configOkToMqtt = okToMqtt + lc.paFanDisabled = paFanDisabled if let deviceNum = accessoryManager.activeDeviceNum, let connectedNode = getNodeInfo(id: deviceNum, context: context), connectedNode.num == node?.user?.num ?? 0 { @@ -276,6 +298,9 @@ struct LoRaConfig: View { .onChange(of: okToMqtt) { _, newOkToMqtt in if newOkToMqtt != node?.loRaConfig?.okToMqtt { hasChanges = true } } + .onChange(of: paFanDisabled) { _, newPaFanDisabled in + if newPaFanDisabled != node?.loRaConfig?.paFanDisabled { hasChanges = true } + } } func setLoRaValues() { if node?.loRaConfig?.modemPreset ?? 0 == 2 { @@ -296,6 +321,7 @@ struct LoRaConfig: View { self.overrideFrequency = node?.loRaConfig?.overrideFrequency ?? 0.0 self.ignoreMqtt = node?.loRaConfig?.ignoreMqtt ?? false self.okToMqtt = node?.loRaConfig?.okToMqtt ?? false + self.paFanDisabled = node?.loRaConfig?.paFanDisabled ?? false self.hasChanges = false } } diff --git a/docs/user/settings.md b/docs/user/settings.md index 54d639809..dfe4a46b6 100644 --- a/docs/user/settings.md +++ b/docs/user/settings.md @@ -32,6 +32,7 @@ LoRa settings control how your radio communicates on the mesh: | Modem Preset | Speed/range trade-off. Most users should use Long Fast or Long Slow. | | Hop Limit | The number of times a message is repeated by other nodes. Higher values increase range but also mesh traffic. | | Frequency Slot | Fine-tune the exact frequency within your region. | +| PA Fan Disabled | Disable the built-in PA cooling fan on supported hardware (e.g. T-Beam Supreme). Only shown when the connected device has a PA fan. | ### Channels