diff --git a/Adafruit_IO/client.py b/Adafruit_IO/client.py index 5031718..54cdf00 100644 --- a/Adafruit_IO/client.py +++ b/Adafruit_IO/client.py @@ -1,4 +1,4 @@ -# Copyright (c) 2014 Adafruit Industries +# Copyright (c) 2018 Adafruit Industries # Authors: Justin Cooper & Tony DiCola # Permission is hereby granted, free of charge, to any person obtaining a copy @@ -60,8 +60,11 @@ def __init__(self, username, key, proxies=None, base_url='https://io.adafruit.co # constructing the path. self.base_url = base_url.rstrip('/') - def _compose_url(self, path): - return '{0}/api/{1}/{2}/{3}'.format(self.base_url, self.api_version, self.username, path) + def _compose_url(self, path, is_time=None): + if not is_time: + return '{0}/api/{1}/{2}/{3}'.format(self.base_url, self.api_version, self.username, path) + else: # return a call to https://io.adafruit.com/api/v2/time/{unit} + return '{0}/api/{1}/{2}'.format(self.base_url, self.api_version, path) def _handle_error(self, response): @@ -78,12 +81,15 @@ def _headers(self, given): headers.update(given) return headers - def _get(self, path): - response = requests.get(self._compose_url(path), + def _get(self, path, is_time=None): + response = requests.get(self._compose_url(path, is_time), headers=self._headers({'X-AIO-Key': self.key}), proxies=self.proxies) self._handle_error(response) - return response.json() + if not is_time: + return response.json() + else: # time doesn't need to serialize into json, just return text + return response.text def _post(self, path, data): response = requests.post(self._compose_url(path), @@ -141,6 +147,15 @@ def send_location_data(self, feed, value, lat, lon, ele): """ return self.create_data(feed, Data(value = value,lat=lat, lon=lon, ele=ele)) + def receive_time(self, time): + """Returns the time from the Adafruit IO server. + + args: + - time (string): millis, seconds, ISO-8601 + """ + timepath = "time/{0}".format(time) + return self._get(timepath, is_time=True) + def receive(self, feed): """Retrieve the most recent value for the specified feed. Feed can be a feed ID, feed key, or feed name. Returns a Data instance whose value diff --git a/Adafruit_IO/mqtt_client.py b/Adafruit_IO/mqtt_client.py index 9899e8c..638d038 100644 --- a/Adafruit_IO/mqtt_client.py +++ b/Adafruit_IO/mqtt_client.py @@ -100,7 +100,10 @@ def _mqtt_message(self, client, userdata, msg): if self.on_message is not None and self._username == parsed_topic[0]: feed = parsed_topic[2] payload = '' if msg.payload is None else msg.payload.decode('utf-8') - self.on_message(self, feed, payload) + elif self.on_message is not None and parsed_topic[0] == 'time': + feed = parsed_topic[0] + payload = msg.payload.decode('utf-8') + self.on_message(self, feed, payload) def connect(self, **kwargs): """Connect to the Adafruit.IO service. Must be called before any loop @@ -163,6 +166,22 @@ def subscribe(self, feed_id): """ self._client.subscribe('{0}/feeds/{1}'.format(self._username, feed_id)) + def subscribe_time(self, time): + """Subscribe to changes on the Adafruit IO time feeds. When the feed is + updated, the on_message function will be called and publish a new value: + time = + millis: milliseconds + seconds: seconds + iso: ISO-8601 (https://en.wikipedia.org/wiki/ISO_8601) + """ + if time == 'millis' or time == 'seconds': + self._client.subscribe('time/{0}'.format(time)) + elif time == 'iso': + self._client.subscribe('time/ISO-8601') + else: + print('ERROR: Invalid time type specified') + return + def publish(self, feed_id, value): """Publish a value to a specified feed. diff --git a/examples/aio_basics/adafruitio_17_time.py b/examples/aio_basics/adafruitio_17_time.py new file mode 100644 index 0000000..ce20da7 --- /dev/null +++ b/examples/aio_basics/adafruitio_17_time.py @@ -0,0 +1,38 @@ +""" +adafruitio_17_time.py +==================================== +Don't have a RTC handy and need +accurate time measurements? + +Let Adafruit IO serve real-time values! + +Author: Brent Rubell +""" +# Import Adafruit IO REST client. +from Adafruit_IO import Client, Feed, Data, RequestError + +# Set to your Adafruit IO key. +# Remember, your key is a secret, +# so make sure not to publish it when you publish this code! +ADAFRUIT_IO_KEY = 'YOUR_AIO_KEY' + +# Set to your Adafruit IO username. +# (go to https://accounts.adafruit.com to find your username) +ADAFRUIT_IO_USERNAME = 'YOUR_AIO_USERNAME' + +# Create an instance of the REST client. +aio = Client(ADAFRUIT_IO_USERNAME, ADAFRUIT_IO_KEY) + +print('---Adafruit IO REST API Time Helpers---') + +print('Seconds: aio.receive_time(seconds)') +secs_val = aio.receive_time('seconds') +print('\t' + secs_val) + +print('Milliseconds: aio.receive_time(millis)') +ms_val = aio.receive_time('millis') +print('\t' + ms_val) + +print('ISO-8601: aio.receive_time(ISO-8601)') +iso_val = aio.receive_time('ISO-8601') +print('\t' + iso_val) diff --git a/examples/mqtt/mqtt_time.py b/examples/mqtt/mqtt_time.py new file mode 100644 index 0000000..e91f820 --- /dev/null +++ b/examples/mqtt/mqtt_time.py @@ -0,0 +1,64 @@ +""" +mqtt_time.py +============================================ +example of utilizing MQTT time topics to grab +the time from the Adafruit IO server. + +Author: Brent Rubell +""" + +# Import standard python modules. +import sys +import time + +# Import Adafruit IO MQTT client. +from Adafruit_IO import MQTTClient + +# Set to your Adafruit IO key. +# Remember, your key is a secret, +# so make sure not to publish it when you publish this code! +ADAFRUIT_IO_KEY = 'YOUR_AIO_KEY' + +# Set to your Adafruit IO username. +# (go to https://accounts.adafruit.com to find your username) +ADAFRUIT_IO_USERNAME = 'YOUR_AIO_USERNAME' + +def disconnected(client): + # Disconnected function will be called when the client disconnects. + print('Disconnected from Adafruit IO!') + sys.exit(1) + +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('\t Feed {0} received new value: {1}'.format(feed_id, payload)) + + +# Create a SECURE MQTT client instance +# Note: This client will default to secure, an optional parameter can be added +# to make it insecure, comment out the below line +# client = MQTTClient(ADAFRUIT_IO_USERNAME, ADAFRUIT_IO_KEY, secure=False) +client = MQTTClient(ADAFRUIT_IO_USERNAME, ADAFRUIT_IO_KEY) + +# Setup the callback functions defined above. +client.on_disconnect = disconnected +client.on_message = message + +# Connect to the Adafruit IO server. +client.connect() + +# time per loop +loop_time = 2 + +client.loop_background() +while True: + print('* Subscribing to /time/seconds') + client.subscribe_time('seconds') + time.sleep(loop_time) + print('* Subscribing to /time/millis') + client.subscribe_time('millis') + time.sleep(loop_time) + print('* Subscribing to iso-8601') + client.subscribe_time('iso') + time.sleep(loop_time) diff --git a/setup.py b/setup.py index f514328..a628730 100644 --- a/setup.py +++ b/setup.py @@ -35,6 +35,6 @@ keywords = 'Adafruit IO', classifiers = classifiers, description = 'Client library for Adafruit IO (http://io.adafruit.com/).', - long_description = open('README.md').read(), + long_description = open('README.rst').read(), install_requires = ["requests", "paho-mqtt"] )