Merge pull request #99 from meshtastic/feature/lora_config

Module Config Mockups
This commit is contained in:
Garth Vander Houwen 2022-06-22 21:34:52 -07:00 committed by GitHub
commit 6fad9b646a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 738 additions and 76 deletions

View file

@ -34,6 +34,9 @@
DD5394FC276993AD00AD86B1 /* SwiftProtobuf in Frameworks */ = {isa = PBXBuildFile; productRef = DD5394FB276993AD00AD86B1 /* SwiftProtobuf */; };
DD5394FE276BA0EF00AD86B1 /* PositionEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD5394FD276BA0EF00AD86B1 /* PositionEntityExtension.swift */; };
DD539502276DAA6A00AD86B1 /* MapLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD539501276DAA6A00AD86B1 /* MapLocation.swift */; };
DD6193752862F6E600E59241 /* ExternalNotificationConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6193742862F6E600E59241 /* ExternalNotificationConfig.swift */; };
DD6193772862F90F00E59241 /* CannedMessagesConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6193762862F90F00E59241 /* CannedMessagesConfig.swift */; };
DD6193792863875F00E59241 /* SerialConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6193782863875F00E59241 /* SerialConfig.swift */; };
DD6B85A828009258000ACD6B /* ShareChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6B85A728009258000ACD6B /* ShareChannel.swift */; };
DD8169F9271F1A6100F4AB02 /* MeshLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8169F8271F1A6100F4AB02 /* MeshLogger.swift */; };
DD8169FB271F1F3A00F4AB02 /* MeshLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8169FA271F1F3A00F4AB02 /* MeshLog.swift */; };
@ -117,6 +120,9 @@
DD5394FD276BA0EF00AD86B1 /* PositionEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PositionEntityExtension.swift; sourceTree = "<group>"; };
DD539501276DAA6A00AD86B1 /* MapLocation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapLocation.swift; sourceTree = "<group>"; };
DD619373285CC7D600E59241 /* MeshtasticDataModel v 4.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModel v 4.xcdatamodel"; sourceTree = "<group>"; };
DD6193742862F6E600E59241 /* ExternalNotificationConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExternalNotificationConfig.swift; sourceTree = "<group>"; };
DD6193762862F90F00E59241 /* CannedMessagesConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CannedMessagesConfig.swift; sourceTree = "<group>"; };
DD6193782863875F00E59241 /* SerialConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SerialConfig.swift; sourceTree = "<group>"; };
DD6B85A728009258000ACD6B /* ShareChannel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareChannel.swift; sourceTree = "<group>"; };
DD8169F8271F1A6100F4AB02 /* MeshLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshLogger.swift; sourceTree = "<group>"; };
DD8169FA271F1F3A00F4AB02 /* MeshLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeshLog.swift; sourceTree = "<group>"; };
@ -232,17 +238,36 @@
children = (
DD3501882852FC3B000FC853 /* Settings.swift */,
DD4A911D2708C65400501B7E /* AppSettings.swift */,
DD8169FA271F1F3A00F4AB02 /* MeshLog.swift */,
DD8169FE272476C700F4AB02 /* LogDocument.swift */,
DD6B85A728009258000ACD6B /* ShareChannel.swift */,
DD61937A2863876A00E59241 /* Config */,
);
path = Settings;
sourceTree = "<group>";
};
DD61937A2863876A00E59241 /* Config */ = {
isa = PBXGroup;
children = (
DD41582528582E9B009B0E59 /* DeviceConfig.swift */,
DD8EBF42285058FA00426DCA /* DisplayConfig.swift */,
DD2553562855B02500E55709 /* LoRaConfig.swift */,
DD2553582855B52700E55709 /* PositionConfig.swift */,
DD41582928585C32009B0E59 /* RangeTestConfig.swift */,
DD415827285859C4009B0E59 /* TelemetryConfig.swift */,
DD8169FA271F1F3A00F4AB02 /* MeshLog.swift */,
DD8169FE272476C700F4AB02 /* LogDocument.swift */,
DD61937B2863877A00E59241 /* Module */,
);
path = Settings;
path = Config;
sourceTree = "<group>";
};
DD61937B2863877A00E59241 /* Module */ = {
isa = PBXGroup;
children = (
DD6193762862F90F00E59241 /* CannedMessagesConfig.swift */,
DD6193742862F6E600E59241 /* ExternalNotificationConfig.swift */,
DD41582928585C32009B0E59 /* RangeTestConfig.swift */,
DD6193782863875F00E59241 /* SerialConfig.swift */,
DD415827285859C4009B0E59 /* TelemetryConfig.swift */,
);
path = Module;
sourceTree = "<group>";
};
DD8EDE9226F97A2B00A5A10B /* Frameworks */ = {
@ -591,6 +616,7 @@
DDC4D568275499A500A4208E /* Persistence.swift in Sources */,
DD90860E26F69BAE00DC5189 /* NodeMap.swift in Sources */,
DD8169FF272476C700F4AB02 /* LogDocument.swift in Sources */,
DD6193792863875F00E59241 /* SerialConfig.swift in Sources */,
DDAF8C6926ED0D070058C060 /* deviceonly.pb.swift in Sources */,
DD90860C26F684AF00DC5189 /* BatteryIcon.swift in Sources */,
DD4A911E2708C65400501B7E /* AppSettings.swift in Sources */,
@ -599,6 +625,7 @@
DDF924CA26FBB953009FE055 /* ConnectedDevice.swift in Sources */,
DDAF8C5D26ED09490058C060 /* portnums.pb.swift in Sources */,
DD9D8F2F2764403B00080993 /* Meshtastic.xcdatamodeld in Sources */,
DD6193772862F90F00E59241 /* CannedMessagesConfig.swift in Sources */,
DD41582628582E9B009B0E59 /* DeviceConfig.swift in Sources */,
DD1BF2F92776FE2E008C8D2F /* UserMessageList.swift in Sources */,
DDB2CC6E27F3EB47009C5FCC /* telemetry.pb.swift in Sources */,
@ -621,6 +648,7 @@
DDC3B274283F411B00AC321C /* LastHeardText.swift in Sources */,
DD2E65262767A01F00E45FC5 /* NodeDetail.swift in Sources */,
DDA6B2E928419CF2003E8C16 /* MeshPackets.swift in Sources */,
DD6193752862F6E600E59241 /* ExternalNotificationConfig.swift in Sources */,
DDD94A502845C8F5004A87A0 /* DateTimeText.swift in Sources */,
C9A88B57278B559900BD810A /* apponly.pb.swift in Sources */,
DD4C158E2824AA7E0032668E /* config.pb.swift in Sources */,

View file

@ -73,6 +73,7 @@
<relationship name="myInfo" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MyInfoEntity" inverseName="myInfoNode" inverseEntity="MyInfoEntity"/>
<relationship name="positionConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="PositionConfigEntity" inverseName="positionConfigNode" inverseEntity="PositionConfigEntity"/>
<relationship name="positions" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="PositionEntity" inverseName="nodePosition" inverseEntity="PositionEntity"/>
<relationship name="rangeTestConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="RangeTestConfigEntity" inverseName="rangeTestConfigNode" inverseEntity="RangeTestConfigEntity"/>
<relationship name="telemetries" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="TelemetryEntity" inverseName="nodeTelemetry" inverseEntity="TelemetryEntity"/>
<relationship name="user" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="UserEntity" inverseName="userNode" inverseEntity="UserEntity"/>
<uniquenessConstraints>
@ -99,6 +100,13 @@
<attribute name="time" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
<relationship name="nodePosition" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="positions" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="RangeTestConfigEntity" representedClassName="RangeTestConfigEntity" syncable="YES" codeGenerationType="class">
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="num" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
<attribute name="save" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<attribute name="sender" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
<relationship name="rangeTestConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="rangeTestConfig" inverseEntity="NodeInfoEntity"/>
</entity>
<entity name="TelemetryEntity" representedClassName="TelemetryEntity" syncable="YES" codeGenerationType="class">
<attribute name="airUtilTx" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
<attribute name="barometricPressure" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
@ -131,12 +139,13 @@
<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="224"/>
<element name="NodeInfoEntity" positionX="-63" positionY="-18" width="128" height="239"/>
<element name="PositionEntity" positionX="-54" positionY="54" width="128" height="119"/>
<element name="TelemetryEntity" positionX="160" positionY="192" width="128" height="194"/>
<element name="UserEntity" positionX="0" positionY="144" width="128" height="200"/>
<element name="DeviceConfigEntity" positionX="45" positionY="144" width="128" height="104"/>
<element name="DisplayConfigEntity" positionX="54" positionY="153" width="128" height="104"/>
<element name="PositionConfigEntity" positionX="63" positionY="162" width="128" height="149"/>
<element name="RangeTestConfigEntity" positionX="72" positionY="171" width="128" height="104"/>
</elements>
</model>

View file

@ -811,11 +811,11 @@ struct Config {
///
/// Medium Range - Slow
case midSlow // = 3
case medSlow // = 3
///
/// Medium Range - Fast
case midFast // = 4
case medFast // = 4
///
/// Short Range - Slow
@ -835,8 +835,8 @@ struct Config {
case 0: self = .longFast
case 1: self = .longSlow
case 2: self = .vlongSlow
case 3: self = .midSlow
case 4: self = .midFast
case 3: self = .medSlow
case 4: self = .medFast
case 5: self = .shortSlow
case 6: self = .shortFast
default: self = .UNRECOGNIZED(rawValue)
@ -848,8 +848,8 @@ struct Config {
case .longFast: return 0
case .longSlow: return 1
case .vlongSlow: return 2
case .midSlow: return 3
case .midFast: return 4
case .medSlow: return 3
case .medFast: return 4
case .shortSlow: return 5
case .shortFast: return 6
case .UNRECOGNIZED(let i): return i
@ -953,8 +953,8 @@ extension Config.LoRaConfig.ModemPreset: CaseIterable {
.longFast,
.longSlow,
.vlongSlow,
.midSlow,
.midFast,
.medSlow,
.medFast,
.shortSlow,
.shortFast,
]
@ -1588,8 +1588,8 @@ extension Config.LoRaConfig.ModemPreset: SwiftProtobuf._ProtoNameProviding {
0: .same(proto: "LongFast"),
1: .same(proto: "LongSlow"),
2: .same(proto: "VLongSlow"),
3: .same(proto: "MidSlow"),
4: .same(proto: "MidFast"),
3: .same(proto: "MedSlow"),
4: .same(proto: "MedFast"),
5: .same(proto: "ShortSlow"),
6: .same(proto: "ShortFast"),
]

View file

@ -304,6 +304,9 @@ struct NodeDetail: View {
Image(systemName: "mappin.and.ellipse").foregroundColor(.accentColor) // .font(.subheadline)
Text("Lat/Long:").font(.caption)
Text("\(String(mappin.latitude ?? 0)) \(String(mappin.longitude ?? 0))")
.foregroundColor(.gray)
.font(.caption)

View file

@ -75,7 +75,7 @@ struct DeviceConfig: View {
Text(dr.description)
}
}
.pickerStyle(InlinePickerStyle())
.pickerStyle(DefaultPickerStyle())
.padding(.top, 10)
.padding(.bottom, 10)
}

View file

@ -151,7 +151,7 @@ struct DisplayConfig: View {
}
.pickerStyle(DefaultPickerStyle())
Text("The number of seconds the screen remains on after the user button is pressed or messages are received.")
Text("How long the screen remains on after the user button is pressed or messages are received.")
.font(.caption)
.listRowSeparator(.visible)
@ -175,7 +175,7 @@ struct DisplayConfig: View {
}
.pickerStyle(DefaultPickerStyle())
Text("The format used to display GPS coordinates on the screen.")
Text("The format used to display GPS coordinates on the device screen.")
.font(.caption)
.listRowSeparator(.visible)
}

View file

@ -134,9 +134,9 @@ enum ModemPresets : Int, CaseIterable, Identifiable {
case .VLongSlow:
return Config.LoRaConfig.ModemPreset.vlongSlow
case .MidSlow:
return Config.LoRaConfig.ModemPreset.midSlow
return Config.LoRaConfig.ModemPreset.medSlow
case .MidFast:
return Config.LoRaConfig.ModemPreset.midFast
return Config.LoRaConfig.ModemPreset.medFast
case .ShortSlow:
return Config.LoRaConfig.ModemPreset.shortSlow
case .ShortFast:

View file

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

View file

@ -0,0 +1,94 @@
//
// External Notification Config.swift
// Meshtastic Apple
//
// Copyright (c) Garth Vander Houwen 6/22/22.
//
import SwiftUI
struct ExternalNotificationConfig: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
var node: NodeInfoEntity
@State var enabled = false
@State var outputMilliseconds = 0
@State var output = 0
@State var active = false
@State var alertMessage = false
@State var alertBell = false
var body: some View {
VStack {
Form {
Section(header: Text("Options")) {
Toggle(isOn: $enabled) {
Label("Enabled", systemImage: "megaphone")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Toggle(isOn: $alertBell) {
Label("Alert when receiving a bell", systemImage: "bell")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Toggle(isOn: $alertMessage) {
Label("Alert when receiving a message", systemImage: "message")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
}
Section(header: Text("GPIO")) {
Toggle(isOn: $active) {
Label("Active", systemImage: "togglepower")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Text("Specifies whether the external circuit is triggered when the device's GPIO is low or high.")
.font(.caption)
.listRowSeparator(.visible)
Picker("GPIO to monitor", selection: $output) {
ForEach(0..<40) {
if $0 == 0 {
Text("Unset")
} else {
Text("Pin \($0)")
}
}
}
.pickerStyle(DefaultPickerStyle())
Text("Specifies the GPIO that your external circuit is attached to on the device.")
.font(.caption)
.listRowSeparator(.visible)
}
}
.navigationTitle("External Notification Config")
.navigationBarItems(trailing:
ZStack {
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?????")
})
.onAppear {
self.bleManager.context = context
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
}

View file

@ -27,28 +27,25 @@ struct RangeTestConfig: View {
Label("Enabled", systemImage: "figure.walk")
}
.toggleStyle(DefaultToggleStyle())
.listRowSeparator(.visible)
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Toggle(isOn: $sender) {
Label("Sender", systemImage: "paperplane")
}
.toggleStyle(DefaultToggleStyle())
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Text("This device will send out range test messages.")
.font(.caption)
.listRowSeparator(.visible)
Toggle(isOn: $save) {
Label("Save", systemImage: "square.and.arrow.down.fill")
}
.toggleStyle(DefaultToggleStyle())
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Text("Saves a CSV with the range test message details, only available on ESP32 devices with a web server.")
.font(.caption)
.listRowSeparator(.visible)
}
}
.navigationTitle("Range Test Config")
.navigationBarItems(trailing:

View file

@ -0,0 +1,226 @@
//
// SerialConfig.swift
// Meshtastic Apple
//
// Copyright (c) Garth Vander Houwen 6/22/22.
//
import SwiftUI
enum SerialBaudRates: Int, CaseIterable, Identifiable {
case baudDefault = 0
case baud110 = 1
case baud300 = 2
case baud600 = 3
case baud1200 = 4
case baud2400 = 5
case baud4800 = 6
case baud9600 = 7
case baud19200 = 8
case baud38400 = 9
case baud57600 = 10
case baud115200 = 11
case baud230400 = 12
case baud460800 = 13
case baud576000 = 14
case baud921600 = 15
var id: Int { self.rawValue }
var description: String {
get {
switch self {
case .baudDefault:
return "Unset"
case .baud110:
return "110 Baud"
case .baud300:
return "300 Baud"
case .baud600:
return "600 Baud"
case .baud1200:
return "1200 Baud"
case .baud2400:
return "2400 Baud"
case .baud4800:
return "4800 Baud"
case .baud9600:
return "9600 Baud"
case .baud19200:
return "19200 Baud"
case .baud38400:
return "38400 Baud"
case .baud57600:
return "57600 Baud"
case .baud115200:
return "115200 Baud"
case .baud230400:
return "230400 Baud"
case .baud460800:
return "460800 Baud"
case .baud576000:
return "576000 Baud"
case .baud921600:
return "921600 Baud"
}
}
}
}
enum SerialModeTypes: Int, CaseIterable, Identifiable {
case modeDefault = 0
case modeSimple = 1
case modeProto = 2
var id: Int { self.rawValue }
var description: String {
get {
switch self {
case .modeDefault:
return "Default"
case .modeSimple:
return "Simple"
case .modeProto:
return "Protobufs"
}
}
}
}
enum SerialTimeoutIntervals: Int, CaseIterable, Identifiable {
case unset = 0
case fiveSeconds = 5
case tenSeconds = 10
case fifteenSeconds = 15
case thirtySeconds = 30
case oneMinute = 60
case fiveMinutes = 300
var id: Int { self.rawValue }
var description: String {
get {
switch self {
case .unset:
return "Unset"
case .fiveSeconds:
return "Five Seconds"
case .tenSeconds:
return "Ten Seconds"
case .fifteenSeconds:
return "Fifteen Seconds"
case .thirtySeconds:
return "Thirty Seconds"
case .oneMinute:
return "One Minute"
case .fiveMinutes:
return "Five Minutes"
}
}
}
}
struct SerialConfig: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
@State var enabled = false
@State var echo = false
@State var rxd = 0
@State var txd = 0
@State var baudRate = 0
@State var timeout = 0
@State var mode = 0
var body: some View {
VStack {
Form {
Section(header: Text("Options")) {
Toggle(isOn: $enabled) {
Label("Enabled", systemImage: "terminal")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Toggle(isOn: $echo) {
Label("Echo", systemImage: "repeat")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Picker("Baud Rate", selection: $baudRate ) {
ForEach(SerialBaudRates.allCases) { sbr in
Text(sbr.description)
}
}
.pickerStyle(DefaultPickerStyle())
Picker("Timeout", selection: $timeout ) {
ForEach(SerialTimeoutIntervals.allCases) { sti in
Text(sti.description)
}
}
.pickerStyle(DefaultPickerStyle())
Picker("Mode", selection: $mode ) {
ForEach(SerialModeTypes.allCases) { smt in
Text(smt.description)
}
}
.pickerStyle(DefaultPickerStyle())
}
Section(header: Text("GPIO")) {
Picker("Receive data (rxd) GPIO pin", selection: $rxd) {
ForEach(0..<40) {
if $0 == 0 {
Text("Unset")
} else {
Text("Pin \($0)")
}
}
}
.pickerStyle(DefaultPickerStyle())
Picker("Transmit data (txd) GPIO pin", selection: $txd) {
ForEach(0..<40) {
if $0 == 0 {
Text("Unset")
} else {
Text("Pin \($0)")
}
}
}
.pickerStyle(DefaultPickerStyle())
}
}
.navigationTitle("Serial Config")
.navigationBarItems(trailing:
ZStack {
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?????")
})
.onAppear {
self.bleManager.context = context
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
}

View file

@ -0,0 +1,311 @@
//
// TelemetryConfig.swift
// Meshtastic Apple
//
// Copyright (c) Garth Vander Houwen 6/13/22.
//
import SwiftUI
enum SensorTypes: Int, CaseIterable, Identifiable {
/// No external telemetry sensor explicitly set
case notSet = 0
/// Moderate accuracy temperature
case dht11 = 1
/// High accuracy temperature
case ds18B20 = 2
/// Moderate accuracy temperature and humidity
case dht12 = 3
/// Moderate accuracy temperature and humidity
case dht21 = 4
/// Moderate accuracy temperature and humidity
case dht22 = 5
/// High accuracy temperature, pressure, humidity
case bme280 = 6
/// High accuracy temperature, pressure, humidity, and air resistance
case bme680 = 7
/// Very high accuracy temperature
case mcp9808 = 8
/// Moderate accuracy temperature and humidity
case shtc3 = 9
/// Moderate accuracy current and voltage
case ina260 = 10
/// Moderate accuracy current and voltage
case ina219 = 11
var id: Int { self.rawValue }
var description: String {
get {
switch self {
case .notSet:
return "Not Set"
case .dht11:
return "DHT11 - Temperature"
case .ds18B20:
return "DS18B20 - Temperature"
case .dht12:
return "DHT12 - Temperature & humidity"
case .dht21:
return "DHT21 - Temperature & humidity"
case .dht22:
return "DHT22 - Temperature & humidity"
case .bme280:
return "BME280 - Temp, pressure & humidity"
case .bme680:
return "BME680 - Temp, pressure, humidity & air resistance"
case .mcp9808:
return "MCP9808 - Temperature"
case .shtc3:
return "SHTC3 - Temperature & humidity"
case .ina260:
return "INA260 - Current & voltage"
case .ina219:
return "INA219 - Current & voltage"
}
}
}
}
// Default of 0 is off
enum ErrorRecoveryIntervals: Int, CaseIterable, Identifiable {
case off = 0
case fifteenSeconds = 15
case thirtySeconds = 30
case oneMinute = 60
case fiveMinutes = 300
case tenMinutes = 600
case fifteenMinutes = 900
case thirtyMinutes = 1800
case oneHour = 3600
var id: Int { self.rawValue }
var description: String {
get {
switch self {
case .off:
return "Unset"
case .fifteenSeconds:
return "Fifteen Seconds"
case .thirtySeconds:
return "Thirty Seconds"
case .oneMinute:
return "One Minute"
case .fiveMinutes:
return "Five Minutes"
case .tenMinutes:
return "Ten Minutes"
case .fifteenMinutes:
return "Fifteen Minutes"
case .thirtyMinutes:
return "Thirty Minutes"
case .oneHour:
return "One Hour"
}
}
}
}
enum UpdateIntervals: Int, CaseIterable, Identifiable {
case fifteenSeconds = 15
case thirtySeconds = 30
case oneMinute = 60
case fiveMinutes = 300
case tenMinutes = 600
case fifteenMinutes = 0
case thirtyMinutes = 1800
case oneHour = 3600
case twoHours = 7200
case threeHours = 10800
case fourHours = 14400
case fiveHours = 18000
case sixHours = 21600
case twelveHours = 43200
case eighteenHours = 64800
case twentyFourHours = 86400
var id: Int { self.rawValue }
var description: String {
get {
switch self {
case .fifteenSeconds:
return "Fifteen Seconds"
case .thirtySeconds:
return "Thirty Seconds"
case .oneMinute:
return "One Minute"
case .fiveMinutes:
return "Five Minutes"
case .tenMinutes:
return "Ten Minutes"
case .fifteenMinutes:
return "Fifteen Minutes"
case .thirtyMinutes:
return "Thirty Minutes"
case .oneHour:
return "One Hour"
case .twoHours:
return "Two Hours"
case .threeHours:
return "Three Hours"
case .fourHours:
return "Four Hours"
case .fiveHours:
return "Five Hours"
case .sixHours:
return "Six Hours"
case .twelveHours:
return "Twelve Hours"
case .eighteenHours:
return "Eighteen Hours"
case .twentyFourHours:
return "Twenty Four Hours"
}
}
}
}
struct TelemetryConfig: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
@State var deviceUpdateInterval = 0
@State var environmentUpdateInterval = 0
@State var environmentMeasurementEnabled = false
@State var environmentSensorType = 0
@State var environmentScreenEnabled = false
@State var environmentDisplayFahrenheit = false
@State var environmentSensorPin = 0
@State var environmentRecoveryInterval = 0
@State var environmentReadErrorCountThreshold = 0
var body: some View {
VStack {
Form {
Section(header: Text("Update Intervals")) {
Picker("Device Metrics", selection: $deviceUpdateInterval ) {
ForEach(UpdateIntervals.allCases) { ui in
Text(ui.description)
}
}
.pickerStyle(DefaultPickerStyle())
Text("How often device metrics are sent out over the mesh. Default is 15 minutes.")
.font(.caption)
Picker("Sensor Metrics", selection: $environmentUpdateInterval ) {
ForEach(UpdateIntervals.allCases) { ui in
Text(ui.description)
}
}
.pickerStyle(DefaultPickerStyle())
Text("How often sensor metrics are sent out over the mesh. Default is 15 minutes.")
.font(.caption)
}
Section(header: Text("Sensor Options")) {
Toggle(isOn: $environmentMeasurementEnabled) {
Label("Enabled", systemImage: "chart.xyaxis.line")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Picker("Sensor", selection: $environmentSensorType ) {
ForEach(SensorTypes.allCases) { st in
Text(st.description)
}
}
.pickerStyle(DefaultPickerStyle())
Toggle(isOn: $environmentScreenEnabled) {
Label("Show on device screen", systemImage: "display")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Toggle(isOn: $environmentDisplayFahrenheit) {
Label("Display Fahrenheit", systemImage: "thermometer")
}
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
Picker("GPIO Pin for sensor readings", selection: $environmentSensorPin) {
ForEach(0..<40) {
if $0 == 0 {
Text("Unset")
} else {
Text("Pin \($0)")
}
}
}
.pickerStyle(DefaultPickerStyle())
}
Section(header: Text("Errors")) {
Picker("Error Count Threshold", selection: $environmentReadErrorCountThreshold) {
ForEach(0..<101) {
if $0 == 0 {
Text("Unset")
} else if $0 % 5 == 0 {
Text("\($0)")
}
}
}
.pickerStyle(DefaultPickerStyle())
Text("Sometimes sensor reads can fail. If this happens, we will retry a configurable number of attempts, each attempt will be delayed by the minimum required refresh rate for that sensor")
.font(.caption)
Picker("Error Recovery Interval", selection: $environmentRecoveryInterval ) {
ForEach(ErrorRecoveryIntervals.allCases) { eri in
Text(eri.description)
}
}
.pickerStyle(DefaultPickerStyle())
Text("Sometimes we can end up with more failures than our error count threshold. In this case, we will stop trying to read from the sensor for a while. Wait this long until trying to read from the sensor again")
.font(.caption)
}
}
.navigationTitle("Telemetry Config")
.navigationBarItems(trailing:
ZStack {
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?????")
})
.onAppear {
self.bleManager.context = context
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
}

View file

@ -47,9 +47,10 @@ struct Settings: View {
Section("Radio Configuration") {
Text("Radio config values will be be enabled when there is a connected node. Save buttons will enable when there is a connected node and config changes to save.")
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)
.listRowSeparator(.visible)
.fixedSize(horizontal: false, vertical: true)
NavigationLink {
DeviceConfig(node: nodes.first(where: { $0.num == connectedNodeNum }) ?? NodeInfoEntity())
@ -93,19 +94,33 @@ struct Settings: View {
Text("Position")
}
.disabled(bleManager.connectedPeripheral == nil)
Text("Default settings values are prefered whenever possible as they consume no bandwidth when sent over the mesh.")
.font(.caption2)
.fixedSize(horizontal: false, vertical: true)
}
Section("Module Configuration") {
Section("Module Configuration - Non Functional interaction preview.") {
// NavigationLink {
// PositionConfig(node: nodes.first(where: { $0.num == connectedNodeNum }) ?? NodeInfoEntity())
// } label: {
//
// Image(systemName: "list.bullet.rectangle.fill")
// .symbolRenderingMode(.hierarchical)
//
// Text("Canned Messages")
// }
NavigationLink {
PositionConfig(node: nodes.first(where: { $0.num == connectedNodeNum }) ?? NodeInfoEntity())
ExternalNotificationConfig(node: nodes.first(where: { $0.num == connectedNodeNum }) ?? NodeInfoEntity())
} label: {
Image(systemName: "list.bullet.rectangle.fill")
Image(systemName: "megaphone")
.symbolRenderingMode(.hierarchical)
Text("Canned Messages")
Text("External Notification")
}
.disabled(true)
NavigationLink {
RangeTestConfig()
} label: {
@ -115,7 +130,18 @@ struct Settings: View {
Text("Range Test")
}
.disabled(!(nodes.first(where: { $0.num == connectedNodeNum })?.myInfo?.hasWifi ?? true) || bleManager.connectedPeripheral == nil)
//.disabled(!(nodes.first(where: { $0.num == connectedNodeNum })?.myInfo?.hasWifi ?? true) || bleManager.connectedPeripheral == nil)
NavigationLink {
SerialConfig()
} label: {
Image(systemName: "terminal")
.symbolRenderingMode(.hierarchical)
Text("Serial")
}
.disabled(false)
NavigationLink {
TelemetryConfig()
@ -126,11 +152,9 @@ struct Settings: View {
Text("Telemetry (Sensors)")
}
.disabled(true)
.disabled(false)
}
// Not Implemented:
// External Notifications - Not Working
// Serial Config - Not sure what the point is
// Store Forward Config - Not Working
// WiFi Config - Would break connection to device
// MQTT Config - Part of WiFi

View file

@ -1,38 +0,0 @@
//
// TelemetryConfig.swift
// Meshtastic Apple
//
// Copyright (c) Garth Vander Houwen 6/13/22.
//
import SwiftUI
struct TelemetryConfig: View {
@Environment(\.managedObjectContext) var context
@EnvironmentObject var bleManager: BLEManager
@State var isPowerSaving = false
@State var isAlwaysPowered = false
var body: some View {
VStack {
Form {
}
.navigationTitle("Telemetry Config")
.navigationBarItems(trailing:
ZStack {
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?????")
})
.onAppear {
self.bleManager.context = context
}
.navigationViewStyle(StackNavigationViewStyle())
}
}
}