Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix miniMQTT compatibility and native_networking examples #37

Merged
merged 13 commits into from
Jan 27, 2022
6 changes: 3 additions & 3 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ To create an Azure IoT Hub instance or an Azure IoT Central app, you will need a

- If you are not a student, head to `aka.ms/FreeAz <https://aka.ms/FreeAz>`_ and sign up to get $200 of credit for 30 days, as well as free tiers of a load of services. You will need a credit card for validation only, your card will not be charged.

ESP32SPI Networking
===================
ESP32 AirLift Networking
========================

To use this library, you will need to create an ESP32_SPI WifiManager, connected to WiFi. You will also need to set the current time, as this is used to generate time-based authentication keys. One way to do this is via the `Adafruit CircuitPython NTP <https://github.com/adafruit/Adafruit_CircuitPython_NTP>`_ library with the following code:

Expand All @@ -79,7 +79,7 @@ To use this library, you will need to create an ESP32_SPI WifiManager, connected
Native Networking
=================
To use this library, with boards that have native networking support, you need to be connected to a network. You will also need to set the current time, as this is used to generate time-based authentication keys. One way to do this is by using the `Adafruit IoT Time Service <https://io.adafruit.com/api/docs/#time>`_ via the `Requests library <https://github.com/adafruit/Adafruit_CircuitPython_Requests/>_` with the following code:
To use this library, with boards that have native networking support, you need to be connected to a network. You will also need to set the current time, as this is used to generate time-based authentication keys. One way to do this is by using the `Adafruit IoT Time API <https://io.adafruit.com/api/docs/#time>`_ via the `Adafruit Requests library <https://github.com/adafruit/Adafruit_CircuitPython_Requests>`_ with the following code:

