예제 #1
0
    def setup_mqtt_conn(self, *args, **kwargs):
        '''
        Setup a mqtt connection and manage it.

        For the available parameters, please check out
        :py:class:`paho.mqtt.client.Client`

        A var ``self._mqtt_c`` will be setup.

        This call will block until the mqtt server connected.
        '''
        self._mqtt_c_lock = SimpleLock()
        self._mqtt_c_lock.acquire()

        client = mqtt.Client()
        client.on_connect = self.mqtt_on_connect
        client.on_disconnect = self.mqtt_on_disconnect
        client.on_subscribe = self.mqtt_on_subscribe
        client.connect(*args, **kwargs)
        client.loop_start()

        self._mqtt_c = client
        if not self._mqtt_c_lock.acquire(timeout=10):
            raise RuntimeError('Connect to mqtt server timeout')
        del self._mqtt_c_lock
예제 #2
0
class MQTTConnMgrMixin(object):
    '''
    Connection Manager MQTT Mixin

    .. todo::
        - reconnect
    '''

    _mqtt_c = None

    def __init__(self):
        super(MQTTConnMgrMixin, self).__init__()
        self.mqtt_connected = False

    def __del__(self):
        super(MQTTConnMgrMixin, self).__del__()
        if self.mqtt_c is not None:
            self.mqtt_c.disconnect()
            self.mqtt_c.loop_stop()

    @property
    def mqtt_c(self):
        '''
        The ``paho.mqtt.client.Client`` instance
        '''
        if self._mqtt_c is None:
            raise AttributeError(
                'Please create client via ``setup_mqtt_conn`` first.')
        return self._mqtt_c

    def setup_mqtt_conn(self, *args, **kwargs):
        '''
        Setup a mqtt connection and manage it.

        For the available parameters, please check out
        :py:class:`paho.mqtt.client.Client`

        A var ``self._mqtt_c`` will be setup.

        This call will block until the mqtt server connected.
        '''
        self._mqtt_c_lock = SimpleLock()
        self._mqtt_c_lock.acquire()

        client = mqtt.Client()
        client.on_connect = self.mqtt_on_connect
        client.on_disconnect = self.mqtt_on_disconnect
        client.on_subscribe = self.mqtt_on_subscribe
        client.connect(*args, **kwargs)
        client.loop_start()

        self._mqtt_c = client
        if not self._mqtt_c_lock.acquire(timeout=10):
            raise RuntimeError('Connect to mqtt server timeout')
        del self._mqtt_c_lock

    def mqtt_on_connect(self, client, userdata, flags, rc):
        '''
        The MQTT client connect callback
        '''
        if rc != 0:
            self._mqtt_c_lock.release()
            msg = 'MQTT server connection refused, code {}'.format(rc)
            log.error(msg)
            raise IOError(msg)

        log.info('Connect to mqtt server successfully')
        self.mqtt_connected = True
        self._mqtt_c_lock.release()

    def mqtt_on_disconnect(self, client, userdata, rc):
        '''
        The MQTT client disconnect callback
        '''
        log.info('MQTT server disconnected')
        self.mqtt_connected = False

    def mqtt_on_subscribe(self, client, userdata, mid, granted_qos):
        '''
        :param mid: the message id returned by ``Client.subscribe``
        '''
        pass

    def mqtt_sub(self, id_, feature, topic, qos=0):
        '''
        Subscribe to a mqtt topic.

        :param id_: the ``UUID`` object
        :param feature: the feature name, if feature name is ``_ctrl``, we will
                        setup the control channel.
        :param topic: the mqtt topic, e.g: ``uuid/feature/i``.
        :param qos: the mqtt qos level, should be 0, 1, 2
        :param ctrl: control channel or not
        :return: a function accept a *on message* callback.
                 This returned function also has following
                 function attributes:

                 :func.cb: the using callback will be stored here.
                 :func.client: the ``paho.mqtt.client.Client`` instance
                 :func.feature: the feature name related to the subscription
                 :func.id: the ``UUID`` object
                 :func.remove_callback: the function for unsubscribing topic
                 :func.topic: the mqtt topic
        '''
        def f(callback):
            if f.cb is not None:
                f.client.message_callback_remove(f.topic)
            f.client.message_callback_add(f.topic, callback)
            f.cb = callback
            return callback

        f.cb = None
        f.client = self.mqtt_c
        f.feature = feature
        f.id = id_
        f.topic = topic
        f.remove_callback = partial(
            self.mqtt_c.message_callback_remove, f.topic)

        self.mqtt_c.subscribe(topic, qos=qos)

        if feature != '_ctrl':
            self.conns[id_].data[feature].i = f
        else:
            self.conns[id_].ctrl.sub = f

        return f

    def mqtt_pub(self, id_, feature, topic, qos=0):
        '''
        Add a publish function to ``self.conns``.

        :param id_: the ``UUID`` object
        :param feature: the feature name, if feature name is ``_ctrl``, we will
                        setup the control channel
        :param ctrl: control channel or not
        :type topic: str

        :return: the ``publish`` function
        '''
        if feature != '_ctrl':
            pub = partial(self.mqtt_c.publish, topic, qos=qos)
            self.conns[id_].data[feature].o = pub
        else:
            pub = partial(mqtt_json_pub(self.mqtt_c.publish), topic, qos=qos)
            self.conns[id_].ctrl.pub = pub

        return pub

    def mqtt_ctrl(self, id_, pub_topic, sub_topic, rev):
        '''
        :param id_: the ``UUID`` object
        :param pub_topic:
        :param sub_topic:
        :param rev:
        '''
        pub = self.mqtt_pub(id_, '_ctrl', pub_topic)
        sub = self.mqtt_sub(id_, '_ctrl', sub_topic)
        self.conns[id_].ctrl.rev = rev
        return pub, sub