今日中に間に合うか!?
この記事は出張中の京都で講演を聴きながら書かれています。
BLE Advent Calenderの今日の当番なので、頑張って書きます。゚(゚´Д`゚)゚。
→すいません、投稿遅れましたm(_ _)m
IoTボタンのブループリント
これ!がつくりたいんですが、Wi-Fi使っていると思うので、それだと直接クラウドにつながっちゃってBLE使わない!ってことで、せっかくなのでBLEを使って作成します。
ちなみにざっくりイカのような構成でつくってみました。これは実はTechCrunch Tokyo 2015 CTO Nightで使われたプレゼンボタンです。
ボタンを押すと、BLEでスマフォに通信が行って、MQTTでAWS経由で自分の手元のPCまでPub/Subでメッセージが来て、最後にWebSocketでつながっているプレゼンツールが次のページに行ったら成功です!
まずボタン(ハード)をつくる
ボタンの構成はこれです。
- ポップンみたいなボタンパーツ(既成品)
- 見栄えを良くするための筐体(Fusion 360で設計→3Dプリンタで製造)
ボタンを買って、
https://www.sengoku.co.jp/mod/sgk_cart/detail.php?code=EEHD-4LG4
3DCADで設計して、
3Dプリンターで出力します!
これで一旦ハードウェアの完成です!
基板作成
EagleやQuadceptを使って作成。回路図・アートワークはまた今度。
要素的には
BLEのチップ
⇅ (ファームウェアで制御)
GPIO(Input|Interrupt)
⇅ (電気的なHIGH/LOWを受け取る)
ボタン
ができる構成。
ファーム
ソースを紹介したいけど、NDA(´・ω・`)
今後Nordicのチップを使うことでオープンにしていきたいと思っています。
仮想言語で書くとこんな感じ
void interrupt() {
notification(characteristic_hander, 1);
}
割り込みピンで入力があったときに呼ばれるコールバックの中に、キャラクタリスティックの通知を送信する関数を呼ぶだけです。
BLE
- BLEのネットワーク構造はスター型
- IoTボタン側をペリフェラルとする
- スマートフォンがセントラル
- Notification
- セントラルは基本的には任意のタイミングでペリフェラルにインベントを起こせる/Write
- ペリフェラルからもセントラルが通知を購読していると、ペリフェラルからのpushがリアルタイム受け取れる(セントラルがペリフェラルをポーリング/readしなくていい)
- GATTの設計
- Notificationができるキャラクタリスティックが一つだけ
iOS
CoreBluetoothを使ってゴニョゴニョします。Swiftを使ったCoreBluetoothの使い方については @shu223 のブログに詳しいのでそちらを見て下さい!
Core Bluetooth with Swift (ObjCのおまけ付き) - Qiita
import CoreBluetooth
...
self.centralManager.scanForPeripheralsWithServices(services, options: nil)
...
func centralManager(central: CBCentralManager,
didDiscoverPeripheral peripheral: CBPeripheral,
advertisementData: [String : AnyObject],
RSSI: NSNumber){
self.peripheral = peripheral
}
...
self.centralManager.connectPeripheral(self.peripheral, options: nil)
...
func centralManager(central: CBCentralManager,
didConnectPeripheral peripheral: CBPeripheral) {
}
let services : [CBUUID]? = [self.serviceUUID]
self.peripheral.delegate = self
self.peripheral.discoverServices(services)
...
func peripheral(peripheral: CBPeripheral,
didDiscoverCharacteristicsForService service: CBService,
error: NSError?){
let characteristics = service.characteristics!
self.characteristic = characteristics[0]
}
self.peripheral.setNotifyValue(true, forCharacteristic: self.characteristic)
func peripheral(peripheral: CBPeripheral,
didUpdateValueForCharacteristic characteristic: CBCharacteristic,
error: NSError?) {
print("Update! characteristic UUID: \(characteristic.UUID), value: \(characteristic.value)")
}
ほい、だいぶ端折りましたが、これでペリフェラルのキャラクタリスティックからのNotificationを受け取れるようになりました!
iOS→AWS IoT
iOSがBLE経由で受け取った通知をそのままAWS IoTを使ってPublishします。
プロトコルはMQTTです。
import Moscapsule
moscapsule_init()
let mqttConfig = MQTTConfig(clientId: "iot_button",
host: "AAAAAAAAAAAAAA.iot.ap-northeast-1.amazonaws.com", port: 8883, keepAlive: 60)
let certFile = NSBundle.mainBundle().pathForResource("1111111111-certificate.pem", ofType: "crt")
let keyFile = NSBundle.mainBundle().pathForResource("2222222222-private.pem", ofType: "key")
let caFile = NSBundle.mainBundle().pathForResource("ca", ofType: "pem")
mqttConfig.mqttServerCert = MQTTServerCert(cafile: caFile, capath: nil)
mqttConfig.mqttClientCert = MQTTClientCert(certfile: certFile!, keyfile: keyFile!, keyfile_passwd: nil)
self.mqttClient = MQTT.newConnection(mqttConfig)
self.mqttClient!.publish(data, topic: "topic/hoge", qos: 1, retain: false)
AWS IoT→Mac
Nodeで書きました!
// aws iotでMQTTの購読
var awsIot = require('aws-iot-device-sdk');
var device = awsIot.device({
keyPath: '1111111111-private.pem.key',
certPath: '2222222222-certificate.pem.crt',
caPath: 'ca.pem',
clientId: 'iot_button_sub',
region: 'ap-northeast-1'
});
// 接続できたら購読する
device.on('connect', function() {
device.subscribe('topic/hoge');
});
// メッセージを受け取る
device.on('message', function(topic, payload) {
...
});
Mac→スライドツール
スライドツールはJS製のものなので、色々ハックできて便利です。
// websocketでブラウザと接続
var io = require('socket.io').listen(8080)
var socket;
io.sockets.on('connection', function(_socket) {
socket = _socket;
});
// MQTTのメッセージが届いたらsocketでメッセージを送る
socket.emit('click', 'next page');
var socket = io.connect("http://localhost:8080");
socket.on('connect', function() {
});
socket.on('click', function(data) {
talkie.next.push();
});
これだけ!簡単ですね!
デモ
まとめ
今回はBLEを使ったIoTボタンを作成してみました!Wi-Fiでもやってみたいですが、電池消費を気にすると接続しっぱなしってのは辛いと思うので、リアルタイム性って意味だとBLEで実装してスマフォやIoT Hubでやり取りする方がこういう用途には向くと思いました。
BLEは触っているけどサーバー側までは…って人の参考になれば幸いです☆