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
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