This repository has been archived by the owner on Oct 11, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 51
/
iothub-explorer-simulate-device.js
234 lines (204 loc) · 8.92 KB
/
iothub-explorer-simulate-device.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
#!/usr/bin/env node
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
'use strict';
// Native packages
var fs = require('fs');
var path = require('path');
// External dependencies
var program = require('commander');
var prettyjson = require('prettyjson');
// Azure IoT SDK dependencies
var DeviceClient = require('azure-iot-device').Client;
var DeviceConnectionString = require('azure-iot-device').ConnectionString;
var Registry = require('azure-iothub').Registry;
// Local dependencies
var packageJson = require('./package.json');
var inputError = require('./common.js').inputError;
var printSuccess = require('./common.js').printSuccess;
var serviceError = require('./common.js').serviceError;
var printErrorAndExit = require('./common.js').printErrorAndExit;
var getSas = require('./common.js').getSas;
var getHostFromSas = require('./common.js').getHostFromSas;
var createDeviceConnectionString = require('./common.js').createDeviceConnectionString;
var createMessageFromArgument = require('./common.js').createMessageFromArgument;
var showDeprecationText = require('./common.js').showDeprecationText;
showDeprecationText('az iot device simulate');
program
.version(packageJson.version)
.description('Simulate a device.')
.option('--device-connection-string <device-connection-string>', 'connection string to use for the device')
.option('-l, --login <iothub-connection-string>', 'use the connection string provided as argument to use to authenticate with your IoT Hub instance')
.option('--protocol <amqp|amqp-ws|http|mqtt|mqtt-ws>', 'protocol used to send and receive messages (defaults to amqp)', verifyProtocol)
.option('--send [message]', 'send a test message as a device. If the message is not specified, a default message will be used')
.option('--send-interval <interval-in-milliseconds>', 'interval to use between each message being sent (defaults to 1000ms)', parseInt)
.option('--send-count <message-count>', 'number of messages to send', parseInt)
.option('--receive', 'Receive cloud-to-device (C2D) messages as a device')
.option('-v, --verbose', 'shows all the information contained in the message received, including annotations and properties')
.option('--receive-count <message-count>', 'number of C2D messages to receive', parseInt)
.option('--settle <complete|abandon|reject>', 'indicate how the received C2D messages should be settled (defaults to \'complete\')', verifySettle)
.option('--upload-file <file-path>', 'upload a file from the simulated device')
.parse(process.argv);
function verifySettle(arg) {
if (!!arg && arg !== 'complete' && arg !== 'reject' && arg !== 'abandon') {
inputError('--settle can take only take one of the following values: \'complete\', \'reject\' or \'abandon\'');
} else {
return arg;
}
}
function verifyProtocol(arg) {
var lowerCaseArg = arg.toLowerCase();
if (lowerCaseArg !== 'amqp' && lowerCaseArg !== 'amqp-ws' && lowerCaseArg !== 'http' && lowerCaseArg !== 'mqtt' && lowerCaseArg !== 'mqtt-ws') {
inputError('--protocol can take only take one of the following values: \'amqp\', \'amqp-ws\', \'mqtt\', \'mqtt-ws\' or \'http\'');
} else {
return lowerCaseArg;
}
}
var sas = getSas(program.login);
if(!program.deviceConnectionString && !sas) {
inputError('You must specify the device connection string (--device-connection-string) or the IoT Hub connection string (--login), or use the \'login\' command first.');
}
if(!program.deviceConnectionString && !program.args[0]) {
inputError('You must specify either a device connection string (--device-connection-string) or the IoT Hub connection string and a device id as first argument');
}
if (!program.send && !program.receive && !program.uploadFile) {
inputError('Nothing to do: please use --send, --receive or --uploadFile');
}
var settleMethod = program.settle || 'complete';
var protocolArg = program.protocol || 'amqp';
var Protocol;
switch(protocolArg) {
case 'amqp-ws':
Protocol = require('azure-iot-device-amqp').AmqpWs;
break;
case 'http':
Protocol = require('azure-iot-device-http').Http;
break;
case 'mqtt':
Protocol = require('azure-iot-device-mqtt').Mqtt;
if (settleMethod !== 'complete') {
inputError('Cannot ' + settleMethod + ' messages with MQTT: messages are automatically completed.');
}
break;
case 'mqtt-ws':
Protocol = require('azure-iot-device-mqtt').MqttWs;
if (settleMethod !== 'complete') {
inputError('Cannot ' + settleMethod + ' messages with MQTT: messages are automatically completed.');
}
break;
default:
Protocol = require('azure-iot-device-amqp').Amqp;
break;
}
var sendInterval = program.sendInterval || 1000;
var sendCount = program.sendCount || Number.MAX_SAFE_INTEGER;
var receiveCount = program.receiveCount || Number.MAX_SAFE_INTEGER;
var uploadFilePath = program.uploadFile;
var deviceConnectionString;
var deviceId = program.args[0];
if (!deviceId) {
deviceConnectionString = program.deviceConnectionString;
if(!deviceConnectionString) {
inputError('You must specify either a device connection string (--device-connection-string) or the IoT Hub connection string and a device id as first argument');
} else {
deviceId = DeviceConnectionString.parse(deviceConnectionString).DeviceId;
simulateDevice();
}
} else {
var registry = Registry.fromSharedAccessSignature(sas.toString());
registry.get(deviceId, function(err, deviceInfo) {
if (err) serviceError(err);
else {
var host = getHostFromSas(sas.toString());
deviceConnectionString = createDeviceConnectionString(deviceInfo, host);
}
simulateDevice();
});
}
function simulateDevice() {
if (!deviceConnectionString) throw new Error('Couldn\'t figure out device connection string');
if (!Protocol) throw new Error('Couldn\'t figure out protocol to connect to IoT Hub');
var sendRunning = !!program.send;
var receiveRunning = !!program.receive;
var uploadRunning = !!program.uploadFile;
var client = DeviceClient.fromConnectionString(deviceConnectionString, Protocol);
client.open(function(err) {
if (err) serviceError('Could not connect as device: ' + err.message);
if (program.send) {
var sendCounter = 0;
var sendItv = setInterval(function() {
var message = program.send === true ? createMessageFromArgument('Simulated message: #' + sendCounter) : createMessageFromArgument(program.send);
client.sendEvent(message, function(err) {
if (err) serviceError(err);
else {
printSuccess('Message #' + sendCounter + ' sent successfully');
sendCounter++;
if (sendCounter === sendCount) {
sendRunning = false;
clearInterval(sendItv);
}
}
});
}, sendInterval);
}
if (program.receive) {
var receiveCounter = 0;
var onMessage = function(msg) {
printSuccess('==================');
printSuccess('Message received:');
console.log(prettyjson.render(msg.data.toString()));
if (program.verbose) {
console.log('user-id: ' + msg.userId);
console.log('message-id: ' + msg.messageId);
console.log('correlation-id: ' + msg.correlationId);
}
if (msg.properties.count() > 0) {
printSuccess('--- properties ---');
msg.properties.propertyList.forEach(function(prop) {
console.log(prop.key + ': ' + prop.value);
});
}
printSuccess('==================');
receiveCounter++;
if (receiveCounter === receiveCount) {
receiveRunning = false;
client.removeListener('message', onMessage);
}
client[settleMethod](msg, function(err) {
if (err) serviceError('Could not ' + settleMethod + ' message: ' + err.message);
else {
printSuccess(settleMethod + ' message: Success');
}
});
};
client.on('message', onMessage);
}
if (uploadFilePath) {
fs.stat(uploadFilePath, function (err, fileStats) {
if (err) inputError('Cannot find: ' + program.uploadFile);
var fileStream = fs.createReadStream(uploadFilePath);
client.uploadToBlob(path.basename(uploadFilePath), fileStream, fileStats.size, function (err) {
if (err) {
printErrorAndExit('Cannot upload file: ' + err.constructor.name + ': ' + err.message);
} else {
printSuccess('Upload successful');
}
fileStream.destroy();
uploadRunning = false;
});
});
}
var taskInterval = setInterval(function() {
if (!sendRunning && !receiveRunning && !uploadRunning) {
printSuccess('Device simulation finished.');
client.close(function(err) {
if (err) serviceError(err);
else {
clearInterval(taskInterval);
process.exit(0);
}
});
}
}, 200);
});
}