Initial commit — RoadCode import

This commit is contained in:
2026-03-08 20:04:49 -05:00
commit 7756eefa02
250 changed files with 24953 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
import Foundation
// MARK: - Shared Data Models (used by both iOS and watchOS)
struct SensorData: Codable {
var temperature: Double
var humidity: Double
var light: Int
var accelX: Double
var accelY: Double
var accelZ: Double
var batteryMV: Int
var uptimeSec: UInt32
}
struct AIStatus: Codable {
var modelID: Int
var confidence: Int
var inferenceMS: Int
var totalInferences: UInt32
var npuLoad: Int
var npuTemp: Int
var classID: Int
}
struct SystemHealth: Codable {
var fleetOnline: Int
var fleetTotal: Int
var agentsActive: Int
var trafficGreen: Int
var trafficYellow: Int
var trafficRed: Int
var tasksPending: Int
var tasksDone: Int
var memoryEntries: UInt32
var reposCount: Int
var cfProjects: Int
var cpuLoad: Double
}

View File

@@ -0,0 +1,77 @@
import SwiftUI
import WatchConnectivity
// MARK: - Watch App Entry Point
@main
struct BlackRoadWatchApp: App {
@StateObject private var dataStore = WatchDataStore.shared
var body: some Scene {
WindowGroup {
WatchContentView()
.environmentObject(dataStore)
}
}
}
// MARK: - Watch Data Store (receives from iPhone)
class WatchDataStore: NSObject, ObservableObject {
static let shared = WatchDataStore()
@Published var sensor: SensorData?
@Published var ai: AIStatus?
@Published var health: SystemHealth?
@Published var lastUpdate: Date?
@Published var isConnected = false
private var wcSession: WCSession?
override init() {
super.init()
guard WCSession.isSupported() else { return }
wcSession = WCSession.default
wcSession?.delegate = self
wcSession?.activate()
}
private func processContext(_ context: [String: Any]) {
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
if let sensorDict = context["sensor"],
let sensorData = try? JSONSerialization.data(withJSONObject: sensorDict),
let sensor = try? JSONDecoder().decode(SensorData.self, from: sensorData) {
self.sensor = sensor
}
if let aiDict = context["ai"],
let aiData = try? JSONSerialization.data(withJSONObject: aiDict),
let ai = try? JSONDecoder().decode(AIStatus.self, from: aiData) {
self.ai = ai
}
if let healthDict = context["health"],
let healthData = try? JSONSerialization.data(withJSONObject: healthDict),
let health = try? JSONDecoder().decode(SystemHealth.self, from: healthData) {
self.health = health
}
self.lastUpdate = Date()
self.isConnected = true
}
}
}
extension WatchDataStore: WCSessionDelegate {
func session(_ session: WCSession, activationDidCompleteWith state: WCSessionActivationState, error: Error?) {}
func session(_ session: WCSession, didReceiveMessage message: [String: Any]) {
processContext(message)
}
func session(_ session: WCSession, didReceiveApplicationContext context: [String: Any]) {
processContext(context)
}
}

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>BlackRoad</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>WKApplication</key>
<true/>
<key>WKCompanionAppBundleIdentifier</key>
<string>io.blackroad.watch</string>
</dict>
</plist>

View File

