【家庭で使える!?Beaconアプリづくりにチャレンジ】BLEAD-TSHで遊ぼう!編 第2回

【2020年2月追記】※本文内で紹介している BLEAD-TSH は 現在販売停止しております。各種センサーとビーコンを組み合わせたソリューションをご希望の場合は、個別ににお問合せ下さい。
開発部のなーさんです。
前回の記事を書いて以降、暇なときにはイニシャルがTSHになる地名を探しています。たとえば千葉県だけでも、袖ヶ浦市とか匝瑳市(←読み方難しい)とかちらほらありました。
さて、BLEAD-TSHで遊んでみようと思い立ち、前回まずはTSHとは何か?について書いてみました。今回は、TSHのアドバタイズを受信するごく簡単なサンプルを作ってみたいと思います。
ターゲット OSはiOSで、開発言語はSwiftです。

下記は2019年5月現在の情報で執筆しています。
文中、画像中で使用されている商標等はそれぞれの企業、団体に帰属します。
コンセプト実証用のソースコードのため簡略化等された箇所があります。

作成するサンプルについて

さっそく作っていこうと思います。
当初、気負ってあれこれ機能をつけていたらブログ向きの分量ではなくなってしまいました。そこで初心に帰って下記のような最低限のサンプルにしました。

  • TSHのスキャンを行うクラスを定義
  • スキャンのOn/OffはViewControllerからSwitchオブジェクトで行う
  • 受信したTSHのデータはprint文で出力
  • Bluetoothは常にオンになっている想定

したがって、受信データから加速度などを取得したいときは、前回に掲載したフォーマット表などを参考にして切り出してください。また、iOSの制約などもあって、フォアグラウンド動作が前提となっています。
使用した環境は
●開発環境
iMac2017(macOS 10.14)
Xcode 10.2.1 + Swift5.0.1
●テスト環境
iPad Air2 (iOS12.0.1)
BLEAD-TSH 1台

サンプルプロジェクトの準備

とりあえず列挙します。
新規プロジェクトをSingle View AppでTSHScanSampleという名前で作成します。
General – Linked Frameworks and LibrariesでCoreBluetooth.frameworkを登録します。

TSHのスキャンを行うクラスとして、TSHScanner.swiftというファイルを追加します。

画面は下記のようにしました。最低Switchオブジェクトが一つだけあればOKです。ラベルはお好みで!

以降ソースコードを示します。

ソース:TSHScanner.swift

実用上はこのクラスはシングルトンにした方がよいかな〜と思います。
また、CBCentralManagerのインスタンス生成時とスキャン開始時に設定オプションを指定できますが、今回は使いどころがありそうな2つのキーを使いました。最初は両方ともfalseにしていますので、設定を変えて動作の違いを感じてください。キーは他にもあるので検索してみてください。

今回オプションに設定したキー

キーの名称内容
CBCentralManagerOptionShowPowerAlertKeyBluetoothがオフのときに通知をだすか否か
CBCentralManagerScanOptionAllowDuplicatesKeyスキャン中、同じデータを受信するたびに通知するか否か

import Foundation
import CoreBluetooth
 
