Skip to content

Integrate Dark Sky Weather Forecasts #79

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

Merged
merged 17 commits into from
Jan 8, 2019
Merged
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()