LoginSignup
1
0

ESP32のBLEテキスト通信モジュールを考えてみた

Last updated at Posted at 2022-03-02

数年前より使いはじめた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機を選んで通信を行う流れになります。

esp32BLE.ino
#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などの通信を行った際にソースを小変更しました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0