Skip to content

Commit fed0298

Browse files
author
brentru
committed
add weather subscription method and example
1 parent fff6baa commit fed0298

File tree

2 files changed

+180
-4
lines changed

2 files changed

+180
-4
lines changed

adafruit_io/adafruit_io.py

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@
4949
'User-Agent': 'AIO-CircuitPython/{0}'.format(__version__)
5050
}
5151

52+
forecast_types = ["current", "forecast_minutes_5",
53+
"forecast_minutes_30", "forecast_hours_1",
54+
"forecast_hours_2", "forecast_hours_6",
55+
"forecast_hours_24", "forecast_days_1",
56+
"forecast_days_2", "forecast_days_5",]
57+
5258
class MQTT():
5359
"""
5460
Client for interacting with the Adafruit IO MQTT API. The client establishes
@@ -164,7 +170,7 @@ def loop_blocking(self):
164170
"""
165171
self._client.loop_forever()
166172

167-
# Subscription
173+
# Subscriptions
168174
def subscribe(self, feed_key=None, group_key=None, shared_user=None):
169175
"""Subscribes to an Adafruit IO feed or group.
170176
Can also subscribe to someone else's feed.
@@ -194,6 +200,15 @@ def subscribe(self, feed_key=None, group_key=None, shared_user=None):
194200
else:
195201
raise AdafruitIO_MQTTError('Must provide a feed_key or group_key.')
196202

203+
204+
def subscribe_weather(self, integration_id, forecast_type):
205+
"""Subscribes to a weather forecast using the Adafruit IO PLUS weather
206+
service. This feature is only avaliable to Adafruit IO PLUS subscribers.
207+
:param int integration_id: Weather record you want data for.
208+
:param str forecast_type: Forecast data you'd like to recieve.
209+
"""
210+
self._client.subscribe('{0}/integration/weather/{1}/{2}'.format(self._user, integration_id, forecast_type))
211+
197212
def unsubscribe(self, feed_key=None, group_key=None, shared_user=None):
198213
"""Unsubscribes from an Adafruit IO feed or group.
199214
Can also subscribe to someone else's feed.
@@ -228,11 +243,12 @@ def publish_multiple(self, feeds_and_data, timeout=3, is_group=False):
228243
"""Publishes multiple data points to multiple feeds or groups.
229244
:param str feeds_and_data: List of tuples containing topic strings and data values.
230245
:param int timeout: Delay between publishing data points to Adafruit IO.
246+
:param bool is_group: Set to True if you're publishing to a group.
231247
232-
Example of publishing multiple data points to Adafruit IO:
248+
Example of publishing multiple data points on different feeds to Adafruit IO:
233249
..code-block:: python
234250
235-
client.publish_multiple([('DemoFeed', value), ('testfeed', value)])
251+
client.publish_multiple([('humidity', 24.5), ('temperature', 54)])
236252
237253
"""
238254
if isinstance(feeds_and_data, list):
@@ -245,7 +261,6 @@ def publish_multiple(self, feeds_and_data, timeout=3, is_group=False):
245261
if is_group:
246262
self.publish(t, d, is_group=True)
247263
else:
248-
print('publishing: {0} to {1}'.format(d, t))
249264
self.publish(t, d)
250265
time.sleep(timeout)
251266