.. code-block:: python
Expand Down
9 changes: 5 additions & 4 deletions adafruit_azureiot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@
* Adafruit CircuitPython firmware for the supported boards:
https://github.com/adafruit/circuitpython/releases
**ESP32SPI Peripheral Networking**
**With ESP32 Airlift Networking**
* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
* Adafruit's ESP32SPI Networking library: https://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI
* Adafruit's ESP32SPI library: https://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI
* Adafruit's NTP library: https://github.com/adafruit/Adafruit_CircuitPython_NTP
**Native Networking**
**With Native Networking**
* CircuitPython's Wifi Module: https://docs.circuitpython.org/en/latest/shared-bindings/wifi/index.html
* Adafruit's CircuitPython Requests Library: https://github.com/adafruit/Adafruit_CircuitPython_Requests/
* Adafruit's Requests Library: https://github.com/adafruit/Adafruit_CircuitPython_Requests/
"""

from .iot_error import IoTError
Expand Down
2 changes: 2 additions & 0 deletions adafruit_azureiot/device_registration.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ def __init__(
logger: Logger = None,
):
"""Creates an instance of the device registration service
:param socket: The network socket
:param str id_scope: The ID scope of the device to register
:param str device_id: The device ID of the device to register
Expand Down Expand Up @@ -163,6 +164,7 @@ def register_device(self, expiry: int) -> str:
"""
Registers the device with the IoT Central device registration service.
Returns the hostname of the IoT hub to use over MQTT
:param int expiry: The expiry time for the registration
:returns: The underlying IoT Hub that this device should connect to
:rtype: str
Expand Down
1 change: 1 addition & 0 deletions adafruit_azureiot/iot_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class IoTError(Exception):

def __init__(self, message: str):
"""Create the IoT Error
:param str message: The error message
"""
super().__init__(message)
Expand Down
17 changes: 15 additions & 2 deletions adafruit_azureiot/iot_mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import adafruit_minimqtt.adafruit_minimqtt as MQTT
import adafruit_logging as logging
from adafruit_logging import Logger

from .iot_error import IoTError
from .keys import compute_derived_symmetric_key
Expand All @@ -31,6 +32,7 @@ class IoTResponse:

def __init__(self, code: int, message: str):
"""Creates an IoT Response object
:param int code: The HTTP response code for this method call, for example 200 if the method was handled successfully
:param str message: The HTTP response message for this method call
"""
Expand All @@ -43,17 +45,20 @@ class IoTMQTTCallback:

def message_sent(self, data: str) -> None:
"""Called when a message is sent to the cloud
:param str data: The data send with the message
"""

def connection_status_change(self, connected: bool) -> None:
"""Called when the connection status changes
:param bool connected: True if the device is connected, otherwise false
"""

# pylint: disable=W0613, R0201
def direct_method_invoked(self, method_name: str, payload: str) -> IoTResponse:
"""Called when a direct method is invoked
:param str method_name: The name of the method that was invoked
:param str payload: The payload with the message
:returns: A response with a code and status to show if the method was correctly handled
Expand All @@ -64,6 +69,7 @@ def direct_method_invoked(self, method_name: str, payload: str) -> IoTResponse:
# pylint: disable=C0103
def cloud_to_device_message_received(self, body: str, properties: dict) -> None:
"""Called when a cloud to device message is received
:param str body: The body of the message
:param dict properties: The propreties sent with the mesage
"""
Expand All @@ -72,6 +78,7 @@ def device_twin_desired_updated(
self, desired_property_name: str, desired_property_value, desired_version: int
) -> None:
"""Called when the device twin desired properties are updated
:param str desired_property_name: The name of the desired property that was updated
:param desired_property_value: The value of the desired property that was updated
:param int desired_version: The version of the desired property that was updated
Expand All @@ -84,6 +91,7 @@ def device_twin_reported_updated(
reported_version: int,
) -> None:
"""Called when the device twin reported values are updated
:param str reported_property_name: The name of the reported property that was updated
:param reported_property_value: The value of the reported property that was updated
:param int reported_version: The version of the reported property that was updated
Expand Down Expand Up @@ -319,17 +327,18 @@ def __init__(
device_id: str,
device_sas_key: str,
token_expires: int = 21600,
logger: logging = None,
logger: Logger = 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 device_sas_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
:param Logger logger: The logger
"""
self._callback = callback
self._socket = socket
Expand Down Expand Up @@ -372,6 +381,7 @@ def _subscribe_to_twin_topics(self):

def connect(self) -> bool:
"""Connects to the MQTT broker
:returns: True if the connection is successful, otherwise False
:rtype: bool
"""
Expand Down Expand Up @@ -426,6 +436,7 @@ def reconnect(self) -> None:

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
"""
Expand All @@ -443,6 +454,7 @@ 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
Expand Down Expand Up @@ -472,6 +484,7 @@ def send_device_to_cloud_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
Expand Down
16 changes: 14 additions & 2 deletions adafruit_azureiot/iotcentral_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import json
import time
import adafruit_logging as logging
from adafruit_logging import Logger
from .device_registration import DeviceRegistration
from .iot_error import IoTError
from .iot_mqtt import IoTMQTT, IoTMQTTCallback, IoTResponse
Expand All @@ -25,6 +26,7 @@ class IoTCentralDevice(IoTMQTTCallback):

def connection_status_change(self, connected: bool) -> None:
"""Called when the connection status changes
:param bool connected: True if the device is connected, otherwise false
"""
if self.on_connection_status_changed is not None:
Expand All @@ -34,6 +36,7 @@ def connection_status_change(self, connected: bool) -> None:
# pylint: disable=W0613, R0201
def direct_method_called(self, method_name: str, payload: str) -> IoTResponse:
"""Called when a direct method is invoked
:param str method_name: The name of the method that was invoked
:param str payload: The payload with the message
:returns: A response with a code and status to show if the method was correctly handled
Expand All @@ -49,6 +52,7 @@ def device_twin_desired_updated(
self, desired_property_name: str, desired_property_value, desired_version: int
) -> None:
"""Called when the device twin desired properties are updated
:param str desired_property_name: The name of the desired property that was updated
:param desired_property_value: The value of the desired property that was updated
:param int desired_version: The version of the desired property that was updated
Expand All @@ -69,6 +73,7 @@ def device_twin_reported_updated(
reported_version: int,
) -> None:
"""Called when the device twin reported values are updated
:param str reported_property_name: The name of the reported property that was updated
:param reported_property_value: The value of the reported property that was updated
:param int reported_version: The version of the reported property that was updated
Expand All @@ -88,16 +93,17 @@ def __init__(
device_id: str,
device_sas_key: str,
token_expires: int = 21600,
logger: logging = None,
logger: Logger = None,
):
"""Create the Azure IoT Central device client
:param socket: The network socket
:param iface: The network interface
:param str id_scope: The ID Scope of the device in IoT Central
:param str device_id: The device ID of the device in IoT Central
:param str device_sas_key: The primary or secondary key of the device in IoT Central
:param int token_expires: The number of seconds till the token expires, defaults to 6 hours
:param adafruit_logging logger: The logger
:param Logger logger: The logger
"""
self._socket = socket
self._iface = iface
Expand Down Expand Up @@ -132,6 +138,7 @@ def property_changed(_property_name: str, property_value, version: int) -> None

def connect(self) -> None:
"""Connects to Azure IoT Central
:raises DeviceRegistrationError: if the device cannot be registered successfully
:raises RuntimeError: if the internet connection is not responding or is unable to connect
"""
Expand Down Expand Up @@ -166,6 +173,7 @@ def connect(self) -> None:

def disconnect(self) -> None:
"""Disconnects from the MQTT broker
:raises IoTError: if there is no open connection to the MQTT broker
"""
if self._mqtt is None:
Expand All @@ -182,13 +190,15 @@ def reconnect(self) -> None:

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.is_connected() if self._mqtt is not None else False

def loop(self) -> None:
"""Listens for MQTT messages
:raises IoTError: if there is no open connection to the MQTT broker
"""
if self._mqtt is None:
Expand All @@ -198,6 +208,7 @@ def loop(self) -> None:

def send_property(self, property_name: str, value) -> None:
"""Updates the value of a writable property
:param str property_name: The name of the property to write to
:param value: The value to set on the property
:raises IoTError: if there is no open connection to the MQTT broker
Expand All @@ -211,6 +222,7 @@ def send_property(self, property_name: str, value) -> None:

def send_telemetry(self, data) -> None:
"""Sends telemetry to the IoT Central app
:param data: The telemetry data to send
:raises IoTError: if there is no open connection to the MQTT broker
"""
Expand Down