Skip to content

IO_HTTP: Support creating group data with send_group_data #124

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 12 commits into from
Jul 18, 2024
35 changes: 33 additions & 2 deletions adafruit_io/adafruit_io.py
Original file line number Diff line number Diff line change
Expand Up @@ -631,10 +631,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 @@ -818,14 +842,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
Loading