import SwiftUI
import CoreBluetooth
import os
class BluetoothViewModel: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeripheralDelegate {
@Revealed var peripherals: [CBPeripheral] = [] // Checklist of found peripherals
@Revealed var connectedPeripheral: CBPeripheral? // The chosen peripheral that's related
@Revealed var discoveredServices: [CBService] = [] // Checklist of found companies
@Revealed var discoveredServiceNames: [String] = [] // Checklist of names of found companies
@Revealed var peripheralNames: [String] = [] // Checklist of peripheral names discovered throughout scanning
@Revealed var filteredPeripheralNames: [String] = [] // Checklist of filtered peripheral names
var cbManager: CBCentralManager?
non-public var peripheralNameReceived = false // Flag to trace when the identify is obtained
override init() {
tremendous.init()
self.cbManager = CBCentralManager(delegate: self, queue: .fundamental)
}
// Begin scanning for peripherals (with out connecting to them)
func startScanning() {
os_log("Begin scanning for all peripherals.")
let choices: [String: Any] = [CBCentralManagerScanOptionAllowDuplicatesKey: NSNumber(value: false)]
cbManager?.scanForPeripherals(withServices: nil, choices: choices) // Scan for all peripherals
}
// Cease scanning for peripherals
func stopScanning() {
os_log("Cease scanning.")
cbManager?.stopScan()
}
// MARK: - CBCentralManagerDelegate Strategies
// Referred to as when the central supervisor's state adjustments
func centralManagerDidUpdateState(_ central: CBCentralManager) {
swap central.state {
case .poweredOn:
os_log("Bluetooth is powered on.")
case .poweredOff:
os_log("Bluetooth is powered off.")
case .unauthorized:
os_log("Bluetooth unauthorized.")
case .unknown:
os_log("Bluetooth state is unknown.")
case .resetting:
os_log("Bluetooth is resetting.")
case .unsupported:
os_log("Bluetooth is unsupported.")
@unknown default:
os_log("Unknown Bluetooth state.")
}
}
// Referred to as when a peripheral is found (however no connection is made)
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi: NSNumber) {
os_log("Found peripheral: %@", peripheral.identify ?? "Unknown")
// Filter out peripherals by identify if discovered within the filtered record
if let identify = peripheral.identify {
if !isPeripheralNameFiltered(identify) {
// Add identify to the record if it isn't filtered out
peripheralNames.append(identify)
os_log("Peripheral identify added: %@", identify)
} else {
os_log("Peripheral identify %@ is filtered out", identify)
}
}
// Add peripheral to the record if it isn't already there
if !peripherals.accommodates(peripheral) {
peripherals.append(peripheral)
}
}
// Operate to verify if a peripheral identify is within the filtered record
func isPeripheralNameFiltered(_ identify: String) -> Bool {
return filteredPeripheralNames.accommodates(identify)
}
// Operate to filter out a particular peripheral by identify
func filterOutPeripheralName(_ identify: String) {
if !filteredPeripheralNames.accommodates(identify) {
filteredPeripheralNames.append(identify)
os_log("Peripheral identify %@ added to filtered record", identify)
}
}
// Referred to as when a peripheral is related
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
os_log("Related to peripheral: %@", peripheral.identify ?? "Unknown")
// Set the peripheral delegate to find its companies
peripheral.delegate = self
connectedPeripheral = peripheral
// Uncover all companies on the related peripheral
peripheral.discoverServices(nil) // Move nil to find all companies
}
// Referred to as when a peripheral connection fails
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
os_log("Failed to connect with peripheral: %@", peripheral.identify ?? "Unknown")
}
// Referred to as when a peripheral is disconnected
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
os_log("Disconnected from peripheral: %@", peripheral.identify ?? "Unknown")
connectedPeripheral = nil
discoveredServices.removeAll()
discoveredServiceNames.removeAll()
peripheralNames.removeAll()
filteredPeripheralNames.removeAll()
}
// MARK: - CBPeripheralDelegate Strategies
// Referred to as when the peripheral discovers its companies
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
if let error = error {
os_log("Failed to find companies: %@", error.localizedDescription)
return
}
os_log("Found companies for peripheral: %@", peripheral.identify ?? "Unknown")
// Outline the UUIDs for Machine Data and Battery Service
let deviceInformationServiceUUID = CBUUID(string: "180A") // Machine Data
let batteryServiceUUID = CBUUID(string: "180F") // Battery Service
// Loop by way of found companies and fetch their names
for service in peripheral.companies ?? [] {
discoveredServices.append(service)
discoveredServiceNames.append(service.uuid.uuidString)
os_log("Service discovered: %@", service.uuid.uuidString)
// Test if the service is Machine Data or Battery Service
if service.uuid == deviceInformationServiceUUID {
os_log("Machine Data Service discovered")
} else if service.uuid == batteryServiceUUID {
os_log("Battery Service discovered")
} else {
os_log("Different service discovered: %@", service.uuid.uuidString)
}
// If system info service is discovered, uncover traits
if service.uuid == deviceInformationServiceUUID {
peripheral.discoverCharacteristics([CBUUID(string: "2A00")], for: service) // Machine Identify attribute
}
}
}
// Referred to as when a peripheral discovers traits for a given service
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
if let error = error {
os_log("Failed to find traits for service: %@", error.localizedDescription)
return
}
os_log("Found traits for service: %@", service.uuid.uuidString)
// If the Machine Data Service is discovered, learn the system identify attribute (2A00)
for attribute in service.traits ?? [] {
if attribute.uuid == CBUUID(string: "2A00") { // Machine Identify attribute
peripheral.readValue(for: attribute)
}
}
}
// Referred to as when a attribute's worth is up to date
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor attribute: CBCharacteristic, error: Error?) {
if let error = error {
os_log("Didn't learn attribute worth: %@", error.localizedDescription)
return
}
if attribute.uuid == CBUUID(string: "2A00") { // Machine Identify attribute
if let nameData = attribute.worth, let deviceName = String(knowledge: nameData, encoding: .utf8) {
os_log("Machine Identify from Machine Data Service: %@", deviceName)
peripheralNames.append(deviceName) // Add system identify to record
peripheralNameReceived = true // Mark the identify as obtained
}
}
}
// Deal with Producer Knowledge (customized identify or metadata) if current
func peripheral(_ peripheral: CBPeripheral, didReadValueFor attribute: CBCharacteristic, error: Error?) {
if let manufacturerData = attribute.worth, attribute.uuid == CBUUID(string: "2A29") {
os_log("Producer Knowledge: %@", convertDataToHexString(manufacturerData))
}
}
// Helper operate to transform Knowledge to a hexadecimal string for logging
non-public func convertDataToHexString(_ knowledge: Knowledge) -> String {
return knowledge.map { String(format: "%02hhx", $0) }.joined()
}
// A way to verify if the identify was obtained earlier than transferring on
func waitForName() {
whereas !peripheralNameReceived {
// Implement a small delay or verify, or you possibly can return right here and deal with different logic asynchronously
usleep(100000) // Sleep for 0.1 seconds for instance
}
}
}
outcomes,
The unknown is being displayed in ios settings with its system identify.
Found peripheral: [TV] Cia television
Peripheral identify added: [TV] Cia television
Found peripheral: Unknown
Found peripheral: Unknown
Found peripheral: [TV] Cia television
Peripheral identify added: [TV] Cia television
Found peripheral: Unknown