#目次
・はじめに
・Windows10(フォームアプリケーション_.NET Framework_C#)の作成
・BLEデバイス(ESP32_Arduino)の作成
・通信する
#はじめに
WindowsでBLE(BluetoothLowEnergy)通信ができないかC#のフォームアプリを作ってみる。
Windows10側はC#を使う。フォームアプリをVisualStudio2019で作成する。
BLEデバイスはESP32とArduinoで作成する。
双方向で数値を送受信する。Bluetoothは簡単そうだが、BLEではどうなるか。
Windowsについては、フォームアプリのほかに適切なものがいろいろある(UWPというらしい…)のだが、これ以外詳しくないのでこれでやる。
・【Notify】でのBLEデバイスからの不定期受信
・【Write】でのBLEデバイスへの書き込み
ができた。実際の結果はこちら
WindowsとESP32の間で無線通信。BluetoothLowEnergy(BLE)による送受信をする。
— いっちー (@get_itchy_feet) April 5, 2020
Windows10(フォームアプリケーション)からESP32に対し、受信【Notify】と書込み【Write】ができるようになったぞ。
またQiitaにでも書こう。 pic.twitter.com/16DX25msf6
#Windows10(フォームアプリケーション_.NET Framework_C#)の作成
まずは【Microsoft Visual Studio Community 2019】から新しいプロジェクト【Windowsフォームアプリケーション .NET Framework】を作成する。使用する言語は【C#】となる。
BLEを扱えるようにするために【Microsoft.Windows.SDK.Contracts】というアドオンが必要みたいだ。下記のサイトを参考に入れてみる。
https://tomosoft.jp/design/?p=41123
画面も簡単に作る。ラベル二つにボタンが一つ、それにタイマー。それぞれ以下の通り。
・ラベル:labelNotifyData 【Notify】による受信した数値を表示。数は二つ。
・ラベル:labelWriteData 書き込みを行う数値を表示。
・ボタン:buttonWrite ボタンをクリックすると【Write】による書き込みを行う。
・タイマー:timer1 ラベルの文字の更新に使用する。intervalが100ms、enabledをtrueに。
BLEでデバイスから送られる数値は二つ。1秒ごと送信され、一つ目は1つずつ値が増えていく、二つ目は【Write】により書き込んだ数値がそのまま返ってくる。これを【Notify】で受信する。
BLEデバイス書き込みはボタンのクリックで行う。クリックすると【Write】で書き込みを行う。数値はボタンクリックごとに一つづつふえる。
また、タイマーを用い100msごとにラベルの文字を更新する。
コードの書き方もいろんなところを参考にコピペして作り上げた。主に参考にしたのは以下のサイト
https://qiita.com/Dr10_TakeHiro/items/7446d68cbffeae7c7184
https://qiita.com/gebo/items/41da7474936845d77d06
起動と同時にスキャンを行い、目的のBLEデバイスと接続する。
相手側のBLEデバイスのUUIDは以下の通り
・BLEデバイスのサービスUUID "00002220-0000-1000-8000-00805F9B34FB"
・【Write】のキャラクタリスティックUUID "00002222-0000-1000-8000-00805F9B34FB"
・【Notify】のキャラクタリスティックUUID "00002221-0000-1000-8000-00805F9B34FB"
以下のようにコードを書いてみる。Tryとかはよくわからんから省略する。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Windows.Devices.Bluetooth;
using Windows.Devices.Bluetooth.Advertisement;
using Windows.Devices.Bluetooth.GenericAttributeProfile;
using System.Runtime.InteropServices.WindowsRuntime; //Asbuffer
namespace FormsAppBleQiitaTest
{
public partial class Form1 : Form
{
static BluetoothLEAdvertisementWatcher watcher;
public Form1()
{
InitializeComponent();
StartBle(); //起動と同時にBleデバイスとの接続を試みる。
}
static public string textLog;
static public string textWriteData;
//ラベルの文字をタイマーで更新する
private void timer1_Tick(object sender, EventArgs e)
{
labelNotifyData.Text = textLog;
labelWriteData.Text = textWriteData;
}
//スキャン他 起動時に呼び出し
public static async void StartBle()
{
watcher = new BluetoothLEAdvertisementWatcher();
watcher.Received += Watcher_Received;
watcher.ScanningMode = BluetoothLEScanningMode.Active;
watcher.Start();
textWriteData = "Write : 0";
}
static bool isBleFind = false;
static bool isBleNotify = false;
static bool isBleWrite = false;
public static async void Watcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
{
var bleServiceUUIDs = args.Advertisement.ServiceUuids;
textLog = "MAC:" + args.BluetoothAddress.ToString();
foreach (var uuidone in bleServiceUUIDs)
{
textLog = uuidone.ToString();
if (uuidone.ToString() == "00002220-0000-1000-8000-00805f9b34fb") //目的のサービスUUIDを探す
{
textLog = "Find";
isBleFind = true;
}
if (isBleFind == true)
{
watcher.Stop(); //目的のサービスUUIDをみつけたらスキャン終了
textLog = "Stop";
BluetoothLEDevice dev = await BluetoothLEDevice.FromBluetoothAddressAsync(args.BluetoothAddress);
GattDeviceService service = dev.GetGattService(new Guid("00002220-0000-1000-8000-00805f9b34fb"));
var characteristicsRx = service.GetCharacteristics(new Guid("00002221-0000-1000-8000-00805f9b34fb"));
CHARACTERISTIC_UUID_RX = characteristicsRx.First();
if (CHARACTERISTIC_UUID_RX.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Notify))
{
CHARACTERISTIC_UUID_RX.ValueChanged += characteristicBleDevice;
await CHARACTERISTIC_UUID_RX.WriteClientCharacteristicConfigurationDescriptorAsync(GattClientCharacteristicConfigurationDescriptorValue.Notify);
isBleNotify = true;
}
var characteristicsTx = service.GetCharacteristics(new Guid("00002222-0000-1000-8000-00805f9b34fb"));
CHARACTERISTIC_UUID_TX = characteristicsTx.First();
if (CHARACTERISTIC_UUID_TX.CharacteristicProperties.HasFlag(GattCharacteristicProperties.Write))
{
isBleWrite = true;
}
break;
}
}
}
public static byte[] RxData;
public static GattCharacteristic CHARACTERISTIC_UUID_RX;
public static GattCharacteristic CHARACTERISTIC_UUID_TX;
//Notifyによる受信時の処理
public static void characteristicBleDevice(GattCharacteristic sender, GattValueChangedEventArgs eventArgs)
{
byte[] data = new byte[eventArgs.CharacteristicValue.Length];
Windows.Storage.Streams.DataReader.FromBuffer(eventArgs.CharacteristicValue).ReadBytes(data);
RxData = data;
textLog = "Notfy : " + RxData[0].ToString() + "," + RxData[1].ToString();
return;
}
//終了時の処理
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (isBleFind == true) CHARACTERISTIC_UUID_RX.Service.Dispose();
}
//ボタンがクリックされたときの処理
byte[] TXdata = { 0 };
private void buttonWrite_Click(object sender, EventArgs e)
{
if (isBleWrite == true)
{
var result = CHARACTERISTIC_UUID_TX.WriteValueAsync(TXdata.AsBuffer());
if (TXdata[0] < 100) TXdata[0]++;
else TXdata[0] = 0;
textWriteData = "Write : " + TXdata[0].ToString();
}
}
}
}
#BLEデバイス(ESP32)の作成
BLEデバイス側を用意する。
ESP32はマルツパーツで【SP32-WROOM-32搭載開発ボード】を購入する。
https://www.marutsu.co.jp/pc/i/1525354/
準備や使い方はいろいろネットに載っている。
以下のようなコードを書き込む。サンプルコードを少しいじった程度だが。
コードの内容は、
・1秒ごとにNotifyで送信する。送信する数値は二つ。
・数値のうち最初の一つは1秒ごとに一つづつ増えていく(1 → 2 → 3 ・・・)。
・もう一つはPCからWriteで受信した数値をそのまま返す。
・設定するUUIDはWindows側のコードの説明を参照
・デバイス名は「BleDevice」
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
BLEServer* pServer = NULL;
BLECharacteristic* pCharacteristic = NULL;
bool deviceConnected = false;
bool oldDeviceConnected = false;
int bleRX,bleTX;
uint8_t notifySend[2] = {0,0};
#define SERVICE_UUID "00002220-0000-1000-8000-00805F9B34FB"
#define CHARACTERISTIC_UUID_RX "00002222-0000-1000-8000-00805F9B34FB"
#define CHARACTERISTIC_UUID_TX "00002221-0000-1000-8000-00805F9B34FB"
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
}
};
class MyCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0) {
Serial.println("*********");
Serial.print("Received Value: ");
for (int i = 0; i < rxValue.length(); i++)
Serial.print(rxValue[i]);
Serial.println();
Serial.println("rxValue[0]");
bleRX = rxValue[0];
}
}
};
void setup() {
Serial.begin(115200);
// Create the BLE Device
BLEDevice::init("BleDevice");
// Create the BLE Server
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create a BLE Characteristic
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY
);
pCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
pCharacteristic->setCallbacks(new MyCallbacks());
// Start the service
pService->start();
// Start advertising
BLEAdvertising *pAdvertising = pServer->getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pServer->getAdvertising()->start();
Serial.println("Waiting a client connection to notify");
}
void loop() {
// notify changed value
if (deviceConnected) {
if(bleRX < 100) bleTX++;
else bleTX = 0;
notifySend[0] = bleTX;
notifySend[1] = bleRX;
pCharacteristic->setValue(notifySend, 2);
pCharacteristic->notify();
delay(1000);
// bluetooth stack will go into congestion, if too many packets are sent, in 6 hours test i was able to go as low as 3ms
}
// disconnecting
if (!deviceConnected && oldDeviceConnected) {
delay(500); // give the bluetooth stack the chance to get things ready
pServer->startAdvertising(); // restart advertising
Serial.println("start advertising");
oldDeviceConnected = deviceConnected;
}
// connecting
if (deviceConnected && !oldDeviceConnected) {
// do stuff here on connecting
oldDeviceConnected = deviceConnected;
}
}
#通信する
BLEデバイスの電源を入れ、Windows側でフォームアプリを起動させると送受信を始める。
ただし、Windows側でデバイスのペアリングを済ませておく必要がある。
【設定】→【Bluetoothとその他のデバイス】→【Bluetoothまたはその他のデバイスを追加する】→【Bluetooth】で「BleDevice」を追加する。
なんとかできたようだ。