Help us understand the problem. What is going on with this article?

M5StackでBLEを使う

この記事はM5Stack Advent Calendar 2018の5日目の記事です。

概要

M5StackからBluetooth Low Energy(BLE)を使うサンプルを作ったのでその紹介です。

ソースコードはこちらから。

M5Stackの準備

M5Stackにソースコードを書き込む

M5Stackに次のBLEのソースコードを書き込みます。

m5stack-ble.ino
#include <M5Stack.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

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");
    pCharacteristic->setValue("Hello World!");
  }

  void onWrite(BLECharacteristic *pCharacteristic) {
    M5.Lcd.println("write");
    std::string value = pCharacteristic->getValue();
    M5.Lcd.println(value.c_str());
  }
};

void setup() {
  Serial.begin(115200);
  M5.begin();
  M5.setWakeupButton(BUTTON_A_PIN);
  M5.Lcd.println("BLE start.");
  m5.Speaker.mute();

  BLEDevice::init("m5-stack");
  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(M5.BtnA.wasPressed()) {
    M5.powerOFF();
  }
  if (deviceConnected) {
    if(M5.BtnB.wasPressed()) {
      M5.Lcd.println("Button B pressed!");
      pCharacteristic->setValue("Button B pressed!");
      pCharacteristic->notify();
    }
  }
  M5.update();
}

Clientの準備

次に、BLE Clientを準備します。

今回は、Pythonを使ったBLE Clientを作成します。

Python Client

次のコードを保存して、BLE Clientを作成します。

client.py
import time
import uuid
import Adafruit_BluefruitLE

SERVICE_UUID = uuid.UUID('4fafc201-1fb5-459e-8fcc-c5c9c331914b')
CHAR_UUID    = uuid.UUID('beb5483e-36e1-4688-b7f5-ea07361b26a8')

ble = Adafruit_BluefruitLE.get_provider()

def main():
    ble.clear_cached_data()

    adapter = ble.get_default_adapter()
    adapter.power_on()
    print('Using adapter: {0}'.format(adapter.name))

    print('Disconnecting any connected devices...')
    ble.disconnect_devices([SERVICE_UUID])

    # Scan devices.
    print('Searching device...')
    try:
        adapter.start_scan()

        device = ble.find_device(name="m5-stack")
        if device is None:
            raise RuntimeError('Failed to find device!')
    finally:
        # Make sure scanning is stopped before exiting.
        adapter.stop_scan()

    print('Connecting to device...')
    device.connect()  # Will time out after 60 seconds, specify timeout_sec parameter
                      # to change the timeout.

    # Once connected do everything else in a try/finally to make sure the device
    # is disconnected when done.
    try:
        print('Discovering services...')
        device.discover([SERVICE_UUID], [CHAR_UUID])

        # Find the service and its characteristics.
        uart = device.find_service(SERVICE_UUID)
        chara = uart.find_characteristic(CHAR_UUID)

        print('Message from device...')
        v = chara.read_value()
        print(v)

        # Write a string to the characteristic.
        print('Sending message to device...')
        chara.write_value(b'hi!')

        def received(data):
            print('Received: {0}'.format(data))

        # Turn on notification of characteristics using the callback above.
        print('Subscribing to characteristic changes...')
        chara.start_notify(received)

        # Now just wait for 30 seconds to receive data.
        print('Waiting 60 seconds to receive data from the device...')
        time.sleep(60)
    finally:
        # Make sure device is disconnected on exit.
        device.disconnect()


# Initialize the BLE system.  MUST be called before other BLE calls!
ble.initialize()

# Start the mainloop to process BLE events, and run the provided function in
# a background thread.  When the provided main function stops running, returns
# an integer status code, or throws an error the program will exit.
ble.run_mainloop_with(main)

BLEを試す

Clientを起動します。 client.py を実行します。

$ python client.py
Using adapter: Default Adapter
Disconnecting any connected devices...
Searching device...
Connecting to device...
Discovering services...
Message from device...
b'Hello World!'
Sending message to device...
Subscribing to characteristic changes...
Waiting 60 seconds to receive data from the device...
Received: b'Button B pressed!'
Received: b'Button B pressed!'
Received: b'Button B pressed!'

コネクションが確立できたら、M5StackのBボタンを押します。

Received: b'Button B pressed!' が表示されれば、正常に動作しています。

まとめ

この記事ではM5Stackを使ったBLE通信について紹介しました。

M5StackはESP32を使っているので、BLEを手軽に使えるのが良いですね。

参考

BLEについて

BLEの技術的な内容については、こちらのページがとても参考になりました。

AdvertisingやServices, Characteristicsなど、BLEの基本的な要素についてまとまっていておすすめです。

https://learn.adafruit.com/introduction-to-bluetooth-low-energy

BLE Clientについて

今回の記事ではPythonを使ったBLE Clientの紹介をしましたが、
Web Bluetooth APIを使ったサンプルや、Node.jsを使ったサンプルも作りました。よければ使ってみてください。

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away