Skip to content
This repository was archived by the owner on Jun 7, 2021. It is now read-only.

Commit 62b66f0

Browse files
author
Joel Collins
committed
Converted readme to markdown
1 parent a62c4ea commit 62b66f0

3 files changed

Lines changed: 206 additions & 201 deletions

File tree

README.md

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
# webthing
2+
3+
![image](https://github.com/mozilla-iot/webthing-python/workflows/Python%20package/badge.svg%0A%20:target:%20https://github.com/mozilla-iot/webthing-python/workflows/Python%20package)
4+
5+
![image](https://img.shields.io/pypi/v/webthing.svg%0A%20:target:%20https://pypi.org/project/webthing/)
6+
7+
![image](https://img.shields.io/badge/license-MPL--2.0-blue.svg%0A%20:target:%20https://github.com/mozilla-iot/webthing-python/blob/master/LICENSE.txt)
8+
9+
Implementation of an HTTP [Web Thing](https://iot.mozilla.org/wot/).
10+
This library is compatible with Python 3.5+.
11+
12+
## Installation
13+
14+
`webthing` can be installed via `pip`, as such:
15+
16+
``` {.sourceCode .shell}
17+
$ pip install webthing
18+
```
19+
20+
## Example Implementation
21+
22+
In this code-walkthrough we will set up a dimmable light and a humidity
23+
sensor (both using fake data, of course). Both working examples can be
24+
found in
25+
[here](https://github.com/mozilla-iot/webthing-python/tree/master/example).
26+
27+
### Dimmable Light
28+
29+
Imagine you have a dimmable light that you want to expose via the web of
30+
things API. The light can be turned on/off and the brightness can be set
31+
from 0% to 100%. Besides the name, description, and type, a `Light`\_ is
32+
required to expose two properties:
33+
34+
- `on`: the state of the light, whether it is turned on or off
35+
- Setting this property via a `PUT {"on": true/false}` call to the
36+
REST API toggles the light.
37+
- `brightness`: the brightness level of the light from 0-100%
38+
- Setting this property via a PUT call to the REST API sets the
39+
brightness level of this light.
40+
41+
First we create a new Thing:
42+
43+
``` {.sourceCode .python}
44+
light = Thing(
45+
'urn:dev:ops:my-lamp-1234',
46+
'My Lamp',
47+
['OnOffSwitch', 'Light'],
48+
'A web connected lamp'
49+
)
50+
```
51+
52+
Now we can add the required properties.
53+
54+
The on property reports and sets the on/off state of the light. For
55+
this, we need to have a Value object which holds the actual state and
56+
also a method to turn the light on/off. For our purposes, we just want
57+
to log the new state if the light is switched on/off.
58+
59+
``` {.sourceCode .python}
60+
light.add_property(
61+
Property(
62+
light,
63+
'on',
64+
Value(True, None, lambda x: print(x)),
65+
metadata={
66+
'@type': 'OnOffProperty',
67+
'title': 'On/Off',
68+
'type': 'boolean',
69+
'description': 'Whether the lamp is turned on',
70+
}))
71+
```
72+
73+
The `brightness` property reports the brightness level of the light and
74+
sets the level. Like before, instead of actually setting the level of a
75+
light, we just log the level.
76+
77+
``` {.sourceCode .python}
78+
light.add_property(
79+
Property(
80+
light,
81+
'brightness',
82+
Value(50, None, lambda x: print(x)),
83+
metadata={
84+
'@type': 'BrightnessProperty',
85+
'title': 'Brightness',
86+
'type': 'number',
87+
'description': 'The level of light from 0-100',
88+
'minimum': 0,
89+
'maximum': 100,
90+
'unit': 'percent',
91+
}))
92+
```
93+
94+
Now we can add our newly created thing to the server and start it:
95+
96+
``` {.sourceCode .python}
97+
server = WebThingServer(light, port=8888)
98+
99+
try:
100+
server.start()
101+
except KeyboardInterrupt:
102+
server.stop()
103+
```
104+
105+
This will start the server, making the light available via the WoT REST
106+
API and announcing it as a discoverable resource on your local network
107+
via mDNS.
108+
109+
### Sensor
110+
111+
Let's now also connect a humidity sensor to the server we set up for our
112+
light.
113+
114+
A `MultiLevelSensor`\_ (a sensor that returns a level instead of just
115+
on/off) has one required property (besides the name, type, and optional
116+
description): `level`. We want to monitor this property and get notified
117+
if the value changes.
118+
119+
First we create a new Thing:
120+
121+
``` {.sourceCode .python}
122+
sensor = Thing(
123+
'urn:dev:ops:my-humidity-sensor-1234',
124+
'My Humidity Sensor',
125+
['MultiLevelSensor'],
126+
'A web connected humidity sensor'
127+
)
128+
```
129+
130+
Then we create and add the appropriate property.
131+
132+
Contrary to the light, the value cannot be set via an API call, as it
133+
wouldn't make much sense, to SET what a sensor is reading. Therefore, we
134+
are creating a **readOnly** property.
135+
136+
``` {.sourceCode .python}
137+
sensor.add_property(
138+
Property(
139+
sensor,
140+
'level',
141+
Value(None, self.read_from_gpio, None),
142+
metadata={
143+
'@type': 'LevelProperty',
144+
'title': 'Humidity',
145+
'type': 'number',
146+
'description': 'The current humidity in %',
147+
'minimum': 0,
148+
'maximum': 100,
149+
'unit': 'percent',
150+
'readOnly': True,
151+
}))
152+
```
153+
154+
In this example, we pass a readproperty method that will read and return
155+
the sensor value every time it is requested.
156+
157+
Alternatively, we can create a thread that queries the physical sensor
158+
every few seconds. We first remove the readproperty argument from our
159+
Property.
160+
161+
``` {.sourceCode .python}
162+
sensor.add_property(
163+
Property(
164+
sensor,
165+
'level',
166+
Value(0.0),
167+
metadata={
168+
'@type': 'LevelProperty',
169+
'title': 'Humidity',
170+
'type': 'number',
171+
'description': 'The current humidity in %',
172+
'minimum': 0,
173+
'maximum': 100,
174+
'unit': 'percent',
175+
'readOnly': True,
176+
}))
177+
```
178+
179+
We then create our looping function to periodically query the sensor and
180+
set the property value.
181+
182+
``` {.sourceCode .python}
183+
self.sensor_update_task = \
184+
get_event_loop().create_task(self.update_level())
185+
186+
async def update_level(self):
187+
try:
188+
while True:
189+
await sleep(3)
190+
sensor.properties["level"].value.set(self.read_from_gpio())
191+
logging.debug('setting new humidity level: %s', new_level)
192+
except CancelledError:
193+
pass
194+
```
195+
196+
This will update our `Value` object with the sensor readings via the
197+
`sensor.properties["level"].value.set(self.read_from_gpio())` call. The
198+
`Value` object now notifies the property and the thing that the value
199+
has changed, which in turn notifies all websocket listeners.
200+
201+
## Adding to Gateway
202+
203+
To add your web thing to the WebThings Gateway, install the "Web Thing"
204+
add-on and follow the instructions
205+
[here](https://github.com/mozilla-iot/thing-url-adapter#readme).

0 commit comments

Comments
 (0)