1. 中心设备
import Foundation
import CoreBluetooth
struct Const {
static let SERVICE_UUID = CBUUID(string: "6B5C4A86-CFB7-4031-98EB-09DF5E2543F0")
static let WRITE_CHARACTERISTIC_UUID = CBUUID(string: "4551ABAE-CE14-4F9E-B31A-E61FC372E480")
static let NOTIFY_CHARACTERISTIC_UUID = CBUUID(string: "DFB13451-1740-4F8A-B0F0-7C20D79E8BDF")
}
class MyCentral: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeripheralDelegate {
let centralManager = CBCentralManager()
// peripheral
var candidates: [CBPeripheral] = []
var peripheral: CBPeripheral?
var service: CBService?
var writeCharacteristic: CBCharacteristic?
var notifyCharacteristic: CBCharacteristic?
// The local name of a peripheral.
@Published var candidateNames: [String] = []
@Published var notifiedMessage = "未受信"
var randomPerSecond = 0
var timer : Timer! = nil
var receivedMessageArray: String = ""
var iPhoneCentralMessageArray: String = ""
var sendData = [
"heartRate": "80",
"bloodPressure": "80",
"bodyTemperature": "36.6",
"respiratoryRate": "70",
]
override init() {
super.init()
centralManager.delegate = self
}
// スキャン開始
func startScan() {
print("start scan")
candidateNames.removeAll()
candidates.removeAll()
if !centralManager.isScanning {
centralManager.scanForPeripherals(withServices: [Const.SERVICE_UUID], options: nil)
}
}
// スキャン停止
func stopScan() {
print("stop scan")
if centralManager.isScanning {
centralManager.stopScan()
}
}
// Centralの状態が変化したとき
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .poweredOff:
print("BLE PoweredOff")
break
case .poweredOn:
print("BLE poweredOn")
break
case .resetting:
print("BLE resetting")
break
case .unauthorized:
print("BLE unauthorized")
break
case .unknown:
print("BLE unknown")
break
case .unsupported:
print("BLE unsupported")
break
@unknown default:
print("BLE illegalstate \(central.state)")
}
}
// ペリフェラルと接続
func connect(index: Int) {
print("BLE start connect")
self.peripheral = candidates[index]
centralManager.connect(self.peripheral!, options: nil)
}
// データ書き込み
func write() {
let data = try! JSONSerialization.data(withJSONObject: sendData, options: [])
print("data:",data)
self.peripheral?.writeValue(data, for: (self.service?.characteristics?.first)!, type: .withoutResponse)
}
// Peripheralを見つけたとき
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
let name = peripheral.name
let localName = advertisementData[CBAdvertisementDataLocalNameKey] as? String
print("BLE discovered \(String(describing: name)) LocalName=\(String(describing: localName))")
if localName != nil && localName == "sample" {
// The local name of a peripheral.
candidateNames.append(localName!)
// peripheral
candidates.append(peripheral)
}
}
// 接続したとき
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("BLE connected")
peripheral.delegate = self
peripheral.discoverServices([Const.SERVICE_UUID])
}
// 接続に失敗したとき
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
print("BLE connect failed")
}
// Serviceを見つけたとき
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
print("BLE discovered services")
service = peripheral.services?.first
peripheral.discoverCharacteristics([Const.WRITE_CHARACTERISTIC_UUID, Const.NOTIFY_CHARACTERISTIC_UUID], for: service!)
}
// Characteristicを見つけたとき
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
print("BLE discovered characteristics")
for characteristic in service.characteristics! {
if characteristic.uuid == Const.WRITE_CHARACTERISTIC_UUID {
writeCharacteristic = characteristic
} else if characteristic.uuid == Const.NOTIFY_CHARACTERISTIC_UUID {
// 通知の受け取りを開始する
notifyCharacteristic = characteristic
peripheral.setNotifyValue(true, for: notifyCharacteristic!)
}
}
}
// 通知を受け取ったとき
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
print("BLE updated characteristis: \(characteristic)")
let data = characteristic.value!
print("data:",data)
let json = try! JSONSerialization.jsonObject(with: data, options: []) as! Dictionary<String, String>
print("json:",json)
notifiedMessage = "\(json)"
createCSV(from: json)
}
// CSVファイル生成
func createCSV(from recArray:Dictionary<String, String>) {
var csvString = "\("Type"),\("Number")\n\n"
for dct in recArray {
csvString = csvString.appending("\(String(describing: dct.key)) ,\(String(describing: dct.value))\n")
}
let dateFormat = DateFormatter()
dateFormat.dateFormat = "yyyyMMddHHmmss"
let now = Date()
print(dateFormat.string(from: now))
let fileManager = FileManager.default
do {
let path = try fileManager.url(for: .documentDirectory, in: .allDomainsMask, appropriateFor: nil, create: false)
let fileURL = path.appendingPathComponent("\(dateFormat.string(from: now))_HealthData.csv")
try csvString.write(to: fileURL, atomically: true, encoding: .utf8)
} catch {
print("error creating file")
}
}
}
2. 外围设备
import Foundation
import CoreBluetooth
import SwiftUI
struct Const {
static let SERVICE_UUID = CBUUID(string: "6B5C4A86-CFB7-4031-98EB-09DF5E2543F0")
static let WRITE_CHARACTERISTIC_UUID = CBUUID(string: "4551ABAE-CE14-4F9E-B31A-E61FC372E480")
static let NOTIFY_CHARACTERISTIC_UUID = CBUUID(string: "DFB13451-1740-4F8A-B0F0-7C20D79E8BDF")
}
class MyPeripheral: NSObject, ObservableObject, CBPeripheralManagerDelegate {
let peripheralManager = CBPeripheralManager()
var service: CBMutableService?
var writeCharacteristic: CBMutableCharacteristic?
var notifyCharacteristic: CBMutableCharacteristic?
@Published var wroteMessage = ""
var count: UInt32 = 0
override init() {
super.init()
peripheralManager.delegate = self
}
var sendData = [
"heartRate": "80",
"bloodPressure": "80",
"bodyTemperature": "36.6",
"respiratoryRate": "70",
]
// アドバタイズ開始ボタンが押されたとき
func startRegistAndAdvertise() {
print("[BLE] start Regist and Advertise")
// まずはレジストから
regist()
}
// アドバタイズ停止ボタンが押されたとき
func stopAdvertise() {
print("[BLE] stop Advertise")
peripheralManager.stopAdvertising()
}
// 通知
func notify() {
print("[BLE] notify")
let data = try! JSONSerialization.data(withJSONObject: sendData, options: [])
print("data:",data)
peripheralManager.updateValue(data, for: notifyCharacteristic!, onSubscribedCentrals: nil)
}
// レジスト
func regist() {
print("[BLE] start regist")
// create service
let service = CBMutableService(type: Const.SERVICE_UUID, primary: true)
// create characteristic
let writeCharacteristic = CBMutableCharacteristic(type: Const.WRITE_CHARACTERISTIC_UUID, properties: [.read, .writeWithoutResponse], value: nil, permissions: [.readable, .writeable])
let notifyCharacteristic = CBMutableCharacteristic(type: Const.NOTIFY_CHARACTERISTIC_UUID, properties: [.read, .notify], value: nil, permissions: [.readable, .writeable])
service.characteristics = [writeCharacteristic, notifyCharacteristic]
// regist
peripheralManager.add(service)
}
// PeripheralManagerの状態が変わったとき
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
switch peripheral.state {
case .poweredOff:
print("[BLE] PoweredOff")
break
case .poweredOn:
print("[BLE] poweredOn")
break
case .resetting:
print("[BLE] resetting")
break
case .unauthorized:
print("[BLE] unauthorized")
break
case .unknown:
print("[BLE] unknown")
break
case .unsupported:
print("[BLE] unsupported")
break
@unknown default:
print("[BLE] illegalstate \(peripheral.state)")
}
}
// レジストが終わったとき
func peripheralManager(_ peripheral: CBPeripheralManager, didAdd service: CBService, error: Error?) {
print("[BLE] didAdd error=\(String(describing: error))")
// Service と Characteristicを持っておく
self.service = service as? CBMutableService
for characteristic in service.characteristics! {
if characteristic.uuid == Const.NOTIFY_CHARACTERISTIC_UUID {
notifyCharacteristic = characteristic as? CBMutableCharacteristic
} else if characteristic.uuid == Const.WRITE_CHARACTERISTIC_UUID {
writeCharacteristic = characteristic as? CBMutableCharacteristic
}
}
// アドバタイズを開始
let advertisementData = [CBAdvertisementDataServiceUUIDsKey: [service.uuid], CBAdvertisementDataLocalNameKey: "sample"] as [String : Any]
peripheralManager.startAdvertising(advertisementData)
}
// アドバタイズが開始されたとき
func peripheralManagerDidStartAdvertising(_ peripheral: CBPeripheralManager, error: Error?) {
print("[BLE] peripheralManagerDidStartAdvertising error=\(String(describing: error))")
}
// Centralからの購読を受信したとき
func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) {
print("[BLE] didSubscribeTo")
}
// Centralからの書き込みを受信したとき
func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveWrite requests: [CBATTRequest]) {
print("[BLE] didReceiveWrite")
// for oneRequest in requests {
// print("oneRequest:",oneRequest)
// guard let requestValue = oneRequest.value,
// let stringFromData = String(data: requestValue, encoding: .utf8) else {
// continue
// }
// print("Received write request:",stringFromData)
// wroteMessage = "\(stringFromData)"
// }
for oneRequest in requests {
print("oneRequest:",oneRequest)
let requestValue = oneRequest.value
let dic = try! JSONSerialization.jsonObject(with: requestValue!, options: []) as! Dictionary<String, String>
print("Received write request:",dic)
wroteMessage = "\(dic)"
createCSV(from: dic)
}
}
// CSVファイル生成
func createCSV(from recArray:Dictionary<String, String>) {
var csvString = "\("Type"),\("Number")\n\n"
for dct in recArray {
csvString = csvString.appending("\(String(describing: dct.key)) ,\(String(describing: dct.value))\n")
}
let dateFormat = DateFormatter()
dateFormat.dateFormat = "yyyyMMddHHmmss"
let now = Date()
print(dateFormat.string(from: now))
let fileManager = FileManager.default
do {
let path = try fileManager.url(for: .documentDirectory, in: .allDomainsMask, appropriateFor: nil, create: false)
let fileURL = path.appendingPathComponent("\(dateFormat.string(from: now))_HealthData.csv")
try csvString.write(to: fileURL, atomically: true, encoding: .utf8)
} catch {
print("error creating file")
}
}
}