LoginSignup
1
1

switchbot Handをobnizから動かした

Posted at

ちょっと前に switchbot 温湿度計をobnizと連携させたの次として、switchbot hand
(一番みんながswitchbotといわれて連想するやつ)を連携させました

Swtichbot APIを読む

前回はMeter(温湿度計)のを読んだので、今回はHandを読みます。

温湿度計の場合はデータの流れがSwitchbotデバイス→obniz→nodejsのみだったので簡単でしたが、
今回はその逆向きもあるので、ちょっとだけ複雑になります。

  • ブロードキャスト(アドバタイズメント)のメッセージ
  • 接続して行うコミュニケーションモード

のうち、コミュニケーションモードが必須になります。

ブロードキャストの方は温湿度計と同じ形で実装できますので、そちらを参考にしてください。

コミュニケーションモード

ドキュメントだとこのあたりですね。

SS20231225120551.png

BLEの知識がないと何を言っていることやら、となるわけですが、
要するに、コマンド方式(Request/Response方式)でいろいろコミュニケーション取れるよ、と書いてあります。

例えば、

  • obniz → Switchbot にスイッチONにして!と依頼する
  • Switchbot → obniz に OKと帰ってくる

とか、

  • obniz → Switchbot に状態を尋ねる
  • Switchbot → obniz で状態を教えてもらう

みたいな感じで、必ずobniz側からスタートする感じになります。

コマンドが当然バイナリ配列になるわけですが、例えばスイッチONにするコマンドはこの形のようです
SS20231225121011.png

SS20231225121031.png

読解する前に、ご丁寧にサンプルが書いてありました
SS20231225121051.png

つまり、 [0x57 0x01 0x00] を送れば動く、ということです。
obniz的にはcharacteristics.write([0x57 0x01 0x00]) ですね。

これを書くだけだとResponseが受け取れてないので、responseも受け取れるように作れば、動かすことができます。

実装してみる

上記を踏まえて実装を抜粋するとこんな感じ



  public async connectWait(
    setting?: Pick<BleConnectSetting, 'retry' | 'forceConnect'>
  ) {
    await this._peripheral.connectWait(setting);

    this._peripheral.ondisconnect = (reason: any) => {
      if (typeof this.ondisconnect === 'function') {
        this.ondisconnect(reason);
      }
    };
    const service = this._peripheral.getService(
      'cba20d00-224d-11e6-9fb8-0002a5d5c51b'
    );
    if (!service) {
      throw new Error(`no service found`);
    }
    const rxFromTargetCharacteristic = service.getCharacteristic(
      'cba20003-224d-11e6-9fb8-0002a5d5c51b'
    )!;
    const txToTargetCharacteristic = service.getCharacteristic(
      'cba20002-224d-11e6-9fb8-0002a5d5c51b'
    )!;

    this._commandSequence = new BleRemoteCommandSequence(
      txToTargetCharacteristic,
      rxFromTargetCharacteristic
    );

    await this._commandSequence.setupWait();
  }

  protected _createCommand(command: number, payload: number[]): number[] {
    return [
      0x57, // Magic Number
      command,
      ...payload,
    ];
  }
  
  protected async executeActionWait(action: SwitchbotBotAction) {
    if (!this._peripheral.connected || !this._commandSequence) {
      throw new Error('connect device at first');
    }
    const results = await this._commandSequence.transactionWait(
      this._createCommand(0x01, [action])
    );
    if (results[0] !== 0x01) {
      throw new Error('execute action failed ' + results[0]);
    }
    return results;
  }

  public async pressWait() {
    return await this.executeActionWait(SWITCHBOT_BOT_ACTION.PushAndPullBack);
  }


connect直後にBleRemoteCommandSequenceを使ってコマンド方式の遣り取りをするインスタンスを作ってます。
pressWaitが押されたら [0x57 0x01 0x00]のバイナリを_createCommandで作り、_commandSequence.transactionWaitで送ってます。

実験してみる

ちゃんと動いているのが確認できました!

そのうちパーツライブラリ化して公開します。

1
1
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
1
1