コード例 #1
0
ファイル: client.py プロジェクト: userJ01/iot-python
    def __init__(self, config, logHandlers=None):
        self._config = ApplicationClientConfig(**config)
        # Call parent constructor
        AbstractClient.__init__(
            self,
            domain=self._config.domain,
            organization=self._config.orgId,
            clientId=self._config.clientId,
            username=self._config.username,
            password=self._config.password,
            logHandlers=logHandlers,
            cleanStart=self._config.cleanStart,
            port=self._config.port,
            transport=self._config.transport,
            caFile=self._config.caFile,
            logLevel=self._config.logLevel,
            sessionExpiry=self._config.sessionExpiry,
            keepAlive=self._config.keepAlive,
        )

        # Add handlers for events and status
        self.client.message_callback_add("iot-2/type/+/id/+/evt/+/fmt/+", self._onDeviceEvent)
        self.client.message_callback_add("iot-2/type/+/id/+/mon", self._onDeviceStatus)
        self.client.message_callback_add("iot-2/app/+/mon", self._onAppStatus)
        self.client.message_callback_add("iot-2/type/+/id/+/intf/+/evt/state", self._onDeviceState)
        self.client.message_callback_add("iot-2/thing/type/+/id/+/intf/+/evt/state", self._onThingState)
        self.client.message_callback_add("iot-2/type/+/id/+/err/data", self._onErrorTopic)
        self.client.message_callback_add("iot-2/thing/type/+/id/+/err/data", self._onThingError)

        # Add handler for commands if not connected to QuickStart
        if not self._config.isQuickstart():
            self.client.message_callback_add("iot-2/type/+/id/+/cmd/+/fmt/+", self._onDeviceCommand)

        # Attach fallback handler
        self.client.on_message = self._onUnsupportedMessage

        # Initialize user supplied callbacks
        self.deviceEventCallback = None
        self.deviceCommandCallback = None
        self.deviceStateCallback = None
        self.deviceStatusCallback = None
        self.thingStateCallback = None
        self.errorTopicCallback = None
        self.appStatusCallback = None

        # Create an api client if not connected in QuickStart mode
        if not self._config.isQuickstart():
            apiClient = ApiClient(self._config, self.logger)
            self.registry = Registry(apiClient)
            self.usage = Usage(apiClient)
            self.dsc = DSC(apiClient)
            self.lec = LEC(apiClient)
            self.mgmt = Mgmt(apiClient)
            self.serviceBindings = ServiceBindings(apiClient)
            self.actions = Actions(apiClient)
            self.state = StateMgr(apiClient)

            # We directly expose the get() method via self.serviceStatus()
            self._serviceStatus = ServiceStatus(apiClient)
コード例 #2
0
ファイル: client.py プロジェクト: TonyJZ/iot-python
    def __init__(self, config, logHandlers=None):
        self._config = ApplicationClientConfig(**config)
        # Call parent constructor
        AbstractClient.__init__(
            self,
            domain=self._config.domain,
            organization=self._config.orgId,
            clientId=self._config.clientId,
            username=self._config.username,
            password=self._config.password,
            logHandlers=logHandlers,
            cleanStart=self._config.cleanStart,
            port=self._config.port,
            transport=self._config.transport,
        )

        # Add handlers for events and status
        self.client.message_callback_add("iot-2/type/+/id/+/evt/+/fmt/+",
                                         self._onDeviceEvent)
        self.client.message_callback_add("iot-2/type/+/id/+/mon",
                                         self._onDeviceStatus)
        self.client.message_callback_add("iot-2/app/+/mon", self._onAppStatus)

        # Add handler for commands if not connected to QuickStart
        if not self._config.isQuickstart():
            self.client.message_callback_add("iot-2/type/+/id/+/cmd/+/fmt/+",
                                             self._onDeviceCommand)

        # Attach fallback handler
        self.client.on_message = self._onUnsupportedMessage

        # Initialize user supplied callbacks
        self.deviceEventCallback = None
        self.deviceCommandCallback = None
        self.deviceStatusCallback = None
        self.appStatusCallback = None

        # Create an api client if not connected in QuickStart mode
        if not self._config.isQuickstart():
            apiClient = ApiClient(self._config, self.logger)
            self.registry = Registry(apiClient)
            self.status = Status(apiClient)
            self.usage = Usage(apiClient)
            self.dsc = DSC(apiClient)
            self.lec = LEC(apiClient)
            self.mgmt = Mgmt(apiClient)
            self.serviceBindings = ServiceBindings(apiClient)
            self.actions = Actions(apiClient)
            self.state = StateMgr(apiClient)
