diff --git a/Meshtastic/Helpers/MeshPackets.swift b/Meshtastic/Helpers/MeshPackets.swift index ecafa677..299dfae1 100644 --- a/Meshtastic/Helpers/MeshPackets.swift +++ b/Meshtastic/Helpers/MeshPackets.swift @@ -8,6 +8,9 @@ import Foundation import CoreData import SwiftUI +#if canImport(ActivityKit) +import ActivityKit +#endif func generateMessageMarkdown (message: String) -> String { @@ -635,6 +638,9 @@ func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManage if connectedNode != Int64(packet.from) { let logString = String.localizedStringWithFormat(NSLocalizedString("mesh.log.telemetry.received %@", comment: "Telemetry received for: %@"), String(packet.from)) MeshLogger.log("📈 \(logString)") + } else { + // If it is the connected node + } let telemetry = TelemetryEntity(context: context) @@ -674,6 +680,24 @@ func telemetryPacket(packet: MeshPacket, connectedNode: Int64, context: NSManage // Only log telemetry from the mesh not the connected device if connectedNode != Int64(packet.from) { print("💾 Telemetry Saved for Node: \(packet.from)") + } else if telemetry.metricsType == 0 { + if #available(iOS 16.2, *) { + var future = Calendar.current.date(byAdding: .minute, value: (Int(0) ), to: Date())! + future = Calendar.current.date(byAdding: .second, value: (Int(60) ), to: future)! + let date = Date.now...future + let updatedMeshStatus = MeshActivityAttributes.MyActivityStatus(timerRange: date, connected: true, channelUtilization: telemetry.channelUtilization, airtime: telemetry.airUtilTx, batteryLevel: UInt32(telemetry.batteryLevel)) + + let alertConfiguration = AlertConfiguration(title: "Mesh activity update", body: "Updated Metrics Data.", sound: .default) + let updatedContent = ActivityContent(state: updatedMeshStatus, staleDate: nil) + print("Update live activity.") + + let stuff = Activity.activities.first(where: { $0.attributes.nodeNum == connectedNode }) + if stuff != nil { + Task { + await stuff?.update(updatedContent, alertConfiguration: alertConfiguration) + } + } + } } } catch { context.rollback() diff --git a/Meshtastic/Views/Bluetooth/Connect.swift b/Meshtastic/Views/Bluetooth/Connect.swift index 80d65a37..b9129950 100644 --- a/Meshtastic/Views/Bluetooth/Connect.swift +++ b/Meshtastic/Views/Bluetooth/Connect.swift @@ -127,7 +127,6 @@ struct Connect: View { Text("Max Channels: \(String(node?.myInfo?.maxChannels ?? 0))") Text("Bitrate: \(String(format: "%.2f", node?.myInfo?.bitrate ?? 0.00))") Text("BLE RSSI: \(bleManager.connectedPeripheral.rssi)") - } } if isUnsetRegion { @@ -316,11 +315,11 @@ func startNodeActivity() { let mostRecent = node?.telemetries?.lastObject as! TelemetryEntity - let activityAttributes = MeshActivityAttributes(nodeNum: Int(node?.num ?? 0), name: node?.user?.longName ?? "unknown", connected: true, channelUtilization: mostRecent.channelUtilization, airtime: mostRecent.airUtilTx, batteryLevel: UInt32(mostRecent.batteryLevel)) + let activityAttributes = MeshActivityAttributes(nodeNum: Int(node?.num ?? 0), name: node?.user?.longName ?? "unknown") let future = Date(timeIntervalSinceNow: Double(timerSeconds)) - let initialContentState = MeshActivityAttributes.ContentState(timerRange: Date.now...future) + let initialContentState = MeshActivityAttributes.ContentState(timerRange: Date.now...future, connected: true, channelUtilization: mostRecent.channelUtilization, airtime: mostRecent.airUtilTx, batteryLevel: UInt32(mostRecent.batteryLevel)) let activityContent = ActivityContent(state: initialContentState, staleDate: Calendar.current.date(byAdding: .minute, value: 2, to: Date())!) @@ -328,7 +327,6 @@ func startNodeActivity() { let myActivity = try Activity.request(attributes: activityAttributes, content: activityContent, pushType: nil) print(" Requested MyActivity live activity. ID: \(myActivity.id)") - postNotification() } catch let error { print("Error requesting live activity: \(error.localizedDescription)") } @@ -352,7 +350,7 @@ func endActivity() { #if os(iOS) func postNotification() { - let timerSeconds = 300 + let timerSeconds = 60 let content = UNMutableNotificationContent() content.title = "Mesh Live Activity Over" content.body = "Your timed mesh live activity is over." diff --git a/Widgets/MeshActivityAttributes.swift b/Widgets/MeshActivityAttributes.swift index 4b09b52d..4d46cca0 100644 --- a/Widgets/MeshActivityAttributes.swift +++ b/Widgets/MeshActivityAttributes.swift @@ -16,14 +16,14 @@ struct MeshActivityAttributes: ActivityAttributes { public struct ContentState: Codable, Hashable { // Dynamic stateful properties about your activity go here! var timerRange: ClosedRange + var connected: Bool + var channelUtilization: Float + var airtime: Float + var batteryLevel: UInt32 } // Fixed non-changing properties about your activity go here! var nodeNum: Int var name: String - var connected: Bool - var channelUtilization: Float - var airtime: Float - var batteryLevel: UInt32 } #endif diff --git a/Widgets/WidgetsLiveActivity.swift b/Widgets/WidgetsLiveActivity.swift index d2bec44b..3a092829 100644 --- a/Widgets/WidgetsLiveActivity.swift +++ b/Widgets/WidgetsLiveActivity.swift @@ -14,13 +14,13 @@ struct WidgetsLiveActivity: Widget { var body: some WidgetConfiguration { ActivityConfiguration(for: MeshActivityAttributes.self) { context in - LiveActivityView(nodeName: context.attributes.name, connected: context.attributes.connected, channelUtilization: context.attributes.channelUtilization, airtime: context.attributes.airtime, batteryLevel: context.attributes.batteryLevel, timerRange: context.state.timerRange) + LiveActivityView(nodeName: context.attributes.name, connected: context.state.connected, channelUtilization: context.state.channelUtilization, airtime: context.state.airtime, batteryLevel: context.state.batteryLevel, timerRange: context.state.timerRange) .widgetURL(URL(string: "meshtastic://node/\(context.attributes.name)")) } dynamicIsland: { context in DynamicIsland { DynamicIslandExpandedRegion(.leading) { - NodeInfoView(nodeName: context.attributes.name, connected: context.attributes.connected, channelUtilization: context.attributes.channelUtilization, airtime: context.attributes.airtime, batteryLevel: context.attributes.batteryLevel) + NodeInfoView(nodeName: context.attributes.name, connected: context.state.connected, channelUtilization: context.state.channelUtilization, airtime: context.state.airtime, batteryLevel: context.state.batteryLevel) .tint(Color("LightIndigo")) .padding(.top) } @@ -65,9 +65,9 @@ struct WidgetsLiveActivity: Widget { @available(iOS 16.2, *) struct WidgetsLiveActivity_Previews: PreviewProvider { - static let attributes = MeshActivityAttributes(nodeNum: 123456789, name: "Meshtastic 8E6G", connected: true, channelUtilization: 0.24, airtime: 0.87, batteryLevel: 39) + static let attributes = MeshActivityAttributes(nodeNum: 123456789, name: "Meshtastic 8E6G") static let state = MeshActivityAttributes.ContentState( - timerRange: Date.now...Date(timeIntervalSinceNow: 3600)) + timerRange: Date.now...Date(timeIntervalSinceNow: 3600), connected: true, channelUtilization: 25.84, airtime: 10.01, batteryLevel: 39) static var previews: some View { attributes @@ -168,14 +168,14 @@ struct TimerView: View { .monospacedDigit() .multilineTextAlignment(.trailing) .frame(width: 80) - .font(.title3) + .font(.callout) .fontWeight(.semibold) .foregroundStyle(.tint) Image(systemName: "timer") .resizable() .foregroundStyle(.secondary) .frame(width: 30, height: 30) - .padding(.trailing) + .padding(.trailing, 7) .opacity(isLuminanceReduced ? 0.5 : 1.0) } }