Beispiel #1
0
    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 ""
Beispiel #2
0
    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 []
Beispiel #3
0
    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()
Beispiel #4
0
    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)
Beispiel #5
0
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)
Beispiel #6
0
    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]
Beispiel #7
0
    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]
Beispiel #8
0
    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)
Beispiel #9
0
    async def connect(self):
        """Connect to device"""

        try:
            # Connect to system bus
            self._dbus = await dbus.Connection.bus_get_async(DBUS.BUS_SYSTEM,
                                                             private=False,
                                                             loop=self.loop)
        except:
            print("ERROR: Invalid Device")

        # Define Signal Match
        self.properties_rule = {
            "type": "signal",
            "interface": "org.freedesktop.DBus.Properties",
            "member": "PropertiesChanged",
            "arg0": "org.bluez.Device1",
            "path": self._device_path
        }

        # Add Match Callback for PropertiesChanged
        await self._dbus.bus_add_match_action_async(self.properties_rule,
                                                    self.properties_changed,
                                                    None)

        # Assemble Connect Method Message
        message = dbus.Message.new_method_call \
        (
            destination = dbus.valid_bus_name(_BLUEZ_DESTINATION),
            path = self._device_path,
            iface = _DEVICE_INTERFACE,
            method = _CONNECT_METHOD
        )

        # Connect
        await self._dbus.send_await_reply(message)

        while True:
            # Resolve Services if they haven't been so already
            services_resolved = await self.get_services_resolved()
            if services_resolved:
                break
            await asyncio.sleep(0.02, loop=self.loop)

        await self.discover_services()
Beispiel #10
0
    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)))
Beispiel #11
0
 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)
Beispiel #12
0
    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
Beispiel #13
0
    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 []
Beispiel #14
0
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