DelphiでBluetooth(2)
結論から
Delphiすごい。無償のCommunity Editionだけで、Bluetooth制御して、HC-05を乗せたArduinoに、Windows PCから通信できましたよ。
無償のツールって、肝心なところで機能が不足していて「ここから先は有償版をお使いください」みたいな話になっているという先入観を持っていたのですが、Delphi Community Editionでは、(私個人が趣味で使うくらいの機能の範囲では)、そういうこともなくて満足です。個人の趣味、Arduinoと連携させて使いたいちょっとしたアプリをこさえるにはピッタリだと思います。
では、やったことの記録。
前回、DelphiのコミュニティエディションでWindows10のPCからBluetoothをスキャンし、ArduinoにつないだBluetoothモジュール、HC-05を検出するところまでやっています。今回、ここも含めてもう一度最初から作り直してみます。
1)周囲のBluetoothデバイスをスキャンする
まず、フォームにBluetooth、ボタン、ListBoxのコントロールを一つずつ設置します。SCANボタンをクリックすると、5秒スキャンして見つかったデバイスをリストボックスに表示するようにします。(メモも残しておきます)
前回は「リストボックス」ではなくて「メモ」だけを使い、経過情報をどんどんそこへ表示するようにしたのですが、これだとスキャンで検出されたデバイスが複数あるときに、「選ぶ」ことができません。なのでリストボックスにした次第。(とはいえ、実際にはスキャンしても一個しか出てこなかったんですけどね(笑))
SCANボタンクリックして、OnClickイベントを発生させると、この手続きが呼ばれ
procedure TForm1.ButtonScanClick(Sender: TObject);
begin
Bluetooth1.DiscoverDevices(5000);
end;
5秒間スキャンします。(カッコ内はスキャン時間をミリ秒で指定)5秒経つと、OnDiscoveryEndというイベントが発生し、
procedure TForm1.Bluetooth1DiscoveryEnd(const Sender: TObject;
const ADeviceList: TBluetoothDeviceList);
この手続きが実行されます。このとき、ADeviceList に、ペアリング可能なBluetoothDeviceのリストが入っているので、ListBoxに表示させます。
procedure TForm1.Bluetooth1DiscoveryEnd(const Sender: TObject;
const ADeviceList: TBluetoothDeviceList);
var
I: Integer;
begin
ListBox1.Clear;
for I := 0 to ADeviceList.Count -1 do
ListBox1.Items.Add(ADeviceList[I].DeviceName);
end;
procedure TForm1.ButtonScanClick(Sender: TObject);
begin
Bluetooth1.DiscoverDevices(5000);
end;
検出できました\(^o^)/ (APWは当方でHC-05に適当に付けた名前)
なお、これで見つからないときは、
・BluetoothコントロールのEnabledがFalseになっていないか?
⇒なっていたらTrueに変更
・HC-05が既にWindowsでペアリング済みではないか
⇒なっていたらOSの「Bluetoothとその他のデバイス」から一旦削除。
この辺を確認して再挑戦してみましょう。
2)ペアリングする
見つけたデバイスとペアリングします。
その前に、使うデバイスと、そのあとソケットを保存しておく変数としてフォームのpublic のところに
public
mydevice :TBluetoothDevice;
mysocket :TBluetoothSocket;
を用意しておきます。
さて
PAIRボタン追加しました。SCANしてリストボックスに出ているデバイスを選んで、PAIRボタンクリックすると、つながるという流れを想定。
ListBoxで選んでいるのがどれかは、ItemIndexプロパティで分かります。
あと、TForm1.Bluetooth1DiscoveryEnd の中で使われていた
ADeviceList と同じものが Bluetooth1.LastDiscoveredDevices でリストとしてとりだせるようです。そこで
procedure TForm1.ButtonPairClick(Sender: TObject);
begin
if ListBox1.ItemIndex > -1 then begin
mydevice := Bluetooth1.LastDiscoveredDevices[ListBox1.ItemIndex];
Bluetooth1.Pair(mydevice);
Memo1.Lines.Add(BoolToStr(mydevice.IsPaired));
end;
end;
とやれば指定したデバイスとペアリングできるようですね。ペアリングができたかどうかをMemoに表示します。(mydeviceとペアリングできていることの確認はmydevice.IsPaired プロパティを見ればいい。)
3)ソケットこさえる
つぎに、ペアリングしたデバイスとの間での通信用にsocket というのを使うらしい。デバイスのサービスリストというのを取得して、その中から目的サービスを選ぶらしいのだけど、私がやってみた限り、HC-05のデバイスに対してのサービスはいつも一個しか見つかりませんでした。だから決め打ちでこんな感じでもいいかと思います。
mysocket:= mydevice.CreateClientSocket(mydevice.LastServiceList.Items[0].UUID,False);
mysocket.Connect;
Connect出来たらあとは
mysocket.SendData(TEncoding.UTF8.GetBytes(’TEST#’));
みたいにして文字列を送ればよいようですね。この、TEncoding.UTF8.GetBytes というのを使うのが大事なとこかと。
4)こうなりました
とやりますと、
※WindowsPCから、Bluetooth経由でArduino側に文字列を送ることができました。(例外処理等は何もやっていません。)
Delphi側ソースコード(全体)
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
System.Bluetooth, FMX.Layouts, FMX.ListBox, FMX.Controls.Presentation,
FMX.StdCtrls, System.Bluetooth.Components, FMX.ScrollBox, FMX.Memo, FMX.Edit;
type
TForm1 = class(TForm)
Bluetooth1: TBluetooth;
ButtonScan: TButton;
ListBox1: TListBox;
Memo1: TMemo;
ButtonPair: TButton;
EditSendData: TEdit;
ButtonSendData: TButton;
ButtonSocket: TButton;
Label1: TLabel;
procedure ButtonScanClick(Sender: TObject);
procedure Bluetooth1DiscoveryEnd(const Sender: TObject;
const ADeviceList: TBluetoothDeviceList);
procedure ButtonPairClick(Sender: TObject);
procedure ButtonSocketClick(Sender: TObject);
procedure ButtonSendDataClick(Sender: TObject);
private
{ private }
public
{ public }
mydevice :TBluetoothDevice;
mysocket :TBluetoothSocket;
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.Bluetooth1DiscoveryEnd(const Sender: TObject;
const ADeviceList: TBluetoothDeviceList);
var
I: Integer;
begin
Memo1.Lines.Add(IntToStr(ADeviceList.Count));
ListBox1.Clear;
for I := 0 to ADeviceList.Count -1 do
ListBox1.Items.Add(ADeviceList[I].DeviceName);
end;
procedure TForm1.ButtonPairClick(Sender: TObject);
begin
if ListBox1.ItemIndex > -1 then begin
mydevice := Bluetooth1.LastDiscoveredDevices[ListBox1.ItemIndex];
Bluetooth1.Pair(mydevice);
Memo1.Lines.Add('ペア成否'+BoolToStr(mydevice.IsPaired));
end;
end;
procedure TForm1.ButtonScanClick(Sender: TObject);
begin
Bluetooth1.DiscoverDevices(5000);
end;
procedure TForm1.ButtonSendDataClick(Sender: TObject);
var mydata : string;
begin
mydata := EditSendData.Text + '#'; //終端文字#
mysocket.SendData(TEncoding.UTF8.GetBytes(mydata));
end;
procedure TForm1.ButtonSocketClick(Sender: TObject);
begin
mysocket:= mydevice.CreateClientSocket(mydevice.LastServiceList.Items[0].UUID,False);
mysocket.Connect;
Memo1.Lines.Add('ソケット成否'+BoolToStr(mysocket.Connected));
end;
end.