Ejemplo n.º 1
0
    def _try_create_mqtt_client(self, hostname):
        minimqtt.set_socket(socket, self._wifi_manager.esp)

        self._mqtts = MQTT(
            broker=hostname,
            username=self._username,
            password=self._passwd,
            port=8883,
            keep_alive=120,
            is_ssl=True,
            client_id=self._device_id,
            log=True,
        )

        self._mqtts.logger.setLevel(logging.INFO)

        # set actions to take throughout connection lifecycle
        self._mqtts.on_connect = self._on_connect
        self._mqtts.on_message = self._on_message
        self._mqtts.on_log = self._on_log
        self._mqtts.on_publish = self._on_publish
        self._mqtts.on_disconnect = self._on_disconnect

        # initiate the connection using the adafruit_minimqtt library
        self._mqtts.last_will()
        self._mqtts.connect()
Ejemplo n.º 2
0
def _createMQTTClient(__self, username, passwd):
    print('User: '******'Password: ', passwd)
    __self._mqtts = MQTT(socket,
                         broker=__self._hostname,
                         username=username,
                         password=passwd,
                         network_manager=wifi_manager,
                         port=8883,
                         keep_alive=120,
                         is_ssl=True,
                         client_id=__self._deviceId,
                         log=True)

    __self._mqtts.logger.setLevel(logging.DEBUG)

    #__self._mqtts = mqtt.Client(client_id=__self._deviceId, protocol=mqtt.MQTTv311)
    __self._mqtts.on_connect = __self._onConnect
    __self._mqtts.on_message = __self._onMessage
    __self._mqtts.on_log = __self._onLog
    __self._mqtts.on_publish = __self._onPublish
    __self._mqtts.on_disconnect = __self._onDisconnect

    __self._mqtts.last_will()
    __self._mqtts.connect()
Ejemplo n.º 3
0
    def iot(self,type='mqtt',group='light-group',action=None,conn=None,disc=None):
        from adafruit_esp32spi import adafruit_esp32spi_wifimanager
        import adafruit_esp32spi.adafruit_esp32spi_socket as socket
        import adafruit_requests as requests
        from adafruit_io.adafruit_io import IO_HTTP

        from secrets import secrets
        from adafruit_io.adafruit_io import IO_MQTT
        from adafruit_minimqtt import MQTT
        if not self.hardware['ESP32']:
            raise
        if not action: action=self.message
        if not conn: conn=self.connected
        if not disc: disc=self.disconnected
        # try:
        requests.set_socket(socket,self._esp)
        self.WIFI = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(self._esp, secrets, status_pixel=None)
        self.group_name = group

        self.WIFI.connect()

        mqtt_client = MQTT(
        socket=socket,
        broker="io.adafruit.com",
        username=secrets["aio_username"],
        password=secrets["aio_key"],
        network_manager=self.WIFI
        )
        self.io = IO_MQTT(mqtt_client)
        self.io.on_connect = conn
        self.io.on_disconnect = disc
        self.io.on_message = action
        # else:
        #     return
        self.io.connect()
Ejemplo n.º 4
0
    def _create_mqtt_client(self) -> None:
        minimqtt.set_socket(self._socket, self._iface)

        self._mqtts = MQTT(
            broker=self._hostname,
            username=self._username,
            password=self._passwd,
            port=8883,
            keep_alive=120,
            is_ssl=True,
            client_id=self._device_id,
            log=True,
        )

        self._mqtts.logger.setLevel(self._logger.getEffectiveLevel())

        # set actions to take throughout connection lifecycle
        self._mqtts.on_connect = self._on_connect
        self._mqtts.on_log = self._on_log
        self._mqtts.on_publish = self._on_publish
        self._mqtts.on_disconnect = self._on_disconnect

        # initiate the connection using the adafruit_minimqtt library
        self._mqtts.connect()
Ejemplo n.º 5
0
    )
    raise

# Set Device Certificate
esp.set_certificate(DEVICE_CERT)

# Set Private Key
esp.set_private_key(DEVICE_KEY)

# Connect to WiFi
wifi.connect()

# Set up a MiniMQTT Client
client = MQTT(socket,
              broker=secrets['broker'],
              username=secrets['user'],
              password=secrets['pass'],
              network_manager=wifi)

# Connect callback handlers to client
client.on_connect = connect
client.on_disconnect = disconnect
client.on_subscribe = subscribe
client.on_unsubscribe = unsubscribe
client.on_publish = publish

print('Attempting to connect to %s' % client.broker)
client.connect()

print('Subscribing to %s' % mqtt_topic)
client.subscribe(mqtt_topic)
Ejemplo n.º 6
0
        pybadger.pixels.fill(val)
        time.sleep(0.1)

    # feed #1 on which we're listening to values of name is named name
    elif topic == secrets['aio_username'] + '/feeds/name':
        pybadger.show_badge(name_string=message,
                            hello_scale=2,
                            my_name_is_scale=2,
                            name_scale=3)


