pythonメニュー

Pythonで扱うbluetooth(pybluez)

pybluezモジュールのインストール

Windows10向けのpybluezモジュールはpipで公開されており、以下のコマンド操作でインストールできました。(2020-09-27時点のPython3.6環境)
(win36) D:\pytest>pip install PyBluez-win10
Collecting PyBluez-win10
  Downloading https://files.pythonhosted.org/packages/4f/9e/05163a0b3486492778661a1a5a7c6877e84ae2be16532d39ed68e2ccd11f/PyBluez-win10-0.22.tar.gz (97kB)
     |????????????????????????????????| 102kB 3.3MB/s
Building wheels for collected packages: PyBluez-win10
  Building wheel for PyBluez-win10 (setup.py) ... done
  Stored in directory: C:\Users\yuu.PC7\AppData\Local\pip\Cache\wheels\7f\c0\b0\882eab8aefba895975f8d1011583ad8613cdb98ede7cc243bb
Successfully built PyBluez-win10
Installing collected packages: PyBluez-win10
Successfully installed PyBluez-win10-0.22
(win36) D:\pytest>
上記は2021-01-31時点で
ERROR: Could not find a version that satisfies the requirement PyBluez-win10
ERROR: No matching distribution found for PyBluez-win10
で失敗しました。 この時点で「pip install PyBluez==0.22」の指定でインストールすることで成功しました。

しかし、単純にインストールできるものではないようで、別のマシンでこの操作をすると失敗でできませんでした。
PCの既存環境によって失敗するということです。この時のエラーメッセージに、次の内容がありました。
building 'bluetooth._msbt' extension
error: Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": 
この「Microsoft C++ Build Tools」は、純粋でない Python パッケージをインストール時にビルドを伴う場合に使います。
この場合であれば、「https://github.com/karulis/pybluez」からクローンをダウンロードして、 展開した位置にカレントディレクトリを移動して「python setup.py install」の実行でインストールするようです。
ですが「Microsoft C++ Build Tools」のバージョンによって失敗することもあるようで、難しいようです。

さて、Pythonディストリビューションに使用される標準の組み込みパッケージにWHL(Python Wheel Package)「ホイール」と 呼ぶものがあります。
ファイル拡張子が「.whl」でこの種類の中には、 WindowsやmacOSなどのプラットフォームに固有で、コンパイルされた拡張機能が含まれているものがあります。
それを入手できれば、対応プラットフォーム専用にコンパイルされているので、簡単にインストールできます。
python3.6の環境のwindows環境であれば、次のようにインストールできます。
pip install PyBluez-0.22-cp36-cp36m-win_AMD64.whl
このファイルはバイナリで内容が簡単に分かりません。 「トロイの木馬」の可能性もあるので安易にネットから探して使うのは危険かもしれません。

クライアントとしての接続

import sys
import bluetooth
import time

devices = bluetooth.discover_devices(lookup_names=True)
print("Found {} devices.".format(len(devices)))

n=0
for addr, name in devices:
    print("No={}  {} - {}".format(n, addr, name))
    n+=1


#no=input("Device No=>>")
#addr, name = devices[int(no)]
addr, name = 'F0:79:59:03:A0:58','ASUS_T00P_YUU'

sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
#sock.bind(('', bluetooth.PORT_ANY))
#sock.listen(1) # backlog: 接続待ち受け数

uuid = '00001101-0000-1000-8000-00805F9B34FB'

'''
bluetooth.advertise_service(
    sock, "MyClient", service_id=uuid,
    service_classes=[ uuid, bluetooth.SERIAL_PORT_CLASS ],
    profiles=[ bluetooth.SERIAL_PORT_PROFILE ],
'''
# https://stackoverrun.com/ja/q/10148302
service = []
retry = 1
while len(service) == 0:
     print( "Looking for service on {0}, try {1}".format(addr, retry) )
     service = bluetooth.find_service(address=addr, uuid=uuid)
     retry = retry + 1
     time.sleep(1)

print(service)

if len(service) == 1: 
    service = service[0]
    print( "Service found. Name={0}".format(service["name"]) )
    print( "Connecting to service." )
    sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
    try:
       sock.connect((addr, service["port"]))
       print( "Connected to service on {0} on port {1}".format(addr, service["port"]) )
    except bluetooth.btcommon.BluetoothError as e:
       print( "Connection failed: {0}".format(e) )
    
    data = sock.recv(4)
    print(data) # bytes
    print(data.decode('ascii'))

    b = '12345'.encode('cp932')
    sock.send(b)
    sock.close()


サーバとして接続相手より受信した情報を表示

import bluetooth
import uuid
print(uuid.uuid4()) 

PORT = 1
server_sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
server_sock.bind(('', bluetooth.PORT_ANY))
server_sock.listen(1) # backlog: 接続待ち受け数

uuid = 'ef7ce24a-a1eb-45d4-9208-f896b0ae8336'
uuid = '00001101-0000-1000-8000-00805F9B34FB'

bluetooth.advertise_service(
    server_sock, "MyServer", service_id=uuid,
    service_classes=[ uuid, bluetooth.SERIAL_PORT_CLASS ],
    profiles=[ bluetooth.SERIAL_PORT_PROFILE ],
)

client_sock, client_addrport = server_sock.accept() # blocking until connection

data = client_sock.recv(1024)
print(data) # bytes
print(data.decode('ascii'))