Developing Web Things with Python, Client. js, and Java
|The Mozilla IoT team lately released the Things Framework , which allows you to build IoT gadgets that speak the Web Matter API . Last week, James constructed an ESP8266 web thing . This time, I’ m going to demonstrate how to build web things with Python, Node. js, or Java. These types of languages are definitely not optimal just for small embedded devices; this guide is intended for higher-end devices that may run these languages with ease, as well as your own desktop computer.
To show, we’ ll be turning the particular Music Player Daemon (MPD) into a web thing. The your local library we’ ll be using here are webthing-python , webthing-node , and webthing-java .
Intro towards the Music Player Daemon (MPD)
The Music Player Daemon is an open-source music player that has been about since 2003. MPD operates in the client/server model, and is controllable more than TCP with a simple text-based process. I won’ t cover set up here, but MPD can be set up via your package manager upon Linux, Homebrew on Mac OPERATING SYSTEM X, or with binaries upon Windows .
Several Quick Notes
Even though this example is written just for MPD, it would be easily portable to music players with an API, or perhaps you could build your own player employing this example as a base. More importantly, this particular example is primarily meant to show the Things Framework, which can be used to develop an endless variety of web things.
The Python, Node. js, and Java web thing your local library all have essentially the same API. While they may not be entirely idiomatic for respective languages, doing this allows us to preserve all the libraries more easily, which is extremely valuable while the Web Thing API is still a living draft.
Getting Started
To start, initialize an empty project for your language of preference. For example , you might create a new task in IntelliJ IDEA for Java, or run npm init
to start a new Node. js task. You’ ll then want to include the webthing library as an addiction. Instructions for doing so can be found for the respective Github project page, you can also look here .
Now we’ re ready to compose some code. Essentially we’ lmost all do the following:
- Create a
Thing
.- Define its qualities.
- Define its activities.
- Define its occasions.
- Connect the
Thing
to aWebThingServer
.
Produce a Thing
First off, let’ s import our library of preference.
Python
from webthing import Action, Event, Property, Issue, Value, WebThingServer
JavaScript
const
Action,
Event,
Property,
Thing,
Value,
WebThingServer,
= require('webthing');
Java
import org. mozilla. iot. webthing. Action;
transfer org. mozilla. iot. webthing. Occasion;
import org. mozilla. iot. webthing. Property;
import org. mozilla. iot. webthing. Thing;
import org. mozilla. iot. webthing. Value;
import org. mozilla. iot. webthing. WebThingServer;
Now, we’ ll create a basic subclass associated with Thing
.
Python
class MPDThing(Thing):
def __init__(self):
Thing. __init__(self, 'MPD', 'musicPlayer', 'Music Player Daemon')
JavaScript
class MPDThing stretches Thing
constructor()
super('MPD', 'musicPlayer', 'Music Player Daemon');
Java
public class MPDThing extends Point
public MPDThing()
super("MPD", "musicPlayer", "Music Player Daemon");
Add Properties
Since we have our MPDThing
, we’ ll need to then add properties to it. Obviously, a very good music player will have quite a few properties. To demonstrate, I am going to show you how to add one, plus I’ ll link to the rest of the program code at the end of this post.
To include a property, you can do the following inside the MPDThing
constructor.
Python
position = self. get_status()
self. add_property(
Property(self,
'volume',
Value(self. get_volume(status), personal. set_volume),
metadata=
'type': 'number',
'description': 'Playback volume',
'minimum': 0,
'maximum': 100,
))
JavaScript
this. getStatus(). then((status) =>
this.getVolume(status).then((v) =>
this.addProperty(
new Property(this,
'volume',
new Value(v, this.setVolume.bind(this)),
type: 'number',
description: 'Playback volume',
minimum: 0,
maximum: 100,
));
);
);
Coffee
ServerStatus status = this particular. client. getServerStatus();
Map< String, Object> volumeMetadata = new HashMap< > ();
volumeMetadata. put("type", "number");
volumeMetadata. put("description", "Playback volume");
volumeMetadata. put("minimum", 0);
volumeMetadata. put("maximum", 100);
this particular. volumeValue =
new Value(status. getVolume(), v -> this. setVolume((int)v));
this particular. addProperty(new Property(this,
"volume",
this. volumeValue,
volumeMetadata));
We’ ve now created a Property
which allows us to GET and PUT the play-back volume. The Worth
piece is an item that essentially stores a cached value and a “ value forwarder” callback. When the volume is set with a PUT request, the value forwarder can be used to forward the new value towards the actual device, which in this situation is the MPD server. We’ ve also set up some metadata for your property, including a description, worth type, and a minimum and optimum value.
Add Activities
A music player may also have a lot of actions. While the MPD web thing has several simple actions like play, pause, plus skip, I’ ve added one which takes some additional input, that will queue a series of random songs. Actions inputs are verified with a JSON Schema validator .
First, let’ s create a good Action
subclass.
Python
class QueueRandomAction(Action):
def __init__(self, issue, input_):
Action. __init__(
self, uuid. uuid4(). hex, thing, 'queueRandom', input_=input_)
def perform_action(self):
songs = personal. thing. list()
if songs:
meant for _ in range(0, int(self. insight['count'])):
self. thing. add(random. choice(songs))
playlist = self. matter. get_playlist()
if playlist is not Not one:
self. thing. add_event(
PlaylistUpdatedEvent(self. factor, playlist))
JavaScript
course QueueRandomAction extends Action
constructor(thing, input)
super(uuidv4(), thing, 'queueRandom', input);
performAction()
return this.thing.list().then((songs) =>
const promises = [] ;
if (songs)
for (let i = 0; i < this.input.count; ++i)
const uri = songs [Math.floor(Math.random() * songs.length)] .file;
promises.push(this.thing.add(uri));
promises.push(this.thing.getPlaylist().then((playlist) =>
if (playlist)
this.thing.addEvent(new PlaylistUpdatedEvent(this.thing, playlist));
));
return Promise.all(promises);
);
Java
public static course QueueRandomAction extends Action
public QueueRandomAction(Thing thing, JSONObject input)
super(UUID.randomUUID().toString(), thing, "queueRandom", input);
@Override
public void performAction()
MPDThing thing = (MPDThing)this.getThing();
Random random = new Random();
List<MPDFile> songs = thing.list();
for (int i = 0; i < this.getInput().getInt("count"); ++i)
MPDFile file = songs.get(random.nextInt(songs.size()));
thing.add(file);
String playlist = thing.getPlaylist();
thing.addEvent(new PlaylistUpdatedEvent(thing, playlist));
QueueRandomAction
takes an insight, count
, lines that number of random songs to the present playlist, and then emits a PlaylistUpdatedEvent
(to be defined shortly). To add this particular new action to our MPDThing
, do the following within the MPDThing
constructor:
Python
self. add_available_action(
'queueRandom',
'description': 'Queue a series of random songs',
'input':
'type': 'object',
'required': [
'count',
] ,
'properties':
'count':
'type': 'number',
'minimum': 1,
,
,
,
QueueRandomAction)
JavaScript
this. addAvailableAction(
'queueRandom',
description: 'Queue a series of random songs',
input:
type: 'object',
required: [
'count',
] ,
properties:
count:
type: 'number',
minimum: 1,
,
,
,
,
QueueRandomAction);
Coffee
Map< String, Object> queueRandomMetadata = new HashMap< > ();
queueRandomMetadata. put("description",
"Queue a series of unique songs");
Map< String, Object> queueRandomInputMetadata = new HashMap< < > ();
queueRandomInputMetadata. put("type", "object");
queueRandomInputMetadata. put("required", new String[]"count" );
Map< String, Object> queueRandomInputPropertiesMetadata =
new HashMap< > ();
Map< String, Object> queueRandomInputPropertiesCountMetadata sama dengan
new HashedMap();
queueRandomInputPropertiesCountMetadata. put("type", "number");
queueRandomInputPropertiesCountMetadata. put("minimum", 1);
queueRandomInputPropertiesMetadata. put("count",
queueRandomInputPropertiesCountMetadata);
queueRandomInputMetadata. put("properties",
queueRandomInputPropertiesMetadata);
queueRandomMetadata. put("input", queueRandomInputMetadata);
this. addAvailableAction("queueRandom",
queueRandomMetadata,
QueueRandomAction. class);
Add Events
The final piece of our Thing
is the events. Since MPD is a client/server model, it can be updated externally simply by any number of other clients. As such, We created an event that will fire once the current playlist is updated.
As with Factor
and Action
, we’ ll develop an Event
subclass.
Python
class PlaylistUpdatedEvent(Event):
def __init__(self, thing, data):
Event. __init__(self, factor, 'playlistUpdated', data=data)
JavaScript
class PlaylistUpdatedEvent extends Event
constructor(thing, data)
super(thing, 'playlistUpdated', data);
Java
public stationary class PlaylistUpdatedEvent extends Event
public PlaylistUpdatedEvent(Thing thing, String data)
super(thing, "playlistUpdated", data);
It is a basic Event
. The data member will be filled along with a string representation of the present playlist.
To add this particular Event
to our thing, we’ ll the actual following in the MPDThing
constructor:
Python
self. add_available_event(
'playlistUpdated',
'description': 'The current playlist has been updated',
'type': 'string' )
JavaScript
this. addAvailableEvent(
'playlistUpdated',
description: 'The current playlist has been updated',
type: 'string',
);
Java
Map< Chain, Object> playlistUpdatedMetadata = new HashMap< > ();
playlistUpdatedMetadata. put("description",
"The current playlist has been updated");
playlistUpdatedMetadata. put("type", "string");
this. addAvailableEvent("playlistUpdated", playlistUpdatedMetadata);
Produce a WebThingServer
Now that we now have a thing with properties, actions, plus events, we’ ll create a WebThingServer
plus attach the MPDThing
to it.
Python
thing = MPDThing()
server = WebThingServer([thing], port=8888)
try:
server. start()
except KeyboardInterrupt:
server. stop()
JavaScript
const thing = new MPDThing();
const server = new WebThingServer([thing], null, 8888);
process. on('SIGINT', () =>
server.stop();
process.exit();
);
machine. start();
Java
MPDThing thing = new MPDThing();
List< Thing> things = new ArrayList< > ();
things. add(thing);
test
WebThingServer server = new WebThingServer(things, null, 8888);
Runtime.getRuntime()
.addShutdownHook(new Thread(() -> server.stop()));
server.start(false);
catch (IOException e)
System.out.println(e);
System.exit(1);
Managing the Web Thing
The web thing is complete plus it’ s now controllable with the Web Thing API. Here’ s i9000 how to add it to the Elements Gateway :
- Empty Things Display
- Add New Thing
- New Thing Displayed
- Extended Thing UI
The Things Gateway doesn’ t currently provide a way to make use of actions or display events, yet those are in the works.
Alternatively, you can control the internet thing via cURL or any additional HTTP library you choose:
Shell
$ curl
-X POST http://127.0.0.1:8888/actions
-H 'Content-Type: application/json'
-d ' "play": '
Wrapping Up
Your own imagination is really your only restrict as to what you can turn into a web matter. If you’ d like to view the rest of this example and how the particular MPD controls are implemented, all the code is available on Github .
If you have any queries or suggestions, you can head over to Talk or find all of us in #iot
on irc. mozilla. org . Additionally , feel free to create problems, or even better, submit pull requests, towards the webthing library repositories!
Erina is a software engineer at Mozilla working on Project Things.
If you liked Developing Web Things with Python, Client. js, and Java by Michael Stegeman Then you'll love Web Design Agency Miami