Skip to content

Commit 92093d4

Browse files
authored
Merge pull request #136 from cj8scrambler/master
Add support for dashboards, blocks and layouts
2 parents 0f83289 + ce3d868 commit 92093d4

File tree

6 files changed

+350
-11
lines changed

6 files changed

+350
-11
lines changed

Diff for: Adafruit_IO/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,5 @@
2121
from .client import Client
2222
from .mqtt_client import MQTTClient
2323
from .errors import AdafruitIOError, RequestError, ThrottlingError, MQTTError
24-
from .model import Data, Feed, Group
25-
from ._version import __version__
24+
from .model import Data, Feed, Group, Dashboard, Block, Layout
25+
from ._version import __version__

Diff for: Adafruit_IO/client.py

+75-3
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
import requests
2929

3030
from .errors import RequestError, ThrottlingError
31-
from .model import Data, Feed, Group
31+
from .model import Data, Feed, Group, Dashboard, Block, Layout
3232

3333
# set outgoing version, pulled from setup.py
3434
version = pkg_resources.require("Adafruit_IO")[0].version
@@ -289,11 +289,13 @@ def create_feed(self, feed, group_key=None):
289289
:param string feed: Key of Adafruit IO feed.
290290
:param group_key group: Group to place new feed in.
291291
"""
292+
f = feed._asdict()
293+
del f['id'] # Don't pass id on create call
292294
path = "feeds/"
293295
if group_key is not None: # create feed in a group
294296
path="/groups/%s/feeds"%group_key
295-
return Feed.from_dict(self._post(path, {"feed": feed._asdict()}))
296-
return Feed.from_dict(self._post(path, {"feed": feed._asdict()}))
297+
return Feed.from_dict(self._post(path, {"feed": f}))
298+
return Feed.from_dict(self._post(path, {"feed": f}))
297299

298300
def delete_feed(self, feed):
299301
"""Delete the specified feed.
@@ -326,3 +328,73 @@ def delete_group(self, group):
326328
"""
327329
path = "groups/{0}".format(group)
328330
self._delete(path)
331+
332+
# Dashboard functionality.
333+
def dashboards(self, dashboard=None):
334+
"""Retrieve a list of all dashboards, or the specified dashboard.
335+
:param string dashboard: Key of Adafruit IO Dashboard. Defaults to None.
336+
"""
337+
if dashboard is None:
338+
path = "dashboards/"
339+
return list(map(Dashboard.from_dict, self._get(path)))
340+
path = "dashboards/{0}".format(dashboard)
341+
return Dashboard.from_dict(self._get(path))
342+
343+
def create_dashboard(self, dashboard):
344+
"""Create the specified dashboard.
345+
:param Dashboard dashboard: Dashboard object to create
346+
"""
347+
path = "dashboards/"
348+
return Dashboard.from_dict(self._post(path, dashboard._asdict()))
349+
350+
def delete_dashboard(self, dashboard):
351+
"""Delete the specified dashboard.
352+
:param string dashboard: Key of Adafruit IO Dashboard.
353+
"""
354+
path = "dashboards/{0}".format(dashboard)
355+
self._delete(path)
356+
357+
# Block functionality.
358+
def blocks(self, dashboard, block=None):
359+
"""Retrieve a list of all blocks from a dashboard, or the specified block.
360+
:param string dashboard: Key of Adafruit IO Dashboard.
361+
:param string block: id of Adafruit IO Block. Defaults to None.
362+
"""
363+
if block is None:
364+
path = "dashboards/{0}/blocks".format(dashboard)
365+
return list(map(Block.from_dict, self._get(path)))
366+
path = "dashboards/{0}/blocks/{1}".format(dashboard, block)
367+
return Block.from_dict(self._get(path))
368+
369+
def create_block(self, dashboard, block):
370+
"""Create the specified block under the specified dashboard.
371+
:param string dashboard: Key of Adafruit IO Dashboard.
372+
:param Block block: Block object to create under dashboard
373+
"""
374+
path = "dashboards/{0}/blocks".format(dashboard)
375+
return Block.from_dict(self._post(path, block._asdict()))
376+
377+
def delete_block(self, dashboard, block):
378+
"""Delete the specified block.
379+
:param string dashboard: Key of Adafruit IO Dashboard.
380+
:param string block: id of Adafruit IO Block.
381+
"""
382+
path = "dashboards/{0}/blocks/{1}".format(dashboard, block)
383+
self._delete(path)
384+
385+
# Layout functionality.
386+
def layouts(self, dashboard):
387+
"""Retrieve the layouts array from a dashboard
388+
:param string dashboard: key of Adafruit IO Dashboard.
389+
"""
390+
path = "dashboards/{0}".format(dashboard)
391+
dashboard = self._get(path)
392+
return Layout.from_dict(dashboard['layouts'])
393+
394+
def update_layout(self, dashboard, layout):
395+
"""Update the layout of the specified dashboard.
396+
:param string dashboard: Key of Adafruit IO Dashboard.
397+
:param Layout layout: Layout object to update under dashboard
398+
"""
399+
path = "dashboards/{0}/update_layouts".format(dashboard)
400+
return Layout.from_dict(self._post(path, {'layouts': layout._asdict()}))

Diff for: Adafruit_IO/model.py

+42-2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343

4444
FEED_FIELDS = [ 'name',
4545
'key',
46+
'id',
4647
'description',
4748
'unit_type',
4849
'unit_symbol',
@@ -61,6 +62,26 @@
6162
'properties',
6263
'name' ]
6364

65+
DASHBOARD_FIELDS = [ 'name',
66+
'key',
67+
'description',
68+
'show_header',
69+
'color_mode',
70+
'block_borders',
71+
'header_image_url',
72+
'blocks' ]
73+
74+
BLOCK_FIELDS = [ 'name',
75+
'id',
76+
'visual_type',
77+
'properties',
78+
'block_feeds' ]
79+
80+
LAYOUT_FIELDS = ['xl',
81+
'lg',
82+
'md',
83+
'sm',
84+
'xs' ]
6485

6586
# These are very simple data model classes that are based on namedtuple. This is
6687
# to keep the classes simple and prevent any confusion around updating data
@@ -71,15 +92,24 @@
7192
Data = namedtuple('Data', DATA_FIELDS)
7293
Feed = namedtuple('Feed', FEED_FIELDS)
7394
Group = namedtuple('Group', GROUP_FIELDS)
74-
95+
Dashboard = namedtuple('Dashboard', DASHBOARD_FIELDS)
96+
Block = namedtuple('Block', BLOCK_FIELDS)
97+
Layout = namedtuple('Layout', LAYOUT_FIELDS)
7598

7699
# Magic incantation to make all parameters to the initializers optional with a
77100
# default value of None.
78101
Group.__new__.__defaults__ = tuple(None for x in GROUP_FIELDS)
79102
Data.__new__.__defaults__ = tuple(None for x in DATA_FIELDS)
103+
Layout.__new__.__defaults__ = tuple(None for x in LAYOUT_FIELDS)
104+
105+
# explicitly set dashboard values so that 'color_mode' is 'dark'
106+
Dashboard.__new__.__defaults__ = (None, None, None, False, "dark", True, None, None)
107+
108+
# explicitly set block values so 'properties' is a dictionary
109+
Block.__new__.__defaults__ = (None, None, None, {}, None)
80110

81111
# explicitly set feed values
82-
Feed.__new__.__defaults__ = (None, None, None, None, None, 'ON', 'Private', None, None, None)
112+
Feed.__new__.__defaults__ = (None, None, None, None, None, None, 'ON', 'Private', None, None, None)
83113

84114
# Define methods to convert from dicts to the data types.
85115
def _from_dict(cls, data):
@@ -103,7 +133,17 @@ def _group_from_dict(cls, data):
103133
return cls(**params)
104134

105135

136+
def _dashboard_from_dict(cls, data):
137+
params = {x: data.get(x, None) for x in cls._fields}
138+
# Parse the blocks if they're provided and generate block instances.
139+
params['blocks'] = tuple(map(Block.from_dict, data.get('blocks', [])))
140+
return cls(**params)
141+
142+
106143
# Now add the from_dict class methods defined above to the data types.
107144
Data.from_dict = classmethod(_from_dict)
108145
Feed.from_dict = classmethod(_feed_from_dict)
109146
Group.from_dict = classmethod(_group_from_dict)
147+
Dashboard.from_dict = classmethod(_dashboard_from_dict)
148+
Block.from_dict = classmethod(_from_dict)
149+
Layout.from_dict = classmethod(_from_dict)

Diff for: examples/basics/dashboard.py

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
"""
2+
'dashboard.py'
3+
=========================================
4+
Creates a dashboard with 3 blocks and feed it data
5+
6+
Author(s): Doug Zobel
7+
"""
8+
from time import sleep
9+
from random import randrange
10+
from Adafruit_IO import Client, Feed, Block, Dashboard, Layout
11+
12+
# Set to your Adafruit IO key.
13+
# Remember, your key is a secret,
14+
# so make sure not to publish it when you publish this code!
15+
ADAFRUIT_IO_USERNAME = ''
16+
17+
# Set to your Adafruit IO username.
18+
# (go to https://accounts.adafruit.com to find your username)
19+
ADAFRUIT_IO_KEY = ''
20+
21+
# Create an instance of the REST client.
22+
aio = Client(ADAFRUIT_IO_USERNAME, ADAFRUIT_IO_KEY)
23+
24+
# Create a new feed named 'Dashboard Data' under the default group
25+
feed = aio.create_feed(Feed(name="Dashboard Data"), "default")
26+
27+
# Fetch group info (group.id needed when adding feeds to blocks)
28+
group = aio.groups("default")
29+
30+
# Create a new dasbhoard named 'Example Dashboard'
31+
dashboard = aio.create_dashboard(Dashboard(name="Example Dashboard"))
32+
33+
# Create a line_chart
34+
linechart = Block(name="Linechart Data",
35+
visual_type = 'line_chart',
36+
properties = {
37+
"gridLines": True,
38+
"historyHours": "2"},
39+
block_feeds = [{
40+
"group_id": group.id,
41+
"feed_id": feed.id
42+
}])
43+
linechart = aio.create_block(dashboard.key, linechart)
44+
45+
# Create a gauge
46+
gauge = Block(name="Gauge Data",
47+
visual_type = 'gauge',
48+
block_feeds = [{
49+
"group_id": group.id,
50+
"feed_id": feed.id
51+
}])
52+
gauge = aio.create_block(dashboard.key, gauge)
53+
54+
# Create a text stream
55+
stream = Block(name="Stream Data",
56+
visual_type = 'stream',
57+
properties = {
58+
"fontSize": "12",
59+
"fontColor": "#63de00",
60+
"showGroupName": "no"},
61+
block_feeds = [{
62+
"group_id": group.id,
63+
"feed_id": feed.id
64+
}])
65+
stream = aio.create_block(dashboard.key, stream)
66+
67+
# Update the large layout to:
68+
# |----------------|
69+
# | Line Chart |
70+
# |----------------|
71+
# | Gauge | Stream |
72+
# |----------------|
73+
layout = Layout(lg = [
74+
{'x': 0, 'y': 0, 'w': 16, 'h': 4, 'i': str(linechart.id)},
75+
{'x': 0, 'y': 4, 'w': 8, 'h': 4, 'i': str(gauge.id)},
76+
{'x': 8, 'y': 4, 'w': 8, 'h': 4, 'i': str(stream.id)}])
77+
aio.update_layout(dashboard.key, layout)
78+
79+
print("Dashboard created at: " +
80+
"https://io.adafruit.com/{0}/dashboards/{1}".format(ADAFRUIT_IO_USERNAME,
81+
dashboard.key))
82+
# Now send some data
83+
value = 0
84+
while True:
85+
value = (value + randrange(0, 10)) % 100
86+
print('sending data: ', value)
87+
aio.send_data(feed.key, value)
88+
sleep(3)

0 commit comments

Comments
 (0)