@@ -0,0 +1,335 @@
import SwiftUI
// MARK: - Brand Colors (Watch)
extension Color {
static let brHotPink = Color(red: 1.0, green: 0.114, blue: 0.424)
static let brAmber = Color(red: 0.961, green: 0.651, blue: 0.137)
static let brElectricBlue = Color(red: 0.161, green: 0.475, blue: 1.0)
static let brViolet = Color(red: 0.612, green: 0.153, blue: 0.690)
}
// MARK: - Main Watch View
struct WatchContentView: View {
@EnvironmentObject var store: WatchDataStore
@State private var currentPage = 0
var body: some View {
TabView(selection: $currentPage) {
WatchFaceView()
.tag(0)
FleetDashboardView()
.tag(1)
SensorView()
.tag(2)
AIView()
.tag(3)
}
.tabViewStyle(.page)
}
}
// MARK: - Page 1: Watch Face
struct WatchFaceView: View {
@EnvironmentObject var store: WatchDataStore
@State private var currentTime = Date()
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
var body: some View {
ZStack {
LinearGradient(
colors: [.black, Color(white: 0.05)],
startPoint: .top,
endPoint: .bottom
)
VStack(spacing: 4) {
Text(timeString)
.font(.system(size: 48, weight: .thin, design: .rounded))
.foregroundStyle(
LinearGradient(
colors: [.brAmber, .brHotPink],
startPoint: .leading,
endPoint: .trailing
)
)
Text(dateString)
.font(.system(size: 13, weight: .medium))
.foregroundColor(.gray)
Spacer().frame(height: 8)
HStack(spacing: 12) {
VStack(spacing: 2) {
Image(systemName: "server.rack")
.font(.system(size: 12))
.foregroundColor(.brElectricBlue)
Text("\(store.health?.fleetOnline ?? 0)/\(store.health?.fleetTotal ?? 0)")
.font(.system(size: 11, weight: .semibold, design: .monospaced))
.foregroundColor(.white)
}
VStack(spacing: 2) {
Circle()
.fill(.green)
.frame(width: 10, height: 10)
Text("\(store.health?.trafficGreen ?? 0)")
.font(.system(size: 11, weight: .semibold, design: .monospaced))
.foregroundColor(.white)
}
VStack(spacing: 2) {
Image(systemName: "brain")
.font(.system(size: 12))
.foregroundColor(.brViolet)
Text("\(store.health?.agentsActive ?? 0)")
.font(.system(size: 11, weight: .semibold, design: .monospaced))
.foregroundColor(.white)
}
VStack(spacing: 2) {
Image(systemName: "thermometer.medium")
.font(.system(size: 12))
.foregroundColor(.brAmber)
Text(String(format: "%.0f\u{00B0}", store.sensor?.temperature ?? 0))
.font(.system(size: 11, weight: .semibold, design: .monospaced))
.foregroundColor(.white)
}
}
HStack(spacing: 4) {
Circle()
.fill(store.isConnected ? .brHotPink : .gray)
.frame(width: 6, height: 6)
Text(store.isConnected ? "BLACKROAD" : "OFFLINE")
.font(.system(size: 9, weight: .bold, design: .monospaced))
.foregroundColor(store.isConnected ? .brHotPink : .gray)
}
.padding(.top, 4)
}
.padding()
}
.ignoresSafeArea()
.onReceive(timer) { input in
currentTime = input
}
}
private var timeString: String {
let formatter = DateFormatter()
formatter.dateFormat = "h:mm"
return formatter.string(from: currentTime)
}
private var dateString: String {
let formatter = DateFormatter()
formatter.dateFormat = "EEEE, MMM d"
return formatter.string(from: currentTime).uppercased()
}
}
// MARK: - Page 2: Fleet Dashboard
struct FleetDashboardView: View {
@EnvironmentObject var store: WatchDataStore
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 8) {
Text("FLEET")
.font(.system(size: 11, weight: .bold, design: .monospaced))
.foregroundColor(.brHotPink)
if let health = store.health {
StatRow(icon: "server.rack", label: "Devices",
value: "\(health.fleetOnline)/\(health.fleetTotal)",
color: .brElectricBlue)
StatRow(icon: "brain", label: "Agents",
value: "\(health.agentsActive)",
color: .brViolet)
StatRow(icon: "circle.fill", label: "Green",
value: "\(health.trafficGreen)",
color: .green)
StatRow(icon: "doc.text", label: "Repos",
value: "\(health.reposCount)",
color: .brAmber)
StatRow(icon: "cloud", label: "CF Projects",
value: "\(health.cfProjects)",
color: .brElectricBlue)
StatRow(icon: "checkmark.circle", label: "Tasks Done",
value: "\(health.tasksDone)",
color: .green)
StatRow(icon: "memorychip", label: "Memory",
value: "\(health.memoryEntries)",
color: .brViolet)
} else {
Text("Waiting for data...")
.font(.system(size: 12))
.foregroundColor(.gray)
}
}
.padding(.horizontal)
}
}
}
// MARK: - Page 3: Sensors
struct SensorView: View {
@EnvironmentObject var store: WatchDataStore
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 8) {
Text("SENSORS")
.font(.system(size: 11, weight: .bold, design: .monospaced))
.foregroundColor(.brAmber)
if let sensor = store.sensor {
StatRow(icon: "thermometer", label: "Temp",
value: String(format: "%.1f\u{00B0}C", sensor.temperature),
color: .brAmber)
StatRow(icon: "humidity", label: "Humidity",
value: String(format: "%.1f%%", sensor.humidity),
color: .brElectricBlue)
StatRow(icon: "battery.100", label: "Battery",
value: "\(sensor.batteryMV)mV",
color: sensor.batteryMV > 3500 ? .green : .red)
StatRow(icon: "clock", label: "Uptime",
value: formatUptime(sensor.uptimeSec),
color: .gray)
} else {
Text("No sensor data")
.font(.system(size: 12))
.foregroundColor(.gray)
}
}
.padding(.horizontal)
}
}
private func formatUptime(_ seconds: UInt32) -> String {
let h = seconds / 3600
let m = (seconds % 3600) / 60
let s = seconds % 60
return String(format: "%02d:%02d:%02d", h, m, s)
}
}
// MARK: - Page 4: AI Status
struct AIView: View {
@EnvironmentObject var store: WatchDataStore
var body: some View {
ScrollView {
VStack(alignment: .leading, spacing: 8) {
Text("NPU")
.font(.system(size: 11, weight: .bold, design: .monospaced))
.foregroundColor(.brViolet)
if let ai = store.ai {
// Confidence bar
VStack(alignment: .leading, spacing: 4) {
HStack {
Text("Confidence")
.font(.system(size: 11))
.foregroundColor(.gray)
Spacer()
Text("\(ai.confidence)%")
.font(.system(size: 11, weight: .bold, design: .monospaced))
.foregroundColor(.brHotPink)
}
GeometryReader { geo in
ZStack(alignment: .leading) {
RoundedRectangle(cornerRadius: 3)
.fill(Color.white.opacity(0.1))
RoundedRectangle(cornerRadius: 3)
.fill(
LinearGradient(
colors: [.brAmber, .brHotPink],
startPoint: .leading,
endPoint: .trailing
)
)
.frame(width: geo.size.width * CGFloat(ai.confidence) / 100.0)
}
}
.frame(height: 6)
}
StatRow(icon: "number", label: "Total",
value: "\(ai.totalInferences)",
color: .brAmber)
// NPU load bar
VStack(alignment: .leading, spacing: 4) {
HStack {
Text("NPU Load")
.font(.system(size: 11))
.foregroundColor(.gray)
Spacer()
Text("\(ai.npuLoad)%")
.font(.system(size: 11, weight: .bold, design: .monospaced))
.foregroundColor(.brElectricBlue)
}
GeometryReader { geo in
ZStack(alignment: .leading) {
RoundedRectangle(cornerRadius: 3)
.fill(Color.white.opacity(0.1))
RoundedRectangle(cornerRadius: 3)
.fill(
LinearGradient(
colors: [.brElectricBlue, .brViolet],
startPoint: .leading,
endPoint: .trailing
)
)
.frame(width: geo.size.width * CGFloat(ai.npuLoad) / 100.0)
}
}
.frame(height: 6)
}
StatRow(icon: "thermometer", label: "NPU Temp",
value: "\(ai.npuTemp)\u{00B0}C",
color: ai.npuTemp > 70 ? .red : .brAmber)
} else {
Text("No NPU data")
.font(.system(size: 12))
.foregroundColor(.gray)
}
}
.padding(.horizontal)
}
}
}
// MARK: - Reusable Components
struct StatRow: View {
let icon: String
let label: String
let value: String
let color: Color
var body: some View {
HStack {
Image(systemName: icon)
.font(.system(size: 12))
.foregroundColor(color)
.frame(width: 20)
Text(label)
.font(.system(size: 12))
.foregroundColor(.gray)
Spacer()
Text(value)
.font(.system(size: 12, weight: .semibold, design: .monospaced))
.foregroundColor(.white)
}
}
}

