51 |
52 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/chapter3-node-js/listing-3.9-callbacks-named-functions.js:
--------------------------------------------------------------------------------
1 | var http = require("http"),
2 | request = require('request'),
3 | fs = require('fs');
4 |
5 | var serviceRootUrl = 'http://localhost:8686';
6 |
7 | http.createServer(function (req, res) {
8 | console.log('New incoming client request...');
9 |
10 | if (req.url === '/log') {
11 | getTemperature(res); //#A
12 |
13 | } else {
14 | res.writeHeader(200, {"Content-Type": "text/plain"});
15 | res.write('Please use /log');
16 | res.end();
17 | }
18 |
19 | }).listen(8787);
20 |
21 | function getTemperature(res) { //#B
22 | request({url: serviceRootUrl + '/temperature', json: true}, function (err, resp, body) {
23 | if (err) throw err;
24 | if (resp.statusCode === 200) {
25 | console.log(body);
26 | var temp = body.temperature;
27 |
28 | getLight(res, temp); //#C
29 | }
30 | });
31 | }
32 |
33 | function getLight(res, temp) {
34 | request({url: serviceRootUrl + '/light', json: true}, function (err, resp, body) {
35 | if (err) throw err;
36 | if (resp.statusCode === 200) {
37 | console.log(body);
38 | var light = body.light;
39 |
40 | logValuesReply(res, temp, light); //#D
41 | }
42 | });
43 | }
44 |
45 | function logValuesReply(res, temp, light) {
46 | var logEntry = 'Temperature: ' + temp + ' Light: ' + light;
47 | fs.appendFile('log.txt', logEntry + '\n', encoding = 'utf8', function (err) {
48 | if (err) throw err;
49 | res.writeHeader(200, {"Content-Type": "text/plain"}); //#E
50 | res.write(logEntry);
51 | res.end();
52 | });
53 | }
54 |
55 | //#A Get the temperature and start the chain of calls
56 | //#B A named temperature function
57 | //#C Once the callback for temperature has been called we proceed with calling the getLight function
58 | //#D We then call the named function to log values
59 | //#E Return to the client
60 |
--------------------------------------------------------------------------------
/chapter9-sharing/social-auth/config/change_me_privateKey.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
2 | Proc-Type: 4,ENCRYPTED
3 | DEK-Info: DES-EDE3-CBC,44A2DEDA261477B8
4 |
5 | LiB+m2sQTIWoP6h3Yl+lCNHtyF5B7htWuBILA4Xf4+87GJGWguTXZGh+av4YlnAI
6 | syl3Yiyr9QhBSFUbsIkfnN0MhfO6C2PogJ82vOSuB6phtZk88yIfLMgbL2xvcI6l
7 | EgcVWsOTkC+c8ORPHMYsuXmKAAEi75VxPw+OCIMeGhgaHGf1ZBjKn6GbPYyi1doH
8 | LGsSmmBM+fiRsWiBYO/4lUmzF12WZuQo/zzS4g+VqTkerTQRI/9loPQMvUx/08s6
9 | ZOQNj9JwflYJZfLqHd84ddN0oh06GSe672rKRle1R9V9siULlRW8To/kuYBSxZTm
10 | UMLSc8cXgoMLxtTnBkkxg+oiJmO3+Hrtab9nLsXcL42XXDxvZ5L0vl/dOZxqzAKN
11 | YSJlCspaeF261xTMdGPnAkdRUt18/8XtLmySD4RbrwDysngO+ZyV7K4mDsuJ5pyO
12 | 4iwSD1izb/rTWKec0LYZ+iEUGg1pvHWFbDI7RqxOuBLCUnxCKY7LfMSmkKGGF7nK
13 | K/4bviR9MkiVqaSPivxp9+Byfx1V+MnaKMBnxhqpmBkKK/BruYyYDsFxuxFgvg2t
14 | 8TfIuuGR3yNfzzSHMmj15Zwro7cuuAzmMJ2aQJTTdFJy4fc6ja4rsZtHQZh949gZ
15 | VpqJO7OpYRu1CpagedF1LmOufShyUTSbJzaGQiy8u4Jgt0WOCUzZerPDgyr1QfAo
16 | G2B1jPQ+uMVe07wZrVZhik2V+egnXCNHK6jmwpMk26woMRMqpuuuPDrrLtRIOEXh
17 | Lfa93pSdXPqUjgtiLzCWtXJJCdAPZkR2Ljs5UVtsh5x/km73mUqme+c4mBvIMxAB
18 | zqJZm+bB/PBWwvPXeVSuh+RHVv1n/n5yhBibJKSlYbo78dneMi9ec3nF1+Nx0uAp
19 | HAnNvmfOGBThM9/lkHz0ui9sjMmCiddypn9XoqAIXLxMUGbm/pqhMjKMHDY5zYWu
20 | teog0OfiCUWlft+tOTem2BqnbdG5cKxzee6wBKbuAQWaiMGtV0/Mae0tnuRnMYfd
21 | NvoxOA8Ha1cy9nkOT9nX8lUhpFOiYFXSNA4ei7JdhGB+4Goyyq2uwZq9BXuPltro
22 | haTfflsPu7C4u3yNxehahIY3bPdAE3qU4Y4znn5R4HornNWenc5k7vB/Etni8Yey
23 | ZaaBOUhiZEaO8GCTpBbvaZRU/diKpWiGn/EeJY/e2iBetg8Bsme4k7SupnD+nrmG
24 | iUG3aMB5fwp1kNceaRxw2ofYctP+hkoO80wRhxfhhpW68Wqic9/P38DHnYSWQMdi
25 | SCe30hbny/D/ATTY5vrjdj4/89pxxSJFaJk+G6Q15IhuaJwj8pcclmvlTtgUTQZy
26 | LYSm87CixnsqnMjqWaUyOQWoE4c4IcO3MGPWWpEpfQN0Wp8L7ht8bP+Y0vlwWSVu
27 | VSdyj/Io0TcuHtV2Av2K6F+PixXuMgQpYj9ktHCs0HkeWGsGiLJbZ3eDBgBEpG/d
28 | 9D4/Z1SVJ8DkbOgkp4DaN9jSc5FfyiUpHbN528Zwcl0nGuO6onJnsgbnURxBxf4d
29 | mK235I7vYLm5o9EHecbrDzLsH7G/XvIYwD2ZVy57142QHC4u4fd3Yg==
30 | -----END RSA PRIVATE KEY-----
31 |
--------------------------------------------------------------------------------
/chapter10-mashups/mashup.css:
--------------------------------------------------------------------------------
1 | .onoffswitch {
2 | position: relative; width: 200px;
3 | -webkit-user-select:none; -moz-user-select:none; -ms-user-select: none;
4 | }
5 | .onoffswitch-checkbox {
6 | display: none;
7 | }
8 | .onoffswitch-label {
9 | display: block; overflow: hidden; cursor: pointer;
10 | border: 2px solid #999999; border-radius: 20px;
11 | }
12 | .onoffswitch-inner {
13 | display: block; width: 200%; margin-left: -100%;
14 | -moz-transition: margin 0.3s ease-in 0s; -webkit-transition: margin 0.3s ease-in 0s;
15 | -o-transition: margin 0.3s ease-in 0s; transition: margin 0.3s ease-in 0s;
16 | }
17 | .onoffswitch-inner:before, .onoffswitch-inner:after {
18 | display: block; float: left; width: 50%; height: 74px; padding: 0; line-height: 74px;
19 | font-size: 14px; color: white; font-family: Trebuchet, Arial, sans-serif; font-weight: bold;
20 | -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;
21 | }
22 | .onoffswitch-inner:before {
23 | content: "Intruder detected!";
24 | padding-left: 10px;
25 | background-color: #F70519; color: #FFFFFF;
26 | }
27 | .onoffswitch-inner:after {
28 | content: "No one detected!";
29 | padding-right: 10px;
30 | background-color: #0839FC; color: #999999;
31 | text-align: right;
32 | }
33 | .onoffswitch-switch {
34 | display: block; width: 50px; margin: 12px;
35 | background: #FFFFFF;
36 | border: 2px solid #999999; border-radius: 20px;
37 | position: absolute; top: 0; bottom: 0; right: 122px;
38 | -moz-transition: all 0.3s ease-in 0s; -webkit-transition: all 0.3s ease-in 0s;
39 | -o-transition: all 0.3s ease-in 0s; transition: all 0.3s ease-in 0s;
40 | }
41 | .onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-inner {
42 | margin-left: 0;
43 | }
44 | .onoffswitch-checkbox:checked + .onoffswitch-label .onoffswitch-switch {
45 | right: 0px;
46 | }
--------------------------------------------------------------------------------
/chapter7-implementation/part1-2-direct-gateway/plugins/internal/pirPlugin.js:
--------------------------------------------------------------------------------
1 | var resources = require('./../../resources/model');
2 |
3 | var interval, sensor;
4 | var model = resources.pi.sensors.pir;
5 | var pluginName = resources.pi.sensors.pir.name;
6 | var localParams = {'simulate': false, 'frequency': 2000};
7 |
8 | exports.start = function (params) { //#A
9 | localParams = params;
10 | if (localParams.simulate) {
11 | simulate();
12 | } else {
13 | connectHardware();
14 | }
15 | };
16 |
17 | exports.stop = function () { //#A
18 | if (localParams.simulate) {
19 | clearInterval(interval);
20 | } else {
21 | sensor.unexport();
22 | }
23 | console.info('%s plugin stopped!', pluginName);
24 | };
25 |
26 | function connectHardware() { //#B
27 | var Gpio = require('onoff').Gpio;
28 | sensor = new Gpio(model.gpio, 'in', 'both'); //#C
29 | sensor.watch(function (err, value) { //#D
30 | if (err) exit(err);
31 | model.value = !!value;
32 | showValue();
33 | });
34 | console.info('Hardware %s sensor started!', pluginName);
35 | };
36 |
37 | function simulate() { //#E
38 | interval = setInterval(function () {
39 | model.value = !model.value;
40 | showValue();
41 | }, localParams.frequency);
42 | console.info('Simulated %s sensor started!', pluginName);
43 | };
44 |
45 | function showValue() {
46 | console.info(model.value ? 'there is someone!' : 'not anymore!');
47 | };
48 |
49 | //#A starts and stops the plugin, should be accessible from other Node.js files so we export them
50 | //#B require and connect the actual hardware driver and configure it
51 | //#C configure the GPIO pin to which the PIR sensor is connected
52 | //#D start listening for GPIO events, the callback will be invoked on events
53 | //#E allows the plugin to be in simulation mode. This is very useful when developing or when you want to test your code on a device with no sensors connected, such as your laptop.
54 |
55 |
56 |
--------------------------------------------------------------------------------
/chapter7-implementation/part1-2-direct-gateway/routes/actuators.js:
--------------------------------------------------------------------------------
1 | var express = require('express'),
2 | router = express.Router(),
3 | resources = require('./../resources/model');
4 |
5 | router.route('/').get(function (req, res, next) {
6 | req.result = resources.pi.actuators;
7 | next();
8 | });
9 |
10 | router.route('/leds').get(function (req, res, next) {
11 | req.result = resources.pi.actuators.leds;
12 | next();
13 | });
14 |
15 | router.route('/leds/:id').get(function (req, res, next) { //#A
16 | req.result = resources.pi.actuators.leds[req.params.id];
17 | next();
18 | }).put(function(req, res, next) { //#B
19 | var selectedLed = resources.pi.actuators.leds[req.params.id];
20 | selectedLed.value = req.body.value; //#C
21 | req.result = selectedLed;
22 | next();
23 | });
24 |
25 | module.exports = router;
26 |
27 | //#A Callback for a GET request on an LED
28 | //#B Callback for a PUT request on an LED
29 | //#C Update the value of the selected LED in the model
30 |
31 |
32 | /*
33 | //Initial version:
34 |
35 | var express = require('express'),
36 | router = express.Router(),
37 | resources = require('./../resources/model');
38 |
39 | router.route('/').get(function (req, res, next) { // #A
40 | res.send(resources.pi.actuators); // #B
41 | });
42 |
43 | router.route('/leds').get(function (req, res, next) { // #C
44 | res.send(resources.pi.actuators.leds);
45 | });
46 |
47 | router.route('/leds/:id').get(function (req, res, next) { //#D
48 | res.send(resources.pi.actuators.leds[req.params.id]); //#E
49 | });
50 |
51 | module.exports = router;
52 |
53 | //#A Create a new route for a GET request
54 | //#B Reply with the actuators model when this route is selected
55 | //#C This route serves a list of LEDs
56 | //#D with :id we inject a variable in the path which will be the LED number
57 | //#E the path variables are accessible via req.params.id we use this to select the right object in our model and return it
58 | */
--------------------------------------------------------------------------------
/chapter10-mashups/mashup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
55 |
56 |
57 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/chapter7-implementation/part1-2-direct-gateway/wot-server.js:
--------------------------------------------------------------------------------
1 | // Final version
2 | var httpServer = require('./servers/http'),
3 | wsServer = require('./servers/websockets'),
4 | resources = require('./resources/model');
5 |
6 | // Internal Plugins
7 | var ledsPlugin = require('./plugins/internal/ledsPlugin'), //#A
8 | pirPlugin = require('./plugins/internal/pirPlugin'), //#A
9 | dhtPlugin = require('./plugins/internal/DHT22SensorPlugin'); //#A
10 |
11 | // Internal Plugins for sensors/actuators connected to the PI GPIOs
12 | // If you test this with real sensors do not forget to set simulate to 'false'
13 | pirPlugin.start({'simulate': true, 'frequency': 2000}); //#B
14 | ledsPlugin.start({'simulate': true, 'frequency': 10000}); //#B
15 | dhtPlugin.start({'simulate': true, 'frequency': 10000}); //#B
16 |
17 | // External Plugins
18 | var coapPlugin = require('./plugins/external/coapPlugin');
19 | coapPlugin.start({'simulate': false, 'frequency': 10000});
20 |
21 | // HTTP Server
22 | var server = httpServer.listen(resources.pi.port, function () {
23 | console.log('HTTP server started...');
24 |
25 | // Websockets server
26 | wsServer.listen(server);
27 |
28 | console.info('Your WoT Pi is up and running on port %s', resources.pi.port);
29 | });
30 | //#A Require all the sensor plugins you need
31 | //#B Start them with a parameter object; here you start them on a laptop so you activate the simulation function
32 |
33 |
34 |
35 | /*
36 | // Initial version:
37 | var httpServer = require('./servers/http'), //#A
38 | resources = require('./resources/model');
39 |
40 | var server = httpServer.listen(resources.pi.port, function () { //#B
41 | console.info('Your WoT Pi is up and running on port %s', resources.pi.port); //#C
42 | });
43 |
44 | //#A Load the http server and the model
45 | //#B Start the HTTP server by invoking listen() on the Express application
46 | //#C Once the server is started the callback is invoked
47 | */
48 |
49 |
--------------------------------------------------------------------------------
/chapter9-sharing/social-auth/views/account.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Web Thing
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
76 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/chapter2-hello-wot/requests/responses.txt:
--------------------------------------------------------------------------------
1 | {
2 | "pi": {
3 | "id": "1",
4 | "name": "My WoT Raspberry PI",
5 | "description": "A simple WoT-connected Raspberry PI for the WoT book.",
6 | "url": "http://devices.webofthings.io/pi/",
7 | "currentStatus": "Live",
8 | "version": "v0.1",
9 | "tags": [
10 | "raspberry",
11 | "pi",
12 | "WoT"
13 | ],
14 | "ip": "todo",
15 | "resources": {
16 | "sensors": {
17 | "url": "sensors/",
18 | "name": "The list of sensors"
19 | },
20 | "actuators": {
21 | "url": "actuators/",
22 | "name": "The list of actuators"
23 | }
24 | },
25 | "links": {
26 | "meta": {
27 | "rel": "http://webofthings.io/meta/device/",
28 | "title": "Metadata"
29 | },
30 | "self": {
31 | "rel": "self/",
32 | "title": "Self"
33 | },
34 | "doc": {
35 | "rel": "http://webofthings.io/docs/pi/",
36 | "title": "Documentation"
37 | },
38 | "ui": {
39 | "rel": "ui/",
40 | "title": "User Interface"
41 | }
42 | }
43 | },
44 | "camera": {
45 | "id": "2",
46 | "name": "My WoT Camera",
47 | "description": "A simple WoT-connected camera.",
48 | "url": "http://devices.webofthings.io/camera/",
49 | "currentStatus": "Live",
50 | "version": "v0.1",
51 | "tags": [
52 | "camera",
53 | "WoT"
54 | ],
55 | "ip": "todo",
56 | "resources": {
57 | "sensors": {
58 | "url": "sensors/",
59 | "name": "The list of sensors"
60 | },
61 | "actuators": {
62 | "url": "actuators/",
63 | "name": "The list of actuators"
64 | }
65 | },
66 | "links": {
67 | "meta": {
68 | "rel": "http://webofthings.io/meta/device/",
69 | "title": "Metadata"
70 | },
71 | "doc": {
72 | "rel": "http://webofthings.io/docs/camera/",
73 | "title": "Documentation"
74 | },
75 | "ui": {
76 | "rel": "ui",
77 | "title": "User Interface"
78 | }
79 | }
80 | }
81 | }
82 |
83 |
84 |
85 | /// Shorter
86 |
87 | {
88 | "pi": {
89 | "id": "1",
90 | "name": "My WoT Raspberry PI",
91 | "description": "A simple WoT-connected Raspberry PI for the WoT book.",
92 | "url": "http://devices.webofthings.io/pi/",
93 | "currentStatus": "Live",
94 | "version": "v0.1",
95 | "tags": ["raspberry","pi","WoT"],
96 | "resources": {},
97 | "links": {}
98 | },
99 | "camera": {
100 | "id": "2",
101 | "name": "My WoT Camera",
102 | "description": "A simple WoT-connected camera.",
103 | "url": "http://devices.webofthings.io/camera/",
104 | "currentStatus": "Live",
105 | "version": "v0.1",
106 | "tags": ["camera","WoT"],
107 | "resources": {},
108 | "links": {}
109 | }
110 | }
111 |
112 |
113 |
114 | /// Step 3 Get the sensors
115 |
116 | {
117 | "temperature": {
118 | "name": "Temperature Sensor",
119 | "description": "A temperature sensor.",
120 | "type": "float",
121 | "unit": "celsius",
122 | "value": 23.4,
123 | "timestamp": "2015-10-04T14:39:17.240Z",
124 | "frequency": 5000
125 | },
126 | "humidity": {
127 | "name": "Humidity Sensor",
128 | "description": "A temperature sensor.",
129 | "type": "float",
130 | "unit": "percent",
131 | "value": 38.9,
132 | "timestamp": "2015-10-04T14:39:17.240Z",
133 | "frequency": 5000
134 | },
135 | "pir": {
136 | "name": "Passive Infrared",
137 | "description": "A passive infrared sensor. When true someone is present.",
138 | "type": "boolean",
139 | "value": true,
140 | "timestamp": "2015-10-04T14:39:17.240Z",
141 | "gpio": 20
142 | }
143 | }
144 |
145 |
146 | "resources": {
147 | "sensors": {
148 | "url": "sensors/",
149 | "name": "The list of sensors"
150 | },
151 | "actuators": {
152 | "url": "actuators/",
153 | "name": "The list of actuators"
154 | }
155 | },
156 |
157 |
158 |
--------------------------------------------------------------------------------
/chapter9-sharing/social-auth/providers/facebook.js:
--------------------------------------------------------------------------------
1 | var passport = require('passport'),
2 | util = require('util'),
3 | FacebookStrategy = require('passport-facebook').Strategy,
4 | session = require('express-session'),
5 | cookieParser = require('cookie-parser'),
6 | auth = require('../middleware/auth'),
7 | methodOverride = require('method-override');
8 |
9 | var acl = require('../config/acl.json'); //#A
10 | var facebookAppId = '446871648832920'; //#A
11 | var facebookAppSecret = '7499c233a1e2c4d8234dedca5e6a0cc3'; //#A
12 | var socialNetworkName = 'facebook'; //#A
13 | var callbackResource = '/auth/facebook/callback'; //#A
14 | var callbackUrl = 'https://localhost:' + acl.config.sourcePort + callbackResource; //#A
15 |
16 |
17 | module.exports.setupFacebookAuth = setupFacebookAuth;
18 | function setupFacebookAuth(app) {
19 | app.use(cookieParser());
20 | app.use(methodOverride());
21 | app.use(session({secret: 'keyboard cat', resave: true, saveUninitialized: true}));
22 | app.use(passport.initialize()); //#B
23 | app.use(passport.session());
24 |
25 | passport.serializeUser(function (user, done) { //#C
26 | done(null, user);
27 | });
28 |
29 | passport.deserializeUser(function (obj, done) {
30 | done(null, obj);
31 | });
32 |
33 | passport.use(new FacebookStrategy({
34 | clientID: facebookAppId, //#D
35 | clientSecret: facebookAppSecret,
36 | callbackURL: callbackUrl //#E
37 | },
38 | function (accessToken, refreshToken, profile, done) {
39 |
40 | auth.checkUser(socialId(profile.id), accessToken, function (err, res) { //#F
41 | if (err) return done(err, null);
42 | else return done(null, profile);
43 | });
44 | }));
45 |
46 | app.get('/auth/facebook',
47 | passport.authenticate('facebook'), //#G
48 | function (req, res) {}); //#H
49 |
50 | app.get(callbackResource, //#I
51 | passport.authenticate('facebook', {session: true, failureRedirect: '/login'}),
52 | function (req, res) {
53 | res.redirect('/account');
54 | });
55 |
56 | app.get('/account', ensureAuthenticated, function (req, res) { //#J
57 | auth.getToken(socialId(req.user.id), function (err, user) {
58 | if (err) res.redirect('/login');
59 | else {
60 | req.user.token = user.token;
61 | res.render('account', {user: req.user});
62 | }
63 | });
64 | });
65 |
66 | function socialId(userId) { //#K
67 | return socialNetworkName + ':' + userId;
68 | };
69 |
70 | app.get('/', ensureAuthenticated, function (req, res) {
71 | res.render('index', {user: req.user});
72 | });
73 |
74 | app.get('/login', function (req, res) {
75 | res.render('login', {user: req.user});
76 | });
77 |
78 | app.get('/logout', function (req, res) {
79 | req.logout();
80 | res.redirect('/');
81 | });
82 |
83 | function ensureAuthenticated(req, res, next) {
84 | if (req.isAuthenticated()) {
85 | return next();
86 | }
87 | res.redirect('/login');
88 | };
89 |
90 | };
91 |
92 | // #A Configuration variables: FB app ID, app secret, name, and the URL to call back after a user authentication on Facebook
93 | // #B Initialize Passport and support storing the user login in sessions
94 | // #C If you had a database of users you’d use these two methods to load and save users
95 | // #D The credentials used to authenticate your auth proxy as a Facebook app
96 | // #E This URL will be called by Facebook after a successful login
97 | // #F The “verify” function, called by the framework after a successful authentication with the provider; here we check if the user is known by the proxy and store their token if so
98 | // #G Trigger the authentication process, and redirect the user to facebook.com
99 | // #H Facebook.com will redirect the user to the callbackUrl, so this function will never be called!
100 | // #I This route will be called by Facebook after user authentication. If it fails you redirect to /login, otherwise to /account
101 | // #J If the user is authenticated you get their token and display their account page; otherwise redirect to /login
102 | // #K A unique social identifier is formed by concatenating the social userId and the social network name
--------------------------------------------------------------------------------
/chapter7-implementation/part3-cloud/setup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | ## This file is a set of cURL requests used in Chapter 7 of the Book "Building the Web of Things" by Guinard & Trifa (bit.ly/wotbook)
3 |
4 | # Ensure we are running bash, if not run in bash
5 | if [ -z "$BASH_VERSION" ]
6 | then
7 | exec bash "$0" "$@"
8 | fi
9 |
10 | SERVER="https://api.evrythng.com"
11 | [ -z "$EVRYTHNG_API_KEY" ] && EVRYTHNG_API_KEY=$1
12 |
13 | mkdir -p payloads
14 |
15 | # Extract JSON content
16 | function parse_json()
17 | {
18 | echo $1 | \
19 | sed -e 's/[{}]/''/g' | \
20 | sed -e 's/", "/'\",\"'/g' | \
21 | sed -e 's/" ,"/'\",\"'/g' | \
22 | sed -e 's/" , "/'\",\"'/g' | \
23 | sed -e 's/","/'\"---SEPARATOR---\"'/g' | \
24 | awk -F=':' -v RS='---SEPARATOR---' "\$1~/\"$2\"/ {print}" | \
25 | sed -e "s/\"$2\"://" | \
26 | tr -d "\n\t" | \
27 | sed -e 's/\\"/"/g' | \
28 | sed -e 's/\\\\/\\/g' | \
29 | sed -e 's/^[ \t]*//g' | \
30 | sed -e 's/^"//' -e 's/"$//'
31 | }
32 |
33 |
34 | #####
35 | ##### Step 0 - Let's create a config.json file which will be used later
36 | #####
37 | echo "{" > config.json
38 | echo ' "operatorApiKey":"'$EVRYTHNG_API_KEY'",' >> config.json
39 |
40 |
41 | #####
42 | ##### Step 1 - 1. Create a Project
43 | #####
44 | curl -X POST "$SERVER/projects" \
45 | -H "Authorization: $EVRYTHNG_API_KEY" \
46 | -H "Content-Type: application/json" \
47 | -d '{ "name": "Web of Things Book", "description": "My First WoT Project" }' > payloads/project.json
48 |
49 | # Parse the response to get the project ID
50 | PROJECT=`cat payloads/project.json`
51 | PROJECT_ID=`parse_json "$PROJECT" id`
52 |
53 | # Store the project ID in our config.json file
54 | echo "Created Project ID: $PROJECT_ID"
55 | echo "RESULT: $PROJECT"
56 | echo ' "projectId":"'$PROJECT_ID'",' >> config.json
57 |
58 |
59 | #####
60 | ##### Step 1 - 2. Let's create an application within this project
61 | #####
62 | curl -X POST "$SERVER/projects/$PROJECT_ID/applications" \
63 | -H "Authorization: $EVRYTHNG_API_KEY" \
64 | -H "Content-Type: application/json" \
65 | -d '{ "name": "My Awesome WoT App", "description": "My First WoT Client Application","tags":["WoT","device","plug","energy"], "socialNetworks": {} }' > payloads/app.json
66 |
67 | # Parse the response to get the app ID and app API key
68 | APP=`cat payloads/app.json`
69 | APP_ID=`parse_json "$APP" id`
70 | APP_API_KEY=`parse_json "$APP" appApiKey`
71 |
72 | # Store the app ID and app API key in our config.json file
73 | echo "Created App ID: $APP_ID"
74 | echo "RESULT: $APP"
75 | echo ' "appId":"'$APP_ID'",' >> config.json
76 | echo ' "appApiKey":"'$APP_API_KEY'",' >> config.json
77 |
78 |
79 |
80 |
81 | #####
82 | ##### Step 2 - 1. Let's now create a product within this project
83 | #####
84 | curl -X POST "$SERVER/products?project=$PROJECT_ID" \
85 | -H "Authorization: $EVRYTHNG_API_KEY" \
86 | -H "Content-Type: application/json" \
87 | -d '{ "fn": "WoT Smart Plug", "description": "A Web-connected Smart Plug","tags":["WoT","device","energy"],"photos":["https://webofthings.github.io/files/plug.jpg"] }' > payloads/product.json
88 |
89 | # Parse the response to get the product ID
90 | PRODUCT=`cat payloads/product.json`
91 | PRODUCT_ID=`parse_json "$PRODUCT" id`
92 |
93 | # Store the product ID in our config.json file
94 | echo "Created Product ID: $PRODUCT_ID"
95 | echo "RESULT: $PRODUCT"
96 | echo ' "productId":"'$PRODUCT_ID'",' >> config.json
97 |
98 |
99 | # Find this product in this project - You should see your product here
100 | curl -X GET "$SERVER/products/$PRODUCT_ID?project=$PROJECT_ID" \
101 | -H "Authorization: $EVRYTHNG_API_KEY" \
102 | -H "Accept: application/json"
103 |
104 |
105 |
106 |
107 | #####
108 | ##### Step 2 - 2. Let's now create a thng (an instance of the product) within this project
109 | #####
110 | curl -X POST "$SERVER/thngs?project=$PROJECT_ID" \
111 | -H "Authorization: $EVRYTHNG_API_KEY" \
112 | -H "Content-Type: application/json" \
113 | -d '{ "name": "My WoT Plug", "product":"'$PRODUCT_ID'", "description": "My own Smart Plug","tags":["WoT","device","plug","energy"] }' > payloads/thng.json
114 |
115 |
116 | # Parse the response to get the thng ID
117 | THNG=`cat payloads/thng.json`
118 | THNG_ID=`parse_json "$THNG" id`
119 |
120 |
121 | # Store the thng ID in our config.json file
122 | echo "Created Thng ID: $THNG_ID"
123 | echo "RESULT: $THNG"
124 | echo ' "thngId":"'$THNG_ID'",' >> config.json
125 |
126 |
127 |
128 | #####
129 | ##### Step 3 - Let's now create an API Key for this device
130 | #####
131 | curl -X POST "$SERVER/auth/evrythng/thngs" \
132 | -H "Authorization: $EVRYTHNG_API_KEY" \
133 | -H "Content-Type: application/json" \
134 | -d '{ "thngId": "'$THNG_ID'" }' > payloads/deviceApiKey.json
135 |
136 | # Parse the response to get the device API Key
137 | THNG_API=`cat payloads/deviceApiKey.json`
138 | THNG_API_KEY=`parse_json "$THNG_API" thngApiKey`
139 |
140 |
141 | # Store the device API Key in our config.json file
142 | echo ' "thngApiKey":"'$THNG_API_KEY'"' >> config.json
143 |
144 | # Close the file
145 | echo '}' >> config.json
146 |
147 |
148 |
149 |
150 | #####
151 | ##### Step 4 - Let's update two properties of this thng
152 | #####
153 | curl -X POST "$SERVER/thngs/$THNG_ID/properties" \
154 | -H "Authorization: $THNG_API_KEY" \
155 | -H "Content-Type: application/json" \
156 | -d '[
157 | {
158 | "key": "status",
159 | "value": true
160 | },
161 | {
162 | "key": "power",
163 | "value": 71
164 | }
165 | ]'
166 |
167 |
168 | # Let's update this Thng a few times with random values
169 | for i in {1..5}
170 | do
171 | curl -X POST "$SERVER/thngs/$THNG_ID/properties" \
172 | -H "Authorization: $THNG_API_KEY" \
173 | -H "Content-Type: application/json" \
174 | -d '[{"key": "voltage","value": '$(( $RANDOM%200 ))'},{"key": "current","value": '$(( $RANDOM%100 ))'},{"key": "power","value": '$(( $RANDOM%400 ))'}]'
175 | sleep 2
176 | done
177 |
178 |
179 |
180 | #####
181 | ##### Section 7.4.3 - Let's use actions to control our plug
182 | #####
183 |
184 | # First, we create a new action type
185 | # NOTE: obviously, this would fail if you have already run the script and this action type already exists in your account!
186 | curl -X POST "$SERVER/actions?project=$PROJECT_ID" \
187 | -H "Authorization: $EVRYTHNG_API_KEY" \
188 | -H "Content-Type: application/json" \
189 | -d '{ "name": "_setStatus", "description": "Changes the Status of the Thng","tags":["WoT","device"] }' > payloads/setStatus.json
190 |
191 |
192 | # Creates a new instance of this action type (= sends a command to the device)
193 | curl -X POST "$SERVER/actions/_setStatus?project=$PROJECT_ID" \
194 | -H "Authorization: $EVRYTHNG_API_KEY" \
195 | -H "Content-Type: application/json" \
196 | -d '{ "type": "_setStatus", "thng":"'$THNG_ID'", "customFields": {"status":false} }'
197 |
198 | #####
199 | ##### Section 7.4.4 - Let's create a redirection for this app
200 | #####
201 | curl -X POST "https://tn.gg/redirections" \
202 | -H "Authorization: $EVRYTHNG_API_KEY" \
203 | -H "Content-Type: application/json" \
204 | -H "Accept: application/json" \
205 | -d '{ "type": "thng", "evrythngId":"'$THNG_ID'", "defaultRedirectUrl":"http://webofthings.github.io/wot-book/plug.html?thngId={evrythngId}&key='$EVRYTHNG_API_KEY'" }'
206 |
--------------------------------------------------------------------------------
/chapter10-mashups/UI/UI.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
191 |
192 | WoT Controller
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
WoT UI
210 |
Control any Web Thing!
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
Smart Plug
220 |
221 |
222 |
223 |
Actions
224 |
225 |
226 |
227 |
228 |
229 |
Properties
230 |
231 |
232 |
233 |
234 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
269 |
276 |
277 |
279 |
280 |
281 |
282 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/chapter7-implementation/part3-cloud/client/plug.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
52 |
53 | Web Thing Controller
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |