mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Merge pull request #472 from meshtastic/2.2.21_Working_Changes
2.2.21 working changes
This commit is contained in:
commit
cd2d70c056
29 changed files with 846 additions and 153 deletions
|
|
@ -241,6 +241,7 @@
|
|||
DD1BF2F82776FE2E008C8D2F /* UserMessageList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserMessageList.swift; sourceTree = "<group>"; };
|
||||
DD2160AE28C5552500C17253 /* MQTTConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MQTTConfig.swift; sourceTree = "<group>"; };
|
||||
DD23A50E26FD1B4400D9B90C /* PeripheralModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeripheralModel.swift; sourceTree = "<group>"; };
|
||||
DD23D9AB2B7133F6003F5CBE /* MeshtasticDataModelV 25.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 25.xcdatamodel"; sourceTree = "<group>"; };
|
||||
DD2553562855B02500E55709 /* LoRaConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoRaConfig.swift; sourceTree = "<group>"; };
|
||||
DD2553582855B52700E55709 /* PositionConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PositionConfig.swift; sourceTree = "<group>"; };
|
||||
DD295CE92B323ED9002CC4AC /* MeshtasticDataModelV22.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV22.xcdatamodel; sourceTree = "<group>"; };
|
||||
|
|
@ -1492,7 +1493,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.2.20;
|
||||
MARKETING_VERSION = 2.2.21;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
|
|
@ -1526,7 +1527,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.2.20;
|
||||
MARKETING_VERSION = 2.2.21;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
|
|
@ -1648,7 +1649,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.2.20;
|
||||
MARKETING_VERSION = 2.2.21;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
|
@ -1681,7 +1682,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.2.20;
|
||||
MARKETING_VERSION = 2.2.21;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
|
@ -1792,6 +1793,7 @@
|
|||
DD3CC6BA28E366DF00FA9159 /* Meshtastic.xcdatamodeld */ = {
|
||||
isa = XCVersionGroup;
|
||||
children = (
|
||||
DD23D9AB2B7133F6003F5CBE /* MeshtasticDataModelV 25.xcdatamodel */,
|
||||
DDB234392B5CA9B000DA6FB1 /* MeshtasticDataModelV 24.xcdatamodel */,
|
||||
DD33DB602B3D1ECC003E1EA0 /* MeshtasticDataModelV 23.xcdatamodel */,
|
||||
DD295CE92B323ED9002CC4AC /* MeshtasticDataModelV22.xcdatamodel */,
|
||||
|
|
@ -1817,7 +1819,7 @@
|
|||
DD5D0A9A2931AD6B00F7EA61 /* MeshtasticDataModelV2.xcdatamodel */,
|
||||
DD3CC6BB28E366DF00FA9159 /* MeshtasticDataModel.xcdatamodel */,
|
||||
);
|
||||
currentVersion = DDB234392B5CA9B000DA6FB1 /* MeshtasticDataModelV 24.xcdatamodel */;
|
||||
currentVersion = DD23D9AB2B7133F6003F5CBE /* MeshtasticDataModelV 25.xcdatamodel */;
|
||||
name = Meshtastic.xcdatamodeld;
|
||||
path = Meshtastic/Meshtastic.xcdatamodeld;
|
||||
sourceTree = "<group>";
|
||||
|
|
|
|||
|
|
@ -12,22 +12,22 @@ enum DeviceRoles: Int, CaseIterable, Identifiable {
|
|||
|
||||
case client = 0
|
||||
case clientMute = 1
|
||||
case router = 2
|
||||
case routerClient = 3
|
||||
case repeater = 4
|
||||
case clientHidden = 8
|
||||
case tracker = 5
|
||||
case lostAndFound = 9
|
||||
case sensor = 6
|
||||
case tak = 7
|
||||
case clientHidden = 8
|
||||
case lostAndFound = 9
|
||||
|
||||
case repeater = 4
|
||||
case router = 2
|
||||
case routerClient = 3
|
||||
|
||||
var id: Int { self.rawValue }
|
||||
var name: String {
|
||||
switch self {
|
||||
case .client:
|
||||
return "Client"
|
||||
case .clientMute:
|
||||
return "Muted Client"
|
||||
return "Client Mute"
|
||||
case .router:
|
||||
return "Router"
|
||||
case .routerClient:
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ enum RegionCodes: Int, CaseIterable, Identifiable {
|
|||
case th = 12
|
||||
case ua433 = 14
|
||||
case ua868 = 15
|
||||
case my_433 = 16
|
||||
case my_919 = 17
|
||||
case lora24 = 13
|
||||
|
||||
var id: Int { self.rawValue }
|
||||
|
|
@ -61,9 +63,52 @@ enum RegionCodes: Int, CaseIterable, Identifiable {
|
|||
return "Ukraine 868mhz"
|
||||
case .lora24:
|
||||
return "2.4 GHZ"
|
||||
case .my_433:
|
||||
return "Malaysia 433mhz"
|
||||
case .my_919:
|
||||
return "Malaysia 919mhz"
|
||||
}
|
||||
}
|
||||
var dutyCycle: Int {
|
||||
switch self {
|
||||
case .unset:
|
||||
return 0
|
||||
case .us:
|
||||
return 100
|
||||
case .eu433:
|
||||
return 10
|
||||
case .eu868:
|
||||
return 10
|
||||
case .cn:
|
||||
return 100
|
||||
case .jp:
|
||||
return 100
|
||||
case .anz:
|
||||
return 100
|
||||
case .kr:
|
||||
return 100
|
||||
case .tw:
|
||||
return 100
|
||||
case .ru:
|
||||
return 100
|
||||
case .in:
|
||||
return 100
|
||||
case .nz865:
|
||||
return 100
|
||||
case .th:
|
||||
return 100
|
||||
case .ua433:
|
||||
return 10
|
||||
case .ua868:
|
||||
return 10
|
||||
case .lora24:
|
||||
return 100
|
||||
case .my_433:
|
||||
return 100
|
||||
case .my_919:
|
||||
return 100
|
||||
}
|
||||
}
|
||||
|
||||
func protoEnumValue() -> Config.LoRaConfig.RegionCode {
|
||||
|
||||
switch self {
|
||||
|
|
@ -99,6 +144,10 @@ enum RegionCodes: Int, CaseIterable, Identifiable {
|
|||
return Config.LoRaConfig.RegionCode.ua868
|
||||
case .lora24:
|
||||
return Config.LoRaConfig.RegionCode.lora24
|
||||
case .my_433:
|
||||
return Config.LoRaConfig.RegionCode.my433
|
||||
case .my_919:
|
||||
return Config.LoRaConfig.RegionCode.my919
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,3 +52,77 @@ enum GpsFormats: Int, CaseIterable, Identifiable {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum GpsUpdateIntervals: Int, CaseIterable, Identifiable {
|
||||
|
||||
case thirtySeconds = 30
|
||||
case oneMinute = 60
|
||||
case fiveMinutes = 300
|
||||
case tenMinutes = 600
|
||||
case fifteenMinutes = 900
|
||||
case thirtyMinutes = 1800
|
||||
case oneHour = 3600
|
||||
case sixHours = 21600
|
||||
case twelveHours = 43200
|
||||
case twentyFourHours = 86400
|
||||
case maxInt32 = 2147483647
|
||||
|
||||
var id: Int { self.rawValue }
|
||||
var description: String {
|
||||
switch self {
|
||||
case .thirtySeconds:
|
||||
return "interval.thirty.seconds".localized
|
||||
case .oneMinute:
|
||||
return "interval.one.minute".localized
|
||||
case .fiveMinutes:
|
||||
return "interval.five.minutes".localized
|
||||
case .tenMinutes:
|
||||
return "interval.ten.minutes".localized
|
||||
case .fifteenMinutes:
|
||||
return "interval.fifteen.minutes".localized
|
||||
case .thirtyMinutes:
|
||||
return "interval.thirty.minutes".localized
|
||||
case .oneHour:
|
||||
return "interval.one.hour".localized
|
||||
case .sixHours:
|
||||
return "interval.six.hours".localized
|
||||
case .twelveHours:
|
||||
return "interval.twelve.hours".localized
|
||||
case .twentyFourHours:
|
||||
return "interval.twentyfour.hours".localized
|
||||
case .maxInt32:
|
||||
return "on.boot".localized
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum GpsMode: Int, CaseIterable, Equatable {
|
||||
case disabled = 0
|
||||
case enabled = 1
|
||||
case notPresent = 2
|
||||
|
||||
var id: Int { self.rawValue }
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
case .disabled:
|
||||
return "gpsmode.disabled".localized
|
||||
case .enabled:
|
||||
return "gpsmode.enabled".localized
|
||||
case .notPresent:
|
||||
return "gpsmode.notPresent".localized
|
||||
}
|
||||
}
|
||||
func protoEnumValue() -> Config.PositionConfig.GpsMode {
|
||||
|
||||
switch self {
|
||||
|
||||
case .enabled:
|
||||
return Config.PositionConfig.GpsMode.enabled
|
||||
case .disabled:
|
||||
return Config.PositionConfig.GpsMode.disabled
|
||||
case .notPresent:
|
||||
return Config.PositionConfig.GpsMode.notPresent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import Foundation
|
|||
|
||||
extension UserDefaults {
|
||||
enum Keys: String, CaseIterable {
|
||||
case enableRangeTest
|
||||
case preferredPeripheralId
|
||||
case preferredPeripheralNum
|
||||
case provideLocation
|
||||
|
|
@ -27,18 +26,12 @@ extension UserDefaults {
|
|||
case mapUseLegacy
|
||||
case enableDetectionNotifications
|
||||
case detectionSensorRole
|
||||
case enableSmartPosition
|
||||
}
|
||||
|
||||
func reset() {
|
||||
Keys.allCases.forEach { removeObject(forKey: $0.rawValue) }
|
||||
}
|
||||
static var blockRangeTest: Bool {
|
||||
get {
|
||||
UserDefaults.standard.bool(forKey: "blockRangeTest")
|
||||
} set {
|
||||
UserDefaults.standard.set(newValue, forKey: "blockRangeTest")
|
||||
}
|
||||
}
|
||||
static var preferredPeripheralId: String {
|
||||
get {
|
||||
UserDefaults.standard.string(forKey: "preferredPeripheralId") ?? ""
|
||||
|
|
@ -201,4 +194,12 @@ extension UserDefaults {
|
|||
UserDefaults.standard.set(newValue.rawValue, forKey: "detectionSensorRole")
|
||||
}
|
||||
}
|
||||
static var enableSmartPosition: Bool {
|
||||
get {
|
||||
UserDefaults.standard.bool(forKey: "enableSmartPosition")
|
||||
}
|
||||
set {
|
||||
UserDefaults.standard.set(newValue, forKey: "enableSmartPosition")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -594,7 +594,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
// Log any other unknownApp calls
|
||||
if !nowKnown { MeshLogger.log("🕸️ MESH PACKET received for Unknown App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure")") }
|
||||
case .textMessageApp, .detectionSensorApp:
|
||||
textMessageAppPacket(packet: decodedInfo.packet, blockRangeTest: UserDefaults.blockRangeTest, connectedNode: (self.connectedPeripheral != nil ? connectedPeripheral.num : 0), context: context!)
|
||||
textMessageAppPacket(packet: decodedInfo.packet, connectedNode: (self.connectedPeripheral != nil ? connectedPeripheral.num : 0), context: context!)
|
||||
case .remoteHardwareApp:
|
||||
MeshLogger.log("🕸️ MESH PACKET received for Remote Hardware App UNHANDLED \((try? decodedInfo.packet.jsonString()) ?? "JSON Decode Failure")")
|
||||
case .positionApp:
|
||||
|
|
@ -620,8 +620,8 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
MeshLogger.log("🕸️ MESH PACKET received for Store and Forward App - Store and Forward is disabled.")
|
||||
}
|
||||
case .rangeTestApp:
|
||||
if wantRangeTestPackets && !UserDefaults.blockRangeTest {
|
||||
textMessageAppPacket(packet: decodedInfo.packet, blockRangeTest: false, connectedNode: (self.connectedPeripheral != nil ? connectedPeripheral.num : 0), context: context!)
|
||||
if wantRangeTestPackets {
|
||||
textMessageAppPacket(packet: decodedInfo.packet, connectedNode: (self.connectedPeripheral != nil ? connectedPeripheral.num : 0), context: context!)
|
||||
}
|
||||
else {
|
||||
MeshLogger.log("🕸️ MESH PACKET received for Range Test App Range testing is disabled.")
|
||||
|
|
@ -976,10 +976,6 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
|
||||
if let lastLocation = LocationsHandler.shared.locationsArray.last {
|
||||
|
||||
/// Throw out crappy locations and only send a position if we are connected to a device
|
||||
if fromNodeNum <= 0 || lastLocation.horizontalAccuracy < 0 || lastLocation.horizontalAccuracy > 100 {
|
||||
return false
|
||||
}
|
||||
positionPacket.latitudeI = Int32(lastLocation.coordinate.latitude * 1e7)
|
||||
positionPacket.longitudeI = Int32(lastLocation.coordinate.longitude * 1e7)
|
||||
let timestamp = lastLocation.timestamp
|
||||
|
|
@ -2386,7 +2382,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
/// send a request for ClientHistory with a time period matching the heartbeat
|
||||
var sfPacket = StoreAndForward()
|
||||
sfPacket.rr = StoreAndForward.RequestResponse.clientHistory
|
||||
sfPacket.history.window = 18000000 // storeAndForwardMessage.heartbeat.period
|
||||
sfPacket.history.window = 120 // storeAndForwardMessage.heartbeat.period
|
||||
var meshPacket: MeshPacket = MeshPacket()
|
||||
meshPacket.to = UInt32(packet.from)
|
||||
meshPacket.from = UInt32(connectedNodeNum)
|
||||
|
|
@ -2432,6 +2428,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
case .clientAbort:
|
||||
MeshLogger.log("🛑 Store and Forward \(storeAndForwardMessage.rr) message received \(storeAndForwardMessage)")
|
||||
case .UNRECOGNIZED:
|
||||
textMessageAppPacket(packet: packet, connectedNode: connectedNodeNum, context: context)
|
||||
MeshLogger.log("📮 Store and Forward \(storeAndForwardMessage.rr) message received \(storeAndForwardMessage)")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import CoreLocation
|
|||
static let shared = LocationsHandler() // Create a single, shared instance of the object.
|
||||
private let manager: CLLocationManager
|
||||
private var background: CLBackgroundActivitySession?
|
||||
var enableSmartPosition: Bool
|
||||
var enableSmartPosition: Bool = UserDefaults.enableSmartPosition
|
||||
|
||||
@Published var locationsArray: [CLLocation]
|
||||
@Published var isStationary = false
|
||||
|
|
@ -41,8 +41,8 @@ import CoreLocation
|
|||
|
||||
private init() {
|
||||
self.manager = CLLocationManager() // Creating a location manager instance is safe to call here in `MainActor`.
|
||||
self.manager.allowsBackgroundLocationUpdates = true
|
||||
locationsArray = [CLLocation]()
|
||||
enableSmartPosition = true
|
||||
}
|
||||
|
||||
func startLocationUpdates() {
|
||||
|
|
@ -55,7 +55,7 @@ import CoreLocation
|
|||
self.updatesStarted = true
|
||||
let updates = CLLocationUpdate.liveUpdates()
|
||||
for try await update in updates {
|
||||
if !self.updatesStarted { break } // End location updates by breaking out of the loop.
|
||||
if !self.updatesStarted { break }
|
||||
if let loc = update.location {
|
||||
self.isStationary = update.isStationary
|
||||
|
||||
|
|
|
|||
|
|
@ -721,13 +721,9 @@ func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManage
|
|||
}
|
||||
}
|
||||
|
||||
func textMessageAppPacket(packet: MeshPacket, blockRangeTest: Bool, connectedNode: Int64, context: NSManagedObjectContext) {
|
||||
func textMessageAppPacket(packet: MeshPacket, connectedNode: Int64, context: NSManagedObjectContext) {
|
||||
|
||||
if let messageText = String(bytes: packet.decoded.payload, encoding: .utf8) {
|
||||
|
||||
if blockRangeTest && messageText.starts(with: "seq ") {
|
||||
return
|
||||
}
|
||||
|
||||
MeshLogger.log("💬 \("mesh.log.textmessage.received".localized)")
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,6 @@
|
|||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>_XCCurrentVersionName</key>
|
||||
<string>MeshtasticDataModelV 24.xcdatamodel</string>
|
||||
<string>MeshtasticDataModelV 25.xcdatamodel</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,412 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="22522" systemVersion="23D56" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||
<entity name="AmbientLightingConfigEntity" representedClassName="AmbientLightingConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="blue" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="current" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="green" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="ledState" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="red" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="ambientLightingConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="ambientLightingConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="BluetoothConfigEntity" representedClassName="BluetoothConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="fixedPin" optional="YES" attributeType="Integer 32" defaultValueString="123456" usesScalarValueType="YES"/>
|
||||
<attribute name="mode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="bluetoothConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="bluetoothConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="CannedMessageConfigEntity" representedClassName="CannedMessageConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="inputbrokerEventCcw" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="inputbrokerEventCw" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="inputbrokerEventPress" optional="YES" attributeType="Integer 32" defaultValueString="0" 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="messages" optional="YES" attributeType="String" minValueString="0" maxValueString="198"/>
|
||||
<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="cannedMessageConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="ChannelEntity" representedClassName="ChannelEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="downlinkEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="id" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="index" attributeType="Integer 32" minValueString="0" maxValueString="13" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="mute" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="name" optional="YES" attributeType="String"/>
|
||||
<attribute name="psk" optional="YES" attributeType="Binary"/>
|
||||
<attribute name="role" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="uplinkEnabled" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<relationship name="myInfoChannel" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MyInfoEntity" inverseName="channels" inverseEntity="MyInfoEntity"/>
|
||||
<fetchedProperty name="allPrivateMessages" optional="YES">
|
||||
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="channel == $FETCH_SOURCE.index && toUser == nil AND isEmoji == false"/>
|
||||
</fetchedProperty>
|
||||
<uniquenessConstraints>
|
||||
<uniquenessConstraint>
|
||||
<constraint value="index"/>
|
||||
</uniquenessConstraint>
|
||||
</uniquenessConstraints>
|
||||
</entity>
|
||||
<entity name="DetectionSensorConfigEntity" representedClassName="DetectionSensorConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="detectionTriggeredHigh" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="enabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="minimumBroadcastSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="monitorPin" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="name" optional="YES" attributeType="String"/>
|
||||
<attribute name="sendBell" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="stateBroadcastSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="usePullup" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<relationship name="detectionSensorConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="detectionSensorConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="DeviceConfigEntity" representedClassName="DeviceConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="buttonGpio" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="buzzerGpio" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="debugLogEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="disableTripleClick" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="doubleTapAsButtonPress" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="isManaged" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="nodeInfoBroadcastSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="rebroadcastMode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="role" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="serialEnabled" optional="YES" attributeType="Boolean" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="deviceConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="deviceConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="DeviceMetadataEntity" representedClassName="DeviceMetadataEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="canShutdown" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="deviceStateVersion" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="firmwareVersion" optional="YES" attributeType="String"/>
|
||||
<attribute name="hasBluetooth" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="hasEthernet" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="hasWifi" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="hwModel" optional="YES" attributeType="String"/>
|
||||
<attribute name="positionFlags" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="role" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="metadataNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="metadata" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="DisplayConfigEntity" representedClassName="DisplayConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="compassNorthTop" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="displayMode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="flipScreen" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="gpsFormat" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="headingBold" optional="YES" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
||||
<attribute name="oledType" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="screenCarouselInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="screenOnSeconds" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="units" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="wakeOnTapOrMotion" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<relationship name="displayConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="displayConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="ExternalNotificationConfigEntity" representedClassName="ExternalNotificationConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="active" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="alertBell" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="alertBellBuzzer" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="alertBellVibra" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="alertMessage" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="alertMessageBuzzer" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="alertMessageVibra" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="nagTimeout" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="output" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="outputBuzzer" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="outputMilliseconds" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="outputVibra" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="useI2SAsBuzzer" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="usePWM" optional="YES" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
||||
<relationship name="externalNotificationConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="externalNotificationConfig" inverseEntity="NodeInfoEntity"/>
|
||||
<fetchedProperty name="fetchedProperty" optional="YES">
|
||||
<fetchRequest name="fetchedPropertyFetchRequest" entity="ExternalNotificationConfigEntity"/>
|
||||
</fetchedProperty>
|
||||
</entity>
|
||||
<entity name="LocationEntity" representedClassName="LocationEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="altitude" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="heading" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="id" optional="YES" attributeType="Integer 32" usesScalarValueType="YES"/>
|
||||
<attribute name="latitudeI" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="longitudeI" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="speed" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="routeLocation" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="RouteEntity" inverseName="locations" inverseEntity="RouteEntity"/>
|
||||
</entity>
|
||||
<entity name="LoRaConfigEntity" representedClassName="LoRaConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="bandwidth" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="channelNum" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="codingRate" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="frequencyOffset" optional="YES" attributeType="Float" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="hopLimit" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="ignoreMqtt" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="modemPreset" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="overrideDutyCycle" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="overrideFrequency" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="regionCode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="spreadFactor" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="sx126xRxBoostedGain" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="txEnabled" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
||||
<attribute name="txPower" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="usePreset" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
||||
<relationship name="loRaConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="loRaConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="MessageEntity" representedClassName="MessageEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="ackError" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="ackSNR" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="ackTimestamp" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="admin" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="adminDescription" optional="YES" attributeType="String"/>
|
||||
<attribute name="channel" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="isEmoji" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="messageId" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="messagePayload" optional="YES" attributeType="String" defaultValueString=""/>
|
||||
<attribute name="messagePayloadMarkdown" optional="YES" attributeType="String"/>
|
||||
<attribute name="messageTimestamp" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="portNum" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="read" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="realACK" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="receivedACK" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="receivedTimestamp" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="replyID" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="rssi" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="snr" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<relationship name="fromUser" optional="YES" maxCount="1" deletionRule="Nullify" ordered="YES" destinationEntity="UserEntity" inverseName="sentMessages" inverseEntity="UserEntity"/>
|
||||
<relationship name="toUser" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="UserEntity" inverseName="receivedMessages" inverseEntity="UserEntity"/>
|
||||
<fetchedProperty name="tapbacks" optional="YES">
|
||||
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="replyID == $FETCH_SOURCE.messageId AND isEmoji == true"/>
|
||||
</fetchedProperty>
|
||||
<uniquenessConstraints>
|
||||
<uniquenessConstraint>
|
||||
<constraint value="messageId"/>
|
||||
</uniquenessConstraint>
|
||||
</uniquenessConstraints>
|
||||
</entity>
|
||||
<entity name="MQTTConfigEntity" representedClassName="MQTTConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="address" optional="YES" attributeType="String" maxValueString="30"/>
|
||||
<attribute name="enabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="encryptionEnabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="jsonEnabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="password" optional="YES" attributeType="String" maxValueString="30"/>
|
||||
<attribute name="proxyToClientEnabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="root" optional="YES" attributeType="String" defaultValueString="msh"/>
|
||||
<attribute name="tlsEnabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="username" optional="YES" attributeType="String" maxValueString="30"/>
|
||||
<relationship name="mqttConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="mqttConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="MyInfoEntity" representedClassName="MyInfoEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="adminIndex" optional="YES" attributeType="Integer 32" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="bleName" optional="YES" attributeType="String"/>
|
||||
<attribute name="minAppVersion" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="myNodeNum" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="peripheralId" optional="YES" attributeType="String"/>
|
||||
<attribute name="rebootCount" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="channels" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="ChannelEntity" inverseName="myInfoChannel" inverseEntity="ChannelEntity"/>
|
||||
<relationship name="myInfoNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="myInfo" inverseEntity="NodeInfoEntity"/>
|
||||
<fetchedProperty name="allMessages" optional="YES">
|
||||
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="toUser == nil"/>
|
||||
</fetchedProperty>
|
||||
<uniquenessConstraints>
|
||||
<uniquenessConstraint>
|
||||
<constraint value="myNodeNum"/>
|
||||
</uniquenessConstraint>
|
||||
</uniquenessConstraints>
|
||||
</entity>
|
||||
<entity name="NetworkConfigEntity" representedClassName="NetworkConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="dns" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="ethEnabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="gateway" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="ip" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="ntpServer" optional="YES" attributeType="String"/>
|
||||
<attribute name="subnet" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="wifiEnabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="wifiMode" optional="YES" attributeType="Integer 32" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="wifiPsk" optional="YES" attributeType="String" minValueString="0" maxValueString="60"/>
|
||||
<attribute name="wifiSsid" optional="YES" attributeType="String" minValueString="0" maxValueString="30"/>
|
||||
<relationship name="networkConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="networkConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="NodeInfoEntity" representedClassName="NodeInfoEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="bleName" optional="YES" attributeType="String"/>
|
||||
<attribute name="channel" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="detection" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="environment" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="id" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="lastHeard" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="peripheralId" optional="YES" attributeType="String"/>
|
||||
<attribute name="rssi" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="snr" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="viaMqtt" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<relationship name="ambientLightingConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="AmbientLightingConfigEntity" inverseName="ambientLightingConfigNode" inverseEntity="AmbientLightingConfigEntity"/>
|
||||
<relationship name="bluetoothConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="BluetoothConfigEntity" inverseName="bluetoothConfigNode" inverseEntity="BluetoothConfigEntity"/>
|
||||
<relationship name="cannedMessageConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="CannedMessageConfigEntity" inverseName="cannedMessagesConfigNode" inverseEntity="CannedMessageConfigEntity"/>
|
||||
<relationship name="detectionSensorConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="DetectionSensorConfigEntity" inverseName="detectionSensorConfigNode" inverseEntity="DetectionSensorConfigEntity"/>
|
||||
<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="externalNotificationConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="ExternalNotificationConfigEntity" inverseName="externalNotificationConfigNode" inverseEntity="ExternalNotificationConfigEntity"/>
|
||||
<relationship name="loRaConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="LoRaConfigEntity" inverseName="loRaConfigNode" inverseEntity="LoRaConfigEntity"/>
|
||||
<relationship name="metadata" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="DeviceMetadataEntity" inverseName="metadataNode" inverseEntity="DeviceMetadataEntity"/>
|
||||
<relationship name="mqttConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MQTTConfigEntity" inverseName="mqttConfigNode" inverseEntity="MQTTConfigEntity"/>
|
||||
<relationship name="myInfo" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="MyInfoEntity" inverseName="myInfoNode" inverseEntity="MyInfoEntity"/>
|
||||
<relationship name="networkConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NetworkConfigEntity" inverseName="networkConfigNode" inverseEntity="NetworkConfigEntity"/>
|
||||
<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="rtttlConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="RTTTLConfigEntity" inverseName="rtttlConfigNode" inverseEntity="RTTTLConfigEntity"/>
|
||||
<relationship name="serialConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="SerialConfigEntity" inverseName="serialConfigNode" inverseEntity="SerialConfigEntity"/>
|
||||
<relationship name="storeForwardConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="StoreForwardConfigEntity" inverseName="storeForwardConfigNode" inverseEntity="StoreForwardConfigEntity"/>
|
||||
<relationship name="telemetries" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="TelemetryEntity" inverseName="nodeTelemetry" inverseEntity="TelemetryEntity"/>
|
||||
<relationship name="telemetryConfig" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="TelemetryConfigEntity" inverseName="telemetryConfigNode" inverseEntity="TelemetryConfigEntity"/>
|
||||
<relationship name="traceRoutes" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="TraceRouteEntity" inverseName="node" inverseEntity="TraceRouteEntity"/>
|
||||
<relationship name="user" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="UserEntity" inverseName="userNode" inverseEntity="UserEntity"/>
|
||||
<uniquenessConstraints>
|
||||
<uniquenessConstraint>
|
||||
<constraint value="num"/>
|
||||
</uniquenessConstraint>
|
||||
</uniquenessConstraints>
|
||||
</entity>
|
||||
<entity name="PositionConfigEntity" representedClassName="PositionConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="broadcastSmartMinimumDistance" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="broadcastSmartMinimumIntervalSecs" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="deviceGpsEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="fixedPosition" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="gpsAttemptTime" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="gpsEnGpio" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="gpsMode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="gpsUpdateInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="positionBroadcastSeconds" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="positionFlags" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="rxGpio" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="smartPositionEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="txGpio" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="positionConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="positionConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="PositionEntity" representedClassName="PositionEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="altitude" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="heading" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="latest" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="latitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="longitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="rssi" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="satsInView" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="seqNo" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="snr" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="speed" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<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="save" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="sender" optional="YES" attributeType="Integer 32" usesScalarValueType="YES"/>
|
||||
<relationship name="rangeTestConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="rangeTestConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="RouteEntity" representedClassName="RouteEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="color" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="date" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="enabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="id" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="name" optional="YES" attributeType="String"/>
|
||||
<attribute name="notes" optional="YES" attributeType="String"/>
|
||||
<relationship name="locations" optional="YES" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="LocationEntity" inverseName="routeLocation" inverseEntity="LocationEntity"/>
|
||||
</entity>
|
||||
<entity name="RTTTLConfigEntity" representedClassName="RTTTLConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="ringtone" optional="YES" attributeType="String" maxValueString="228" defaultValueString=""/>
|
||||
<relationship name="rtttlConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="rtttlConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="SerialConfigEntity" representedClassName="SerialConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="baudRate" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="echo" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="enabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="mode" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="overrideConsoleSerialPort" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="rxd" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="timeout" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="txd" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="serialConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="serialConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="StoreForwardConfigEntity" representedClassName="StoreForwardConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="enabled" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="heartbeat" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="YES"/>
|
||||
<attribute name="historyReturnMax" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="historyReturnWindow" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="records" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="storeForwardConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="storeForwardConfig" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="TelemetryConfigEntity" representedClassName="TelemetryConfigEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="deviceUpdateInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="environmentDisplayFahrenheit" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="environmentMeasurementEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="environmentScreenEnabled" optional="YES" attributeType="Boolean" usesScalarValueType="YES"/>
|
||||
<attribute name="environmentUpdateInterval" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<relationship name="telemetryConfigNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="telemetryConfig" 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"/>
|
||||
<attribute name="batteryLevel" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="channelUtilization" optional="YES" attributeType="Float" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="current" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="gasResistance" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="metricsType" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="relativeHumidity" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="rssi" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="snr" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="temperature" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="time" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="voltage" optional="YES" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<relationship name="nodeTelemetry" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="telemetries" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="TraceRouteEntity" representedClassName="TraceRouteEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="altitude" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="hasPositions" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="id" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="latitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="longitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="num" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="response" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="route" optional="YES" attributeType="Transformable" customClassName="[UInt32]"/>
|
||||
<attribute name="routeText" optional="YES" attributeType="String"/>
|
||||
<attribute name="time" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<relationship name="hops" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="TraceRouteHopEntity" inverseName="traceRoute" inverseEntity="TraceRouteHopEntity"/>
|
||||
<relationship name="node" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="traceRoutes" inverseEntity="NodeInfoEntity"/>
|
||||
</entity>
|
||||
<entity name="TraceRouteHopEntity" representedClassName="TraceRouteHopEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="altitude" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="latitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="longitudeI" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="name" optional="YES" attributeType="String"/>
|
||||
<attribute name="num" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="time" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<relationship name="traceRoute" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="TraceRouteEntity" inverseName="hops" inverseEntity="TraceRouteEntity"/>
|
||||
</entity>
|
||||
<entity name="UserEntity" representedClassName="UserEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="hwModel" attributeType="String"/>
|
||||
<attribute name="isLicensed" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="lastMessage" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="longName" attributeType="String"/>
|
||||
<attribute name="mute" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="num" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="role" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="shortName" attributeType="String"/>
|
||||
<attribute name="userId" attributeType="String"/>
|
||||
<attribute name="vip" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<relationship name="receivedMessages" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="MessageEntity" inverseName="toUser" inverseEntity="MessageEntity"/>
|
||||
<relationship name="sentMessages" optional="YES" toMany="YES" deletionRule="Nullify" ordered="YES" destinationEntity="MessageEntity" inverseName="fromUser" inverseEntity="MessageEntity"/>
|
||||
<relationship name="userNode" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="NodeInfoEntity" inverseName="user" inverseEntity="NodeInfoEntity"/>
|
||||
<fetchedProperty name="adminMessages" optional="YES">
|
||||
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="(fromUser.num == $FETCH_SOURCE.num) AND isEmoji == false AND admin = true"/>
|
||||
</fetchedProperty>
|
||||
<fetchedProperty name="allMessages" optional="YES">
|
||||
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="((toUser.num == $FETCH_SOURCE.num) OR (fromUser.num == $FETCH_SOURCE.num)) AND toUser != nil AND fromUser != nil AND isEmoji == false AND admin = false AND portNum != 10 "/>
|
||||
</fetchedProperty>
|
||||
<fetchedProperty name="detectionSensorMessages" optional="YES">
|
||||
<fetchRequest name="fetchedPropertyFetchRequest" entity="MessageEntity" predicateString="(fromUser.num == $FETCH_SOURCE.num) AND portNum = 10"/>
|
||||
</fetchedProperty>
|
||||
</entity>
|
||||
<entity name="WaypointEntity" representedClassName="WaypointEntity" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="created" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="expire" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="icon" optional="YES" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="id" attributeType="Integer 64" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="lastUpdated" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="latitudeI" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="locked" attributeType="Integer 64" defaultValueString="NO" usesScalarValueType="YES"/>
|
||||
<attribute name="longDescription" optional="YES" attributeType="String" maxValueString="100"/>
|
||||
<attribute name="longitudeI" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES"/>
|
||||
<attribute name="name" attributeType="String" minValueString="1" maxValueString="30"/>
|
||||
</entity>
|
||||
</model>
|
||||
|
|
@ -61,8 +61,14 @@ class PersistenceController {
|
|||
do {
|
||||
|
||||
try persistentStoreCoordinator.destroyPersistentStore(at: url, ofType: NSSQLiteStoreType, options: nil)
|
||||
try persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: nil)
|
||||
print("💥 CoreData database truncated. All app data has been erased.")
|
||||
|
||||
do {
|
||||
try persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: nil)
|
||||
} catch let error {
|
||||
print("💣 Failed to re-create CoreData database: " + error.localizedDescription)
|
||||
try persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: url, options: nil)
|
||||
}
|
||||
|
||||
} catch let error {
|
||||
print("💣 Failed to destroy CoreData database, delete the app and re-install to clear data. Attempted to clear persistent store: " + error.localizedDescription)
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext)
|
|||
newNode.lastHeard = Date(timeIntervalSince1970: TimeInterval(Int64(packet.rxTime)))
|
||||
newNode.snr = packet.rxSnr
|
||||
newNode.rssi = packet.rxRssi
|
||||
newNode.viaMqtt = packet.viaMqtt
|
||||
if let nodeInfoMessage = try? NodeInfo(serializedData: packet.decoded.payload) {
|
||||
newNode.channel = Int32(nodeInfoMessage.channel)
|
||||
print(packet.channel)
|
||||
|
|
@ -161,6 +162,7 @@ func upsertNodeInfoPacket (packet: MeshPacket, context: NSManagedObjectContext)
|
|||
}
|
||||
fetchedNode[0].snr = packet.rxSnr
|
||||
fetchedNode[0].rssi = packet.rxRssi
|
||||
fetchedNode[0].viaMqtt = packet.viaMqtt
|
||||
|
||||
if let nodeInfoMessage = try? NodeInfo(serializedData: packet.decoded.payload) {
|
||||
fetchedNode[0].channel = Int32(nodeInfoMessage.channel)
|
||||
|
|
@ -277,6 +279,7 @@ func upsertPositionPacket (packet: MeshPacket, context: NSManagedObjectContext)
|
|||
}
|
||||
fetchedNode[0].snr = packet.rxSnr
|
||||
fetchedNode[0].rssi = packet.rxRssi
|
||||
fetchedNode[0].viaMqtt = packet.viaMqtt
|
||||
fetchedNode[0].positions = mutablePositions.copy() as? NSOrderedSet
|
||||
|
||||
do {
|
||||
|
|
@ -492,6 +495,7 @@ func upsertLoRaConfigPacket(config: Meshtastic.Config.LoRaConfig, nodeNum: Int64
|
|||
newLoRaConfig.txEnabled = config.txEnabled
|
||||
newLoRaConfig.channelNum = Int32(config.channelNum)
|
||||
newLoRaConfig.sx126xRxBoostedGain = config.sx126XRxBoostedGain
|
||||
newLoRaConfig.ignoreMqtt = config.ignoreMqtt
|
||||
fetchedNode[0].loRaConfig = newLoRaConfig
|
||||
} else {
|
||||
fetchedNode[0].loRaConfig?.regionCode = Int32(config.region.rawValue)
|
||||
|
|
@ -508,6 +512,8 @@ func upsertLoRaConfigPacket(config: Meshtastic.Config.LoRaConfig, nodeNum: Int64
|
|||
fetchedNode[0].loRaConfig?.txEnabled = config.txEnabled
|
||||
fetchedNode[0].loRaConfig?.channelNum = Int32(config.channelNum)
|
||||
fetchedNode[0].loRaConfig?.sx126xRxBoostedGain = config.sx126XRxBoostedGain
|
||||
fetchedNode[0].loRaConfig?.ignoreMqtt = config.ignoreMqtt
|
||||
fetchedNode[0].loRaConfig?.sx126xRxBoostedGain = config.sx126XRxBoostedGain
|
||||
}
|
||||
do {
|
||||
try context.save()
|
||||
|
|
@ -592,6 +598,7 @@ func upsertPositionConfigPacket(config: Meshtastic.Config.PositionConfig, nodeNu
|
|||
let newPositionConfig = PositionConfigEntity(context: context)
|
||||
newPositionConfig.smartPositionEnabled = config.positionBroadcastSmartEnabled
|
||||
newPositionConfig.deviceGpsEnabled = config.gpsEnabled
|
||||
newPositionConfig.gpsMode = Int32(config.gpsMode.rawValue)
|
||||
newPositionConfig.rxGpio = Int32(config.rxGpio)
|
||||
newPositionConfig.txGpio = Int32(config.txGpio)
|
||||
newPositionConfig.gpsEnGpio = Int32(config.gpsEnGpio)
|
||||
|
|
@ -601,11 +608,12 @@ func upsertPositionConfigPacket(config: Meshtastic.Config.PositionConfig, nodeNu
|
|||
newPositionConfig.broadcastSmartMinimumDistance = Int32(config.broadcastSmartMinimumDistance)
|
||||
newPositionConfig.positionFlags = Int32(config.positionFlags)
|
||||
newPositionConfig.gpsAttemptTime = 900
|
||||
newPositionConfig.gpsUpdateInterval = 120
|
||||
newPositionConfig.gpsUpdateInterval = Int32(config.gpsUpdateInterval)
|
||||
fetchedNode[0].positionConfig = newPositionConfig
|
||||
} else {
|
||||
fetchedNode[0].positionConfig?.smartPositionEnabled = config.positionBroadcastSmartEnabled
|
||||
fetchedNode[0].positionConfig?.deviceGpsEnabled = config.gpsEnabled
|
||||
fetchedNode[0].positionConfig?.gpsMode = Int32(config.gpsMode.rawValue)
|
||||
fetchedNode[0].positionConfig?.rxGpio = Int32(config.rxGpio)
|
||||
fetchedNode[0].positionConfig?.txGpio = Int32(config.txGpio)
|
||||
fetchedNode[0].positionConfig?.gpsEnGpio = Int32(config.gpsEnGpio)
|
||||
|
|
@ -614,7 +622,7 @@ func upsertPositionConfigPacket(config: Meshtastic.Config.PositionConfig, nodeNu
|
|||
fetchedNode[0].positionConfig?.broadcastSmartMinimumIntervalSecs = Int32(config.broadcastSmartMinimumIntervalSecs)
|
||||
fetchedNode[0].positionConfig?.broadcastSmartMinimumDistance = Int32(config.broadcastSmartMinimumDistance)
|
||||
fetchedNode[0].positionConfig?.gpsAttemptTime = 900
|
||||
fetchedNode[0].positionConfig?.gpsUpdateInterval = 120
|
||||
fetchedNode[0].positionConfig?.gpsUpdateInterval = Int32(config.gpsUpdateInterval)
|
||||
fetchedNode[0].positionConfig?.positionFlags = Int32(config.positionFlags)
|
||||
}
|
||||
do {
|
||||
|
|
|
|||
|
|
@ -235,6 +235,16 @@ struct AdminMessage {
|
|||
set {payloadVariant = .enterDfuModeRequest(newValue)}
|
||||
}
|
||||
|
||||
///
|
||||
/// Delete the file by the specified path from the device
|
||||
var deleteFileRequest: String {
|
||||
get {
|
||||
if case .deleteFileRequest(let v)? = payloadVariant {return v}
|
||||
return String()
|
||||
}
|
||||
set {payloadVariant = .deleteFileRequest(newValue)}
|
||||
}
|
||||
|
||||
///
|
||||
/// Set the owner for this node
|
||||
var setOwner: User {
|
||||
|
|
@ -460,6 +470,9 @@ struct AdminMessage {
|
|||
/// Only implemented on NRF52 currently
|
||||
case enterDfuModeRequest(Bool)
|
||||
///
|
||||
/// Delete the file by the specified path from the device
|
||||
case deleteFileRequest(String)
|
||||
///
|
||||
/// Set the owner for this node
|
||||
case setOwner(User)
|
||||
///
|
||||
|
|
@ -598,6 +611,10 @@ struct AdminMessage {
|
|||
guard case .enterDfuModeRequest(let l) = lhs, case .enterDfuModeRequest(let r) = rhs else { preconditionFailure() }
|
||||
return l == r
|
||||
}()
|
||||
case (.deleteFileRequest, .deleteFileRequest): return {
|
||||
guard case .deleteFileRequest(let l) = lhs, case .deleteFileRequest(let r) = rhs else { preconditionFailure() }
|
||||
return l == r
|
||||
}()
|
||||
case (.setOwner, .setOwner): return {
|
||||
guard case .setOwner(let l) = lhs, case .setOwner(let r) = rhs else { preconditionFailure() }
|
||||
return l == r
|
||||
|
|
@ -953,6 +970,7 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
|
|||
19: .standard(proto: "get_node_remote_hardware_pins_request"),
|
||||
20: .standard(proto: "get_node_remote_hardware_pins_response"),
|
||||
21: .standard(proto: "enter_dfu_mode_request"),
|
||||
22: .standard(proto: "delete_file_request"),
|
||||
32: .standard(proto: "set_owner"),
|
||||
33: .standard(proto: "set_channel"),
|
||||
34: .standard(proto: "set_config"),
|
||||
|
|
@ -1176,6 +1194,14 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
|
|||
self.payloadVariant = .enterDfuModeRequest(v)
|
||||
}
|
||||
}()
|
||||
case 22: try {
|
||||
var v: String?
|
||||
try decoder.decodeSingularStringField(value: &v)
|
||||
if let v = v {
|
||||
if self.payloadVariant != nil {try decoder.handleConflictingOneOf()}
|
||||
self.payloadVariant = .deleteFileRequest(v)
|
||||
}
|
||||
}()
|
||||
case 32: try {
|
||||
var v: User?
|
||||
var hadOneofValue = false
|
||||
|
|
@ -1407,6 +1433,10 @@ extension AdminMessage: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementat
|
|||
guard case .enterDfuModeRequest(let v)? = self.payloadVariant else { preconditionFailure() }
|
||||
try visitor.visitSingularBoolField(value: v, fieldNumber: 21)
|
||||
}()
|
||||
case .deleteFileRequest?: try {
|
||||
guard case .deleteFileRequest(let v)? = self.payloadVariant else { preconditionFailure() }
|
||||
try visitor.visitSingularStringField(value: v, fieldNumber: 22)
|
||||
}()
|
||||
case .setOwner?: try {
|
||||
guard case .setOwner(let v)? = self.payloadVariant else { preconditionFailure() }
|
||||
try visitor.visitSingularMessageField(value: v, fieldNumber: 32)
|
||||
|
|
|
|||
|
|
@ -415,6 +415,10 @@ struct Config {
|
|||
/// (Re)define PIN_GPS_EN for your board.
|
||||
var gpsEnGpio: UInt32 = 0
|
||||
|
||||
///
|
||||
/// Set where GPS is enabled, disabled, or not present
|
||||
var gpsMode: Config.PositionConfig.GpsMode = .disabled
|
||||
|
||||
var unknownFields = SwiftProtobuf.UnknownStorage()
|
||||
|
||||
///
|
||||
|
|
@ -516,6 +520,46 @@ struct Config {
|
|||
|
||||
}
|
||||
|
||||
enum GpsMode: SwiftProtobuf.Enum {
|
||||
typealias RawValue = Int
|
||||
|
||||
///
|
||||
/// GPS is present but disabled
|
||||
case disabled // = 0
|
||||
|
||||
///
|
||||
/// GPS is present and enabled
|
||||
case enabled // = 1
|
||||
|
||||
///
|
||||
/// GPS is not present on the device
|
||||
case notPresent // = 2
|
||||
case UNRECOGNIZED(Int)
|
||||
|
||||
init() {
|
||||
self = .disabled
|
||||
}
|
||||
|
||||
init?(rawValue: Int) {
|
||||
switch rawValue {
|
||||
case 0: self = .disabled
|
||||
case 1: self = .enabled
|
||||
case 2: self = .notPresent
|
||||
default: self = .UNRECOGNIZED(rawValue)
|
||||
}
|
||||
}
|
||||
|
||||
var rawValue: Int {
|
||||
switch self {
|
||||
case .disabled: return 0
|
||||
case .enabled: return 1
|
||||
case .notPresent: return 2
|
||||
case .UNRECOGNIZED(let i): return i
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
init() {}
|
||||
}
|
||||
|
||||
|
|
@ -1366,6 +1410,15 @@ extension Config.PositionConfig.PositionFlags: CaseIterable {
|
|||
]
|
||||
}
|
||||
|
||||
extension Config.PositionConfig.GpsMode: CaseIterable {
|
||||
// The compiler won't synthesize support with the UNRECOGNIZED case.
|
||||
static var allCases: [Config.PositionConfig.GpsMode] = [
|
||||
.disabled,
|
||||
.enabled,
|
||||
.notPresent,
|
||||
]
|
||||
}
|
||||
|
||||
extension Config.NetworkConfig.AddressMode: CaseIterable {
|
||||
// The compiler won't synthesize support with the UNRECOGNIZED case.
|
||||
static var allCases: [Config.NetworkConfig.AddressMode] = [
|
||||
|
|
@ -1471,6 +1524,7 @@ extension Config.DeviceConfig.Role: @unchecked Sendable {}
|
|||
extension Config.DeviceConfig.RebroadcastMode: @unchecked Sendable {}
|
||||
extension Config.PositionConfig: @unchecked Sendable {}
|
||||
extension Config.PositionConfig.PositionFlags: @unchecked Sendable {}
|
||||
extension Config.PositionConfig.GpsMode: @unchecked Sendable {}
|
||||
extension Config.PowerConfig: @unchecked Sendable {}
|
||||
extension Config.NetworkConfig: @unchecked Sendable {}
|
||||
extension Config.NetworkConfig.AddressMode: @unchecked Sendable {}
|
||||
|
|
@ -1776,6 +1830,7 @@ extension Config.PositionConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm
|
|||
10: .standard(proto: "broadcast_smart_minimum_distance"),
|
||||
11: .standard(proto: "broadcast_smart_minimum_interval_secs"),
|
||||
12: .standard(proto: "gps_en_gpio"),
|
||||
13: .standard(proto: "gps_mode"),
|
||||
]
|
||||
|
||||
mutating func decodeMessage<D: SwiftProtobuf.Decoder>(decoder: inout D) throws {
|
||||
|
|
@ -1796,6 +1851,7 @@ extension Config.PositionConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm
|
|||
case 10: try { try decoder.decodeSingularUInt32Field(value: &self.broadcastSmartMinimumDistance) }()
|
||||
case 11: try { try decoder.decodeSingularUInt32Field(value: &self.broadcastSmartMinimumIntervalSecs) }()
|
||||
case 12: try { try decoder.decodeSingularUInt32Field(value: &self.gpsEnGpio) }()
|
||||
case 13: try { try decoder.decodeSingularEnumField(value: &self.gpsMode) }()
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
|
@ -1838,6 +1894,9 @@ extension Config.PositionConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm
|
|||
if self.gpsEnGpio != 0 {
|
||||
try visitor.visitSingularUInt32Field(value: self.gpsEnGpio, fieldNumber: 12)
|
||||
}
|
||||
if self.gpsMode != .disabled {
|
||||
try visitor.visitSingularEnumField(value: self.gpsMode, fieldNumber: 13)
|
||||
}
|
||||
try unknownFields.traverse(visitor: &visitor)
|
||||
}
|
||||
|
||||
|
|
@ -1854,6 +1913,7 @@ extension Config.PositionConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageIm
|
|||
if lhs.broadcastSmartMinimumDistance != rhs.broadcastSmartMinimumDistance {return false}
|
||||
if lhs.broadcastSmartMinimumIntervalSecs != rhs.broadcastSmartMinimumIntervalSecs {return false}
|
||||
if lhs.gpsEnGpio != rhs.gpsEnGpio {return false}
|
||||
if lhs.gpsMode != rhs.gpsMode {return false}
|
||||
if lhs.unknownFields != rhs.unknownFields {return false}
|
||||
return true
|
||||
}
|
||||
|
|
@ -1875,6 +1935,14 @@ extension Config.PositionConfig.PositionFlags: SwiftProtobuf._ProtoNameProviding
|
|||
]
|
||||
}
|
||||
|
||||
extension Config.PositionConfig.GpsMode: SwiftProtobuf._ProtoNameProviding {
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
0: .same(proto: "DISABLED"),
|
||||
1: .same(proto: "ENABLED"),
|
||||
2: .same(proto: "NOT_PRESENT"),
|
||||
]
|
||||
}
|
||||
|
||||
extension Config.PowerConfig: SwiftProtobuf.Message, SwiftProtobuf._MessageImplementationBase, SwiftProtobuf._ProtoNameProviding {
|
||||
static let protoMessageName: String = Config.protoMessageName + ".PowerConfig"
|
||||
static let _protobuf_nameMap: SwiftProtobuf._NameMap = [
|
||||
|
|
|
|||
|
|
@ -126,6 +126,10 @@ enum HardwareModel: SwiftProtobuf.Enum {
|
|||
/// Makerfabs SenseLoRA Industrial Monitor (ESP32-S3 + RFM96)
|
||||
case senseloraS3 // = 28
|
||||
|
||||
///
|
||||
/// Canary Radio Company - CanaryOne: https://canaryradio.io/products/canaryone
|
||||
case canaryone // = 29
|
||||
|
||||
///
|
||||
/// ---------------------------------------------------------------------------
|
||||
/// Less common/prototype boards listed here (needs one more byte over the air)
|
||||
|
|
@ -230,6 +234,14 @@ enum HardwareModel: SwiftProtobuf.Enum {
|
|||
/// with one cut and one jumper Meshtastic works
|
||||
case chatter2 // = 56
|
||||
|
||||
///
|
||||
/// Heltec Wireless Paper, With ESP32-S3 CPU and E-Ink display
|
||||
/// Older "V1.0" Variant, has no "version sticker"
|
||||
/// E-Ink model is DEPG0213BNS800
|
||||
/// Tab on the screen protector is RED
|
||||
/// Flex connector marking is FPC-7528B
|
||||
case heltecWirelessPaperV10 // = 57
|
||||
|
||||
///
|
||||
/// ------------------------------------------------------------------------------------------------------------------------------------------
|
||||
/// Reserved ID For developing private Ports. These will show up in live traffic sparsely, so we can use a high number. Keep it within 8 bits.
|
||||
|
|
@ -267,6 +279,7 @@ enum HardwareModel: SwiftProtobuf.Enum {
|
|||
case 26: self = .rak11310
|
||||
case 27: self = .senseloraRp2040
|
||||
case 28: self = .senseloraS3
|
||||
case 29: self = .canaryone
|
||||
case 32: self = .loraRelayV1
|
||||
case 33: self = .nrf52840Dk
|
||||
case 34: self = .ppr
|
||||
|
|
@ -292,6 +305,7 @@ enum HardwareModel: SwiftProtobuf.Enum {
|
|||
case 54: self = .ebyteEsp32S3
|
||||
case 55: self = .esp32S3Pico
|
||||
case 56: self = .chatter2
|
||||
case 57: self = .heltecWirelessPaperV10
|
||||
case 255: self = .privateHw
|
||||
default: self = .UNRECOGNIZED(rawValue)
|
||||
}
|
||||
|
|
@ -323,6 +337,7 @@ enum HardwareModel: SwiftProtobuf.Enum {
|
|||
case .rak11310: return 26
|
||||
case .senseloraRp2040: return 27
|
||||
case .senseloraS3: return 28
|
||||
case .canaryone: return 29
|
||||
case .loraRelayV1: return 32
|
||||
case .nrf52840Dk: return 33
|
||||
case .ppr: return 34
|
||||
|
|
@ -348,6 +363,7 @@ enum HardwareModel: SwiftProtobuf.Enum {
|
|||
case .ebyteEsp32S3: return 54
|
||||
case .esp32S3Pico: return 55
|
||||
case .chatter2: return 56
|
||||
case .heltecWirelessPaperV10: return 57
|
||||
case .privateHw: return 255
|
||||
case .UNRECOGNIZED(let i): return i
|
||||
}
|
||||
|
|
@ -384,6 +400,7 @@ extension HardwareModel: CaseIterable {
|
|||
.rak11310,
|
||||
.senseloraRp2040,
|
||||
.senseloraS3,
|
||||
.canaryone,
|
||||
.loraRelayV1,
|
||||
.nrf52840Dk,
|
||||
.ppr,
|
||||
|
|
@ -409,6 +426,7 @@ extension HardwareModel: CaseIterable {
|
|||
.ebyteEsp32S3,
|
||||
.esp32S3Pico,
|
||||
.chatter2,
|
||||
.heltecWirelessPaperV10,
|
||||
.privateHw,
|
||||
]
|
||||
}
|
||||
|
|
@ -2570,6 +2588,7 @@ extension HardwareModel: SwiftProtobuf._ProtoNameProviding {
|
|||
26: .same(proto: "RAK11310"),
|
||||
27: .same(proto: "SENSELORA_RP2040"),
|
||||
28: .same(proto: "SENSELORA_S3"),
|
||||
29: .same(proto: "CANARYONE"),
|
||||
32: .same(proto: "LORA_RELAY_V1"),
|
||||
33: .same(proto: "NRF52840DK"),
|
||||
34: .same(proto: "PPR"),
|
||||
|
|
@ -2595,6 +2614,7 @@ extension HardwareModel: SwiftProtobuf._ProtoNameProviding {
|
|||
54: .same(proto: "EBYTE_ESP32_S3"),
|
||||
55: .same(proto: "ESP32_S3_PICO"),
|
||||
56: .same(proto: "CHATTER_2"),
|
||||
57: .same(proto: "HELTEC_WIRELESS_PAPER_V1_0"),
|
||||
255: .same(proto: "PRIVATE_HW"),
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -209,21 +209,18 @@ struct Connect: View {
|
|||
}.padding([.bottom, .top])
|
||||
}
|
||||
}
|
||||
.confirmationDialog("Connecting to a new radio will clear all local app data on the phone.", isPresented: $presentingSwitchPreferredPeripheral, titleVisibility: .visible) {
|
||||
.confirmationDialog("Connecting to a new radio will clear all local app data on the phone. The app may close.", isPresented: $presentingSwitchPreferredPeripheral, titleVisibility: .visible) {
|
||||
|
||||
Button("Connect to new radio?", role: .destructive) {
|
||||
bleManager.stopScanning()
|
||||
bleManager.connectedPeripheral = nil
|
||||
UserDefaults.preferredPeripheralId = ""
|
||||
UserDefaults.preferredPeripheralId = selectedPeripherialId
|
||||
if bleManager.connectedPeripheral != nil && bleManager.connectedPeripheral.peripheral.state == CBPeripheralState.connected {
|
||||
bleManager.disconnectPeripheral()
|
||||
}
|
||||
|
||||
clearCoreDataDatabase(context: context)
|
||||
let radio = bleManager.peripherals.first(where: { $0.peripheral.identifier.uuidString == selectedPeripherialId})
|
||||
bleManager.connectTo(peripheral: radio!.peripheral)
|
||||
presentingSwitchPreferredPeripheral = false
|
||||
selectedPeripherialId = ""
|
||||
PersistenceController.shared.clearDatabase()
|
||||
let radio = bleManager.peripherals.first(where: { $0.peripheral.identifier.uuidString == selectedPeripherialId })
|
||||
if radio != nil {
|
||||
bleManager.connectTo(peripheral: radio!.peripheral)
|
||||
}
|
||||
}
|
||||
}
|
||||
.textCase(nil)
|
||||
|
|
|
|||
|
|
@ -89,14 +89,21 @@ struct NodeListItem: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
if node.channel > 0 {
|
||||
HStack {
|
||||
HStack {
|
||||
if node.channel > 0 {
|
||||
Image(systemName: "fibrechannel")
|
||||
.font(.callout)
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text("Channel: \(node.channel)")
|
||||
.font(.callout)
|
||||
}
|
||||
if node.viaMqtt && connectedNode != node.num {
|
||||
Image(systemName: "network")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.font(.callout)
|
||||
Text("Via MQTT")
|
||||
.font(.callout)
|
||||
}
|
||||
}
|
||||
if !connected {
|
||||
HStack {
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ struct NodeMap: View {
|
|||
Section(header: Text("Map Options")) {
|
||||
Picker(selection: $selectedMapLayer, label: Text("")) {
|
||||
ForEach(MapLayer.allCases, id: \.self) { layer in
|
||||
if layer == MapLayer.offline && UserDefaults.enableOfflineMaps {
|
||||
if layer == MapLayer.offline && enableOfflineMaps {
|
||||
Text(layer.localized)
|
||||
} else if layer != MapLayer.offline {
|
||||
Text(layer.localized)
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ struct AppSettings: View {
|
|||
@State var totalDownloadedTileSize = ""
|
||||
@StateObject var locationHelper = LocationHelper()
|
||||
@State var provideLocation: Bool = UserDefaults.provideLocation
|
||||
@State var blockRangeTest: Bool = UserDefaults.blockRangeTest
|
||||
@State var enableSmartPosition: Bool = UserDefaults.enableSmartPosition
|
||||
@State var useLegacyMap: Bool = UserDefaults.mapUseLegacy
|
||||
@State var provideLocationInterval: Int = UserDefaults.provideLocationInterval
|
||||
@State private var isPresentingCoreDataResetConfirm = false
|
||||
|
|
@ -20,12 +20,6 @@ struct AppSettings: View {
|
|||
VStack {
|
||||
Form {
|
||||
Section(header: Text("options")) {
|
||||
|
||||
Toggle(isOn: $blockRangeTest) {
|
||||
Label("range.test.blocked", systemImage: "x.circle")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
||||
Toggle(isOn: $useLegacyMap) {
|
||||
Label("map.use.legacy", systemImage: "map")
|
||||
}
|
||||
|
|
@ -71,10 +65,14 @@ struct AppSettings: View {
|
|||
}
|
||||
Section(header: Text("Location Settings")) {
|
||||
Toggle(isOn: $provideLocation) {
|
||||
Label("provide.location", systemImage: "location.circle.fill")
|
||||
Label("appsettings.provide.location", systemImage: "location.circle.fill")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
if UserDefaults.provideLocation {
|
||||
if provideLocation {
|
||||
Toggle(isOn: $enableSmartPosition) {
|
||||
Label("appsettings.smartposition", systemImage: "brain.fill")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
VStack {
|
||||
Picker("update.interval", selection: $provideLocationInterval) {
|
||||
ForEach(LocationUpdateInterval.allCases) { lu in
|
||||
|
|
@ -106,8 +104,8 @@ struct AppSettings: View {
|
|||
Button("Erase all app data?", role: .destructive) {
|
||||
bleManager.disconnectPeripheral()
|
||||
clearCoreDataDatabase(context: context)
|
||||
context.refreshAllObjects()
|
||||
UserDefaults.standard.reset()
|
||||
UserDefaults.standard.synchronize()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -137,7 +135,7 @@ struct AppSettings: View {
|
|||
totalDownloadedTileSize = tileManager.getAllDownloadedSize()
|
||||
})
|
||||
}
|
||||
.navigationTitle("app.settings")
|
||||
.navigationTitle("appsettings")
|
||||
.navigationBarItems(trailing:
|
||||
ZStack {
|
||||
ConnectedDevice(bluetoothOn: bleManager.isSwitchedOn, deviceConnected: bleManager.connectedPeripheral != nil, name: (bleManager.connectedPeripheral != nil) ? bleManager.connectedPeripheral.shortName : "?")
|
||||
|
|
@ -151,9 +149,6 @@ struct AppSettings: View {
|
|||
self.bleManager.context = context
|
||||
}
|
||||
}
|
||||
.onChange(of: blockRangeTest) { newBlockRangeTest in
|
||||
UserDefaults.blockRangeTest = newBlockRangeTest
|
||||
}
|
||||
.onChange(of: provideLocation) { newProvideLocation in
|
||||
UserDefaults.provideLocation = newProvideLocation
|
||||
if bleManager.connectedPeripheral != nil {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// ShareChannel.swift
|
||||
// MeshtasticApple
|
||||
// Channels.swift
|
||||
// Meshtastic Apple
|
||||
//
|
||||
// Copyright(c) Garth Vander Houwen 4/8/22.
|
||||
//
|
||||
|
|
@ -25,12 +25,11 @@ struct Channels: View {
|
|||
var node: NodeInfoEntity?
|
||||
|
||||
@State var hasChanges = false
|
||||
@State var hasValidKey = false
|
||||
@State private var isPresentingEditView = false
|
||||
@State private var isPresentingSaveConfirm: Bool = false
|
||||
@State private var channelIndex: Int32 = 0
|
||||
@State private var channelName = ""
|
||||
@State private var channelKeySize = 32
|
||||
@State private var channelKeySize = 16
|
||||
@State private var channelKey = "AQ=="
|
||||
@State private var channelRole = 0
|
||||
@State private var uplink = false
|
||||
|
|
@ -90,7 +89,7 @@ struct Channels: View {
|
|||
if node?.myInfo?.channels?.array.count ?? 0 < 8 && node != nil {
|
||||
|
||||
Button {
|
||||
let key = generateChannelKey(size: 32)
|
||||
let key = generateChannelKey(size: 16)
|
||||
channelName = ""
|
||||
channelIndex = Int32(node!.myInfo!.channels!.array.count)
|
||||
channelRole = 2
|
||||
|
|
@ -168,34 +167,16 @@ struct Channels: View {
|
|||
HStack(alignment: .top) {
|
||||
Text("Key")
|
||||
Spacer()
|
||||
TextField(
|
||||
"Key",
|
||||
text: $channelKey
|
||||
)
|
||||
.padding(4)
|
||||
.disableAutocorrection(true)
|
||||
.keyboardType(.alphabet)
|
||||
.foregroundColor(Color.gray)
|
||||
.textSelection(.enabled)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 25.0)
|
||||
.stroke(
|
||||
hasValidKey ?
|
||||
Color.green :
|
||||
Color.red
|
||||
, lineWidth: 2.0)
|
||||
)
|
||||
.onChange(of: channelKey, perform: { _ in
|
||||
let tempKey = Data(base64Encoded: channelKey) ?? Data()
|
||||
if tempKey.count == channelKeySize || channelKeySize == -1{
|
||||
hasValidKey = true
|
||||
}
|
||||
else {
|
||||
hasValidKey = false
|
||||
}
|
||||
hasChanges = true
|
||||
})
|
||||
.disabled(channelKeySize <= 0)
|
||||
Text(channelKey)
|
||||
.foregroundColor(Color.gray)
|
||||
.textSelection(.enabled)
|
||||
// TextField(
|
||||
// "",
|
||||
// text: $channelKey,
|
||||
// axis: .vertical
|
||||
// )
|
||||
// .foregroundColor(Color.gray)
|
||||
// .disabled(true)
|
||||
}
|
||||
Picker("Channel Role", selection: $channelRole) {
|
||||
if channelRole == 1 {
|
||||
|
|
@ -275,7 +256,7 @@ struct Channels: View {
|
|||
} label: {
|
||||
Label("save", systemImage: "square.and.arrow.down")
|
||||
}
|
||||
.disabled(bleManager.connectedPeripheral == nil || !hasChanges || !hasValidKey)
|
||||
.disabled(bleManager.connectedPeripheral == nil || !hasChanges)
|
||||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ struct LoRaConfig: View {
|
|||
.scrollDismissesKeyboard(.immediately)
|
||||
.focused($focusedField, equals: .channelNum)
|
||||
}
|
||||
Text("This determines the actual frequency you are transmitting on in the band.")
|
||||
Text("This determines the actual frequency you are transmitting on in the band. If set to 0 this value will be calculated automatically based on the primary channel name.")
|
||||
.font(.caption)
|
||||
Toggle(isOn: $rxBoostedGain) {
|
||||
Label("RX Boosted Gain", systemImage: "waveform.badge.plus")
|
||||
|
|
|
|||
|
|
@ -30,6 +30,15 @@ struct MQTTConfig: View {
|
|||
var body: some View {
|
||||
VStack {
|
||||
Form {
|
||||
if node != nil && node?.loRaConfig != nil {
|
||||
let rc = RegionCodes(rawValue: Int(node?.loRaConfig?.regionCode ?? 0))
|
||||
if rc?.dutyCycle ?? 0 <= 10 {
|
||||
Text("Your region has a \(rc?.dutyCycle ?? 0)% duty cycle. MQTT is not advised when you are duty cycle restricted, the extra traffice will quickly overwhelm your LoRa mesh.")
|
||||
.font(.callout)
|
||||
.foregroundColor(.red)
|
||||
}
|
||||
}
|
||||
|
||||
if node != nil && node?.metadata == nil && node?.num ?? 0 != bleManager.connectedPeripheral?.num ?? 0 {
|
||||
Text("There has been no response to a request for device metadata over the admin channel for this node.")
|
||||
.font(.callout)
|
||||
|
|
@ -88,7 +97,7 @@ struct MQTTConfig: View {
|
|||
Label("JSON Enabled", systemImage: "ellipsis.curlybraces")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
Text("JSON mode is a limited, unencrypted MQTT output.")
|
||||
Text("JSON mode is a limited, unencrypted MQTT output that can crash your node it should not be enabled unless you are locally integrating with home assistant")
|
||||
.font(.caption2)
|
||||
|
||||
Toggle(isOn: $tlsEnabled) {
|
||||
|
|
@ -304,19 +313,11 @@ struct MQTTConfig: View {
|
|||
.onChange(of: encryptionEnabled) { newEncryptionEnabled in
|
||||
if node != nil && node?.mqttConfig != nil {
|
||||
if newEncryptionEnabled != node!.mqttConfig!.encryptionEnabled { hasChanges = true }
|
||||
if newEncryptionEnabled {
|
||||
jsonEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
.onChange(of: jsonEnabled) { newJsonEnabled in
|
||||
if node != nil && node?.mqttConfig != nil {
|
||||
if newJsonEnabled != node!.mqttConfig!.jsonEnabled { hasChanges = true }
|
||||
|
||||
if newJsonEnabled {
|
||||
encryptionEnabled = false
|
||||
proxyToClientEnabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
.onChange(of: tlsEnabled) { newTlsEnabled in
|
||||
|
|
|
|||
|
|
@ -36,14 +36,16 @@ struct PositionConfig: View {
|
|||
|
||||
@State var smartPositionEnabled = true
|
||||
@State var deviceGpsEnabled = true
|
||||
@State var gpsMode = 0
|
||||
@State var rxGpio = 0
|
||||
@State var txGpio = 0
|
||||
@State var gpsEnGpio = 0
|
||||
@State var fixedPosition = false
|
||||
@State var gpsUpdateInterval = 0
|
||||
@State var positionBroadcastSeconds = 0
|
||||
@State var broadcastSmartMinimumDistance = 0
|
||||
@State var broadcastSmartMinimumIntervalSecs = 0
|
||||
@State var positionFlags = 3
|
||||
@State var positionFlags = 811
|
||||
|
||||
/// Position Flags
|
||||
/// Altitude value - 1
|
||||
|
|
@ -143,6 +145,34 @@ struct PositionConfig: View {
|
|||
.font(.caption)
|
||||
}
|
||||
}
|
||||
Section(header: Text("Device GPS")) {
|
||||
Picker("", selection: $gpsMode) {
|
||||
ForEach(GpsMode.allCases, id: \.self) { at in
|
||||
Text(at.description)
|
||||
.tag(at.id)
|
||||
}
|
||||
}
|
||||
.pickerStyle(SegmentedPickerStyle())
|
||||
.padding(.top, 5)
|
||||
.padding(.bottom, 5)
|
||||
|
||||
if gpsMode == 1 {
|
||||
Picker("Update Interval", selection: $gpsUpdateInterval) {
|
||||
ForEach(GpsUpdateIntervals.allCases) { ui in
|
||||
Text(ui.description)
|
||||
}
|
||||
}
|
||||
Text("How often should we try to get a GPS position.")
|
||||
.font(.caption)
|
||||
} else {
|
||||
Toggle(isOn: $fixedPosition) {
|
||||
Label("Fixed Position", systemImage: "location.square.fill")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
Text("If enabled your current phone location will be sent to the device and will broadcast over the mesh on the position interval. Fixed positon will always use the most recent position the device has.")
|
||||
.font(.caption)
|
||||
}
|
||||
}
|
||||
Section(header: Text("Position Flags")) {
|
||||
|
||||
Text("Optional fields to include when assembling position messages. the more fields are included, the larger the message will be - leading to longer airtime and a higher risk of packet loss")
|
||||
|
|
@ -205,13 +235,9 @@ struct PositionConfig: View {
|
|||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
}
|
||||
}
|
||||
Section(header: Text("Device GPS")) {
|
||||
Toggle(isOn: $deviceGpsEnabled) {
|
||||
Label("Device GPS Enabled", systemImage: "location")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
if deviceGpsEnabled {
|
||||
|
||||
|
||||
if gpsMode == 1 {
|
||||
Section(header: Text("Advanced Device GPS")) {
|
||||
Picker("GPS Receive GPIO", selection: $rxGpio) {
|
||||
ForEach(0..<49) {
|
||||
if $0 == 0 {
|
||||
|
|
@ -244,13 +270,6 @@ struct PositionConfig: View {
|
|||
.pickerStyle(DefaultPickerStyle())
|
||||
Text("(Re)define PIN_GPS_EN for your board.")
|
||||
.font(.caption)
|
||||
} else {
|
||||
Toggle(isOn: $fixedPosition) {
|
||||
Label("Fixed Position", systemImage: "location.square.fill")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
Text("If enabled your current location will be set as a fixed position.")
|
||||
.font(.caption)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -283,8 +302,10 @@ struct PositionConfig: View {
|
|||
if connectedNode != nil {
|
||||
var pc = Config.PositionConfig()
|
||||
pc.positionBroadcastSmartEnabled = smartPositionEnabled
|
||||
pc.gpsEnabled = deviceGpsEnabled
|
||||
pc.gpsEnabled = gpsMode == 1
|
||||
pc.gpsMode = Config.PositionConfig.GpsMode(rawValue: gpsMode) ?? Config.PositionConfig.GpsMode.notPresent
|
||||
pc.fixedPosition = fixedPosition
|
||||
pc.gpsUpdateInterval = UInt32(gpsUpdateInterval)
|
||||
pc.positionBroadcastSecs = UInt32(positionBroadcastSeconds)
|
||||
pc.broadcastSmartMinimumIntervalSecs = UInt32(broadcastSmartMinimumIntervalSecs)
|
||||
pc.broadcastSmartMinimumDistance = UInt32(broadcastSmartMinimumDistance)
|
||||
|
|
@ -342,6 +363,11 @@ struct PositionConfig: View {
|
|||
if newDeviceGps != node!.positionConfig!.deviceGpsEnabled { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: gpsMode) { newGpsMode in
|
||||
if node != nil && node!.positionConfig != nil {
|
||||
if newGpsMode != node!.positionConfig!.gpsMode { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: rxGpio) { newRxGpio in
|
||||
if node != nil && node!.positionConfig != nil {
|
||||
if newRxGpio != node!.positionConfig!.rxGpio { hasChanges = true }
|
||||
|
|
@ -382,6 +408,11 @@ struct PositionConfig: View {
|
|||
if newBroadcastSmartMinimumDistance != node!.positionConfig!.broadcastSmartMinimumDistance { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: gpsUpdateInterval) { newGpsUpdateInterval in
|
||||
if node != nil && node!.positionConfig != nil {
|
||||
if newGpsUpdateInterval != node!.positionConfig!.gpsUpdateInterval { hasChanges = true }
|
||||
}
|
||||
}
|
||||
.onChange(of: includeAltitude) { altFlag in
|
||||
let pf = PositionFlags(rawValue: self.positionFlags)
|
||||
let existingValue = pf.contains(.Altitude)
|
||||
|
|
@ -440,11 +471,16 @@ struct PositionConfig: View {
|
|||
}
|
||||
func setPositionValues() {
|
||||
self.smartPositionEnabled = node?.positionConfig?.smartPositionEnabled ?? true
|
||||
self.deviceGpsEnabled = node?.positionConfig?.deviceGpsEnabled ?? true
|
||||
self.deviceGpsEnabled = node?.positionConfig?.deviceGpsEnabled ?? false
|
||||
self.gpsMode = Int(node?.positionConfig?.gpsMode ?? 0)
|
||||
if node?.positionConfig?.deviceGpsEnabled ?? false && gpsMode != 1 {
|
||||
self.gpsMode = 1
|
||||
}
|
||||
self.rxGpio = Int(node?.positionConfig?.rxGpio ?? 0)
|
||||
self.txGpio = Int(node?.positionConfig?.txGpio ?? 0)
|
||||
self.gpsEnGpio = Int(node?.positionConfig?.gpsEnGpio ?? 0)
|
||||
self.fixedPosition = node?.positionConfig?.fixedPosition ?? false
|
||||
self.gpsUpdateInterval = Int(node?.positionConfig?.gpsUpdateInterval ?? 30)
|
||||
self.positionBroadcastSeconds = Int(node?.positionConfig?.positionBroadcastSeconds ?? 900)
|
||||
self.broadcastSmartMinimumIntervalSecs = Int(node?.positionConfig?.broadcastSmartMinimumIntervalSecs ?? 30)
|
||||
self.broadcastSmartMinimumDistance = Int(node?.positionConfig?.broadcastSmartMinimumDistance ?? 50)
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ struct Settings: View {
|
|||
} label: {
|
||||
Image(systemName: "gearshape")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text("app.settings")
|
||||
Text("appsettings")
|
||||
}
|
||||
.tag(SettingsSidebar.appSettings)
|
||||
if #available(iOS 17.0, macOS 14.0, *) {
|
||||
|
|
@ -312,13 +312,15 @@ struct Settings: View {
|
|||
}
|
||||
}
|
||||
.onAppear {
|
||||
self.preferredNodeNum = UserDefaults.preferredPeripheralNum
|
||||
if nodes.count > 1 {
|
||||
if selectedNode == 0 {
|
||||
if self.preferredNodeNum == 0 {
|
||||
self.preferredNodeNum = UserDefaults.preferredPeripheralNum
|
||||
if nodes.count > 1 {
|
||||
if selectedNode == 0 {
|
||||
self.selectedNode = Int(bleManager.connectedPeripheral != nil ? UserDefaults.preferredPeripheralNum : 0)
|
||||
}
|
||||
} else {
|
||||
self.selectedNode = Int(bleManager.connectedPeripheral != nil ? UserDefaults.preferredPeripheralNum : 0)
|
||||
}
|
||||
} else {
|
||||
self.selectedNode = Int(bleManager.connectedPeripheral != nil ? UserDefaults.preferredPeripheralNum : 0)
|
||||
}
|
||||
}
|
||||
.listStyle(GroupedListStyle())
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
## Overview
|
||||
|
||||
SwiftUI client applicaitons for iOS, iPadOS and macOS.
|
||||
SwiftUI client applications for iOS, iPadOS and macOS.
|
||||
|
||||
## OS Requirements
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@
|
|||
"always.on"="Immer an";
|
||||
"ambient.lighting"="Ambient Lighting";
|
||||
"ambient.lighting.config"="Ambient Lighting Config";
|
||||
"app.settings"="App Einstellungen";
|
||||
"appsettings"="App Einstellungen";
|
||||
"appsettings.provide.location"="Standort im Mesh veröffentlichen";
|
||||
"appsettings.smartposition"="Smart Position";
|
||||
"are.you.sure"="Bist Du sicher?";
|
||||
"ascii.capable"="ASCII fähig";
|
||||
"available.radios"="Geräte in der Nähe";
|
||||
|
|
@ -60,6 +62,7 @@
|
|||
"current"="Current";
|
||||
"default"="Standard";
|
||||
"delete"="Löschen";
|
||||
"detection.sensor"="Detection Sensor";
|
||||
"device"="Gerät";
|
||||
"device.config"="Gerätekonfiguration";
|
||||
"device.metrics.delete"="Delete all device metrics?";
|
||||
|
|
@ -222,7 +225,6 @@
|
|||
"position"="Position";
|
||||
"position.config"="Positionseinstellungen";
|
||||
"preferred.radio"="Bevorzugtes Gerät";
|
||||
"provide.location"="Standort im Mesh veröffentlichen";
|
||||
"radio.configuration"="Geräteeinstellungen";
|
||||
"range.test"="Entfernungstest";
|
||||
"range.test.blocked"="Block Range Test";
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@
|
|||
"always.on"="Always On";
|
||||
"ambient.lighting"="Ambient Lighting";
|
||||
"ambient.lighting.config"="Ambient Lighting Config";
|
||||
"app.settings"="App Settings";
|
||||
"appsettings"="App Settings";
|
||||
"appsettings.provide.location"="Share location";
|
||||
"appsettings.smartposition"="Smart Position";
|
||||
"are.you.sure"="Are you sure?";
|
||||
"ascii.capable"="ASCII Capable";
|
||||
"available.radios"="Available Radios";
|
||||
|
|
@ -67,15 +69,16 @@
|
|||
"device.config"="Device Config";
|
||||
"device.metrics.delete"="Delete all device metrics?";
|
||||
"device.metrics.log"="Device Metrics Log";
|
||||
"device.role.client"="Client (default) - App connected client.";
|
||||
"device.role.clienthidden"=" Used for nodes that \"only speak when spoken to\" Turns all of the routine broadcasts but allows for ad-hoc communication. Still rebroadcasts, but with local only rebroadcast mode (known meshes only). Can be used for private operation or to dramatically reduce airtime / power consumption.";
|
||||
"device.role.clientmute"="Client Mute - Same as a client except packets will not hop over this node, does not contribute to routing packets for mesh.";
|
||||
"device.role.lostandfound"="Used to automatically send a text message to the mesh with the current position of the device on a frequent interval: \"I'm lost! Position: lat / long\"";
|
||||
"device.role.router"="Router - Mesh packets will prefer to be routed over this node. Assumes device will operate in a standalone manner while placed in a location with a coverage advantage. WARNING: The BLE/Wi-Fi radios and the OLED screen will be put to sleep.";
|
||||
"device.role.routerclient"="Router Client - Hybrid of the Client and Router roles. Similar to Router, except the Router Client can be used as both a Router and an app connected Client. BLE/Wi-Fi and OLED screen will not be put to sleep.";
|
||||
"device.role.repeater"="Repeater - Mesh packets will prefer to be routed over this node. This role eliminates unnecessary overhead such as NodeInfo, DeviceTelemetry, and any other mesh packet, resulting in the device not appearing as part of the network. Please see Rebroadcast Mode for additional settings specific to this role.";
|
||||
"device.role.tracker"="Tracker - For use with devices intended as a GPS tracker. Position packets sent from this device will be higher priority, with position broadcasting every two minutes. Smart Position Broadcast will default to off.";
|
||||
"device.role.tak"="Used for nodes dedicated for connection to an ATAK EUD. Turns off many of the routine broadcasts to favor CoT packet stream from the Meshtastic ATAK plugin -> IMeshService -> Node";
|
||||
"device.role.client"="App connected or stand alone messaging client.";
|
||||
"device.role.clientmute"="Client that does not forward packets from other devices.";
|
||||
"device.role.clienthidden"="Client that only broadcasts as needed for stealth or power savings.";
|
||||
"device.role.tracker"="Prioritizes broadcasting GPS position packets.";
|
||||
"device.role.lostandfound"="Broadcasts location as message to default channel regularly for to assist with node recovery.";
|
||||
"device.role.sensor"="Prioritizes broadcasting telemetry packets.";
|
||||
"device.role.tak"="Optimized for ATAK system communication, reduces routine broadcasts.";
|
||||
"device.role.repeater"="Infrastructure node for extending mesh network coverage by relaying messages with minimal overhead. Not visible in Nodes list. Best positioned in strategic locations to maximize the network's overall coverage. Device is not shown in topology.";
|
||||
"device.role.router"="Infrastructure node for on extending mesh network coverage by relaying messages. Visible in Nodes list. Best positioned in strategic locations to maximize the network's overall coverage. Device is shown in topology.";
|
||||
"device.role.routerclient"="Combination of both ROUTER and CLIENT. Not for mobile nodes.";
|
||||
"direct.messages"="Direct Messages";
|
||||
"dismiss.keyboard"="Dismiss";
|
||||
"display"="Display (Device Screen)";
|
||||
|
|
@ -100,6 +103,9 @@
|
|||
"gpsformat.mgrs"="Military Grid Reference System";
|
||||
"gpsformat.olc"="Open Location Code (aka Plus Codes)";
|
||||
"gpsformat.osgr"="Ordnance Survey Grid Reference";
|
||||
"gpsmode.disabled"="Disabled";
|
||||
"gpsmode.enabled"="Enabled";
|
||||
"gpsmode.notPresent"="Not Present";
|
||||
"heard"="Heard";
|
||||
"heard.last"="Last Heard";
|
||||
"hybrid"="Hybrid";
|
||||
|
|
@ -226,7 +232,6 @@
|
|||
"position"="Position";
|
||||
"position.config"="Position Config";
|
||||
"preferred.radio"="Preferred Radio";
|
||||
"provide.location"="Share location";
|
||||
"radio.configuration"="Radio Configuration";
|
||||
"range.test"="Range Test";
|
||||
"range.test.blocked"="Block Range Test";
|
||||
|
|
|
|||
|
|
@ -16,7 +16,9 @@
|
|||
"always.on"="Zawsze włączone";
|
||||
"ambient.lighting"="Ambient Lighting";
|
||||
"ambient.lighting.config"="Ambient Lighting Config";
|
||||
"app.settings"="Ustawienia aplikacji";
|
||||
"appsettings"="Ustawienia aplikacji";
|
||||
"appsettings.provide.location"="Udostępnij lokalizację";
|
||||
"appsettings.smartposition"="Smart Position";
|
||||
"are.you.sure"="Jesteś pewny?";
|
||||
"ascii.capable"="Zgodny z ASCII";
|
||||
"available.radios"="Dostępne radia";
|
||||
|
|
@ -62,6 +64,7 @@
|
|||
"current"="Bieżący";
|
||||
"default"="Domyślny";
|
||||
"delete"="Usuń";
|
||||
"detection.sensor"="Detection Sensor";
|
||||
"device"="Urządzenie";
|
||||
"device.config"="Konfiguracja urządzenia";
|
||||
"device.metrics.delete"="Usunąć wszystkie metryki urządzenia?";
|
||||
|
|
@ -223,7 +226,6 @@
|
|||
"position"="Pozycja";
|
||||
"position.config"="Konfiguracja pozycji";
|
||||
"preferred.radio"="Preferowane radio";
|
||||
"provide.location"="Udostępnij lokalizację";
|
||||
"radio.configuration"="Konfiguracja radia";
|
||||
"range.test"="Test zasięgu";
|
||||
"range.test.blocked"="Block Range Test";
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@
|
|||
"always.on"="常亮";
|
||||
"ambient.lighting"="Ambient Lighting";
|
||||
"ambient.lighting.config"="Ambient Lighting Config";
|
||||
"app.settings"="通用设置";
|
||||
"appsettings"="通用设置";
|
||||
"appsettings.provide.location"="提供定位到 Mesh 网络";
|
||||
"appsettings.smartposition"="Smart Position";
|
||||
"are.you.sure"="是否确认?";
|
||||
"ascii.capable"="ASCII Capable";
|
||||
"available.radios"="可以连接的电台";
|
||||
|
|
@ -60,6 +62,7 @@
|
|||
"current"="当前";
|
||||
"default"="默认";
|
||||
"delete"="删除";
|
||||
"detection.sensor"="Detection Sensor";
|
||||
"device"="电台";
|
||||
"device.config"="电台配置";
|
||||
"device.metrics.delete"="删除所有电台指标?";
|
||||
|
|
@ -222,7 +225,6 @@
|
|||
"position"="定位";
|
||||
"position.config"="定位配置";
|
||||
"preferred.radio"="首选电台";
|
||||
"provide.location"="提供定位到 Mesh 网络";
|
||||
"radio.configuration"="电台配置";
|
||||
"range.test"="拉距测试";
|
||||
"range.test.blocked"="区块范围测试";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue