Alexa対応のセンサーを自作する

f:id:moyashipan:20201027230054j:plain

Alexa対応センサーは種類が少なすぎる

Alexaに対応したセンサーはいくつかの種類が販売されており、センサーの値の変化を実行条件にした定形アクションを組むことができます。

センサーの種類として、例えば、Echo Flexにそのまま接続できるような人感センサー。

他には、電池で駆動するドアセンサー。

似たような物として、スマホアプリと連動した漏水センサーや温度計などもありますが、現時点ではAlexaの定形アクション実行条件に対応していることが確認できなかったため、自分としては実質「人感センサーとドアセンサーしかAlexaの定形アクション実行条件に対応していない」という認識です。

もっと豊富な種類のセンサーを扱いたい

Alexa対応のセンサーが今後増えていく可能性はありますが、いつ出るともわかりませんし、自分の検知したい機能を有しているかもわかりません。

無いなら作りましょう。
たとえば自分は以前、測距センサーを使って猫がいるかどうかを判定し、IFTTTに対してイベントをトリガーする電子工作を行いました。 moyashipan.hatenablog.com

これをIFTTTを経由せず、Alexaにデバイス登録できるセンサーとして作ってみました。

完成した物

測距センサーで一定の距離内に遮蔽物がある/ないことを検知して、その結果をドアセンサーの閉/開としてAlexaに伝える仕組みを作りました。

3Dプリンターでケースも作ってみました。

作り方

こちらを参考にしました。 qiita.com

必要なことを大きくまとめると以下です。

  • Alexa Smart Homeのカスタムスキルを登録する
  • Lambdaの関数コードを登録する
  • バイス側からChangeReportを送る

ただし、Lambdaのコードは以下のように変更してあります。

  • 今回はContactSensorとして登録する(いつ動きがあったか、ではなく今いるのかどうかで管理したい)
  • DiscoverAcceptGrant にだけ反応して、それ以外は ChangeReport イベントをデバイスから送ることにする

コードは記事の最後にまとめて記載しています。
上手くいけば、Alexa上に自分が設定したデバイスが追加されているはずです。
client_id, client_secret, refresh_token が取得できたら、デバイスの準備に移ります。

バイスの準備

今回は以下を使いました。

  • M5ATOM Matrix
  • 測距センサー

www.switch-science.com

akizukidenshi.com

M5ATOM Matrixの背面にある「33ピン」「5V」「GND」に測距センサーを接続し、後述のコードの所定の箇所を以下の情報で上書きし、書き込みます。

  • WiFi用のSSID, パスワード
  • client_id, client_secret, refresh_token

上手くいけば、Alexa上の当デバイスの開閉の値が更新されるのが見れるはずです。
Alexaの画面上だけでなく、距離の度合いがLEDアレイに大きく表示されるので動作確認がしやすくて良いですね。

上手くいかない場合にはPostmanなどを利用して、どの通信が上手くいっていないかを確かめると良いでしょう。

ホットカーペットの準備

今回はセンサーの値に応じてホットカーペットをON/OFFするというねらいなので、スマートプラグでON/OFFされるホットカーペットを準備します。

例えば以下のような製品をつないで、スマートプラグにホットカーペットという名前を付けて、Alexaにデバイス登録するだけです。
これだけでも(=センサーが無くても)声や時刻でON/OFFできるので便利ですね。

定形アクションの設定

センサーとホットカーペットの準備ができたので、最後に定形アクションの設定を行います。
以下のように2つの定形アクションを設定します。

これにより、猫がいる間だけホットカーペットが自動でONになる仕組みが実現できました。

さいごに

スマートホームに対するこだわりが増してくると、既存のセンサーだけでは満足できなくなってきます。
そんな時、自分でセンサーを繋いだデバイスを作れると便利です。
今回は測距センサーを用いましたが、それ以外のセンサーを繋げば、例えば

  • 明るくなったら/暗くなったら
  • 重くなったら/軽くなったら
  • うるさくなったら/静かになったら

といった場合にAlexaに通知・トリガーイベントを送信するデバイスも作れるでしょう。

慣れないうちはAWSの操作でまごつくこともありますが、スマートホームの自由度が増すのでぜひ試してみてください。

Lambda関数コード

exports.handler = function (request, context) {
    if (request.directive.header.namespace === 'Alexa.Discovery' && request.directive.header.name === 'Discover') {
        log("DEBUG:", "Alexa.Discovery:",  JSON.stringify(request));
        handleDiscovery(request, context, "");
    }
    else if (request.directive.header.name === 'AcceptGrant') {
        log("DEBUG:", "AcceptGrant:", JSON.stringify(request));   // AcceptGrantの内容をlogに出力
        var response = {
            "event": {
              "header": {
                "namespace": "Alexa.Authorization",
                "name": "AcceptGrant.Response",
                "messageId": request.directive.header.messageId,
                "payloadVersion": "3"
              },
              "payload": {}
           }
        };
        context.succeed(response);
    } 
    else {
      log("DEBUG:", "Other request:", JSON.stringify(request));
      log("DEBUG:", "Other context:", JSON.stringify(context));
    }

    function handleDiscovery(request, context) {
        var payload = {
            "endpoints":
            [
              {
                "endpointId": "sensor-001",
                "manufacturerName": "MOYASHIPAN Cat Carpet Sensor",
                "friendlyName": "ホットカーペット猫センサー",
                "description": "ホットカーペットに猫が乗っているかどうかを検出するセンサーです",
                "displayCategories": ["CONTACT_SENSOR"],
                "cookie": {
                  "key1": "このエンドポイントのキーと値のペアです",
                  "key2": "複数のエントリーがある場合があります",
                  "key3": "参照目的で使用します",
                  "key4": "現在のエンドポイントの状態を維持するためには使わないでください"
                },
                "capabilities": [
                  {
                    "type": "AlexaInterface",
                    "interface": "Alexa",
                    "version": "3"
                  },
                  {
                    "type": "AlexaInterface",
                    "interface": "Alexa.ContactSensor",
                    "version": "3",
                    "properties": {
                      "supported": [
                        {
                          "name": "detectionState"
                        }
                      ],
                      "proactivelyReported": true,
                      "retrievable": true
                    }
                  },
                  {
                    "type": "AlexaInterface",
                    "interface": "Alexa.EndpointHealth",
                    "version": "3",
                    "properties": {
                      "supported": [
                        {
                          "name": "connectivity"
                        }
                      ],
                      "proactivelyReported": true,
                      "retrievable": true
                    }
                  }
                ]
              }
            ]
        };
        var header = request.directive.header;
        header.name = "Discover.Response";
        log("DEBUG", "Discovery Response:", JSON.stringify({ header: header, payload: payload }));
        context.succeed({ event: { header: header, payload: payload } });
    }

    function log(message, message1, message2) {
        console.log(message + message1 + message2);
    }
};

M5ATOM Matrix用コード

Arduino IDEから書き込んでください