final class TSHScanner: NSObject, CBCentralManagerDelegate {
/** 定数 */
private let powerAlertKey = false // Bluetoothがオフのときに通知を出すか
private let allowDuplicateKey = false // 同じデバイスの電波を何度も通知するか
// CBCentralManager
private var cbCentralManager: CBCentralManager!
 
//***********************
// MARK: - メソッド Internal
//***********************
/** スキャン開始 */
func startScan() {
// 一度停止を試みる
stopScan()
// スキャンの準備
// delegate:デリゲートを記述した場所
// queue:別スレッドでスキャンさせたいときに設定
// options:各種設定
cbCentralManager = CBCentralManager(
delegate: self,
queue: nil,
options: [CBCentralManagerOptionShowPowerAlertKey: powerAlertKey]
)
}
/** スキャン停止 */
func stopScan() {
guard cbCentralManager != nil else {
return
}
// 停止
if cbCentralManager.isScanning {
cbCentralManager.stopScan()
}
}
//***********************
// MARK: - デリゲート
//***********************
 
/** Bluetoothの状態通知 */
func centralManagerDidUpdateState(_ central: CBCentralManager) {
 
switch central.state {
case .poweredOff:
print("Bluetoothがオフ")
 
case .poweredOn:
// スキャン開始
// withServices:ここに設定したServiceUUIDのみ通知されます(TSHでは使いません)
// options:スキャンの設定を変えられます
cbCentralManager.scanForPeripherals(
withServices: nil,
options: [CBCentralManagerScanOptionAllowDuplicatesKey: allowDuplicateKey]
)
print("スキャン開始")
 
case .unknown: break
case .resetting: break
case .unsupported: break
case .unauthorized: break
@unknown default:
fatalError("fatal error")
}
}
 
/** ペリフェラルが見つかったとき */
func centralManager(_ central: CBCentralManager,
didDiscover peripheral: CBPeripheral,
advertisementData: [String : Any],
rssi RSSI: NSNumber) {
// nilなら処理終了
guard
// TSHデータの取得を試みる
let manuData = advertisementData[CBAdvertisementDataManufacturerDataKey] as? Data,
let periName = peripheral.name
else {
return
}
// BLEADじゃなければ処理終了
guard periName == "BLEAD" else {
return
}
// フォーマットから外れるときは処理終了
guard
manuData.count == 26,
(manuData[0] == 0xCE && manuData[1] == 0x01),
(manuData[2] == 0x53 && manuData[3] == 0x04)
else {
return
}
//***********************
// MARK: ここでTSHのデータを出力する
//***********************
print("TSHデータ:", dataToString(data: manuData), Int(truncating: RSSI))
}
 
//***********************
// MARK: - メソッド Private
//***********************
 
/** Dataを文字列に変換 */
private func dataToString(data: Data) -> String {
return data.map{ String(format: "%.2hhx", $0) }.joined()
}
}
 

ソース:ViewController.swift

スイッチオンオフによるスキャナークラスの制御のみのシンプルな構成です。実はAppDelegate.swiftから制御しようと思ったら、あまりにも画面が地味になりすぎるので、スイッチ制御にしました。

import UIKit
 
class ViewController: UIViewController {
// BLEAD-TSHスキャナークラス
private let tshScanner = TSHScanner()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
/** スイッチでオンオフ */
@IBAction func switchOnOff(_ sender: UISwitch) {
if sender.isOn {
tshScanner.startScan()
}else{
tshScanner.stopScan()
}
}
}

なお、「switchOnOff」は、SwitchのTouch Up Inseideの操作に紐づけて作成してください。

動作確認

ここまでできたらアプリを実行してみましょう!!
シミュレータでは動作しないので、スマホ実機にインストールしてください。
うまく動けばXcodeに下記のようなログが出力されます。受信したデータとRSSI値をただひたすら文字列で列挙します。
TSHのトリセツやフォーマット表、BLEAD-MC-Lightアプリの出力と見比べてみてください。

今回の記事は以上となります。
このソースコードは最低限の機能しかありません。みなさんのアイディアでいろいろ改造して、TSHとともに遊んでみてください!!

次回の予定

次回はBLEAD-TSHを使ったアプリの作例をご紹介します。
・・・さて、
もう突っ込みたくて仕方ない方もいらっしゃるかもしれません。
千葉県はChibaなので、TSH関係ないです〜
それでは!
以上、ご質問・ご指摘等ありましたら、弊社までお気軽にお問い合わせください。

関連記事

  1. 「そもそもBLEって何?」Bluetoothの技術概要

  2. 自宅Wi-Fiお知らせアプリ開発【第三回】 Beacon 探索機能編 …

  3. Raspberry Pi CM4 のセットアップ

  4. 電波の届く範囲内だけコンテンツの閲覧を可能に

  5. あなたにも、ぜひ読んで欲しいテクノロジー記事【7選】

  6. 知識ゼロで Unity をはじめてみた【その1 -環境作成-】