feat: Writes to characteristic

This commit is contained in:
2026-07-25 16:15:56 +01:00
parent 0505e435a6
commit 1bb8a83308
2 changed files with 137 additions and 18 deletions

View File

@@ -3,8 +3,8 @@
<plist version="1.0">
<dict>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>This app uses Bluetooth to connect to devices.</string>
<string>This app uses Bluetooth to connect to the collar tag.</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>This app uses Bluetooth.</string>
<string>This app uses Bluetooth to connect to the collar tag.</string>
</dict>
</plist>

View File

@@ -1,8 +1,14 @@
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 periphManager: CBPeripheralManager!
private var centralManager: CBCentralManager!
private var myPeripheral: CBPeripheral?
@Published var status = "Starting..."
override init() {
@@ -11,22 +17,135 @@ final class BluetoothManager: NSObject, ObservableObject {
}
}
extension BluetoothManager: CBPeripheralManagerDelegate {
func peripheralManagerDidUpdateState(_ central: CBPeripheralManager) {
switch central.state {
case .poweredOn:
status = "Broadcasting"
let uuid = CBUUID(string: "12345678-1234-1234-1234-123456789ABC")
periphManager.startAdvertising(
[
CBAdvertisementDataServiceUUIDsKey: [uuid],
CBAdvertisementDataLocalNameKey: "scbt-Test"
])
case .poweredOff:
status = "Bluetooth off"
extension BluetoothManager: CBCentralManagerDelegate, CBPeripheralDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
guard central.state == .poweredOn else {
status = "Bluetooth OFF"
return
}
default:
status = "Bluetooth unavailable"
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<UInt32>.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!)"
}
}
}