docs: def publish(self, topic, payload=None, qos=0, retain=False):
          # type: (str, bytes, int, bool) -> Tuple[int, int]
          """
          Send a message to the broker.
  
          :param topic: the topic that the message should be published on
          :param payload: the actual message to send. If not given, or set to
                          None a zero length message will be used. Passing an
                          int or float will result in the payload being
                          converted to a string representing that number.
                          If you wish to send a true int/float, use struct.pack()
                          to create the payload you require.
          :param qos: the quality of service level to use
          :param retain: if set to True, the message will be set as the
                         "last known good"/retained message for the topic
  
          :returns: Returns a tuple (result, mid), where result is
                    MQTT_ERR_SUCCESS to indicate success or MQTT_ERR_NO_CONN
                    if the client is not currently connected. mid is the message
                    ID for the publish request.
  
          """
          if not self.connected:
              self.client.reconnect()
  
          result, mid = self.client.publish(topic, payload, qos, retain)
          if result == MQTT_ERR_SUCCESS:
              logger.debug('Published topic {0}: {1}'.format(topic, payload))
          else:
              logger.error('Error {0} publishing topic {1}'
                           .format(result, topic))
  
          return (result, mid)