View File

@@ -0,0 +1,222 @@
import Foundation
import Network
import WatchConnectivity
import Combine
// MARK: - UDP Listener for M1s Firmware Broadcasts
class BlackRoadUDPManager: NSObject, ObservableObject {
static let shared = BlackRoadUDPManager()
@Published var isListening = false
@Published var isConnected = false
@Published var watchReachable = false
@Published var sensorData: SensorData?
@Published var aiStatus: AIStatus?
@Published var systemHealth: SystemHealth?
@Published var lastUpdate: Date?
@Published var packetsReceived: UInt64 = 0
@Published var sourceAddress: String = ""
private var listener: NWListener?
private var wcSession: WCSession?
private let udpPort: UInt16 = 8420
private let queue = DispatchQueue(label: "io.blackroad.udp", qos: .userInteractive)
override init() {
super.init()
setupWatchConnectivity()
}
// MARK: - UDP Listener
func startListening() {
guard listener == nil else { return }
do {
let params = NWParameters.udp
params.allowLocalEndpointReuse = true
params.requiredInterfaceType = .wifi
listener = try NWListener(using: params, on: NWEndpoint.Port(rawValue: udpPort)!)
listener?.stateUpdateHandler = { [weak self] state in
DispatchQueue.main.async {
switch state {
case .ready:
self?.isListening = true
print("[BR] UDP listener ready on port \(self?.udpPort ?? 0)")
case .failed(let error):
self?.isListening = false
print("[BR] UDP listener failed: \(error)")
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
self?.stopListening()
self?.startListening()
}
case .cancelled:
self?.isListening = false
default:
break
}
}
}
listener?.newConnectionHandler = { [weak self] connection in
self?.handleConnection(connection)
}
listener?.start(queue: queue)
} catch {
print("[BR] Failed to create UDP listener: \(error)")
}
}
func stopListening() {
listener?.cancel()
listener = nil
DispatchQueue.main.async {
self.isListening = false
self.isConnected = false
}
}
private func handleConnection(_ connection: NWConnection) {
connection.start(queue: queue)
receiveData(on: connection)
}
private func receiveData(on connection: NWConnection) {
connection.receiveMessage { [weak self] data, context, isComplete, error in
if let data = data, !data.isEmpty {
self?.processPacket(data, from: connection)
}
if error == nil {
self?.receiveData(on: connection)
}
}
}
// MARK: - JSON Parsing
private func processPacket(_ data: Data, from connection: NWConnection) {
guard let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
let type = json["type"] as? String, type == "br_watch" else {
return
}
if let endpoint = connection.currentPath?.remoteEndpoint,
case let .hostPort(host, _) = endpoint {
let addr = "\(host)"
DispatchQueue.main.async { self.sourceAddress = addr }
}
DispatchQueue.main.async { [weak self] in
guard let self = self else { return }
self.packetsReceived += 1
self.isConnected = true
self.lastUpdate = Date()
if let sensorDict = json["sensor"] as? [String: Any] {
self.sensorData = SensorData(
temperature: sensorDict["temp"] as? Double ?? 0,
humidity: sensorDict["hum"] as? Double ?? 0,
light: 0,
accelX: 0, accelY: 0, accelZ: 0,
batteryMV: sensorDict["bat"] as? Int ?? 0,
uptimeSec: UInt32(sensorDict["up"] as? Int ?? 0)
)
}
if let aiDict = json["ai"] as? [String: Any] {
self.aiStatus = AIStatus(
modelID: 1,
confidence: aiDict["conf"] as? Int ?? 0,
inferenceMS: 0,
totalInferences: UInt32(aiDict["infers"] as? Int ?? 0),
npuLoad: aiDict["load"] as? Int ?? 0,
npuTemp: aiDict["temp"] as? Int ?? 0,
classID: 0
)
}
if let fleetDict = json["fleet"] as? [String: Any] {
self.systemHealth = SystemHealth(
fleetOnline: fleetDict["on"] as? Int ?? 0,
fleetTotal: fleetDict["total"] as? Int ?? 0,
agentsActive: fleetDict["agents"] as? Int ?? 0,
trafficGreen: fleetDict["green"] as? Int ?? 0,
trafficYellow: 0,
trafficRed: 0,
tasksPending: 0,
tasksDone: fleetDict["tasks"] as? Int ?? 0,
memoryEntries: UInt32(fleetDict["mem"] as? Int ?? 0),
reposCount: fleetDict["repos"] as? Int ?? 0,
cfProjects: fleetDict["cf"] as? Int ?? 0,
cpuLoad: 0
)
}
self.sendToWatch()
}
}
// MARK: - Watch Connectivity
private func setupWatchConnectivity() {
guard WCSession.isSupported() else { return }
wcSession = WCSession.default
wcSession?.delegate = self
wcSession?.activate()
}
private func sendToWatch() {
guard let session = wcSession, session.activationState == .activated else { return }
let encoder = JSONEncoder()
var context: [String: Any] = [:]
if let sensor = sensorData,
let sensorJSON = try? encoder.encode(sensor),
let sensorDict = try? JSONSerialization.jsonObject(with: sensorJSON) {
context["sensor"] = sensorDict
}
if let ai = aiStatus,
let aiJSON = try? encoder.encode(ai),
let aiDict = try? JSONSerialization.jsonObject(with: aiJSON) {
context["ai"] = aiDict
}
if let health = systemHealth,
let healthJSON = try? encoder.encode(health),
let healthDict = try? JSONSerialization.jsonObject(with: healthJSON) {
context["health"] = healthDict
}
context["timestamp"] = Date().timeIntervalSince1970
try? session.updateApplicationContext(context)
if session.isReachable {
session.sendMessage(context, replyHandler: nil)
}
DispatchQueue.main.async {
self.watchReachable = session.isReachable
}
}
}
// MARK: - WCSessionDelegate
extension BlackRoadUDPManager: WCSessionDelegate {
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
print("[BR] Watch session activated: \(activationState.rawValue)")
DispatchQueue.main.async { self.watchReachable = session.isReachable }
}
func sessionDidBecomeInactive(_ session: WCSession) {}
func sessionDidDeactivate(_ session: WCSession) { session.activate() }
func sessionReachabilityDidChange(_ session: WCSession) {
DispatchQueue.main.async { self.watchReachable = session.isReachable }
}
}

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
</plist>

