Skip to content

Commit 2787332

Browse files
authored
Merge pull request #124 from adafruit/tyeth/issue97
IO_HTTP: Support creating group data with `send_group_data`
2 parents e0779b3 + 7d74850 commit 2787332

File tree

2 files changed

+95
-7
lines changed

2 files changed

+95
-7
lines changed

adafruit_io/adafruit_io.py

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -639,10 +639,34 @@ def send_batch_data(self, feed_key: str, data_list: list):
639639
:param list Data: Data list to send
640640
"""
641641
validate_feed_key(feed_key)
642-
path = "feeds/{0}/data/batch".format(feed_key)
642+
path = self._compose_path("feeds/{0}/data/batch".format(feed_key))
643643
data_dict = type(data_list)((data._asdict() for data in data_list))
644644
self._post(path, {"data": data_dict})
645645

646+
def send_group_data(
647+
self, group_key: str, feeds_and_data: list, metadata: Optional[dict] = None
648+
):
649+
"""
650+
Sends data to specified Adafruit IO feeds in a group
651+
652+
:param str group_key: Adafruit IO feed key
653+
:param list feeds_and_data: A list of dicts, with feed "key" and "value" entries
654+
:param dict metadata: Optional metadata for the data e.g. created_at, lat, lon, ele
655+
"""
656+
validate_feed_key(group_key)
657+
path = self._compose_path("groups/{0}/data".format(group_key))
658+
if not isinstance(feeds_and_data, list):
659+
raise ValueError(
660+
'This method accepts a list of dicts with "key" and "value".'
661+
)
662+
if metadata is not None:
663+
if not isinstance(metadata, dict):
664+
raise ValueError("Metadata must be a dictionary.")
665+
metadata.update({"feeds": feeds_and_data})
666+
self._post(path, metadata)
667+
else:
668+
self._post(path, {"feeds": feeds_and_data})
669+
646670
def receive_all_data(self, feed_key: str):
647671
"""
648672
Get all data values from a specified Adafruit IO feed. Data is
@@ -826,14 +850,21 @@ def receive_random_data(self, generator_id: int):
826850
path = self._compose_path("integrations/words/{0}".format(generator_id))
827851
return self._get(path)
828852

