ズンドコキヨシ with Bluetooth Low Energy

  • 38
    いいね
  • 0
    コメント

既に 多くの言語・技術でズンドコキヨシ が試みられていますが、Bluetooth Low Energy (以下BLE) 版はまだないみたいなので、やってみました。

ズンドコキヨシカルチャーの発祥ツイート:

ちなみに iOS / Core Bluetooth です。 Swift バージョンは 2.2

GATT

ズンドコキヨシGATTを以下のように定義しました。(各UUID はuuidgen で生成)

Services

ズンドコキヨシService

  • UUID: B8A18F4F-2A2B-4084-AC2D-1ABC289EF05D
  • Characteristics
    • ズンドコCharacteristic
    • キヨシCharacteristic
GATT.swift
enum Service : Int {
    case ズンドコキヨシ

    func UUID() -> CBUUID {
        switch self {
        case .ズンドコキヨシ:
            return CBUUID(string: "B8A18F4F-2A2B-4084-AC2D-1ABC289EF05D")
        }
    }

    func mutableService() -> CBMutableService {
        return CBMutableService(type: UUID(), primary: true)
    }
}

Characteristics

ズンドコCharacteristic

  • UUID: C2F0882D-2440-40F4-A4A9-95BE43B89EAE
  • Properties: Read, Notify
  • value: ズン or ドコ

キヨシCharacteristic

  • UUID: C2F0882E-2440-40F4-A4A9-95BE43B89EAE
  • Properties: Write
  • value: 0x00 1
GATT.swift
enum Characteristic : Int {
    case ズンドコ
    case キヨシ

    func UUID() -> CBUUID {
        switch self {
        case .ズンドコ:
            return CBUUID(string: "C2F0882D-2440-40F4-A4A9-95BE43B89EAE")
        case .キヨシ:
            return CBUUID(string: "C2F0882E-2440-40F4-A4A9-95BE43B89EAE")
        }
    }

    private func properties() -> CBCharacteristicProperties {
        switch self {
        case .ズンドコ:
            return [CBCharacteristicProperties.Notify, CBCharacteristicProperties.Read]
        case .キヨシ:
            return [CBCharacteristicProperties.Write]
        }
    }

    private func permissions() -> CBAttributePermissions {
        switch self {
        case .ズンドコ:
            return [CBAttributePermissions.Readable]
        case .キヨシ:
            return [CBAttributePermissions.Writeable]
        }
    }

    func mutableCharacteristic() -> CBMutableCharacteristic {
        return CBMutableCharacteristic(
            type: UUID(),
            properties: properties(),
            value: nil,
            permissions: permissions())
    }
}

ズンドコ

ズンドコCharacteristicでやり取りする値。実体は UInt8 (1バイト)

Zundoko.swift
enum ズンドコ: UInt8 {
    case ズン
    case ドコ

    private func data() -> NSData {
        return NSData(bytes: [self], length: 1)
    }

    static func randomData() -> NSData {
        return ズンドコ(rawValue: UInt8(arc4random_uniform(2)))!.data()
    }

    init?(data: NSData) {
        var bytes = [UInt8](count: data.length, repeatedValue: 0)
        data.getBytes(&bytes, length: data.length)
        guard let value = bytes.first, zundoko = ズンドコ(rawValue: value) else { return nil }
        self = zundoko
    }
}

ズンドコPeripheral

ボタンを押すと、 ズン or ドコ をランダムに生成してBLEで送信 します。具体的には、Zundoko Characteristic の値を ズン or ドコ で更新します。

Peripheral.swift
func publishservice () {
    // キャラクタリスティックを作成
    ズンドコCharacteristic = Characteristic.ズンドコ.mutableCharacteristic()
    キヨシCharacteristic   = Characteristic.キヨシ.mutableCharacteristic()

    // サービスを作成
    let service = Service.ズンドコキヨシ.mutableService()
    service.characteristics = [ズンドコCharacteristic, キヨシCharacteristic]

    // サービスを Peripheral Managerに追加
    peripheralManager.addService(service)
}
Peripoheral.swift
@IBAction func zundokoBtnTapped(sender: UIButton) {
    let data = ズンドコ.randomData()
    ズンドコCharacteristic.value = data

    // 更新を通知
    peripheralManager.updateValue(
        data,
        forCharacteristic: ズンドコCharacteristic,
        onSubscribedCentrals: nil)
}

IMG_3743.PNG

キヨシCentral

BLEで送信されてきた ズン or ドコ を受け取り、画面に表示 します。具体的には、Peripheral側からのズンドコCharacteristicの更新通知を受け取り、画面を更新します。

Central.swift
func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?)
{
    guard let data = characteristic.value, zundoko = ズンドコ(data: data) else { return }
    zundokos.append(zundoko)

    let recents = zundokos.suffix(5)
    zundokoLabel.showZundokos(recents)

    if recents == [.ズン, .ズン, .ズン, .ズン, .ドコ] {
        sayKiyoshi()
    }
}

IMG_5899.PNG

直近5件が [ズン, ズン, ズン, ズン, ドコ] になると 「キ・ヨ・シ!」をBLEで送信 します。具体的には、Peripheral側のキヨシCharacteristicに値を書き込みます。

Central.swift
private func sayKiyoshi() {
    guard let peripheral = peripheral, kiyoshiCharacteristic = kiyoshiCharacteristic else { return }

    var value = 0x00
    let data = NSData(bytes: &value, length: 1)

    peripheral.writeValue(
        data,
        forCharacteristic: kiyoshiCharacteristic,
        type: CBCharacteristicWriteType.WithResponse)
}

改めてズンドコPeripheral側

Peripheral側ではキヨシCharacteristicへの書き込み要求を受けたら、画面に「キ・ヨ・シ!」を表示 します。

Peripheral.swift
func peripheralManager(peripheral: CBPeripheralManager, didReceiveWriteRequests requests: [CBATTRequest])
{
    for request in requests where request.characteristic.UUID == キヨシCharacteristic.UUID {
        キヨシCharacteristic.value = request.value
        kiyoshiLabel.hidden = false
    }
    peripheralManager.respondToRequest(requests[0] , withResult: CBATTError.Success)
}

IMG_3742.PNG

デモ

2台のiPhoneを用意し、それぞれにCentral, Peripheralをインストールします。

やってみた動画:

参考書籍

下記書籍のサンプルを流用しました。

iOS×BLE Core Bluetoothプログラミング
堤 修一 松村 礼央
ソシム
売り上げランキング: 48,410

今回は「スキャン」や「アドバタイズ」等の話は割愛しましたが、本書4章以降にかなりわかりやすく書いてあります。以下に紹介記事を書いたので興味があればご参照ください。

関連記事


  1. 「キ・ヨ・シ!」と文字列を送るのはBLEの思想的にマッチしないのでとりあえず1バイトの値を送る、という仕様にしてます。