Skip to content

Commit 37403c9

Browse files
authored
Merge pull request #79 from brentru/integrate-darkskies
Integrate Dark Sky Weather Forecasts
2 parents 19f8cea + dc54320 commit 37403c9

File tree

5 files changed

+160
-60
lines changed

5 files changed

+160
-60
lines changed

Adafruit_IO/_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "2.0.18"
1+
__version__ = "2.0.19"

Adafruit_IO/client.py

+13-3
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,10 @@ def __init__(self, username, key, proxies=None, base_url='https://io.adafruit.co
6161
self.base_url = base_url.rstrip('/')
6262

6363
def _compose_url(self, path, is_time=None):
64-
if not is_time:
64+
if is_time: # return a call to https://io.adafruit.com/api/v2/time/{unit}
65+
return '{0}/api/{1}/{2}'.format(self.base_url, self.api_version, path)
66+
else:
6567
return '{0}/api/{1}/{2}/{3}'.format(self.base_url, self.api_version, self.username, path)
66-
else: # return a call to https://io.adafruit.com/api/v2/time/{unit}
67-
return '{0}/api/{1}/{2}'.format(self.base_url, self.api_version, path)
6868

6969

7070
def _handle_error(self, response):
@@ -161,6 +161,16 @@ def receive_time(self, time):
161161
"""
162162
timepath = "time/{0}".format(time)
163163
return self._get(timepath, is_time=True)
164+
165+
def receive_weather(self, weather_id=None):
166+
"""Adafruit IO Weather Service, Powered by Dark Sky
167+
:param int id: optional ID for retrieving a specified weather record.
168+
"""
169+
if weather_id:
170+
weatherpath = "integrations/weather/{0}".format(weather_id)
171+
else:
172+
weatherpath = "integrations/weather"
173+
return self._get(weatherpath)
164174

165175
def receive(self, feed):
166176
"""Retrieve the most recent value for the specified feed. Returns a Data

Adafruit_IO/mqtt_client.py

+21-2
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929

3030
logger = logging.getLogger(__name__)
3131

32+
forecast_types = ["current", "forecast_minutes_5",
33+
"forecast_minutes_30", "forecast_hours_1",
34+
"forecast_hours_2", "forecast_hours_6",
35+
"forecast_hours_24", "forecast_days_1",
36+
"forecast_days_2", "forecast_days_5",]
3237

3338
class MQTTClient(object):
3439
"""Interface for publishing and subscribing to feed changes on Adafruit IO
@@ -103,15 +108,18 @@ def _mqtt_message(self, client, userdata, msg):
103108
assume topic looks like `username/topic/id`
104109
"""
105110
parsed_topic = msg.topic.split('/')
106-
if self.on_message is not None:
107-
topic = parsed_topic[2]
111+
if self.on_message is not None and parsed_topic[2] == 'weather':
112+
topic = parsed_topic[4] # parse out the forecast type
108113
payload = '' if msg.payload is None else msg.payload.decode('utf-8')
109114
elif self.on_message is not None and parsed_topic[0] == 'time':
110115
topic = parsed_topic[0]
111116
payload = msg.payload.decode('utf-8')
112117
elif self.on_message is not None and parsed_topic[1] == 'groups':
113118
topic = parsed_topic[3]
114119
payload = msg.payload.decode('utf-8')
120+
else: # default topic
121+
topic = parsed_topic[2]
122+
payload = '' if msg.payload is None else msg.payload.decode('utf-8')
115123
self.on_message(self, topic, payload)
116124

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

208+
def subscribe_weather(self, weather_id, forecast_type):
209+
"""Subscribe to Adafruit IO Weather
210+
:param int weather_id: weather record you want data for
211+
:param string type: type of forecast data requested
212+
"""
213+
if forecast_type in forecast_types:
214+
self._client.subscribe('{0}/integration/weather/{1}/{2}'.format(self._username, weather_id, forecast_type))
215+
else:
216+
raise TypeError("Invalid Forecast Type Specified.")
217+
return
218+
200219
def subscribe_time(self, time):
201220
"""Subscribe to changes on the Adafruit IO time feeds. When the feed is
202221
updated, the on_message function will be called and publish a new value:

examples/basics/digital_in.py

-54
This file was deleted.

examples/mqtt/mqtt_weather.py

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
"""
2+
Example of using the Adafruit IO MQTT Client
3+
for subscribing to the Adafruit IO Weather Service
4+
Note: This feature is avaliable for IO Plus Subscribers ONLY
5+
6+
API Documentation: https://io.adafruit.com/services/weather
7+
8+
Author: Brent Rubell for Adafruit Industries
9+
"""
10+
11+
# Import standard python modules.
12+
import sys
13+
import json
14+
15+
# Import Adafruit IO MQTT client.
16+
from Adafruit_IO import MQTTClient
17+
18+
# Set to your Adafruit IO key.
19+
# Remember, your key is a secret,
20+
# so make sure not to publish it when you publish this code!
21+
ADAFRUIT_IO_KEY = 'KEY'
22+
23+
# Set to your Adafruit IO username.
24+
# (go to https://accounts.adafruit.com to find your username)
25+
ADAFRUIT_IO_USERNAME = 'USER'
26+
27+
# Set to ID of the forecast to subscribe to for updates
28+
forecast_id = 2153
29+
30+
# Set to the ID of the feed to subscribe to for updates.
31+
"""
32+
Valid forecast types are:
33+
current
34+
forecast_minutes_5
35+
forecast_minutes_30
36+
forecast_hours_1
37+
forecast_hours_2
38+
forecast_hours_6
39+
forecast_hours_24
40+
forecast_days_1
41+
forecast_days_2
42+
forecast_days_5
43+
"""
44+
# Subscribe to the current forecast
45+
forecast_today = 'current'
46+
# Subscribe to tomorrow's forecast
47+
forecast_two_days = 'forecast_days_2'
48+
# Subscribe to forecast in 5 days
49+
forecast_in_5_days = 'forecast_days_5'
50+
51+
# Define callback functions which will be called when certain events happen.
52+
# pylint: disable=redefined-outer-name
53+
def connected(client):
54+
# Connected function will be called when the client is connected to Adafruit IO.
55+
# This is a good place to subscribe to feed changes. The client parameter
56+
# passed to this function is the Adafruit IO MQTT client so you can make
57+
# calls against it easily.
58+
print('Connected to Adafruit IO! Listening to forecast: {0}...'.format(forecast_id))
59+
# Subscribe to changes on the current forecast.
60+
client.subscribe_weather(forecast_id, forecast_today)
61+
62+
# Subscribe to changes on tomorrow's forecast.
63+
client.subscribe_weather(forecast_id, forecast_two_days)
64+
65+
# Subscribe to changes on forecast in 5 days.
66+
client.subscribe_weather(forecast_id, forecast_in_5_days)
67+
68+
# pylint: disable=unused-argument
69+
def disconnected(client):
70+
# Disconnected function will be called when the client disconnects.
71+
print('Disconnected from Adafruit IO!')
72+
sys.exit(1)
73+
74+
# pylint: disable=unused-argument
75+
def message(client, topic, payload):
76+
"""Message function will be called when any subscribed forecast has an update.
77+
Weather data is updated at most once every 20 minutes.
78+
"""
79+
# forecast based on mqtt topic
80+
if topic == 'current':
81+
# Print out today's forecast
82+
today_forecast = payload
83+
print('\nCurrent Forecast')
84+
parseForecast(today_forecast)
85+
elif topic == 'forecast_days_2':
86+
# Print out tomorrow's forecast
87+
two_day_forecast = payload
88+
print('\nWeather in Two Days')
89+
parseForecast(two_day_forecast)
90+
elif topic == 'forecast_days_5':
91+
# Print out forecast in 5 days
92+
five_day_forecast = payload
93+
print('\nWeather in 5 Days')
94+
parseForecast(five_day_forecast)
95+
96+
def parseForecast(forecast_data):
97+
"""Parses and prints incoming forecast data
98+
"""
99+
# incoming data is a utf-8 string, encode it as a json object
100+
forecast = json.loads(forecast_data)
101+
# Print out the forecast
102+
try:
103+
print('It is {0} and {1}F.'.format(forecast['summary'], forecast['temperature']))
104+
except KeyError:
105+
# future weather forecasts return a high and low temperature, instead of 'temperature'
106+
print('It will be {0} with a high of {1}F and a low of {2}F.'.format(
107+
forecast['summary'], forecast['temperatureLow'], forecast['temperatureHigh']))
108+
print('with humidity of {0}%, wind speed of {1}mph, and {2}% chance of precipitation.'.format(
109+
forecast['humidity'], forecast['windSpeed'], forecast['precipProbability']))
110+
111+
# Create an MQTT client instance.
112+
client = MQTTClient(ADAFRUIT_IO_USERNAME, ADAFRUIT_IO_KEY)
113+
114+
# Setup the callback functions defined above.
115+
client.on_connect = connected
116+
client.on_disconnect = disconnected
117+
client.on_message = message
118+
119+
# Connect to the Adafruit IO server.
120+
client.connect()
121+
122+
# Start a message loop that blocks forever waiting for MQTT messages to be
123+
# received. Note there are other options for running the event loop like doing
124+
# so in a background thread--see the mqtt_client.py example to learn more.
125+
client.loop_blocking()

0 commit comments

Comments
 (0)