ESP32でBLE通信、ESP32からiOSでデータ受信
今回はBLE通信を使って、iOS端末でESP32から送られたデータを受信します。これが実現できれば、ESP32に繋げられたセンサの値などをiOSで受信し管理できるようになります。BLEはWiFiよりも消費電力が圧倒的に少なくて済む通信方法です。ESP32などの小型マイコンボードとの相性もとても良いのでぜひ挑戦してみてください。
はじめに
前回のおさらい
はじめに前回のおさらいです。BLE通信をはじめるには、アドバタイジングで目的のサービスを持つペリフェラルを見つけ、キャラクタリスティックを取得する必要がありました。よってペリフェラルのサービスUUIDとキャラクタリスティックUUIDの2つ以上が必要になります。

前回は、iOSからESP32へデータを送信してLチカを実現させました。よってキャラクタリスティックの属性にはWriteが必要でした。 今回は、ESP32のデータをiOSで受信したいのでNotify属性を使ってデータを受信します。
ところで、この記事で扱うiOSとESP32は次のような関係になります。混乱しないよう気をつけてください。
iOS | ESP32 |
---|---|
セントラル | ペリフェラル |
マスタ | スレイブ |
クライアント | サーバ |
ESP32のUUIDをそれぞれ次のように決めました。
項目 | 値 |
---|---|
SERVICE UUID | 4fafc201-1fb5-459e-8fcc-c5c9c331914b |
CHARACTERISTIC UUID | beb5483e-36e1-4688-b7f5-ea07361b26a8 |
これらの値はESP32のサンプルの値を使用してます。必要あればこちらのジェネレータでUUIDを生成して書き換えてください。 https://www.uuidgenerator.net/
BLE通信でESP32のデータをiOSで受信するプログラム
概要
ESP32のGPIO32へ可変抵抗を取り付け、読み取ったアナログ値をiOSでBLE経由で受信するプログラムを作っていきます。
可変抵抗は両側をGNDと3.3Vに接続し、真ん中の端子をGPIOへ繋いでください。BLE通信を開始したらNotify通知を設定し、抵抗値をiOSで受け取りUILabeで表示させます。
ESP32(ペリフェラル)
ESP32(ペリフェラル)のArduinoで書いたプログラムです。前回のBluetooth Lチカとそれほど変わりません。ESP32でデータを通知するにはキャラクタリスティックにデータをセットして通知します。
->setValue(str);
pCharacteristic->notify(); pCharacteristic
なお、ここでは文字列をセットしましたが、int型などもセットできるようです。
/*
sendData2Iphone.ino
https://101010.fun
*/
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#define TOUCH_PIN 32
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
* pCharacteristic;
BLECharacteristic
void sendMessage(int v) {
char str[30];
(str, "%d", v);
sprintf.println(str);
Serial->setValue(str);
pCharacteristic->notify();
pCharacteristic}
void setup() {
.begin(115200);
Serial
(TOUCH_PIN, INPUT_PULLUP); // 内蔵抵抗でプルアップまたは10kΩの抵抗でプルアップ
pinMode
::init("ESP32 Bluetooth Server");
BLEDevice* pServer = BLEDevice::createServer();
BLEServer* pService = pServer->createService(SERVICE_UUID);
BLEService= pService->createCharacteristic(
pCharacteristic ,
CHARACTERISTIC_UUID::PROPERTY_NOTIFY
BLECharacteristic);
->start();
pService* pAdvertising = BLEDevice::getAdvertising();
BLEAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(true);
pAdvertising->setMinPreferred(0x06); // iPhone接続の問題に役立つ
pAdvertising->setMinPreferred(0x12);
pAdvertising::startAdvertising();
BLEDevice.println("Characteristic defined! Now you can read it in your phone!");
Serial}
void loop() {
int val = analogRead(TOUCH_PIN);
.println(val);
Serial(val);
sendMessage(10);
delay}
iOS(セントラル)
基本的には前回のLチカプログラムと変わりません。今回はNotifyですのでキャラクタリスティックが一致したら、しっかり通知登録をしてあげます。
.setNotifyValue(true, for: kRXCBCharacteristic) peripheral
すると CBPeripheralDelegate
のデリゲートメソッド
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?)
でデータを受信できるはずです。
//
// ReciveViewController.swift
//
// Created by 101010.fun Arai on 2021/07/14.
//
import UIKit
import CoreBluetooth
class ReciveViewController: UIViewController {
@IBOutlet weak var counterLabel:UILabel!
= "4fafc201-1fb5-459e-8fcc-c5c9c331914b" // サービス
let kUARTServiceUUID = "beb5483e-36e1-4688-b7f5-ea07361b26a8" // ペリフェラルからの受信用
let kRXCharacteristicUUID
: CBCentralManager!
var centralManager: CBPeripheral!
var peripheral: CBUUID!
var serviceUUID : CBCharacteristic?
var kRXCBCharacteristic: [CBUUID]!
var charcteristicUUIDs
override func viewDidLoad() {
.viewDidLoad()
super()
setup}
private func setup() {
("setup...")
print
= CBCentralManager()
centralManager .delegate = self as CBCentralManagerDelegate
centralManager
= CBUUID(string: kUARTServiceUUID)
serviceUUID = [CBUUID(string: kRXCharacteristicUUID)]
charcteristicUUIDs }
}
//MARK : - CBCentralManagerDelegate
: CBCentralManagerDelegate {
extension ReciveViewController
(_ central: CBCentralManager) {
func centralManagerDidUpdateState("CentralManager didUpdateState")
print
switch central.state {
//電源ONを待って、スキャンする
case CBManagerState.poweredOn:
: [CBUUID] = [serviceUUID]
let services?.scanForPeripherals(withServices: services,
centralManager: nil)
optionsdefault:
break
}
}
/// ペリフェラルを発見すると呼ばれる
(_ central: CBCentralManager,
func centralManager: CBPeripheral,
didDiscover peripheral: [String : Any],
advertisementData: NSNumber) {
rssi RSSI
.peripheral = peripheral
self?.stopScan()
centralManager
//接続開始
.connect(peripheral, options: nil)
central(" - centralManager didDiscover")
print}
/// 接続されると呼ばれる
(_ central: CBCentralManager,
func centralManager: CBPeripheral) {
didConnect peripheral
.delegate = self
peripheral.discoverServices([serviceUUID])
peripheral(" - centralManager didConnect")
print}
/// 切断されると呼ばれる?
(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
func centralManager(#function)
printif error != nil {
(error.debugDescription)
print() // ペアリングのリトライ
setupreturn
}
}
}
//MARK : - CBPeripheralDelegate
: CBPeripheralDelegate {
extension ReciveViewController
/// サービス発見時に呼ばれる
(_ peripheral: CBPeripheral,
func peripheral: Error?) {
didDiscoverServices error
if error != nil {
(error.debugDescription)
printreturn
}
//キャリアクタリスティク探索開始
if let service = peripheral.services?.first {
("Searching characteristic...")
print.discoverCharacteristics(charcteristicUUIDs,
peripheralfor: service)
}
}
/// キャリアクタリスティク発見時に呼ばれる
(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
func peripheral
if error != nil {
(error.debugDescription)
printreturn
}
("service.characteristics.count: \(service.characteristics!.count)")
printfor characteristics in service.characteristics! {
if(characteristics.uuid == CBUUID(string: kRXCharacteristicUUID)) {
.kRXCBCharacteristic = characteristics
self("kTXCBCharacteristic did discovered!")
print}
}
if(self.kRXCBCharacteristic != nil) {
()
startReciving}
(" - Characteristic didDiscovered")
print
}
private func startReciving() {
= kRXCBCharacteristic else {
guard let kRXCBCharacteristic return
}
.setNotifyValue(true, for: kRXCBCharacteristic)
peripheral("Start monitoring the message from Arduino.\n\n")
print}
/// データ送信時に呼ばれる
(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
func peripheral(#function)
printif error != nil {
(error.debugDescription)
printreturn
}
}
(_ peripheral: CBPeripheral, didUpdateValueFor descriptor: CBDescriptor, error: Error?) {
func peripheral(#function)
print}
/// データ更新時に呼ばれる
(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
func peripheral(#function)
print
if error != nil {
(error.debugDescription)
printreturn
}
(data: characteristic.value!)
updateWithData}
private func updateWithData(data : Data) {
if let dataString = String(data: data, encoding: String.Encoding.utf8) {
(dataString)
print.text = dataString
counterLabel}
}
}
今回のプログラムでツマヅイたら、前回のBluetooth Lチカをもう一度見直してみてください。プログラム中で書き換えた箇所はそれほど多くないはずです。
Bluetooth開発に役に立つツール
最後に、Bluetooth開発をする際におすすめのアプリを紹介します。こちらのアプリは、ペリフェラルのサービスやキャラクタリスティック情報をスキャンできるアプリです。UUIDなどで何かつまずいた場合に役立ちますので入れておくと便利です。 {{apps_ble_scanner}}
関連記事
- はじめてのBLE通信、iOSからESP32のLチカ
- ESP32でBluetooth Classicを使ってAndroidと通信する
- ダイソーのBluetoothリモコンシャッターをESP32でハックする
- DS18B20の使い方|Arduino・ESP32・Raspberry Pi
- ESP32とMH-Z19CセンサでCO2濃度の測定