ESP32をAmazon Alexaのスマートホームのデバイスに登録する方法

はじめに

ESP32とAmazon Alexa(以下、Alexa)の連携を考えた際にIFTTTとBlynkを利用する方法が最初に思いつきます。

qiita.com

qiita.com

しかしながら、IFTTTとAlexaの連携ではAmazon Echoに話しかける際に「◯◯、トリガー」と語尾にトリガーとつけて発話しなければなりません。

そこで本記事ではESP32をAlexaのスマートホームのデバイスにし、自然な発話から制御できる方法をご紹介します。

完成品

AlexaのアプリからLEDを制御しています。Amazon Echoに話しかけても同様のことが出来ます。


開発環境

準備物

  • ESP32-DevKitC

akizukidenshi.com

  • LEDと抵抗とブレッドボード(確認用)

前提

本記事ではESP32の開発環境の設定とAmazon Echo及びAlexaアプリの設定がお済みの方を対象としております。

1.FauxmoESPの取得

ESP32をスマートホームのデバイスとするライブラリであるFauxmoESPとライブラリ内で利用しているAsyncTCPを下記からダウンロードします。

FauxmoESPについてはバージョン2.4.4を利用しております。「ダウンロード」→「タグ」から2.4.4のzipファイルをダウンロードしてください。

bitbucket.org

github.com

ダウンロードしたものをArduino IDEの「スケッチ」→「ライブラリをインクルード」→「.ZIP形式のライブラリをインストール」を選択してインストールします。

Arduino IDEの「スケッチ」→「ライブラリをインクルード」→「ライブラリを管理」から「fauxmoESP」と検索すると同名のライブラリがありますが、ESP32は非対応のものです。

※※FauxmoESPのバージョン3.0.0については私の環境では正常に動作しませんでした。下記でも同様の指摘がされています。(2018/09/22)
xoseperez / fauxmoESP / issues / #58 - v3.0 not discovered by Alexa — Bitbucket

2.スケッチ例

Arduino IDEから下記のスケッチを書き込みます。こちらのスケッチはオンの時にLEDが点灯し、オフの時に消灯します。サンプル例をもとに作成してます。

#include <Arduino.h>
#include <WiFi.h>
#include "fauxmoESP.h"
#define SERIAL_BAUDRATE                 115200
#define LED                             2

fauxmoESP fauxmo;

char ssid[] = "";
char password[] = "";

// -----------------------------------------------------------------------------
// Wifi
// -----------------------------------------------------------------------------

void wifiSetup() {

    // Set WIFI module to STA mode
    WiFi.mode(WIFI_STA);

    // Connect
    Serial.printf("[WIFI] Connecting to %s ",ssid);
    WiFi.begin(ssid, password);

    // Wait
    while (WiFi.status() != WL_CONNECTED) {
        Serial.print(".");
        delay(100);
    }
    Serial.println();

    // Connected!
    Serial.printf("[WIFI] STATION Mode, SSID: %s, IP address: %s\n", WiFi.SSID().c_str(), WiFi.localIP().toString().c_str());

}

void setup() {

    // Init serial port and clean garbage
    Serial.begin(SERIAL_BAUDRATE);
    Serial.println();
    Serial.println();

    // Wifi
    wifiSetup();

    // LED
    pinMode(LED, OUTPUT);
    digitalWrite(LED, HIGH);

    // You have to call enable(true) once you have a WiFi connection
    // You can enable or disable the library at any moment
    // Disabling it will prevent the devices from being discovered and switched
    fauxmo.enable(true);

    // Add virtual devices
    fauxmo.addDevice("照明");

    // fauxmoESP 2.0.0 has changed the callback signature to add the device_id,
    // this way it's easier to match devices to action without having to compare strings.
    fauxmo.onSetState([](unsigned char device_id, const char * device_name, bool state) {
        Serial.printf("[MAIN] Device #%d (%s) state: %s\n", device_id, device_name, state ? "ON" : "OFF");
        digitalWrite(LED, state);
    });

    // Callback to retrieve current state (for GetBinaryState queries)
    fauxmo.onGetState([](unsigned char device_id, const char * device_name) {
        return digitalRead(LED);
    });

}

void loop() {

    // Since fauxmoESP 2.0 the library uses the "compatibility" mode by
    // default, this means that it uses WiFiUdp class instead of AsyncUDP.
    // The later requires the Arduino Core for ESP8266 staging version
    // whilst the former works fine with current stable 2.3.0 version.
    // But, since it's not "async" anymore we have to manually poll for UDP
    // packets
    fauxmo.handle();

    static unsigned long last = millis();
    if (millis() - last > 5000) {
        last = millis();
        Serial.printf("[MAIN] Free heap: %d bytes\n", ESP.getFreeHeap());
    }

}

私の環境ではコンパイル時に\Arduino\libraries\xoseperez-fauxmoesp-985880034f3a\src\fauxmoESP.cppに対してエラーメッセージが2つ出ました。

  1. error: embedded '\0' in format [-Werror=format-contains-nul]
  2. error: format '%X' expects argument of type 'unsigned int', but argument 5 has type 'long unsigned int' [-Werror=format=]

該当している行はこちらの2つでした。

345行目:snprintf_P(uuid, sizeof(uuid), PSTR("%02X%06X46584D\0"), device_id, chip_id); // DEV_ID + CHIPID + "FXM"
350行目:sprintf(serial, "221703K0%06X\0", chip_id); // "221703K0" + CHIPID

1はこちらを参考にして修正をし、
stackoverflow.com

2は%Xを%lXと修正しました。

修正後はこちらとなります。

345行目:snprintf_P(uuid, sizeof(uuid), PSTR("%02X%06lX46584D%c"), device_id, chip_id,'\0'); // DEV_ID + CHIPID + "FXM"
350行目:sprintf(serial, "221703K0%06lX%c", chip_id,'\0'); // "221703K0" + CHIPID


修正後、再度コンパイルすることで、コンパイルエラーがなくなると思います。

3.ESP32の接続例

正常に動作しているかを確認するためにLEDを接続します。スケッチで指定したピン番号と同じ番号の箇所に繋ぎます。

f:id:kuracux:20180921232154j:plain

ESP32の起動後、Wi-Fiに接続できるとLEDが点灯します。

4.Alexaアプリと接続

Alexaアプリの「スマートホーム」→「デバイスを追加」を選択します。

f:id:kuracux:20180921233059j:plain:w250 f:id:kuracux:20180921233057j:plain:w250

Amazon Echoによる検索後、スケッチ例のfauxmo.addDeviceにて指定した名前が一覧に表示されます。

f:id:kuracux:20180921233111j:plain:w300

指定した名前を選択して、ボタンを押すとLEDが点灯・消灯します。また、Amazon Echoに「(指定した名前)を消して」や「(指定した名前)オン」と話しかけることで制御することも出来ます。

f:id:kuracux:20180921233121j:plain:w300

おわりに

ESP32をAlexaのスマートホームのデバイスに登録する方法をご紹介しました。

FauxmoESPのバージョン3.0.0では数値を扱えるようになるそうなので、実現できれば照明の調整等も出来そうですね。

This allows for a simpler code and also support for numeric values (you can now say "Alexa, set light to 50").

おまけ

ESP32を搭載しているM5Stackにおいても同様のことが出来ました。