Swift iPhone 与 ESP32 之间的 BLE 通信
Swift BLE communication between iPhone and ESP32
我完全是 Swift 的新手,因此有一些非常基本的问题。
我计划构建一个简单的 iPhone 应用程序,它可以与连接到我的 eBike 控制器的 ESP32 对话(双向)。 ESP32 设置为通过 BLE 传输和接收数据。它发送 4 个信号:mode(1,2,3)、light(on/off)、bat(battery;值在 31,5 和 41,5 之间) 和 speed(float) 并接受命令:“um”改变模式和“li”在灯光之间切换 on/off
各自的UUID如下
#define SERVICE_UUID "19074fb4-161b-47c7-964e-9d087266d6a7"
#define CHARACTERISTIC_UUID_RX "101880eb-a78e-4cee-b252-56e06093f4da"
#define CHARACTERISTIC_UUID_TX_MODE "5d64d30b-3e03-4e65-82a2-a85e9d568f84"
#define CHARACTERISTIC_UUID_TX_LIGHT "dfbec318-8292-4b34-87b5-f13e4efb1560"
#define CHARACTERISTIC_UUID_TX_BAT "a5b79c5d-977a-4ef0-b3f3-b8f26e166378"
#define CHARACTERISTIC_UUID_TX_SPEED "b0bfad34-c571-41a5-8bc3-7726ced1ebbe"
在 Swift 一侧,我有 UI,但我无法让按钮(模式、指示灯、连接)和连接正常工作。
这是我的 swift 文件,包括。 BLE 功能:
//
// BLEController.swift
// Bike Controller
//
// Created by David Melinc on 19.05.22.
//
import Foundation
import CoreBluetooth
struct Peripheral: Identifiable {
let id: Int
let name: String
let rssi: Int
}
class BLEController: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeripheralDelegate {
var myCentral: CBCentralManager!
var myPeripheral: CBPeripheral!
@Published var isSwitchedOn = false
@Published var peripherals = [Peripheral]()
@Published var mode: UInt16 = 0
@Published var light: String = " "
@Published var bat: UInt16 = 0
@Published var speed: UInt16 = 0
let SERVICE_UUID = CBUUID(string: "19074fb4-161b-47c7-964e-9d087266d6a7")
let CHARACTERISTIC_UUID_RX = CBUUID(string: "101880eb-a78e-4cee-b252-56e06093f4da")
let CHARACTERISTIC_UUID_TX_MODE = CBUUID(string: "5d64d30b-3e03-4e65-82a2-a85e9d568f84")
let CHARACTERISTIC_UUID_TX_LIGHT = CBUUID(string: "dfbec318-8292-4b34-87b5-f13e4efb1560")
let CHARACTERISTIC_UUID_TX_BAT = CBUUID(string: "a5b79c5d-977a-4ef0-b3f3-b8f26e166378")
let CHARACTERISTIC_UUID_TX_SPEED = CBUUID(string: "b0bfad34-c571-41a5-8bc3-7726ced1ebbe")
override init() {
super.init()
myCentral = CBCentralManager(delegate: self, queue: nil)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
isSwitchedOn = true
}
else {
isSwitchedOn = false
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
var peripheralName: String!
if let name = advertisementData[CBAdvertisementDataLocalNameKey] as? String {
peripheralName = name
}
else {
peripheralName = "Unknown"
}
let newPeripheral = Peripheral(id: peripherals.count, name: peripheralName, rssi: RSSI.intValue)
print(newPeripheral)
peripherals.append(newPeripheral)
}
func connectBLE(peripheral1) {
print("trying to connect to \(peripheral1)")
self.myCentral.connect(peripheral1, options: nil)
print(2)
}
}
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
self.myPeripheral.discoverServices(nil)
print("Connected to "+peripheral.name!)
}
func startScanning() {
print("startScanning")
myCentral.scanForPeripherals(withServices: nil, options: nil)
self.perform(#selector(stopScanning), with: self, afterDelay: 5)
}
@objc func stopScanning() {
print("stopScanning")
myCentral.stopScan()
}
}
这是 UI 文件:
import SwiftUI
struct BLEdevices: View {
//@StateObject var bleController = BLEController()
@EnvironmentObject var bleController: BLEController
var body: some View {
ZStack {
Color("Themecolor")
.edgesIgnoringSafeArea(.all)
VStack (spacing: 10) {
Text("Bluetooth Devices")
.font(.largeTitle)
.frame(maxWidth: .infinity, alignment: .center)
List(bleController.peripherals) { peripheral in
HStack {
Text(peripheral.name)
Spacer()
Text(String(peripheral.rssi))
Spacer()
Button(action: {
//bleController.connectBLE(peripheral.name)
}) {
Text("CONNECT")
.font(.system(size: 10))
.fontWeight(.bold)
.padding()
.foregroundColor(.black)
.frame(alignment: .center)
.background(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.white, lineWidth: 2)
.background(Color.white.cornerRadius(10)))
}
}
}
.frame(height: 600)
HStack (spacing: 10) {
Button(action: {
bleController.startScanning()
}) {
Text("SCAN")
.font(.title)
.fontWeight(.bold)
.padding()
.foregroundColor(.black)
.frame(width: 150, alignment: .center)
.background(
RoundedRectangle(cornerRadius: 25)
.stroke(Color.white, lineWidth: 2)
.background(Color.white.cornerRadius(25)))
}
Button(action: {
bleController.stopScanning()
}) {
Text("STOP")
.font(.title)
.fontWeight(.bold)
.padding()
.foregroundColor(.black)
.frame(width: 150, alignment: .center)
.background(
RoundedRectangle(cornerRadius: 25)
.stroke(Color.white, lineWidth: 2)
.background(Color.white.cornerRadius(25)))
}
}
}
}
}
}
struct BLEdevices_Previews: PreviewProvider {
static var previews: some View {
BLEdevices()
}
}
我想运行扫描完周围后的connectBLE功能
因此我的问题如下,
1.) 扫描整个区域后如何连接到特定设备?
我在从“peripheral.name”返回到 CBPeripheral 格式时遇到问题,我可以使用它来放入我的 myCentral.connect 函数。
2.) 两台设备连接后如何收发数据?
来自 ESP32 的所有信号均使用单独的 UUID 通过 ESP32 的通知传输,但我不知道如何在 Swift 端 get/handle 它们。
使用“模式”和“灯光”按钮,我想向 ESP32 发送简单的 ASCII 代码。
如果有人能在我遇到困难时帮助我,我将不胜感激。
最佳大卫
重要的是您宣传要找到的服务,而不仅仅是 create/facilitate。像 nRF connect 这样的应用程序可以帮助您确定该服务是否被广告,否则扫描服务(该特定服务)将不成功。
第二个问题:看他的作品https://www.raywenderlich.com/231-core-bluetooth-tutorial-for-ios-heart-rate-monitor
你可以读出意在被读的特征,反之亦然。并不总是需要通知。
我完全是 Swift 的新手,因此有一些非常基本的问题。 我计划构建一个简单的 iPhone 应用程序,它可以与连接到我的 eBike 控制器的 ESP32 对话(双向)。 ESP32 设置为通过 BLE 传输和接收数据。它发送 4 个信号:mode(1,2,3)、light(on/off)、bat(battery;值在 31,5 和 41,5 之间) 和 speed(float) 并接受命令:“um”改变模式和“li”在灯光之间切换 on/off
各自的UUID如下
#define SERVICE_UUID "19074fb4-161b-47c7-964e-9d087266d6a7"
#define CHARACTERISTIC_UUID_RX "101880eb-a78e-4cee-b252-56e06093f4da"
#define CHARACTERISTIC_UUID_TX_MODE "5d64d30b-3e03-4e65-82a2-a85e9d568f84"
#define CHARACTERISTIC_UUID_TX_LIGHT "dfbec318-8292-4b34-87b5-f13e4efb1560"
#define CHARACTERISTIC_UUID_TX_BAT "a5b79c5d-977a-4ef0-b3f3-b8f26e166378"
#define CHARACTERISTIC_UUID_TX_SPEED "b0bfad34-c571-41a5-8bc3-7726ced1ebbe"
在 Swift 一侧,我有 UI,但我无法让按钮(模式、指示灯、连接)和连接正常工作。
这是我的 swift 文件,包括。 BLE 功能:
//
// BLEController.swift
// Bike Controller
//
// Created by David Melinc on 19.05.22.
//
import Foundation
import CoreBluetooth
struct Peripheral: Identifiable {
let id: Int
let name: String
let rssi: Int
}
class BLEController: NSObject, ObservableObject, CBCentralManagerDelegate, CBPeripheralDelegate {
var myCentral: CBCentralManager!
var myPeripheral: CBPeripheral!
@Published var isSwitchedOn = false
@Published var peripherals = [Peripheral]()
@Published var mode: UInt16 = 0
@Published var light: String = " "
@Published var bat: UInt16 = 0
@Published var speed: UInt16 = 0
let SERVICE_UUID = CBUUID(string: "19074fb4-161b-47c7-964e-9d087266d6a7")
let CHARACTERISTIC_UUID_RX = CBUUID(string: "101880eb-a78e-4cee-b252-56e06093f4da")
let CHARACTERISTIC_UUID_TX_MODE = CBUUID(string: "5d64d30b-3e03-4e65-82a2-a85e9d568f84")
let CHARACTERISTIC_UUID_TX_LIGHT = CBUUID(string: "dfbec318-8292-4b34-87b5-f13e4efb1560")
let CHARACTERISTIC_UUID_TX_BAT = CBUUID(string: "a5b79c5d-977a-4ef0-b3f3-b8f26e166378")
let CHARACTERISTIC_UUID_TX_SPEED = CBUUID(string: "b0bfad34-c571-41a5-8bc3-7726ced1ebbe")
override init() {
super.init()
myCentral = CBCentralManager(delegate: self, queue: nil)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
isSwitchedOn = true
}
else {
isSwitchedOn = false
}
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
var peripheralName: String!
if let name = advertisementData[CBAdvertisementDataLocalNameKey] as? String {
peripheralName = name
}
else {
peripheralName = "Unknown"
}
let newPeripheral = Peripheral(id: peripherals.count, name: peripheralName, rssi: RSSI.intValue)
print(newPeripheral)
peripherals.append(newPeripheral)
}
func connectBLE(peripheral1) {
print("trying to connect to \(peripheral1)")
self.myCentral.connect(peripheral1, options: nil)
print(2)
}
}
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
self.myPeripheral.discoverServices(nil)
print("Connected to "+peripheral.name!)
}
func startScanning() {
print("startScanning")
myCentral.scanForPeripherals(withServices: nil, options: nil)
self.perform(#selector(stopScanning), with: self, afterDelay: 5)
}
@objc func stopScanning() {
print("stopScanning")
myCentral.stopScan()
}
}
这是 UI 文件:
import SwiftUI
struct BLEdevices: View {
//@StateObject var bleController = BLEController()
@EnvironmentObject var bleController: BLEController
var body: some View {
ZStack {
Color("Themecolor")
.edgesIgnoringSafeArea(.all)
VStack (spacing: 10) {
Text("Bluetooth Devices")
.font(.largeTitle)
.frame(maxWidth: .infinity, alignment: .center)
List(bleController.peripherals) { peripheral in
HStack {
Text(peripheral.name)
Spacer()
Text(String(peripheral.rssi))
Spacer()
Button(action: {
//bleController.connectBLE(peripheral.name)
}) {
Text("CONNECT")
.font(.system(size: 10))
.fontWeight(.bold)
.padding()
.foregroundColor(.black)
.frame(alignment: .center)
.background(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.white, lineWidth: 2)
.background(Color.white.cornerRadius(10)))
}
}
}
.frame(height: 600)
HStack (spacing: 10) {
Button(action: {
bleController.startScanning()
}) {
Text("SCAN")
.font(.title)
.fontWeight(.bold)
.padding()
.foregroundColor(.black)
.frame(width: 150, alignment: .center)
.background(
RoundedRectangle(cornerRadius: 25)
.stroke(Color.white, lineWidth: 2)
.background(Color.white.cornerRadius(25)))
}
Button(action: {
bleController.stopScanning()
}) {
Text("STOP")
.font(.title)
.fontWeight(.bold)
.padding()
.foregroundColor(.black)
.frame(width: 150, alignment: .center)
.background(
RoundedRectangle(cornerRadius: 25)
.stroke(Color.white, lineWidth: 2)
.background(Color.white.cornerRadius(25)))
}
}
}
}
}
}
struct BLEdevices_Previews: PreviewProvider {
static var previews: some View {
BLEdevices()
}
}
我想运行扫描完周围后的connectBLE功能
因此我的问题如下,
1.) 扫描整个区域后如何连接到特定设备? 我在从“peripheral.name”返回到 CBPeripheral 格式时遇到问题,我可以使用它来放入我的 myCentral.connect 函数。 2.) 两台设备连接后如何收发数据? 来自 ESP32 的所有信号均使用单独的 UUID 通过 ESP32 的通知传输,但我不知道如何在 Swift 端 get/handle 它们。 使用“模式”和“灯光”按钮,我想向 ESP32 发送简单的 ASCII 代码。
如果有人能在我遇到困难时帮助我,我将不胜感激。
最佳大卫
重要的是您宣传要找到的服务,而不仅仅是 create/facilitate。像 nRF connect 这样的应用程序可以帮助您确定该服务是否被广告,否则扫描服务(该特定服务)将不成功。
第二个问题:看他的作品https://www.raywenderlich.com/231-core-bluetooth-tutorial-for-ios-heart-rate-monitor
你可以读出意在被读的特征,反之亦然。并不总是需要通知。