Skip to content

Commit

Permalink
Merge pull request #124 from adafruit/tyeth/issue97
Browse files Browse the repository at this point in the history
IO_HTTP: Support creating group data with `send_group_data`
  • Loading branch information
tyeth authored Jul 18, 2024
2 parents e0779b3 + 7d74850 commit 2787332
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 7 deletions.
35 changes: 33 additions & 2 deletions adafruit_io/adafruit_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -639,10 +639,34 @@ def send_batch_data(self, feed_key: str, data_list: list):
:param list Data: Data list to send
"""
validate_feed_key(feed_key)
path = "feeds/{0}/data/batch".format(feed_key)
path = self._compose_path("feeds/{0}/data/batch".format(feed_key))
data_dict = type(data_list)((data._asdict() for data in data_list))
self._post(path, {"data": data_dict})

def send_group_data(
self, group_key: str, feeds_and_data: list, metadata: Optional[dict] = None
):
"""
Sends data to specified Adafruit IO feeds in a group
:param str group_key: Adafruit IO feed key
:param list feeds_and_data: A list of dicts, with feed "key" and "value" entries
:param dict metadata: Optional metadata for the data e.g. created_at, lat, lon, ele
"""
validate_feed_key(group_key)
path = self._compose_path("groups/{0}/data".format(group_key))
if not isinstance(feeds_and_data, list):
raise ValueError(
'This method accepts a list of dicts with "key" and "value".'
)
if metadata is not None:
if not isinstance(metadata, dict):
raise ValueError("Metadata must be a dictionary.")
metadata.update({"feeds": feeds_and_data})
self._post(path, metadata)
else:
self._post(path, {"feeds": feeds_and_data})

def receive_all_data(self, feed_key: str):
"""
Get all data values from a specified Adafruit IO feed. Data is
Expand Down Expand Up @@ -826,14 +850,21 @@ def receive_random_data(self, generator_id: int):
path = self._compose_path("integrations/words/{0}".format(generator_id))
return self._get(path)

def receive_time(self):
def receive_time(self, timezone: str = None):
"""
Returns a struct_time from the Adafruit IO Server based on the device's IP address.
https://circuitpython.readthedocs.io/en/latest/shared-bindings/time/__init__.html#time.struct_time
The default time returned is based on the device's IP address being geolocated,
falling back to UTC if unable to be geolocated. The timezone can be manually set.
:param str timezone: Timezone to return time in, see https://io.adafruit.com/services/time
"""
path = self._compose_path("integrations/time/struct.json")
if timezone is not None:
path += "?tz={0}".format(timezone)
time_struct = self._get(path)
return time.struct_time(
# pylint: disable=line-too-long
(
time_struct["year"],
time_struct["mon"],
Expand Down
67 changes: 62 additions & 5 deletions examples/adafruit_io_http/adafruit_io_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
# Adafruit IO HTTP API - Group Interactions
# Documentation: https://io.adafruit.com/api/docs/#groups
# adafruit_circuitpython_adafruitio with an esp32spi_socket
import adafruit_datetime as datetime
import board
import busio
from digitalio import DigitalInOut
Expand All @@ -14,14 +15,26 @@


# Add a secrets.py to your filesystem that has a dictionary called secrets with "ssid" and
# "password" keys with your WiFi credentials. DO NOT share that file or commit it into Git or other
# source control.
# "password" keys with your WiFi credentials, along with "aio_username" and "aio_key" for
# your Adafruit IO user/key. DO NOT share that file or commit it into Git or other source control.
# pylint: disable=no-name-in-module,wrong-import-order
try:
from secrets import secrets
except ImportError:
print("WiFi secrets are kept in secrets.py, please add them there!")
raise
import os

if os.getenv("ADAFRUIT_AIO_USERNAME") and os.getenv("ADAFRUIT_AIO_KEY"):
secrets = {
"aio_username": os.getenv("ADAFRUIT_AIO_USERNAME", "Your_Username_Here"),
"aio_key": os.getenv("ADAFRUIT_AIO_KEY", "Your_Adafruit_IO_Key_Here"),
"ssid": os.getenv("CIRCUITPY_WIFI_SSID", ""),
"password": os.getenv("CIRCUITPY_WIFI_PASSWORD", ""),
}
else:
print(
"WiFi + Adafruit IO secrets are kept in secrets.py, please add them there!"
)
raise

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

# If you are using a wifi based mcu use this instead of esp code above, remove the from
# adafruit_esp32spi import line, optionally esp.connect(secrets["ssid"], secrets["password"])
# import wifi
# esp = wifi.radio

# Initialize a requests session
pool = adafruit_connection_manager.get_radio_socketpool(esp)
ssl_context = adafruit_connection_manager.get_radio_ssl_context(esp)
requests = adafruit_requests.Session(pool, ssl_context)

# If you are testing on python with blinka, use real requests below and comment out above:
# import os, datetime, requests as real_requests
# from adafruit_io.adafruit_io import IO_HTTP
# secrets = {
# "aio_username": os.getenv("ADAFRUIT_AIO_USERNAME"),
# "aio_key": os.getenv("ADAFRUIT_AIO_KEY"),
# }
# requests = real_requests.Session()


# Set your Adafruit IO Username and Key in secrets.py
# (visit io.adafruit.com if you need to create an account,
# or if you need your Adafruit IO key.)
Expand All @@ -72,8 +100,37 @@
humidity_feed = io.create_new_feed("humidity", "a feed for humidity data")
io.add_feed_to_group(sensor_group["key"], humidity_feed["key"])

# show humidity feed is in two groups
print("Getting fresh humidity feed info... (notice groups)")
print(io.get_feed(humidity_feed["key"]))

# fetch current time
print("Fetching current time from IO... ", end="")
year, month, day, hour, minute, second, *_ = io.receive_time(timezone="UTC")
old_time = datetime.datetime(year, month, day, hour, minute, second)
print(old_time.isoformat())

# Publish data for multiple feeds to a group, use different timestamps for no reason
print("Publishing batch data to group feeds with created_at set 99minutes ago...")
thetime = old_time - datetime.timedelta(minutes=99)
print(thetime)

io.send_group_data(
group_key=sensor_group["key"],
feeds_and_data=[
{"key": "temperature", "value": 20.0},
{"key": "humidity", "value": 40.0},
],
metadata={
"lat": 50.1858942,
"lon": -4.9677478,
"ele": 4,
"created_at": thetime.isoformat(),
},
)

# Get info from the group
print("Getting fresh group info...")
print("Getting fresh group info... (notice created_at vs updated_at)")
sensor_group = io.get_group("envsensors") # refresh data via HTTP API
print(sensor_group)

Expand Down

0 comments on commit 2787332

Please sign in to comment.