View File

@@ -0,0 +1,16 @@
import SwiftUI
@main
struct BlackRoadWatchiOSApp: App {
@StateObject private var udpManager = BlackRoadUDPManager.shared
var body: some Scene {
WindowGroup {
iOSContentView()
.environmentObject(udpManager)
.onAppear {
udpManager.startListening()
}
}
}
}

View File

@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>BlackRoad Watch</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchScreen</key>
<dict>
<key>UIColorName</key>
<string>Black</string>
</dict>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
<string>wifi</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>NSLocalNetworkUsageDescription</key>
<string>BlackRoad Watch needs local network access to receive data from the M1s Dock via UDP.</string>
<key>NSBonjourServices</key>
<array>
<string>_blackroad._udp</string>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,208 @@
import SwiftUI
// MARK: - BlackRoad Brand Colors
extension Color {
static let brHotPink = Color(red: 1.0, green: 0.114, blue: 0.424)
static let brAmber = Color(red: 0.961, green: 0.651, blue: 0.137)
static let brElectricBlue = Color(red: 0.161, green: 0.475, blue: 1.0)
static let brViolet = Color(red: 0.612, green: 0.153, blue: 0.690)
}
// MARK: - iOS Bridge View
struct iOSContentView: View {
@EnvironmentObject var udp: BlackRoadUDPManager
var body: some View {
NavigationView {
ScrollView {
VStack(spacing: 20) {
connectionCard
if udp.isConnected {
sensorCard
aiCard
fleetCard
}
}
.padding()
}
.background(Color.black)
.navigationTitle("BlackRoad Watch")
.navigationBarTitleDisplayMode(.inline)
.toolbarColorScheme(.dark, for: .navigationBar)
.toolbarBackground(.visible, for: .navigationBar)
.toolbarBackground(Color.black, for: .navigationBar)
}
.preferredColorScheme(.dark)
}
// MARK: - Connection Card
private var connectionCard: some View {
VStack(spacing: 12) {
HStack {
Text("BLACKROAD")
.font(.system(size: 13, weight: .black, design: .monospaced))
.foregroundStyle(
LinearGradient(
colors: [.brAmber, .brHotPink],
startPoint: .leading,
endPoint: .trailing
)
)
Spacer()
Text("BRIDGE")
.font(.system(size: 11, weight: .bold, design: .monospaced))
.foregroundColor(.gray)
}
Divider().background(Color.gray.opacity(0.3))
HStack {
Circle()
.fill(udp.isConnected ? Color.green : Color.red)
.frame(width: 10, height: 10)
Text("M1s Dock")
.font(.system(size: 14, weight: .medium))
.foregroundColor(.white)
Spacer()
if udp.isConnected {
Text(udp.sourceAddress)
.font(.system(size: 12, design: .monospaced))
.foregroundColor(.gray)
} else {
Text(udp.isListening ? "Listening on :8420" : "Starting...")
.font(.system(size: 12, design: .monospaced))
.foregroundColor(.gray)
}
}
HStack {
Circle()
.fill(udp.watchReachable ? Color.green : Color.orange)
.frame(width: 10, height: 10)
Text("Apple Watch")
.font(.system(size: 14, weight: .medium))
.foregroundColor(.white)
Spacer()
Text(udp.watchReachable ? "Connected" : "Waiting")
.font(.system(size: 12, design: .monospaced))
.foregroundColor(.gray)
}
HStack {
Label("\(udp.packetsReceived)", systemImage: "arrow.down.circle")
.font(.system(size: 12, design: .monospaced))
.foregroundColor(.brElectricBlue)
Spacer()
if let last = udp.lastUpdate {
Text(last, style: .relative)
.font(.system(size: 12))
.foregroundColor(.gray)
}
}
}
.padding()
.background(
RoundedRectangle(cornerRadius: 16)
.fill(Color.white.opacity(0.05))
.overlay(
RoundedRectangle(cornerRadius: 16)
.strokeBorder(
LinearGradient(
colors: [.brAmber.opacity(0.5), .brHotPink.opacity(0.3)],
startPoint: .topLeading,
endPoint: .bottomTrailing
),
lineWidth: 1
)
)
)
}
// MARK: - Sensor Card
private var sensorCard: some View {
VStack(alignment: .leading, spacing: 8) {
Label("SENSORS", systemImage: "thermometer")
.font(.system(size: 11, weight: .bold, design: .monospaced))
.foregroundColor(.brAmber)
if let s = udp.sensorData {
dataRow("Temperature", String(format: "%.1f\u{00B0}C", s.temperature), .brAmber)
dataRow("Humidity", String(format: "%.1f%%", s.humidity), .brElectricBlue)
dataRow("Battery", "\(s.batteryMV)mV", s.batteryMV > 3500 ? .green : .red)
dataRow("Uptime", formatUptime(s.uptimeSec), .gray)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
.background(RoundedRectangle(cornerRadius: 16).fill(Color.white.opacity(0.05)))
}
// MARK: - AI Card
private var aiCard: some View {
VStack(alignment: .leading, spacing: 8) {
Label("NPU", systemImage: "brain")
.font(.system(size: 11, weight: .bold, design: .monospaced))
.foregroundColor(.brViolet)
if let a = udp.aiStatus {
dataRow("Load", "\(a.npuLoad)%", .brElectricBlue)
dataRow("Temp", "\(a.npuTemp)\u{00B0}C", a.npuTemp > 70 ? .red : .brAmber)
dataRow("Confidence", "\(a.confidence)%", .brHotPink)
dataRow("Inferences", "\(a.totalInferences)", .brAmber)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
.background(RoundedRectangle(cornerRadius: 16).fill(Color.white.opacity(0.05)))
}
// MARK: - Fleet Card
private var fleetCard: some View {
VStack(alignment: .leading, spacing: 8) {
Label("FLEET", systemImage: "server.rack")
.font(.system(size: 11, weight: .bold, design: .monospaced))
.foregroundColor(.brHotPink)
if let h = udp.systemHealth {
dataRow("Devices", "\(h.fleetOnline)/\(h.fleetTotal)", .brElectricBlue)
dataRow("Agents", "\(h.agentsActive)", .brViolet)
dataRow("Green", "\(h.trafficGreen)", .green)
dataRow("Tasks Done", "\(h.tasksDone)", .green)
dataRow("Repos", "\(h.reposCount)", .brAmber)
dataRow("CF Projects", "\(h.cfProjects)", .brElectricBlue)
dataRow("Memory", "\(h.memoryEntries)", .brViolet)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
.background(RoundedRectangle(cornerRadius: 16).fill(Color.white.opacity(0.05)))
}
// MARK: - Helpers
private func dataRow(_ label: String, _ value: String, _ color: Color) -> some View {
HStack {
Text(label)
.font(.system(size: 13))
.foregroundColor(.gray)
Spacer()
Text(value)
.font(.system(size: 13, weight: .semibold, design: .monospaced))
.foregroundColor(color)
}
}
private func formatUptime(_ seconds: UInt32) -> String {
let h = seconds / 3600
let m = (seconds % 3600) / 60
let s = seconds % 60
return String(format: "%02d:%02d:%02d", h, m, s)
}
}