wifi.connect()

# Set up a MiniMQTT Client with broker address and api keys
mqtt_client = MQTT(socket,
                   broker='io.adafruit.com',
                   username=secrets['aio_username'],
                   password=secrets['aio_key'],
                   network_manager=wifi)

mqtt_client.on_connect = connected
mqtt_client.on_disconnect = disconnected
mqtt_client.on_message = message

# Connect the client to the MQTT broker.
print('Connecting to MQTT BROKER...')
mqtt_client.connect()

while True:
    # Poll the message queue forever (BLOCKING!!)
    mqtt_client.loop_forever()
Ejemplo n.º 7
0
# Set AWS Device Certificate
esp.set_certificate(DEVICE_CERT)

# Set AWS RSA Private Key
esp.set_private_key(DEVICE_KEY)

# Connect to WiFi
print("Connecting to WiFi...")
wifi.connect()
print("Connected!")

# Set up a new MiniMQTT Client
client =  MQTT(socket,
               broker = secrets['broker'],
               client_id = secrets['client_id'],
               network_manager = wifi,
               log=True)

# Initialize AWS IoT MQTT API Client
aws_iot = MQTT_CLIENT(client)

# Connect callback handlers to AWS IoT MQTT Client
aws_iot.on_connect = connect
aws_iot.on_disconnect = disconnect
aws_iot.on_subscribe = subscribe
aws_iot.on_unsubscribe = unsubscribe
aws_iot.on_publish = publish
aws_iot.on_message = message

print('Attempting to connect to %s'%client.broker)
Ejemplo n.º 8
0
# pylint: disable=unused-argument
def message(client, feed_id, payload):
    # Message function will be called when a subscribed feed has a new value.
    # The feed_id parameter identifies the feed, and the payload parameter has
    # the new value.
    print("Feed {0} received new value: {1}".format(feed_id, payload))


# Connect to WiFi
wifi.connect()

# Initialize a new MQTT Client object
mqtt_client = MQTT(socket=socket,
                   broker="io.adafruit.com",
                   username=secrets["aio_user"],
                   password=secrets["aio_key"],
                   network_manager=wifi)

# Initialize an Adafruit IO MQTT Client
io = IO_MQTT(mqtt_client)

# Connect the callback methods defined above to Adafruit IO
io.on_connect = connected
io.on_disconnect = disconnected
io.on_message = message

# Connect to Adafruit IO
io.connect()

# Below is an example of manually publishing a new  value to Adafruit IO.
Ejemplo n.º 9
0
    print('Disconnected from Adafruit IO!')


def message(client, topic, message):
    # This method is called when a topic the client is subscribed to
    # has a new message.
    print('New message on topic {0}: {1}'.format(topic, message))


# Connect to WiFi
wifi.connect()

# Set up a MiniMQTT Client
mqtt_client = MQTT(socket,
                   broker='io.adafruit.com',
                   username=secrets['aio_username'],
                   password=secrets['aio_key'],
                   network_manager=wifi)

# Setup the callback methods above
mqtt_client.on_connect = connected
mqtt_client.on_disconnect = disconnected
mqtt_client.on_message = message

# Connect the client to the MQTT broker.
print('Connecting to Adafruit IO...')
mqtt_client.connect()

photocell_val = 0
while True:
    # Poll the message queue
wifi.connect()
print("Connected!")

# Initialize Google Cloud IoT Core interface
google_iot = Cloud_Core(wifi, secrets, log=False)

# Optional JSON-Web-Token (JWT) Generation
# print("Generating JWT...")
# jwt = google_iot.generate_jwt()
# print("Your JWT is: ", jwt)

# Set up a new MiniMQTT Client
client = MQTT(socket,
              broker=google_iot.broker,
              username=google_iot.username,
              password=secrets['jwt'],
              client_id=google_iot.cid,
              network_manager=wifi,
              log=True)

# Initialize Google MQTT API Client
google_mqtt = MQTT_API(client)

# Connect callback handlers to Google MQTT Client
google_mqtt.on_connect = connect
google_mqtt.on_disconnect = disconnect
google_mqtt.on_subscribe = subscribe
google_mqtt.on_unsubscribe = unsubscribe
google_mqtt.on_publish = publish
google_mqtt.on_message = message
Ejemplo n.º 11
0
def message(client, topic, message):
    """Method callled when a client's subscribed feed has a new
    value.
    :param str topic: The topic of the feed with a new value.
    :param str message: The new value
    """
    print('New message on topic {0}: {1}'.format(topic, message))


# Connect to WiFi
wifi.connect()

# Set up a MiniMQTT Client
mqtt_client = MQTT(socket,
                   broker=secrets['broker'],
                   username=secrets['user'],
                   password=secrets['pass'],
                   network_manager=wifi)

# Setup the callback methods above
mqtt_client.on_connect = connected
mqtt_client.on_disconnect = disconnected
mqtt_client.on_message = message

