Help us understand the problem. What is going on with this article?

toio.jsをブラウザで動かしてみた

toioとは?

toio(トイオ)はソニーから発売された手のひらサイズのロボットです。
toio
シンプルな見た目ながら工夫次第で色んな遊び方ができるのが特徴で、我が家では4才になる息子がゲズンロイドにどハマりしています。

toio.js

さてそんなtoioをプログラミングできるNode.js向けのライブラリ toio.js が公開されました。

サンプルを触ってみると動作も安定しておりAPIもお手軽で良い感じです。

何を作ろうか思案しているときに、ふとWeb Bluetoothのことを思い出したので、ブラウザ上でtoio.jsを動かしてみることにしました。

ブラウザからtoioを操作するご様子

まずは実際の動作の様子から。こちらの動画をご覧ください。
toioをブラウザから操作する
Node.jsは使っておらず、ブラウザだけでtoioを制御しています。

toioを持っていればChromeから以下のURLにアクセスすることで同じアプリを試すことができます。

https://snoguchi.github.io/toio-browser-example/dist/

Web Bluetoothを利用するためChromeでしか動作しない1のがやや残念ですが、URLを送りつけるだけで手軽に自作のtoioアプリをドヤれるのはなかなか画期的ではないでしょうか。

toio.jsをブラウザで使う方法

このようなアプリを作るために、toio.jsをブラウザから利用するためのポイントを解説していきます。

1. webpackの設定でnobleのWeb Bluetoothバインディングを有効にする

ブラウザでJSといえばwebpackですね。
toio.jsは依存モジュールが少ないこともあって比較的素直にwebpackが通るのですが、1点だけ特別な設定をしてあげる必要があります。それがこちら。

webpack.config.js
module.exports = {
  ...
  resolve: {
    alias: {
      // noble-macをnobleにバイパス
      'noble-mac': 'noble'
    }
  },
  plugins: [
    // ついでにwsも不要なので無効化
    new webpack.IgnorePlugin(/^ws$/)
  ],
  ...
};

toio.jsがBLEスタックとして利用している noble は元々Web Bluetoothバインディングを持っています2が、noble-mac というラッパーがこのバインディングを無効化してしまっています。

ブラウザではnoble-macモジュールは不要なのでwebpackでオリジナルのnobleにバイパスするように設定します。

またnobleがWeb Bluetoothのフォールバックのためwsモジュールを巻き込もうとしますが、Chromeで使うと割り切れば不要なのでそちらも無効化しておきます。

2. ユーザアクションからcubeを初期化する

Web Bluetooth APIはユーザーアクション(クリックやキーボード操作など)をトリガーに実行する必要があります。

toio.jsの場合は以下のようにcubeの初期化部分をclickリスナーなどからたたくようにしてあげればOKです。

main.js
import { NearestScanner } from '@toio/scanner';

document.getElementById('connect').addEventListener('click', async () => {
  const cube = await new NearestScanner().start();
  await cube.connect();
}

初期化部分さえパスしてしまえば、その後はユーザ操作がなくともAPIを叩けるようになります。

3. Web Bluetoothの一部APIを排他制御する

ここまでの手順で PC Chrome 上ではtoio.jsが動作するようになるのですが、Android Chromeでは初期化時( cube.connect() の実行時)にエラーが出てしまいます。

AndroidのBLEには readValueとstartNotificationを複数同時に実行できない という制約があり、どうやらこれに引っかかってしまうようです。

この制約はWeb Bluetooth APIに以下のようなモンキーパッチをあてることで回避することが出来ます。自前のアプリにそのままコピペするなどしてお試しください。

main.js
if (/android/i.test(navigator.userAgent)) {
  const mutexify = (promiseFn, mutex = Promise.resolve()) => {
    return function(...args) {
      const job = () => promiseFn.apply(this, args);
      return (mutex = mutex.then(job, job));
    };
  };

  // readValue と startNotification を排他制御
  const proto = BluetoothRemoteGATTCharacteristic.prototype;
  const mutex = Promise.resolve();
  proto.startNotifications = mutexify(proto.startNotifications, mutex);
  proto.readValue = mutexify(proto.readValue, mutex);
}

さいごに

以上の3点で、PC/AndroidのChromeからtoio.jsを利用することが出来るようになると思います。サンプルのソースも置いておきますので不明な点があれば参考にしてみてください。

https://github.com/snoguchi/toio-browser-example

この記事がなにかtoioアプリ開発のきっかけになれば嬉しいです。

それではみなさま良いtoio.jsライフをお過ごしください!


  1. このあたりを見るとOperaでも動作するのかもしれないが未確認 

  2. 何故かnobleのサイト見ててもほとんど言及がなくソース見て初めて気が付くレベル 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした