From fa4e000cebbe19c8f26f04664ee3b71310d36d44 Mon Sep 17 00:00:00 2001 From: Garth Vander Houwen Date: Thu, 10 Oct 2024 06:13:14 -0700 Subject: [PATCH] Updates for new protos --- Localizable.xcstrings | 68 +-- Meshtastic.xcodeproj/project.pbxproj | 4 +- Meshtastic/Enums/LoraConfigEnums.swift | 57 ++- Meshtastic/Helpers/MeshPackets.swift | 3 + .../Meshtastic.xcdatamodeld/.xccurrentversion | 2 +- .../contents | 482 ++++++++++++++++++ Meshtastic/Persistence/UpdateCoreData.swift | 4 +- Meshtastic/Views/Bluetooth/Connect.swift | 3 + Meshtastic/Views/Helpers/SecureInput.swift | 2 +- .../Config/Module/DetectionSensorConfig.swift | 16 +- .../Settings/Config/SecurityConfig.swift | 66 ++- Widgets/MeshActivityAttributes.swift | 5 + Widgets/WidgetsLiveActivity.swift | 2 +- 13 files changed, 646 insertions(+), 68 deletions(-) create mode 100644 Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 46.xcdatamodel/contents diff --git a/Localizable.xcstrings b/Localizable.xcstrings index a1d2ddab..da00af42 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -469,9 +469,6 @@ }, "Admin & Direct Message Keys" : { - }, - "Admin Key" : { - }, "admin.log" : { "extractionState" : "manual", @@ -1534,13 +1531,13 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "尝试连接%@失败,你可能需要在系统设置的蓝牙选项中忽略该电台。" + "value" : "尝试连接%d失败,你可能需要在系统设置的蓝牙选项中忽略该电台。" } }, "zh-Hant-TW" : { "stringUnit" : { "state" : "translated", - "value" : "嘗試連接%@失敗,你可能需要在系统設定的藍芽選項中忽略該電台。" + "value" : "嘗試連接%d失敗,你可能需要在系统設定的藍芽選項中忽略該電台。" } } } @@ -5198,9 +5195,6 @@ }, "Detection sensor messages are received as text messages. If you enable notifications you will recieve a notification for each detection message received and a corresponding unread message badge." : { - }, - "Detection trigger High" : { - }, "detection.sensor" : { "localizations" : { @@ -5877,55 +5871,55 @@ "localizations" : { "de" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "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." } }, "en" : { "stringUnit" : { "state" : "translated", - "value" : "Infrastructure node for extending network coverage by relaying messages with minimal overhead. Not visible in Nodes list." + "value" : "Infrastructure node on a tower or mountain top only. Not to be used for roofs or mobile nodes. Relays messages with minimal overhead. Not visible in Nodes list." } }, "fr" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Noeud d'infrastructure qui étend la couverture du réseau en relayant les messages avec un minimum de surcharge. Invisible dans la liste des noeuds." } }, "he" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "מכשיר תשתית להרחבת המש על ידי העברת הודעות עם דאטה נוסף מינימלי." } }, "pl" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Przekaźnik - Pakiety siatki będą preferować trasowanie przez ten węzeł. Ta rola eliminuje niepotrzebny nadmiar, taki jak NodeInfo, DeviceTelemetry i inne pakiety siatki, skutkując tym, że urządzenie nie będzie widoczne jako część sieci. Proszę zobaczyć tryb Rebroadcast dla dodatkowych ustawień specyficznych dla tej roli." } }, "pt-PT" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Nó de infraestrutura para ampliar a cobertura da rede transmitindo mensagens com sobrecarga mínima. Não visível na lista de Nós." } }, "se" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Infrastrukturnod för att utöka nätverkstäckningen genom att vidarebefordra meddelanden med minimal overhead. Syns inte i Noder-listan." } }, "zh-Hans" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "中继模式 - Mesh 网络数据包将优先通过此节点路由。此模式可消除不必要的开销,如节点信息、设备遥测和任何其他 Mesh 数据包,从而使设备不显示为 Mesh 网络的一部分。有关此角色的其他特定设置,请参阅转播模式。" } }, "zh-Hant-TW" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "中繼模式 - Mesh 網路數據包將優先通過此中繼點路由。此模式可消除不必要的開銷,如 NodeInfo、DeviceTelemetry 和任何其他 Mesh 數據包,從而使設備不顯示為 Mesh 網路的一部分。有關此角色的其他特定設置,請參閱轉播模式。" } } @@ -5936,55 +5930,55 @@ "localizations" : { "de" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Router - Mesh Pakete werden bevorzugt über diesen Node gerouted. Dieser Node wird nicht von einer Client App benutzt. WLAN, Bluetooth und Display sind aus." } }, "en" : { "stringUnit" : { "state" : "translated", - "value" : "Infrastructure node for extending network coverage by relaying messages. Visible in Nodes list." + "value" : "Infrastructure node on a tower or mountain top only. Not to be used for roofs or mobile nodes. Needs exceptional coverage. Visible in Nodes list." } }, "fr" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Noeud d'infrastructure qui étend la couverture du réseau en relayant les messages. Visible dans la liste des noeuds." } }, "he" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "מכשיר תשתית להרחבת המש על ידי העברת הודעות. מופיע ברשימת מכשירים." } }, "pl" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Router - Pakiety siatki będą preferować trasowanie przez ten węzeł. Zakłada, że urządzenie będzie działać samodzielnie, umieszczone w miejscu z przewagą zasięgu. UWAGA: Radia BLE/Wi-Fi i ekran OLED zostaną uśpione." } }, "pt-PT" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Nó de infraestrutura para ampliar a cobertura da rede transmitindo mensagens. Visível na lista de Nós." } }, "se" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "Infrastrukturnod för att utöka nätverkstäckningen genom att vidarebefordra meddelanden. Synlig i Noder-listan." } }, "zh-Hans" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "纯路由模式 - 自动转发 Mesh 网络中其他节点的消息,中继模式下屏幕会熄灭,Wi-Fi 和蓝牙将会进入睡眠模式,App 将无法连接到电台进行收发操作。" } }, "zh-Hant-TW" : { "stringUnit" : { - "state" : "translated", + "state" : "needs_review", "value" : "纯路由模式 - 自動轉發 Mesh 網路中其他中繼點的消息,中繼模式下螢幕會熄滅,Wi-Fi 和藍芽將會進入睡眠模式,App 將無法連接到電台進行收發操作。" } } @@ -6002,7 +5996,7 @@ "en" : { "stringUnit" : { "state" : "translated", - "value" : "Combination of both ROUTER and CLIENT. Not for mobile devices. Deprecated" + "value" : "Deprecated role use client." } }, "fr" : { @@ -16683,6 +16677,9 @@ }, "Primary" : { + }, + "Primary Admin Key" : { + }, "Primary GPIO" : { @@ -18913,6 +18910,9 @@ }, "Secondary" : { + }, + "Secondary Admin Key" : { + }, "Security" : { @@ -21031,6 +21031,9 @@ }, "Ten Minutes" : { + }, + "Tertiary Admin Key" : { + }, "The amount of time to wait before we consider your packet as done." : { @@ -21062,7 +21065,7 @@ "The most recent public key for this node does not match the previously recorded key. You can delete the node and let it exchange keys again, but this also may indicate a more serious security problem. Contact the user through another trusted channel to determine if the key change was due to a factory reset or other intentional action." : { }, - "The public key authorized to send admin messages to this node." : { + "The primary public key authorized to send admin messages to this node." : { }, "The public key does not match the recorded key. You may delete the node and let it exchange keys again, but this may indicate a more serious security problem. Contact the user through another trusted channel, to determine if the key change was due to a factory reset or other intentional action." : { @@ -21073,9 +21076,15 @@ }, "The root topic to use for MQTT." : { + }, + "The secondary public key authorized to send admin messages to this node." : { + }, "The state of the LED (on/off)" : { + }, + "The tertiarypublic key authorized to send admin messages to this node." : { + }, "There has been no response to a request for device metadata over the admin channel for this node." : { @@ -22607,9 +22616,6 @@ }, "When using in GPIO mode, keep the output on for this long. " : { - }, - "Whether or not the GPIO pin state detection is triggered on HIGH (1) or LOW (0)" : { - }, "WiFi Options" : { diff --git a/Meshtastic.xcodeproj/project.pbxproj b/Meshtastic.xcodeproj/project.pbxproj index c6706b44..e870495b 100644 --- a/Meshtastic.xcodeproj/project.pbxproj +++ b/Meshtastic.xcodeproj/project.pbxproj @@ -299,6 +299,7 @@ DD007BAD2AA4E91200F5FA12 /* MyInfoEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInfoEntityExtension.swift; sourceTree = ""; }; DD007BAF2AA5981000F5FA12 /* NodeInfoEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeInfoEntityExtension.swift; sourceTree = ""; }; DD05296F2B77F454008E44CD /* MeshtasticDataModelV 26.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 26.xcdatamodel"; sourceTree = ""; }; + DD0BE30C2CB785D8000BA445 /* MeshtasticDataModelV 46.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 46.xcdatamodel"; sourceTree = ""; }; DD0E20FF2B892E1300F2D100 /* MeshtasticDataModelV 28.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 28.xcdatamodel"; sourceTree = ""; }; DD0E21002B8A6BC500F2D100 /* DeviceHardware.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = DeviceHardware.json; sourceTree = ""; }; DD0E9C222A30CE3A00580CBB /* MeshtasticDataModelV14.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MeshtasticDataModelV14.xcdatamodel; sourceTree = ""; }; @@ -1910,6 +1911,7 @@ DD3CC6BA28E366DF00FA9159 /* Meshtastic.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + DD0BE30C2CB785D8000BA445 /* MeshtasticDataModelV 46.xcdatamodel */, DD6D5A342CA13BA600ED3032 /* MeshtasticDataModelV 45.xcdatamodel */, DD7CF8DA2C93663C008BD10E /* MeshtasticDataModelV 44.xcdatamodel */, DD7E235F2C7AA3E50078ACDF /* MeshtasticDataModelV 43.xcdatamodel */, @@ -1956,7 +1958,7 @@ DD5D0A9A2931AD6B00F7EA61 /* MeshtasticDataModelV2.xcdatamodel */, DD3CC6BB28E366DF00FA9159 /* MeshtasticDataModel.xcdatamodel */, ); - currentVersion = DD6D5A342CA13BA600ED3032 /* MeshtasticDataModelV 45.xcdatamodel */; + currentVersion = DD0BE30C2CB785D8000BA445 /* MeshtasticDataModelV 46.xcdatamodel */; name = Meshtastic.xcdatamodeld; path = Meshtastic/Meshtastic.xcdatamodeld; sourceTree = ""; diff --git a/Meshtastic/Enums/LoraConfigEnums.swift b/Meshtastic/Enums/LoraConfigEnums.swift index b0dd9966..2a2d7090 100644 --- a/Meshtastic/Enums/LoraConfigEnums.swift +++ b/Meshtastic/Enums/LoraConfigEnums.swift @@ -25,9 +25,12 @@ enum RegionCodes: Int, CaseIterable, Identifiable { case th = 12 case ua433 = 14 case ua868 = 15 - case my_433 = 16 - case my_919 = 17 - case sg_923 = 18 + case my433 = 16 + case my919 = 17 + case sg923 = 18 + case ph433 = 19 + case ph868 = 20 + case ph915 = 21 case lora24 = 13 var topic: String { switch self { @@ -61,12 +64,18 @@ enum RegionCodes: Int, CaseIterable, Identifiable { "UA_433" case .ua868: "UA_868" - case .my_433: + case .my433: "MY_433" - case .my_919: + case .my919: "MY_919" - case .sg_923: + case .sg923: "SG_923" + case .ph433: + "ph_433" + case .ph868: + "ph_868" + case .ph915: + "ph_915" case .lora24: "LORA_24" } } @@ -105,12 +114,18 @@ enum RegionCodes: Int, CaseIterable, Identifiable { return "Ukraine 868mhz" case .lora24: return "2.4 GHZ" - case .my_433: + case .my433: return "Malaysia 433mhz" - case .my_919: + case .my919: return "Malaysia 919mhz" - case .sg_923: + case .sg923: return "Singapore 923mhz" + case .ph433: + return "Philippines 433mhz" + case .ph868: + return "Philippines 868mhz" + case .ph915: + return "Philippines 915mhz" } } var dutyCycle: Int { @@ -147,11 +162,17 @@ enum RegionCodes: Int, CaseIterable, Identifiable { return 10 case .lora24: return 100 - case .my_433: + case .my433: return 100 - case .my_919: + case .my919: return 100 - case .sg_923: + case .sg923: + return 100 + case .ph433: + return 100 + case .ph868: + return 100 + case .ph915: return 100 } } @@ -190,12 +211,18 @@ enum RegionCodes: Int, CaseIterable, Identifiable { return Config.LoRaConfig.RegionCode.ua868 case .lora24: return Config.LoRaConfig.RegionCode.lora24 - case .my_433: + case .my433: return Config.LoRaConfig.RegionCode.my433 - case .my_919: + case .my919: return Config.LoRaConfig.RegionCode.my919 - case .sg_923: + case .sg923: return Config.LoRaConfig.RegionCode.sg923 + case .ph433: + return Config.LoRaConfig.RegionCode.ph433 + case .ph868: + return Config.LoRaConfig.RegionCode.ph868 + case .ph915: + return Config.LoRaConfig.RegionCode.ph915 } } } diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index 9c4ed69c..803c4dff 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -780,6 +780,9 @@ func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManage sentPackets: UInt32(telemetry.numPacketsTx), receivedPackets: UInt32(telemetry.numPacketsRx), badReceivedPackets: UInt32(telemetry.numPacketsRxBad), + dupeReceivedPackets: UInt32(telemetry.numRxDupe), + packetsSentRelay: UInt32(telemetry.numTxRelay), + packetsCanceledRelay: UInt32(telemetry.numTxRelayCanceled), nodesOnline: UInt32(telemetry.numOnlineNodes), totalNodes: UInt32(telemetry.numTotalNodes), timerRange: date) diff --git a/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion b/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion index 4269da21..6d376a5f 100644 --- a/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion +++ b/Meshtastic/Meshtastic.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - MeshtasticDataModelV 45.xcdatamodel + MeshtasticDataModelV 46.xcdatamodel diff --git a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 46.xcdatamodel/contents b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 46.xcdatamodel/contents new file mode 100644 index 00000000..a79a311f --- /dev/null +++ b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 46.xcdatamodel/contents @@ -0,0 +1,482 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Meshtastic/Persistence/UpdateCoreData.swift b/Meshtastic/Persistence/UpdateCoreData.swift index 69757588..548ead43 100644 --- a/Meshtastic/Persistence/UpdateCoreData.swift +++ b/Meshtastic/Persistence/UpdateCoreData.swift @@ -989,7 +989,7 @@ func upsertDetectionSensorModuleConfigPacket(config: ModuleConfig.DetectionSenso newConfig.sendBell = config.sendBell newConfig.name = config.name newConfig.monitorPin = Int32(config.monitorPin) - newConfig.detectionTriggeredHigh = config.detectionTriggeredHigh + newConfig.detectionTriggeredHigh = config.detectionTriggerType == .logicHigh ? true : false newConfig.usePullup = config.usePullup newConfig.minimumBroadcastSecs = Int32(truncatingIfNeeded: config.minimumBroadcastSecs) newConfig.stateBroadcastSecs = Int32(truncatingIfNeeded: config.stateBroadcastSecs) @@ -1000,7 +1000,7 @@ func upsertDetectionSensorModuleConfigPacket(config: ModuleConfig.DetectionSenso fetchedNode[0].detectionSensorConfig?.name = config.name fetchedNode[0].detectionSensorConfig?.monitorPin = Int32(config.monitorPin) fetchedNode[0].detectionSensorConfig?.usePullup = config.usePullup - fetchedNode[0].detectionSensorConfig?.detectionTriggeredHigh = config.detectionTriggeredHigh + fetchedNode[0].detectionSensorConfig?.detectionTriggeredHigh = config.detectionTriggerType == .logicHigh ? true : false fetchedNode[0].detectionSensorConfig?.minimumBroadcastSecs = Int32(truncatingIfNeeded: config.minimumBroadcastSecs) fetchedNode[0].detectionSensorConfig?.stateBroadcastSecs = Int32(truncatingIfNeeded: config.stateBroadcastSecs) } diff --git a/Meshtastic/Views/Bluetooth/Connect.swift b/Meshtastic/Views/Bluetooth/Connect.swift index c26b7676..be466530 100644 --- a/Meshtastic/Views/Bluetooth/Connect.swift +++ b/Meshtastic/Views/Bluetooth/Connect.swift @@ -341,6 +341,9 @@ struct Connect: View { sentPackets: UInt32(mostRecent?.numPacketsTx ?? 0), receivedPackets: UInt32(mostRecent?.numPacketsRx ?? 0), badReceivedPackets: UInt32(mostRecent?.numPacketsRxBad ?? 0), + dupeReceivedPackets: UInt32(mostRecent?.numRxDupe ?? 0), + packetsSentRelay: UInt32(mostRecent?.numTxRelay ?? 0), + packetsCanceledRelay: UInt32(mostRecent?.numTxRelayCanceled ?? 0), nodesOnline: UInt32(mostRecent?.numOnlineNodes ?? 0), totalNodes: UInt32(mostRecent?.numTotalNodes ?? 0), timerRange: Date.now...future) diff --git a/Meshtastic/Views/Helpers/SecureInput.swift b/Meshtastic/Views/Helpers/SecureInput.swift index a2994747..6bcab1d0 100644 --- a/Meshtastic/Views/Helpers/SecureInput.swift +++ b/Meshtastic/Views/Helpers/SecureInput.swift @@ -12,7 +12,7 @@ struct SecureInput: View { private var idiom: UIUserInterfaceIdiom { UIDevice.current.userInterfaceIdiom } @Binding private var text: String @Binding private var isValid: Bool - @State private var isSecure: Bool = true + @State var isSecure: Bool = true private var title: String init(_ title: String, text: Binding, isValid: Binding) { diff --git a/Meshtastic/Views/Settings/Config/Module/DetectionSensorConfig.swift b/Meshtastic/Views/Settings/Config/Module/DetectionSensorConfig.swift index eb50a80f..076cb016 100644 --- a/Meshtastic/Views/Settings/Config/Module/DetectionSensorConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/DetectionSensorConfig.swift @@ -116,11 +116,11 @@ struct DetectionSensorConfig: View { } .pickerStyle(DefaultPickerStyle()) - Toggle(isOn: $detectionTriggeredHigh) { - Label("Detection trigger High", systemImage: "dial.high") - Text("Whether or not the GPIO pin state detection is triggered on HIGH (1) or LOW (0)") - } - .toggleStyle(SwitchToggleStyle(tint: .accentColor)) +// Toggle(isOn: $detectionTriggeredHigh) { +// Label("Detection trigger High", systemImage: "dial.high") +// Text("Whether or not the GPIO pin state detection is triggered on HIGH (1) or LOW (0)") +// } +// .toggleStyle(SwitchToggleStyle(tint: .accentColor)) Toggle(isOn: $usePullup) { Label("Uses pullup resistor", systemImage: "arrow.up.to.line") @@ -166,7 +166,7 @@ struct DetectionSensorConfig: View { dsc.sendBell = self.sendBell dsc.name = self.name dsc.monitorPin = UInt32(self.monitorPin) - dsc.detectionTriggeredHigh = self.detectionTriggeredHigh + // dsc.detectionTriggeredHigh = self.detectionTriggeredHigh dsc.usePullup = self.usePullup dsc.minimumBroadcastSecs = UInt32(self.minimumBroadcastSecs) dsc.stateBroadcastSecs = UInt32(self.stateBroadcastSecs) @@ -217,7 +217,7 @@ struct DetectionSensorConfig: View { if newSendBell != node?.detectionSensorConfig?.sendBell { hasChanges = true } } .onChange(of: detectionTriggeredHigh) { _, newDetectionTriggeredHigh in - if newDetectionTriggeredHigh != node?.detectionSensorConfig?.detectionTriggeredHigh { hasChanges = true } + // if newDetectionTriggeredHigh != node?.detectionSensorConfig?.detectionTriggeredHigh { hasChanges = true } } .onChange(of: usePullup) { _, newUsePullup in if newUsePullup != node?.detectionSensorConfig?.usePullup { hasChanges = true } @@ -244,7 +244,7 @@ struct DetectionSensorConfig: View { self.name = (node?.detectionSensorConfig?.name ?? "") self.monitorPin = Int(node?.detectionSensorConfig?.monitorPin ?? 0) self.usePullup = (node?.detectionSensorConfig?.usePullup ?? false) - self.detectionTriggeredHigh = (node?.detectionSensorConfig?.detectionTriggeredHigh ?? true) + // self.detectionTriggeredHigh = (node?.detectionSensorConfig?.detectionTriggeredHigh ?? true) self.minimumBroadcastSecs = Int(node?.detectionSensorConfig?.minimumBroadcastSecs ?? 45) self.stateBroadcastSecs = Int(node?.detectionSensorConfig?.stateBroadcastSecs ?? 0) diff --git a/Meshtastic/Views/Settings/Config/SecurityConfig.swift b/Meshtastic/Views/Settings/Config/SecurityConfig.swift index 75b69463..8ddd5816 100644 --- a/Meshtastic/Views/Settings/Config/SecurityConfig.swift +++ b/Meshtastic/Views/Settings/Config/SecurityConfig.swift @@ -26,7 +26,11 @@ struct SecurityConfig: View { @State var privateKey = "" @State var hasValidPrivateKey: Bool = false @State var adminKey = "" + @State var adminKey2 = "" + @State var adminKey3 = "" @State var hasValidAdminKey: Bool = true + @State var hasValidAdminKey2: Bool = true + @State var hasValidAdminKey3: Bool = true @State var isManaged = false @State var serialEnabled = false @State var debugLogApiEnabled = false @@ -49,8 +53,7 @@ struct SecurityConfig: View { Text("Sent out to other nodes on the mesh to allow them to compute a shared secret key.") .foregroundStyle(.secondary) .font(idiom == .phone ? .caption : .callout) - } - VStack(alignment: .leading) { + Divider() Label("Private Key", systemImage: "key.fill") SecureInput("Private Key", text: $privateKey, isValid: $hasValidPrivateKey) .background( @@ -60,11 +63,34 @@ struct SecurityConfig: View { Text("Used to create a shared key with a remote device.") .foregroundStyle(.secondary) .font(idiom == .phone ? .caption : .callout) - } - VStack(alignment: .leading) { - Label("Admin Key", systemImage: "key.viewfinder") - SecureInput("Admin Key", text: $adminKey, isValid: $hasValidAdminKey) - Text("The public key authorized to send admin messages to this node.") + Divider() + Label("Primary Admin Key", systemImage: "key.viewfinder") + SecureInput("Primary Admin Key", text: $adminKey, isValid: $hasValidAdminKey) + .background( + RoundedRectangle(cornerRadius: 10.0) + .stroke(hasValidAdminKey ? Color.clear : Color.red, lineWidth: 2.0) + ) + Text("The primary public key authorized to send admin messages to this node.") + .foregroundStyle(.secondary) + .font(idiom == .phone ? .caption : .callout) + Divider() + Label("Secondary Admin Key", systemImage: "key.viewfinder") + SecureInput("Secondary Admin Key", text: $adminKey2, isValid: $hasValidAdminKey2) + .background( + RoundedRectangle(cornerRadius: 10.0) + .stroke(hasValidAdminKey2 ? Color.clear : Color.red, lineWidth: 2.0) + ) + Text("The secondary public key authorized to send admin messages to this node.") + .foregroundStyle(.secondary) + .font(idiom == .phone ? .caption : .callout) + Divider() + Label("Tertiary Admin Key", systemImage: "key.viewfinder") + SecureInput("Tertiary Admin Key", text: $adminKey2, isValid: $hasValidAdminKey2) + .background( + RoundedRectangle(cornerRadius: 10.0) + .stroke(hasValidAdminKey3 ? Color.clear : Color.red, lineWidth: 2.0) + ) + Text("The tertiarypublic key authorized to send admin messages to this node.") .foregroundStyle(.secondary) .font(idiom == .phone ? .caption : .callout) } @@ -147,6 +173,28 @@ struct SecurityConfig: View { } hasChanges = true } + .onChange(of: adminKey2) { _, key in + let tempKey = Data(base64Encoded: key) ?? Data() + if key.isEmpty { + hasValidAdminKey2 = true + } else if tempKey.count == 32 { + hasValidAdminKey2 = true + } else { + hasValidAdminKey2 = false + } + hasChanges = true + } + .onChange(of: adminKey3) { _, key in + let tempKey = Data(base64Encoded: key) ?? Data() + if key.isEmpty { + hasValidAdminKey3 = true + } else if tempKey.count == 32 { + hasValidAdminKey3 = true + } else { + hasValidAdminKey3 = false + } + hasChanges = true + } .onFirstAppear { // Need to request a DeviceConfig from the remote node before allowing changes if let connectedPeripheral = bleManager.connectedPeripheral, let node { @@ -186,7 +234,7 @@ struct SecurityConfig: View { var config = Config.SecurityConfig() config.publicKey = Data(base64Encoded: publicKey) ?? Data() config.privateKey = Data(base64Encoded: privateKey) ?? Data() - config.adminKey = [Data(base64Encoded: adminKey) ?? Data()] + config.adminKey = [Data(base64Encoded: adminKey) ?? Data(), Data(base64Encoded: adminKey2) ?? Data(), Data(base64Encoded: adminKey3) ?? Data()] config.isManaged = isManaged config.serialEnabled = serialEnabled config.debugLogApiEnabled = debugLogApiEnabled @@ -211,6 +259,8 @@ struct SecurityConfig: View { self.publicKey = node?.securityConfig?.publicKey?.base64EncodedString() ?? "" self.privateKey = node?.securityConfig?.privateKey?.base64EncodedString() ?? "" self.adminKey = node?.securityConfig?.adminKey?.base64EncodedString() ?? "" + self.adminKey2 = node?.securityConfig?.adminKey?.base64EncodedString() ?? "" + self.adminKey3 = node?.securityConfig?.adminKey?.base64EncodedString() ?? "" self.isManaged = node?.securityConfig?.isManaged ?? false self.serialEnabled = node?.securityConfig?.serialEnabled ?? false self.debugLogApiEnabled = node?.securityConfig?.debugLogApiEnabled ?? false diff --git a/Widgets/MeshActivityAttributes.swift b/Widgets/MeshActivityAttributes.swift index a2abdbba..876b75de 100644 --- a/Widgets/MeshActivityAttributes.swift +++ b/Widgets/MeshActivityAttributes.swift @@ -21,8 +21,13 @@ struct MeshActivityAttributes: ActivityAttributes { var sentPackets: UInt32 var receivedPackets: UInt32 var badReceivedPackets: UInt32 + var dupeReceivedPackets: UInt32 + var packetsSentRelay: UInt32 + var packetsCanceledRelay: UInt32 var nodesOnline: UInt32 var totalNodes: UInt32 + + public var numTxRelayCanceled: UInt32 = 0 var timerRange: ClosedRange } diff --git a/Widgets/WidgetsLiveActivity.swift b/Widgets/WidgetsLiveActivity.swift index e16e3913..efc6ca11 100644 --- a/Widgets/WidgetsLiveActivity.swift +++ b/Widgets/WidgetsLiveActivity.swift @@ -122,7 +122,7 @@ struct WidgetsLiveActivity: Widget { struct WidgetsLiveActivity_Previews: PreviewProvider { static let attributes = MeshActivityAttributes(nodeNum: 123456789, name: "RAK Compact Rotary Handset Gray 8E6G") - static let state = MeshActivityAttributes.ContentState(uptimeSeconds: 600, channelUtilization: 1.2, airtime: 3.5, sentPackets: 12587, receivedPackets: 12555, badReceivedPackets: 800, nodesOnline: 99, totalNodes: 100, timerRange: Date.now...Date(timeIntervalSinceNow: 300)) + static let state = MeshActivityAttributes.ContentState(uptimeSeconds: 600, channelUtilization: 1.2, airtime: 3.5, sentPackets: 12587, receivedPackets: 12555, badReceivedPackets: 800, dupeReceivedPackets: 100 , packetsSentRelay: 250, packetsCanceledRelay: 372, nodesOnline: 99, totalNodes: 100, timerRange: Date.now...Date(timeIntervalSinceNow: 300)) static var previews: some View { attributes