AWS Cloud9でCapybara+Selenium+Chrome設定時のエラーとその対処法について[ Everyday Rails 6章 ]
はじめに
「Rails チュートリアル」にて開発環境としてAWS Cloud9を使っていたことから、「Everyday Rails - RSpecによるRailsテスト入門」を進める際にも継続してAWS Cloud9を利用しています。
しかし、6章の「JavaScriptを使った操作をテストする」という項目で記載通りにSelenium+Chromeの設定をし、スペックを実行しようとしてもエラーが出てしまい実行することが出来ませんでした。
本記事では、私が直面したエラーメッセージとその対処法を記載したいと思います。
対象
- AWS Cloud9でRuby on RailsおよびRSpecを使用している
- 下記、設定は完了している
spec/rails_helper.rbの以下の行のコメントアウトを外している
Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }
spec/support/capybara.rbに以下を記述
Capybara.javascript_driver = :selenium_chrome
Gemfileに'chromedriver-helper'を追加
エラーメッセージとその対処法
その1
Selenium::WebDriver::Error::UnknownError: unknown error: cannot find Chrome binary
Amazon LinuxにChromeが入っていないことが原因だと考えられます。
下記コマンドを実行し、インストールを行ないましょう。
curl https://intoli.com/install-google-chrome.sh | bash
参考
https://www.t4traw.net/blog/2018/03/awsamazon-cloud9環境でheadless-chromeを使う/
その2
Selenium::WebDriver::Error::UnknownError: unknown error: Chrome failed to start: exited abnormally
spec/support/capybara.rbの記述内容を以下のように修正します。
Capybara.javascript_driver = :selenium_chrome_headless
Capybara.javascript_driver = :selenium_chromeでは実際にChromeを開いてテストしますが、AWS Cloud9ではそれが出来ないのだと思われます。
そのため、ヘッドレスモードを使ってテストをするように設定することで解決します。
その3
NameError: uninitialized constant Selenium::WebDriver::Chrome::Options
「::Selenium::WebDriver::Chrome::Options」はselenium-webdriverのバージョン3.4.1にて追加されたため、それ以上のバージョンにしなければなりません。Gemfileのselenium-webdriverのバージョンを3.4.1以上に設定し、bundle installを実行しましょう。
NTPサーバから時刻を取得してM5Stackに表示する
はじめに
M5Stackのスケッチ例に「TFT_Clock_Digital」というものがあります。
TFT_Clock_Digital pic.twitter.com/7TpLEJwhfg
— クラクス (@kuracux) 2018年10月7日
デジタル時計のように時刻が画面上に表示され1秒ごとに変化しますが、表示される時刻はコンパイルした時刻が基準となります。
(厳密には違うと思いますが大雑把な認識としてだとお思いください。)
そのため、例えば15:47:00にコンパイルした場合、電源を入れる度に15:47:00がまず表示され、そこから1秒ごとに表示される時刻が変化します。
しかしながら、そのままでは時計としての役割を果たせないため、NTPサーバから時刻を取得して現在の時刻を表示できるものを作成しましたのでご紹介します。
完成品
画面に表示されている文字列の見た目はTFT_Clock_Digitalと同様ですが、こちらは電源ボタンを押して再度起動しても隣の時計とほぼ同じ時刻を表示してくれます。
NTPサーバーから取得した時刻をM5StackのTFT_Clock_Digitalで表示してみました pic.twitter.com/W3zUNAq9F6
— クラクス (@kuracux) 2018年10月3日
準備物
- M5Stack Gray
- 出版社/メーカー: スイッチサイエンス
- メディア: おもちゃ&ホビー
- この商品を含むブログを見る
※M5Stackであればどのシリーズ(Basic,FIRE等)でも問題ないと思います。
1.下記のスケッチを書き込む
スケッチ例にある「TFT_Clock_Digital」と「SimpleTime」の合わせ技となっております。
以下にそれぞれのスケッチ例がありますので、参考になるかと思います。
- TFT_Clock_Digital
ファイル→スケッチ例→M5Stack→Advanced→Display→TFT_Clock_Digital
- SimpleTime
ファイル→スケッチ例→ ESP32→Time→SimpleTime
#include <M5Stack.h> #include <WiFi.h> #include "time.h" const char* ssid = ""; const char* password = ""; const char* ntpServer = "ntp.jst.mfeed.ad.jp"; const long gmtOffset_sec = 9 * 3600; const int daylightOffset_sec = 0; static uint8_t conv2d(const char* p); // Forward declaration needed for IDE 1.6.x uint8_t hh = conv2d(__TIME__), mm = conv2d(__TIME__ + 3), ss = conv2d(__TIME__ + 6); // Get H, M, S from compile time byte xcolon = 0, xsecs = 0; void setup(void) { Serial.begin(115200); M5.begin(); M5.Lcd.fillScreen(TFT_BLACK); M5.Lcd.setTextSize(1); M5.Lcd.setTextColor(TFT_YELLOW, TFT_BLACK); //connect to WiFi Serial.printf("Connecting to %s ", ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("CONNECTED"); //init and get the time configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); struct tm timeinfo; if (!getLocalTime(&timeinfo)) { Serial.println("Failed to obtain time"); return; } //disconnect WiFi as it's no longer needed WiFi.disconnect(true); WiFi.mode(WIFI_OFF); } void loop() { struct tm timeinfo; if (!getLocalTime(&timeinfo)) { Serial.println("Failed to obtain time"); return; } hh = timeinfo.tm_hour; mm = timeinfo.tm_min; ss = timeinfo.tm_sec; // Update digital time int xpos = 0; int ypos = 85; // Top left corner ot clock text, about half way down int ysecs = ypos + 24; // Draw hours and minutes if (hh < 10) xpos += M5.Lcd.drawChar('0', xpos, ypos, 8); // Add hours leading zero for 24 hr clock xpos += M5.Lcd.drawNumber(hh, xpos, ypos, 8); // Draw hours xcolon = xpos; // Save colon coord for later to flash on/off later xpos += 29; if (mm < 10) xpos += M5.Lcd.drawChar('0', xpos, ypos, 8); // Add minutes leading zero xpos += M5.Lcd.drawNumber(mm, xpos, ypos, 8); // Draw minutes xsecs = xpos; // Sae seconds 'x' position for later display updates if (ss % 2) { // Flash the colons on/off M5.Lcd.setTextColor(0x39C4, TFT_BLACK); // Set colour to grey to dim colon M5.Lcd.drawChar(':', xcolon, ypos - 8, 8); // Hour:minute colon xpos += M5.Lcd.drawChar(':', xsecs, ysecs, 6); // Seconds colon M5.Lcd.setTextColor(TFT_YELLOW, TFT_BLACK); // Set colour back to yellow }else{ M5.Lcd.drawChar(':', xcolon, ypos - 8, 8); // Hour:minute colon xpos += M5.Lcd.drawChar(':', xsecs, ysecs, 6); // Seconds colon } //Draw seconds if (ss < 10) xpos += M5.Lcd.drawChar('0', xpos, ysecs, 6); // Add leading zero M5.Lcd.drawNumber(ss, xpos, ysecs, 6); // Draw seconds } // Function to extract numbers from compile time string static uint8_t conv2d(const char* p) { uint8_t v = 0; if ('0' <= *p && *p <= '9') v = *p - '0'; return 10 * v + *++p - '0'; }
参考
M5Stackとカラーセンサでカラーピッカーとカラーミキサーを作る
はじめに
先日開催されたROHM OPEN HACK CHALLENGE2018の最終審査に関するツイートが私のタイムラインに流れてきました。
open.rohm.com
どの作品も素晴らしいものでしたが、私が特に好きだったものは優秀賞に選ばれた『絵の具カラーピッカー「絵のピック」』でした。
絵の具カラーピッカー「絵のピック」。実世界の色をコピーして絵の具を作ります。絵を描くのが楽しくなりそうなアイテム… #rohc2018 pic.twitter.com/8tgU39tVi4
— 池澤あやか / いけあや (@ikeay) 2018年9月8日
「絵のピック」について簡単に説明すると、カラーセンサで対象の色を読み取り、読み取った色を実際に絵の具を使用して作ってくれるものです。(詳細は下記参照)
open.rohm.com
この作品を見て、私も似たようなものを作りたいと思いましたが、なかなか実現することが難しいため、簡易的に、かつ似たようなことが出来るものをM5Stackとカラーセンサを用いて作りましたのでご紹介します。
完成品
今回作成した機能は2つです。
1つ目の機能は色の読み取りです(カラーピッカー)。こちらはカラーセンサを用いて実現しています。読み取った色をディスプレイに表示しています。
カラーセンサーが届いたのでM5Stackでカラーピッカーを作りました。ボタンを押すことで色を読み取ります。#M5Stack pic.twitter.com/a6S67sOUuy
— クラクス (@kuracux) 2018年9月12日
2つ目の機能は読み取った2つの色を混ぜることです(カラーミキサー)。1つ目の機能を用いて色を2回読み取り、それらを混ぜ合わせた色をディスプレイに表示しています。
カラーセンサーで検出した2つの色を混ぜた結果をM5Stackにて表示してみました#M5Stack pic.twitter.com/PGdVMADs49
— クラクス (@kuracux) 2018年9月13日
準備物
- M5Stack Gray
- 出版社/メーカー: スイッチサイエンス
- メディア: おもちゃ&ホビー
- この商品を含むブログを見る
※M5Stackであればどのシリーズ(Basic,FIRE等)でも問題ないと思います。
- カラーセンサ
WINGONEER カラーセンサ色認識モジュールTCS230 TCS3200
- 出版社/メーカー: WINGONEER
- メディア:
- この商品を含むブログを見る
- ジャンパーワイヤ(オス-メス)
1.M5Stackとカラーセンサを繋ぐ
カラーセンサの接続に関して、こちらを参考に繋ぎました。
nn-hokuson.hatenablog.com
私は以下のようにカラーセンサとM5Stackを繋ぎましたが、M5Stackのピンの仕様について理解できていないのでこれが正しいかは保証できません。ご了承ください。
カラーセンサ | M5Stack |
---|---|
S0 | 1 |
S1 | 16 |
S2 | 17 |
S3 | 21 |
OUT | 22 |
VCC | 5V |
0E | G |
GND | G |
2.キャリブレーション用のスケッチ例
1.で参考にした記事より引用
センサから得られる値はお使いの環境で多少変化すると思うので、キャリブレーションする必要があります。
白色の紙をセンシングした時のRGB値と、黒色の紙をセンシングした時のRGB値を調べて、whiteRGB、blackRGBの値に代入して下さい。
よって、まずは下記のスケッチを書き込み、キャリブレーションします。こちらも先程の記事内のスケッチを参考にしております。
#include <M5Stack.h> #define S0 1 #define S1 16 #define S2 17 #define S3 21 #define sensorOut 22 void setup() { M5.begin(); pinMode(S0, OUTPUT); pinMode(S1, OUTPUT); pinMode(S2, OUTPUT); pinMode(S3, OUTPUT); pinMode(sensorOut, INPUT); digitalWrite(S0,HIGH); digitalWrite(S1,LOW); Serial.begin(9600); } void loop(void) { if (M5.BtnA.wasPressed()){ digitalWrite(S2,LOW); digitalWrite(S3,LOW); int r = pulseIn(sensorOut, LOW); //r = map(constrain(r,blackR,whiteR), whiteR, blackR,0,255); delay(100); digitalWrite(S2,HIGH); digitalWrite(S3,HIGH); int g = pulseIn(sensorOut, LOW); //g = map(constrain(g,blackG,whiteG), whiteG, blackG,0,255); delay(100); digitalWrite(S2,LOW); digitalWrite(S3,HIGH); int b = pulseIn(sensorOut, LOW); //b = map(constrain(b,blackB,whiteB), whiteB, blackB,0,255); delay(100); Serial.println(String(r) + "," + String(g) + "," + String(b) ); } M5.update(); }
対象物にカラーセンサを当ててM5Stackの左のボタンを押すことでシリアルモニタにRGB値が表示されます。
3.カラーピッカーとカラーミキサーのスケッチ例
下記のスケッチを書き込みます。2.で検出したwhiteRGB、blackRGBにそれぞれ変更してから書き込んでください。
#include <M5Stack.h> #define S0 1 #define S1 16 #define S2 17 #define S3 21 #define sensorOut 22 int whiteR = 151; int whiteG = 160; int whiteB = 120; int blackR = 14; int blackG = 14; int blackB = 11; boolean flag = false; int beforeR = 0; int beforeG = 0; int beforeB = 0; int r = 0; int g = 0; int b = 0; int alpha = 128; uint16_t getColor(uint8_t red, uint8_t green, uint8_t blue){ return ((red>>3)<<11) | ((green>>2)<<5) | (blue>>3); } void setup() { M5.begin(); M5.Lcd.setBrightness(200); pinMode(S0, OUTPUT); pinMode(S1, OUTPUT); pinMode(S2, OUTPUT); pinMode(S3, OUTPUT); pinMode(sensorOut, INPUT); digitalWrite(S0,HIGH); digitalWrite(S1,LOW); Serial.begin(9600); } void loop(void) { if (M5.BtnA.wasPressed()){ beforeR = r; beforeG = g; beforeB = b; digitalWrite(S2,LOW); digitalWrite(S3,LOW); r = pulseIn(sensorOut, LOW); r = map(constrain(r,blackR,whiteR), whiteR, blackR,0,255); digitalWrite(S2,HIGH); digitalWrite(S3,HIGH); g = pulseIn(sensorOut, LOW); g = map(constrain(g,blackG,whiteG), whiteG, blackG,0,255); digitalWrite(S2,LOW); digitalWrite(S3,HIGH); b = pulseIn(sensorOut, LOW); b = map(constrain(b,blackB,whiteB), whiteB, blackB,0,255); Serial.println(String(r) + "," + String(g) + "," + String(b) ); M5.Lcd.fillScreen(getColor(r,g,b)); }else if(M5.BtnB.wasPressed()){ M5.Lcd.fillScreen(getColor(r*((double)alpha/255)+beforeR*(1-(double)alpha/255),g*((double)alpha/255)+beforeG*(1-(double)alpha/255),b*((double)alpha/255)+beforeB*(1-(double)alpha/255))); } M5.update(); }
左のボタンを押すことで色の読み取り、2つの色を読み取った後に真ん中のボタンを押すことで2色を混ぜた後の色がディスプレイに表示されます。
スケッチ作成時に参考にしたもの
qiita.com
おわりに
M5Stackとカラーセンサでカラーピッカーとカラーミキサーを作る方法をご紹介しました。
現実世界に存在する色を読み取ってディスプレイに表示できるだけでも楽しいので、良ければ試してみてください。
M5Stack Grayを振ってディスプレイ上の画像を切り替える
はじめに
M5Stack Grayには加速度、ジャイロ、磁気を計測可能な9軸センサ、MPU9250が搭載されています。
本記事ではジャイロセンサを用いて、M5Stack Gray本体を振ることでディスプレイ上の画像を切り替える方法をご紹介します。
完成品
M5Stackを振るとディスプレイに表示されている画像が切り替わるようにしました。 pic.twitter.com/HFKQrfQ64g
— クラクス (@kuracux) 2018年9月25日
準備物
- M5Stack Gray
- 出版社/メーカー: スイッチサイエンス
- メディア: おもちゃ&ホビー
- この商品を含むブログを見る
※ M5Stack Basicではジャイロセンサを搭載していないため実現できません。
また、M5Stack FIREについてはMPU6050(三軸加速度センサ・三軸ジャイロセンサ)が搭載されているため、同様のことができるとは思います。
しかしながら、私がM5Stack FIREを所持しておらず動作確認が出来ないため、本記事の対象外とさせていただきます。
- microSDカード
- 出版社/メーカー: トランセンド・ジャパン
- 発売日: 2015/10/02
- メディア: Personal Computers
- この商品を含むブログ (1件) を見る
前提
Arduino IDEによるM5Stackの開発環境の構築が出来ており、M5Stackのスケッチ例にあるJpegDrawとMPU9250BasicAHRSの動作確認が済んでいる方を対象としています。
以下にスケッチ例がありますので確認してください。
- JpegDraw
ファイル→スケッチ例→M5Stack→Advanced→Display→JpegDraw
- MPU9250BasicAHRS
ファイル→スケッチ例→M5Stack→Modules→MPU9250→MPU9250BasicAHRS
1. 画像ファイルの準備
microSDカードにpicturesフォルダを作成し、その中に画像ファイルを何枚か入れます。また、画像ファイルのファイル名を連番となるようにします。
(本記事では画像枚数を3枚、ファイル名をp0.jpg、p1.jpg、p2.jpgとしています。)
2. スケッチ例
ポイントとしては本体を振った際のジャイロセンサの値を閾値によって判定し、移動方向(左右)に対応したフラグを立てています。
今回は完成品でご紹介した左に振る→右に振る→画像が切り替わるのスケッチとなっていますが、右に振る→左に振る→何らかの処理も可能です。
#include <M5Stack.h> #include "utility/MPU9250.h" MPU9250 IMU; bool leftFlag = false; //左に動いたことを保持するフラグ bool rightFlag = false; //右に動いたことを保持するフラグ int maxPicSize = 3; //SDカード内に入れた画像の枚数 int th = 80; int count = 1; void setup() { M5.begin(); Wire.begin(); M5.Lcd.setBrightness(100); M5.Lcd.drawJpgFile(SD, "/pictures/p0.jpg"); byte c = IMU.readByte(MPU9250_ADDRESS, WHO_AM_I_MPU9250); IMU.calibrateMPU9250(IMU.gyroBias, IMU.accelBias); } void loop() { if (IMU.readByte(MPU9250_ADDRESS, INT_STATUS) & 0x01){ IMU.readGyroData(IMU.gyroCount); // Read the x/y/z adc values IMU.getGres(); IMU.gz = (float)IMU.gyroCount[2]*IMU.gRes; } IMU.delt_t = millis() - IMU.count; if (IMU.delt_t > 100){ int accel = (int)(IMU.gz); if(accel < -th){ if(leftFlag){ //左に振る→右に振るの後の処理 M5.Lcd.fillScreen(BLACK); int num = count++ % maxPicSize; String s = "/pictures/p"+String(num)+".jpg"; M5.Lcd.drawJpgFile(SD, s.c_str()); }else{ rightFlag = true; } }else if(accel > th){ if(rightFlag){ //右に振る→左に振るの後の処理 }else{ leftFlag = true; } }else{ leftFlag = false; rightFlag = false; } IMU.count = millis(); } }
3. M5Stack Grayを振る
振りましょう。
おわりに
M5Stack Grayを振ってディスプレイ上の画像を切り替える方法をご紹介しました。
今回は画像の切り替えでしたが、画像の表示部分を別の処理に書き換えることで、振る→何らかの処理をするということも実現できると思います。
ESP32とAmazon Alexaを連携して物理スイッチを制御する
はじめに
前回の記事でESP32をAmazon Alexa(以下、Alexa)のスマートホームのデバイスに登録する方法をご紹介しました。
記事内では動作確認のためにLEDの点灯・消灯を制御していましたが、SwitchBotのような物理スイッチの制御を実現してみましたのでご紹介します。
Switch Bot ボタンを押してくれる超小型指ロボット (ワイヤレス / スイッチボット)
- 出版社/メーカー: Switch Bot / Glappy
- メディア: ホーム&キッチン
- この商品を含むブログを見る
完成品
AlexaアプリからESP32に接続されたサーボモータを制御しています。また、Amazon Echoに話しかけても動作可能です。
見た目は残念ですが、物理スイッチの制御を実現しています。
また、通常のように物理スイッチを指で押すことも可能となっています。
SwitchBotは手元にないけど、物理スイッチを制御したいという願望を無理矢理叶えたものがこちらになります。 pic.twitter.com/ylORdQt96h
— クラクス (@kuracux) 2018年9月14日
準備物
Echo 第2世代 - スマートスピーカー with Alexa、サンドストーン
- 出版社/メーカー: Amazon
- 発売日: 2018/04/03
- メディア: エレクトロニクス
- この商品を含むブログ (3件) を見る
- Alexaアプリ
- ESP32-DevKitC
- ブレッドボードとジャンパーワイヤ(オス-オス)
- サーボモータ(SG92R)
前提
前回の記事を参考にESP32とAlexaとの連携がすでに済んでいる方を対象としています。
1 スケッチ例
Arduino IDEから下記のスケッチを書き込みます。前回の記事のスケッチをもとに作成しています。
#include <Arduino.h> #include <WiFi.h> #include "fauxmoESP.h" #define SERIAL_BAUDRATE 115200 #define SERVO 15 fauxmoESP fauxmo; char ssid[] = ""; char password[] = ""; bool inputState = true; //オンオフ記録用 // ----------------------------------------------------------------------------- // 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(); // 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"); inputState = state; if(inputState){ //オンのときのサーボの挙動を記述 ledcWrite(0,60); delay(500); ledcWrite(0,40); }else{ //オフのときのサーボの挙動を記述 ledcWrite(0,25); delay(500); ledcWrite(0,40); } }); // Callback to retrieve current state (for GetBinaryState queries) fauxmo.onGetState([](unsigned char device_id, const char * device_name) { return inputState == HIGH; }); ledcSetup(0, 50, 10); // 0ch 50 Hz 10bit resolution ledcAttachPin(SERVO, 0); // 15pin, 0ch ledcWrite(0,40); } 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()); } }
2 ESP32の接続例
スケッチにて指定したピンと電源とGNDのところに挿します。
3 Alexaアプリとの接続
前回の記事と同様に接続します。今回はボタンを押すとオン・オフに応じてサーボモータが指定した動きをします。
おわりに
ESP32とAlexaを連携して物理スイッチを制御する方法をご紹介しました。
かなり強引な方法ではありますが、音声やアプリから物理スイッチを制御できるようになると生活が便利になって良いですね。
おまけ
Amazon Echoのミュートボタンを音声でオンにする方法が分からなかったため、サーボモータを利用して音声操作で無理矢理押すようにしました。
Amazon Echoのマイクオフ機能を音声で操作する方法が分からなかったので操作できるようにしました#AmazonEcho pic.twitter.com/m4JxJ4rwsY
— クラクス (@kuracux) 2018年9月2日
ESP32をAmazon Alexaのスマートホームのデバイスに登録する方法
はじめに
ESP32とAmazon Alexa(以下、Alexa)の連携を考えた際にIFTTTとBlynkを利用する方法が最初に思いつきます。
しかしながら、IFTTTとAlexaの連携ではAmazon Echoに話しかける際に「◯◯、トリガー」と語尾にトリガーとつけて発話しなければなりません。
完成品
AlexaのアプリからLEDを制御しています。Amazon Echoに話しかけても同様のことが出来ます。
Alexaのスマートホームのデバイスとして登録したESP32の音声操作版です。 pic.twitter.com/g3JYOs1E5J
— クラクス (@kuracux) 2018年9月21日
準備物
Echo 第2世代 - スマートスピーカー with Alexa、サンドストーン
- 出版社/メーカー: Amazon
- 発売日: 2018/04/03
- メディア: エレクトロニクス
- この商品を含むブログ (3件) を見る
- Amazon Alexaアプリ
- ESP32-DevKitC
- LEDと抵抗とブレッドボード(確認用)
前提
本記事ではESP32の開発環境の設定とAmazon Echo及びAlexaアプリの設定がお済みの方を対象としております。
1.FauxmoESPの取得
ESP32をスマートホームのデバイスとするライブラリであるFauxmoESPとライブラリ内で利用しているAsyncTCPを下記からダウンロードします。
FauxmoESPについてはバージョン2.4.4を利用しております。「ダウンロード」→「タグ」から2.4.4のzipファイルをダウンロードしてください。
ダウンロードしたものを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つ出ました。
- error: embedded '\0' in format [-Werror=format-contains-nul]
- 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
4.Alexaアプリと接続
Alexaアプリの「スマートホーム」→「デバイスを追加」を選択します。
Amazon Echoによる検索後、スケッチ例のfauxmo.addDeviceにて指定した名前が一覧に表示されます。
指定した名前を選択して、ボタンを押すとLEDが点灯・消灯します。また、Amazon Echoに「(指定した名前)を消して」や「(指定した名前)オン」と話しかけることで制御することも出来ます。
おわりに
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においても同様のことが出来ました。
M5StackもAmazon Alexaのスマートホームのデバイスとして登録できました。ボタンを押すことでベイマックス(白)⇔ベイマックス2.0と変わります。#M5Stack pic.twitter.com/L7jXeJDI8d
— クラクス (@kuracux) 2018年9月20日