Skip to content

Commit

Permalink
Merge pull request #79 from brentru/integrate-darkskies
Browse files Browse the repository at this point in the history
Integrate Dark Sky Weather Forecasts
  • Loading branch information
brentru authored Jan 8, 2019
2 parents 19f8cea + dc54320 commit 37403c9
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 60 deletions.
2 changes: 1 addition & 1 deletion Adafruit_IO/_version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "2.0.18"
__version__ = "2.0.19"
16 changes: 13 additions & 3 deletions Adafruit_IO/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ def __init__(self, username, key, proxies=None, base_url='https://io.adafruit.co
self.base_url = base_url.rstrip('/')

def _compose_url(self, path, is_time=None):
if not is_time:
if is_time: # 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)
else:
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):
Expand Down Expand Up @@ -161,6 +161,16 @@ def receive_time(self, time):
"""
timepath = "time/{0}".format(time)
return self._get(timepath, is_time=True)

def receive_weather(self, weather_id=None):
"""Adafruit IO Weather Service, Powered by Dark Sky
:param int id: optional ID for retrieving a specified weather record.
"""
if weather_id:
weatherpath = "integrations/weather/{0}".format(weather_id)
else:
weatherpath = "integrations/weather"
return self._get(weatherpath)

def receive(self, feed):
"""Retrieve the most recent value for the specified feed. Returns a Data
Expand Down
23 changes: 21 additions & 2 deletions Adafruit_IO/mqtt_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@

logger = logging.getLogger(__name__)

forecast_types = ["current", "forecast_minutes_5",
"forecast_minutes_30", "forecast_hours_1",
"forecast_hours_2", "forecast_hours_6",
"forecast_hours_24", "forecast_days_1",
"forecast_days_2", "forecast_days_5",]

class MQTTClient(object):
"""Interface for publishing and subscribing to feed changes on Adafruit IO
Expand Down Expand Up @@ -103,15 +108,18 @@ def _mqtt_message(self, client, userdata, msg):
assume topic looks like `username/topic/id`
"""
parsed_topic = msg.topic.split('/')
if self.on_message is not None:
topic = parsed_topic[2]
if self.on_message is not None and parsed_topic[2] == 'weather':
topic = parsed_topic[4] # parse out the forecast type
payload = '' if msg.payload is None else msg.payload.decode('utf-8')
elif self.on_message is not None and parsed_topic[0] == 'time':
topic = parsed_topic[0]
payload = msg.payload.decode('utf-8')
elif self.on_message is not None and parsed_topic[1] == 'groups':
topic = parsed_topic[3]
payload = msg.payload.decode('utf-8')
else: # default topic
topic = parsed_topic[2]
payload = '' if msg.payload is None else msg.payload.decode('utf-8')
self.on_message(self, topic, payload)

def _mqtt_subscribe(client, userdata, mid, granted_qos):
Expand Down Expand Up @@ -197,6 +205,17 @@ def subscribe_group(self, group_id):
"""
self._client.subscribe('{0}/groups/{1}'.format(self._username, group_id))

def subscribe_weather(self, weather_id, forecast_type):
"""Subscribe to Adafruit IO Weather
:param int weather_id: weather record you want data for
:param string type: type of forecast data requested
"""
if forecast_type in forecast_types:
self._client.subscribe('{0}/integration/weather/{1}/{2}'.format(self._username, weather_id, forecast_type))
else:
raise TypeError("Invalid Forecast Type Specified.")
return

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:
Expand Down
54 changes: 0 additions & 54 deletions examples/basics/digital_in.py

This file was deleted.

125 changes: 125 additions & 0 deletions examples/mqtt/mqtt_weather.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
"""
Example of using the Adafruit IO MQTT Client
for subscribing to the Adafruit IO Weather Service
Note: This feature is avaliable for IO Plus Subscribers ONLY
API Documentation: https://io.adafruit.com/services/weather
Author: Brent Rubell for Adafruit Industries
"""

# Import standard python modules.
import sys
import json

# 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 = 'KEY'

# Set to your Adafruit IO username.
# (go to https://accounts.adafruit.com to find your username)
ADAFRUIT_IO_USERNAME = 'USER'

# Set to ID of the forecast to subscribe to for updates
forecast_id = 2153

# Set to the ID of the feed to subscribe to for updates.
"""
Valid forecast types are:
current
forecast_minutes_5
forecast_minutes_30
forecast_hours_1
forecast_hours_2
forecast_hours_6
forecast_hours_24
forecast_days_1
forecast_days_2
forecast_days_5
"""
# Subscribe to the current forecast
forecast_today = 'current'
# Subscribe to tomorrow's forecast
forecast_two_days = 'forecast_days_2'
# Subscribe to forecast in 5 days
forecast_in_5_days = 'forecast_days_5'

# Define callback functions which will be called when certain events happen.
# pylint: disable=redefined-outer-name
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 to forecast: {0}...'.format(forecast_id))
# Subscribe to changes on the current forecast.
client.subscribe_weather(forecast_id, forecast_today)

# Subscribe to changes on tomorrow's forecast.
client.subscribe_weather(forecast_id, forecast_two_days)

# Subscribe to changes on forecast in 5 days.
client.subscribe_weather(forecast_id, forecast_in_5_days)

# pylint: disable=unused-argument
def disconnected(client):
# Disconnected function will be called when the client disconnects.
print('Disconnected from Adafruit IO!')
sys.exit(1)

# pylint: disable=unused-argument
def message(client, topic, payload):
"""Message function will be called when any subscribed forecast has an update.
Weather data is updated at most once every 20 minutes.
"""
# forecast based on mqtt topic
if topic == 'current':
# Print out today's forecast
today_forecast = payload
print('\nCurrent Forecast')
parseForecast(today_forecast)
elif topic == 'forecast_days_2':
# Print out tomorrow's forecast
two_day_forecast = payload
print('\nWeather in Two Days')
parseForecast(two_day_forecast)
elif topic == 'forecast_days_5':
# Print out forecast in 5 days
five_day_forecast = payload
print('\nWeather in 5 Days')
parseForecast(five_day_forecast)

def parseForecast(forecast_data):
"""Parses and prints incoming forecast data
"""
# incoming data is a utf-8 string, encode it as a json object
forecast = json.loads(forecast_data)
# Print out the forecast
try:
print('It is {0} and {1}F.'.format(forecast['summary'], forecast['temperature']))
except KeyError:
# future weather forecasts return a high and low temperature, instead of 'temperature'
print('It will be {0} with a high of {1}F and a low of {2}F.'.format(
forecast['summary'], forecast['temperatureLow'], forecast['temperatureHigh']))
print('with humidity of {0}%, wind speed of {1}mph, and {2}% chance of precipitation.'.format(
forecast['humidity'], forecast['windSpeed'], forecast['precipProbability']))

# Create an MQTT client instance.
client = MQTTClient(ADAFRUIT_IO_USERNAME, ADAFRUIT_IO_KEY)

# Setup the callback functions defined above.
client.on_connect = connected
client.on_disconnect = disconnected
client.on_message = message

# Connect to the Adafruit IO server.
client.connect()

# Start a message loop that blocks forever waiting for MQTT messages to be
# received. Note there are other options for running the event loop like doing
# so in a background thread--see the mqtt_client.py example to learn more.
client.loop_blocking()

0 comments on commit 37403c9

Please sign in to comment.