829-
def receive_time(self):
853+
def receive_time(self, timezone: str = None):
830854
"""
831855
Returns a struct_time from the Adafruit IO Server based on the device's IP address.
832856
https://circuitpython.readthedocs.io/en/latest/shared-bindings/time/__init__.html#time.struct_time
857+
The default time returned is based on the device's IP address being geolocated,
858+
falling back to UTC if unable to be geolocated. The timezone can be manually set.
859+
860+
:param str timezone: Timezone to return time in, see https://io.adafruit.com/services/time
833861
"""
834862
path = self._compose_path("integrations/time/struct.json")
863+
if timezone is not None:
864+
path += "?tz={0}".format(timezone)
835865
time_struct = self._get(path)
836866
return time.struct_time(
867+
# pylint: disable=line-too-long
837868
(
838869
time_struct["year"],
839870
time_struct["mon"],

examples/adafruit_io_http/adafruit_io_groups.py

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# Adafruit IO HTTP API - Group Interactions
55
# Documentation: https://io.adafruit.com/api/docs/#groups
66
# adafruit_circuitpython_adafruitio with an esp32spi_socket
7+
import adafruit_datetime as datetime
78
import board
89
import busio
910
from digitalio import DigitalInOut
@@ -14,14 +15,26 @@
1415

1516

1617
# Add a secrets.py to your filesystem that has a dictionary called secrets with "ssid" and
17-
# "password" keys with your WiFi credentials. DO NOT share that file or commit it into Git or other
18-
# source control.
18+
# "password" keys with your WiFi credentials, along with "aio_username" and "aio_key" for
19+
# your Adafruit IO user/key. DO NOT share that file or commit it into Git or other source control.
1920
# pylint: disable=no-name-in-module,wrong-import-order
2021
try:
2122
from secrets import secrets
2223
except ImportError:
23-
print("WiFi secrets are kept in secrets.py, please add them there!")
24-
raise
24+
import os
25+
26+
if os.getenv("ADAFRUIT_AIO_USERNAME") and os.getenv("ADAFRUIT_AIO_KEY"):
27+
secrets = {
28+
"aio_username": os.getenv("ADAFRUIT_AIO_USERNAME", "Your_Username_Here"),
29+
"aio_key": os.getenv("ADAFRUIT_AIO_KEY", "Your_Adafruit_IO_Key_Here"),
30+
"ssid": os.getenv("CIRCUITPY_WIFI_SSID", ""),
31+
"password": os.getenv("CIRCUITPY_WIFI_PASSWORD", ""),
32+
}
33+
else:
34+
print(
35+
"WiFi + Adafruit IO secrets are kept in secrets.py, please add them there!"
36+
)
37+
raise
2538

2639
# If you are using a board with pre-defined ESP32 Pins:
2740
esp32_cs = DigitalInOut(board.ESP_CS)
@@ -45,11 +58,26 @@
4558
continue
4659
print("Connected to", str(esp.ssid, "utf-8"), "\tRSSI:", esp.rssi)
4760

61+
# If you are using a wifi based mcu use this instead of esp code above, remove the from
62+
# adafruit_esp32spi import line, optionally esp.connect(secrets["ssid"], secrets["password"])
63+
# import wifi
64+
# esp = wifi.radio
65+
4866
# Initialize a requests session
4967
pool = adafruit_connection_manager.get_radio_socketpool(esp)
5068
ssl_context = adafruit_connection_manager.get_radio_ssl_context(esp)
5169
requests = adafruit_requests.Session(pool, ssl_context)
5270

71+
# If you are testing on python with blinka, use real requests below and comment out above:
72+
# import os, datetime, requests as real_requests
73+
# from adafruit_io.adafruit_io import IO_HTTP
74+
# secrets = {
75+
# "aio_username": os.getenv("ADAFRUIT_AIO_USERNAME"),
76+
# "aio_key": os.getenv("ADAFRUIT_AIO_KEY"),
77+
# }
78+
# requests = real_requests.Session()
79+
80+
5381
# Set your Adafruit IO Username and Key in secrets.py
5482
# (visit io.adafruit.com if you need to create an account,
5583
# or if you need your Adafruit IO key.)
@@ -72,8 +100,37 @@
72100
humidity_feed = io.create_new_feed("humidity", "a feed for humidity data")
73101
io.add_feed_to_group(sensor_group["key"], humidity_feed["key"])
74102

103+
# show humidity feed is in two groups
104+
print("Getting fresh humidity feed info... (notice groups)")
105+
print(io.get_feed(humidity_feed["key"]))
106+
107+
# fetch current time
108+
print("Fetching current time from IO... ", end="")
109+
year, month, day, hour, minute, second, *_ = io.receive_time(timezone="UTC")
110+
old_time = datetime.datetime(year, month, day, hour, minute, second)
111+
print(old_time.isoformat())
112+
113+
# Publish data for multiple feeds to a group, use different timestamps for no reason
114+
print("Publishing batch data to group feeds with created_at set 99minutes ago...")
115+
thetime = old_time - datetime.timedelta(minutes=99)
116+
print(thetime)
117+
118+
io.send_group_data(
119+
group_key=sensor_group["key"],
120+
feeds_and_data=[
121+
{"key": "temperature", "value": 20.0},
122+
{"key": "humidity", "value": 40.0},
123+
],
124+
metadata={
125+
"lat": 50.1858942,
126+
"lon": -4.9677478,
127+
"ele": 4,
128+
"created_at": thetime.isoformat(),
129+
},
130+
)
131+
75132
# Get info from the group
76-
print("Getting fresh group info...")
133+
print("Getting fresh group info... (notice created_at vs updated_at)")
77134
sensor_group = io.get_group("envsensors") # refresh data via HTTP API
78135
print(sensor_group)
79136

0 commit comments

Comments
 (0)