text: import json
  
  import paho.mqtt.client as mqtt
  import logger
  
  LWT_ONLINE = "online"
  LWT_OFFLINE = "offline"
  _LOGGER = logger.get(__name__)
  
  
  class MqttClient:
      def __init__(self, config):
          self._config = config
          self._mqttc = mqtt.Client(
              client_id=self.client_id,
              clean_session=False,
              userdata={"global_topic_prefix": self.topic_prefix},
          )
  
          if self.username and self.password:
              self.mqttc.username_pw_set(self.username, self.password)
  
          if self.ca_cert:
              cert_reqs = mqtt.ssl.CERT_REQUIRED if self.ca_verify else mqtt.ssl.CERT_NONE
              self.mqttc.tls_set(self.ca_cert, cert_reqs=cert_reqs)
              self.mqttc.tls_insecure_set(not self.ca_verify)
  
          if self.availability_topic:
              topic = self._format_topic(self.availability_topic)
              _LOGGER.debug("Setting LWT to: %s" % topic)
              self.mqttc.will_set(topic, payload=LWT_OFFLINE, retain=True)
  
      def publish(self, messages):
          if not messages:
              return
  
          for m in messages:
              if m.use_global_prefix:
                  topic = self._format_topic(m.topic)
              else:
                  topic = m.topic
              self.mqttc.publish(topic, m.payload, retain=m.retain)
  
      @property
      def client_id(self):
          return (
              self._config["client_id"]
              if "client_id" in self._config
              else "bt-mqtt-gateway"
          )
  
      @property
      def hostname(self):
          return self._config["host"]
  
      @property
      def port(self):
          return self._config["port"] if "port" in self._config else 1883
  
      @property
      def username(self):
          return str(self._config["username"]) if "username" in self._config else None
  
      @property
      def password(self):
          return str(self._config["password"]) if "password" in self._config else None
  
      @property
      def ca_cert(self):
          return self._config["ca_cert"] if "ca_cert" in self._config else None
  
      @property
      def ca_verify(self):
          if "ca_verify" in self._config:
              # Constrain config input to boolean value
              if self._config["ca_verify"]:
                  return True
              else:
                  return False
          else:
              return True
  
      @property
      def topic_prefix(self):
          return self._config["topic_prefix"] if "topic_prefix" in self._config else None
  
      @property
      def availability_topic(self):
          return (
              self._config["availability_topic"]
              if "availability_topic" in self._config
              else None
          )
  
      @property
      def mqttc(self):
          return self._mqttc
  
      # noinspection PyUnusedLocal
      def on_connect(self, client, userdata, flags, rc):
          if self.availability_topic:
              self.publish(
                  [
                      MqttMessage(
                          topic=self.availability_topic, payload=LWT_ONLINE, retain=True
                      )
                  ]
              )
  
      def callbacks_subscription(self, callbacks):
          self.mqttc.on_connect = self.on_connect
  
          self.mqttc.connect(self.hostname, port=self.port)
  
          for topic, callback in callbacks:
              topic = self._format_topic(topic)
              _LOGGER.debug("Subscribing to: %s" % topic)
              self.mqttc.message_callback_add(topic, callback)
              self.mqttc.subscribe(topic)
  
          self.mqttc.loop_start()
  
      def __del__(self):
          if self.availability_topic:
              self.publish(
                  [
                      MqttMessage(
                          topic=self.availability_topic, payload=LWT_OFFLINE, retain=True
                      )
                  ]
              )
  
      def _format_topic(self, topic):
          return "{}/{}".format(self.topic_prefix, topic) if self.topic_prefix else topic
  
  
  class MqttMessage:
      use_global_prefix = True
  
      def __init__(self, topic=None, payload=None, retain=False):
          self._topic = topic
          self._payload = payload
          self._retain = retain
  
      @property
      def topic(self):
          return self._topic
  
      @topic.setter
      def topic(self, new_topic):
          self._topic = new_topic
  
      @property
      def payload(self):
          if isinstance(self.raw_payload, str):
              return self.raw_payload
          else:
              return json.dumps(self.raw_payload)
  
      @property
      def raw_payload(self):
          return self._payload
  
      @property
      def retain(self):
          return self._retain
  
      @retain.setter
      def retain(self, new_retain):
          self._retain = new_retain
  
      @property
      def as_dict(self):
          return {"topic": self.topic, "payload": self.payload}
  
      def __repr__(self):
          return self.as_dict.__str__()
  
      def __str__(self):
          return self.__repr__()
  
  
  class MqttConfigMessage(MqttMessage):
      SENSOR = "sensor"
      CLIMATE = "climate"
      BINARY_SENSOR = "binary_sensor"
  
      use_global_prefix = False
  
      def __init__(self, component, name, payload=None, retain=False):
          super().__init__("{}/{}/config".format(component, name), payload, retain)
  