# Connect the client to the MQTT broker.
mqtt_client.connect()

# Start a blocking message loop
# If you only want to listen to incoming messages,
# you'll want to loop_forever as it handles network reconnections
# No code below this line will execute.
    print("Turning pump off")
    water_pump.value = False


# Initialize Google Cloud IoT Core interface
google_iot = Cloud_Core(esp, secrets)

# JSON-Web-Token (JWT) Generation
print("Generating JWT...")
jwt = google_iot.generate_jwt()
print("Your JWT is: ", jwt)

# Set up a new MiniMQTT Client
client = MQTT(socket,
              broker=google_iot.broker,
              username=google_iot.username,
              password=jwt,
              client_id=google_iot.cid,
              network_manager=wifi)

# Initialize Google MQTT API Client
google_mqtt = MQTT_API(client)

# Connect callback handlers to Google MQTT Client
google_mqtt.on_connect = connect
google_mqtt.on_disconnect = disconnect
google_mqtt.on_subscribe = subscribe
google_mqtt.on_unsubscribe = unsubscribe
google_mqtt.on_publish = publish
google_mqtt.on_message = message

print('Attempting to connect to %s' % client.broker)
Ejemplo n.º 13
0
class IoTMQTT:
    """MQTT client for Azure IoT
    """

    _iotc_api_version = constants["iotcAPIVersion"]

    def _gen_sas_token(self):
        token_expiry = int(time.time() + self._token_expires)
        uri = self._hostname + "%2Fdevices%2F" + self._device_id
        signed_hmac_sha256 = DeviceRegistration.compute_derived_symmetric_key(
            self._key, uri + "\n" + str(token_expiry))
        signature = parse.quote(signed_hmac_sha256, "~()*!.'")
        if signature.endswith(
                "\n"
        ):  # somewhere along the crypto chain a newline is inserted
            signature = signature[:-1]
        token = "SharedAccessSignature sr={}&sig={}&se={}".format(
            uri, signature, token_expiry)
        return token

    # Workaround for https://github.com/adafruit/Adafruit_CircuitPython_MiniMQTT/issues/25
    def _try_create_mqtt_client(self, hostname):
        minimqtt.set_socket(socket, self._wifi_manager.esp)

        self._mqtts = MQTT(
            broker=hostname,
            username=self._username,
            password=self._passwd,
            port=8883,
            keep_alive=120,
            is_ssl=True,
            client_id=self._device_id,
            log=True,
        )

        self._mqtts.logger.setLevel(logging.INFO)

        # set actions to take throughout connection lifecycle
        self._mqtts.on_connect = self._on_connect
        self._mqtts.on_message = self._on_message
        self._mqtts.on_log = self._on_log
        self._mqtts.on_publish = self._on_publish
        self._mqtts.on_disconnect = self._on_disconnect

        # initiate the connection using the adafruit_minimqtt library
        self._mqtts.last_will()
        self._mqtts.connect()

    def _create_mqtt_client(self):
        try:
            self._try_create_mqtt_client(self._hostname)
        except ValueError:
            # Workaround for https://github.com/adafruit/Adafruit_CircuitPython_MiniMQTT/issues/25
            self._try_create_mqtt_client("https://" + self._hostname)

    # pylint: disable=C0103, W0613
    def _on_connect(self, client, userdata, _, rc):
        self._logger.info("- iot_mqtt :: _on_connect :: rc = " + str(rc) +
                          ", userdata = " + str(userdata))
        if rc == 0:
            self._mqtt_connected = True
        self._auth_response_received = True
        self._callback.connection_status_change(True)

    # pylint: disable=C0103, W0613
    def _on_log(self, client, userdata, level, buf):
        self._logger.info("mqtt-log : " + buf)
        if level <= 8:
            self._logger.error("mqtt-log : " + buf)

    def _on_disconnect(self, client, userdata, rc):
        self._logger.info("- iot_mqtt :: _on_disconnect :: rc = " + str(rc))
        self._auth_response_received = True

        if rc == 5:
            self._logger.error("on(disconnect) : Not authorized")
            self.disconnect()

        if rc == 1:
            self._mqtt_connected = False

        if rc != 5:
            self._callback.connection_status_change(False)

    def _on_publish(self, client, data, topic, msg_id):
        self._logger.info("- iot_mqtt :: _on_publish :: " + str(data) +
                          " on topic " + str(topic))

    # pylint: disable=W0703
    def _handle_device_twin_update(self, msg: str, topic: str):
        self._logger.debug("- iot_mqtt :: _echo_desired :: " + topic)
        twin = None
        desired = None

        print(msg)

        try:
            twin = json.loads(msg)
        except Exception as e:
            self._logger.error(
                "ERROR: JSON parse for Device Twin message object has failed. => "
                + msg + " => " + str(e))
            return

        if "reported" in twin:
            reported = twin["reported"]

            if "$version" in reported:
                reported_version = reported["$version"]
                reported.pop("$version")
            else:
                self._logger.error(
                    "ERROR: Unexpected payload for reported twin update => " +
                    msg)
                return

            for property_name, value in reported.items():
                self._callback.device_twin_reported_updated(
                    property_name, value, reported_version)

        is_patch = "desired" not in twin

        if is_patch:
            desired = twin
        else:
            desired = twin["desired"]

        if "$version" in desired:
            desired_version = desired["$version"]
            desired.pop("$version")
        else:
            self._logger.error(
                "ERROR: Unexpected payload for desired twin update => " + msg)
            return

        for property_name, value in desired.items():
            self._callback.device_twin_desired_updated(property_name, value,
                                                       desired_version)

    def _handle_direct_method(self, msg: str, topic: str):
        index = topic.find("$rid=")
        method_id = 1
        method_name = "None"
        if index == -1:
            self._logger.error("ERROR: C2D doesn't include topic id")
        else:
            method_id = topic[index + 5:]
            topic_template = "$iothub/methods/POST/"
            len_temp = len(topic_template)
            method_name = topic[len_temp:topic.find("/", len_temp + 1)]

        ret = self._callback.direct_method_called(method_name, msg)

        ret_code = 200
        ret_message = "{}"
        if ret.get_response_code() is not None:
            ret_code = ret.get_response_code()
        if ret.get_response_message() is not None:
            ret_message = ret.get_response_message()

            # ret message must be JSON
            if not ret_message.startswith("{") or not ret_message.endswith(
                    "}"):
                ret_json = {"Value": ret_message}
                ret_message = json.dumps(ret_json)

        next_topic = "$iothub/methods/res/{}/?$rid={}".format(
            ret_code, method_id)
        self._logger.info("C2D: => " + next_topic + " with data " +
                          ret_message + " and name => " + method_name)
        self._send_common(next_topic, ret_message)

    def _handle_cloud_to_device_message(self, msg: str, topic: str):
        parts = topic.split("&")[1:]

        properties = {}
        for part in parts:
            key_value = part.split("=")
            properties[key_value[0]] = key_value[1]

        self._callback.cloud_to_device_message_received(msg, properties)

    # pylint: disable=W0702, R0912
    def _on_message(self, client, msg_topic, payload):
        topic = ""
        msg = None

        print("Topic: ", str(msg_topic))
        self._logger.info("- iot_mqtt :: _on_message :: payload(" +
                          str(payload) + ")")

        if payload is not None:
            try:
                msg = payload.decode("utf-8")
            except:
                msg = str(payload)

        if msg_topic is not None:
            try:
                topic = msg_topic.decode("utf-8")
            except:
                topic = str(msg_topic)

        if topic.startswith("$iothub/"):
            if topic.startswith("$iothub/twin/PATCH/properties/desired/"
                                ) or topic.startswith(
                                    "$iothub/twin/res/200/?$rid="):
                self._handle_device_twin_update(str(msg), topic)
            elif topic.startswith("$iothub/methods"):
                self._handle_direct_method(str(msg), topic)
            else:
                if not topic.startswith(
                        "$iothub/twin/res/"):  # not twin response
                    self._logger.error("ERROR: unknown twin! - {}".format(msg))
        elif topic.startswith("devices/{}/messages/devicebound".format(
                self._device_id)):
            self._handle_cloud_to_device_message(str(msg), topic)
        else:
            self._logger.error("ERROR: (unknown message) - {}".format(msg))

    def _send_common(self, topic, data) -> None:
        self._logger.debug("Sending message on topic: " + topic)
        self._logger.debug("Sending message: " + str(data))

        retry = 0

        while True:
            gc.collect()
            try:
                self._logger.debug("Trying to send...")
                self._mqtts.publish(topic, data)
                self._logger.debug("Data sent")
                break
            except RuntimeError as runtime_error:
                self._logger.info(
                    "Could not send data, retrying after 0.5 seconds: " +
                    str(runtime_error))
                retry = retry + 1

                if retry >= 10:
                    self._logger.error("Failed to send data")
                    raise

                time.sleep(0.5)
                continue

        print("finished _send_common")
        gc.collect()

    def _get_device_settings(self) -> None:
        self._logger.info("- iot_mqtt :: _get_device_settings :: ")
        self.loop()
        self._send_common("$iothub/twin/GET/?$rid=0", " ")

    # pylint: disable=R0913
    def __init__(self,
                 callback: IoTMQTTCallback,
                 wifi_manager: ESPSPI_WiFiManager,
                 hostname: str,
                 device_id: str,
                 key: str,
                 token_expires: int = 21600,
                 logger: logging = None):
        """Create the Azure IoT MQTT client
        :param wifi_manager: The WiFi manager
        :param IoTMQTTCallback callback: A callback class
        :param str hostname: The hostname of the MQTT broker to connect to, get this by registering the device
        :param str device_id: The device ID of the device to register
        :param str key: The primary or secondary key of the device to register
        :param int token_expires: The number of seconds till the token expires, defaults to 6 hours
        :param adafruit_logging logger: The logger
        """
        self._wifi_manager = wifi_manager
        self._callback = callback
        self._mqtt_connected = False
        self._auth_response_received = False
        self._mqtts = None
        self._device_id = device_id
        self._hostname = hostname
        self._key = key
        self._token_expires = token_expires
        self._username = "******".format(self._hostname,
                                                       device_id,
                                                       self._iotc_api_version)
        self._passwd = self._gen_sas_token()
        self._logger = logger if logger is not None else logging.getLogger(
            "log")

    def connect(self):
        """Connects to the MQTT broker
        """
        self._logger.info("- iot_mqtt :: connect :: " + self._hostname)

        self._create_mqtt_client()

        self._logger.info(
            " - iot_mqtt :: connect :: created mqtt client. connecting..")
        while self._auth_response_received is None:
            self.loop()

        self._logger.info(
            " - iot_mqtt :: connect :: on_connect must be fired. Connected ? "
            + str(self.is_connected()))
        if not self.is_connected():
            return 1

        self._mqtt_connected = True
        self._auth_response_received = True

        self._mqtts.subscribe("devices/{}/messages/events/#".format(
            self._device_id))
        self._mqtts.subscribe("devices/{}/messages/devicebound/#".format(
            self._device_id))
        self._mqtts.subscribe("$iothub/twin/PATCH/properties/desired/#"
                              )  # twin desired property changes
        self._mqtts.subscribe("$iothub/twin/res/#")  # twin properties response
        self._mqtts.subscribe("$iothub/methods/#")

        if self._get_device_settings() == 0:
            self._callback.settings_updated()
        else:
            return 1

        return 0

    def disconnect(self):
        """Disconnects from the MQTT broker
        """
        if not self.is_connected():
            return

        self._logger.info("- iot_mqtt :: disconnect :: ")
        self._mqtt_connected = False
        self._mqtts.disconnect()

    def is_connected(self):
        """Gets if there is an open connection to the MQTT broker
        """
        return self._mqtt_connected

    def loop(self):
        """Listens for MQTT messages
        """
        if not self.is_connected():
            return

        self._mqtts.loop()

    def _send_common(self, topic, data):
        self._mqtts.publish(topic, data)

    def send_device_to_cloud_message(self,
                                     data,
                                     system_properties=None) -> None:
        """Send a device to cloud message from this device to Azure IoT Hub
        """
        self._logger.info("- iot_mqtt :: send_device_to_cloud_message :: " +
                          data)
        topic = "devices/{}/messages/events/".format(self._device_id)

        if system_properties is not None:
            firstProp = True
            for prop in system_properties:
                if not firstProp:
                    topic += "&"
                else:
                    firstProp = False
                topic += prop + "=" + str(system_properties[prop])

        self._send_common(topic, data)
        self._callback.message_sent(data)

    def send_twin_patch(self, data):
        """Send a patch for the reported properties of the device twin
        """
        self._logger.info("- iot_mqtt :: sendProperty :: " + data)
        topic = "$iothub/twin/PATCH/properties/reported/?$rid={}".format(
            int(time.time()))
        return self._send_common(topic, data)
Ejemplo n.º 14
0
    # This method is called when the client unsubscribes from a feed.
    print('Unsubscribed from {0} with PID {1}'.format(topic, pid))


def publish(client, userdata, topic, pid):
    # This method is called when the client publishes data to a feed.
    print('Published to {0} with PID {1}'.format(topic, pid))


# Connect to WiFi
wifi.connect()

# Set up a MiniMQTT Client
client = MQTT(
    socket,
    broker='192.168.1.164',  #secrets['mqtt-broker'],
    port=1883,
    network_manager=wifi)

# Connect callback handlers to client
client.on_connect = connect
client.on_disconnect = disconnect
client.on_subscribe = subscribe
client.on_unsubscribe = unsubscribe
client.on_publish = publish

print('Attempting to connect to %s' % client.broker)
client.connect()

print('Subscribing to %s' % mqtt_topic)
client.subscribe(mqtt_topic)
Ejemplo n.º 15
0

# ------------- Network Connection ------------- #

# Connect to WiFi
print("Connecting to WiFi...")
wifi.connect()
print("Connected to WiFi!")

# Initialize MQTT interface with the esp interface
MQTT.set_socket(socket, esp)

# Set up a MiniMQTT Client
client = MQTT(
    broker=secrets["broker"],
    port=1883,
    username=secrets["user"],
    password=secrets["pass"],
)

