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 {