- 記事公開日
ダイソー「スマートフォンシャッターリモコン」でM5Stackを無線操作(Bluetooth通信)
ダイソーで販売している220円の「スマートフォンシャッターリモコン」
今回は、このBluetooth通信ができるリモコンを使って、M5Stack BASICの無線操作を行ってみました。
操作の流れ
- M5Stack上に「Connecting…」が表示されているときに、リモコンの電源をONにすると、ペアリングが行われます。
- ペアリングに成功すると、M5Stackの画面が「Success!」という表示に切り替わります。
- リモコンのボタンを押すと、その回数がM5Stack上に表示されます。
Arduino IDEの設定
今回使用した開発環境・マイコンは以下の通りです↓
- Arduino IDE 2.3.2
- M5Stack BASIC v2.6
ボードのインストール
Arduino IDEを起動後、上部メニューから、[ファイル]ー[基本設定]を選択します。
[追加のボードマネージャのURL]に以下のURL↓を貼り付けて、[OK」をクリックします。
https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/arduino/package_m5stack_index.json
これで、M5Stack関連のボードがArduino IDEにインストールされます。
ボードの設定
上部メニューから、[ツール]ー[ボード]を選択します。
今回は「M5Stack BASIC」を使用しますが、選択肢に「BASIC」がないので、[M5Stack]ー[M5Fire]を選択します。
ライブラリのインストール
上部メニューから、[スケッチ]ー[ライブラリをインクルード]ー[ライブラリを管理]を開きます。
画面左に表示されたフォームに「NimBLEDevice」を入力し、「NimBLE-Arduino by h2zero」をインストールします。
プログラム
#include <M5Stack.h>
#include "NimBLEDevice.h"
// Bluetooth Low Energy (BLE)で使用するサービスのUUIDを設定
NimBLEUUID serviceUUID("1812");
// BLEのスキャンオブジェクトとデバイスオブジェクトを定義
NimBLEScan* pBLEScan;
BLEAdvertisedDevice* myDevice;
// 接続状態を示すフラグを定義
boolean connected = false;
// ボタン押下回数を記録する変数を定義
int buttonPressCount = 0;
// BLEの通知を受け取るためのコールバック関数を定義
static void notifyCallback(NimBLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) {
// 受信した通知の特徴のUUIDとハンドルをシリアルモニターに出力
Serial.print("Notify callback for characteristic ");
Serial.print(pBLERemoteCharacteristic->getUUID().toString().c_str());
Serial.print("(");
Serial.print(pBLERemoteCharacteristic->getHandle());
Serial.print(") of data length ");
// 受信したデータの長さを出力
Serial.print(length);
Serial.print(" data: ");
// 受信データの内容を16進数形式で出力
for (int i = 0; i < length; i++) {
Serial.printf("%02X ", pData[i]);
// データが'02'の場合、ボタンが押されたとみなしてカウントアップ
if(pData[i] == 02) {
// ボタン押下回数をカウントアップ
buttonPressCount++;
// M5StackのLCDにボタン押下回数を表示
M5.Lcd.setCursor(10, 20); // カーソルを(10, 20)に設定
M5.Lcd.printf("Button pressed: %d", buttonPressCount); // ボタン押下回数を表示
// 表示を300ミリ秒遅延
delay(300);
}
}
// 行末に改行を挿入してデータ表示の完了を示す
Serial.println();
}
// BLEクライアント接続時のコールバッククラスを定義
class MyClientCallback : public NimBLEClientCallbacks {
// クライアントが接続したときに呼ばれる関数
void onConnect(NimBLEClient* pclient) {
}
// クライアントが切断したときに呼ばれる関数
void onDisconnect(NimBLEClient* pclient) {
// 接続状態をfalseに設定し、切断をシリアルに出力
connected = false;
Serial.println("onDisconnect");
}
};
// BLEでアドバタイズされているデバイスを処理するクラスを定義
class MyAdvertisedDeviceCallbacks : public NimBLEAdvertisedDeviceCallbacks {
// BLEデバイスを発見したときに呼ばれる関数
void onResult(NimBLEAdvertisedDevice* advertisedDevice) {
// アドバタイズされたデバイス情報をシリアルモニターに出力
Serial.printf("Advertised Device: %s \n", advertisedDevice->toString().c_str());
// サービスUUIDを持つかつ該当するサービスをアドバタイズしている場合、スキャンを停止してデバイスを保存
if (advertisedDevice->haveServiceUUID() && advertisedDevice->isAdvertisingService(serviceUUID)) {
NimBLEDevice::getScan()->stop();
myDevice = advertisedDevice;
}
}
};
// 初期設定関数
void setup() {
// M5Stackと電源の初期化
M5.begin();
M5.Power.begin();
// シリアル通信の初期化と待機
Serial.begin(115200);
delay(1000);
Serial.println("Scanning...");
// BLEデバイスのスキャン設定
NimBLEDevice::setScanFilterMode(CONFIG_BTDM_SCAN_DUPL_TYPE_DEVICE);
NimBLEDevice::setScanDuplicateCacheSize(200);
NimBLEDevice::init("");
// スキャンオブジェクトの取得と設定
pBLEScan = NimBLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks(), false);
pBLEScan->setActiveScan(true);
pBLEScan->setInterval(97);
pBLEScan->setWindow(37);
pBLEScan->setMaxResults(0);
// スキャンの開始
pBLEScan->start(0, nullptr, false);
}
// メインループ
void loop() {
// デバイスが見つかり、接続がまだされていない場合に接続を試みる
if (myDevice != NULL && connected == false) {
// BLEクライアントの作成とコールバックの設定
BLEClient* pClient = BLEDevice::createClient();
pClient->setClientCallbacks(new MyClientCallback());
// デバイスへの接続を試みる
pClient->connect(myDevice);
// 指定したサービスの取得
BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
// サービスが見つからなければ切断して戻る
if (pRemoteService == nullptr) {
pClient->disconnect();
return;
}
// サービスに含まれる全てのCharacteristicを取得
Serial.println("characteristic list");
std::vector<NimBLERemoteCharacteristic*>* vectorCharacteristics = pRemoteService->getCharacteristics(true);
// 取得したCharacteristicが通知可能であれば、通知を受け取る設定を行う
for (int i = 0; i < vectorCharacteristics->size(); i++) {
if (vectorCharacteristics->at(i)->canNotify()) {
Serial.print(vectorCharacteristics->at(i)->registerForNotify(notifyCallback));
}
}
// 接続フラグをtrueに設定
connected = true;
// 接続成功メッセージをM5StackのLCDに表示
M5.Lcd.setCursor(10, 10);
M5.Lcd.print("Success! ");
M5.Lcd.setCursor(10, 20); // カーソルを(10, 20)に設定
M5.Lcd.printf("Button pressed: 0"); // ボタン押下回数を表示
}
// 接続されていない場合は、M5StackのLCDに接続待ちのメッセージを表示
if(!connected) {
M5.Lcd.fillScreen(BLACK); // 画面を黒で塗りつぶし
M5.Lcd.setCursor(10, 10);
M5.Lcd.print("Connecting...");
}
// 1秒ごとにループ
delay(1000);
}
プログラムは下記の記事を参考にさせていただきました↓
ダイソーの新型Bluetoothシャッター | Lang-ship
プログラムが正常に書き込まれた後、シリアルモニタを表示させると、Bluetooth通信可能なデバイス一覧やボタンを押したときのキーが表示されます。
文字化けしているときは、通信速度を115200bpsに変更してください。
なお、リモコンには大きなボタンと小さなボタンがありますが、どちらを押しても同じキーが送信されています。
使い分けはできませんので、実質、ボタン1つのリモコンです。