More complete module configuration previews, less prone to crashing settings page

This commit is contained in:
Garth Vander Houwen 2022-07-01 10:57:54 -07:00
parent 7317b6fbe4
commit ce35f49b7c
12 changed files with 516 additions and 51 deletions

View file

@ -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 = "<group>"; };
DDC4D567275499A500A4208E /* Persistence.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = "<group>"; };
DDCE4E2B2869F92900BE9F8F /* UserConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserConfig.swift; sourceTree = "<group>"; };
DDCE4E2D286B7BC400BE9F8F /* StoreForwaredConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreForwaredConfig.swift; sourceTree = "<group>"; };
DDCE4E2F286B7BD800BE9F8F /* InputBrokerConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputBrokerConfig.swift; sourceTree = "<group>"; };
DDCFF600285453A7005FA625 /* localonly.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = localonly.pb.swift; sourceTree = "<group>"; };
DDD94A4F2845C8F5004A87A0 /* DateTimeText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateTimeText.swift; sourceTree = "<group>"; };
DDD9E4E3284B208E003777C5 /* UserEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserEntityExtension.swift; sourceTree = "<group>"; };
@ -273,8 +269,6 @@
DD41582928585C32009B0E59 /* RangeTestConfig.swift */,
DD6193782863875F00E59241 /* SerialConfig.swift */,
DD415827285859C4009B0E59 /* TelemetryConfig.swift */,
DDCE4E2D286B7BC400BE9F8F /* StoreForwaredConfig.swift */,
DDCE4E2F286B7BD800BE9F8F /* InputBrokerConfig.swift */,
);
path = Module;
sourceTree = "<group>";
@ -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;
};

View file

@ -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!)

View file

@ -1,5 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="20086" systemVersion="21F79" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="CannedMessageConfig" representedClassName="CannedMessageConfig" syncable="YES" codeGenerationType="class">
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="inputbrokerPinA" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="inputbrokerPinB" optional="YES" attributeType="Integer 32" usesScalarValueType="YES"/>
<attribute name="inputbrokerPinPress" optional="YES" attributeType="Integer 32" usesScalarValueType="YES"/>
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="rotary1Enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="sendBell" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="updown1Enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<relationship name="cannedMessagesConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="cannedMessagesConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="DeviceConfigEntity" representedClassName="DeviceConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="debugLogEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
@ -67,6 +78,7 @@
<attribute name="lastHeard" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="snr" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<relationship name="cannedMessagesConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="CannedMessageConfig" inverseName="cannedMessagesConfigNode" inverseEntity="CannedMessageConfig"/>
<relationship name="deviceConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="DeviceConfigEntity" inverseName="deviceConfigNode" inverseEntity="DeviceConfigEntity"/>
<relationship name="displayConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="DisplayConfigEntity" inverseName="displayConfigNode" inverseEntity="DisplayConfigEntity"/>
<relationship name="loRaConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="LoRaConfigEntity" inverseName="loRaConfigNode" inverseEntity="LoRaConfigEntity"/>
@ -141,11 +153,12 @@
<element name="LoRaConfigEntity" positionX="45" positionY="144" width="128" height="104"/>
<element name="MessageEntity" positionX="-36" positionY="63" width="128" height="215"/>
<element name="MyInfoEntity" positionX="-18" positionY="81" width="128" height="209"/>
<element name="NodeInfoEntity" positionX="-63" positionY="-18" width="128" height="239"/>
<element name="NodeInfoEntity" positionX="-63" positionY="-18" width="128" height="254"/>
<element name="PositionConfigEntity" positionX="63" positionY="162" width="128" height="149"/>
<element name="PositionEntity" positionX="-54" positionY="54" width="128" height="119"/>
<element name="RangeTestConfigEntity" positionX="72" positionY="171" width="128" height="104"/>
<element name="TelemetryEntity" positionX="160" positionY="192" width="128" height="194"/>
<element name="UserEntity" positionX="0" positionY="144" width="128" height="200"/>
<element name="CannedMessageConfig" positionX="45" positionY="144" width="128" height="164"/>
</elements>
</model>

View file

@ -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 {

View file

@ -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:

View file

@ -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())
}
}
}

View file

@ -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:

View file

@ -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

View file

@ -1,8 +0,0 @@
//
// StoreForwaredConfig.swift
// Meshtastic
//
// Created by Garth Vander Houwen on 6/28/22.
//
import Foundation

View file

@ -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:

View file

@ -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
}

View file

@ -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) {