[PYTHON] A memo when connecting bluetooth from a smartphone / PC to Raspberry Pi 4

I tried to summarize the general procedure when connecting bluetooth to Raspberry Pi from a smartphone / PC and performing control using python on the Raspberry Pi side. (Since I was referring to an outside site and I got stuck in some places ...)

Operating environment

Installation of environment

reference: https://qiita.com/shippokun/items/0953160607833077163f

#Install pyBluez dependent packages
$ sudo apt-get install -y python-dev libbluetooth3-dev

#Install pyBluez
$ sudo pip3 install pybluez

# sudo apt-get install bluetooth blueman -y # bluez-tool

$ sudo apt install libusb-dev
$ sudo apt install libdbus-1-dev
$ sudo apt install libglib2.0-dev
$ sudo apt install libudev-dev -y
$ sudo apt install libical-dev -y
$ sudo apt install libreadline-dev -y
$ sudo apt install libdbus-glib-1-dev -y
$ sudo apt install libbluetooth-dev

Check the Raspberry Pi's Bluetooth mac address (if needed)

$ hciconfig
hci0:   Type: Primary  Bus: UART
        BD Address: DC:A6:32:37:3D:60  ACL MTU: 1021:8  SCO MTU: 64:1
        UP RUNNING PSCAN
        RX bytes:3163 acl:22 sco:0 events:92 errors:0
        TX bytes:3627 acl:21 sco:0 commands:64 errors:0

Examine unused channels (if needed)

$ sudo sdptool browse local | grep Channel
    Channel: 17
    Channel: 16
    Channel: 15
    Channel: 14
    Channel: 10
    Channel: 9
    Channel: 24
    Channel: 12
    Channel: 3

Just run sudo sdptool browse local and you'll see what channel is being used for what.

$ sudo sdptool browse local
...
Service Name: Headset Voice gateway
Service RecHandle: 0x10005
Service Class ID List:
  "Headset Audio Gateway" (0x1112)
  "Generic Audio" (0x1203)
Protocol Descriptor List:
  "L2CAP" (0x0100)
  "RFCOMM" (0x0003)
    Channel: 12
Profile Descriptor List:
  "Headset" (0x1108)
    Version: 0x0102

...

