diff --git a/.travis.yml b/.travis.yml index 4c0ccb6..2b581f8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -43,6 +43,7 @@ install: script: - pylint adafruit_io/*.py - - ([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name,bad-whitespace examples/*.py) + - ([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name,bad-whitespace examples/http/*.py) + - ([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name,bad-whitespace examples/mqtt/*.py) - circuitpython-build-bundles --filename_prefix adafruit-circuitpython-adafruit_io --library_location . - cd docs && sphinx-build -E -W -b html . _build/html && cd .. diff --git a/README.rst b/README.rst index 52d2850..a6644bd 100644 --- a/README.rst +++ b/README.rst @@ -23,12 +23,6 @@ This driver depends on: * `Adafruit CircuitPython `_ -You'll also need a library to communicate with an ESP32 as a coprocessor using a WiFiManager object. This library supports connecting an ESP32 using either SPI or UART. - -* SPI: `Adafruit CircuitPython ESP32SPI `_ - -* UART: `Adafruit CircuitPython ESP_ATcontrol `_ - Please ensure all dependencies are available on the CircuitPython filesystem. This is easily achieved by downloading `the Adafruit library and driver bundle `_. @@ -36,35 +30,9 @@ This is easily achieved by downloading Usage Example ============= -Create an Adafruit IO Client object - -.. code-block:: python - - io = RESTClient(aio_username, aio_key, wifi) - -Sending data to an Adafruit IO feed - -.. code-block:: python - - io.send_data(feed, data) - -Receiving data from an Adafruit IO feed - -.. code-block:: python - - data = io.receive_data(feed) - -Creating a new feed named circuitpython with a description - -.. code-block:: python - - feed = io.create_new_feed('circuitpython', 'an Adafruit IO CircuitPython feed') - -Listing the record of a specified feed: +Usage examples for the Adafruit IO HTTP API are within the examples/http folder. -.. code-block:: python - - feed = io.get_feed('circuitpython') +Usage examples for the Adafruit IO MQTT API are within the examples/mqtt folder. Contributing ============ diff --git a/adafruit_io/adafruit_io.py b/adafruit_io/adafruit_io.py index 0b77e58..ca9dd5a 100755 --- a/adafruit_io/adafruit_io.py +++ b/adafruit_io/adafruit_io.py @@ -23,7 +23,7 @@ `adafruit_io` ================================================================================ -A CircuitPython/Python library for communicating with Adafruit IO over WiFi +A CircuitPython library for communicating with Adafruit IO. * Author(s): Brent Rubell for Adafruit Industries @@ -34,42 +34,410 @@ * Adafruit CircuitPython firmware for the supported boards: https://github.com/adafruit/circuitpython/releases - -* Adafruit ESP32SPI or ESP_ATcontrol library: - https://github.com/adafruit/Adafruit_CircuitPython_ESP32SPI - https://github.com/adafruit/Adafruit_CircuitPython_ESP_ATcontrol """ -from time import struct_time -from adafruit_io.adafruit_io_errors import AdafruitIO_RequestError, AdafruitIO_ThrottleError +import time +import json +from adafruit_io.adafruit_io_errors import ( + AdafruitIO_RequestError, + AdafruitIO_ThrottleError, + AdafruitIO_MQTTError, +) __version__ = "0.0.0-auto.0" __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_Adafruit_IO.git" -CLIENT_HEADERS = { - 'User-Agent': 'AIO-CircuitPython/{0}'.format(__version__) -} +CLIENT_HEADERS = {"User-Agent": "AIO-CircuitPython/{0}".format(__version__)} + -class RESTClient(): +class IO_MQTT: """ - REST Client for interacting with the Adafruit IO API. + Client for interacting with the Adafruit IO MQTT API. + https://io.adafruit.com/api/docs/mqtt.html#adafruit-io-mqtt-api + + :param MiniMQTT mqtt_client: MiniMQTT Client object. """ - def __init__(self, adafruit_io_username, adafruit_io_key, wifi_manager): + + # pylint: disable=protected-access + def __init__(self, mqtt_client): + # Check for MiniMQTT client + mqtt_client_type = str(type(mqtt_client)) + if "MQTT" in mqtt_client_type: + self._client = mqtt_client + else: + raise TypeError( + "This class requires a MiniMQTT client object, please create one." + ) + # MiniMQTT's username kwarg is optional, IO requires a username + try: + self._user = self._client._user + except: + raise TypeError( + "Adafruit IO requires a username, please set one in MiniMQTT" + ) + # User-defined MQTT callback methods must be init'd to None + self.on_connect = None + self.on_disconnect = None + self.on_message = None + self.on_subscribe = None + self.on_unsubscribe = None + # MQTT event callbacks + self._client.on_connect = self._on_connect_mqtt + self._client.on_disconnect = self._on_disconnect_mqtt + self._client.on_message = self._on_message_mqtt + self._logger = False + # Write to the MiniMQTT logger, if avaliable. + if self._client._logger is not None: + self._logger = True + self._client.set_logger_level("DEBUG") + self._connected = False + + def __enter__(self): + return self + + def __exit__(self, exception_type, exception_value, traceback): + self.disconnect() + + def connect(self): + """Connects to the Adafruit IO MQTT Broker. + Must be called before any other API methods are called. + """ + try: + self._client.connect() + except: + raise AdafruitIO_MQTTError("Unable to connect to Adafruit IO.") + + def disconnect(self): + """Disconnects from Adafruit IO MQTT Broker. + """ + if self._connected: + self._client.disconnect() + + @property + def is_connected(self): + """Returns if connected to Adafruit IO MQTT Broker.""" + return self._client.is_connected + + # pylint: disable=not-callable, unused-argument + def _on_connect_mqtt(self, client, userdata, flags, return_code): + """Runs when the client calls on_connect. + """ + if self._logger: + self._client._logger.debug("Client called on_connect.") + if return_code == 0: + self._connected = True + else: + raise AdafruitIO_MQTTError(return_code) + # Call the user-defined on_connect callback if defined + if self.on_connect is not None: + self.on_connect(self) + + # pylint: disable=not-callable, unused-argument + def _on_disconnect_mqtt(self, client, userdata, return_code): + """Runs when the client calls on_disconnect. + """ + if self._logger: + self._client._logger.debug("Client called on_disconnect") + self._connected = False + # Call the user-defined on_disconnect callblack if defined + if self.on_disconnect is not None: + self.on_disconnect(self) + + # pylint: disable=not-callable + def _on_message_mqtt(self, client, topic, payload): + """Runs when the client calls on_message. Parses and returns + incoming data from Adafruit IO feeds. + :param MQTT client: A MQTT Client Instance. + :param str topic: MQTT topic response from Adafruit IO. + :param str payload: MQTT payload data response from Adafruit IO. + """ + if self._logger: + self._client._logger.debug("Client called on_message.") + if self.on_message is not None: + # Parse the MQTT topic string + topic_name = topic.split("/") + if topic_name[1] == "groups": + # Adafruit IO Group Feed(s) + feeds = [] + messages = [] + # Conversion of incoming group to a json response + payload = json.loads(payload) + for feed in payload["feeds"]: + feeds.append(feed) + for msg in feeds: + payload = payload["feeds"][msg] + messages.append(payload) + topic_name = feeds + message = messages + elif topic_name[0] == "time": + # Adafruit IO Time Topic + topic_name = topic_name[1] + message = payload + else: + # Standard Adafruit IO Feed + topic_name = topic_name[2] + message = payload + else: + raise ValueError( + "You must define an on_message method before calling this callback." + ) + self.on_message(self, topic_name, message) + + def loop(self): + """Manually process messages from Adafruit IO. + Call this method to check incoming subscription messages. + + Example usage of polling the message queue using loop. + + ..code-block:: python + + while True: + io.loop() + """ + self._client.loop() + + def loop_blocking(self): + """Starts a blocking loop and to processes messages + from Adafruit IO. Code below this call will not run. """ - Creates an instance of the Adafruit IO REST Client. + self._client.loop_forever() + + # Subscriptions + def subscribe(self, feed_key=None, group_key=None, shared_user=None): + """Subscribes to your Adafruit IO feed or group. + Can also subscribe to someone else's feed. + :param str feed_key: Adafruit IO Feed key. + :param str group_key: Adafruit IO Group key. + :param str shared_user: Owner of the Adafruit IO feed, required for shared feeds. + + Example of subscribing to an Adafruit IO Feed named 'temperature'. + + .. code-block:: python + + client.subscribe('temperature') + + Example of subscribing to two Adafruit IO feeds: 'temperature' + and 'humidity'. + + .. code-block:: python + + client.subscribe([('temperature'), ('humidity')]) + """ + if shared_user is not None and feed_key is not None: + self._client.subscribe("{0}/feeds/{1}".format(shared_user, feed_key)) + elif group_key is not None: + self._client.subscribe("{0}/groups/{1}".format(self._user, group_key)) + elif feed_key is not None: + self._client.subscribe("{0}/feeds/{1}".format(self._user, feed_key)) + else: + raise AdafruitIO_MQTTError("Must provide a feed_key or group_key.") + + def subscribe_to_throttling(self): + """Subscribes to your personal Adafruit IO /throttle topic. + https://io.adafruit.com/api/docs/mqtt.html#mqtt-api-rate-limiting + """ + self._client.subscribe("%s/throttle" % self._user) + + def subscribe_to_errors(self): + """Subscribes to your personal Adafruit IO /errors topic. + Notifies you of errors relating to publish/subscribe calls. + """ + self._client.subscribe("%s/errors" % self._user) + + def subscribe_to_randomizer(self, randomizer_id): + """Subscribes to a random data stream created by the Adafruit IO Words service. + :param int randomizer_id: Random word record you want data for. + """ + self._client.subscribe( + "{0}/integration/words/{1}".format(self._user, randomizer_id) + ) + + def subscribe_to_weather(self, weather_record, forecast): + """Subscribes to a weather forecast using the Adafruit IO PLUS weather + service. This feature is only avaliable to Adafruit IO PLUS subscribers. + :param int weather_record: Weather record you want data for. + :param str forecast: Forecast data you'd like to recieve. + """ + self._client.subscribe( + "{0}/integration/weather/{1}/{2}".format( + self._user, weather_record, forecast + ) + ) + + def subscribe_to_time(self, time_type): + """Adafruit IO provides some built-in MQTT topics for getting the current server time. + :param str time_type: Current Adafruit IO server time. Can be 'seconds', 'millis', or 'iso'. + Information about these topics can be found on the Adafruit IO MQTT API Docs.: + https://io.adafruit.com/api/docs/mqtt.html#time-topics + """ + if "seconds" or "millis" or "hours" in time_type: + self._client.subscribe("time/" + time_type) + elif time_type == "iso": + self._client.subscribe("time/ISO-8601") + else: + raise TypeError("Invalid time feed type specified") + + def unsubscribe(self, feed_key=None, group_key=None, shared_user=None): + """Unsubscribes from an Adafruit IO feed or group. + Can also subscribe to someone else's feed. + :param str feed_key: Adafruit IO Feed key. + :param str group_key: Adafruit IO Group key. + :param str shared_user: Owner of the Adafruit IO feed, required for shared feeds. + + Example of unsubscribing from a feed. + + .. code-block:: python + + client.unsubscribe('temperature') + + Example of unsubscribing from two feeds: 'temperature' + and 'humidity' + + .. code-block:: python + + client.unsubscribe([('temperature'), ('humidity')]) + + Example of unsubscribing from a shared feed. + + .. code-block:: python + + client.unsubscribe('temperature', shared_user='adabot') + + """ + if shared_user is not None and feed_key is not None: + self._client.unsubscribe("{0}/feeds/{1}".format(shared_user, feed_key)) + elif group_key is not None: + self._client.unsubscribe("{0}/groups/{1}".format(self._user, feed_key)) + elif feed_key is not None: + self._client.unsubscribe("{0}/feeds/{1}".format(self._user, feed_key)) + else: + raise AdafruitIO_MQTTError("Must provide a feed_key or group_key.") + + # Publishing + def publish_multiple(self, feeds_and_data, timeout=3, is_group=False): + """Publishes multiple data points to multiple feeds or groups with a variable + timeout. + + :param str feeds_and_data: List of tuples containing topic strings and data values. + :param int timeout: Delay between publishing data points to Adafruit IO, in seconds. + :param bool is_group: Set to True if you're publishing to a group. + + Example of publishing multiple data points on different feeds to Adafruit IO: + ..code-block:: python + + client.publish_multiple([('humidity', 24.5), ('temperature', 54)]) + + """ + if isinstance(feeds_and_data, list): + feed_data = [] + for topic, data in feeds_and_data: + feed_data.append((topic, data)) + else: + raise AdafruitIO_MQTTError("This method accepts a list of tuples.") + for topic, data in feed_data: + if is_group: + self.publish(topic, data, is_group=True) + else: + self.publish(topic, data) + time.sleep(timeout) + + # pylint: disable=too-many-arguments + def publish(self, feed_key, data, metadata=None, shared_user=None, is_group=False): + """Publishes to an An Adafruit IO Feed. + + :param str feed_key: Adafruit IO Feed key. + :param str data: Data to publish to the feed or group. + :param int data: Data to publish to the feed or group. + :param float data: Data to publish to the feed or group. + :param str metadata: Optional metadata associated with the data. + :param str shared_user: Owner of the Adafruit IO feed, required for + feed sharing. + :param bool is_group: Set True if publishing to an Adafruit IO Group. + + Example of publishing an integer to Adafruit IO on feed 'temperature'. + ..code-block:: python + + client.publish('temperature', 30) + + Example of publishing a floating point value to feed 'temperature'. + ..code-block:: python + + client.publish('temperature', 3.14) + + Example of publishing a string to feed 'temperature'. + ..code-block:: python + + client.publish('temperature, 'thirty degrees') + + Example of publishing an integer to group 'weatherstation'. + ..code-block:: python + + client.publish('weatherstation', 12, is_group=True) + + Example of publishing to a shared feed. + ..code-block:: python + + client.publish('temperature', shared_user='myfriend') + + Example of publishing a value along with locational metadata to a feed. + ..code-block:: python + + data = 42 + # format: "lat, lon, ele" + metadata = "40.726190, -74.005334, -6" + io.publish("location-feed", data, metadata) + + """ + if is_group: + self._client.publish("{0}/groups/{1}".format(self._user, feed_key), data) + if shared_user is not None: + self._client.publish("{0}/feeds/{1}".format(shared_user, feed_key), data) + if metadata is not None: + if isinstance(data, int or float): + data = str(data) + csv_string = data + "," + metadata + self._client.publish( + "{0}/feeds/{1}/csv".format(self._user, feed_key), csv_string + ) + else: + self._client.publish("{0}/feeds/{1}".format(self._user, feed_key), data) + + def get(self, feed_key): + """Calling this method will make Adafruit IO publish the most recent + value on feed_key. + https://io.adafruit.com/api/docs/mqtt.html#retained-values + :param str feed_key: Adafruit IO Feed key. + + Example of obtaining a recently published value on a feed: + ..code-block:: python + + io.get('temperature') + """ + self._client.publish("{0}/feeds{1}/get".format(self._user, feed_key), "\0") + + +class IO_HTTP: + """ + Client for interacting with the Adafruit IO HTTP API. + https://io.adafruit.com/api/docs/#adafruit-io-http-api + :param str adafruit_io_username: Adafruit IO Username :param str adafruit_io_key: Adafruit IO Key :param wifi_manager: WiFiManager object from ESPSPI_WiFiManager or ESPAT_WiFiManager - """ + + """ + + def __init__(self, adafruit_io_username, adafruit_io_key, wifi_manager): self.username = adafruit_io_username self.key = adafruit_io_key wifi_type = str(type(wifi_manager)) - if ('ESPSPI_WiFiManager' in wifi_type or 'ESPAT_WiFiManager' in wifi_type): + if "ESPSPI_WiFiManager" in wifi_type or "ESPAT_WiFiManager" in wifi_type: self.wifi = wifi_manager else: raise TypeError("This library requires a WiFiManager object.") - self._aio_headers = [{"X-AIO-KEY":self.key, - "Content-Type":'application/json'}, - {"X-AIO-KEY":self.key,}] + self._aio_headers = [ + {"X-AIO-KEY": self.key, "Content-Type": "application/json"}, + {"X-AIO-KEY": self.key}, + ] @staticmethod def _create_headers(io_headers): @@ -84,9 +452,14 @@ def _create_data(data, metadata): """Creates JSON data payload """ if metadata is not None: - return {'value':data, 'lat':metadata['lat'], 'lon':metadata['lon'], - 'ele':metadata['ele'], 'created_at':metadata['created_at']} - return {'value':data} + return { + "value": data, + "lat": metadata["lat"], + "lon": metadata["lon"], + "ele": metadata["ele"], + "created_at": metadata["created_at"], + } + return {"value": data} @staticmethod def _handle_error(response): @@ -114,9 +487,8 @@ def _post(self, path, payload): :param json payload: JSON data to send to Adafruit IO """ response = self.wifi.post( - path, - json=payload, - headers=self._create_headers(self._aio_headers[0])) + path, json=payload, headers=self._create_headers(self._aio_headers[0]) + ) self._handle_error(response) return response.json() @@ -126,8 +498,8 @@ def _get(self, path): :param str path: Formatted Adafruit IO URL from _compose_path """ response = self.wifi.get( - path, - headers=self._create_headers(self._aio_headers[1])) + path, headers=self._create_headers(self._aio_headers[1]) + ) self._handle_error(response) return response.json() @@ -137,8 +509,8 @@ def _delete(self, path): :param str path: Formatted Adafruit IO URL from _compose_path """ response = self.wifi.delete( - path, - headers=self._create_headers(self._aio_headers[0])) + path, headers=self._create_headers(self._aio_headers[0]) + ) self._handle_error(response) return response.json() @@ -155,8 +527,8 @@ def send_data(self, feed_key, data, metadata=None, precision=None): if precision: try: data = round(data, precision) - except NotImplementedError: # received a non-float value - raise NotImplementedError('Precision requires a floating point value') + except NotImplementedError: # received a non-float value + raise NotImplementedError("Precision requires a floating point value") payload = self._create_data(data, metadata) self._post(path, payload) @@ -185,7 +557,7 @@ def add_feed_to_group(self, group_key, feed_key): :param str feed_key: Feed to add to the group """ path = self._compose_path("groups/{0}/add".format(group_key)) - payload = {'feed_key':feed_key} + payload = {"feed_key": feed_key} return self._post(path, payload) def create_new_group(self, group_key, group_description): @@ -195,7 +567,7 @@ def create_new_group(self, group_key, group_description): :param str group_description: Brief summary about the group """ path = self._compose_path("groups") - payload = {'name':group_key, 'description':group_description} + payload = {"name": group_key, "description": group_description} return self._post(path, payload) def delete_group(self, group_key): @@ -235,9 +607,7 @@ def create_new_feed(self, feed_key, feed_desc=None, feed_license=None): :param str feed_license: Optional feed license """ path = self._compose_path("feeds") - payload = {'name':feed_key, - 'description':feed_desc, - 'license':feed_license} + payload = {"name": feed_key, "description": feed_desc, "license": feed_license} return self._post(path, payload) def delete_feed(self, feed_key): @@ -271,7 +641,18 @@ def receive_time(self): Returns a struct_time from the Adafruit IO Server based on the device's IP address. https://circuitpython.readthedocs.io/en/latest/shared-bindings/time/__init__.html#time.struct_time """ - path = self._compose_path('integrations/time/struct.json') - time = self._get(path) - return struct_time((time['year'], time['mon'], time['mday'], time['hour'], - time['min'], time['sec'], time['wday'], time['yday'], time['isdst'])) + path = self._compose_path("integrations/time/struct.json") + time_struct = self._get(path) + return time.struct_time( + ( + time_struct["year"], + time_struct["mon"], + time_struct["mday"], + time_struct["hour"], + time_struct["min"], + time_struct["sec"], + time_struct["wday"], + time_struct["yday"], + time_struct["isdst"], + ) + ) diff --git a/adafruit_io/adafruit_io_errors.py b/adafruit_io/adafruit_io_errors.py index 9e9ecea..10e0389 100755 --- a/adafruit_io/adafruit_io_errors.py +++ b/adafruit_io/adafruit_io_errors.py @@ -26,16 +26,30 @@ * Author(s): Brent Rubell """ + class AdafruitIO_ThrottleError(Exception): """Adafruit IO request error class for rate-limiting""" + def __init__(self): - super(AdafruitIO_ThrottleError, self).__init__("Number of Adafruit IO Requests exceeded! \ - Please try again in 30 seconds..") + super(AdafruitIO_ThrottleError, self).__init__( + "Number of Adafruit IO Requests exceeded! \ + Please try again in 30 seconds.." + ) + class AdafruitIO_RequestError(Exception): """Adafruit IO request error class""" + def __init__(self, response): response_content = response.json() - error = response_content['error'] - super(AdafruitIO_RequestError, self).__init__("Adafruit IO Error {0}: {1}" - .format(response.status_code, error)) + error = response_content["error"] + super(AdafruitIO_RequestError, self).__init__( + "Adafruit IO Error {0}: {1}".format(response.status_code, error) + ) + + +class AdafruitIO_MQTTError(Exception): + """Adafruit IO MQTT error class""" + + def __init__(self, response): + super(AdafruitIO_MQTTError, self).__init__("MQTT Error: {0}".format(response)) diff --git a/docs/examples.rst b/docs/examples.rst index db69245..6b609f6 100644 --- a/docs/examples.rst +++ b/docs/examples.rst @@ -3,6 +3,6 @@ Simple test Ensure your device works with this simple test. -.. literalinclude:: ../examples/adafruit_io_simpletest_data.py - :caption: examples/adafruit_io_simpletest_data.py +.. literalinclude:: ../examples/http/adafruit_io_simpletest.py + :caption: examples/http/adafruit_io_simpletest.py :linenos: diff --git a/examples/adafruit_io_simpletest_analog_in.py b/examples/http/adafruit_io_analog_in.py similarity index 91% rename from examples/adafruit_io_simpletest_analog_in.py rename to examples/http/adafruit_io_analog_in.py index 99ce01a..74bad6c 100644 --- a/examples/adafruit_io_simpletest_analog_in.py +++ b/examples/http/adafruit_io_analog_in.py @@ -12,8 +12,8 @@ # Import NeoPixel Library import neopixel -# Import Adafruit IO REST Client -from adafruit_io.adafruit_io import RESTClient, AdafruitIO_RequestError +# Import Adafruit IO HTTP Client +from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError # Delay between polling and sending light sensor data, in seconds SENSOR_DELAY = 30 @@ -48,8 +48,8 @@ aio_username = secrets['aio_username'] aio_key = secrets['aio_key'] -# Create an instance of the Adafruit IO REST client -io = RESTClient(aio_username, aio_key, wifi) +# Create an instance of the Adafruit IO HTTP client +io = IO_HTTP(aio_username, aio_key, wifi) try: # Get the 'light' feed from Adafruit IO diff --git a/examples/adafruit_io_simpletest_digital_out.py b/examples/http/adafruit_io_digital_out.py similarity index 91% rename from examples/adafruit_io_simpletest_digital_out.py rename to examples/http/adafruit_io_digital_out.py index d1a9f3f..b370db3 100644 --- a/examples/adafruit_io_simpletest_digital_out.py +++ b/examples/http/adafruit_io_digital_out.py @@ -13,8 +13,8 @@ # Import NeoPixel Library import neopixel -# Import Adafruit IO REST Client -from adafruit_io.adafruit_io import RESTClient, AdafruitIO_RequestError +# Import Adafruit IO HTTP Client +from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError # Get wifi details and more from a secrets.py file try: @@ -46,8 +46,8 @@ aio_username = secrets['aio_username'] aio_key = secrets['aio_key'] -# Create an instance of the Adafruit IO REST client -io = RESTClient(aio_username, aio_key, wifi) +# Create an instance of the Adafruit IO HTTP client +io = IO_HTTP(aio_username, aio_key, wifi) try: # Get the 'digital' feed from Adafruit IO diff --git a/examples/adafruit_io_simpletest_esp_at.py b/examples/http/adafruit_io_esp_at.py similarity index 92% rename from examples/adafruit_io_simpletest_esp_at.py rename to examples/http/adafruit_io_esp_at.py index f75eb29..c5b92d4 100644 --- a/examples/adafruit_io_simpletest_esp_at.py +++ b/examples/http/adafruit_io_esp_at.py @@ -10,8 +10,8 @@ import busio from digitalio import DigitalInOut -# Import Adafruit IO REST Client -from adafruit_io.adafruit_io import RESTClient, AdafruitIO_RequestError +# Import Adafruit IO HTTP Client +from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError # ESP32 AT from adafruit_espatcontrol import adafruit_espatcontrol, adafruit_espatcontrol_wifimanager @@ -62,8 +62,8 @@ aio_username = secrets['aio_username'] aio_key = secrets['aio_key'] -# Create an instance of the Adafruit IO REST client -io = RESTClient(aio_username, aio_key, wifi) +# Create an instance of the Adafruit IO HTTP client +io = IO_HTTP(aio_username, aio_key, wifi) try: # Get the 'temperature' feed from Adafruit IO diff --git a/examples/adafruit_io_simpletest_feeds.py b/examples/http/adafruit_io_feeds.py similarity index 91% rename from examples/adafruit_io_simpletest_feeds.py rename to examples/http/adafruit_io_feeds.py index b7d6bc5..f4c4969 100644 --- a/examples/adafruit_io_simpletest_feeds.py +++ b/examples/http/adafruit_io_feeds.py @@ -11,8 +11,8 @@ # Import NeoPixel Library import neopixel -# Import Adafruit IO REST Client -from adafruit_io.adafruit_io import RESTClient +# Import Adafruit IO HTTP Client +from adafruit_io.adafruit_io import IO_HTTP # Get wifi details and more from a secrets.py file try: @@ -44,8 +44,8 @@ aio_username = secrets['aio_username'] aio_key = secrets['aio_key'] -# Create an instance of the Adafruit IO REST client -io = RESTClient(aio_username, aio_key, wifi) +# Create an instance of the Adafruit IO HTTP client +io = IO_HTTP(aio_username, aio_key, wifi) # Create a new 'circuitpython' feed with a description print('Creating new Adafruit IO feed...') diff --git a/examples/adafruit_io_simpletest_groups.py b/examples/http/adafruit_io_groups.py similarity index 91% rename from examples/adafruit_io_simpletest_groups.py rename to examples/http/adafruit_io_groups.py index ded81f2..32f8d25 100644 --- a/examples/adafruit_io_simpletest_groups.py +++ b/examples/http/adafruit_io_groups.py @@ -11,8 +11,8 @@ # Import NeoPixel Library import neopixel -# Import Adafruit IO REST Client -from adafruit_io.adafruit_io import RESTClient +# Import Adafruit IO HTTP Client +from adafruit_io.adafruit_io import IO_HTTP # Get wifi details and more from a secrets.py file try: @@ -43,8 +43,8 @@ aio_username = secrets['aio_username'] aio_key = secrets['aio_key'] -# Create an instance of the Adafruit IO REST client -io = RESTClient(aio_username, aio_key, wifi) +# Create an instance of the Adafruit IO HTTP client +io = IO_HTTP(aio_username, aio_key, wifi) # Create a new group print('Creating a new Adafruit IO Group...') diff --git a/examples/adafruit_io_simpletest_metadata.py b/examples/http/adafruit_io_metadata.py similarity index 90% rename from examples/adafruit_io_simpletest_metadata.py rename to examples/http/adafruit_io_metadata.py index b6f7650..2b0c5f4 100644 --- a/examples/adafruit_io_simpletest_metadata.py +++ b/examples/http/adafruit_io_metadata.py @@ -12,8 +12,8 @@ # Import NeoPixel Library import neopixel -# Import Adafruit IO REST Client -from adafruit_io.adafruit_io import RESTClient, AdafruitIO_RequestError +# Import Adafruit IO HTTP Client +from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError # Get wifi details and more from a secrets.py file try: @@ -45,8 +45,8 @@ aio_username = secrets['aio_username'] aio_key = secrets['aio_key'] -# Create an instance of the Adafruit IO REST client -io = RESTClient(aio_username, aio_key, wifi) +# Create an instance of the Adafruit IO HTTP client +io = IO_HTTP(aio_username, aio_key, wifi) try: # Get the 'location' feed from Adafruit IO diff --git a/examples/adafruit_io_simpletest_randomizer.py b/examples/http/adafruit_io_randomizer.py similarity index 91% rename from examples/adafruit_io_simpletest_randomizer.py rename to examples/http/adafruit_io_randomizer.py index b2ea801..2717a18 100644 --- a/examples/adafruit_io_simpletest_randomizer.py +++ b/examples/http/adafruit_io_randomizer.py @@ -13,8 +13,8 @@ # Import NeoPixel Library import neopixel -# Import Adafruit IO REST Client -from adafruit_io.adafruit_io import RESTClient +# Import Adafruit IO HTTP Client +from adafruit_io.adafruit_io import IO_HTTP # Get wifi details and more from a secrets.py file try: @@ -46,8 +46,8 @@ aio_username = secrets['aio_username'] aio_key = secrets['aio_key'] -# Create an instance of the Adafruit IO REST client -io = RESTClient(aio_username, aio_key, wifi) +# Create an instance of the Adafruit IO HTTP client +io = IO_HTTP(aio_username, aio_key, wifi) # Random Data ID # (to obtain this value, visit diff --git a/examples/adafruit_io_simpletest_data.py b/examples/http/adafruit_io_simpletest.py similarity index 91% rename from examples/adafruit_io_simpletest_data.py rename to examples/http/adafruit_io_simpletest.py index af55dfd..eaa9277 100644 --- a/examples/adafruit_io_simpletest_data.py +++ b/examples/http/adafruit_io_simpletest.py @@ -12,8 +12,8 @@ # Import NeoPixel Library import neopixel -# Import Adafruit IO REST Client -from adafruit_io.adafruit_io import RESTClient, AdafruitIO_RequestError +# Import Adafruit IO HTTP Client +from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError # Get wifi details and more from a secrets.py file try: @@ -45,8 +45,8 @@ aio_username = secrets['aio_username'] aio_key = secrets['aio_key'] -# Create an instance of the Adafruit IO REST client -io = RESTClient(aio_username, aio_key, wifi) +# Create an instance of the Adafruit IO HTTP client +io = IO_HTTP(aio_username, aio_key, wifi) try: # Get the 'temperature' feed from Adafruit IO diff --git a/examples/adafruit_io_simpletest_temperature.py b/examples/http/adafruit_io_temperature.py similarity index 92% rename from examples/adafruit_io_simpletest_temperature.py rename to examples/http/adafruit_io_temperature.py index f75bb84..d5085cc 100644 --- a/examples/adafruit_io_simpletest_temperature.py +++ b/examples/http/adafruit_io_temperature.py @@ -17,8 +17,8 @@ # Import NeoPixel Library import neopixel -# Import Adafruit IO REST Client -from adafruit_io.adafruit_io import RESTClient, AdafruitIO_RequestError +# Import Adafruit IO HTTP Client +from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError # Import ADT7410 Library import adafruit_adt7410 @@ -53,8 +53,8 @@ aio_username = secrets['aio_username'] aio_key = secrets['aio_key'] -# Create an instance of the Adafruit IO REST client -io = RESTClient(aio_username, aio_key, wifi) +# Create an instance of the Adafruit IO HTTP client +io = IO_HTTP(aio_username, aio_key, wifi) try: # Get the 'temperature' feed from Adafruit IO diff --git a/examples/adafruit_io_simpletest_weather.py b/examples/http/adafruit_io_weather.py similarity index 92% rename from examples/adafruit_io_simpletest_weather.py rename to examples/http/adafruit_io_weather.py index 8d131bf..3182584 100644 --- a/examples/adafruit_io_simpletest_weather.py +++ b/examples/http/adafruit_io_weather.py @@ -14,8 +14,8 @@ # Import NeoPixel Library import neopixel -# Import Adafruit IO REST Client -from adafruit_io.adafruit_io import RESTClient +# Import Adafruit IO HTTP Client +from adafruit_io.adafruit_io import IO_HTTP # Get wifi details and more from a secrets.py file try: @@ -47,8 +47,8 @@ aio_username = secrets['aio_username'] aio_key = secrets['aio_key'] -# Create an instance of the Adafruit IO REST client -io = RESTClient(aio_username, aio_key, wifi) +# Create an instance of the Adafruit IO HTTP client +io = IO_HTTP(aio_username, aio_key, wifi) # Weather Location ID # (to obtain this value, visit diff --git a/examples/mqtt/adafruit_io_groups.py b/examples/mqtt/adafruit_io_groups.py new file mode 100755 index 0000000..a1a567a --- /dev/null +++ b/examples/mqtt/adafruit_io_groups.py @@ -0,0 +1,119 @@ +# Subscribing to an Adafruit IO Group +# and Publishing to the feeds in the group +import time +from random import randint + +import board +import busio +from adafruit_esp32spi import adafruit_esp32spi +from adafruit_esp32spi import adafruit_esp32spi_wifimanager +import adafruit_esp32spi.adafruit_esp32spi_socket as socket +from digitalio import DigitalInOut +import neopixel +from adafruit_io.adafruit_io import IO_MQTT +from adafruit_minimqtt import MQTT + +### WiFi ### + +# Get wifi details and more from a secrets.py file +try: + from secrets import secrets +except ImportError: + print("WiFi secrets are kept in secrets.py, please add them there!") + raise + +# If you are using a board with pre-defined ESP32 Pins: +esp32_cs = DigitalInOut(board.ESP_CS) +esp32_ready = DigitalInOut(board.ESP_BUSY) +esp32_reset = DigitalInOut(board.ESP_RESET) + +# If you have an externally connected ESP32: +# esp32_cs = DigitalInOut(board.D9) +# esp32_ready = DigitalInOut(board.D10) +# esp32_reset = DigitalInOut(board.D5) + +spi = busio.SPI(board.SCK, board.MOSI, board.MISO) +esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) +"""Use below for Most Boards""" +status_light = neopixel.NeoPixel( + board.NEOPIXEL, 1, brightness=0.2 +) # Uncomment for Most Boards +"""Uncomment below for ItsyBitsy M4""" +# status_light = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2) +# Uncomment below for an externally defined RGB LED +# import adafruit_rgbled +# from adafruit_esp32spi import PWMOut +# RED_LED = PWMOut.PWMOut(esp, 26) +# GREEN_LED = PWMOut.PWMOut(esp, 27) +# BLUE_LED = PWMOut.PWMOut(esp, 25) +# status_light = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED) +wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) + + +# Define callback functions which will be called when certain events happen. +# pylint: disable=unused-argument +def connected(client): + # Connected function will be called when the client is connected to Adafruit IO. + # This is a good place to subscribe to feed changes. The client parameter + # passed to this function is the Adafruit IO MQTT client so you can make + # calls against it easily. + print("Connected to Adafruit IO!") + + # Subscribe to Group + io.subscribe(group_key=group_name) + +# pylint: disable=unused-argument +def disconnected(client): + # Disconnected function will be called when the client disconnects. + print("Disconnected from Adafruit IO!") + +# 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 + +# Group name +group_name = "weatherstation" + +# Feeds within the group +temp_feed = "weatherstation.temperature" +humid_feed = "weatherstation.humidity" + +# Connect to Adafruit IO +io.connect() + +print("Publishing new messages to group feeds every 5 seconds...") + +while True: + io.loop() + temp_reading = randint(0, 100) + print("Publishing value {0} to feed: {1}".format(temp_reading, temp_feed)) + io.publish(temp_feed, temp_reading) + + humid_reading = randint(0, 100) + print("Publishing value {0} to feed: {1}".format(humid_reading, humid_feed)) + io.publish(humid_feed, humid_reading) + time.sleep(5) diff --git a/examples/mqtt/adafruit_io_location.py b/examples/mqtt/adafruit_io_location.py new file mode 100755 index 0000000..76c0a07 --- /dev/null +++ b/examples/mqtt/adafruit_io_location.py @@ -0,0 +1,114 @@ +# Example of tagging data with location values +# and sending it to an Adafruit IO feed. + +import board +import busio +from digitalio import DigitalInOut +from adafruit_esp32spi import adafruit_esp32spi +from adafruit_esp32spi import adafruit_esp32spi_wifimanager +import adafruit_esp32spi.adafruit_esp32spi_socket as socket +import neopixel + + +from adafruit_minimqtt import MQTT +from adafruit_io.adafruit_io import IO_MQTT + +### WiFi ### + +# Get wifi details and more from a secrets.py file +try: + from secrets import secrets +except ImportError: + print("WiFi secrets are kept in secrets.py, please add them there!") + raise + +# If you are using a board with pre-defined ESP32 Pins: +esp32_cs = DigitalInOut(board.ESP_CS) +esp32_ready = DigitalInOut(board.ESP_BUSY) +esp32_reset = DigitalInOut(board.ESP_RESET) + +# If you have an externally connected ESP32: +# esp32_cs = DigitalInOut(board.D9) +# esp32_ready = DigitalInOut(board.D10) +# esp32_reset = DigitalInOut(board.D5) + +spi = busio.SPI(board.SCK, board.MOSI, board.MISO) +esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) +"""Use below for Most Boards""" +status_light = neopixel.NeoPixel( + board.NEOPIXEL, 1, brightness=0.2 +) # Uncomment for Most Boards +"""Uncomment below for ItsyBitsy M4""" +# status_light = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2) +# Uncomment below for an externally defined RGB LED +# import adafruit_rgbled +# from adafruit_esp32spi import PWMOut +# RED_LED = PWMOut.PWMOut(esp, 26) +# GREEN_LED = PWMOut.PWMOut(esp, 27) +# BLUE_LED = PWMOut.PWMOut(esp, 25) +# status_light = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED) +wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) + +# Define callback functions which will be called when certain events happen. +# pylint: disable=unused-argument +def connected(client): + # Connected function will be called when the client is connected to Adafruit IO. + # This is a good place to subscribe to feed changes. The client parameter + # passed to this function is the Adafruit IO MQTT client so you can make + # calls against it easily. + print("Connected to Adafruit IO!") + + # Subscribe to a feed named location + io.subscribe("location") + +# pylint: disable=unused-argument +def disconnected(client): + # Disconnected function will be called when the client disconnects. + print("Disconnected from Adafruit IO!") + +# 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() + +# Set data +data_value = 42 + +# Set up metadata associated with data_value +# lat, lon, ele +metadata = "40.726190, -74.005334, -6" + +# Send data and location metadata to the 'location' feed +print("Sending data and location metadata to IO...") +io.publish("location", data_value, metadata) +print("Data sent!") + + +# Listen forever... +io.loop_blocking() diff --git a/examples/mqtt/adafruit_io_simpletest.py b/examples/mqtt/adafruit_io_simpletest.py new file mode 100755 index 0000000..b7cd68b --- /dev/null +++ b/examples/mqtt/adafruit_io_simpletest.py @@ -0,0 +1,120 @@ +# Example of using the Adafruit IO CircuitPython MQTT client +# to subscribe to an Adafruit IO feed and publish random data +# to be received by the feed. +# +# Example by Tony DiCola for Adafruit Industries +# Modified by Brent Rubell for Adafruit Industries, 2019 +import time +from random import randint + + +import board +import busio +from adafruit_esp32spi import adafruit_esp32spi +from adafruit_esp32spi import adafruit_esp32spi_wifimanager +import adafruit_esp32spi.adafruit_esp32spi_socket as socket +from digitalio import DigitalInOut +import neopixel +from adafruit_io.adafruit_io import IO_MQTT +from adafruit_minimqtt import MQTT + +### WiFi ### + +# Get wifi details and more from a secrets.py file +try: + from secrets import secrets +except ImportError: + print("WiFi secrets are kept in secrets.py, please add them there!") + raise + +# If you are using a board with pre-defined ESP32 Pins: +esp32_cs = DigitalInOut(board.ESP_CS) +esp32_ready = DigitalInOut(board.ESP_BUSY) +esp32_reset = DigitalInOut(board.ESP_RESET) + +# If you have an externally connected ESP32: +# esp32_cs = DigitalInOut(board.D9) +# esp32_ready = DigitalInOut(board.D10) +# esp32_reset = DigitalInOut(board.D5) + +spi = busio.SPI(board.SCK, board.MOSI, board.MISO) +esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) +"""Use below for Most Boards""" +status_light = neopixel.NeoPixel( + board.NEOPIXEL, 1, brightness=0.2 +) # Uncomment for Most Boards +"""Uncomment below for ItsyBitsy M4""" +# status_light = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2) +# Uncomment below for an externally defined RGB LED +# import adafruit_rgbled +# from adafruit_esp32spi import PWMOut +# RED_LED = PWMOut.PWMOut(esp, 26) +# GREEN_LED = PWMOut.PWMOut(esp, 27) +# BLUE_LED = PWMOut.PWMOut(esp, 25) +# status_light = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED) +wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) + +# Define callback functions which will be called when certain events happen. +# pylint: disable=unused-argument +def connected(client): + # Connected function will be called when the client is connected to Adafruit IO. + # This is a good place to subscribe to feed changes. The client parameter + # passed to this function is the Adafruit IO MQTT client so you can make + # calls against it easily. + print("Connected to Adafruit IO! Listening for DemoFeed changes...") + # Subscribe to changes on a feed named DemoFeed. + client.subscribe("DemoFeed") + +# pylint: disable=unused-argument +def disconnected(client): + # Disconnected function will be called when the client disconnects. + print("Disconnected from Adafruit IO!") + +# 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. +last = 0 +print("Publishing a new message every 10 seconds...") +while True: + # Explicitly pump the message loop. + io.loop() + # Send a new message every 10 seconds. + if (time.monotonic() - last) >= 5: + value = randint(0, 100) + print("Publishing {0} to DemoFeed.".format(value)) + io.publish("DemoFeed", value) + last = time.monotonic() + + +# You can also call loop_blocking if you only want to receive values. +# NOTE: If uncommented, no code below this line will run. +# io.loop_blocking() diff --git a/examples/mqtt/adafruit_io_time.py b/examples/mqtt/adafruit_io_time.py new file mode 100755 index 0000000..a07b117 --- /dev/null +++ b/examples/mqtt/adafruit_io_time.py @@ -0,0 +1,115 @@ +# Adafruit IO provides some built-in MQTT topics +# for obtaining the current server time, if you don't have +# access to a RTC module. + +import board +import busio +from digitalio import DigitalInOut +from adafruit_esp32spi import adafruit_esp32spi +from adafruit_esp32spi import adafruit_esp32spi_wifimanager +import adafruit_esp32spi.adafruit_esp32spi_socket as socket +import neopixel + +from adafruit_minimqtt import MQTT +from adafruit_io.adafruit_io import IO_MQTT + +### WiFi ### + +# Get wifi details and more from a secrets.py file +try: + from secrets import secrets +except ImportError: + print("WiFi secrets are kept in secrets.py, please add them there!") + raise + +# If you are using a board with pre-defined ESP32 Pins: +esp32_cs = DigitalInOut(board.ESP_CS) +esp32_ready = DigitalInOut(board.ESP_BUSY) +esp32_reset = DigitalInOut(board.ESP_RESET) + +# If you have an externally connected ESP32: +# esp32_cs = DigitalInOut(board.D9) +# esp32_ready = DigitalInOut(board.D10) +# esp32_reset = DigitalInOut(board.D5) + +spi = busio.SPI(board.SCK, board.MOSI, board.MISO) +esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) +"""Use below for Most Boards""" +status_light = neopixel.NeoPixel( + board.NEOPIXEL, 1, brightness=0.2 +) # Uncomment for Most Boards +"""Uncomment below for ItsyBitsy M4""" +# status_light = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2) +# Uncomment below for an externally defined RGB LED +# import adafruit_rgbled +# from adafruit_esp32spi import PWMOut +# RED_LED = PWMOut.PWMOut(esp, 26) +# GREEN_LED = PWMOut.PWMOut(esp, 27) +# BLUE_LED = PWMOut.PWMOut(esp, 25) +# status_light = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED) +wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light) + +# Define callback functions which will be called when certain events happen. +# pylint: disable=unused-argument +def connected(client): + # Connected function will be called when the client is connected to Adafruit IO. + # This is a good place to subscribe to feed changes. The client parameter + # passed to this function is the Adafruit IO MQTT client so you can make + # calls against it easily. + print("Connected to Adafruit IO!") + + # Subscribe to time/seconds topic + # https://io.adafruit.com/api/docs/mqtt.html#time-seconds + io.subscribe_to_time('seconds') + + # Subscribe to time/millis topic + # https://io.adafruit.com/api/docs/mqtt.html#time-millis + io.subscribe_to_time('millis') + + # Subscribe to time/ISO-8601 topic + # https://io.adafruit.com/api/docs/mqtt.html#time-iso-8601 + io.subscribe_to_time('iso') + + # Subscribe to time/hours topic + # NOTE: This topic only publishes once every hour. + # https://io.adafruit.com/api/docs/mqtt.html#adafruit-io-monitor + io.subscribe_to_time('hours') + +# pylint: disable=unused-argument +def disconnected(client): + # Disconnected function will be called when the client disconnects. + print("Disconnected from Adafruit IO!") + +# 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() + +# Listen forever... +io.loop_blocking()