1 | # Raptor javascript SDK
|
2 |
|
3 | ![Build status](https://travis-ci.org/raptorbox/raptorjs.svg) ![npm release](https://badge.fury.io/js/raptor-sdk.svg) [![Conventional Commits](https://img.shields.io/badge/Conventional%20Commits-1.0.0-yellow.svg)](https://conventionalcommits.org)
|
4 |
|
5 |
|
6 | Raptor IoT platform javascript SDK
|
7 |
|
8 | # Topics
|
9 |
|
10 | - [Introduction](#introduction)
|
11 | - [Installation](#installation)
|
12 |
|
13 | - [Node.js](#nodejs)
|
14 | - [Browser](#browser)
|
15 |
|
16 | - [Library configuration](#library-configuration)
|
17 |
|
18 | - [Example usage](#example-usage)
|
19 |
|
20 | - [List all devices](#list-all-devices)
|
21 | - [Search for devices](#search-for-devices)
|
22 | - [Create a device](#create-a-device)
|
23 | - [Load a device definition](#load-a-device-definition)
|
24 | - [Sending data update](#sending-data-update)
|
25 | - [Load a device by ID](#loading-a-device-by-id)
|
26 | - [Retrieving data](#retrieving-data)
|
27 | - [Search for data](#search-for-data)
|
28 |
|
29 | - [Numeric range](#numeric-range)
|
30 | - [Time range](#time-range)
|
31 | - [Match](#match)
|
32 | - [Bounding box](#bounding-box)
|
33 | - [Distance](#distance)
|
34 | - [Combining searches](#combining-searches)
|
35 |
|
36 | - [Getting realtime updates](#getting-realtime-updates)
|
37 |
|
38 | - [Connecting to the broker](#connecting-to-the-broker)
|
39 | - [Listening for updates to a stream](#listening-for-updates-to-a-stream)
|
40 | - [Listening for all the updates](#listening-for-all-the-updates)
|
41 |
|
42 | - [Actuations](#actuations)
|
43 |
|
44 | - [Invoking an actuation](#invoking-an-actuation)
|
45 | - [Listening for actuations](#listening-for-actuations)
|
46 |
|
47 | - [Additional notes](#additional-notes)
|
48 |
|
49 | - [Tests](#tests)
|
50 |
|
51 | - [Contributing](#contributing)
|
52 |
|
53 | - [Docs](#docs)
|
54 |
|
55 | - [License](#license)
|
56 | - [Changelog](#Changelog)
|
57 |
|
58 | --------------------------------------------------------------------------------
|
59 |
|
60 | # Introduction
|
61 |
|
62 | Raptor.js exposes the feature from the [Raptor](http://github.com/raptorbox/raptor) platform as a convenient javascript API.
|
63 |
|
64 | This branch is pair with the Raptor API `v4.x`
|
65 |
|
66 | # Installation
|
67 |
|
68 | ## Node.js
|
69 |
|
70 | Install the module from the git repository
|
71 |
|
72 | ```sh
|
73 | npm i raptorbox/raptorjs
|
74 | ```
|
75 |
|
76 |
|
77 | and then import it in your code
|
78 |
|
79 | ```javascript
|
80 | const Raptor = require('raptor')
|
81 | ```
|
82 |
|
83 | ## Browser
|
84 |
|
85 | To generate a build use `webpack` inside the repository directory. A generated build is made available under [dist](./dist/) for stable releases.
|
86 |
|
87 | # Library configuration
|
88 |
|
89 | The minimum configuration required is the token to access the API.
|
90 |
|
91 | ```javascript
|
92 | const raptor = new Raptor('your api key 1');
|
93 | ```
|
94 |
|
95 | Login with user and password (will fetch a session apiKey automatically). An additional `url` can be provided to use a personalized endpoint
|
96 |
|
97 | ```javascript
|
98 | const raptor = new Raptor({
|
99 | username: "admin",
|
100 | password: "admin",
|
101 | url: "http://raptor.local",
|
102 | });
|
103 | ```
|
104 |
|
105 | # Example usage
|
106 |
|
107 | ## List all devices
|
108 |
|
109 | ```javascript
|
110 | raptor.Inventory().list()
|
111 | .then((pager) => console.info("List loaded, %s elements", pager.getTotalElements()))
|
112 | .catch((e) => console.warn("An error occured! %j", e))
|
113 | ```
|
114 |
|
115 | Delete an device with
|
116 |
|
117 | ```javascript
|
118 | raptor.Inventory().delete(deviceId)
|
119 | ```
|
120 |
|
121 | Delete all the devices instances with
|
122 |
|
123 | ```javascript
|
124 | raptor.Inventory().list()
|
125 | .then((pager) => {
|
126 | pager.getContent().each((d) => raptor.Inventory().delete(d))
|
127 | console.log("All clear")
|
128 | })
|
129 | ```
|
130 |
|
131 | ## Search for devices
|
132 |
|
133 | To perform a search at least one option is required, multiple option will be AND-ed together
|
134 |
|
135 | - Field `id`, `name`, `description` supports text-based queries, with those optional params
|
136 | ```javascript
|
137 | {
|
138 | // one of those values
|
139 | in: [ "value1", "value2" ],
|
140 | // contains string
|
141 | contains: "some string",
|
142 | // exactly match the string
|
143 | match: "exact match"
|
144 | }
|
145 | ```
|
146 |
|
147 | - Field `properties` supports object-based queries, with those optional params
|
148 | ```javascript
|
149 | {
|
150 | // has a key
|
151 | containsKey: "my_key",
|
152 | // has a value
|
153 | containsValue: 1001,
|
154 | // contains those key-values
|
155 | has: {
|
156 | field1: true,
|
157 | field2: 1001
|
158 | }
|
159 | }
|
160 | ```
|
161 |
|
162 | ```javascript
|
163 | var params = {
|
164 | // short format for contains
|
165 | id: "1111-3333-4444-5555",
|
166 | name: {
|
167 | in: ["My device", "quadcopter_1"]
|
168 | }
|
169 | description: {
|
170 | contains: "example"
|
171 | },
|
172 | // short format for has: {...}
|
173 | properties: {
|
174 | model: "a4b2788"
|
175 | }
|
176 | }
|
177 |
|
178 | // paging support
|
179 | var limit = 1000, // get 1000 results
|
180 | offset = 10; // starting from record 10
|
181 |
|
182 | raptor.Inventory().search(params, limit, offset)
|
183 | .then((list) => console.log("Found %s", list.size()))
|
184 | ```
|
185 |
|
186 | ## Create a device
|
187 |
|
188 | ```javascript
|
189 | var definition = {
|
190 | "name": "Robot",
|
191 | "description": "My device",
|
192 | "streams": {
|
193 | "sensing": {
|
194 | "light": "number",
|
195 | "alarm": "boolean"
|
196 | "message": "string"
|
197 | }
|
198 | },
|
199 | "actions": [ "take-photo", "beep" ],
|
200 | "properties": {
|
201 | "model": 'robot-001',
|
202 | "colors": ['red', 'blue']
|
203 | }
|
204 | }
|
205 | ```
|
206 |
|
207 | Create the device in Raptor
|
208 |
|
209 | ```javascript
|
210 | raptor.Inventory().create(definition)
|
211 | .then((device) => {
|
212 | // device is the new device create
|
213 | console.info("Drone device created, id" + device.id);
|
214 | console.info(device.toJSON());
|
215 | // see below how to use the device to send and receive data
|
216 | })
|
217 | .catch((e) => {
|
218 | console.warn("An error occured!");
|
219 | return Promise.reject(e);
|
220 | });
|
221 | ```
|
222 |
|
223 | ## Sending data update
|
224 |
|
225 | First you have to select the stream you want to use, `sensing` in our case, and send the data with the `push` method.
|
226 |
|
227 | ```javascript
|
228 |
|
229 | const record = device.getStream('sensing').createRecord({
|
230 | light: 90,
|
231 | alarm: true,
|
232 | message: "good morning",
|
233 | })
|
234 |
|
235 | raptor.Stream().push(record)
|
236 |
|
237 | ```
|
238 |
|
239 | To store a searchable location in the stream use the special `location` field. The `timestamp` field allow to specify the date/time of the record
|
240 |
|
241 | ```javascript
|
242 |
|
243 | const record = device.getStream('sensing').createRecord({
|
244 | timestamp: 2037304801,
|
245 | location: {
|
246 | latitude: 11.234,
|
247 | longitude: 45.432
|
248 | }
|
249 | channels: {
|
250 | light: 42,
|
251 | alarm: false,
|
252 | message: "ok",
|
253 | }
|
254 | })
|
255 |
|
256 | raptor.Stream().push(record)
|
257 |
|
258 | ```
|
259 |
|
260 | ## Loading a device by ID
|
261 |
|
262 | Let's load an instance of a Drone from it's definition
|
263 |
|
264 | ```javascript
|
265 |
|
266 | let deviceId = "the device id";
|
267 |
|
268 | raptor.Inventory().read(deviceId)
|
269 | .then((device) => console.info("Device loaded, id %s: \n%s",
|
270 | device.id,
|
271 | device.toJSON()
|
272 | ))
|
273 |
|
274 | ```
|
275 |
|
276 | ## Retrieving data from a device
|
277 |
|
278 | The returned value is an array of records from the device
|
279 |
|
280 | ```javascript
|
281 |
|
282 | // paging support
|
283 | var offset = 0,
|
284 | limit = 500
|
285 |
|
286 | raptor.Stream().pull(device.getStrem("sensing"), offset, limit)
|
287 | .then((result) => console.log("Data size %s == %s", result.length, limit));
|
288 | ```
|
289 |
|
290 | ## Search for data in a Stream
|
291 |
|
292 | Methods to search for data in a stream
|
293 |
|
294 | Available search types are
|
295 |
|
296 | - [Numeric range](#numeric-range)
|
297 | - [Time range](#time-range)
|
298 | - [Match](#match)
|
299 | - [Bounding box](#bounding-box)
|
300 | - [Distance](#distance)
|
301 |
|
302 | ### Numeric Range
|
303 |
|
304 | Search for data in a stream matching a numeric range constrain
|
305 |
|
306 | ```javascript
|
307 | raptor.Stream().search(device.getStream('sensing'), {
|
308 | channels: {
|
309 | // search for light threshold between 30, 100
|
310 | light: [30, 100]
|
311 | }
|
312 | })
|
313 | ```
|
314 |
|
315 | ### Time Range
|
316 |
|
317 | Search for data in a time range, creation date (`lastUpdate`) value will be used to match the search
|
318 |
|
319 | ```javascript
|
320 |
|
321 | const to = Math.floor((new Date).getTime() / 1000), // now, in UNIX seconds
|
322 | from = to - (60*60*24), // -1 day
|
323 |
|
324 | raptor.Stream().search(device.getStream('sensing'), {
|
325 | timestamp: {
|
326 | between: [ from, to ]
|
327 | }
|
328 | })
|
329 | ```
|
330 |
|
331 | ### Match
|
332 |
|
333 | Search for a matching value in a provided channel
|
334 |
|
335 | ```javascript
|
336 | raptor.Stream().search(device.getStream('sensing'), {
|
337 | channels: {
|
338 | message: {
|
339 | match: "warning"
|
340 | }
|
341 | }
|
342 | })
|
343 | ```
|
344 |
|
345 | ### Bounding box
|
346 |
|
347 | Search by a delimiting [bounding box](http://en.wikipedia.org/wiki/Minimum_bounding_box)
|
348 |
|
349 | This search type will look to match a channel named `location` with a geojson value. [See API docs](http://docs.servioticypublic.apiary.io/#dataqueries)
|
350 |
|
351 | ```javascript
|
352 | raptor.Stream().search(device.getStream('sensing'), {
|
353 | location: {
|
354 | boundingBox: {
|
355 | northWest: {
|
356 | latitude: 11.123
|
357 | longitude: 45.321
|
358 | },
|
359 | southWest: {
|
360 | latitude: 12.123
|
361 | longitude: 46.321
|
362 | }
|
363 | }
|
364 | }
|
365 | })
|
366 | ```
|
367 |
|
368 | ### Distance
|
369 |
|
370 | Search data by distance
|
371 |
|
372 | ```javascript
|
373 | raptor.Stream().search(device.getStream('sensing'), {
|
374 | location: {
|
375 | distance: {
|
376 | center: {
|
377 | latitude: 11.123,
|
378 | longitude: 45.321
|
379 | },
|
380 | radius: 100,
|
381 | unit: "km"
|
382 | }
|
383 | }
|
384 | })
|
385 | ```
|
386 |
|
387 | ### Combining searches
|
388 |
|
389 | To combine multiple filters
|
390 |
|
391 | _Notice_ that `distance` is incompatible with `bbox`, if both provided `bbox` will be used
|
392 |
|
393 | ```javascript
|
394 | raptor.Stream().search(device.getStream('sensing'), {
|
395 | location: {
|
396 | distance: {
|
397 | center: {
|
398 | latitude: 11.123,
|
399 | longitude: 45.321
|
400 | },
|
401 | radius: 100,
|
402 | unit: "km"
|
403 | }
|
404 | }
|
405 | channels: {
|
406 | // search for light threshold between 30, 100
|
407 | light: [30, 100],
|
408 | // and with alarm to true
|
409 | alarm: true,
|
410 | // and message matching "warning"
|
411 | message: {
|
412 | match: "warning"
|
413 | }
|
414 | }
|
415 | })
|
416 | ```
|
417 |
|
418 | # Getting realtime updates
|
419 |
|
420 | Updates are delivered over MQTT subscriptions
|
421 |
|
422 | ## Connecting to the broker
|
423 |
|
424 | Connection can be done by providing the `username` and `password` or with an empty `username` and a valid apiKey as the `password`.
|
425 |
|
426 | Those configuration are automatically taken from the configuration object provided by the library
|
427 |
|
428 | ## Listening for updates to a stream
|
429 |
|
430 | Get realtime updates from data streams
|
431 |
|
432 | ```javascript
|
433 | device.Stream().subscribe(device.getStream("sensing"), (data) => {
|
434 | console.log("Stream updated!");
|
435 | console.log(data);
|
436 | })
|
437 | ```
|
438 |
|
439 | To stop listening
|
440 |
|
441 | ```javascript
|
442 | device.Stream().unsubscribe(device.getStream("sensing"))
|
443 | ```
|
444 |
|
445 | ## Listening for events
|
446 |
|
447 | In some case could be useful to receive all the notifications available, to do so use listen to the `data` event on the device
|
448 |
|
449 | ```javascript
|
450 | device.Inventory().subscribe(device, (data) => {
|
451 | console.log("Stream updated!");
|
452 | console.log(data);
|
453 | })
|
454 | ```
|
455 |
|
456 | Unregister from events subscription with
|
457 |
|
458 | ```javascript
|
459 | device.Inventory().unubscribe(device)
|
460 | ```
|
461 |
|
462 | # Actions
|
463 |
|
464 | Actions allow to invoke virtual operations on an device.
|
465 |
|
466 | ## Invoking an actuation
|
467 |
|
468 | To invoke an actuation use the `invoke` method and provide additional parameters as argument
|
469 |
|
470 | Note that the argument passed to `invoke` **must** be a string, so to send JSON take care of serializing it accordingly
|
471 |
|
472 | ```javascript
|
473 | var status = JSON.stringify({ exposure: 'high', blur: 0.2 }); // must be a string!
|
474 | raptor.Action().invoke(device.getAction('take-photo'), status)
|
475 | ```
|
476 |
|
477 | ## Listening for actions
|
478 |
|
479 | On the device side you can listen for specific actions and implement actuations on their arrival.
|
480 |
|
481 | ```javascript
|
482 | raptor.Action().subscribe(device.getAction("take-photo"), (id, raw) => {
|
483 | // parse content
|
484 | var params = JSON.parse(raw)
|
485 | console.log("[id: %s] Take a photo with exposure: %j and blur: %s", id, params.exposure, params.blur);
|
486 | // camera.takePhoto(params)
|
487 | })
|
488 | ```
|
489 |
|
490 | # Contributing
|
491 |
|
492 | Feel free to open an issue or contact us to discuss the library status and future development.
|
493 |
|
494 | ## Adding a release
|
495 |
|
496 | Currently we use `standard-version` to tag version
|
497 |
|
498 | - `npm run release` for a minor relase
|
499 | - `npm run release-major` for a major relase
|
500 |
|
501 | # Docs
|
502 |
|
503 | API docs can be generated using `jsdoc`
|
504 |
|
505 | `./node_modules/jsdoc/jsdoc.js ./ -c ./jsdoc.json -l -r`
|
506 |
|
507 | # License
|
508 |
|
509 | Apache2
|
510 |
|
511 | ```
|
512 | Copyright FBK/CREATE-NET
|
513 |
|
514 | Licensed under the Apache License, Version 2.0 (the "License");
|
515 | you may not use this file except in compliance with the License.
|
516 | You may obtain a copy of the License at
|
517 |
|
518 | http://www.apache.org/licenses/LICENSE-2.0
|
519 |
|
520 | Unless required by applicable law or agreed to in writing, software
|
521 | distributed under the License is distributed on an "AS IS" BASIS,
|
522 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
523 | See the License for the specific language governing permissions and
|
524 | limitations under the License.
|
525 | ```
|