diff --git a/Localizable.xcstrings b/Localizable.xcstrings index aaa84ccd..11d7c54b 100644 --- a/Localizable.xcstrings +++ b/Localizable.xcstrings @@ -194,6 +194,9 @@ }, "256 bit" : { + }, + "A Trace Route was sent, no response has been received." : { + }, "about" : { "localizations" : { @@ -20156,7 +20159,7 @@ "Store and forward clients can request history from routers on the network." : { }, - "Store and forward router devices must also be in the router or router client device role and requires a ESP32 device with PSRAM." : { + "Store and forward router devices require a ESP32 device with PSRAM." : { }, "storeforward" : { @@ -21874,6 +21877,12 @@ }, "Trace route sent to %@" : { + }, + "Trace route to %@ was not sent." : { + + }, + "Trace Route was rate limited. You can send a trace route a maximum of once every thirty seconds." : { + }, "Traffic" : { diff --git a/Meshtastic/Helpers/BLEManager.swift b/Meshtastic/Helpers/BLEManager.swift index 0ffb0af2..bb1cb8c4 100644 --- a/Meshtastic/Helpers/BLEManager.swift +++ b/Meshtastic/Helpers/BLEManager.swift @@ -592,7 +592,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate return } do { - let logRecord = try LogRecord(serializedData: characteristic.value!) + let logRecord = try LogRecord(serializedBytes: characteristic.value!) var message = logRecord.source.isEmpty ? logRecord.message : "[\(logRecord.source)] \(logRecord.message)" switch logRecord.level { case .debug: @@ -613,14 +613,6 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate // Ignore fail to parse as LogRecord } - case LEGACY_LOGRADIO_UUID: - if characteristic.value == nil || characteristic.value!.isEmpty { - return - } - if let log = String(data: characteristic.value!, encoding: .utf8) { - handleRadioLog(radioLog: log) - } - case FROMRADIO_UUID: if characteristic.value == nil || characteristic.value!.isEmpty { @@ -629,7 +621,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate var decodedInfo = FromRadio() do { - decodedInfo = try FromRadio(serializedData: characteristic.value!) + decodedInfo = try FromRadio(serializedBytes: characteristic.value!) } catch { Logger.services.error("πŸ’₯ \(error.localizedDescription, privacy: .public) \(characteristic.value!, privacy: .public)") @@ -644,6 +636,21 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate ) mqttManager.mqttClientProxy?.publish(message) } else if decodedInfo.payloadVariant == FromRadio.OneOf_PayloadVariant.clientNotification(decodedInfo.clientNotification) { + if decodedInfo.clientNotification.hasReplyID { + /// Set Sent bool on TraceRouteEntity to false if we got rate limited + if decodedInfo.clientNotification.message.starts(with: "TraceRoute") { + let traceRoute = getTraceRoute(id: Int64(decodedInfo.clientNotification.replyID), context: context) + traceRoute?.sent = false + do { + try context.save() + Logger.data.info("πŸ’Ύ [TraceRouteEntity] Trace Route Rate Limited") + } catch { + context.rollback() + let nsError = error as NSError + Logger.data.error("πŸ’₯ [TraceRouteEntity] Error Updating Core Data: \(nsError, privacy: .public)") + } + } + } let manager = LocalNotificationManager() manager.notifications = [ Notification( @@ -916,7 +923,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate } } case .neighborinfoApp: - if let neighborInfo = try? NeighborInfo(serializedData: decodedInfo.packet.decoded.payload) { + if let neighborInfo = try? NeighborInfo(serializedBytes: decodedInfo.packet.decoded.payload) { // MeshLogger.log("πŸ•ΈοΈ MESH PACKET received for Neighbor Info App UNHANDLED") MeshLogger.log("πŸ•ΈοΈ MESH PACKET received for Neighbor Info App UNHANDLED \(neighborInfo)") } diff --git a/Meshtastic/Helpers/LocationsHandler.swift b/Meshtastic/Helpers/LocationsHandler.swift index 9b16e3de..20d7725f 100644 --- a/Meshtastic/Helpers/LocationsHandler.swift +++ b/Meshtastic/Helpers/LocationsHandler.swift @@ -85,15 +85,15 @@ import OSLog if smartPostion { let age = -location.timestamp.timeIntervalSinceNow if age > 10 { - Logger.services.warning("πŸ“ [App] Bad Location \(self.count, privacy: .public): Too Old \(age, privacy: .public) seconds ago \(location, privacy: .private)") + Logger.services.info("πŸ“ [App] Smart Position - Bad Location: Too Old \(age, privacy: .public) seconds ago \(location, privacy: .private)") return false } if location.horizontalAccuracy < 0 { - Logger.services.warning("πŸ“ [App] Bad Location \(self.count, privacy: .public): Horizontal Accuracy: \(location.horizontalAccuracy) \(location, privacy: .private)") + Logger.services.info("πŸ“ [App] Smart Position - Bad Location: Horizontal Accuracy: \(location.horizontalAccuracy) \(location, privacy: .private)") return false } if location.horizontalAccuracy > 5 { - Logger.services.warning("πŸ“ [App] Bad Location \(self.count, privacy: .public): Horizontal Accuracy: \(location.horizontalAccuracy) \(location, privacy: .private)") + Logger.services.info("πŸ“ [App] Smart Position - Bad Location: Horizontal Accuracy: \(location.horizontalAccuracy) \(location, privacy: .private)") return false } } diff --git a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 45.xcdatamodel/contents b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 45.xcdatamodel/contents index c16a68b0..65a05ff9 100644 --- a/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 45.xcdatamodel/contents +++ b/Meshtastic/Meshtastic.xcdatamodeld/MeshtasticDataModelV 45.xcdatamodel/contents @@ -418,6 +418,7 @@ + diff --git a/Meshtastic/Views/Nodes/TraceRouteLog.swift b/Meshtastic/Views/Nodes/TraceRouteLog.swift index 03c2b5ba..f32cbc81 100644 --- a/Meshtastic/Views/Nodes/TraceRouteLog.swift +++ b/Meshtastic/Views/Nodes/TraceRouteLog.swift @@ -39,7 +39,8 @@ struct TraceRouteLog: View { VStack { List(node.traceRoutes?.reversed() as? [TraceRouteEntity] ?? [], id: \.self, selection: $selectedRoute) { route in Label { - Text("\(route.time?.formatted() ?? "unknown".localized) - \(route.response ? (route.hops?.count == 0 && route.response ? "Direct" : "\(route.hops?.count ?? 0) \(route.hops?.count ?? 0 == 1 ? "Hop": "Hops")") : "No Response")") + Text("\(route.time?.formatted() ?? "unknown".localized) - \(route.response ? (route.hops?.count == 0 && route.response ? "Direct" : "\(route.hops?.count ?? 0) \(route.hops?.count ?? 0 == 1 ? "Hop": "Hops")") : (route.sent ? "No Response" : "Not Sent"))") + .font(.callout) } icon: { Image(systemName: route.response ? (route.hops?.count == 0 && route.response ? "person.line.dotted.person" : "point.3.connected.trianglepath.dotted") : "person.slash") .symbolRenderingMode(.hierarchical) @@ -47,7 +48,7 @@ struct TraceRouteLog: View { } .listStyle(.plain) } - .frame(minHeight: CGFloat(node.traceRoutes?.count ?? 0 * 40), maxHeight: 150) + .frame(minHeight: CGFloat(node.traceRoutes?.count ?? 0 * 40), maxHeight: 250) Divider() ScrollView { if selectedRoute != nil { @@ -74,16 +75,36 @@ struct TraceRouteLog: View { .symbolRenderingMode(.hierarchical) } .font(.title3) + } else if !(selectedRoute?.sent ?? true) { + Label { + VStack { + Text("Trace route to \(selectedRoute?.node?.user?.longName ?? "unknown".localized) was not sent.") + .font(idiom == .phone ? .body : .largeTitle) + .fontWeight(.semibold) + Text("Trace Route was rate limited. You can send a trace route a maximum of once every thirty seconds.") + .font(idiom == .phone ? .caption : .body) + .foregroundStyle(.secondary) + .padding() + } + } icon: { + Image(systemName: "square.and.arrow.up.trianglebadge.exclamationmark") + .symbolRenderingMode(.hierarchical) + } } else { - VStack { - Label { + Label { + VStack { Text("Trace route sent to \(selectedRoute?.node?.user?.longName ?? "unknown".localized)") - } icon: { - Image(systemName: "signpost.right.and.left") - .symbolRenderingMode(.hierarchical) + .font(idiom == .phone ? .body : .largeTitle) + .fontWeight(.semibold) + Text("A Trace Route was sent, no response has been received.") + .font(idiom == .phone ? .caption : .body) + .foregroundStyle(.secondary) + .padding() } - .font(idiom == .phone ? .headline : .largeTitle) - } + } icon: { + Image(systemName: "signpost.right.and.left") + .symbolRenderingMode(.hierarchical) + } } if selectedRoute?.hops?.count ?? 0 >= 3 { HStack(alignment: .center) { diff --git a/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift b/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift index 8fff8979..aeee9601 100644 --- a/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift +++ b/Meshtastic/Views/Settings/Config/Module/StoreForwardConfig.swift @@ -56,7 +56,7 @@ struct StoreForwardConfig: View { } VStack { if isRouter { - Text("Store and forward router devices must also be in the router or router client device role and requires a ESP32 device with PSRAM.") + Text("Store and forward router devices require a ESP32 device with PSRAM.") .foregroundColor(.gray) .font(.callout) } else {