diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index 37a37ae1..479f6dce 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -70,8 +70,6 @@ DDC3B274283F411B00AC321C /* LastHeardText.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC3B273283F411B00AC321C /* LastHeardText.swift */; }; DDC4D568275499A500A4208E /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDC4D567275499A500A4208E /* Persistence.swift */; }; DDCE4E2C2869F92900BE9F8F /* UserConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDCE4E2B2869F92900BE9F8F /* UserConfig.swift */; }; - DDCE4E2E286B7BC400BE9F8F /* StoreForwaredConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDCE4E2D286B7BC400BE9F8F /* StoreForwaredConfig.swift */; }; - DDCE4E30286B7BD800BE9F8F /* InputBrokerConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDCE4E2F286B7BD800BE9F8F /* InputBrokerConfig.swift */; }; DDCFF601285453A7005FA625 /* localonly.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDCFF600285453A7005FA625 /* localonly.pb.swift */; }; DDD94A502845C8F5004A87A0 /* DateTimeText.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD94A4F2845C8F5004A87A0 /* DateTimeText.swift */; }; DDD9E4E4284B208E003777C5 /* UserEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDD9E4E3284B208E003777C5 /* UserEntityExtension.swift */; }; @@ -167,8 +165,6 @@ DDC3B273283F411B00AC321C /* LastHeardText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LastHeardText.swift; sourceTree = ""; }; DDC4D567275499A500A4208E /* Persistence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = ""; }; DDCE4E2B2869F92900BE9F8F /* UserConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserConfig.swift; sourceTree = ""; }; - DDCE4E2D286B7BC400BE9F8F /* StoreForwaredConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreForwaredConfig.swift; sourceTree = ""; }; - DDCE4E2F286B7BD800BE9F8F /* InputBrokerConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputBrokerConfig.swift; sourceTree = ""; }; DDCFF600285453A7005FA625 /* localonly.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = localonly.pb.swift; sourceTree = ""; }; DDD94A4F2845C8F5004A87A0 /* DateTimeText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTimeText.swift; sourceTree = ""; }; DDD9E4E3284B208E003777C5 /* UserEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserEntityExtension.swift; sourceTree = ""; }; @@ -273,8 +269,6 @@ DD41582928585C32009B0E59 /* RangeTestConfig.swift */, DD6193782863875F00E59241 /* SerialConfig.swift */, DD415827285859C4009B0E59 /* TelemetryConfig.swift */, - DDCE4E2D286B7BC400BE9F8F /* StoreForwaredConfig.swift */, - DDCE4E2F286B7BD800BE9F8F /* InputBrokerConfig.swift */, ); path = Module; sourceTree = ""; @@ -642,7 +636,6 @@ C9A7BC1027759A9600760B50 /* PositionAnnotationView.swift in Sources */, DD882F5D2772E4640005BF05 /* Contacts.swift in Sources */, DD47E3CE26F103C600029299 /* NodeList.swift in Sources */, - DDCE4E30286B7BD800BE9F8F /* InputBrokerConfig.swift in Sources */, DD8EBF43285058FA00426DCA /* DisplayConfig.swift in Sources */, DD47E3D626F17ED900029299 /* CircleText.swift in Sources */, DDC2E18F26CE25FE0042C5E4 /* ContentView.swift in Sources */, @@ -672,7 +665,6 @@ DDAF8C6726ED0C8C0058C060 /* remote_hardware.pb.swift in Sources */, DDAF8C6526ED0A490058C060 /* channel.pb.swift in Sources */, DDC2E15826CE248E0042C5E4 /* MeshtasticApp.swift in Sources */, - DDCE4E2E286B7BC400BE9F8F /* StoreForwaredConfig.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index c7e02928..738dec39 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -456,6 +456,8 @@ class BLEManager: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeriph if meshLoggingEnabled { MeshLogger.log("ℹ️ MESH PACKET received for Unknown App UNHANDLED \(try! decodedInfo.packet.jsonString())") } } + + print(decodedInfo.moduleConfig.isInitialized) } case .textMessageApp: textMessageAppPacket(packet: decodedInfo.packet, connectedNode: (self.connectedPeripheral != nil ? connectedPeripheral.num : 0), meshLogging: meshLoggingEnabled, context: context!) diff --git a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModel v 4.xcdatamodel/contents b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModel v 4.xcdatamodel/contents index a9000be5..8cb1191b 100644 --- a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModel v 4.xcdatamodel/contents +++ b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModel v 4.xcdatamodel/contents @@ -1,5 +1,16 @@ + + + + + + + + + + + @@ -67,6 +78,7 @@ + @@ -141,11 +153,12 @@ - + + \ No newline at end of file diff --git a/Meshtastic/Views/Bluetooth/Connect.swift b/Meshtastic/Views/Bluetooth/Connect.swift index efd87c4c..ee5043cd 100644 --- a/Meshtastic/Views/Bluetooth/Connect.swift +++ b/Meshtastic/Views/Bluetooth/Connect.swift @@ -26,7 +26,7 @@ struct Connect: View { var body: some View { let firmwareVersion = bleManager.lastConnnectionVersion - let minimumVersion = "1.3.21" + let minimumVersion = "1.3.22" let supportedVersion = firmwareVersion == "0.0.0" || minimumVersion.compare(firmwareVersion, options: .numeric) == .orderedAscending || minimumVersion.compare(firmwareVersion, options: .numeric) == .orderedSame NavigationView { diff --git a/Meshtastic/Views/Settings/Config/DisplayConfig.swift b/Meshtastic/Views/Settings/Config/DisplayConfig.swift index dfa0436a..ffc883de 100644 --- a/Meshtastic/Views/Settings/Config/DisplayConfig.swift +++ b/Meshtastic/Views/Settings/Config/DisplayConfig.swift @@ -93,7 +93,6 @@ enum ScreenOnIntervals: Int, CaseIterable, Identifiable { enum ScreenCarouselIntervals: Int, CaseIterable, Identifiable { case off = 0 - case fifteenSeconds = 15 case thirtySeconds = 30 case oneMinute = 60 case fiveMinutes = 300 @@ -106,8 +105,6 @@ enum ScreenCarouselIntervals: Int, CaseIterable, Identifiable { switch self { case .off: return "Off" - case .fifteenSeconds: - return "Fifteen Seconds" case .thirtySeconds: return "Thirty Seconds" case .oneMinute: diff --git a/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift b/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift index c3aea46d..a69721f0 100644 --- a/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/CannedMessagesConfig.swift @@ -1,8 +1,351 @@ // // CannedMessagesConfig.swift -// MeshtasticApple +// Meshtastic Apple // -// Created by Garth Vander Houwen on 6/22/22. +// Copyright (c) Garth Vander Houwen 6/22/22. // +import SwiftUI -import Foundation +// Default of 0 is unset +enum ConfigPresets : Int, CaseIterable, Identifiable { + + case unset = 0 + case rakRotaryEncoder = 1 + case tbeamThreeButtonScreen = 2 + + var id: Int { self.rawValue } + var description: String { + get { + switch self { + + case .unset: + return "Manual Configuration" + case .rakRotaryEncoder: + return "RAK Rotary Encoder Module" + case .tbeamThreeButtonScreen: + return "TBEAM 3 Button OLED Screen" + } + } + } +} + +// Default of 0 is off +enum InputEventChars: Int, CaseIterable, Identifiable { + + case keyNone = 0 + case keyUp = 17 + case keyDown = 18 + case keyLeft = 19 + case keyRight = 20 + case keySelect = 10 + case keyBack = 27 + case keyCancel = 24 + + var id: Int { self.rawValue } + var description: String { + get { + switch self { + + case .keyNone: + return "None" + case .keyUp: + return "Up" + case .keyDown: + return "Down" + case .keyLeft: + return "Left" + case .keyRight: + return "Right" + case .keySelect: + return "Select" + case .keyBack: + return "Back" + case .keyCancel: + return "Cancel" + } + } + } +} + +struct CannedMessagesConfig: View { + + @Environment(\.managedObjectContext) var context + @EnvironmentObject var bleManager: BLEManager + + var node: NodeInfoEntity + + @State private var isPresentingSaveConfirm: Bool = false + @State var initialLoad: Bool = true + @State var hasChanges = false + @State var configPreset = 0 + + @State var enabled = false + /// CannedMessageModule will sends a bell character with the messages. + @State var sendBell: Bool = false + /// Enable the rotary encoder #1. This is a 'dumb' encoder sending pulses on both A and B pins while rotating. + @State var rotary1Enabled = false + /// Enable the Up/Down/Select input device. Can be RAK rotary encoder or 3 buttons. Uses the a/b/press definitions from inputbroker. + @State var updown1Enabled: Bool = false + /// GPIO pin for rotary encoder A port. + @State var inputbrokerPinA = 0 + /// GPIO pin for rotary encoder B port. + @State var inputbrokerPinB = 0 + /// GPIO pin for rotary encoder Press port. + @State var inputbrokerPinPress = 0 + /// Generate input event on CW of this kind. + @State var inputbrokerEventCw = 0 + /// Generate input event on CCW of this kind. + @State var inputbrokerEventCcw = 0 + /// Generate input event on Press of this kind. + @State var inputbrokerEventPress = 0 + + var body: some View { + + VStack { + + Form { + + Section(header: Text("Options")) { + + Toggle(isOn: $enabled) { + + Label("Enabled", systemImage: "list.bullet.rectangle.fill") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + + Toggle(isOn: $sendBell) { + + Label("Send Bell", systemImage: "bell") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + + Picker("Configuration Presets", selection: $configPreset ) { + ForEach(ConfigPresets.allCases) { cp in + Text(cp.description) + } + } + .pickerStyle(DefaultPickerStyle()) + .padding(.top, 10) + .padding(.bottom, 10) + + } + Section(header: Text("Control Type")) { + + + Toggle(isOn: $rotary1Enabled) { + + Label("Rotary 1", systemImage: "dial.min") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + .disabled(updown1Enabled) + + Toggle(isOn: $updown1Enabled) { + + Label("Up Down 1", systemImage: "arrow.up.arrow.down") + } + .toggleStyle(SwitchToggleStyle(tint: .accentColor)) + .disabled(rotary1Enabled) + + } + .disabled(configPreset > 0) + Section(header: Text("Inputs")) { + + Picker("Pin A", selection: $inputbrokerPinA) { + ForEach(0..<40) { + + if $0 == 0 { + + Text("Unset") + + } else { + + Text("Pin \($0)") + } + } + } + .pickerStyle(DefaultPickerStyle()) + Text("GPIO pin for rotary encoder A port.") + .font(.caption) + + Picker("Pin B", selection: $inputbrokerPinB) { + ForEach(0..<40) { + + if $0 == 0 { + + Text("Unset") + + } else { + + Text("Pin \($0)") + } + } + } + .pickerStyle(DefaultPickerStyle()) + Text("GPIO pin for rotary encoder B port.") + .font(.caption) + + Picker("Press Pin", selection: $inputbrokerPinPress) { + ForEach(0..<40) { + + if $0 == 0 { + + Text("Unset") + + } else { + + Text("Pin \($0)") + } + } + } + .pickerStyle(DefaultPickerStyle()) + Text("GPIO pin for rotary encoder Press port.") + .font(.caption) + + } + .disabled(configPreset > 0) + + Section(header: Text("Key Mapping")) { + + Picker("inputbrokerEventCw", selection: $inputbrokerEventCw ) { + ForEach(InputEventChars.allCases) { iec in + Text(iec.description) + } + } + .pickerStyle(DefaultPickerStyle()) + .padding(.top, 10) + .padding(.bottom, 10) + + Picker("inputbrokerEventCcw", selection: $inputbrokerEventCcw ) { + ForEach(InputEventChars.allCases) { iec in + Text(iec.description) + } + } + .pickerStyle(DefaultPickerStyle()) + .padding(.top, 10) + .padding(.bottom, 10) + + Picker("inputBrokerEventPress", selection: $inputbrokerEventPress ) { + ForEach(InputEventChars.allCases) { iec in + Text(iec.description) + } + } + .pickerStyle(DefaultPickerStyle()) + .padding(.top, 10) + .padding(.bottom, 10) + } + .disabled(configPreset > 0) + } + .disabled(!(node.myInfo?.hasWifi ?? false)) + + Button { + + isPresentingSaveConfirm = true + + } label: { + + Label("Save", systemImage: "square.and.arrow.down") + } + .disabled(bleManager.connectedPeripheral == nil || !hasChanges || !(node.myInfo?.hasWifi ?? false)) + .buttonStyle(.bordered) + .buttonBorderShape(.capsule) + .controlSize(.large) + .padding() + .confirmationDialog( + + "Are you sure?", + isPresented: $isPresentingSaveConfirm + ) { + Button("Save Canned Messages Module Config to \(bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown")?") { + + var cmc = ModuleConfig.CannedMessageConfig() + cmc.enabled = enabled + cmc.sendBell = sendBell + cmc.rotary1Enabled = rotary1Enabled + cmc.updown1Enabled = updown1Enabled + if rotary1Enabled { + + /// Input event origin accepted by the canned messages + /// Can be e.g. "rotEnc1", "upDownEnc1" or keyword "_any" + cmc.allowInputSource = "rotEnc1" + + } else if updown1Enabled { + + cmc.allowInputSource = "upDownEnc1" + + } else { + + cmc.allowInputSource = "_any" + } + cmc.inputbrokerPinA = UInt32(inputbrokerPinA) + cmc.inputbrokerPinB = UInt32(inputbrokerPinB) + cmc.inputbrokerPinPress = UInt32(inputbrokerPinPress) + + //if bleManager.saveRangeTestModuleConfig(config: rtc, destNum: bleManager.connectedPeripheral.num, wantResponse: false) { + + // Should show a saved successfully alert once I know that to be true + // for now just disable the button after a successful save + hasChanges = false + + //} else { + + //} + } + } + + .navigationTitle("Canned Messages Config") + .navigationBarItems(trailing: + + ZStack { + + ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?????") + }) + .onAppear { + + if self.initialLoad{ + + self.bleManager.context = context + self.enabled = node.cannedMessagesConfig?.enabled ?? false + self.rotary1Enabled = node.cannedMessagesConfig?.rotary1Enabled ?? false + self.updown1Enabled = node.cannedMessagesConfig?.updown1Enabled ?? false + self.inputbrokerPinA = Int(node.cannedMessagesConfig?.inputbrokerPinA ?? 0) + self.inputbrokerPinB = Int(node.cannedMessagesConfig?.inputbrokerPinB ?? 0) + self.inputbrokerPinPress = Int(node.cannedMessagesConfig?.inputbrokerPinPress ?? 0) + self.hasChanges = false + self.initialLoad = false + } + } + .onChange(of: configPreset) { newPreset in + + if newPreset == 1 { + + // RAK Rotary Encoder + updown1Enabled = true + rotary1Enabled = false + + } else if newPreset == 2 { + + // TBeam Three Button 1.3" OLED Screen + updown1Enabled = true + rotary1Enabled = false + } + + hasChanges = true + } + .onChange(of: enabled) { newEnabled in + + //if newEnabled != node.cannedMessagesConfig!.enabled { + + hasChanges = true + //} + } + .onChange(of: sendBell) { newBell in + + //if newBell != node.rangeTestConfig!.save { + + hasChanges = true + //} + } + .navigationViewStyle(StackNavigationViewStyle()) + } + } +} diff --git a/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift b/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift index 200e5e1e..0340c876 100644 --- a/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/ExternalNotificationConfig.swift @@ -53,12 +53,19 @@ struct ExternalNotificationConfig: View { var node: NodeInfoEntity + @State private var isPresentingSaveConfirm: Bool = false + @State var initialLoad: Bool = true + @State var hasChanges = false + @State var enabled = false - @State var outputMilliseconds = 0 - @State var output = 0 - @State var active = false - @State var alertMessage = false @State var alertBell = false + @State var alertMessage = false + @State var active = false + @State var output = 0 + @State var outputMilliseconds = 0 + + + var body: some View { @@ -114,7 +121,6 @@ struct ExternalNotificationConfig: View { .pickerStyle(DefaultPickerStyle()) Text("Specifies the GPIO that your external circuit is attached to on the device.") .font(.caption) - .listRowSeparator(.visible) Picker("GPIO Output Duration", selection: $outputMilliseconds ) { ForEach(OutputIntervals.allCases) { oi in @@ -124,9 +130,49 @@ struct ExternalNotificationConfig: View { .pickerStyle(DefaultPickerStyle()) Text("Specifies how long the monitored GPIO should output.") .font(.caption) - .listRowSeparator(.visible) } } + + Button { + + isPresentingSaveConfirm = true + + } label: { + + Label("Save", systemImage: "square.and.arrow.down") + } + .disabled(bleManager.connectedPeripheral == nil || !hasChanges || !(node.myInfo?.hasWifi ?? false)) + .buttonStyle(.bordered) + .buttonBorderShape(.capsule) + .controlSize(.large) + .padding() + .confirmationDialog( + + "Are you sure?", + isPresented: $isPresentingSaveConfirm + ) { + Button("Save External Notification Module Config to \(bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown")?") { + + var enc = ModuleConfig.ExternalNotificationConfig() + enc.enabled = enabled + enc.alertBell = alertBell + enc.alertMessage = alertMessage + enc.active = active + enc.output = UInt32(output) + enc.outputMs = UInt32(outputMilliseconds) + + //if bleManager.saveRangeTestModuleConfig(config: rtc, destNum: bleManager.connectedPeripheral.num, wantResponse: false) { + + // Should show a saved successfully alert once I know that to be true + // for now just disable the button after a successful save + hasChanges = false + + //} else { + + //} + } + } + .navigationTitle("External Notification Config") .navigationBarItems(trailing: diff --git a/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift b/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift index 274707ae..0f3d4a83 100644 --- a/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/RangeTestConfig.swift @@ -1,5 +1,5 @@ // -// TelemetryConfig.swift +// RangeTestConfig.swift // Meshtastic Apple // // Copyright (c) Garth Vander Houwen 6/13/22. @@ -112,15 +112,15 @@ struct RangeTestConfig: View { rtc.save = save rtc.sender = UInt32(sender) - if bleManager.saveRangeTestModuleConfig(config: rtc, destNum: bleManager.connectedPeripheral.num, wantResponse: false) { + //if bleManager.saveRangeTestModuleConfig(config: rtc, destNum: bleManager.connectedPeripheral.num, wantResponse: false) { // Should show a saved successfully alert once I know that to be true // for now just disable the button after a successful save hasChanges = false - } else { + //} else { - } + //} } } @@ -145,17 +145,17 @@ struct RangeTestConfig: View { } .onChange(of: enabled) { newEnabled in - if newEnabled != node.rangeTestConfig!.enabled { + //if newEnabled != node.rangeTestConfig!.enabled { hasChanges = true - } + //} } .onChange(of: save) { newSave in - if newSave != node.rangeTestConfig!.save { + //if newSave != node.rangeTestConfig!.save { hasChanges = true - } + //} } .onChange(of: sender) { newSender in diff --git a/Meshtastic/Views/Settings/Config/Module/StoreForwaredConfig.swift b/Meshtastic/Views/Settings/Config/Module/StoreForwaredConfig.swift deleted file mode 100644 index 32f18fd2..00000000 --- a/Meshtastic/Views/Settings/Config/Module/StoreForwaredConfig.swift +++ /dev/null @@ -1,8 +0,0 @@ -// -// StoreForwaredConfig.swift -// Meshtastic -// -// Created by Garth Vander Houwen on 6/28/22. -// - -import Foundation diff --git a/Meshtastic/Views/Settings/Config/Module/TelemetryConfig.swift b/Meshtastic/Views/Settings/Config/Module/TelemetryConfig.swift index 01cae42c..eb6b9b92 100644 --- a/Meshtastic/Views/Settings/Config/Module/TelemetryConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/TelemetryConfig.swift @@ -76,6 +76,37 @@ enum SensorTypes: Int, CaseIterable, Identifiable { } } } + func protoEnumValue() -> TelemetrySensorType { + + switch self { + + + case .notSet: + return TelemetrySensorType.notSet + case .dht11: + return TelemetrySensorType.dht11 + case .ds18B20: + return TelemetrySensorType.ds18B20 + case .dht12: + return TelemetrySensorType.dht12 + case .dht21: + return TelemetrySensorType.dht21 + case .dht22: + return TelemetrySensorType.dht22 + case .bme280: + return TelemetrySensorType.bme280 + case .bme680: + return TelemetrySensorType.bme680 + case .mcp9808: + return TelemetrySensorType.mcp9808 + case .shtc3: + return TelemetrySensorType.shtc3 + case .ina260: + return TelemetrySensorType.ina260 + case .ina219: + return TelemetrySensorType.ina219 + } + } } // Default of 0 is off @@ -183,6 +214,12 @@ struct TelemetryConfig: View { @Environment(\.managedObjectContext) var context @EnvironmentObject var bleManager: BLEManager + var node: NodeInfoEntity + + @State private var isPresentingSaveConfirm: Bool = false + @State var initialLoad: Bool = true + @State var hasChanges = false + @State var deviceUpdateInterval = 0 @State var environmentUpdateInterval = 0 @@ -294,6 +331,48 @@ struct TelemetryConfig: View { .font(.caption) } } + + Button { + + isPresentingSaveConfirm = true + + } label: { + + Label("Save", systemImage: "square.and.arrow.down") + } + .disabled(bleManager.connectedPeripheral == nil || !hasChanges || !(node.myInfo?.hasWifi ?? false)) + .buttonStyle(.bordered) + .buttonBorderShape(.capsule) + .controlSize(.large) + .padding() + .confirmationDialog( + + "Are you sure?", + isPresented: $isPresentingSaveConfirm + ) { + Button("Save Telemetry Module Config to \(bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown")?") { + + var tc = ModuleConfig.TelemetryConfig() + tc.environmentMeasurementEnabled = environmentMeasurementEnabled + tc.environmentSensorType = SensorTypes(rawValue: environmentSensorType)!.protoEnumValue() + tc.environmentScreenEnabled = environmentScreenEnabled + tc.environmentDisplayFahrenheit = environmentDisplayFahrenheit + tc.environmentSensorPin = UInt32(environmentSensorPin) + tc.environmentRecoveryInterval = UInt32(environmentRecoveryInterval) + tc.environmentReadErrorCountThreshold = UInt32(environmentReadErrorCountThreshold) + + //if bleManager.saveRangeTestModuleConfig(config: rtc, destNum: bleManager.connectedPeripheral.num, wantResponse: false) { + + // Should show a saved successfully alert once I know that to be true + // for now just disable the button after a successful save + hasChanges = false + + //} else { + + //} + } + } + .navigationTitle("Telemetry Config") .navigationBarItems(trailing: diff --git a/Meshtastic/Views/Settings/Settings.swift b/Meshtastic/Views/Settings/Settings.swift index 9c1bebc3..b7cde110 100644 --- a/Meshtastic/Views/Settings/Settings.swift +++ b/Meshtastic/Views/Settings/Settings.swift @@ -42,6 +42,10 @@ struct Settings: View { Section("Radio Configuration") { + Text("Radio config views will be be enabled when there is a connected node. Save buttons will be enabled when there are config changes to save.") + .font(.caption) + .fixedSize(horizontal: false, vertical: true) + NavigationLink { ShareChannel(node: nodes.first(where: { $0.num == connectedNodeNum }) ?? NodeInfoEntity()) } label: { @@ -51,10 +55,6 @@ struct Settings: View { } .disabled(bleManager.connectedPeripheral == nil) - Text("Radio config views will be be enabled when there is a connected node. Save buttons will be enabled when there are config changes to save.") - .font(.caption) - .fixedSize(horizontal: false, vertical: true) - NavigationLink { UserConfig(node: nodes.first(where: { $0.num == connectedNodeNum }) ?? NodeInfoEntity()) } label: { @@ -116,7 +116,7 @@ struct Settings: View { Section("Module Configuration - Non Functional interaction preview.") { NavigationLink { - PositionConfig(node: nodes.first(where: { $0.num == connectedNodeNum }) ?? NodeInfoEntity()) + CannedMessagesConfig(node: nodes.first(where: { $0.num == connectedNodeNum }) ?? NodeInfoEntity()) } label: { Image(systemName: "list.bullet.rectangle.fill") @@ -135,6 +135,7 @@ struct Settings: View { Text("External Notification") } + .disabled(bleManager.connectedPeripheral == nil) NavigationLink { RangeTestConfig(node: nodes.first(where: { $0.num == connectedNodeNum }) ?? NodeInfoEntity()) @@ -145,8 +146,7 @@ struct Settings: View { Text("Range Test (ESP32 Only)") } - .disabled(true) - //.disabled(bleManager.connectedPeripheral == nil) + .disabled(bleManager.connectedPeripheral == nil) //nodes.first(where: { $0.num == connectedNodeNum })?.myInfo?.hasWifi ?? true)//|| // nodes.first(where: { $0.num == connectedNodeNum })!.rangeTestConfig != nil) @@ -161,8 +161,9 @@ struct Settings: View { } .disabled(false) + NavigationLink { - TelemetryConfig() + TelemetryConfig(node: nodes.first(where: { $0.num == connectedNodeNum }) ?? NodeInfoEntity()) } label: { Image(systemName: "chart.xyaxis.line") @@ -173,7 +174,7 @@ struct Settings: View { .disabled(false) } // Not Implemented: - // Store Forward Config - Not Working + // Store Forward Config - Not Working, TBEAM Only // WiFi Config - Would break connection to device // MQTT Config - Part of WiFi } diff --git a/Meshtastic/Views/Settings/UserConfig.swift b/Meshtastic/Views/Settings/UserConfig.swift index 1def1199..032e1686 100644 --- a/Meshtastic/Views/Settings/UserConfig.swift +++ b/Meshtastic/Views/Settings/UserConfig.swift @@ -37,9 +37,9 @@ struct UserConfig: View { let totalBytes = longName.utf8.count // Only mess with the value if it is too big - if totalBytes > 40 { + if totalBytes > 36 { - let firstNBytes = Data(longName.utf8.prefix(40)) + let firstNBytes = Data(longName.utf8.prefix(36)) if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) { @@ -53,9 +53,9 @@ struct UserConfig: View { let totalBytes = shortName.utf8.count // Only mess with the value if it is too big - if totalBytes > 5 { + if totalBytes > 4 { - let firstNBytes = Data(shortName.utf8.prefix(5)) + let firstNBytes = Data(shortName.utf8.prefix(4)) if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) {