mirror of
https://github.com/kawasaki/pyscrlink.git
synced 2025-09-05 17:20:20 +02:00
BLEDBusSession: get GATT services and characteristics
Using DBus interface, get GATT services and characteristics of the connected BLE device. Also implement read request to a characteristic.
This commit is contained in:
@@ -289,6 +289,7 @@ class BLEDBusSession(Session):
|
|||||||
except Exception:
|
except Exception:
|
||||||
None
|
None
|
||||||
params['peripheralId'] = node_name
|
params['peripheralId'] = node_name
|
||||||
|
self.devpath = devpath
|
||||||
await self._send_notification('didDiscoverPeripheral', params)
|
await self._send_notification('didDiscoverPeripheral', params)
|
||||||
logger.debug("end _find_device.")
|
logger.debug("end _find_device.")
|
||||||
|
|
||||||
@@ -306,8 +307,75 @@ class BLEDBusSession(Session):
|
|||||||
self.status = self.INITIAL
|
self.status = self.INITIAL
|
||||||
self.dbus = sd_bus_open_system()
|
self.dbus = sd_bus_open_system()
|
||||||
self.discovery_running = False
|
self.discovery_running = False
|
||||||
|
self.iface = None
|
||||||
|
self.devpath = None
|
||||||
|
self.services = {}
|
||||||
|
self.chars = {}
|
||||||
|
self.chars_cache = {}
|
||||||
self._connect_to_adapters()
|
self._connect_to_adapters()
|
||||||
|
|
||||||
|
async def _get_characteristics(self, service_path):
|
||||||
|
service_introspect = DbusInterfaceCommonAsync()
|
||||||
|
service_introspect._connect('org.bluez', service_path, bus=self.dbus)
|
||||||
|
s = await service_introspect.dbus_introspect()
|
||||||
|
parser = ET.fromstring(s)
|
||||||
|
nodes = parser.findall("./node")
|
||||||
|
if not nodes:
|
||||||
|
logger.error(f"characteristic not found at {service_path}")
|
||||||
|
return
|
||||||
|
for node in nodes:
|
||||||
|
path = service_path + '/' + node.attrib['name']
|
||||||
|
if self.chars.get(path):
|
||||||
|
continue
|
||||||
|
logger.debug(f"getting GATT characteristic at {path}")
|
||||||
|
char = GattCharacteristicInterfaceAsync()
|
||||||
|
char._connect('org.bluez', path, bus=self.dbus)
|
||||||
|
self.chars[path] = char
|
||||||
|
cid = await char.uuid
|
||||||
|
logger.debug(f"found char {cid}")
|
||||||
|
|
||||||
|
async def _get_services(self):
|
||||||
|
# do D-Bus introspect to the device path and get service paths under it
|
||||||
|
dev_introspect = DbusInterfaceCommonAsync()
|
||||||
|
dev_introspect._connect('org.bluez', self.devpath, bus=self.dbus)
|
||||||
|
s = await dev_introspect.dbus_introspect()
|
||||||
|
parser = ET.fromstring(s)
|
||||||
|
nodes = parser.findall("./node")
|
||||||
|
if not nodes:
|
||||||
|
logger.error("service not found")
|
||||||
|
return []
|
||||||
|
for node in nodes:
|
||||||
|
path = self.devpath + '/' + node.attrib['name']
|
||||||
|
if self.services.get(path):
|
||||||
|
continue
|
||||||
|
logger.debug(f"getting GATT service at {path}")
|
||||||
|
service = GattServiceInterfaceAsync()
|
||||||
|
service._connect('org.bluez', path, bus=self.dbus)
|
||||||
|
self.services[path] = service
|
||||||
|
sid = await service.uuid
|
||||||
|
logger.debug(f"found service {sid}")
|
||||||
|
await self._get_characteristics(path)
|
||||||
|
|
||||||
|
async def _get_char(self, id):
|
||||||
|
char = self.chars_cache.get(id)
|
||||||
|
if char:
|
||||||
|
return char
|
||||||
|
await self._get_services()
|
||||||
|
btuuid = BTUUID(id)
|
||||||
|
for char in self.chars.values():
|
||||||
|
raw_uuid = await char.uuid
|
||||||
|
char_uuid = BTUUID(raw_uuid)
|
||||||
|
if char_uuid == btuuid:
|
||||||
|
self.chars_cache[id] = char
|
||||||
|
return char
|
||||||
|
logger.error(f"Can not get characteristic: {id}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
async def _start_notification(self, char):
|
||||||
|
logger.debug('startNotification')
|
||||||
|
(fd, mtu) = await char.acquire_notify({})
|
||||||
|
logger.debug(f'fd={fd}')
|
||||||
|
|
||||||
def handle_request(self, method, params):
|
def handle_request(self, method, params):
|
||||||
logger.debug("handle request")
|
logger.debug("handle request")
|
||||||
|
|
||||||
@@ -347,6 +415,17 @@ class BLEDBusSession(Session):
|
|||||||
res["error"] = { "message": "Failed to connect to device" }
|
res["error"] = { "message": "Failed to connect to device" }
|
||||||
self.status = self.DONE
|
self.status = self.DONE
|
||||||
|
|
||||||
|
elif self.status == self.CONNECTED and method == 'read':
|
||||||
|
logger.debug("handle read request")
|
||||||
|
service_id = params['serviceId']
|
||||||
|
chara_id = params['characteristicId']
|
||||||
|
c = await self._get_char(chara_id)
|
||||||
|
value = await c.read_value({})
|
||||||
|
message = base64.standard_b64encode(value).decode('ascii')
|
||||||
|
res['result'] = { 'message': message, 'encode': 'base64' }
|
||||||
|
if params.get('startNotifications') == True:
|
||||||
|
await self._start_notification(c)
|
||||||
|
|
||||||
logger.debug(res)
|
logger.debug(res)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user