-
Notifications
You must be signed in to change notification settings - Fork 53
/
Particle.js
2828 lines (2656 loc) · 135 KB
/
Particle.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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
const Defaults = require('./Defaults');
const EventStream = require('./EventStream');
const Agent = require('./Agent');
const Client = require('./Client');
/**
* Particle Cloud API wrapper.
*
* See <https://docs.particle.io/reference/javascript/> for examples
* of using the `Particle` class.
*
* Most Particle methods take a single unnamed argument object documented as
* `options` with key/value pairs for each option.
*
* @typedef {import('./Agent').RequestResponse} RequestResponse
* @typedef {import('./Agent').RequestError} RequestError
*/
// These typedef avoid importing the type on every @return statement
class Particle {
/**
* Contructor for the Cloud API wrapper.
*
* Create a new Particle object and call methods below on it.
*
* @param {Object} options Options for this API call Options to be used for all requests (see [Defaults](../src/Defaults.js))
* @param {string} [options.baseUrl]
* @param {string} [options.clientSecret]
* @param {string} [options.clientId]
* @param {number} [options.tokenDuration]
* @param {string} [options.auth] The access token. If not specified here, will have to be added to every request
*/
constructor(options = {}){
if (options.auth) {
this.setDefaultAuth(options.auth);
}
// todo - this seems a bit dangerous - would be better to put all options/context in a contained object
Object.assign(this, Defaults, options);
this.context = {};
this.agent = new Agent(this.baseUrl);
}
_isValidContext(name, context){
return (name === 'tool' || name === 'project') && context !== undefined;
}
setContext(name, context){
if (context !== undefined){
if (this._isValidContext(name, context)){
this.context[name] = context;
} else {
throw Error('unknown context name or undefined context: ' + name);
}
}
}
/**
* Builds the final context from the context parameter and the context items in the api.
* @param {Object} context The invocation context, this takes precedence over the local context.
* @returns {Object} The context to use.
* @private
*/
_buildContext(context){
return Object.assign(this.context, context);
}
/**
* Login to Particle Cloud using an existing Particle acccount.
* @param {Object} options Options for this API call
* @param {String} options.username Username for the Particle account
* @param {String} options.password Password for the Particle account
* @param {Number} options.tokenDuration How long the access token should last in seconds
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Number} [options.context] Request context
* @returns {Promise} A promise
*/
// @ts-ignore
login({ username, password, tokenDuration = this.tokenDuration, headers, context }){
return this.request({
uri: '/oauth/token',
method: 'post',
headers,
form: {
username,
password,
grant_type: 'password',
// @ts-ignore
client_id: this.clientId,
// @ts-ignore
client_secret: this.clientSecret,
expires_in: tokenDuration
},
context
});
}
/**
* If login failed with an 'mfa_required' error, this must be called with a valid OTP code to login
* @param {Object} options Options for this API call
* @param {String} options.mfaToken Given as 'mfa_token' in the error body of `.login()`.
* @param {String} options.otp Current one-time-password generated from the authentication application
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Number} [options.context] Request context
* @returns {Promise} A promise
*/
sendOtp({ mfaToken, otp, headers, context }){
return this.request({
uri: '/oauth/token',
method: 'post',
headers,
form: {
grant_type: 'urn:custom:mfa-otp',
mfa_token: mfaToken,
otp,
// @ts-ignore
client_id: this.clientId,
// @ts-ignore
client_secret: this.clientSecret
},
context
});
}
/**
* Enable MFA on the currently logged in user
* @param {Object} options Options for this API call
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
enableMfa({ auth, headers, context }){
return this.get({ uri: '/v1/user/mfa-enable', auth, headers, context });
}
/**
* Confirm MFA for the user. This must be called with current TOTP code, determined from the results of enableMfa(). You will be prompted to enter an OTP code every time you login after enrollment is confirmed.
* @param {Object} options Options for this API call
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} options.mfaToken Token given from previous step to
* @param {Object} options.otp Current one-time-password generated from the authentication app
* @param {Boolean} options.invalidateTokens Should all tokens be invalidated
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
confirmMfa({ mfaToken, otp, invalidateTokens = false, auth, headers, context }){
let data = { mfa_token: mfaToken, otp };
if (invalidateTokens) {
data.invalidate_tokens = true;
}
return this.post({
uri: '/v1/user/mfa-enable',
auth,
headers,
data,
context
});
}
/**
* Disable MFA for the user.
* @param {Object} options Options for this API call
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} options.currentPassword User's current password
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
disableMfa({ currentPassword, auth, headers, context }){
return this.put({
uri: '/v1/user/mfa-disable',
auth,
headers,
data: { current_password: currentPassword },
context
});
}
/**
* Create Customer for Product.
* @param {Object} options Options for this API call
* @param {String} options.email Username for the Particle account
* @param {String} options.password Password for the Particle account
* @param {String} options.product Create the customer in this product ID or slug
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
createCustomer({ email, password, product, headers, context }){
return this.request({
uri: `/v1/products/${product}/customers`,
method: 'post',
headers,
form: {
email,
password,
grant_type: 'client_credentials',
// @ts-ignore
client_id: this.clientId,
// @ts-ignore
client_secret: this.clientSecret
},
context
});
}
/**
* Login to Particle Cloud using an OAuth client.
* @param {Object} options Options for this API call
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
loginAsClientOwner({ headers, context }){
return this.request({
uri: '/oauth/token',
method: 'post',
headers,
form: {
grant_type: 'client_credentials',
// @ts-ignore
client_id: this.clientId,
// @ts-ignore
client_secret: this.clientSecret
},
context
});
}
/**
* Create a user account for the Particle Cloud
* @param {Object} options Options for this API call
* @param {String} options.username Email of the new user
* @param {String} options.password Password
* @param {String} options.accountInfo Object that contains account information fields such as user real name, company name, business account flag etc
* @param {Object} [options.utm] Object that contains info about the campaign that lead to this user creation
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
createUser({ username, password, accountInfo, utm, headers, context }){
return this.post({
uri: '/v1/users',
headers,
data: {
username,
password,
account_info: accountInfo,
utm
},
context
});
}
/**
* Verify new user account via verification email
* @param {Object} options Options for this API call
* @param {String} options.token The string token sent in the verification email
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
verifyUser({ token, headers, context }){
return this.post({
uri: '/v1/user/verify',
headers,
data: { token },
context
});
}
/**
* Send reset password email for a Particle Cloud user account
* @param {Object} options Options for this API call
* @param {String} options.username Email of the user
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
resetPassword({ username, headers, context }){
return this.post({
uri: '/v1/user/password-reset',
headers,
data: { username },
context
});
}
/**
* Revoke an access token
* @param {Object} options Options for this API call
* @param {String} options.token Access token you wish to revoke
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
deleteAccessToken({ token, headers, context }){
return this.delete({
uri: `/v1/access_tokens/${token}`,
headers,
context
});
}
/**
* Revoke the current session access token
* @param {Object} options Options for this API call
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
deleteCurrentAccessToken({ auth, headers, context }){
return this.delete({
uri: '/v1/access_tokens/current',
auth,
headers,
context
});
}
/**
* Revoke all active access tokens
* @param {Object} options Options for this API call
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
deleteActiveAccessTokens({ auth, headers, context }){
return this.delete({
uri: '/v1/access_tokens',
auth,
headers,
context
});
}
/**
* Delete the current user
* @param {Object} options Options for this API call
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {String} options.password Password
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
deleteUser({ auth, password, headers, context }){
return this.delete({
uri: '/v1/user',
data: { password },
auth,
headers,
context
});
}
/**
* Retrieves the information that is used to identify the current login for tracking.
* @param {Object} [options] Options for this API call
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Boolean} [options.full] When true, retrieve all information for registering a user with the tracking API. When false,
* retrieve only the unique tracking ID for the current login.
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise<Object>} Resolve the tracking identify of the current login
*/
trackingIdentity({ full = false, auth, headers, context } = {}){
return this.get({
uri: '/v1/user/identify',
auth,
headers,
query: (full ? undefined : { tracking: 1 }),
context
});
}
/**
* List devices claimed to the account or product
* @param {Object} options Options for this API call
* @param {String} [options.deviceId] (Product only) Filter results to devices with this ID (partial matching)
* @param {String} [options.deviceName] (Product only) Filter results to devices with this name (partial matching)
* @param {Array.<string>} [options.groups] (Product only) A list of full group names to filter results to devices belonging to these groups only.
* @param {String} [options.sortAttr] (Product only) The attribute by which to sort results. See API docs for options.
* @param {String} [options.sortDir] (Product only) The direction of sorting. See API docs for options.
* @param {Number} [options.page] (Product only) Current page of results
* @param {Number} [options.perPage] (Product only) Records per page
* @param {String} [options.product] List devices in this product ID or slug
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
listDevices({ deviceId, deviceName, groups, sortAttr, sortDir, page, perPage, product, auth, headers, context }){
let uri, query;
if (product){
uri = `/v1/products/${product}/devices`;
query = {
deviceId,
deviceName,
groups: Array.isArray(groups) ? groups.join(',') : undefined,
sortAttr,
sortDir,
page,
per_page: perPage
};
} else {
uri = '/v1/devices';
}
return this.get({ uri, auth, headers, query, context });
}
/**
* Get detailed informationa about a device
* @param {Object} options Options for this API call
* @param {String} options.deviceId Device ID or Name
* @param {String} [options.product] Device in this product ID or slug
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
getDevice({ deviceId, product, auth, headers, context }){
const uri = this.deviceUri({ deviceId, product });
return this.get({ uri, auth, headers, context });
}
/**
* Claim a device to the account. The device must be online and unclaimed.
* @param {Object} options Options for this API call
* @param {String} options.deviceId Device ID
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {boolean} options.requestTransfer True to request the device be transfered from another user
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
claimDevice({ deviceId, requestTransfer, auth, headers, context }){
return this.post({
uri: '/v1/devices',
auth,
headers,
data: {
id: deviceId,
request_transfer: !!requestTransfer
},
context
});
}
/**
* Add a device to a product or move device out of quarantine.
* @param {Object} options Options for this API call
* @param {String} options.deviceId Device ID
* @param {Object} options.file A file that contains a single-column list of device IDs, device serial numbers, device IMEIs, or devie ICCIDs.
* Node: Either a path or Buffer. Browser: a File or Blob.
* @param {String} options.product Add to this product ID or slug
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
addDeviceToProduct({ deviceId, product, file, auth, headers, context }){
let files, data;
if (file){
files = { file };
} else if (deviceId){
data = { id: deviceId };
}
return this.request({
uri: `/v1/products/${product}/devices`,
method: 'post',
headers,
data,
files,
auth,
context
});
}
/**
* Unclaim / Remove a device from your account or product, or deny quarantine
* @param {Object} options Options for this API call
* @param {String} options.deviceId Device ID or Name
* @param {Boolean} [options.deny] (Product only) Deny this quarantined device, instead of removing an already approved device
* @param {String} options.product Remove from this product ID or slug
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
removeDevice({ deviceId, deny, product, auth, headers, context }){
const uri = this.deviceUri({ deviceId, product });
const data = product ? { deny } : undefined;
return this.delete({ uri, data, auth, headers, context });
}
/**
* Unclaim a product device its the owner, but keep it in the product
* @param {Object} options Options for this API call
* @param {String} options.deviceId Device ID or Name
* @param {String} options.product Remove from this product ID or slug
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
removeDeviceOwner({ deviceId, product, auth, headers, context }){
const uri = `/v1/products/${product}/devices/${deviceId}/owner`;
return this.delete({ uri, auth, headers, context });
}
/**
* Rename a device
* @param {Object} options Options for this API call
* @param {String} options.deviceId Device ID or Name
* @param {String} options.name Desired Name
* @param {String} [options.product] Rename device in this product ID or slug
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
renameDevice({ deviceId, name, product, auth, headers, context }){
return this.updateDevice({ deviceId, name, product, auth, headers, context });
}
/**
* Instruct the device to turn on/off the LED in a rainbow pattern
* @param {Object} options Options for this API call
* @param {String} options.deviceId Device ID or Name
* @param {Boolean} options.signal Signal on or off
* @param {String} [options.product] Device in this product ID or slug
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
signalDevice({ deviceId, signal, product, auth, headers, context }){
return this.updateDevice({ deviceId, signal, product, auth, headers, context });
}
/**
* Store some notes about device
* @param {Object} options Options for this API call
* @param {String} options.deviceId Device ID or Name
* @param {String} options.notes Your notes about this device
* @param {String} [options.product] Device in this product ID or slug
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
setDeviceNotes({ deviceId, notes, product, auth, headers, context }){
return this.updateDevice({ deviceId, notes, product, auth, headers, context });
}
/**
* Mark device as being used in development of a product so it opts out of automatic firmware updates
* @param {Object} options Options for this API call
* @param {String} options.deviceId Device ID or Name
* @param {Boolean} options.development Set to true to mark as development, false to return to product fleet
* @param {String} options.product Device in this product ID or slug
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
markAsDevelopmentDevice({ deviceId, development = true, product, auth, headers, context }){
return this.updateDevice({ deviceId, development, product, auth, headers, context });
}
/**
* Mark device as being used in development of a product, so it opts out of automatic firmware updates
* @param {Object} options Options for this API call
* @param {String} options.deviceId Device ID or Name
* @param {Number} options.desiredFirmwareVersion Lock the product device to run this firmware version.
* @param {Boolean} [options.flash] Immediately flash firmware indicated by desiredFirmwareVersion
* @param {String} options.product Device in this product ID or slug
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
lockDeviceProductFirmware({ deviceId, desiredFirmwareVersion, flash, product, auth, headers, context }){
return this.updateDevice({ deviceId, desiredFirmwareVersion, flash, product, auth, headers, context });
}
/**
* Mark device as receiving automatic firmware updates
* @param {Object} options Options for this API call
* @param {String} options.deviceId Device ID or Name
* @param {String} options.product Device in this product ID or slug
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
unlockDeviceProductFirmware({ deviceId, product, auth, headers, context }){
return this.updateDevice({ deviceId, desiredFirmwareVersion: null, product, auth, headers, context });
}
/**
* Update multiple device attributes at the same time
* @param {Object} options Options for this API call
* @param {String} options.deviceId Device ID or Name
* @param {String} [options.name] Desired Name
* @param {Boolean} [options.signal] Signal device on or off
* @param {String} [options.notes] Your notes about this device
* @param {Boolean} [options.development] (Product only) Set to true to mark as development, false to return to product fleet
* @param {Number | null} [options.desiredFirmwareVersion] (Product only) Lock the product device to run this firmware version.
* Pass `null` to unlock firmware and go back to released firmware.
* @param {Boolean} [options.flash] (Product only) Immediately flash firmware indicated by desiredFirmwareVersion
* @param {String} [options.product] Device in this product ID or slug
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
updateDevice({ deviceId, name, signal, notes, development, desiredFirmwareVersion, flash, product, auth, headers, context }){
let signalValue;
if (signal !== undefined){
signalValue = signal ? '1' : '0';
}
const uri = this.deviceUri({ deviceId, product });
const data = product ?
{ name, signal: signalValue, notes, development, desired_firmware_version: desiredFirmwareVersion, flash } :
{ name, signal: signalValue, notes };
return this.put({ uri, auth, headers, data, context });
}
/**
* Disable device protection.
*
* @param {Object} options Options for this API call.
* @param {String} options.deviceId Device ID or name.
* @param {String} options.action Request action: `prepare` or `confirm`.
* @param {String} [options.org] Organziation ID or slug.
* @param {String} [options.product] Product ID or slug.
* @param {String} [options.serverNonce] Base64-encoded server nonce. Mandatory if `action` is `confirm`,
* @param {String} [options.deviceNonce] Base64-encoded device nonce. Mandatory if `action` is `confirm`,
* @param {String} [options.deviceSignature] Base64-encoded device signature. Mandatory if `action` is `confirm`,
* @param {String} [options.devicePublicKeyFingerprint] Base64-encoded fingerprint of the device public key.
* Mandatory if `action` is `confirm`,
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor.
* @param {Object} [options.headers] Key/value pairs to send as headers.
* @param {Object} [options.context] Request context.
* @returns {Promise} A promise
*/
unprotectDevice({ deviceId, org, product, action, serverNonce, deviceNonce, deviceSignature, devicePublicKeyFingerprint, auth, headers, context }) {
const data = { action };
if (deviceNonce !== undefined) {
data.device_nonce = deviceNonce;
}
if (serverNonce !== undefined) {
data.server_nonce = serverNonce;
}
if (deviceSignature !== undefined) {
data.device_signature = deviceSignature;
}
if (devicePublicKeyFingerprint !== undefined) {
data.device_public_key_fingerprint = devicePublicKeyFingerprint;
}
const uri = this.deviceUri({ deviceId, product, org }) + '/unprotect';
return this.put({ uri, data, auth, headers, context });
}
/**
* Provision a new device for products that allow self-provisioning
* @param {Object} options Options for this API call
* @param {String} options.productId Product ID where to create this device
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
provisionDevice({ productId, auth, headers, context }){
return this.post({
uri: '/v1/devices',
auth,
headers,
data: { product_id: productId },
context
});
}
/**
* Generate a claim code to use in the device claiming process.
* To generate a claim code for a product, the access token MUST belong to a
* customer of the product.
* @param {Object} options Options for this API call
* @param {String} [options.iccid] ICCID of the SIM card used in the Electron
* @param {String} [options.product] Device in this product ID or slug
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
getClaimCode({ iccid, product, auth, headers, context }){
const uri = product ? `/v1/products/${product}/device_claims` : '/v1/device_claims';
return this.post({ uri, auth, headers, data: { iccid }, context });
}
validatePromoCode({ promoCode, auth, headers, context }){
return this.get({
uri: `/v1/promo_code/${promoCode}`,
auth,
headers,
context
});
}
/**
* Get the value of a device variable
* @param {Object} options Options for this API call
* @param {String} options.deviceId Device ID or Name
* @param {String} options.name Variable name
* @param {String} [options.product] Device in this product ID or slug
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
getVariable({ deviceId, name, product, auth, headers, context }){
const uri = product ?
`/v1/products/${product}/devices/${deviceId}/${name}` :
`/v1/devices/${deviceId}/${name}`;
return this.get({ uri, auth, headers, context });
}
/**
* Compile and flash application firmware to a device. Pass a pre-compiled binary to flash it directly to the device.
* @param {Object} options Options for this API call
* @param {String} options.deviceId Device ID or Name
* @param {String} options.product Flash device in this product ID or slug
* @param {Object} options.files Object containing files to be compiled and flashed. Keys should be the filenames, including relative path, and the values should be a path or Buffer of the file contents in Node, or a File or Blob in the browser.
* @param {String} [options.targetVersion=latest] System firmware version to compile against
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
flashDevice({ deviceId, product, files, targetVersion, auth, headers, context }){
const uri = this.deviceUri({ deviceId, product });
const form = {};
if (targetVersion){
form.build_target_version = targetVersion;
} else {
form.latest = 'true';
}
return this.request({ uri, method: 'put', auth, headers, files, form, context });
}
/**
* DEPRECATED: Flash the Tinker application to a device. Instead compile and flash the Tinker source code.
* @param {Object} options Options for this API call
* @param {String} options.deviceId Device ID or Name
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
flashTinker({ deviceId, auth, headers, context }){
/* eslint-disable no-console */
/* @ts-ignore */
if (console && console.warning){
// @ts-ignore
console.warning('Particle.flashTinker is deprecated');
}
/* eslint-enable no-console */
return this.put({
uri: `/v1/devices/${deviceId}`,
headers,
data: { app: 'tinker' },
auth,
context
});
}
/**
* Compile firmware using the Particle Cloud
* @param {Object} options Options for this API call
* @param {Object} options.files Object containing files to be compiled. Keys should be the filenames, including relative path, and the values should be a path or Buffer of the file contents in Node, or a File or Blob in the browser.
* @param {Number} [options.platformId] Platform id number of the device you are compiling for. Common values are 0=Core, 6=Photon, 10=Electron.
* @param {String} [options.targetVersion=latest] System firmware version to compile against
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
compileCode({ files, platformId, targetVersion, auth, headers, context }){
const form = { platform_id: platformId };
if (targetVersion){
form.build_target_version = targetVersion;
} else {
form.latest = 'true';
}
return this.request({
uri: '/v1/binaries',
method: 'post',
auth,
headers,
files,
form,
context
});
}
/**
* Download a firmware binary
* @param {Object} options Options for this API call
* @param {String} options.binaryId Binary ID received from a successful compile call
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise<RequestResponse, RequestError>} A promise
*/
downloadFirmwareBinary({ binaryId, auth, headers, context }){
return this.request({
uri: `/v1/binaries/${binaryId}`,
method: 'get',
auth,
headers,
context,
isBuffer: true
});
}
/**
* Send a new device public key to the Particle Cloud
* @param {Object} options Options for this API call
* @param {String} options.deviceId Device ID or Name
* @param {String | Buffer} options.key Public key contents
* @param {String} [options.algorithm=rsa] Algorithm used to generate the public key. Valid values are `rsa` or `ecc`.
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
sendPublicKey({ deviceId, key, algorithm, auth, headers, context }){
return this.post({
uri: `/v1/provisioning/${deviceId}`,
auth,
headers,
data: {
deviceID: deviceId,
publicKey: ( typeof key === 'string' ? key : key.toString() ),
filename: 'particle-api',
order: `manual_${ Date.now() }`,
algorithm: algorithm || 'rsa'
},
context
});
}
/**
* Call a device function
* @param {Object} options Options for this API call
* @param {String} options.deviceId Device ID or Name
* @param {String} options.name Function name
* @param {String} options.argument Function argument
* @param {String} [options.product] Device in this product ID or slug
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
callFunction({ deviceId, name, argument, product, auth, headers, context }){
const uri = product ?
`/v1/products/${product}/devices/${deviceId}/${name}` :
`/v1/devices/${deviceId}/${name}`;
return this.post({ uri, auth, headers, data: { args: argument }, context });
}
/**
* Get a stream of events
* @param {Object} options Options for this API call
* @param {String} [options.deviceId] Device ID or Name, or `mine` to indicate only your devices.
* @param {String} [options.name] Event Name
* @param {String} [options.org] Organization Slug
* @param {String} [options.product] Events for this product ID or slug
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @returns {Promise} If the promise resolves, the resolution value will be an EventStream object that will
* emit 'event' events.
*/
getEventStream({ deviceId, name, org, product, auth }){
let uri = '/v1/';
if (org){
uri += `orgs/${org}/`;
}
if (product){
uri += `products/${product}/`;
}
if (deviceId){
uri += 'devices/';
if (!(deviceId.toLowerCase() === 'mine')){
uri += `${deviceId}/`;
}
}
uri += 'events';
if (name){
uri += `/${encodeURIComponent(name)}`;
}
auth = this._getActiveAuthToken(auth);
return new EventStream(`${this.baseUrl}${uri}`, auth).connect();
}
/**
* Publish a event to the Particle Cloud
* @param {Object} options Options for this API call
* @param {String} options.name Event name
* @param {String} options.data Event data
* @param {Boolean} options.isPrivate Should the event be publicly available?
* @param {String} [options.product] Event for this product ID or slug
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
publishEvent({ name, data, isPrivate, product, auth, headers, context }){
const uri = product ? `/v1/products/${product}/events` : '/v1/devices/events';
const postData = { name, data, private: isPrivate };
return this.post({ uri, auth, headers, data: postData, context });
}
/**
* @typedef {Object} Hook
* @property {String} [method=POST] Type of web request triggered by the Webhook (GET, POST, PUT, or DELETE)
* @property {Object} [auth] Auth data like `{ user: 'me', pass: '1234' }` for basic auth or `{ bearer: 'token' }` to send with the Webhook request
* @property {Object} [headers] Additional headers to add to the Webhook like `{ 'X-ONE': '1', X-TWO: '2' }`
* @property {Object} [query] Query params to add to the Webhook request like `{ foo: 'foo', bar: 'bar' }`
* @property {Object} [json] JSON data to send with the Webhook request - sets `Content-Type` to `application/json`
* @property {Object} [form] Form data to send with the Webhook request - sets `Content-Type` to `application/x-www-form-urlencoded`
* @property {String} [body] Custom body to send with the Webhook request
* @property {Object} [responseTemplate] Template to use to customize the Webhook response body
* @property {Object} [responseEvent] The Webhook response event name that your devices can subscribe to
* @property {Object} [errorResponseEvent] The Webhook error response event name that your devices can subscribe to
*/
/**
* Create a webhook
* @param {Object} options Options for this API call
* @param {String} options.event The name of the Particle event that should trigger the Webhook
* @param {String} options.url The web address that will be targeted when the Webhook is triggered
* @param {String} [options.device] Trigger Webhook only for this device ID or Name
* @param {Boolean} [options.rejectUnauthorized] Set to `false` to skip SSL certificate validation of the target URL
* @param {Boolean} [options.noDefaults] Don't include default event data in the webhook request
* @param {Hook} [options.hook] Webhook configuration settings
* @param {String} [options.product] Webhook for this product ID or slug
* @param {string} [options.auth] The access token. Can be ignored if provided in constructor
* @param {Object} [options.headers] Key/Value pairs like `{ 'X-FOO': 'foo', X-BAR: 'bar' }` to send as headers.
* @param {Object} [options.context] Request context
* @returns {Promise} A promise
*/
createWebhook({ event, url, device, rejectUnauthorized, noDefaults, hook, product, auth, headers, context }){
const uri = product ? `/v1/products/${product}/webhooks` : '/v1/webhooks';
const data = { event, url, deviceId: device, rejectUnauthorized, noDefaults };
if (hook){
data.requestType = hook.method;
data.auth = hook.auth;
data.headers = hook.headers;
data.query = hook.query;
data.json = hook.json;
data.form = hook.form;
data.body = hook.body;
data.responseTemplate = hook.responseTemplate;
data.responseTopic = hook.responseEvent;
data.errorResponseTopic = hook.errorResponseEvent;
}
if (!data.requestType){
data.requestType = 'POST';
}
return this.post({ uri, auth, headers, data, context });
}
/**
* Delete a webhook
* @param {Object} options Options for this API call