63
49

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

M5StackAdvent Calendar 2018

Day 5

M5StackでBLEを使う

Last updated at Posted at 2018-12-04

この記事は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を作成します。

Bleakのインストール

ここでは、BLEモジュールBleakを使います。

pip install bleak

Python Client

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

client.py
#!/usr/bin/env python3
import asyncio
import logging
import uuid

from bleak import BleakScanner, BleakClient

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


async def run(loop):
    print("Searching devices...")
    devices = await BleakScanner.discover()

    device = list(filter(lambda d: d.name == DEVICE_NAME, devices))
    if len(device) == 0:
        raise RuntimeError(f"Failed to find a device name '{DEVICE_NAME}'")

    address = device[0].address
    print(f"Connecting to the device... (address: {address})")
    async with BleakClient(address, loop=loop) as client:
        print("Message from the device...")
        value = await client.read_gatt_char(CHAR_UUID)
        print(value.decode())

        print("Sending message to the device...")
        message = bytearray(b"hi!")
        await client.write_gatt_char(CHAR_UUID, message, True)

        def callback(sender, data):
            print(f"Received: {data}")

        print("Subscribing to characteristic changes...")
        await client.start_notify(CHAR_UUID, callback)

        print("Waiting 60 seconds to receive data from the device...")
        await asyncio.sleep(60)


loop = asyncio.get_event_loop()
loop.run_until_complete(run(loop))

BLEを試す

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

$ python3 client.py
Searching devices...
Connecting to the device... (address: 6B6ABA49-B0CA-4461-994E-A70A88E0E354)
Message from the device...
Hello World!
Sending message to the 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の基本的な要素についてまとまっていておすすめです。

BLE Clientについて

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

63
49
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
63
49

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?