EnOcean BLE スイッチ Easyfit(EWSDB)を買ってみた②　Windowsフォームアプリを作成する。

#目次
・はじめに
・Windowsフォームアプリ作成結果
・フォームアプリ作成準備
・C#プログラム

#はじめに
　BLE対応のEnOceanスイッチ_Easyfit(EWSDB)を購入した。
　まずは前回にあるように動作確認してみた。
https://qiita.com/get_itchy_feet/items/0e29cda011fce7da7b73
　このデバイスの詳細はスイッチサイエンスさんのホームページにある。
https://www.switch-science.com/catalog/6526/
　今回はこの動画の後半にあるようなスイッチを押したことがわかるアプリの作成を行いたい。
　スマホのアプリは作成できないため、PCアプリで作成を行う。UWPとかもわからんのでフォームアプリである。

#Windowsフォームアプリ作成結果
　実際に作成したアプリは以下の通りである。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">スイッチサイエンスさんでEnOcean BLE スイッチ Easyfit(EWSDB)を買ってみた<a href="https://t.co/1WWYqH44zZ">https://t.co/1WWYqH44zZ</a><br><br>WindowsでBLEを受信できるようにアプリを作成してみたが、感度がすごく悪い。<br>こんなものなのかなあ…。 <a href="https://t.co/NJNbyQgAw1">pic.twitter.com/NJNbyQgAw1</a></p>&mdash; いっちー (@get_itchy_feet) <a href="https://twitter.com/get_itchy_feet/status/1346478015111303168?ref_src=twsrc%5Etfw">January 5, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
　ボタンを押すと4つあるスイッチのうち押したスイッチの場所が青く表示される。
　非常に反応が悪い・・・。データを取得できたり、できなかったりである。
　スマホのBLEスキャナアプリで動作確認していた時にはこんなに反応が悪くなかった。コードの書き方が悪いのか、WINDOWS自体の性能なのか。

#フォームアプリ作成準備
　アドバタイズパケットに含まれているデータから目的のデータ（SwitchStatus）を取り出したい。
　まずはManifacture Dataを取り出す必要がある。
　以下の記事にアドバタイズパケットの中身の詳細があるので参考にした。
　https://qiita.com/gebo/items/2e51bebd3d26a3025d9f
　
　BLEの送受信は以前に以下の記事でやってみている。
　https://qiita.com/get_itchy_feet/items/a61c49fed9c9fe46b5f0
　ただし、今回はScanのみである。
　まずは【Microsoft Visual Studio Community 2019】から新しいプロジェクト【Windowsフォームアプリケーション .NET Framework】を作成する。使用する言語は【C#】となる。
　BLEを扱えるようにするために【Microsoft.Windows.SDK.Contracts】アドオンをいれる。
　
　以下のようにフォームアプリをデザインする。
　テキストボックスにデバイスアドレス（スイッチの裏面に記載のあるID）を記入
　→【Scan Start】ボタンをおすと、Scanを開始し、スイッチからのデータが受信できるようになる。
　→スイッチを押すと押された場所に該当するPicture Boxの色が灰色から青に変わる。スイッチを離すと灰色に戻る。
<img width=70% src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184089/6a8d6b14-0947-ef5f-b433-4e4f42afcd13.png>
#C#プログラム
　実際のFormのプログラムは以下の通りである。

