M5 Atom Lite と Blynk でスマートリモコンを作る
はじめに
外で起動できるエアコン、イイですよね。
帰る前にスマホでエアコンつけて、帰ったらキンキン。憧れませんか?
2000円くらいでできるっぽかったので、やってみました。
備忘録的にまとめていきたいと思います。
必要なもの
※記載している価格は執筆時点でのスイッチサイエンス様の販売価格です。
-
M5 ATOM Lite - 1,408円
-
M5Stack用赤外線送受信ユニット - 616円
- パソコン
- スマホ
- インターネット環境(Wi-Fi)
環境構築
Blynk
今回は Blynk というサービスを利用したいと思います。
Blynkとは、スマホ・PC と IoT 機器をインターネットで接続してくれるサービスです。
基本無料で利用できるので、早速アカウントを作成しましょう。
アカウント作成を終えると、Blynk Tour が開始されます。
「Hi Blynk!」と挨拶を返したら、先へ進みましょう。挨拶は基本です。
Blynk Tour を終えると、Quickstart が開始されます。
ここでは Atom の機器登録とテンプレートの作成を行うことができます。
ここで作ったものを改変して Atom に書き込みます。
Hardware は ESP32
、Connectivity type は WiFi
を選択します。
IDE は PlatformIO
がおすすめです。
VSCode を IDE 化することができるすごいやつです。
導入はこちらの記事を参考にしてください。
VSCodeの設定
プロジェクトを新規作成し、Blynk 用のライブラリをインポートしろと書いています。
PlatformIO の Home から + New Project
をクリックします。
画像のように設定してください。
- Name:任意の名前
- Board:M5Stick-C (M5Stack)
- Framework:Arduino
プロジェクトが作成されると、Home の Projects タブに表示されます。
先ほど作成したプロジェクトの Open
をクリックしてください。
プロジェクトの設定ファイル platformio.ini
が開かれます。
いったん Home に戻り、Libraries から Blynk を検索します。
3番めくらいにBlynk by Volodymyr Shymanskyy
というのがあるので、クリックします。
Add to Project
をクリックし、さきほど作成したプロジェクトを選択し、Add
をクリックします。
設定ファイルを確認すると、ライブラリの情報が増えています。
M5 Atom を使用するため、いくつか追記します。
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:m5stick-c]
platform = espressif32
board = m5stick-c
framework = arduino
lib_deps = blynkkk/Blynk@^1.1.0
M5Atom
upload_speed = 115200
monitor_speed = 115200
直接書き換えて、上書き保存してください。
ついでに必要なライブラリを追加でインポートします。
Blynk のライブラリをインポートしたときと同様の手順です。
IRremoteESP8266 by David Conran
-
FastLED by Daniel Garcia
再度 設定ファイルを確認すると、先程追加したライブラリが増えています。
動作確認
試しに Atom の LED を光らせてみましょう。
界隈ではポピュラーな動作確認で「Lチカ」と呼ばれているようです。
PC に Atom を接続してください。
[Project]¥src¥main.cpp
を開きます。ここに動作を記述していきます。
#define FASTLED_ESP32_I2S true
#include <M5Atom.h>
uint16_t tmr = 0;
bool flg = false;
CRGB dispColor(uint8_t r, uint8_t g, uint8_t b){
return (CRGB)((r << 16) | (g << 8) | b);
}
void drawColor(uint8_t r, uint8_t g, uint8_t b){
M5.dis.drawpix(0, dispColor(r, g, b));
}
void setup(){
M5.begin(true, false, true);
drawColor(0, 0, 0);
tmr = 0;
flg = false;
}
void loop(){
M5.update();
if(M5.Btn.isPressed()){
flg = true;
}
if(flg){
tmr ++;
if(tmr % 2){
drawColor(0, 0, 60);
}else{
drawColor(20, 20, 20);
}
if(tmr >= 10 && !(M5.Btn.isPressed())){
flg = false;
tmr = 0;
drawColor(0, 0, 0);
}
}
delay(150);
}
サンプルで作ってみました。
とりあえずこれを main.cpp
にコピペしましょう。
下の青いバーにある →(書込ボタン)
をクリックすると、Atom へ書き込みを行います。
緑の文字で SUCCESS
と表示されたら書き込み完了です。
動画のように動作すれば動作確認完了です。
Blynk に戻りましょう
ここでは Atom が Wi-Fi に接続するサンプルを使い、機器登録を行います。
Wi-Fi の SSID と Password を入力してください。
M5 Atom は 2.4GHz 帯の Wi-Fi に対応しているため、末尾が -g
等の 2.4GHz帯の SSID を入力することに注意してください。
入力したら、コードをコピーし、main.cpp
にペーストします。
Atom で動作するため、#include <M5Atom.h>
を追記し、Atom に書き込みます。
/*************************************************************
This is a simple demo of sending and receiving some data.
Be sure to check out other examples!
*************************************************************/
// Template ID, Device Name and Auth Token are provided by the Blynk.Cloud
// See the Device Info tab, or Template settings
#define BLYNK_TEMPLATE_ID "************************"
#define BLYNK_DEVICE_NAME "************************"
#define BLYNK_AUTH_TOKEN "************************"
// Comment this out to disable prints and save space
#define BLYNK_PRINT Serial
#include <M5Atom.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
char auth[] = BLYNK_AUTH_TOKEN;
// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "ate********c-g";
char pass[] = "**************";
BlynkTimer timer;
// This function is called every time the Virtual Pin 0 state changes
BLYNK_WRITE(V0)
{
// Set incoming value from pin V0 to a variable
int value = param.asInt();
// Update state
Blynk.virtualWrite(V1, value);
}
// This function is called every time the device is connected to the Blynk.Cloud
BLYNK_CONNECTED()
{
// Change Web Link Button message to "Congratulations!"
Blynk.setProperty(V3, "offImageUrl", "https://static-image.nyc3.cdn.digitaloceanspaces.com/general/fte/congratulations.png");
Blynk.setProperty(V3, "onImageUrl", "https://static-image.nyc3.cdn.digitaloceanspaces.com/general/fte/congratulations_pressed.png");
Blynk.setProperty(V3, "url", "https://docs.blynk.io/en/getting-started/what-do-i-need-to-blynk/how-quickstart-device-was-made");
}
// This function sends Arduino's uptime every second to Virtual Pin 2.
void myTimerEvent()
{
// You can send any value at any time.
// Please don't send more that 10 values per second.
Blynk.virtualWrite(V2, millis() / 1000);
}
void setup()
{
// Debug console
Serial.begin(115200);
Blynk.begin(auth, ssid, pass);
// You can also specify server:
//Blynk.begin(auth, ssid, pass, "blynk.cloud", 80);
//Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,100), 8080);
// Setup a function to be called every second
timer.setInterval(1000L, myTimerEvent);
}
void loop()
{
Blynk.run();
timer.run();
// You can inject your own code or combine it with other sketches.
// Check other examples on how to communicate with Blynk. Remember
// to avoid delay() function!
}
Atom からの情報を確認するには シリアルモニタ
をクリックします。
Blynk への接続に成功すると AA が表示されます。
ブラウザの方も自動で進みます。
Go To Device
をクリックしてください。
Atom の接続時間が Uptime
として表示されるようになっています。
Atom を PC から切断し、ACアダプタから給電してください。
PC から切断すると更新が止まり、給電を始めるとリセットされ、また数字が増えていくことを確認できます。
さて、無線で Atom と接続できることは確認できました。
続いてモバイルネットワークからも接続できるか確認しましょう。
スマートフォンに Blynk アプリ をインストールしてください。
インストールが完了したら起動し、ログインしてください。
Quickstart Divices を開き、デバイスの Wi-Fi をオフにします。
モバイルネットワークで Uptime が更新されたら、外からも Atom と接続できることが確認できます。
赤外線通信の準備
リモコンの信号を読み取り、それを再現することでスマートリモコンを実現します。
信号の解析
信号の解析にも Atom を使用します。
Atom と M5Stack用赤外線送受信ユニット
を接続しましょう。
赤外線関係はこちらの記事を参考にさせていただきました。
AtomLite_IR_Recv.ino
の内容をそのまま書き込みます。
#include <M5Atom.h>
#include <IRrecv.h>
#include <IRsend.h>
#include <IRremoteESP8266.h>
#include <IRutils.h>
const uint16_t kIrLed = 26;
const uint16_t kRecvPin = 32;
const uint16_t kCaptureBufferSize = 1024;
const uint8_t kTimeout = 50;
IRrecv irrecv(kRecvPin, kCaptureBufferSize, kTimeout, true);
IRsend irsend(kIrLed);
decode_results results; // Somewhere to store the results
uint32_t value;
void setup() {
M5.begin(true, false, true);
irrecv.enableIRIn();
irsend.begin();
}
void loop() {
M5.update();
if (irrecv.decode(&results)) {
Serial.print(resultToHumanReadableBasic(&results));
Serial.print(resultToSourceCode(&results));
value = results.value;
Serial.println(value);
delay(500);
}
delay(50);
}
これを書き込むことで、読み取った赤外線信号がシリアルモニタに表示されます。
受光部に向かってリモコンを押してみます。
Protocol : UNKNOWN
Code : 0x8F2ACD44 (43 Bits)
uint16_t rawData[85] = {1980, 1034, 5514, 1038, 1494, 530, 1494, 530, 488,
538, 488, 538, 488, 540, 488, 538, 456, 570, 488, 540, 1494, 530, 488,
538, 488, 538, 488, 540, 488, 538, 488, 538, 456, 572, 1494, 530, 488,
540, 1494, 530, 488, 538, 488, 538, 488, 538, 488, 538, 456, 570, 488,
540, 488, 538, 488, 540, 486, 540, 488, 538, 488, 538, 488, 538, 456,
572, 488, 538, 488, 540, 1494, 530, 486, 540, 1494, 530, 1494, 530,
488, 538, 1496, 530, 1488, 536, 430}; // UNKNOWN 8F2ACD44
2401946948
重要なのは rawData の部分です。
uint16_t rawData[85] = {1980, 1034, 5514, 1038, 1494, 530, 1494, 530, 488,
538, 488, 538, 488, 540, 488, 538, 456, 570, 488, 540, 1494, 530, 488,
538, 488, 538, 488, 540, 488, 538, 488, 538, 456, 572, 1494, 530, 488,
540, 1494, 530, 488, 538, 488, 538, 488, 538, 488, 538, 456, 570, 488,
540, 488, 538, 488, 540, 486, 540, 488, 538, 488, 538, 488, 538, 456,
572, 488, 538, 488, 540, 1494, 530, 486, 540, 1494, 530, 1494, 530,
488, 538, 1496, 530, 1488, 536, 430};
この信号を送信することでリモコンの操作をシミュレートできます。
信号はスプレッドシートにまとめると楽に管理できます。
A列にはこのような数式を入力しています。
="const uint16_t " & B2 & " [" & len(C2) - len(SUBSTITUTE(C2,",","")) + 1 & "] = {" & C2 & "};"
A列を範囲選択してエディタに貼り付けることでデータを一気に記述できます。
const uint16_t test [85] = {2024, 998, 5542, 1008, 1522, 502, 1522, 502, 516, 512, 516, 510, 516, 512, 488, 538, 456, 570, 516, 512, 1522, 502, 516, 510, 516, 512, 516, 512, 514, 512, 488, 538, 456, 572, 1520, 502, 516, 512, 1520, 502, 516, 512, 516, 510, 516, 510, 488, 538, 456, 570, 516, 510, 516, 512, 516, 510, 516, 510, 516, 512, 514, 512, 488, 538, 456, 570, 516, 510, 516, 512, 1520, 502, 516, 512, 1520, 502, 1520, 502, 488, 538, 1522, 502, 1518, 504, 428};
const uint16_t test2 [85] = {2018, 1000, 5506, 1046, 1486, 538, 1486, 538, 480, 546, 480, 546, 506, 522, 496, 532, 524, 502, 480, 548, 1486, 538, 480, 548, 480, 546, 480, 546, 480, 546, 496, 532, 526, 502, 1510, 514, 480, 548, 480, 546, 480, 546, 480, 546, 480, 546, 496, 532, 1512, 512, 480, 546, 480, 546, 480, 546, 480, 546, 480, 548, 480, 548, 496, 530, 504, 524, 480, 546, 480, 546, 480, 546, 506, 522, 1512, 512, 1512, 512, 496, 532, 526, 502, 1512, 512, 474};
const uint16_t test3 [85] = {2012, 1004, 5532, 1018, 1514, 510, 1512, 510, 506, 520, 506, 520, 506, 520, 494, 532, 524, 502, 504, 522, 1512, 510, 508, 520, 506, 520, 506, 520, 506, 520, 494, 532, 502, 526, 1512, 510, 506, 520, 506, 520, 506, 520, 506, 520, 506, 520, 494, 532, 502, 524, 1512, 510, 506, 520, 506, 518, 508, 520, 506, 520, 506, 520, 494, 532, 502, 524, 506, 520, 506, 520, 506, 520, 506, 520, 1512, 512, 1512, 510, 494, 532, 1512, 510, 506, 520, 474};
送信してみる
送信する信号の解析が終わったら、送信するコードを書き込みます。
本体のボタンを押したら信号が発信されます。
信号のデータは先程抽出したものに変更してください。
#include <M5Atom.h>
#include <IRsend.h>
#include <IRremoteESP8266.h>
#include <IRutils.h>
const uint16_t kIrLed = 26;
const uint16_t test [85] = {2024, 998, 5542, 1008, 1522, 502, 1522, 502, 516, 512, 516, 510, 516, 512, 488, 538, 456, 570, 516, 512, 1522, 502, 516, 510, 516, 512, 516, 512, 514, 512, 488, 538, 456, 572, 1520, 502, 516, 512, 1520, 502, 516, 512, 516, 510, 516, 510, 488, 538, 456, 570, 516, 510, 516, 512, 516, 510, 516, 510, 516, 512, 514, 512, 488, 538, 456, 570, 516, 510, 516, 512, 1520, 502, 516, 512, 1520, 502, 1520, 502, 488, 538, 1522, 502, 1518, 504, 428};
IRsend irsend(kIrLed);
void setup() {
M5.begin(true, false, true);
irsend.begin();
}
void loop() {
M5.update();
if(M5.Btn.wasPressed()){
Serial.println("send[test]");
irsend.sendRaw(test, 85, 38);
}
delay(50);
}
スマートフォンから操作する
いよいよ Blynk の出番です。
機器登録のときのテンプレートに送信に使うコードを追加します。
#define BLYNK_TEMPLATE_ID "TMPLiYnWKL5H"
#define BLYNK_DEVICE_NAME "Quickstart Device"
#define BLYNK_AUTH_TOKEN "bVjuNoJAGYoCZ3kmQnQssQenOYIczxhY"
#define BLYNK_PRINT Serial
#include <M5Atom.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <BlynkSimpleEsp32.h>
char auth[] = BLYNK_AUTH_TOKEN;
char ssid[] = "ate********c-g";
char pass[] = "**************";
const uint16_t kIrLed = 26;
IRsend irsend(kIrLed);
const uint16_t test [85] = {2024, 998, 5542, 1008, 1522, 502, 1522, 502, 516, 512, 516, 510, 516, 512, 488, 538, 456, 570, 516, 512, 1522, 502, 516, 510, 516, 512, 516, 512, 514, 512, 488, 538, 456, 572, 1520, 502, 516, 512, 1520, 502, 516, 512, 516, 510, 516, 510, 488, 538, 456, 570, 516, 510, 516, 512, 516, 510, 516, 510, 516, 512, 514, 512, 488, 538, 456, 570, 516, 510, 516, 512, 1520, 502, 516, 512, 1520, 502, 1520, 502, 488, 538, 1522, 502, 1518, 504, 428};
BlynkTimer timer;
BLYNK_WRITE(V10) // test
{
int value = param.asInt();
if(value){
Serial.println("send[test]");
irsend.sendRaw(test, 85, 38);
}
}
BLYNK_WRITE(V0)
{
int value = param.asInt();
Blynk.virtualWrite(V1, value);
}
BLYNK_CONNECTED()
{
Blynk.setProperty(V3, "offImageUrl", "https://static-image.nyc3.cdn.digitaloceanspaces.com/general/fte/congratulations.png");
Blynk.setProperty(V3, "onImageUrl", "https://static-image.nyc3.cdn.digitaloceanspaces.com/general/fte/congratulations_pressed.png");
Blynk.setProperty(V3, "url", "https://docs.blynk.io/en/getting-started/what-do-i-need-to-blynk/how-quickstart-device-was-made");
}
// This function sends Arduino's uptime every second to Virtual Pin 2.
void myTimerEvent()
{
Blynk.virtualWrite(V2, millis() / 1000);
}
void setup()
{
Serial.begin(115200);
Blynk.begin(auth, ssid, pass);
irsend.begin();
// Setup a function to be called every second
timer.setInterval(1000L, myTimerEvent);
}
void loop()
{
Blynk.run();
timer.run();
// You can inject your own code or combine it with other sketches.
// Check other examples on how to communicate with Blynk. Remember
// to avoid delay() function!
}
重要なのはこの部分です。
(V10)
というのがバーチャルピンというもので、仮想のピンの値を管理しています。
この関数は (V10)
というバーチャルピンが変化したときに実行されます。
BLYNK_WRITE(V10) // test
{
int value = param.asInt();
if(value){
Serial.println("send[test]");
irsend.sendRaw(test, 85, 38);
}
}
バーチャル品を変化させるのはスマホです。
スマホからボタンを押すことでバーチャル品が 0 -> 1 -> 0
と変化します。
ボタンを押したときだけ動作してほしいので if(value) でボタンを離したときに実行されないようにしています。
あとは Blynk 側の設定です。
Templates
-> Quickstart Template
-> Datastreams
-> Edit
+ New Datastream
-> Virtual Pin
画像のような設定にします。
Automations
-> Type Of Automation を Sensor
にします。
Save And Apply
をクリックしてください。
続いてスマホのボタンレイアウトを設定します。
右上の スパナマーク
を押します。
設計画面になったら右上の + マーク
を押します。
Widget Box が開きます。その中の Button
を押します。
画像のような設定にします。
リモコンの画面に戻り、先程作成した test button
を押してみてください。
スマホで押したボタンにより 10番のバーチャルピンが変化し
BLYNK_WRITE(V10)
が実行され、send[test]
が表示されました。
単純なボタンならバーチャルピンの番号を変えるだけで簡単に実装できます。
Discussion