examples/adafruit_io_mqtt_weather.py

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# Example of using the Adafruit IO CircuitPython MQTT Client
2+
# for subscribe to a weather forecast provided by the
3+
# Adafruit IO Weather Service (IO Plus subscribers ONLY).
4+
# This example uses ESP32SPI to connect over WiFi
5+
#
6+
# by Brent Rubell for Adafruit Industries, 2019
7+
import time
8+
from random import randint
9+
import board
10+
import neopixel
11+
import busio
12+
from digitalio import DigitalInOut
13+
14+
# Import WiFi configuration
15+
from adafruit_esp32spi import adafruit_esp32spi
16+
from adafruit_esp32spi import adafruit_esp32spi_wifimanager
17+
import adafruit_esp32spi.adafruit_esp32spi_socket as socket
18+
19+
# Import the Adafruit IO MQTT Class
20+
from adafruit_io.adafruit_io import MQTT
21+
22+
### WiFi ###
23+
24+
# Get wifi details and more from a secrets.py file
25+
try:
26+
from secrets import secrets
27+
except ImportError:
28+
print("WiFi secrets are kept in secrets.py, please add them there!")
29+
raise
30+
31+
# If you are using a board with pre-defined ESP32 Pins:
32+
esp32_cs = DigitalInOut(board.ESP_CS)
33+
esp32_ready = DigitalInOut(board.ESP_BUSY)
34+
esp32_reset = DigitalInOut(board.ESP_RESET)
35+
36+
# If you have an externally connected ESP32:
37+
# esp32_cs = DigitalInOut(board.D9)
38+
# esp32_ready = DigitalInOut(board.D10)
39+
# esp32_reset = DigitalInOut(board.D5)
40+
41+
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
42+
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
43+
"""Use below for Most Boards"""
44+
status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) # Uncomment for Most Boards
45+
"""Uncomment below for ItsyBitsy M4"""
46+
# status_light = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2)
47+
# Uncomment below for an externally defined RGB LED
48+
# import adafruit_rgbled
49+
# from adafruit_esp32spi import PWMOut
50+
# RED_LED = PWMOut.PWMOut(esp, 26)
51+
# GREEN_LED = PWMOut.PWMOut(esp, 27)
52+
# BLUE_LED = PWMOut.PWMOut(esp, 25)
53+
# status_light = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED)
54+
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)
55+
56+
# Set to ID of the forecast to subscribe to for updates
57+
forecast_id = 2127
58+
59+
# Set to the ID of the feed to subscribe to for updates.
60+
"""
61+
Valid forecast types are:
62+
current
63+
forecast_minutes_5
64+
forecast_minutes_30
65+
forecast_hours_1
66+
forecast_hours_2
67+
forecast_hours_6
68+
forecast_hours_24
69+
forecast_days_1
70+
forecast_days_2
71+
forecast_days_5
72+
"""
73+
# Subscribe to the current forecast
74+
forecast_today = 'current'
75+
# Subscribe to tomorrow's forecast
76+
forecast_two_days = 'forecast_days_2'
77+
# Subscribe to forecast in 5 days
78+
forecast_in_5_days = 'forecast_days_5'
79+
80+
# Define callback functions which will be called when certain events happen.
81+
# pylint: disable=redefined-outer-name
82+
def connected(client):
83+
# Connected function will be called when the client is connected to Adafruit IO.
84+
# This is a good place to subscribe to feed changes. The client parameter
85+
# passed to this function is the Adafruit IO MQTT client so you can make
86+
# calls against it easily.
87+
print('Connected to Adafruit IO! Listening to forecast: {0}...'.format(forecast_id))
88+
# Subscribe to changes on the current forecast.
89+
client.subscribe_weather(forecast_id, forecast_today)
90+
91+
# Subscribe to changes on tomorrow's forecast.
92+
client.subscribe_weather(forecast_id, forecast_two_days)
93+
94+
# Subscribe to changes on forecast in 5 days.
95+
client.subscribe_weather(forecast_id, forecast_in_5_days)
96+
97+
# pylint: disable=unused-argument
98+
def disconnected(client):
99+
# Disconnected function will be called when the client disconnects.
100+
print('Disconnected from Adafruit IO!')
101+
sys.exit(1)
102+
103+
# pylint: disable=unused-argument
104+
def message(client, topic, payload):
105+
"""Message function will be called when any subscribed forecast has an update.
106+
Weather data is updated at most once every 20 minutes.
107+
"""
108+
print('NEW MESSAGE: ', topic, payload)
109+
# forecast based on mqtt topic
110+
if topic == 'current':
111+
# Print out today's forecast
112+
today_forecast = payload
113+
print('\nCurrent Forecast')
114+
parseForecast(today_forecast)
115+
elif topic == 'forecast_days_2':
116+
# Print out tomorrow's forecast
117+
two_day_forecast = payload
118+
print('\nWeather in Two Days')
119+
parseForecast(two_day_forecast)
120+
elif topic == 'forecast_days_5':
121+
# Print out forecast in 5 days
122+
five_day_forecast = payload
123+
print('\nWeather in 5 Days')
124+
parseForecast(five_day_forecast)
125+
126+
def parseForecast(forecast_data):
127+
"""Parses and prints incoming forecast data
128+
"""
129+
# incoming data is a utf-8 string, encode it as a json object
130+
forecast = json.loads(forecast_data)
131+
# Print out the forecast
132+
try:
133+
print('It is {0} and {1}F.'.format(forecast['summary'], forecast['temperature']))
134+
except KeyError:
135+
# future weather forecasts return a high and low temperature, instead of 'temperature'
136+
print('It will be {0} with a high of {1}F and a low of {2}F.'.format(
137+
forecast['summary'], forecast['temperatureLow'], forecast['temperatureHigh']))
138+
print('with humidity of {0}%, wind speed of {1}mph, and {2}% chance of precipitation.'.format(
139+
forecast['humidity'], forecast['windSpeed'], forecast['precipProbability']))
140+
141+
# Connect to WiFi
142+
wifi.connect()
143+
144+
# Initialize a new Adafruit IO WiFi MQTT client.
145+
client = MQTT(secrets['aio_user'],
146+
secrets['aio_password'],
147+
wifi,
148+
socket)
149+
150+
# Setup the callback functions defined above.
151+
client.on_connect = connected
152+
client.on_disconnect = disconnected
153+
client.on_message = message
154+
155+
# Connect to the Adafruit IO server.
156+
client.connect()
157+
158+
# Start a message loop that blocks forever waiting for MQTT messages to be
159+
# received. Note there are other options for running the event loop like doing
160+
# so in a background thread--see the mqtt_client.py example to learn more.
161+
client.loop_blocking()

0 commit comments

Comments
 (0)