Add serial port service by specifying an unused channel. (Of course, if you specify a used channel, it will fail in the next step. I didn't notice this and got it first ...)

sudo sdptool add --channel=22 SP

If you want to add a serial port service without specifying a channel, do the following instead of the above:

sudo sdptool add SP

Check if the serial port service could be added.

sudo sdptool browse local

When the above is executed, it looks like the following Service Name: Serial Port You should get the output. here Channel: 1 The channel number is displayed as shown, so check it.

Service Name: Serial Port
Service Description: COM Port
Service Provider: BlueZ
Service RecHandle: 0x10001
Service Class ID List:
  "Serial Port" (0x1101)
Protocol Descriptor List:
  "L2CAP" (0x0100)
  "RFCOMM" (0x0003)
    Channel: 1
Language Base Attr List:
  code_ISO639: 0x656e
  encoding:    0x6a
  base_offset: 0x100
Profile Descriptor List:
  "Serial Port" (0x1101)
    Version: 0x0100

Edit the configuration file to enable serial communication via Bluetooth immediately after startup.

sudo nano /etc/systemd/system/dbus-org.bluez.service

Add --compat to the ExecStart ... line (make it work in compatibility mode). Also,

ExecStartPost=/usr/bin/sdptool add SP
#When specifying a channel, describe the following instead of the above.
#Be careful not to specify used channels.
# ExecStartPost=/usr/bin/sdptool add --channel=22 SP

Is added so that the serial communication protocol (SPP) is added at startup. Specifying the channel number is optional.

[Unit]
Description=Bluetooth service
Documentation=man:bluetoothd(8)
ConditionPathIsDirectory=/sys/class/bluetooth

[Service]
Type=dbus
BusName=org.bluez
ExecStart=/usr/lib/bluetooth/bluetoothd --compat
ExecStartPost=/usr/bin/sdptool add SP
#When specifying a channel, describe the following instead of the above.
#Be careful not to specify used channels.
# ExecStartPost=/usr/bin/sdptool add --channel=22 SP

NotifyAccess=main
#WatchdogSec=10
#Restart=on-failure
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
LimitNPROC=1
ProtectHome=true
ProtectSystem=full


Restart the Raspberry Pi.

$ sudo reboot -h

Pair

Turn on Bluetooth on the Raspberry Pi and allow Bluetooth to be searched on the server side.

sudo bluetoothctl
[bluetooth] power on
[bluetooth] discoverable on
[bluetooth] agent on
[bluetooth] default-agent

If you try to connect in this state, you will be asked to confirm the passkey and service authentication as shown below, so enter yes / no.

reference: https://qiita.com/oko1977/items/9f53f3b11a1b033219ea

[CHG] Device 80:19:34:31:CD:1E Connected: yes
Request confirmation
[agent] Confirm passkey 291086 (yes/no): yes
Authorize service
[agent] Authorize service 0000110e-0000-1000-8000-00805f9b34fb (yes/no): yes
Authorize service
[agent] Authorize service 0000110d-0000-1000-8000-00805f9b34fb (yes/no): yes
[CHG] Device 80:19:34:31:CD:1E UUIDs: 00001000-0000-1000-8000-00805f9b34fb
...
[CHG] Device 80:19:34:31:CD:1E UUIDs: c7f94713-891e-496a-a0e7-983a0946126e
[CHG] Device 80:19:34:31:CD:1E Connected: no
[CHG] Device 80:19:34:31:CD:1E Connected: yes
[CHG] Device 80:19:34:31:CD:1E Connected: no
[bluetooth]#

here,

image.png

If it is recognized as a sound device as shown in the image above, select raspberrypi from the device and printer and select

--Serial Port (SPP)'SerialPort' --Remotely controllable devices --Remote control

Uncheck items other than. (If you do not remove it, it will be treated as a sound device. In my environment, the sound device I was using was inactivated and no sound was produced.)

image.png

image.png

By the way, if "Serial Port (SPP)'SerialPort'" does not appear, follow the procedure at the beginning. sdptool add SP To check again if the serial communication service is enabled.

Try to receive

Do the following:

sudo rfcomm listen /dev/rfcomm0

To specify the channel number, execute as follows (in the case of channel number 22).

sudo rfcomm listen /dev/rfcomm0 22

Launch another console and cat / dev / rfcomm0 to check the message on the Raspberry Pi side.

$ sudo cat /dev/rfcomm0

Also, launch another console Try echoing the message to the / dev / rfcomm0 device on the Raspberry Pi.

$ sudo echo abcd > /dev/rfcomm0

Try to receive with python & bluez

  1 # -*- coding: utf-8 -*-
  2 # Author: Shinsuke Ogata
  3
  4 import sys
  5 import traceback
  6 import time
  7 import bluetooth
  8 import threading
  9
 10 class SocketThread(threading.Thread):
 11     '''
 12     @param client_Client socket returned as a result of socket accept.
 13     @param notify_receive Functions / methods that process data received by serial communication.
 14     @param notify_error Function / method that executes processing when an error occurs
 15     '''
 16     def __init__(self, server_socket, client_socket, notify_receive, notify_error, debug):
 17         super(SocketThread, self).__init__()
 18         self._server_socket = server_socket
 19         self._client_socket = client_socket
 20         self._receive = notify_receive
 21         self._error = notify_error
 22         self._debug = debug
 23
 24     def run(self):
 25         while True:
 26             try:
 27                 data = self._client_socket.recv(1024)
 28                 if self._receive != None:
 29                     self._receive(data)
 30             except KeyboardInterrupt:
 31                 self._client_socket.close()
 32                 self._server_socket.close()
 33                 break
 34             except bluetooth.btcommon.BluetoothError:
 35                 self._client_socket.close()
 36                 self._server_socket.close()
 37                 if self._debug:
 38                     print('>>>> bluetooth.btcommon.BluetoothError >>>>')
 39                     traceback.print_exc()
 40                     print('<<<< bluetooth.btcommon.BluetoothError <<<<')
 41                 break
 42             except:
 43                 self._client_socket.close()
 44                 self._server_socket.close()
 45                 if self._debug:
 46                     print('>>>> Unknown Error >>>>')
 47                     traceback.print_exc()
 48                     print('<<<< Unknown Error <<<<')
 49                 break
 50
 51 class BluetoothServer(threading.Thread):
 52
 53     '''
 54     @param notify_receive Functions / methods that process data received by serial communication.
 55     @param notify_error Function / method that executes processing when an error occurs
 56     @param debug Set to True when issuing debug messages
 57     '''
 58     def __init__(self, notify_receive, notify_error=None, debug=False):
 59         super(BluetoothServer, self).__init__()
 60         self._port =1
 61         self._receive = notify_receive
 62         self._error = notify_error
 63         self._server_socket = None
 64         self._debug = debug
 65
 66     def run(self):
 67         try:
 68             self._server_socket=bluetooth.BluetoothSocket( bluetooth.RFCOMM )
 69
 70             if self._debug:
 71                 print("BluetoothServer: binding...")
 72
 73             self._server_socket.bind( ("",self._port ))
 74
 75             if self._debug:
 76                 print("BluetoothServer: listening...")
 77
 78             self._server_socket.listen(1)
 79
 80             client_socket,address = self._server_socket.accept()
 81
 82             if self._debug:
 83                 print("BluetoothServer: accept!!")
 84             task = SocketThread(self._server_socket, client_socket, self._receive, self._error, self._debug)
 85             task.start()
 86         except KeyboardInterrupt:
 87             if self._debug:
 88                 print("BluetoothServer: KeyboardInterrupt")
 89         except:
 90             if self._debug:
 91                 print('>>>> Unknown Error >>>>')
 92                 traceback.print_exc()
 93                 print('<<<< Unknown Error <<<<')
 94
 95
 96 def receive(data):
 97     print("receive [%s]" % data)
 98
 99 def error(data):
100     print("error")
101
102 if __name__ == '__main__':
103     task = BluetoothServer(receive, error, True)
104     task.start()

Recommended Posts

A memo when connecting bluetooth from a smartphone / PC to Raspberry Pi 4
Control music playback on a smartphone connected to Raspberry Pi 3 and bluetooth with AVRCP
Output from Raspberry Pi to Line
About the error I encountered when trying to use Adafruit_DHT from Python on a Raspberry Pi
A memo to simply use the illuminance sensor TSL2561 with Raspberry Pi 2
Connect your Raspberry Pi to your smartphone using Blynk
Memo of migrating Django's DB from SQLite 3 to MySQL on Docker on Raspberry Pi 4B
Speeding up when connecting from cx_Oracle to Autonomous Database
Raspberry Pi 4 setup memo
A memorandum when making a surveillance camera with Raspberry Pi
[Raspberry PI & Garmin GLO] Until you connect Bluetooth GPS to Raspberry Pi
I tried to automate [a certain task] using Raspberry Pi
Change the message displayed when logging in to Raspberry Pi
How to get temperature from switchBot thermo-hygrometer using raspberry Pi
[Raspberry Pi] Minimum device driver creation memo to output GPIO
Introduced python3-OpenCV3 to Raspberry Pi
I talked to Raspberry Pi
Introducing PyMySQL to raspberry pi3
Raspberry Pi + Python + OpenGL memo
Use your Raspberry Pi to read your student ID number from your student ID card
I made a web server with Raspberry Pi to watch anime
I want to run the Python GUI when starting Raspberry Pi
Raspberry Pi --1 --First time (Connect a temperature sensor to display the temperature)
[Note] Using 16x2-digit character LCD (1602A) from Python with Raspberry Pi
Port FreeRTOS to Raspberry Pi 4B
Tensorflow memo [updated from time to time]
Using a webcam with Raspberry Pi
[Raspberry Pi] Changed Python default to Python3
A story I was addicted to when inserting from Python to a PostgreSQL table
[Python memo] I want to get a 2-digit hexadecimal number from a decimal number
I tried to make a traffic light-like with Raspberry Pi 4 (Python edition)
[Pyto] I tried to use a smartphone as a flick keyboard for PC
A story that suffered from OS differences when trying to implement a dissertation
I want to prevent the speaker connected to the Raspberry Pi (jessie) from bouncing when the OS is restarted (Python script)