M5Stackを使ったBLE通信のテストをしてみました。
以前、ESP8266というWiFiモジュールについてテストしたことがありますが、Arduinoを使った開発ができることがとても便利に感じました。
M5StackはESP32というWiFiだけでなく、Bluetoothも対応し、それにユーザインターフェイス、バッテリ駆動・・・もうこれだけで、かなり使用用途が広がることがわかります。スタックということでモジュールを積み重なることで機能を追加できます。
通信相手は、M5Stickというもっと小型化したデバイスを使います。
BLE通信については、このブログで何度か取り上げましたが、以下が最初になります。
もう一度思い出しながらテストをしているのですが、いつも混乱してしまうのは、マスタ/スレーブの関係だったので、それぞれの役割をまとめてみました。
[マスタ]
セントラル(Central)
スキャン
接続要求・切断
クライアント
[スレーブ]
ペリフェラル(Peripheral)
ペリフェラルはサービス(Service)とキャラクタリスティック(Characteristic)で定義
アドバタイズ(待ち受け)
接続要求を受けるとアドバタイズ終了・接続確率
接続切断を受けると再度アドバタイズ
どうしても慣れ親しんだWebサーバなどのクライアント/サーバの考え方でいうと、サーバが複数のクライアントを待ち受けするという構図と思ってしまうのですが、BLE では一つのクライアントが複数のサーバにリクエストするという構図になります。
ここではセントラルがM5Stick、ペリフェラルがM5Stackとしてテストします。
〇セントラル
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
#include <M5StickC.h> #include "BLEDevice.h" #define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" #define SERVER_NAME "M5Stack" static BLEUUID serviceUUID(SERVICE_UUID); static BLEUUID charUUID(CHARACTERISTIC_UUID); static BLEAddress *pServerAddress; static boolean doConnect = false; static boolean connected = false; static BLERemoteCharacteristic* pRemoteCharacteristic; static void notifyCallback( BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) { ; } bool connectToServer(BLEAddress pAddress) { BLEClient* pClient = BLEDevice::createClient(); pClient->connect(pAddress); BLERemoteService* pRemoteService = pClient->getService(serviceUUID); if (pRemoteService == nullptr) { return false; } pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID); if (pRemoteCharacteristic == nullptr) { return false; } pRemoteCharacteristic->registerForNotify(notifyCallback); } class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks { void onResult(BLEAdvertisedDevice advertisedDevice) { if(advertisedDevice.getName()==SERVER_NAME){ // advertisedDevice.getScan()->stop(); pServerAddress = new BLEAddress(advertisedDevice.getAddress()); doConnect = true; } } }; void setup() { M5.begin(); M5.Lcd.setRotation(3); M5.MPU6886.Init(); M5.Lcd.println("Start!"); BLEDevice::init(""); BLEScan* pBLEScan = BLEDevice::getScan(); pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks()); pBLEScan->setActiveScan(true); pBLEScan->start(10); } void loop() { M5.update(); if(M5.BtnB.isPressed()){ pRemoteCharacteristic->writeValue("Btn B!"); } if (doConnect == true) { if (connectToServer(*pServerAddress)) { M5.Lcd.println("connected!"); connected = true; } else { connected = false; } doConnect = false; } if (connected) { std::string value = pRemoteCharacteristic->readValue(); String strVal=value.c_str(); M5.Lcd.println(strVal); } else{ doConnect = true; } delay(2000); } |
参考) /http://keisoku-lab.mond.jp/2018/01/30/esp32%E3%81%AEarduino-ide%E3%81%A7ble%E3%82%92%E8%A9%A6%E3%81%97%E3%81%A6%E3%81%BF%E3%81%BE%E3%81%97%E3%81%9F/
〇ペリフェラル
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
#include <M5Stack.h> #include <BLEDevice.h> #include <BLEUtils.h> #include <BLEServer.h> #include <BLE2902.h> #define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b" #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8" #define SERVER_NAME "M5Stack" BLEServer* pServer = NULL; BLECharacteristic* pCharacteristic = NULL; bool deviceConnected = false; class MyServerCallbacks: public BLEServerCallbacks { void onConnect(BLEServer* pServer) { M5.Lcd.println("connect"); deviceConnected = true; }; void onDisconnect(BLEServer* pServer) { M5.Lcd.println("disconnect"); deviceConnected = false; } }; class MyCallbacks: public BLECharacteristicCallbacks { void onRead(BLECharacteristic *pCharacteristic) { M5.Lcd.println("read"); std::string value = pCharacteristic->getValue(); M5.Lcd.println(value.c_str()); } void onWrite(BLECharacteristic *pCharacteristic) { M5.Lcd.println("write"); } }; void setup() { M5.begin(); M5.setWakeupButton(BUTTON_A_PIN); M5.Lcd.println("Start!"); BLEDevice::init(SERVER_NAME); BLEServer *pServer = BLEDevice::createServer(); pServer->setCallbacks(new MyServerCallbacks()); BLEService *pService = pServer->createService(SERVICE_UUID); pCharacteristic = pService->createCharacteristic( CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_NOTIFY | BLECharacteristic::PROPERTY_INDICATE ); pCharacteristic->setCallbacks(new MyCallbacks()); pCharacteristic->addDescriptor(new BLE2902()); pService->start(); BLEAdvertising *pAdvertising = pServer->getAdvertising(); pAdvertising->start(); } void loop() { if (deviceConnected) { if(M5.BtnB.wasPressed()) { pCharacteristic->setValue("Hello!"); } } M5.update(); } |
参考) https://qiita.com/nsawa/items/2afd4ae9c10af87d0133
テストは、ボタンを押すと文字列を相互に送信することを確認にしました。
実際に動かしてみると、この手軽さがとても魅力です。