2022/05/31 08:58
大バグを修正して再掲しました。
DaisoBleButton.hpp
#ifndef _DAISO_BLE_BUTTON_HPP_
#define _DAISO_BLE_BUTTON_HPP_
#include <NimBLEDevice.h>
#include <nvs.h>
#include <functional>
#include <map>
static const char * nvs_name = "DaisoBleButton";
static const char * allow_devices [] = {"AB Shutter3"};
static const NimBLEUUID uuid_service((uint16_t)0x1812);
static const NimBLEUUID uuid_characteristic((uint16_t)0x2a4d);
class DaisoBleButton {
public:
static int begin() {
NimBLEDevice::init("");
uint8_t devCount = 0;
uint32_t nvs_handle;
if(!nvs_open(nvs_name, NVS_READONLY, &nvs_handle)) {
for(;;devCount++) {
char key[3];
sprintf(key, "%02u", devCount);
uint64_t address;
if(nvs_get_u64(nvs_handle, key, &address))
break;
auto pClient = NimBLEDevice::createClient(NimBLEAddress(address));
if(pClient) {
pClient->setConnectTimeout(1);
buttons[pClient] = new DaisoBleButton(devCount, pClient);
}
}
}
nvs_close(nvs_handle);
return devCount;
}
static int paring(const int period = 10) {
auto pClients = NimBLEDevice::getClientList();
for(auto pClient : *pClients)
pClient->disconnect();
auto pBLEScan = NimBLEDevice::getScan();
pBLEScan->setActiveScan(true);
Serial.println("paring mode. wait 10 secs..");
auto pScanResults = pBLEScan->start(period);
int devCount = 0;
uint32_t nvs_handle;
if(!nvs_open(nvs_name, NVS_READWRITE, &nvs_handle)) {
for (int i = 0; i < pScanResults.getCount(); i++) {
auto advertisedDevice = pScanResults.getDevice(i);
Serial.print("Found Device ");
Serial.println(advertisedDevice.getName().c_str());
for(auto allow : allow_devices) {
if (!strncmp(advertisedDevice.getName().c_str(), allow, strlen(allow)) && advertisedDevice.haveServiceUUID()) {
auto pClient = NimBLEDevice::createClient(advertisedDevice.getAddress());
if(pClient && pClient->connect()) {
if(!devCount)
nvs_erase_all(nvs_handle);
uint64_t address = advertisedDevice.getAddress();
char key[3];
sprintf(key, "%02d", devCount);
nvs_set_u64(nvs_handle, key, address);
Serial.printf("added to list[%d]: %llu %s", devCount, address, advertisedDevice.getAddress().toString().c_str());
Serial.println();
devCount ++;
pClient->disconnect();
break;
}
}
}
}
}
nvs_close(nvs_handle);
return devCount;
}
static void handle() {
auto pClients = NimBLEDevice::getClientList();
for (auto pClient : *pClients) {
if(pClient && !pClient->isConnected() && pClient->connect()) {
pClient->getServices(true);
auto pService = pClient->getService(uuid_service);
auto pCharacteristics = pService->getCharacteristics(true);
for (auto pCharacteristic : *pCharacteristics) {
if(uuid_characteristic.equals(pCharacteristic->getUUID())) {
pCharacteristic->subscribe(false,
[](BLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) {
buttons[pRemoteCharacteristic->getRemoteService()->getClient()]->subscribe(pRemoteCharacteristic, pData, length, isNotify);
}
);
}
}
}
}
}
static std::function<void(DaisoBleButton *)> onClick_A;
static std::function<void(DaisoBleButton *)> onClick_B;
private:
static std::map<NimBLEClient *, DaisoBleButton *> buttons;
public:
uint8_t getId() {return id;}
NimBLEAddress getAddress() {return bleClient->getPeerAddress();}
private:
DaisoBleButton(uint8_t _id, NimBLEClient * _bleClient) : id(_id), bleClient(_bleClient) {;}
void subscribe(BLERemoteCharacteristic* pRemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) {
if(length == 2 && (pData[0] || pData[1])) {
if(pData[0] == 0x01 && pData[1] == 0x00) {
if(last_value[0] == 0x00 && last_value[1] == 0x28) {
if(onClick_B)
onClick_B(this);
}
else {
if(onClick_A)
onClick_A(this);
}
}
last_value[0] = pData[0];
last_value[1] = pData[1];
}
}
private:
NimBLEClient * bleClient;
uint8_t last_value[2] = {0x00, 0x00};
uint8_t id;
};
std::function<void(DaisoBleButton *)> DaisoBleButton :: onClick_A = nullptr;
std::function<void(DaisoBleButton *)> DaisoBleButton :: onClick_B = nullptr;
std::map<NimBLEClient *, DaisoBleButton *> DaisoBleButton :: buttons;
#endif
使用例
#include "DaisoBleButton.hpp"
void setup() {
Serial.begin(115200);
pinMode(0, INPUT_PULLUP);
DaisoBleButton::onClick_A = [] (DaisoBleButton * button) {
Serial.println("button A");
};
DaisoBleButton::onClick_B = [] (DaisoBleButton * button) {
Serial.println("button B");
};
if(!DaisoBleButton::begin()) {
DaisoBleButton::paring();
ESP.restart();
}
}
void loop() {
DaisoBleButton::handle();
if(digitalRead(0) == LOW && DaisoBleButton::paring() > 0)
ESP.restart();
delay(1);
}
ペアリングモード(デフォルト10秒間)の間に接続された ダイソーモバイルシャッター の情報を NVS に記録し、次回からはその接続のみを受け付けます。
GPIO0 を押すと改めてペアリングモードに入り、ペアを登録し直すことが出来ます。
ESP32-DevBoard 以外の、例えば M5Stack 等では GPIO0 ではなく備わってる物理スイッチに変更するといいでしょう。