mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
More complete module configuration previews, less prone to crashing settings page
This commit is contained in:
parent
7317b6fbe4
commit
ce35f49b7c
12 changed files with 516 additions and 51 deletions
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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!)
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
//
|
||||
// StoreForwaredConfig.swift
|
||||
// Meshtastic
|
||||
//
|
||||
// Created by Garth Vander Houwen on 6/28/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue