8
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

BLEタグとiPhoneでつくるオレオレAmazon Dash Button

Posted at

Amazon Dash Buttonをハックして自分専用に作り変えるネタが流行ってますが、もう少し簡単にできないものかと、思いまして作ってみました。

シナリオ

  1. 会議室のホワイトボードマーカーが書けなくなったことに気がつく
  2. ホワイトボードの近くの小さなBLEタグのボタンを押す
  3. Kintoneへレコードが登録される
  4. 総務部の人がそのレコードを見てホワイトボードマーカーを補充
  5. 総務部の人はKintoneのレコードを削除する

材料

  1. ボタン付きBLEタグ:iTag 833円(https://www.amazon.co.jp/dp/B017SC9U76?th=1)
  2. お手持ちのiPhone

原理

BLE通信でボタン付きBLEタグのボタンクリックイベントを拾うだけ

BLEのServiceやCharacteristicはどうやって調べたの?

下記のアプリを使うとあっという間に分かります。

BLExplr
https://itunes.apple.com/jp/app/blexplr/id524018027?mt=8

コード

コンセプト通り機能するかを確認するレベルの内容ですが、こんな感じです。

ViewController.swift
import UIKit
import CoreBluetooth
import Alamofire

class ViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate  {

    @IBOutlet weak var label: UILabel!
    @IBOutlet weak var activityIndicator: UIActivityIndicatorView!
    var centralManager: CBCentralManager!
    var tag: CBPeripheral!
    let kintoneBaseURL   = "https://<Kintoneのドメイン>/k/v1"
    let kintoneAppID     = /* <KintoneアプリのID> */
    let kintoneToken     = /* <KIntoneアプリのアクセストークン> */
    let blueTagUUID      = /* <iTagのUUID> */
    let blueTagServiceID = /* <iTagのService ID> */
    let blueTagCharID    = /* <iTagのCharacteristic ID> */
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.centralManager = CBCentralManager(delegate: self, queue: nil, options: nil)
        label.isHidden = true
        activityIndicator.startAnimating()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }


    // CentralManager状態の受信
    func centralManagerDidUpdateState(_ central: CBCentralManager) {
        switch (central.state) {
        case .poweredOff:
            NSLog("BLE PoweredOff")
        case .poweredOn:
            NSLog("BLE PoweredOn")
            central.scanForPeripherals(withServices: nil, options: nil)
        case .resetting:
            NSLog("BLE Resetting")
        case .unauthorized:
            NSLog("BLE Unauthorized")
        case .unknown:
            NSLog("BLE Unknown")
        case .unsupported:
            NSLog("BLE Unsupported")
        }
    }
    
    // Peripheral探索結果の受信と接続
    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber){
        NSLog("name: \(peripheral.name), UUID: \(peripheral.identifier.uuidString), adData: \(advertisementData), RSSI: \(RSSI)")
        
        if(peripheral.identifier.uuidString == blueTagUUID){
            self.centralManager.stopScan()
            self.tag = peripheral
            self.centralManager.connect(self.tag, options: nil)
        }
    }
    
    // Peripheralへの接続結果の受信(成功時)
    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
        NSLog("connection success: \(peripheral.identifier.uuidString)")
        peripheral.delegate = self
        
        // サービスを探索
        let UUID = CBUUID(string: blueTagServiceID)
        peripheral.discoverServices([UUID])
    }
    
    // Peripheralへの接続結果の受信(失敗時)
    func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
        NSLog("connection failed: \(peripheral.identifier.uuidString)")
    }
    
    // Service探索結果の受信
    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
        if (error != nil) {
            NSLog("error: \(error)")
            return
        }
        
        for service in peripheral.services!
        {
            NSLog("found service: \(service)")
            
            //Characterristicを探索
            let UUID = CBUUID(string: blueTagCharID)
            peripheral.discoverCharacteristics([UUID], for:service as CBService)
        }
    }
    
    // Characterristic探索結果の受信
    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?){
        if (error != nil) {
            NSLog("error: \(error)")
            return
        }
        
        for characteristic in service.characteristics! {
            NSLog("found characteristic: \(characteristic.uuid)")
            if(characteristic.uuid.uuidString == blueTagCharID){
                peripheral.setNotifyValue(true, for: characteristic)
            }
        }
    }
    
    // データ更新通知受け取り開始/停止結果を取得する
    func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
        if let error = error {
            NSLog("error: \(error)")
        } else {
            NSLog("isNotifying: \(characteristic.isNotifying)")
            activityIndicator.hidesWhenStopped = true
            activityIndicator.stopAnimating()
            label.isHidden = false
        }
    }
    
    // データ更新通知を受け取る = ボタンが押された際に発生するイベント
    func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
        if let error = error {
            NSLog("error: \(error)")
            return
        }
        
        NSLog("value updated. UUID: \(characteristic.uuid.uuidString), value: \(characteristic.value)")
        
        if(label.text == "Push me!"){
            label.text = "Hello!"
        }else{
            label.text = "Push me!"
        }
        sendKintone()
    }
    
    func sendKintone(){
        let headers: HTTPHeaders = [
            "X-Cybozu-API-Token":kintoneToken
        ]

        let params: Parameters = [
            "app": kintoneAppID,
            "record": [
                "アイテム" : ["value" : "会議室A:ホワイトボードマーカー(黒)"],
                "数量"    : ["value" : "2"],
            ]
        ]
        
        _ = Alamofire.request("\(kintoneBaseURL)/record.json", method: .post, parameters: params, encoding: JSONEncoding.default, headers: headers).responseJSON{ resp in
                        
            switch resp.result {
            case .success:
                NSLog("Sent")
            case .failure(let error):
                NSLog(error as! String)
            }
        }
    }
}

参考にした記事

[Swift][初心者]BLE接続するための情報まとめ
Core Bluetooth with Swift (ObjCのおまけ付き)

8
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?