数年前より使いはじめたArduinoManagerはESP32のBLE通信を用いて
iOS機からESP32の情報などを閲覧・設定等可能な良いアプリでした。
でした・・・ 過去形です・・・
しかし先日のArduinoManagerソフトウェアアップデートで私の作った
ソフトはことごとく動かなくなりました。
そこで新規一転でPythonista3とこのESP32BLEテキスト通信ソフトで
2023年4月まで乗り切ってきました。 良いアプリでした。
でした・・・ 過去形です・・・
またも2023年4月末のPythonista3のアップデートで私の作ったソフトは
動かなくなりました。
私のプログラム達の冥福を~~~
今回修復したところで再びのソフトウェアアップデートで自作ソフトが
動かなくなるのは無駄なのでArduinoManagerを使うのを諦める事にしました。
なら以前の様に1台1台SSIDとPASSWORD埋め込みコンパイルを使う?
なんて事は考えられないので、BLEテキスト通信モジュールを自作することにしました。
以前からiOS機のPythonista3でソフト開発したいなと思っていたので良い機会です。
Pythonista3のBLE通信ソフトが死んでしまった際にBLE通信部をUDP通信に置き換えて
ソフトを作ったのですが、通信部と処理部で完全分離させると楽に移行できますね。
2023年にSwift PlaygroundでBLE通信をする
#実行に必要なリソース
ESP32とArduinoIDE開発環境
iOS機とSwift Playground開発環境(多分更新すると思います
#機能
ESP32側はSerial通信と同じような使い方がしたいので、私がよく使う
Serial通信のメソッドだけサポートしてみました。
begin
connected
available
read
SendChars
==あまり厳密なテストは行っていませんので、意図しない制約があると思います==
#使い方
私が作ったPythonista3コードと組み合わせて送受信を行えます。
iOS機から通信したいESP32機を選んで通信を行う流れになります。
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>
// BLEサーバーとConnectしているか
class BLE_MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) { Connected = ConnectOnce = true; advertisingStop(); }
void onDisconnect(BLEServer* pServer) { Connected = ConnectOnce = false; advertisingStart(); }
public:;
BLEAdvertising* pAdvertising;
bool Connected, ConnectOnce;
BLE_MyServerCallbacks(){ Connected = false; }
void advertisingSet( const char *SERVICE_UUID ){
pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->setScanResponse(true);
pAdvertising->setMinPreferred(0x06);
pAdvertising->setMinPreferred(0x12);
}
void advertisingStart(){ pAdvertising->start(); }
void advertisingStop(){ pAdvertising->stop(); }
};
// BLEサーバーからの受信バッファ制御
#define BLE_BUFFER_SIZE 255
class BLE_MyCharacteristicCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic* pCharacteristic) {
std::string value = pCharacteristic->getValue();
if( value.length() == 0 ) return;
receivedOne = true;
for( int i=0 ; i<value.length() ; i++ ){
area[ writePos ] = (byte)value[i];
writePos = ( writePos==(BLE_BUFFER_SIZE-1) ? 0 : writePos+1 );
}
}
public:;
byte area[ BLE_BUFFER_SIZE ];
int writePos, readPos;
bool receivedOne;
BLE_MyCharacteristicCallbacks(){
writePos = readPos = 0;
receivedOne = false;
}
};
class ESP32_BLE_COM
{
private:
const char *BLE_SERVER_NAME;
String SERVICE_UUID;
String CHAR_UUID;
BLECharacteristic* pCharacteristic;
BLE_MyServerCallbacks *servercallbacks;
BLE_MyCharacteristicCallbacks *Buffer;
BLEService* pService;
public:
ESP32_BLE_COM(){ }
void beign( const char *serverName, char *serviceUUID, char *charUUID ){
BLE_SERVER_NAME = serverName;
SERVICE_UUID = serviceUUID;
CHAR_UUID = charUUID;
BLEDevice::init( BLE_SERVER_NAME );
BLEServer* pServer = BLEDevice::createServer();
servercallbacks = new BLE_MyServerCallbacks();
pServer->setCallbacks( servercallbacks );
pService = pServer->createService(SERVICE_UUID.c_str());
pCharacteristic = pService->createCharacteristic(
CHAR_UUID.c_str(),
BLECharacteristic::PROPERTY_READ |
BLECharacteristic::PROPERTY_WRITE |
BLECharacteristic::PROPERTY_NOTIFY |
BLECharacteristic::PROPERTY_INDICATE
);
Buffer = new BLE_MyCharacteristicCallbacks();
pCharacteristic->setCallbacks( Buffer );
pCharacteristic->addDescriptor(new BLE2902());
pService->start();
servercallbacks->advertisingSet(SERVICE_UUID.c_str());
servercallbacks->advertisingStart();
}
void deinit( bool releasememory ){
if( BLE_SERVER_NAME==NULL ) return;
BLEDevice::deinit( releasememory );
BLE_SERVER_NAME = NULL;
}
// データが送信可能になて始めてコネクテッドになります
bool connected(){ if( !servercallbacks->Connected ) return false;
//if( !Buffer->receivedOne ) return false;
return true;
}
// 接続後1回の確認のみtrueを返します
bool connectOnce(){ if( !connected() ) return false;
if( !servercallbacks->ConnectOnce ) return false;
Serial.printf("BLE connect\n");
servercallbacks->ConnectOnce = false; return true;
}
bool available(){ if(Buffer->readPos==Buffer->writePos) return false; else return true; }
int read(){
if( !available() ) return -1;
byte ret = Buffer->area[Buffer->readPos];
Buffer->readPos = ( Buffer->readPos==(BLE_BUFFER_SIZE-1) ? 0 : Buffer->readPos+1 );
return (int)ret;
}
// BLEサーバーへの送信 (複数byte)
void SendChars( char *c, int len ){
pCharacteristic->setValue( (uint8_t *)c, len ); // 実はテキスト数値を送っています
pCharacteristic->notify();
}
/*
void SendChars( char *c, int len ){ for( int i=0 ; i<len ; i++ ) SendChar( c[i] ); }
// BLEサーバーへの送信 (1byte)
void SendChar( char b ){
pCharacteristic->setValue( String((byte)b).c_str() ); // 実はテキスト数値を送っています
pCharacteristic->notify();
}
*/
//
void start(){ pService->start(); Serial.printf("BLE service start\n"); }
void stop(){ pService->stop(); Serial.printf("BLE service stop\n"); }
};
int count;
byte BUFFER[128];
int BUFFER_POS = 0;
ESP32_BLE_COM BLE;
void setup(){
Serial.begin(115200);
BLE.beign( "ESP32_BLE_SERVER", "FFAA", "0001" );
}
void loop() {
if( !BLE.connected() ) return;
if( BLE.available() ){
int num = BLE.read();
BUFFER[BUFFER_POS] = num;
BUFFER_POS++;
if( num==0 ){
Serial.println( String( (char*)BUFFER ) );
BUFFER_POS = 0;
char str[30];
sprintf( str, "ESP32 Message:%d", count );
Serial.println( str );
BLE.SendChars( str, strlen(str)+1 );
count ++;
}
return;
}
}
あとがき
以前はESP32にWebServerを実装して設定変更等を行っていたのですが
スマホから接続可能なESP32機を調べる方法に悩んでいました。
調べてみるとWebに記事が無いもんですね(汗) びっくりです。
なので今後誰かがマトモなBLEのシリアルライブラリを作ってくれると
良いなぁと考えつつ、シリアル通信のメソッドを模倣して作りました。
2024年になってPython BLEAKとESP32C3などの通信を行った際にソースを小変更しました。