```C#:WindowsFormsAppEnOceanSwitchBle.cs
using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using Windows.Devices.Bluetooth.Advertisement;
using System.Runtime.InteropServices.WindowsRuntime;        //Asbuffer

namespace WindowsFormsAppEnOceanSwitchBle
{
    public partial class Form1 : Form
    {
        //状態確認用コメントを表示
        string textBleScanStatus;
        //Scanの準備
        static BluetoothLEAdvertisementWatcher watcherEnOcean;
        //対象のBleDeviceAddress
        ulong addressBleDevice = 0xE215000183BE,addressTextBox;
        public Form1()
        {
            InitializeComponent();
            //Scanの準備
            watcherEnOcean = new BluetoothLEAdvertisementWatcher();
            labelCommnetButton.Text = "( Watcher initialized ) click button -> Scan start";
            //テキストボックスの数値の初期化
            textBoxBleDeviceAddress.Text = addressBleDevice.ToString("X");
        }
        private void buttonScan_Click(object sender, EventArgs e)
        {
            //TextBoxの数値を取得 -> 変換
            string textBox = textBoxBleDeviceAddress.Text;
            addressTextBox = ulong.Parse(textBox, System.Globalization.NumberStyles.HexNumber);        //16進数で変換
            textBleScanStatus = watcherEnOcean.Status.ToString();
            //Started -> Scan Stop ,Created or Stopped -> Scan Start ,その他 -> よくわからんのでもう一回押してみる
            if (textBleScanStatus == "Started")
            {
                watcherEnOcean.Stop();
                buttonScan.Text = "Start Scan";
                labelCommnetButton.Text = "( Scan Stoped ) click button -> Scan start";
            }
            else if ((textBleScanStatus == "Created") || (textBleScanStatus == "Stopped"))
            {
                BleScanStart();
                buttonScan.Text = "Stop Scan";
                labelCommnetButton.Text = "( Scanning ) click button -> Scan start";
            }
            else
            {
                labelCommnetButton.Text = "( Error Occured ) click button after a while";
            }
        }
        void BleScanStart()
        {
            watcherEnOcean.Received += Watcher_Received;
            //追加データがあった場合に取得できるようにスキャン要求を可能にする（必要なのか？）。
            watcherEnOcean.ScanningMode = BluetoothLEScanningMode.Active;
            watcherEnOcean.Start();
        }
        void Watcher_Received(BluetoothLEAdvertisementWatcher sender, BluetoothLEAdvertisementReceivedEventArgs args)
        {
            //BleDeviceのAddressを取得し、Textboxの中身と比較
            if (args.BluetoothAddress == addressTextBox)
            {
                //ManufacturerDataの中身を取得する。
                var dataScanManufacturerData = args.Advertisement.ManufacturerData;
                foreach (var dataM in dataScanManufacturerData)
                {
                    var dataA = dataM.Data.ToArray();
                    //ManufacturerDataの内、Status（dataA[4]に相当）の中身を分解し、格納する。
                    //SwitchID A0 = dataSwitchNumber[0] , A1 = dataSwitchNumber[1] , B0 = dataSwitchNumber[2] , B1 = dataSwitchNumber[3] 
                    //dataSwitchPress Press=1,Release＝0
                    int[] dataSwitchNumber = new int[4];
                    int dataSwitchPress;
                    dataSwitchPress = dataA[4] % 2;
                    int dataP = dataA[4];
                    for (int a = 0 ; a < 4 ; a++)
                    {
                        dataP = dataP / 2;
                        dataSwitchNumber[a] = dataP % 2;
                    }
                    //ボタンの表示用の4つの四角形を変更する。
                    PictureBox[] pictureBoxSwitch = { pictureBoxSwitchA0, pictureBoxSwitchA1, pictureBoxSwitchB0, pictureBoxSwitchB1 };
                    Bitmap[] canvasSwitch = new Bitmap[4];
                    Graphics[] graphicSwitch = new Graphics[4];
                    for (int a = 0; a < 4; a++)
                    {
                        if (dataSwitchNumber[a] == 1)
                        {
                            canvasSwitch[a] = new Bitmap(pictureBoxSwitch[a].Width, pictureBoxSwitch[a].Height);                            //pictureBoxSwitchと同じサイズのビットマップを作成
                            graphicSwitch[a] = Graphics.FromImage(canvasSwitch[a]);
                            Brush brush;
                            if (dataSwitchPress == 1) brush = Brushes.Blue;
                            else brush = Brushes.Gray;
                            graphicSwitch[a].FillRectangle(brush, 0, 0, canvasSwitch[a].Width, canvasSwitch[a].Height);        //pictureBoxSwitchと同じサイズの四角形をGrayで塗りつぶし
                            graphicSwitch[a].Dispose();
                            pictureBoxSwitch[a].Image = canvasSwitch[a];
                        }
                    }
                }
            }
        }
    }
}
```

#プログラムの中身
　ボタンが押されるとテキストボックスの中身を読み込み、ulong型に変換する。
　WatcherのStatusの中身を確認し、Scan中ならScanをやめ、Scanしていない場合は【BleScanStart()】でScanを開始する。あと終了作業中及びエラー発生時というステータスがあるらしいが、この場合にどうすればよいんかわからなかったため、何も起こらないようにした。
　スキャンを開始すると、周囲のBLEデバイスのアドバタイズデータを取得し始める。
　スキャン要求もできるようにしているが、必要かどうかがわからない。たぶん必要ないと思われる。
　デバイスのアドレスが Easyfit(EWSDB)のアドレスと合った場合にManifactureDataを取得する。Statusは4番目に格納されているため、4番目のデータの中身を確認し、4つあるPicture Boxに反映させている。

　以上である。
　アドバタイズデータの取得に関してはWindowsよりAndroidとかのほうが安定していそうな感じではあるな。