Compare commits
8 commits
master
...
group_send
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab8aad0b68 | ||
|
|
8e0c35906d | ||
|
|
c3d2a66fa7 | ||
|
|
db45babec5 | ||
|
|
2a271ef31c | ||
|
|
f38b5bc751 | ||
|
|
c122320296 | ||
|
|
f7f9d1ba5a |
5 changed files with 125 additions and 7 deletions
|
|
@ -21,5 +21,5 @@
|
|||
from .client import Client
|
||||
from .mqtt_client import MQTTClient
|
||||
from .errors import AdafruitIOError, RequestError, ThrottlingError, MQTTError
|
||||
from .model import Data, Feed, Group, Dashboard, Block, Layout
|
||||
from .model import Data, Feed, Group, Dashboard, Block, Layout, GroupFeedData
|
||||
from ._version import __version__
|
||||
|
|
|
|||
|
|
@ -22,7 +22,13 @@ import time
|
|||
from time import struct_time
|
||||
import json
|
||||
import platform
|
||||
import pkg_resources
|
||||
try:
|
||||
from importlib.metadata import version as pkg_version # Python 3.8+
|
||||
except ImportError:
|
||||
try:
|
||||
from importlib_metadata import version as pkg_version # Backport for <3.8
|
||||
except ImportError:
|
||||
pkg_version = None
|
||||
import re
|
||||
from urllib.parse import urlparse
|
||||
from urllib.parse import parse_qs
|
||||
|
|
@ -30,13 +36,26 @@ from urllib.parse import parse_qs
|
|||
|
||||
import requests
|
||||
|
||||
|
||||
from .errors import RequestError, ThrottlingError
|
||||
from .model import Data, Feed, Group, Dashboard, Block, Layout
|
||||
|
||||
DEFAULT_PAGE_LIMIT = 100
|
||||
|
||||
# set outgoing version, pulled from setup.py
|
||||
version = pkg_resources.require("Adafruit_IO")[0].version
|
||||
# set outgoing version, pulled from setup.py or package metadata
|
||||
_package_name = "Adafruit_IO"
|
||||
_version = None
|
||||
if pkg_version:
|
||||
try:
|
||||
_version = pkg_version(_package_name)
|
||||
except Exception:
|
||||
pass
|
||||
if not _version:
|
||||
try:
|
||||
_version = pkg_resources.require(_package_name)[0].version
|
||||
except Exception:
|
||||
_version = "unknown"
|
||||
version = _version
|
||||
default_headers = {
|
||||
'User-Agent': 'AdafruitIO-Python/{0} ({1}, {2} {3})'.format(version,
|
||||
platform.platform(),
|
||||
|
|
@ -185,6 +204,26 @@ class Client(object):
|
|||
data_dict = type(data_list)((data._asdict() for data in data_list))
|
||||
self._post(path, {"data": data_dict})
|
||||
|
||||
def send_group_multiple_data(self, group, data_list):
|
||||
"""Create a new row of data in the specified group. Group can be a group
|
||||
ID, group key, or group name. Data must be a list of GroupFeedData objects, or
|
||||
a Dict with a feeds property, containing a list of GroupFeedData objects with
|
||||
at least a value property and key set on it. Optionally, metadata (created_at,
|
||||
lat/lon/ele) can be set at the root object level.
|
||||
Returns a Data instance with details about the newly appended rows of data.
|
||||
|
||||
:param string group: Name/Key/ID of Adafruit IO group.
|
||||
:param List[GroupFeedData]|Dict data_list: Multiple data values with keys.
|
||||
"""
|
||||
path = "groups/{0}/data".format(group)
|
||||
if isinstance(data_list, list):
|
||||
data_dict = {"feeds": [data._asdict() for data in data_list]}
|
||||
elif isinstance(data_list, dict):
|
||||
data_dict = data_list
|
||||
else:
|
||||
raise TypeError("data_list must be a dict or list")
|
||||
self._post(path, data_dict)
|
||||
|
||||
def append(self, feed, value):
|
||||
"""Helper function to simplify adding a value to a feed. Will append the
|
||||
specified value to the feed identified by either name, key, or ID.
|
||||
|
|
|
|||
|
|
@ -41,6 +41,10 @@ DATA_FIELDS = [ 'created_epoch',
|
|||
'lon',
|
||||
'ele']
|
||||
|
||||
# List of fields/properties for GroupFeedData object
|
||||
GROUPFEEDDATA_FIELDS = [ 'value',
|
||||
'key']
|
||||
|
||||
FEED_FIELDS = [ 'name',
|
||||
'key',
|
||||
'id',
|
||||
|
|
@ -95,12 +99,14 @@ Group = namedtuple('Group', GROUP_FIELDS)
|
|||
Dashboard = namedtuple('Dashboard', DASHBOARD_FIELDS)
|
||||
Block = namedtuple('Block', BLOCK_FIELDS)
|
||||
Layout = namedtuple('Layout', LAYOUT_FIELDS)
|
||||
GroupFeedData = namedtuple('GroupFeedData', GROUPFEEDDATA_FIELDS)
|
||||
|
||||
# Magic incantation to make all parameters to the initializers optional with a
|
||||
# default value of None.
|
||||
Group.__new__.__defaults__ = tuple(None for x in GROUP_FIELDS)
|
||||
Data.__new__.__defaults__ = tuple(None for x in DATA_FIELDS)
|
||||
Layout.__new__.__defaults__ = tuple(None for x in LAYOUT_FIELDS)
|
||||
GroupFeedData.__new__.__defaults__ = tuple(None for x in GROUPFEEDDATA_FIELDS)
|
||||
|
||||
# explicitly set dashboard values so that 'color_mode' is 'dark'
|
||||
Dashboard.__new__.__defaults__ = (None, None, None, False, "dark", True, None, None)
|
||||
|
|
@ -147,3 +153,4 @@ Group.from_dict = classmethod(_group_from_dict)
|
|||
Dashboard.from_dict = classmethod(_dashboard_from_dict)
|
||||
Block.from_dict = classmethod(_from_dict)
|
||||
Layout.from_dict = classmethod(_from_dict)
|
||||
GroupFeedData.from_dict = classmethod(_from_dict)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import time
|
||||
import unittest
|
||||
|
||||
from Adafruit_IO import Client, Data, Feed, Group, Dashboard, Block, Layout, RequestError
|
||||
from Adafruit_IO import Client, Data, Feed, Group, Dashboard, Block, Layout, RequestError, GroupFeedData
|
||||
|
||||
import base
|
||||
|
||||
|
|
@ -95,6 +95,61 @@ class TestClient(base.IOTestCase):
|
|||
data = io.receive(test_feed.key)
|
||||
self.assertEqual(int(data.value), 42)
|
||||
|
||||
def test_send_group_multiple_data_as_list(self):
|
||||
"""send_group_multiple_data
|
||||
"""
|
||||
io = self.get_client()
|
||||
self.ensure_group_deleted(io, 'testgroup')
|
||||
self.ensure_feed_deleted(io, 'testfeed1')
|
||||
self.ensure_feed_deleted(io, 'testfeed2')
|
||||
test_group = io.create_group(Group(name="testgroup"))
|
||||
test_feed1 = io.create_feed(Feed(name="testfeed1"), test_group.key)
|
||||
test_feed2 = io.create_feed(Feed(name="testfeed2"), test_group.key)
|
||||
data_list = [
|
||||
GroupFeedData(value=42, key=test_feed1.key.replace(
|
||||
test_group.key + ".", "")),
|
||||
GroupFeedData(value=42, key=test_feed2.key.replace(
|
||||
test_group.key + ".", ""))
|
||||
]
|
||||
io.send_group_multiple_data(test_group.key, data_list)
|
||||
data = io.receive(test_feed1.key)
|
||||
self.assertEqual(int(data.value), 42)
|
||||
data = io.receive(test_feed2.key)
|
||||
self.assertEqual(int(data.value), 42)
|
||||
self.ensure_feed_deleted(io, 'testfeed1')
|
||||
self.ensure_feed_deleted(io, 'testfeed2')
|
||||
self.ensure_group_deleted(io, 'testgroup')
|
||||
|
||||
def test_send_group_multiple_data_as_dict(self):
|
||||
"""send_group_multiple_data
|
||||
"""
|
||||
io = self.get_client()
|
||||
self.ensure_group_deleted(io, 'testgroup')
|
||||
self.ensure_feed_deleted(io, 'testfeed1')
|
||||
self.ensure_feed_deleted(io, 'testfeed2')
|
||||
test_group = io.create_group(Group(name="testgroup"))
|
||||
test_feed1 = io.create_feed(Feed(name="testfeed1"), test_group.key)
|
||||
test_feed2 = io.create_feed(Feed(name="testfeed2"), test_group.key)
|
||||
data_dict = {
|
||||
"feeds": [
|
||||
{"key": test_feed1.key.replace(
|
||||
test_group.key + ".", ""), "value": 43},
|
||||
{"key": test_feed2.key.replace(
|
||||
test_group.key + ".", ""), "value": 43}
|
||||
],
|
||||
"lat": 40.726190,
|
||||
"lon": -74.005334,
|
||||
"ele": -6,
|
||||
}
|
||||
io.send_group_multiple_data(test_group.key, data_dict)
|
||||
data = io.receive(test_feed1.key)
|
||||
self.assertEqual(int(data.value), 43)
|
||||
data = io.receive(test_feed2.key)
|
||||
self.assertEqual(int(data.value), 43)
|
||||
self.ensure_feed_deleted(io, 'testfeed1')
|
||||
self.ensure_feed_deleted(io, 'testfeed2')
|
||||
self.ensure_group_deleted(io, 'testgroup')
|
||||
|
||||
def test_receive_next(self):
|
||||
"""receive_next
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
from Adafruit_IO import Data, Feed, Group, Dashboard, Block, Layout
|
||||
from Adafruit_IO import Data, Feed, Group, Dashboard, Block, Layout, GroupFeedData
|
||||
|
||||
import base
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ class TestData(base.IOTestCase):
|
|||
self.assertIsNone(feed.license)
|
||||
self.assertIsNone(feed.status_notify)
|
||||
self.assertIsNone(feed.status_timeout)
|
||||
|
||||
|
||||
def test_group_properties_are_optional(self):
|
||||
group = Group(name="foo")
|
||||
self.assertEqual(group.name, 'foo')
|
||||
|
|
@ -116,3 +116,20 @@ class TestData(base.IOTestCase):
|
|||
self.assertIsNone(data.expiration)
|
||||
self.assertIsNone(data.position)
|
||||
self.assertIsNone(data.id)
|
||||
|
||||
|
||||
class TestGroupFeedData(base.IOTestCase):
|
||||
|
||||
def test_groupfeeddata_properties_are_optional(self):
|
||||
"""GroupFeedData fields have optional properties
|
||||
"""
|
||||
data = GroupFeedData(value='foo', key='test_key')
|
||||
self.assertEqual(data.value, 'foo')
|
||||
self.assertEqual(data.key, 'test_key')
|
||||
|
||||
def test_groupfeeddata_from_dict_ignores_unknown_items(self):
|
||||
data = GroupFeedData.from_dict(
|
||||
{'value': 'foo', 'key': 'test_key', 'unknown_param': 42})
|
||||
self.assertEqual(data.value, 'foo')
|
||||
self.assertEqual(data.key, 'test_key')
|
||||
self.assertFalse(hasattr(data, 'unknown_param'))
|
||||
|
|
|
|||
Loading…
Reference in a new issue