refactored BluetoothHID.py, added comments for future maintainability

This commit is contained in:
mpeter 2025-08-08 19:46:28 +02:00
parent 73df805af0
commit 03be0d7eec

View file

@ -5,6 +5,15 @@ import os
import socket
# see section "2.5 PSMs and SPSMs": https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Assigned_Numbers/out/en/Assigned_Numbers.pdf
BLUETOOTH_PORT_HID_CONTROL = 0x0011
BLUETOOTH_PORT_HID_INTERRUPT = 0x0013
# see section "3.3 SDP Service Class and Profile Identifiers" of https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Assigned_Numbers/out/en/Assigned_Numbers.pdf
# and Vol 3, Part B, section 2.5.1 of https://www.bluetooth.com/specifications/specs/core-specification-5-3/
BLUETOOT_PROFILE_HID = "00001124-0000-1000-8000-00805f9b34fb"
class BluetoothHIDProfile(dbus.service.Object):
def __init__(self, bus, path):
super(BluetoothHIDProfile, self).__init__(bus, path)
@ -43,40 +52,51 @@ def error_handler(e):
class BluetoothHIDService(object):
PROFILE_PATH = "/org/bluez/bthid_profile"
PROFILE_PATH = "/org/bluez/emubthid_profile"
HOST = 0
PORT = 1
def __init__(self, service_record, MAC):
self.P_CTRL = 0x0011
self.P_INTR = 0x0013
self.SELFMAC = MAC
bus = dbus.SystemBus()
bluez_obj = bus.get_object("org.bluez", "/org/bluez")
manager = dbus.Interface(bluez_obj, "org.bluez.ProfileManager1")
BluetoothHIDProfile(bus, self.PROFILE_PATH)
opts = {
"ServiceRecord": service_record,
"Name": "BTKeyboardProfile",
"RequireAuthentication": False,
"RequireAuthorization": False,
"Service": "MY BTKBD",
"Role": "server"
}
sock_control = L2CAPSocket(True)
sock_inter = L2CAPSocket(True)
sock_control.bind((self.SELFMAC, self.P_CTRL))
sock_inter.bind((self.SELFMAC, self.P_INTR))
# The PSM parameter sets the bluetooth "port" for L2CAP connections
# "Valid values in the first range are assigned by the Bluetooth SIG and indicate protocols."
# https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Core-54/out/en/host/logical-link-control-and-adaptation-protocol-specification.html
sock_control.bind((self.SELFMAC, BLUETOOTH_PORT_HID_CONTROL))
sock_inter.bind((self.SELFMAC, BLUETOOTH_PORT_HID_INTERRUPT))
manager.RegisterProfile(self.PROFILE_PATH, "00001124-0000-1000-8000-00805f9b34fb", opts)
print("Registered")
# IDEs dont see this function because bluetooth.BluetoothSocket imports them dynamically
sock_control.listen(1)
sock_inter.listen(1)
print(f"waiting for connection at controller {MAC}, please double check with the MAC in bluetoothctl")
manager.RegisterProfile(self.PROFILE_PATH, BLUETOOT_PROFILE_HID, {
"Name": "Emulated Bluetooth keyboard",
# "Service": "MY BTKBD", # this refers to the bluetooth spec service class uuid
"Role": "server",
"RequireAuthentication": True,
"RequireAuthorization": True,
"ServiceRecord": service_record,
# note: it seems as if socket creation could be replaced with working through DBus (see PSM option and NewConnection function).
# maybe currently the conenction is somehow handled at 2 places at the same time?
#
# https://www.bluez.org/bluez-5-api-introduction-and-porting-guide/
# "The new Profile1 interface (and removal of org.bluez.Service)"
})
print("Registered Bluetooth HID profile in Bluez")
print(f"Waiting for connection at controller {MAC}, please double check with the MAC in bluetoothctl")
self.ccontrol, cinfo = sock_control.accept()
print("Control channel connected to " + cinfo[self.HOST])
self.cinter, cinfo = sock_inter.accept()