|
1 | 1 | // Connect to an IoT Agent and use fallback values if necessary |
2 | 2 |
|
3 | | - |
4 | 3 | const IoTDevices = require('../devices'); |
5 | 4 | const DEVICE_API_KEY = process.env.DUMMY_DEVICES_API_KEY || '1234'; |
6 | | - |
7 | | -const debug = require('debug')('tutorial:xml'); |
8 | | - |
| 5 | +const xmlParser = require('xml-parser'); |
9 | 6 |
|
10 | 7 | // A series of constants used by our set of devices |
11 | | -const OK = ' OK'; |
12 | | -const NOT_OK = ' NOT OK'; |
13 | | - |
| 8 | +const OK = 'success'; |
| 9 | +const NOT_OK = 'error'; |
14 | 10 |
|
15 | 11 | /* global MQTT_CLIENT */ |
16 | 12 |
|
17 | 13 | // |
18 | 14 | // Splits the deviceId from the command sent. |
19 | 15 | // |
20 | | -function getXMLCommand(string) { |
21 | | - const command = string.split('@'); |
22 | | - if (command.length === 1) { |
23 | | - command.push(''); |
| 16 | +function getResult(status, command, id, info) { |
| 17 | + if (info) { |
| 18 | + return '<' + status + ' command="' + command + '" device="' + id + '">' + info + '</' + status + '/>'; |
24 | 19 | } |
25 | | - return command[1]; |
| 20 | + return '<' + status + ' command="' + command + '" device="' + id + '"/>'; |
26 | 21 | } |
27 | 22 |
|
28 | 23 | // This processor sends XML payload northbound to |
29 | 24 | // the southport of the IoT Agent and sends measures |
30 | 25 | // for the motion sensor, door and lamp. |
31 | 26 |
|
32 | | -// XML 2.0 is a lightweight text based protocol aimed to constrained |
33 | | -// devices and communications |
34 | | -// where the bandwidth and device memory may be limited resources. |
35 | | -// |
36 | | -// A device can report new measures to the IoT Platform using an HTTP GET request to the /iot/d path with the following query parameters: |
37 | | -// |
38 | | -// i (device ID): Device ID (unique for the API Key). |
39 | | -// k (API Key): API Key for the service the device is registered on. |
40 | | -// t (timestamp): Timestamp of the measure. Will override the automatic IoTAgent timestamp (optional). |
41 | | -// d (Data): XML 2.0 payload. |
42 | | -// |
43 | | -// At the moment the API key and timestamp are unused by the simulator. |
44 | | - |
45 | 27 | class XMLCommand { |
46 | 28 | // The bell will respond to the "ring" command. |
47 | 29 | // this will briefly set the bell to on. |
48 | 30 | // The bell is not a sensor - it will not report state northbound |
49 | 31 | actuateBell(req, res) { |
50 | | - |
51 | | - |
52 | | - debug(req.body) |
53 | | - |
54 | | - |
55 | | - const keyValuePairs = req.body.split('|') || ['']; |
56 | | - const command = getXMLCommand(keyValuePairs[0]); |
57 | | - const deviceId = 'bell' + req.params.id; |
58 | | - const result = keyValuePairs[0] + '| ' + command; |
| 32 | + const data = xmlParser(req.body); |
| 33 | + const deviceId = data.root.attributes.device; |
| 34 | + const command = data.root.name; |
59 | 35 |
|
60 | 36 | if (IoTDevices.notFound(deviceId)) { |
61 | | - return res.status(404).send(result + NOT_OK); |
| 37 | + return res.status(404).send(getResult(NOT_OK, command, deviceId, 'not found')); |
62 | 38 | } else if (IoTDevices.isUnknownCommand('bell', command)) { |
63 | | - return res.status(422).send(result + NOT_OK); |
| 39 | + return res.status(422).send(getResult(NOT_OK, command, deviceId, 'unknown command')); |
64 | 40 | } |
65 | 41 |
|
66 | 42 | // Update device state |
67 | 43 | IoTDevices.actuateDevice(deviceId, command); |
68 | | - return res.status(200).send(result + OK); |
| 44 | + return res.status(200).send(getResult(OK, command, deviceId)); |
69 | 45 | } |
70 | 46 |
|
71 | 47 | // The door responds to "open", "close", "lock" and "unlock" commands |
72 | 48 | // Each command alters the state of the door. When the door is unlocked |
73 | 49 | // it can be opened and shut by external events. |
74 | 50 | actuateDoor(req, res) { |
75 | | - const keyValuePairs = req.body.split('|') || ['']; |
76 | | - const command = getXMLCommand(keyValuePairs[0]); |
77 | | - const deviceId = 'door' + req.params.id; |
78 | | - const result = keyValuePairs[0] + '| ' + command; |
| 51 | + const data = xmlParser(req.body); |
| 52 | + const deviceId = data.root.attributes.device; |
| 53 | + const command = data.root.name; |
79 | 54 |
|
80 | 55 | if (IoTDevices.notFound(deviceId)) { |
81 | | - return res.status(404).send(result + NOT_OK); |
| 56 | + return res.status(404).send(getResult(NOT_OK, command, deviceId, 'not found')); |
82 | 57 | } else if (IoTDevices.isUnknownCommand('door', command)) { |
83 | | - return res.status(422).send(result + NOT_OK); |
| 58 | + return res.status(422).send(getResult(NOT_OK, command, deviceId, 'unknown command')); |
84 | 59 | } |
85 | 60 |
|
86 | 61 | // Update device state |
87 | 62 | IoTDevices.actuateDevice(deviceId, command); |
88 | | - return res.status(200).send(result + OK); |
| 63 | + return res.status(200).send(getResult(OK, command, deviceId)); |
89 | 64 | } |
90 | 65 |
|
91 | 66 | // The lamp can be "on" or "off" - it also registers luminosity. |
92 | 67 | // It will slowly dim as time passes (provided no movement is detected) |
93 | 68 | actuateLamp(req, res) { |
94 | | - const keyValuePairs = req.body.split('|') || ['']; |
95 | | - const command = getXMLCommand(keyValuePairs[0]); |
96 | | - const deviceId = 'lamp' + req.params.id; |
97 | | - const result = keyValuePairs[0] + '| ' + command; |
| 69 | + const data = xmlParser(req.body); |
| 70 | + const deviceId = data.root.attributes.device; |
| 71 | + const command = data.root.name; |
98 | 72 |
|
99 | 73 | if (IoTDevices.notFound(deviceId)) { |
100 | | - return res.status(404).send(result + NOT_OK); |
| 74 | + return res.status(404).send(getResult(NOT_OK, command, deviceId, 'not found')); |
101 | 75 | } else if (IoTDevices.isUnknownCommand('lamp', command)) { |
102 | | - return res.status(422).send(result + NOT_OK); |
| 76 | + return res.status(422).send(getResult(NOT_OK, command, deviceId, 'unknown command')); |
103 | 77 | } |
104 | 78 |
|
105 | 79 | // Update device state |
106 | 80 | IoTDevices.actuateDevice(deviceId, command); |
107 | | - return res.status(200).send(result + OK); |
| 81 | + return res.status(200).send(getResult(OK, command, deviceId)); |
108 | 82 | } |
109 | 83 |
|
110 | 84 | // cmd topics are consumed by the actuators (bell, lamp and door) |
111 | 85 | processMqttMessage(topic, message) { |
112 | 86 | const path = topic.split('/'); |
113 | 87 | if (path.pop() === 'cmd') { |
114 | | - const keyValuePairs = message.split('|') || ['']; |
115 | | - const command = getXMLCommand(keyValuePairs[0]); |
116 | | - const deviceId = path.pop(); |
117 | | - const result = keyValuePairs[0] + '| ' + command; |
| 88 | + const data = xmlParser(message); |
| 89 | + const deviceId = data.root.attributes.device; |
| 90 | + const command = data.root.name; |
118 | 91 |
|
119 | 92 | if (!IoTDevices.notFound(deviceId)) { |
120 | 93 | IoTDevices.actuateDevice(deviceId, command); |
121 | 94 | const topic = '/' + DEVICE_API_KEY + '/' + deviceId + '/cmdexe'; |
122 | | - MQTT_CLIENT.publish(topic, result + OK); |
| 95 | + MQTT_CLIENT.publish(topic, getResult(OK, command, deviceId)); |
123 | 96 | } |
124 | 97 | } |
125 | 98 | } |
126 | 99 | } |
127 | 100 |
|
128 | | - |
129 | | - |
130 | 101 | module.exports = XMLCommand; |
131 | | - |
0 commit comments