コード例 #3
0
ファイル: client.py プロジェクト: cclauss/iot-python
    def __init__(self, config, logHandlers=None):
        self._config = ApplicationClientConfig(**config)
        # Call parent constructor
        AbstractClient.__init__(
            self,
            domain=self._config.domain,
            organization=self._config.orgId,
            clientId=self._config.clientId,
            username=self._config.username,
            password=self._config.password,
            logHandlers=logHandlers,
            cleanStart=self._config.cleanStart,
            port=self._config.port,
            transport=self._config.transport,
        )

        # Add handlers for events and status
        self.client.message_callback_add("iot-2/type/+/id/+/evt/+/fmt/+", self._onDeviceEvent)
        self.client.message_callback_add("iot-2/type/+/id/+/mon", self._onDeviceStatus)
        self.client.message_callback_add("iot-2/app/+/mon", self._onAppStatus)

        # Add handler for commands if not connected to QuickStart
        if not self._config.isQuickstart():
            self.client.message_callback_add("iot-2/type/+/id/+/cmd/+/fmt/+", self._onDeviceCommand)

        # Attach fallback handler
        self.client.on_message = self._onUnsupportedMessage

        # Initialize user supplied callbacks
        self.deviceEventCallback = None
        self.deviceCommandCallback = None
        self.deviceStatusCallback = None
        self.appStatusCallback = None

        # Create an api client if not connected in QuickStart mode
        if not self._config.isQuickstart():
            apiClient = ApiClient(self._config, self.logger)
            self.registry = Registry(apiClient)
            self.status = Status(apiClient)
            self.usage = Usage(apiClient)
            self.dsc = DSC(apiClient)
            self.lec = LEC(apiClient)
            self.mgmt = Mgmt(apiClient)
            self.serviceBindings = ServiceBindings(apiClient)
コード例 #4
0
class ApplicationClient(AbstractClient):
    """
    Extends #wiotp.AbstractClient to implement an application client supporting 
    messaging over MQTT
        
    # Parameters
    options (dict): Configuration options for the client
    logHandlers (list<logging.Handler>): Log handlers to configure.  Defaults to `None`, 
        which will result in a default log handler being created.
    
    # Configuration Options
    The options parameter expects a Python dictionary containing the following keys:
    
    - `auth-key` The API key to to securely connect your application to Watson IoT Platform.
    - `auth-token` An authentication token to securely connect your application to Watson IoT Platform.
    - `clean-session` A boolean value indicating whether to use MQTT clean session.
    """

    def __init__(self, config, logHandlers=None):
        self._config = ApplicationClientConfig(**config)
        # Call parent constructor
        AbstractClient.__init__(
            self,
            domain=self._config.domain,
            organization=self._config.orgId,
            clientId=self._config.clientId,
            username=self._config.username,
            password=self._config.password,
            logHandlers=logHandlers,
            cleanStart=self._config.cleanStart,
            port=self._config.port,
            transport=self._config.transport,
            caFile=self._config.caFile,
        )

        # Add handlers for events and status
        self.client.message_callback_add("iot-2/type/+/id/+/evt/+/fmt/+", self._onDeviceEvent)
        self.client.message_callback_add("iot-2/type/+/id/+/mon", self._onDeviceStatus)
        self.client.message_callback_add("iot-2/app/+/mon", self._onAppStatus)
        self.client.message_callback_add("iot-2/type/+/id/+/intf/+/evt/state", self._onDeviceState)
        self.client.message_callback_add("iot-2/thing/type/+/id/+/intf/+/evt/state", self._onThingState)
        self.client.message_callback_add("iot-2/type/+/id/+/err/data", self._onErrorTopic)
        self.client.message_callback_add("iot-2/thing/type/+/id/+/err/data", self._onThingError)

        # Add handler for commands if not connected to QuickStart
        if not self._config.isQuickstart():
            self.client.message_callback_add("iot-2/type/+/id/+/cmd/+/fmt/+", self._onDeviceCommand)

        # Attach fallback handler
        self.client.on_message = self._onUnsupportedMessage

        # Initialize user supplied callbacks
        self.deviceEventCallback = None
        self.deviceCommandCallback = None
        self.deviceStateCallback = None
        self.deviceStatusCallback = None
        self.thingStateCallback = None
        self.errorTopicCallback = None
        self.appStatusCallback = None

        # Create an api client if not connected in QuickStart mode
        if not self._config.isQuickstart():
            apiClient = ApiClient(self._config, self.logger)
            self.registry = Registry(apiClient)
            self.usage = Usage(apiClient)
            self.dsc = DSC(apiClient)
            self.lec = LEC(apiClient)
            self.mgmt = Mgmt(apiClient)
            self.serviceBindings = ServiceBindings(apiClient)
            self.actions = Actions(apiClient)
            self.state = StateMgr(apiClient)

            # We directly expose the get() method via self.serviceStatus()
            self._serviceStatus = ServiceStatus(apiClient)

    def serviceStatus(self):
        if not self._config.isQuickstart():
            return self._serviceStatus.get()
        else:
            return None

    def subscribeToDeviceEvents(self, typeId="+", deviceId="+", eventId="+", msgFormat="+", qos=0):
        """
        Subscribe to device event messages

        # Parameters
        typeId (string): typeId for the subscription, optional.  Defaults to all device types (MQTT `+` wildcard)
        deviceId (string): deviceId for the subscription, optional.  Defaults to all devices (MQTT `+` wildcard)
        eventId (string): eventId for the subscription, optional.  Defaults to all events (MQTT `+` wildcard)
        msgFormat (string): msgFormat for the subscription, optional.  Defaults to all formats (MQTT `+` wildcard)
        qos (int): MQTT quality of service level to use (`0`, `1`, or `2`)

        # Returns
        int: If the subscription was successful then the return Message ID (mid) for the subscribe request
            will be returned. The mid value can be used to track the subscribe request by checking against
            the mid argument if you register a subscriptionCallback method.
            If the subscription fails then the return value will be `0`
        """
        if self._config.isQuickstart() and deviceId == "+":
            self.logger.warning(
                "QuickStart applications do not support wildcard subscription to events from all devices"
            )
            return 0

        topic = "iot-2/type/%s/id/%s/evt/%s/fmt/%s" % (typeId, deviceId, eventId, msgFormat)
        return self._subscribe(topic, qos)

    def subscribeToDeviceStatus(self, typeId="+", deviceId="+"):
        """
        Subscribe to device status messages

        # Parameters
        typeId (string): typeId for the subscription, optional.  Defaults to all device types (MQTT `+` wildcard)
        deviceId (string): deviceId for the subscription, optional.  Defaults to all devices (MQTT `+` wildcard)

        # Returns
        int: If the subscription was successful then the return Message ID (mid) for the subscribe request
            will be returned. The mid value can be used to track the subscribe request by checking against
            the mid argument if you register a subscriptionCallback method.
            If the subscription fails then the return value will be `0`
        """
        if self._config.isQuickstart() and deviceId == "+":
            self.logger.warning("QuickStart applications do not support wildcard subscription to device status")
            return 0

        topic = "iot-2/type/%s/id/%s/mon" % (typeId, deviceId)
        return self._subscribe(topic, 0)

    def subscribeToErrorTopic(self, typeId="+", Id="+"):
        """
        Subscribe to device error messages

        # Parameters
        typeId (string): typeId for the subscription, optional.  Defaults to all device types (MQTT `+` wildcard)
        Id (string): deviceId for the subscription, optional.  Defaults to all devices (MQTT `+` wildcard)

        # Returns
        int: If the subscription was successful then the return Message ID (mid) for the subscribe request
            will be returned. The mid value can be used to track the subscribe request by checking against
            the mid argument if you register a subscriptionCallback method.
            If the subscription fails then the return value will be `0`
        """
        if self._config.isQuickstart() and Id == "+":
            self.logger.warning("QuickStart applications do not support wildcard subscription to error topics")
            return 0

        topic = "iot-2/type/%s/id/%s/err/data" % (typeId, Id)
        return self._subscribe(topic, 0)

    def subscribeToThingErrors(self, typeId="+", Id="+"):
        """
        Subscribe to thingerror messages

        # Parameters
        typeId (string): typeId for the subscription, optional.  Defaults to all thing types (MQTT `+` wildcard)
        Id (string): thingId for the subscription, optional.  Defaults to all things (MQTT `+` wildcard)

        # Returns
        int: If the subscription was successful then the return Message ID (mid) for the subscribe request
            will be returned. The mid value can be used to track the subscribe request by checking against
            the mid argument if you register a subscriptionCallback method.
            If the subscription fails then the return value will be `0`
        """
        if self._config.isQuickstart() and Id == "+":
            self.logger.warning("QuickStart applications do not support wildcard subscription to error topics")
            return 0

        topic = "iot-2/thing/type/%s/id/%s/err/data" % (typeId, Id)
        return self._subscribe(topic, 0)

    def subscribeToThingState(self, typeId="+", thingId="+", logicalInterfaceId="+"):
        """
        Subscribe to thing state messages

        # Parameters
        typeId (string): typeId for the subscription, optional.  Defaults to all thing types (MQTT `+` wildcard)
        thingId (string): thingId for the subscription, optional.  Defaults to all things (MQTT `+` wildcard)
        logicalInterfaceId (string): logicalInterfaceId for the subscription, optional.  Defaults to all LIs (MQTT `+` wildcard)

        # Returns
        int: If the subscription was successful then the return Message ID (mid) for the subscribe request
            will be returned. The mid value can be used to track the subscribe request by checking against
            the mid argument if you register a subscriptionCallback method.
            If the subscription fails then the return value will be `0`
        """
        if self._config.isQuickstart():
            self.logger.warning("QuickStart applications do not support thing state")
            return 0

        topic = "iot-2/thing/type/%s/id/%s/intf/%s/evt/state" % (typeId, thingId, logicalInterfaceId)
        return self._subscribe(topic, 0)

    def subscribeToDeviceState(self, typeId="+", deviceId="+", logicalInterfaceId="+"):
        """
        Subscribe to device state messages

        # Parameters
        typeId (string): typeId for the subscription, optional.  Defaults to all thing types (MQTT `+` wildcard)
        deviceId (string): thingId for the subscription, optional.  Defaults to all devices (MQTT `+` wildcard)
        logicalInterfaceId (string): logicalInterfaceId for the subscription, optional.  Defaults to all LIs (MQTT `+` wildcard)

        # Returns
        int: If the subscription was successful then the return Message ID (mid) for the subscribe request
            will be returned. The mid value can be used to track the subscribe request by checking against
            the mid argument if you register a subscriptionCallback method.
            If the subscription fails then the return value will be `0`
        """
        if self._config.isQuickstart():
            self.logger.warning("QuickStart applications do not support device state")
            return 0

        topic = "iot-2/type/%s/id/%s/intf/%s/evt/state" % (typeId, deviceId, logicalInterfaceId)
        return self._subscribe(topic, 0)

    def subscribeToDeviceCommands(self, typeId="+", deviceId="+", commandId="+", msgFormat="+"):
        """
        Subscribe to device command messages

        # Parameters
        typeId (string): typeId for the subscription, optional.  Defaults to all device types (MQTT `+` wildcard)
        deviceId (string): deviceId for the subscription, optional.  Defaults to all devices (MQTT `+` wildcard)
        commandId (string): commandId for the subscription, optional.  Defaults to all commands (MQTT `+` wildcard)
        msgFormat (string): msgFormat for the subscription, optional.  Defaults to all formats (MQTT `+` wildcard)
        qos (int): MQTT quality of service level to use (`0`, `1`, or `2`)

        # Returns
        int: If the subscription was successful then the return Message ID (mid) for the subscribe request
            will be returned. The mid value can be used to track the subscribe request by checking against
            the mid argument if you register a subscriptionCallback method.
            If the subscription fails then the return value will be `0`
        """
        if self._config.isQuickstart():
            self.logger.warning("QuickStart applications do not support commands")
            return 0

        topic = "iot-2/type/%s/id/%s/cmd/%s/fmt/%s" % (typeId, deviceId, commandId, msgFormat)
        return self._subscribe(topic, 0)

    def publishEvent(self, typeId, deviceId, eventId, msgFormat, data, qos=0, onPublish=None):
        topic = "iot-2/type/%s/id/%s/evt/%s/fmt/%s" % (typeId, deviceId, eventId, msgFormat)
        return self._publishEvent(topic, eventId, msgFormat, data, qos, onPublish)

    def publishCommand(self, typeId, deviceId, commandId, msgFormat, data=None, qos=0, onPublish=None):
        """
        Publish a command to a device

        # Parameters
        typeId (string) : The type of the device this command is to be published to
        deviceId (string): The id of the device this command is to be published to
        command (string) : The name of the command
        msgFormat (string) : The format of the command payload
        data (dict) : The command data
        qos (int) : The equivalent MQTT semantics of quality of service using the same constants (optional, defaults to `0`)
        onPublish (function) : A function that will be called when receipt of the publication is confirmed.  This has
            different implications depending on the qos:
            - qos 0 : the client has asynchronously begun to send the event
            - qos 1 and 2 : the client has confirmation of delivery from WIoTP
        """
        if self._config.isQuickstart():
            self.logger.warning("QuickStart applications do not support sending commands")
            return False
        if not self.connectEvent.wait(timeout=10):
            return False
        else:
            topic = "iot-2/type/%s/id/%s/cmd/%s/fmt/%s" % (typeId, deviceId, commandId, msgFormat)

            # Raise an exception if there is no codec for this msgFormat
            if self.getMessageCodec(msgFormat) is None:
                raise MissingMessageEncoderException(msgFormat)

            payload = self.getMessageCodec(msgFormat).encode(data, datetime.now())
            result = self.client.publish(topic, payload=payload, qos=qos, retain=False)
            if result[0] == paho.MQTT_ERR_SUCCESS:
                # Because we are dealing with aync pub/sub model and callbacks it is possible that
                # the _onPublish() callback for this mid is called before we obtain the lock to place
                # the mid into the _onPublishCallbacks list.
                #
                # _onPublish knows how to handle a scenario where the mid is not present (no nothing)
                # in this scenario we will need to invoke the callback directly here, because at the time
                # the callback was invoked the mid was not yet in the list.
                with self._messagesLock:
                    if result[1] in self._onPublishCallbacks:
                        # paho callback beat this thread so call callback inline now
                        del self._onPublishCallbacks[result[1]]
                        if onPublish is not None:
                            onPublish()
                    else:
                        # this thread beat paho callback so set up for call later
                        self._onPublishCallbacks[result[1]] = onPublish
                return True
            else:
                return False

    def _onUnsupportedMessage(self, client, userdata, message):
        """
        Internal callback for messages that have not been handled by any of the specific internal callbacks, these
        messages are not passed on to any user provided callback
        """
        self.logger.warning(
            "Received messaging on unsupported topic '%s' on topic '%s'" % (message.payload, message.topic)
        )

    def _onDeviceEvent(self, client, userdata, pahoMessage):
        """
        Internal callback for device event messages, parses source device from topic string and
        passes the information on to the registerd device event callback
        """
        try:
            event = Event(pahoMessage, self._messageCodecs)
            self.logger.debug("Received event '%s' from %s:%s" % (event.eventId, event.typeId, event.deviceId))
            if self.deviceEventCallback:
                self.deviceEventCallback(event)
        except InvalidEventException as e:
            self.logger.critical(str(e))

    def _onThingState(self, client, userdata, pahoMessage):
        """
        Internal callback for thing state messages, parses source thing from topic string and
        passes the information on to the registerd thing state callback
        """
        try:
            state = State(pahoMessage)
            self.logger.debug("Received state from %s:%s" % (state.typeId, state.thingId))
            if self.thingStateCallback:
                self.thingStateCallback(state)
        except InvalidEventException as e:
            self.logger.critical(str(e))

    def _onDeviceState(self, client, userdata, pahoMessage):
        """
        Internal callback for thing state messages, parses source thing from topic string and
        passes the information on to the registerd thing state callback
        """
        try:
            state = DeviceState(pahoMessage)
            self.logger.debug("Received state from %s:%s" % (state.typeId, state.deviceId))
            if self.deviceStateCallback:
                self.deviceStateCallback(state)
        except InvalidEventException as e:
            self.logger.critical(str(e))

    def _onErrorTopic(self, client, userdata, pahoMessage):
        """
        Internal callback for error messages, parses source thing/device from topic string and
        passes the information on to the registerd error callback
        """
        try:
            error = Error(pahoMessage)
            self.logger.debug("Received error from device %s:%s" % (error.typeId, error.id))
            if self.errorTopicCallback:
                self.errorTopicCallback(error)
        except InvalidEventException as e:
            self.logger.critical(str(e))

    def _onThingError(self, client, userdata, pahoMessage):
        """
        Internal callback for error messages, parses source thing/device from topic string and
        passes the information on to the registerd error callback
        """
        try:
            error = ThingError(pahoMessage)
            self.logger.debug("Received error from thing %s:%s" % (error.typeId, error.id))
            if self.errorTopicCallback:
                self.errorTopicCallback(error)
        except InvalidEventException as e:
            self.logger.critical(str(e))

    def _onDeviceCommand(self, client, userdata, pahoMessage):
        """
        Internal callback for device command messages, parses source device from topic string and
        passes the information on to the registerd device command callback
        """
        try:
            command = Command(pahoMessage, self._messageCodecs)
            self.logger.debug(
                "Received command '%s' from %s:%s" % (command.commandId, command.typeId, command.deviceId)
            )
            if self.deviceCommandCallback:
                self.deviceCommandCallback(command)
        except InvalidEventException as e:
            self.logger.critical(str(e))

    def _onDeviceStatus(self, client, userdata, pahoMessage):
        """
        Internal callback for device status messages, parses source device from topic string and
        passes the information on to the registerd device status callback
        """
        try:
            status = Status(pahoMessage)
            self.logger.debug("Received %s action from %s" % (status.action, status.clientId))
            if self.deviceStatusCallback:
                self.deviceStatusCallback(status)
        except InvalidEventException as e:
            self.logger.critical(str(e))

    def _onAppStatus(self, client, userdata, pahoMessage):
        """
        Internal callback for application command messages, parses source application from topic string and
        passes the information on to the registerd applicaion status callback
        """
        try:
            status = Status(pahoMessage)
            self.logger.debug("Received %s action from %s" % (status.action, status.clientId))
            if self.appStatusCallback:
                self.appStatusCallback(status)
        except InvalidEventException as e:
            self.logger.critical(str(e))
コード例 #5
0
ファイル: client.py プロジェクト: cclauss/iot-python
class ApplicationClient(AbstractClient):
    """
    Extends #wiotp.AbstractClient to implement an application client supporting 
    messaging over MQTT
        
    # Parameters
    options (dict): Configuration options for the client
    logHandlers (list<logging.Handler>): Log handlers to configure.  Defaults to `None`, 
        which will result in a default log handler being created.
    
    # Configuration Options
    The options parameter expects a Python dictionary containing the following keys:
    
    - `auth-key` The API key to to securely connect your application to Watson IoT Platform.
    - `auth-token` An authentication token to securely connect your application to Watson IoT Platform.
    - `clean-session` A boolean value indicating whether to use MQTT clean session.
    """

    def __init__(self, config, logHandlers=None):
        self._config = ApplicationClientConfig(**config)
        # Call parent constructor
        AbstractClient.__init__(
            self,
            domain=self._config.domain,
            organization=self._config.orgId,
            clientId=self._config.clientId,
            username=self._config.username,
            password=self._config.password,
            logHandlers=logHandlers,
            cleanStart=self._config.cleanStart,
            port=self._config.port,
            transport=self._config.transport,
        )

        # Add handlers for events and status
        self.client.message_callback_add("iot-2/type/+/id/+/evt/+/fmt/+", self._onDeviceEvent)
        self.client.message_callback_add("iot-2/type/+/id/+/mon", self._onDeviceStatus)
        self.client.message_callback_add("iot-2/app/+/mon", self._onAppStatus)

        # Add handler for commands if not connected to QuickStart
        if not self._config.isQuickstart():
            self.client.message_callback_add("iot-2/type/+/id/+/cmd/+/fmt/+", self._onDeviceCommand)

        # Attach fallback handler
        self.client.on_message = self._onUnsupportedMessage

        # Initialize user supplied callbacks
        self.deviceEventCallback = None
        self.deviceCommandCallback = None
        self.deviceStatusCallback = None
        self.appStatusCallback = None

        # Create an api client if not connected in QuickStart mode
        if not self._config.isQuickstart():
            apiClient = ApiClient(self._config, self.logger)
            self.registry = Registry(apiClient)
            self.status = Status(apiClient)
            self.usage = Usage(apiClient)
            self.dsc = DSC(apiClient)
            self.lec = LEC(apiClient)
            self.mgmt = Mgmt(apiClient)
            self.serviceBindings = ServiceBindings(apiClient)

    def subscribeToDeviceEvents(self, typeId="+", deviceId="+", eventId="+", msgFormat="+", qos=0):
        """
        Subscribe to device event messages

        # Parameters
        typeId (string): typeId for the subscription, optional.  Defaults to all device types (MQTT `+` wildcard)
        deviceId (string): deviceId for the subscription, optional.  Defaults to all devices (MQTT `+` wildcard)
        eventId (string): eventId for the subscription, optional.  Defaults to all events (MQTT `+` wildcard)
        msgFormat (string): msgFormat for the subscription, optional.  Defaults to all formats (MQTT `+` wildcard)
        qos (int): MQTT quality of service level to use (`0`, `1`, or `2`)

        # Returns
        int: If the subscription was successful then the return Message ID (mid) for the subscribe request
            will be returned. The mid value can be used to track the subscribe request by checking against
            the mid argument if you register a subscriptionCallback method.
            If the subscription fails then the return value will be `0`
        """
        if self._config.isQuickstart() and deviceId == "+":
            self.logger.warning(
                "QuickStart applications do not support wildcard subscription to events from all devices"
            )
            return 0

        topic = "iot-2/type/%s/id/%s/evt/%s/fmt/%s" % (typeId, deviceId, eventId, msgFormat)
        return self._subscribe(topic, qos)

    def subscribeToDeviceStatus(self, typeId="+", deviceId="+"):
        """
        Subscribe to device status messages

        # Parameters
        typeId (string): typeId for the subscription, optional.  Defaults to all device types (MQTT `+` wildcard)
        deviceId (string): deviceId for the subscription, optional.  Defaults to all devices (MQTT `+` wildcard)

        # Returns
        int: If the subscription was successful then the return Message ID (mid) for the subscribe request
            will be returned. The mid value can be used to track the subscribe request by checking against
            the mid argument if you register a subscriptionCallback method.
            If the subscription fails then the return value will be `0`
        """
        if self._config.isQuickstart() and deviceId == "+":
            self.logger.warning("QuickStart applications do not support wildcard subscription to device status")
            return 0

        topic = "iot-2/type/%s/id/%s/mon" % (typeId, deviceId)
        return self._subscribe(topic, 0)

    def subscribeToDeviceCommands(self, typeId="+", deviceId="+", commandId="+", msgFormat="+"):
        """
        Subscribe to device command messages

        # Parameters
        typeId (string): typeId for the subscription, optional.  Defaults to all device types (MQTT `+` wildcard)
        deviceId (string): deviceId for the subscription, optional.  Defaults to all devices (MQTT `+` wildcard)
        commandId (string): commandId for the subscription, optional.  Defaults to all commands (MQTT `+` wildcard)
        msgFormat (string): msgFormat for the subscription, optional.  Defaults to all formats (MQTT `+` wildcard)
        qos (int): MQTT quality of service level to use (`0`, `1`, or `2`)

        # Returns
        int: If the subscription was successful then the return Message ID (mid) for the subscribe request
            will be returned. The mid value can be used to track the subscribe request by checking against
            the mid argument if you register a subscriptionCallback method.
            If the subscription fails then the return value will be `0`
        """
        if self._config.isQuickstart():
            self.logger.warning("QuickStart applications do not support commands")
            return 0

        topic = "iot-2/type/%s/id/%s/cmd/%s/fmt/%s" % (typeId, deviceId, commandId, msgFormat)
        return self._subscribe(topic, 0)

    def publishEvent(self, typeId, deviceId, eventId, msgFormat, data, qos=0, on_publish=None):
        topic = "iot-2/type/%s/id/%s/evt/%s/fmt/%s" % (typeId, deviceId, eventId, msgFormat)
        return self._publishEvent(topic, eventId, msgFormat, data, qos, on_publish)

    def publishCommand(self, typeId, deviceId, commandId, msgFormat, data=None, qos=0, on_publish=None):
        """
        Publish a command to a device

        # Parameters
        typeId (string) : The type of the device this command is to be published to
        deviceId (string): The id of the device this command is to be published to
        command (string) : The name of the command
        msgFormat (string) : The format of the command payload
        data (dict) : The command data
        qos (int) : The equivalent MQTT semantics of quality of service using the same constants (optional, defaults to `0`)
        on_publish (function) : A function that will be called when receipt of the publication is confirmed.  This has
            different implications depending on the qos:
            - qos 0 : the client has asynchronously begun to send the event
            - qos 1 and 2 : the client has confirmation of delivery from WIoTP
        """
        if self._config.isQuickstart():
            self.logger.warning("QuickStart applications do not support sending commands")
            return False
        if not self.connectEvent.wait(timeout=10):
            return False
        else:
            topic = "iot-2/type/%s/id/%s/cmd/%s/fmt/%s" % (typeId, deviceId, commandId, msgFormat)

            # Raise an exception if there is no codec for this msgFormat
            if self.getMessageCodec(msgFormat) is None:
                raise MissingMessageEncoderException(msgFormat)

            payload = self.getMessageCodec(msgFormat).encode(data, datetime.now())
            result = self.client.publish(topic, payload=payload, qos=qos, retain=False)
            if result[0] == paho.MQTT_ERR_SUCCESS:
                # Because we are dealing with aync pub/sub model and callbacks it is possible that
                # the _onPublish() callback for this mid is called before we obtain the lock to place
                # the mid into the _onPublishCallbacks list.
                #
                # _onPublish knows how to handle a scenario where the mid is not present (no nothing)
                # in this scenario we will need to invoke the callback directly here, because at the time
                # the callback was invoked the mid was not yet in the list.
                with self._messagesLock:
                    if result[1] in self._onPublishCallbacks:
                        # paho callback beat this thread so call callback inline now
                        del self._onPublishCallbacks[result[1]]
                        if on_publish is not None:
                            on_publish()
                    else:
                        # this thread beat paho callback so set up for call later
                        self._onPublishCallbacks[result[1]] = on_publish
                return True
            else:
                return False

    def _onUnsupportedMessage(self, client, userdata, message):
        """
        Internal callback for messages that have not been handled by any of the specific internal callbacks, these
        messages are not passed on to any user provided callback
        """
        self.logger.warning(
            "Received messaging on unsupported topic '%s' on topic '%s'" % (message.payload, message.topic)
        )

    def _onDeviceEvent(self, client, userdata, pahoMessage):
        """
        Internal callback for device event messages, parses source device from topic string and
        passes the information on to the registerd device event callback
        """
        try:
            event = Event(pahoMessage, self._messageCodecs)
            self.logger.debug("Received event '%s' from %s:%s" % (event.eventId, event.typeId, event.deviceId))
            if self.deviceEventCallback:
                self.deviceEventCallback(event)
        except InvalidEventException as e:
            self.logger.critical(str(e))

    def _onDeviceCommand(self, client, userdata, pahoMessage):
        """
        Internal callback for device command messages, parses source device from topic string and
        passes the information on to the registerd device command callback
        """
        try:
            command = Command(pahoMessage, self._messageCodecs)
            self.logger.debug(
                "Received command '%s' from %s:%s" % (command.commandId, command.typeId, command.deviceId)
            )
            if self.deviceCommandCallback:
                self.deviceCommandCallback(command)
        except InvalidEventException as e:
            self.logger.critical(str(e))

    def _onDeviceStatus(self, client, userdata, pahoMessage):
        """
        Internal callback for device status messages, parses source device from topic string and
        passes the information on to the registerd device status callback
        """
        try:
            status = Status(pahoMessage)
            self.logger.debug("Received %s action from %s" % (status.action, status.clientId))
            if self.deviceStatusCallback:
                self.deviceStatusCallback(status)
        except InvalidEventException as e:
            self.logger.critical(str(e))

    def _onAppStatus(self, client, userdata, pahoMessage):
        """
        Internal callback for application command messages, parses source application from topic string and
        passes the information on to the registerd applicaion status callback
        """
        try:
            status = Status(pahoMessage)
            self.logger.debug("Received %s action from %s" % (status.action, status.clientId))
            if self.appStatusCallback:
                self.appStatusCallback(status)
        except InvalidEventException as e:
            self.logger.critical(str(e))