import Foundation import CoreBluetooth import WatchConnectivity import Combine // MARK: - BLE Service/Characteristic UUIDs (must match firmware) enum BlackRoadBLEConstants { static let serviceUUID = CBUUID(string: "00000001-0000-0000-0000-005242BB0000") static let sensorUUID = CBUUID(string: "00000001-0000-0000-0000-005242BB0100") static let aiStatusUUID = CBUUID(string: "00000001-0000-0000-0000-005242BB0200") static let sysHealthUUID = CBUUID(string: "00000001-0000-0000-0000-005242BB0300") static let notifUUID = CBUUID(string: "00000001-0000-0000-0000-005242BB0400") } // MARK: - Data Models struct SensorData: Codable { var temperature: Double // Celsius var humidity: Double // % var light: Int var accelX: Double // g var accelY: Double var accelZ: Double var batteryMV: Int var uptimeSec: UInt32 static func decode(from data: Data) -> SensorData? { guard data.count >= 20 else { return nil } return SensorData( temperature: Double(data.uint16(at: 0)) / 100.0, humidity: Double(data.uint16(at: 2)) / 100.0, light: Int(data.uint16(at: 4)), accelX: Double(data.int16(at: 6)) / 1000.0, accelY: Double(data.int16(at: 8)) / 1000.0, accelZ: Double(data.int16(at: 10)) / 1000.0, batteryMV: Int(data.uint16(at: 12)), uptimeSec: data.uint32(at: 14) ) } } struct AIStatus: Codable { var modelID: Int var confidence: Int var inferenceMS: Int var totalInferences: UInt32 var npuLoad: Int var npuTemp: Int var classID: Int static func decode(from data: Data) -> AIStatus? { guard data.count >= 11 else { return nil } return AIStatus( modelID: Int(data[0]), confidence: Int(data[1]), inferenceMS: Int(data.uint16(at: 2)), totalInferences: data.uint32(at: 4), npuLoad: Int(data[8]), npuTemp: Int(data[9]), classID: Int(data[10]) ) } } 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 static func decode(from data: Data) -> SystemHealth? { guard data.count >= 20 else { return nil } return SystemHealth( fleetOnline: Int(data[0]), fleetTotal: Int(data[1]), agentsActive: Int(data[2]), trafficGreen: Int(data[3]), trafficYellow: Int(data[4]), trafficRed: Int(data[5]), tasksPending: Int(data.uint16(at: 6)), tasksDone: Int(data.uint16(at: 8)), memoryEntries: data.uint32(at: 10), reposCount: Int(data.uint16(at: 14)), cfProjects: Int(data.uint16(at: 16)), cpuLoad: Double(data.uint16(at: 18)) / 100.0 ) } } struct BRNotification: Codable { enum NotificationType: Int, Codable { case info = 0, warning = 1, critical = 2, deploy = 3 } var type: NotificationType var source: Int var eventID: Int var message: String static func decode(from data: Data) -> BRNotification? { guard data.count >= 4 else { return nil } let msgData = data.subdata(in: 4.. UInt16 { guard offset + 2 <= count else { return 0 } return subdata(in: offset.. Int16 { guard offset + 2 <= count else { return 0 } return subdata(in: offset.. UInt32 { guard offset + 4 <= count else { return 0 } return subdata(in: offset..