# Connect callback handlers to client
client.on_connect = connect
client.on_disconnect = disconnected
client.on_subscribe = subscribe
client.on_publish = publish
client.on_message = message

print("Attempting to connect to %s" % client.broker)
client.connect()

print("Subscribing to %s, %s, %s, and %s" %
      (mqtt_feed1, mqtt_feed2, mqtt_button1, mqtt_button2))
Ejemplo n.º 16
0
class IoTMQTT:
    """MQTT client for Azure IoT
    """
    def _gen_sas_token(self) -> str:
        token_expiry = int(time.time() + self._token_expires)
        uri = self._hostname + "%2Fdevices%2F" + self._device_id
        signed_hmac_sha256 = compute_derived_symmetric_key(
            self._key, uri + "\n" + str(token_expiry))
        signature = quote(signed_hmac_sha256, "~()*!.'")
        if signature.endswith(
                "\n"
        ):  # somewhere along the crypto chain a newline is inserted
            signature = signature[:-1]
        token = "SharedAccessSignature sr={}&sig={}&se={}".format(
            uri, signature, token_expiry)
        return token

    def _create_mqtt_client(self) -> None:
        minimqtt.set_socket(self._socket, self._iface)

        self._mqtts = MQTT(
            broker=self._hostname,
            username=self._username,
            password=self._passwd,
            port=8883,
            keep_alive=120,
            is_ssl=True,
            client_id=self._device_id,
            log=True,
        )

        self._mqtts.logger.setLevel(self._logger.getEffectiveLevel())

        # set actions to take throughout connection lifecycle
        self._mqtts.on_connect = self._on_connect
        self._mqtts.on_log = self._on_log
        self._mqtts.on_publish = self._on_publish
        self._mqtts.on_disconnect = self._on_disconnect

        # initiate the connection using the adafruit_minimqtt library
        self._mqtts.connect()

    # pylint: disable=C0103, W0613
    def _on_connect(self, client, userdata, _, rc) -> None:
        self._logger.info("- iot_mqtt :: _on_connect :: rc = " + str(rc) +
                          ", userdata = " + str(userdata))
        if rc == 0:
            self._mqtt_connected = True
        self._auth_response_received = True
        self._callback.connection_status_change(True)

    # pylint: disable=C0103, W0613
    def _on_log(self, client, userdata, level, buf) -> None:
        self._logger.info("mqtt-log : " + buf)
        if level <= 8:
            self._logger.error("mqtt-log : " + buf)

    def _on_disconnect(self, client, userdata, rc) -> None:
        self._logger.info("- iot_mqtt :: _on_disconnect :: rc = " + str(rc))
        self._auth_response_received = True

        if rc == 5:
            self._logger.error("on(disconnect) : Not authorized")
            self.disconnect()

        if rc == 1:
            self._mqtt_connected = False

        if rc != 5:
            self._callback.connection_status_change(False)

    def _on_publish(self, client, data, topic, msg_id) -> None:
        self._logger.info("- iot_mqtt :: _on_publish :: " + str(data) +
                          " on topic " + str(topic))

    # pylint: disable=W0703
    def _handle_device_twin_update(self, client, topic: str, msg: str) -> None:
        self._logger.debug("- iot_mqtt :: _echo_desired :: " + topic)
        twin = None
        desired = None

        try:
            twin = json.loads(msg)
        except json.JSONDecodeError as e:
            self._logger.error(
                "ERROR: JSON parse for Device Twin message object has failed. => "
                + msg + " => " + str(e))
            return

        if "reported" in twin:
            reported = twin["reported"]

            if "$version" in reported:
                reported_version = reported["$version"]
                reported.pop("$version")
            else:
                self._logger.error(
                    "ERROR: Unexpected payload for reported twin update => " +
                    msg)
                return

            for property_name, value in reported.items():
                self._callback.device_twin_reported_updated(
                    property_name, value, reported_version)

        is_patch = "desired" not in twin

        if is_patch:
            desired = twin
        else:
            desired = twin["desired"]

        if "$version" in desired:
            desired_version = desired["$version"]
            desired.pop("$version")
        else:
            self._logger.error(
                "ERROR: Unexpected payload for desired twin update => " + msg)
            return

        for property_name, value in desired.items():
            self._callback.device_twin_desired_updated(property_name, value,
                                                       desired_version)

    def _handle_direct_method(self, client, topic: str, msg: str) -> None:
        index = topic.find("$rid=")
        method_id = 1
        method_name = "None"
        if index == -1:
            self._logger.error("ERROR: C2D doesn't include topic id")
        else:
            method_id = topic[index + 5:]
            topic_template = "$iothub/methods/POST/"
            len_temp = len(topic_template)
            method_name = topic[len_temp:topic.find("/", len_temp + 1)]

        ret = self._callback.direct_method_invoked(method_name, msg)
        gc.collect()

        ret_code = 200
        ret_message = "{}"
        if ret.response_code is not None:
            ret_code = ret.response_code
        if ret.response_message is not None:
            ret_message = ret.response_message

            # ret message must be JSON
            if not ret_message.startswith("{") or not ret_message.endswith(
                    "}"):
                ret_json = {"Value": ret_message}
                ret_message = json.dumps(ret_json)

        next_topic = "$iothub/methods/res/{}/?$rid={}".format(
            ret_code, method_id)
        self._logger.info("C2D: => " + next_topic + " with data " +
                          ret_message + " and name => " + method_name)
        self._send_common(next_topic, ret_message)

    def _handle_cloud_to_device_message(self, client, topic: str,
                                        msg: str) -> None:
        parts = topic.split("&")[1:]

        properties = {}
        for part in parts:
            key_value = part.split("=")
            properties[key_value[0]] = key_value[1]

        self._callback.cloud_to_device_message_received(msg, properties)
        gc.collect()

    def _send_common(self, topic: str, data) -> None:
        # Convert data to a string
        if isinstance(data, dict):
            data = json.dumps(data)

        if not isinstance(data, str):
            raise IoTError("Data must be a string or a dictionary")

        self._logger.debug("Sending message on topic: " + topic)
        self._logger.debug("Sending message: " + str(data))

        retry = 0

        while True:
            gc.collect()
            try:
                self._logger.debug("Trying to send...")
                self._mqtts.publish(topic, data)
                self._logger.debug("Data sent")
                break
            except RuntimeError as runtime_error:
                self._logger.info(
                    "Could not send data, retrying after 0.5 seconds: " +
                    str(runtime_error))
                retry = retry + 1

                if retry >= 10:
                    self._logger.error("Failed to send data")
                    raise

                time.sleep(0.5)
                continue

        gc.collect()

    def _get_device_settings(self) -> None:
        self._logger.info("- iot_mqtt :: _get_device_settings :: ")
        self.loop()
        self._send_common("$iothub/twin/GET/?$rid=0", " ")

    # pylint: disable=R0913
    def __init__(
        self,
        callback: IoTMQTTCallback,
        socket,
        iface,
        hostname: str,
        device_id: str,
        key: str,
        token_expires: int = 21600,
        logger: logging = None,
    ):
        """Create the Azure IoT MQTT client
        :param IoTMQTTCallback callback: A callback class
        :param socket: The socket to communicate over
        :param iface: The network interface to communicate over
        :param str hostname: The hostname of the MQTT broker to connect to, get this by registering the device
        :param str device_id: The device ID of the device to register
        :param str key: The primary or secondary key of the device to register
        :param int token_expires: The number of seconds till the token expires, defaults to 6 hours
        :param adafruit_logging logger: The logger
        """
        self._callback = callback
        self._socket = socket
        self._iface = iface
        self._mqtt_connected = False
        self._auth_response_received = False
        self._mqtts = None
        self._device_id = device_id
        self._hostname = hostname
        self._key = key
        self._token_expires = token_expires
        self._username = "******".format(
            self._hostname, device_id, constants.IOTC_API_VERSION)
        self._passwd = self._gen_sas_token()
        self._logger = logger if logger is not None else logging.getLogger(
            "log")
        self._is_subscribed_to_twins = False

    def _subscribe_to_core_topics(self):
        device_bound_topic = "devices/{}/messages/devicebound/#".format(
            self._device_id)
        self._mqtts.add_topic_callback(device_bound_topic,
                                       self._handle_cloud_to_device_message)
        self._mqtts.subscribe(device_bound_topic)

        self._mqtts.add_topic_callback("$iothub/methods/#",
                                       self._handle_direct_method)
        self._mqtts.subscribe("$iothub/methods/#")

    def _subscribe_to_twin_topics(self):
        self._mqtts.add_topic_callback(
            "$iothub/twin/PATCH/properties/desired/#",
            self._handle_device_twin_update)
        self._mqtts.subscribe("$iothub/twin/PATCH/properties/desired/#"
                              )  # twin desired property changes

        self._mqtts.add_topic_callback("$iothub/twin/res/200/#",
                                       self._handle_device_twin_update)
        self._mqtts.subscribe(
            "$iothub/twin/res/200/#")  # twin properties response

    def connect(self) -> bool:
        """Connects to the MQTT broker
        :returns: True if the connection is successful, otherwise False
        :rtype: bool
        """
        self._logger.info("- iot_mqtt :: connect :: " + self._hostname)

        self._create_mqtt_client()

        self._logger.info(
            " - iot_mqtt :: connect :: created mqtt client. connecting..")
        while self._auth_response_received is None:
            self.loop()

        self._logger.info(
            " - iot_mqtt :: connect :: on_connect must be fired. Connected ? "
            + str(self.is_connected()))
        if not self.is_connected():
            return False

        self._mqtt_connected = True
        self._auth_response_received = True

        self._subscribe_to_core_topics()

        return True

    def subscribe_to_twins(self) -> None:
        """Subscribes to digital twin updates
        Only call this if your tier of IoT Hub supports this
        """
        if self._is_subscribed_to_twins:
            return

        # do this separately as this is not supported in B1 hubs
        self._subscribe_to_twin_topics()

        self._get_device_settings()

        self._is_subscribed_to_twins = True

    def disconnect(self) -> None:
        """Disconnects from the MQTT broker
        """
        if not self.is_connected():
            return

        self._logger.info("- iot_mqtt :: disconnect :: ")
        self._mqtt_connected = False
        self._mqtts.disconnect()

    def reconnect(self) -> None:
        """Reconnects to the MQTT broker
        """
        self._logger.info("- iot_mqtt :: reconnect :: ")

        self._mqtts.reconnect()

    def is_connected(self) -> bool:
        """Gets if there is an open connection to the MQTT broker
        :returns: True if there is an open connection, False if not
        :rtype: bool
        """
        return self._mqtt_connected

    def loop(self) -> None:
        """Listens for MQTT messages
        """
        if not self.is_connected():
            return

        self._mqtts.loop()
        gc.collect()

    def send_device_to_cloud_message(self,
                                     message,
                                     system_properties: dict = None) -> None:
        """Send a device to cloud message from this device to Azure IoT Hub
        :param message: The message data as a JSON string or a dictionary
        :param system_properties: System properties to send with the message
        :raises: ValueError if the message is not a string or dictionary
        :raises RuntimeError: if the internet connection is not responding or is unable to connect
        """
        self._logger.info("- iot_mqtt :: send_device_to_cloud_message :: " +
                          message)
        topic = "devices/{}/messages/events/".format(self._device_id)

        if system_properties is not None:
            firstProp = True
            for prop in system_properties:
                if not firstProp:
                    topic += "&"
                else:
                    firstProp = False
                topic += prop + "=" + str(system_properties[prop])

        # Convert message to a string
        if isinstance(message, dict):
            message = json.dumps(message)

        if not isinstance(message, str):
            raise ValueError("message must be a string or a dictionary")

        self._send_common(topic, message)
        self._callback.message_sent(message)

    def send_twin_patch(self, patch) -> None:
        """Send a patch for the reported properties of the device twin
        :param patch: The patch as a JSON string or a dictionary
        :raises: IoTError if the data is not a string or dictionary
        :raises RuntimeError: if the internet connection is not responding or is unable to connect
        """
        self._logger.info("- iot_mqtt :: sendProperty :: " + str(patch))
        topic = "$iothub/twin/PATCH/properties/reported/?$rid={}".format(
            int(time.time()))
        self._send_common(topic, patch)
