import SwiftUI import CoreBluetooth struct Constants { static let scbtSvcUuid = "00010F2C-DEAD-BEEF-A455-DEAD69BEEF69"; static let scbtPetUuid: String = "00010F2D-DEAD-BEEF-A455-DEAD69BEEF69"; } final class BluetoothManager: NSObject, ObservableObject { private var centralManager: CBCentralManager! private var myPeripheral: CBPeripheral? @Published var status = "Starting..." override init() { super.init() periphManager = CBPeripheralManager(delegate: self, queue: nil) } } extension BluetoothManager: CBCentralManagerDelegate, CBPeripheralDelegate { func centralManagerDidUpdateState(_ central: CBCentralManager) { guard central.state == .poweredOn else { status = "Bluetooth OFF" return } let uuid = CBUUID(string: Constants.scbtSvcUuid) centralManager.scanForPeripherals( withServices: [uuid], options: [ CBCentralManagerScanOptionAllowDuplicatesKey: false ] ) } // Discovery callback func centralManager( _ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String: Any], rssi RSSI: NSNumber ) { if (peripheral.name != nil) { status = "Found: \(peripheral.name!)" } else { status = "Found: \(peripheral.identifier)" } myPeripheral = peripheral central.stopScan() central.connect(peripheral) } // Connection callback func centralManager( _ central: CBCentralManager, didConnect peripheral: CBPeripheral ) { status = "Connected" let uuid = CBUUID(string: Constants.scbtSvcUuid) peripheral.discoverServices([uuid]) peripheral.delegate = self } // Connection failure callback func centralManager( _ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error? ) { let error2: String if (error == nil) { error2 = "unknown" } else { error2 = "\(error!)" } status = "Failed: \(error2)" } // Disconnection callback func centralManager( _ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error? ) { let error2: String if (error == nil) { error2 = "unknown" } else { error2 = "\(error!)" } status = "Disconnected: \(error2)" } // Service callback func peripheral( _ peripheral: CBPeripheral, didDiscoverServices error: Error? ) { guard let services = peripheral.services else { return } status = "Service found" let scbtSvc = CBUUID(string: Constants.scbtSvcUuid) let scbtPet = CBUUID(string: Constants.scbtPetUuid) for service in services { // Ignore non scbtSvc if (service.uuid != scbtSvc) { continue } peripheral.discoverCharacteristics([scbtPet], for: service) } } // Characteristic callback func peripheral( _ perihperal: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error? ) { if (error != nil) { status = "\(error!)" return } guard let characteristics = service.characteristics else { return } status = "Characteristics found (\(characteristics.count))" let scbtPet = CBUUID(string: Constants.scbtPetUuid) for characteristic in characteristics { // Ignore non pet if (characteristic.uuid != scbtPet) { continue } var value: UInt32 = 0 let data = Data(bytes: &value, count: MemoryLayout.size) perihperal.writeValue(data, for: characteristic, type: .withResponse) status = "Written \(data)" } } // Characteristic write callback func peripheral( _ perihperal: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: (any Error)? ) { if (error == nil) { status = "Write success" } else { status = "Write failed: \(error!)" } } }