Web Bluetooth からAkerunを操作する

この記事はAkerun Advent Calendar 20日目の記事です。

今回はファームウェアエンジニア いとう が担当です。今回はWeb Bluetoothでウェブエンジニアデビューします。目指せフルスタック!

目的

今月行われたエンジニア日帰り合宿での出来事です

誰か 「Akerunの初期設定、スマホ持ってなかったりPCに専用アプリインストールできないお客様もいる。どうしようか?」

私 「Web Bluetoothでブラウザだけで設定できればよくね?(ウェブエンジニア賢い人多そうだからサクッと作ってくれそう)」

誰か「ほな、お前やってな」

私 「・・・」

Web Bluetooth

無茶振りされましたがWeb Bluetoothなんてqiitaで何度か記事を目にしただけで海のものとも山のものともついてない私です。仕様書はここみたいです。

設定

色々な Web Bluetooth記事をみていると必ず https接続が必要!と書いてあります。まずは環境を用意することにしました。

serveo

私はサーバーとか何にもわかりませんのでSlackに流れていたローカルファイルをhttpsで公開できるserveoを使ってみます。

http://serveo.net/

f:id:photosynth-inc:20191220012449p:plain

死んどる・・・(2019年12月20日現在serveoはダウンしていうようです)

ngrok

改めて弊社の優秀なウェブエンジニアーズに聞いたところ ngrok が良さげだったのでここを参考にインストールします。ngrokはスムーズにインストール&登録できました。

nginx

ngrokさえインストールできればローカル環境でウェブサーバーを立てれば準備完了です。macOSのシステム環境設定の共有からWeb共有を有効にしま・・・・え!?ない!。随分前からWeb共有はなくなっているようです。歳はとりたくないですね。

ということでqiitaの記事にもあるようにnginxをインストールしてみましょう。

brew install nginx
nginx

上記だけで可能とのことでしたが3つほどつまずきました。

  • インストール時に権限関連で怒られる
    • brewのエラーに解決方法でてますのでその通りに実施してOK
  • 実行時にnginx: [emerg] mkdir() "/usr/local/var/run/nginx/client_body_temp" failed (2: No such file or directory)と怒られる
  • 実行時にnginx: [warn] 1024 worker_connections exceed open file resource limit: 256と怒られる

それではngrokを起動してみましょう

./ngrok http 8080
ngrok by @inconshreveable                                                                                            (Ctrl+C to quit)
                                                                                                                                     
Session Status                online                                                                                                 
Account                       waiwai@supaahakaa.co.jp (Plan: Free)                                                                   
Version                       2.3.35                                                                                                 
Region                        United States (us)                                                                                     
Web Interface                 http://127.0.0.1:4040                                                                                  
Forwarding                    http://xxxxxxxx.ngrok.io -> http://localhost:8080                                                      
Forwarding                    https://xxxxxxxx.ngrok.io -> http://localhost:8080                                                     
                                                                                                                                     
Connections                   ttl     opn     rt1     rt5     p50     p90                                                            
                              0       0       0.00    0.00    0.00    0.00        

このhttps://xxxxxxxx.ngrok.ioにアクセスすると・・・

f:id:photosynth-inc:20191220020520p:plain

あれ?だめです。結論から言うと下記のコマンドでないと動きませんでした。何故かはイマイチわかってません。

./ngrok http -host-header=rewirte 127.0.0.1:8080

これでようやくhttps接続でローカルファイルを公開できるようになりました!

結局

ここまでhttps接続環境を揃えてスクリプトをしこしこ書いていたのですが、検証のためhttps接続でなければどのようなエラーとなるのかを確認したくFinderからChromeにindex.htmlをDnDすると・・・動くやん!誰やhttpsいるっていうたん!というわけで2019年12月20日現在はhttps接続は必須ではないようです。(後述:Windows環境では必須でした)

処女作

これで私もフロントエンドエンジニアデビュー。長編大作のhtmlファイルです。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Akerun web door sensor</title>
    <script src="akerun.js"></script>
  </head>
  <body>
    <button id="close">Close</button>
  </body>
</html>

JavaScriptです。今回はAkerun付属ドアセンサーの通信を模してみました。(セキュリティ処理を外した特別なファームウェアをAkerun側に書き込んでいます。皆様がご利用のAkerunは下記の処理では動作したりしません。念の為)

var Akerun = function() {};

Akerun.prototype = {
  // AKerun
  AKERUN_SERVICE_UUID: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
  UUID_AKERUN_RX: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",

  close: function() {
    navigator.bluetooth
      .requestDevice({
        filters: [{ namePrefix: "akerun_******xx" }],
        optionalServices: [this.AKERUN_SERVICE_UUID]
      })
      .then(device => {
        console.log("device", device);
        return device.gatt.connect();
      })
      .then(server => {
        console.log("server", server);
        return server.getPrimaryService(this.AKERUN_SERVICE_UUID);
      })
      .then(service => {
        console.log("service", service);
        return service.getCharacteristic(this.UUID_AKERUN_RX);
      })
      .then(chara => {
        var buffer = new Uint8Array(xxx);
        buffer[0] = CMD_0;
        buffer[1] = CMD_1;
        buffer[2] = CMD_2;
        buffer[3] = CMD_3;
        // 中略
        buffer[xxx-1] = CMD_XXX;
        chara.writeValue(buffer);
        console.log("Akerun:", chara);
      })
      .catch(error => {
        console.log(error);
      });
  }
};

window.onload = function() {
  var akerun = new Akerun();
  document
    .getElementById("close")
    .addEventListener("click", akerun.close.bind(akerun), false);
};

結果

f:id:photosynth-inc:20191220121624g:plain

  • BLE通信はすんなりできたのでAkerunの初期設定ぐらいであれば十分可能
  • ただしJavaScriptコードが丸見えなのでセキュアな仕組みを別途構築する必要がある
    • 初期設定限定で以降は口を閉じるような仕組み?
  • 実運用では環境の縛りキツい

    • Chrome縛り
    • PCに詳しくないユーザーはPCにBLE搭載しているかどうか判断できなさそうでサポートが難しい
  • JavaScript完全に理解した

2019年12月20日追記

  • Windowsから実行するときにはchrome://flags/#enable-experimental-web-platform-featuresのフラグを有効にしてもらわないといけない
    • このフラグへのURLはリンククリックでもセキュリティのため遷移しないのでまず一般ユーザーに使ってもらうのは厳しいでしょう
    • 将来に期待

参考にしたサイト

2019年12月20日追記、編集

  • みられたくないところが伏せ字にしきれてなかったコードを微修正
  • Windowsでの制約を追記
    • macOS上はごくごく普通に動くのに・・・

・・・

株式会社フォトシンスでは、一緒にプロダクトを成長させる様々なレイヤのエンジニアを募集しています。 recruit.jobcan.jp

Akerun Proの購入はこちらから akerun.com