Ejemplo n.º 17
0
            buttons[0].selected = False
            print("Button 1 ON")
        else:
            buttons[0].label="OFF"
            buttons[0].selected = True
            print("Button 1 OFF")

# ------------- Network Connection ------------- #

# Connect to WiFi
wifi.connect()

# Set up a MiniMQTT Client
client = MQTT(socket,
              broker = secrets['broker'],
              port = 1883,
              username = secrets['user'],
              password = secrets['pass'],
              network_manager = wifi)

# Connect callback handlers to client
client.on_connect = connect
client.on_disconnect = disconnected
client.on_subscribe = subscribe
client.on_publish = publish
client.on_message = message

print('Attempting to connect to %s' % client.broker)
client.connect()

print('Subscribing to %s, %s, %s, and %s' % (mqtt_feed1, mqtt_feed2, mqtt_button1, mqtt_button2))
client.subscribe(mqtt_feed1)
def message(client, topic, message):
    """Method callled when a client's subscribed feed has a new
    value.
    :param str topic: The topic of the feed with a new value.
    :param str message: The new value
    """
    print('New message on topic {0}: {1}'.format(topic, message))

# Connect to WiFi
wifi.connect()

# Set up a MiniMQTT Client
mqtt_client = MQTT(socket,
                   broker = secrets['broker'],
                   username = secrets['user'],
                   password = secrets['pass'],
                   network_manager = wifi)

# Setup the callback methods above
mqtt_client.on_connect = connected
mqtt_client.on_disconnect = disconnected
mqtt_client.on_message = message

# Connect the client to the MQTT broker.
mqtt_client.connect()

photocell_val = 0
while True:
    # Poll the message queue
    mqtt_client.loop()
Ejemplo n.º 19
0

# pylint: disable=unused-argument
def on_message(client, topic, message):
    # This method is called whenever a new message is received
    # from the server.
    print('New message on topic {0}: {1}'.format(topic, message))


# Connect to WiFi
wifi.connect()

# Set up a MiniMQTT Client
mqtt_client = MQTT(socket,
                   broker=secrets['broker'],
                   username=secrets['user'],
                   password=secrets['pass'],
                   network_manager=wifi)

# Attach on_message method to the MQTT Client
mqtt_client.on_message = on_message

# Initialize the MQTT Client
mqtt_client.connect()

# Subscribe the client to topic aio_subscribe_feed
mqtt_client.subscribe(aio_subscribe_feed)

photocell_val = 0
while True:
    # Poll the message queue