async def read_descriptor(self, uuid): """Read Characteristic Descriptor""" descriptor_path = "" for s in self.services: for c in s.characteristics: if uuid == c.uuid: for d in c.descriptors: descriptor_path = d.path try: # Assemble Read Value Method Message message = dbus.Message.new_method_call( destination=dbus.valid_bus_name(_BLUEZ_DESTINATION), path=dbus.valid_path(descriptor_path), iface=_GATT_DESCRIPTOR_INTERFACE, method=_READ_VALUE_METHOD, ) message.append_objects("a{sv}", {}) except Exception as ex: print("Exception, No Descriptor found for this Characteristic") try: reply = await self._dbus.send_await_reply(message) values = reply.expect_return_objects("ay")[0] return values except: return []
async def discover_services(self): """Discover Device Services""" if self.services: return self.services else: print("Get Services...") message = dbus.Message.new_method_call( destination=dbus.valid_bus_name(_BLUEZ_DESTINATION), path=dbus.valid_path("/"), iface=_DBUS_OBJECT_MANAGER_INTERFACE, method=_GET_MANAGED_OBJECTS_METHOD, ) # Dict of {Object Path, Dict of {String, Dict of {String, Variant}}} objects) reply = await self._dbus.send_await_reply(message) values = reply.expect_return_objects("a{oa{sa{sv}}}")[0] services_regex = re.compile(self._device_path + "/service[0-9abcdef]{4}$") self.services = [ Service( device=self, path=objpath, uuid=objvalue["org.bluez.GattService1"]["UUID"][1], ) for objpath, objvalue in values.items() if services_regex.match(objpath) ] for service in self.services: await service.resolve_characteristics() # Notify user self._services_resolved()
async def stop_notify(self, uuid): """Stop Notification Subscription""" char_path = "" for s in self.services: for c in s.characteristics: if uuid == c.uuid: char_path = c.path # Remove callback to active notify subscriptions del self._notification_callbacks[char_path] rule = { "type": "signal", "interface": "org.freedesktop.DBus.Properties", "member": "PropertiesChanged", "arg0": "org.bluez.GattCharacteristic1", "path": char_path, } # Remove Notify Callback await self._dbus.bus_remove_match_action_async(rule, self.signal_parser, None) # Assemble Stop Notify Method Message message = dbus.Message.new_method_call( destination=dbus.valid_bus_name(_BLUEZ_DESTINATION), path=dbus.valid_path(char_path), iface=_GATT_CHARACTERISTIC_INTERFACE, method=_STOP_NOTIFY_METHOD, ) await self._dbus.send_await_reply(message)
async def write_char(self, uuid, data): """Write Service Char""" char_path = "" for s in self.services: for c in s.characteristics: if uuid == c.uuid: char_path = c.path bytes = [DBUS.subtype_byte(b) for b in data] # Assemble Write Value Method Message message = dbus.Message.new_method_call( destination=dbus.valid_bus_name(_BLUEZ_DESTINATION), path=dbus.valid_path(char_path), iface=_GATT_CHARACTERISTIC_INTERFACE, method=_WRITE_VALUE_METHOD, ) message.append_objects("ay", bytes) message.append_objects("a{sv}", {}) try: reply = await self._dbus.send_await_reply(message) values = reply.expect_return_objects("") except dbus.DBusError: return ""
def set_trusted(conn, trusted): message = dbsy.Message.new_method_call \ ( destination = dbsy.valid_bus_name(BUS_NAME), path = dbsy.valid_path(dev_path), iface = "org.freedesktop.DBus.Properties", method = "Set", ) message.append_objects('ssv', "org.bluez.Device1", 'Trusted', (dbsy.DBUS.Signature('b'), trusted)) error = None reply = conn.connection.send_with_reply_and_block(message, error=error) error_name, error_message = handle_reply(reply, None) if error_name: print('Error setting Trusted: ', error_name, error_message)
async def get_services_resolved(self): """Is Services Resolved""" # Assemble Get Method Message message = dbus.Message.new_method_call( destination=dbus.valid_bus_name(_BLUEZ_DESTINATION), path=dbus.valid_path(self._device_path), iface=DBUS.INTERFACE_PROPERTIES, method="Get", ) message.append_objects("s", dbus.valid_interface(_DEVICE_INTERFACE)) message.append_objects("s", "ServicesResolved") reply = await self._dbus.send_await_reply(message) return reply.expect_return_objects("v")[0][1]
async def is_connected(self): """Is Connected to device""" # Assemble IsConnected Method Message message = dbus.Message.new_method_call( destination=dbus.valid_bus_name(_BLUEZ_DESTINATION), path=dbus.valid_path(self._device_path), iface=DBUS.INTERFACE_PROPERTIES, method="Get", ) message.append_objects("s", dbus.valid_interface(_DEVICE_INTERFACE)) message.append_objects("s", "Connected") reply = await self._dbus.send_await_reply(message) # Return Boolean IsConnected return reply.expect_return_objects("v")[0][1]
async def disconnect(self): """Disconnect to device""" # Remove Match Callback for PropertiesChanged await self._dbus.bus_remove_match_action_async(self.properties_rule, self.properties_changed, None) # Assemble Disonnect Method Message message = dbus.Message.new_method_call( destination=dbus.valid_bus_name(_BLUEZ_DESTINATION), path=dbus.valid_path(self._device_path), iface=_DEVICE_INTERFACE, method=_DISCONNECT_METHOD, ) await self._dbus.send_await_reply(message)
async def _get_properties(self): """Get Properties""" # Assemble GetAll Properties Method Message message = dbus.Message.new_method_call( destination=dbus.valid_bus_name(_BLUEZ_DESTINATION), path=dbus.valid_path(self._device_path), iface=DBUS.INTERFACE_PROPERTIES, method="GetAll", ) message.append_objects("s", dbus.valid_interface(_DEVICE_INTERFACE)) reply = await self._dbus.send_await_reply(message) values = reply.expect_return_objects("a{sv}")[0] print(values) for propname in sorted(values.keys()): proptype, propvalue = values[propname] sys.stdout.write("%s(%s) = %s\n" % (propname, proptype, repr(propvalue)))
def handle_agent_manager(self, register, capability=None): error = None success = None message = dbsy.Message.new_method_call \ ( destination = dbsy.valid_bus_name(BUS_NAME), path = dbsy.valid_path("/org/bluez"), iface = "org.bluez.AgentManager1", method = "RegisterAgent" if register else "UnregisterAgent" ) if register: message.append_objects('os', AGENT_PATH, capability) success = 'Agent registered' else: message.append_objects('o', AGENT_PATH) success = 'Agent unregistered' reply = self.conn.connection.send_with_reply_and_block(message, error=error) handle_reply(reply, print, success)
async def read_char(self, uuid): """Read Service Char""" char_path = "" for s in self.services: for c in s.characteristics: if uuid == c.uuid: char_path = c.path # Assemble Read Value Method Message message = dbus.Message.new_method_call( destination=dbus.valid_bus_name(_BLUEZ_DESTINATION), path=dbus.valid_path(char_path), iface=_GATT_CHARACTERISTIC_INTERFACE, method=_READ_VALUE_METHOD, ) message.append_objects("a{sv}", {}) reply = await self._dbus.send_await_reply(message) values = reply.expect_return_objects("ay")[0] return values
async def read_value(self): """Read Characteristic Descriptor""" # Connect to system bus self._dbus = await dbus.Connection.bus_get_async(DBUS.BUS_SYSTEM, private=False) try: # Assemble Read Value Method Message message = dbus.Message.new_method_call( destination=dbus.valid_bus_name(_BLUEZ_DESTINATION), path=dbus.valid_path(self.path), iface=_GATT_DESCRIPTOR_INTERFACE, method=_READ_VALUE_METHOD, ) message.append_objects("a{sv}", {}) except Exception as ex: print("Exception, Invalid Descriptor Path") try: reply = await self._dbus.send_await_reply(message) values = reply.expect_return_objects("ay")[0] return values except: return []
def pair_with_agent(_osmc_bt, device_uuid, adapter_pattern=None, capability='KeyboardDisplay', timeout=15000): global osmc_bt, mainloop, agent, dev_path, device_obj, paired osmc_bt = _osmc_bt paired = False try: device = bluezutils.find_device(device_uuid, adapter_pattern) except: device = None return_status('DEVICE_NOT_FOUND', ['Device not Found']) return False dev_path = device.object_path rvl_conn = ravel.system_bus() # Check if already paired message = dbsy.Message.new_method_call \ ( destination = dbsy.valid_bus_name(BUS_NAME), path = dbsy.valid_path(dev_path), iface = "org.freedesktop.DBus.Properties", method = "Get" ) message.append_objects('ss', "org.bluez.Device1", 'Paired') error = None reply = rvl_conn.connection.send_with_reply_and_block(message, error=error) if error != None and reply.type == DBUS.MESSAGE_TYPE_ERROR: reply.set_error(error) result = None set_trusted(rvl_conn, False) rvl_conn = None return paired else: result = reply.expect_return_objects("v")[0] if result[0] == 'b' and result[1] == True: print('Already paired') paired = True set_trusted(rvl_conn, True) rvl_conn = None return paired # Create the agent object agent = AgentInterface(rvl_conn, capability) # This bit needed to run in Spyder3 IDE try: nest_asyncio.apply() except: pass # there's probably a more elegant way to do this try: mainloop = asyncio.get_running_loop() if mainloop: mainloop.stop() except: pass mainloop = asyncio.new_event_loop() rvl_conn.attach_asyncio(mainloop) message = dbsy.Message.new_method_call \ ( destination = dbsy.valid_bus_name(BUS_NAME), path = dbsy.valid_path(dev_path), iface = "org.bluez.Device1", method = "Pair" ) async def pair(conn, message): print('Pairing') await_reply = await conn.connection.send_await_reply(message) print('Finished') return await_reply reply = mainloop.run_until_complete(pair(rvl_conn, message)) error_name, error_message = handle_reply(reply, None) print(error_name) if error_name == "org.freedesktop.DBus.Error.NoReply" and device: error_message = 'Timed out. Cancelling pairing' message = dbsy.Message.new_method_call \ ( destination = dbsy.valid_bus_name(BUS_NAME), path = dbsy.valid_path(dev_path), iface = "org.bluez.Device1", method = "CancelPairing" ) try: rvl_conn.connection.send_with_reply_and_block(message) set_trusted(rvl_conn, False) except: pass if error_message is not None: print('PAIRING_FAILED ' + error_message) return_status('PAIRING_FAILED', [error_message]) try: set_trusted(rvl_conn, False) except: pass else: print('PAIRING_OK') return_status('PAIRING_OK', []) paired = True set_trusted(rvl_conn, True) agent.close() rvl_conn = None return paired