Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/lwmqn/smartobject

A Smart Object Class that helps you with creating IPSO Smart Objects in your JavaScript applications.
https://github.com/lwmqn/smartobject

ipso ipso-objects ipso-smart smartobject

Last synced: 5 days ago
JSON representation

A Smart Object Class that helps you with creating IPSO Smart Objects in your JavaScript applications.

Awesome Lists containing this project

README

        

# smartobject
A Smart Object Class that helps you with creating IPSO Smart Objects in your JavaScript applications

[![NPM](https://nodei.co/npm/smartobject.png?downloads=true)](https://nodei.co/npm/smartobject/)

[![Travis branch](https://img.shields.io/travis/lwmqn/smartobject/master.svg?maxAge=2592000)](https://travis-ci.org/lwmqn/smartobject)
[![npm](https://img.shields.io/npm/v/smartobject.svg?maxAge=2592000)](https://www.npmjs.com/package/smartobject)
[![npm](https://img.shields.io/npm/l/smartobject.svg?maxAge=2592000)](https://www.npmjs.com/package/smartobject) [![Greenkeeper badge](https://badges.greenkeeper.io/lwmqn/smartobject.svg)](https://greenkeeper.io/)
[![Coverage Status](https://coveralls.io/repos/github/lwmqn/smartobject/badge.svg?branch=master)](https://coveralls.io/github/lwmqn/smartobject?branch=master)

## Table of Contents

1. [Overview](#Overview)
2. [Installation](#Installation)
3. [Usage](#Usage)
4. [Resources Planning](#Resources)
5. [APIs](#APIs)
6. [Code Templates](https://github.com/lwmqn/smartobject/blob/master/docs/templates.md)


## 1. Overview

**smartobject** is a _Smart Object_ Class that helps you with creating [_IPSO_](http://www.ipso-alliance.org/) _Smart Objects_ in your JavaScript applications. If you like to use the IPSO data model in your projects or products, you can use **smartobject** as the base class to abstract your hardware, sensor modules, or gadgets into plugins (node.js packages) for users convenience. Here is [an example of hardware abstraction with mraa](https://github.com/lwmqn/smartobject/wiki/Hardware-Abstraction-with-mraa) on Linkit Smart 7688 in our wiki. In addition, this module is isomorphic and you can use it at server-side as well to generate the smart objects.

IPSO defines a hierarchical data model to describe real-world gadgets, such as temperature sensors and light controllers.
* IPSO uses _**Object**_ to tell what kind of a gadget is, and uses _**Object Instance**_ to tell which one a gadget is.
* An _**Object**_ is like a class or a boilerplate, and each kind of _Object_ has an unique _Object Id_ (`oid`) defined by IPSO, e.g., 3303 for the _Temperature Sensor Object_. Here is the [list of oids](https://github.com/simenkid/lwm2m-id#Identifiers).
* An _**Object Instance**_ is the entity of an _Object_. Each _**Object Instance**_ has an unique _**Object Instance Id**_ to identify itself from other gadgets of the same class. Simply speaking, `oid` is like a namespace to manage all the same kind of _IPSO Object Instances_.
* The _**Resources**_ are used to describe what attributes may a gadget have, for example, a temperature sensor may have attributes such as _sensorValue_, _unit_, _minMeaValue_, .etc. _**Resource Values**_ will be filled after instantiated. Here is the [list of templates](https://github.com/lwmqn/smartobject/blob/master/docs/templates.md) to show you what attributes may a gadget have.

![ISPO Model](https://raw.githubusercontent.com/lwmqn/documents/master/media/ipso_model.png)

[**Note**]
* The _italics_, such _Object_, _Object Id_, _Object Instance_, and _Object Instance Id_, are used to distinguish the _**IPSO Objects**_ from the JavaScript **objects**.


## 2. Installation

> $ npm install smartobject --save


## 3. Usage

Here is a quick example to show you how to create your _Smart Object_ with only few steps:

* **Step 1**: Import the SmartObject Class and create an instance from it
```js
var SmartObject = require('smartobject');
var so = new SmartObject(); // so can hold many Object Instances in it
```

* **Step 2**: Initialize a temperature sensor in your smart object `so` (ref: [code templates](https://github.com/lwmqn/smartobject/blob/master/docs/templates.md))
```js
so.init(
'temperature', // 'temperature' is the IPSO-defined Object Identifier (oid, 3303).
0, // 0 is the unique Object Instance Id (iid) assigned by you.
{ // This object contains all Resources (attributes) this sensor has.
sensorValue: 31, // 'sensorValue' is the IPSO-defined Resource Id (rid, 5700)
units : 'C' // 'units' is the IPSO-defined Resource Id (rid, 5701)
}
);
```
* **Step 3**: Initialize more _Object Instances_. Finally, we have 3 temperature sensors, 1 magnetometer, and 4 digital inputs in our `so`
```js
// Init more temperature sensors (each with an unique iid)
so.init('temperature', 1, {
sensorValue: 28,
units : 'C'
});

so.init('temperature', 2, {
sensorValue: 72.6,
units : 'F'
});

// Init other gadgets
so.init('magnetometer', 0, {
xValue: 18,
yValue: 21,
zValue: 231
});

so.init('dIn', 0, { dInState: 1 });
so.init('dIn', 1, { dInState: 0 });
so.init('dIn', 6, { dInState: 0 });
so.init('dIn', 7, {
// if dInState should be read from by certain operation
dInState: {
read: function (cb) {
var hal = this.parent.hal; // see SmartObject constructor
hal.digitalPin0.read(function (err, val) {
cb(null, val);
});
}
}
});
```


## 4. Resources Planning

The great benefit of using **smartobject** in your application is that you almost need not to tackle the allocation of _Resources_ by yourself. It provides a scheme to help you with management of reading/writing your hardware or executing a procedure on the machine. All you have to do is to plan and define your _Resources_ well, and then use **smartobject** methods to do your jobs. You can use **smartobject** to abstract your hardware, sensor modules, or gadgets into plugins (node.js packages).

Imagine that you have to read the temperature value from a sensor with one-wire interface:
* How to export this sensor to an IPSO smart object?
* How do you read the temperature value from your smart object?
* How do you do with the access control? Your _Resource_ is readable? writable? or remotely executable?

Please refer to [Resources Planning Tutorial](https://github.com/lwmqn/smartobject/blob/master/docs/resource_plan.md) for more details. It will show you how to initialize your _Resources_ and how to abstract your hardware with _IPSO Resources_ as well. In addition, here are some [code templates](https://github.com/lwmqn/smartobject/blob/master/docs/templates.md) for your convenience to create smart objects.


## 5. APIs

* [new SmartObject()](#API_smartobject)
* [init()](#API_init), [remove()](#API_remove)
* [objectList()](#API_objectList)
* [has()](#API_has), [get()](#API_get), [set()](#API_set)
* [read()](#API_read), [write()](#API_write), [exec()](#API_exec)
* [dump()](#API_dump), [dumpSync()](#API_dumpSync)
* [isReadable()](#API_isReadable), [isWritable()](#API_isWritable), [isExecutable()](#API_isExecutable)

[**Note**]
* In general, the most often used APIs are `new SmartObject()`, `init()`, `read()`, and `write()`. It's not that complicated as it looks like.

*************************************************
## SmartObject Class
Exposed by `require('smartobject')`.


### new SmartObject([hal][, setup])
Create an instance of SmartObject class. This document will use `so` to indicate this kind of instance.

A `so` can hold many _IPSO Object Instances_ in it. The `so` itself has an accessible but un-enumerable boolean property `'ipsoOnly'` to define if this `so` only accepts IPSO-defined `oid` and `rid`. Default value for `so.ipsoOnly` is `false`. You can set it to `true` in the `setup` function.

If `so.ipsoOnly == true`, then the given `oid` must be an IPSO-defined Object Id, `iid` must be a number, and all keys within `resrcs` object must be IPSO-defined Resource Ids, or `so.init()` will throw Errors.

**Arguments:**

1. `hal` (_Object_): Optional. A component or controller of the hardware abstraction layer. It will be assigned to `this.hal` at creation of a `so`. Noted that `so.hal` is accessible but un-enumerable.
2. `setup` (_Function_): Optional. A setup function allows you to do some initializing work, for example, setting gpio direction. In the setup function, `this` will be bound to the `so` itself, thus you can use `this.hal` to access your hardware.

**Returns:**

* (_Object_): **so**

**Examples:**

* A very simple case. There is no hardware with the smart object. For example, at server-side we only need the **data** of a smart object, thus we don't have the `hal`.

```js
var SmartObject = require('smartobject');

var so = new SmartObject();
```

* No hardware, and you like to make `so` accept only IPSO-defined identifiers.

```js
var SmartObject = require('smartobject');

var so = new SmartObject(function () {
this.ipsoOnly = true;
});
```

* We have 2 LEDs and 1 Switch controlled via `mraa`. This is a typical example at client-side (machine).

```js
var m = require('mraa');
var SmartObject = require('smartobject');

var myHardware = {
led1: new m.Gpio(44),
led2: new m.Gpio(44),
onOffSwitch: new m.Gpio(45),
foo: 'bar'
};

var so = new SmartObject(myHardware, function () {
var hal = this.hal;

// hardware initialization
hal.led1.dir(m.DIR_OUT);
hal.led2.dir(m.DIR_OUT);
hal.onOffSwitch.dir(m.DIR_IN);

hal.foo = 'initialized';
this.ipsoOnly = true;
});
```

*************************************************

### init(oid, iid, resrcs[, setup])
Create and initialize an _Object Instance_ in `so`, where `oid` is the [_IPSO Object Id_](https://github.com/simenkid/lwm2m-id#Identifiers) to indicate what kind of your gadget is, `iid` is the _Object Instance Id_, and `resrcs` is an object that wraps up all the _Resources_.

* Be careful, invoking `init()` against an existing _Object Instance_ will firstly wipe out all its _Resources_ and inner `_state` and then put the new _Resources_ into it. Thus, it is better to initialize your _Instance_ only once throughout your code.
* Property `_state` is a special _Resource_ that is an **accesible** but **un-enumerable** protected member in the _Object Instance_. It is an object where you can maintain some private information or inner state within the _Object Instance_. We will talk about it more later.

**Arguments:**

1. `oid` (_String_ | _Number_): _IPSO Object Id_, for example, `'temperature'` or `3303`. `so` will internally turn the id into its string version, say `'temperature'`, as the key if given with a numeric id.
2. `iid` (_String_ | _Number_): _Object Instance Id_. It would be nice to use numbers, i.e., `0`, `1`, `2` to strictly meet the IPSO definition. But strings are also accepted, e.g., `'sen01'`, `'sen02'`, `'sen03'`, it is just like a handle to help you distinguish different _Instances_ that share the same _Object_ class.
3. `resrcs` (_Object_): _IPSO Resources_, which is an object with **rid-value pairs** to describe the _Resources_. Each key in `resrcs` is a _Resource Id_ that can be a string or a number. And each value can be a primitive, an data object, or an object with specific methods, i.e. read(), write(), exec(). The [Resources Planning Tutorial](https://github.com/lwmqn/smartobject/blob/master/docs/resource_plan.md) will give you some hints. You can have your private information or inner states within an object assigned to the `resrc._state` property, for example `resrc = { _state: { foo: 'bar' } }`.
4. `setup` (_Function_): Optional. A setup function allows you to set some things up, for example, setting some flags or states for inner use. In this function, `this` will be bound to the _Object Instance_ itself, thus you can use `this._state` to access your inner state. Further more, you can use `this.parent` to get the `so` that owns this _Object Instance_, and use `this.parent.hal` to access your hardware.

**Returns:**

* (_Object_): `objInst`, the initialized _Object Instance_.

**Examples:**

* A very simple case. There is no hardware with the smart object.

```js
var so = new SmartObject();

so.init('temperature', 0, {
sensorValue: 31,
units : 'C'
});

so.init('temperature', 1, {
_state: { // inner state
foo: 'bar'
},
sensorValue: 75,
units : 'F'
});

so.init(3303, 18, {
sensorValue: 301,
units : 'K'
}, function () {
// this._state is an empty object by default
// you can attach things to it
this._state.foo = 'bar';
});

// Dumped data of the so will look like:
// (inner _state will not be dumped)
/*
{
temperature: {
'0': {
sensorValue: 31,
units : 'C'
},
'1': {
sensorValue: 75,
units : 'F'
},
'18': {
sensorValue: 301,
units : 'K'
}
}
}
*/
```

* We have 1 LED and 1 On/Off Switch controlled via `mraa`.

```js
var m = require('mraa');
var SmartObject = require('smartobject');

var so = new SmartObject({
led: new m.Gpio(44),
onOffSwitch: new m.Gpio(45)
}, function () {
var hal = this.hal;

// hardware initialization
hal.led.dir(m.DIR_OUT);
hal.onOffSwitch.dir(m.DIR_IN);

this.ipsoOnly = true;
});

// led
so.init('lightCtrl', 0 , {
_state: { // protected resource to maintain inner states
readCounts: 0, // to record times of read
writeCounts: 0 // to record times of written
},
onOff: {
read: function (cb) {
// 'this' is bound to Object Instance itself
// this.parent === so
var hal = this.parent.hal;
var ledState = hal.led.read();

this._state.readCounts += 1; // inner record
cb(null, ledState);
},
write: function (val, cb) {
var hal = this.parent.hal;
hal.led.write(val);

this._state.writeCounts += 1; // inner record
cb(null, hal.led.read());
}
}
});
```

*************************************************

### remove(oid, iid)
Remove an _Object Instance_ in `so`, where `oid` is the [_IPSO Object Id_](https://github.com/simenkid/lwm2m-id#Identifiers) to indicate what kind of your gadget is, `iid` is the _Object Instance Id_.

**Arguments:**

1. `oid` (_String_ | _Number_): _IPSO Object Id_, for example, `'temperature'` or `3303`. `so` will internally turn the id into its string version, say `'temperature'`, as the key if given with a numeric id.
2. `iid` (_String_ | _Number_): _Object Instance Id_. It would be nice to use numbers, i.e., `0`, `1`, `2` to strictly meet the IPSO definition. But strings are also accepted, e.g., `'sen01'`, `'sen02'`, `'sen03'`, it is just like a handle to help you distinguish different _Instances_ that share the same _Object_ class.

**Returns:**

* (_Boolean_): Returns `true` if remove successfully, else returns `false` if the _Object Instance_ does not exist.

**Examples:**

```js
so.remove('temperature', 0)
```

*************************************************

### objectList()
Returns the list of _Objects_ and _Object Instances_ with their identifiers. If an _Id_ is an IPSO-defined one, it will be returned as a number. If you're using LWM2M interface, you may need this method to generate the _Object List_ when registering to a server.

**Arguments:**

1. _none_

**Returns:**

* (_Array_): Returns an array that contains all the identifiers, each element is in the form of `{ oid: 3301, iid: [ 0, 1, 2, 3 ] }`.

**Examples:**

```js
var so = new SmartObject();

so.init('temperature', 0, {
sensorValue: 31,
units : 'C'
});

so.init('temperature', 18, {
sensorValue: 301,
units : 'K'
});

so.init('illuminance', 0, {
sensorValue: 128.6
});

so.initResrc('presence', 6, {
dInState: 0
});

so.initResrc('myGadget', 'gad72', {
myResource: 'hello_world'
});

so.objectList();
/*
[
{ oid: 3303, iid: [ 0, 18 ] },
{ oid: 3301, iid: [ 0 ] },
{ oid: 3302, iid: [ 6 ] },
{ oid: 'myGadget', iid: [ 'gad72' ] } // not IPSO-defined
]
*/
```

*************************************************

### has(oid[, iid[, rid]])
To see if `so` has the specified _Object_, _Object Instance_, or _Resource_.

**Arguments:**

1. `oid` (_String_ | _Number_): _Object Id_ of the target.
2. `iid` (_String_ | _Number_): _Object Instance Id_ of the target.
3. `rid` (_String_ | _Number_): _Resource Id_ of the target.

**Returns:**

* (_Boolean_): Returns `true` if target exists, otherwise `false`.

**Examples:**

```js
// Checks if so has the 'humidity' Object
so.has('humidity'); // true

// Checks if so has the 'foo' Object Instance with iid = 0
so.has('foo', 0); // false

// Checks if so has the 'sensorValue' Resource in temperature sensor 8
so.has('temperature', 8, 'sensorValue'); // true
```

*************************************************

### get(oid, iid, rid)
Synchronously get the specified _Resource_.

* At client-side (machine), the `get()` method is usually used to get the raw _Resource_ which may be an object with read/write/exec callbacks. If you like to read the **exact value** of a _Resource_, you should use the asynchronous `read()` method. Since reading something from somewhere may require some special and asynchronous operations, such as reading data from a wire, and reading from a database.
* At server-side (data center), the _Resource values_ are simple data pieces requested from machines. Thus, using `get()` to get the _stored value of a Resource on the server_ is no problem.

**Arguments:**

1. `oid` (_String_ | _Number_): _Object Id_ of the target.
2. `iid` (_String_ | _Number_): _Object Instance Id_ of the target.
3. `rid` (_String_ | _Number_): _Resource Id_ of the target.

**Returns:**

* (_Depends_): Returns the _Resource_ value, or `undefined` if _Resource_ does not exist.

**Examples:**

```js
so.get('temperature', 2, 'sensorValue'); // 26.4

// If the Resource is an object with read/write/exec method(s)
so.get('temperature', 1, 'sensorValue');
/*
{
read: function (cb) { ... }
}
*/

// If you do like to read the exact value from the temperature sensor, please use read()
so.read('temperature', 1, 'sensorValue', function (err, data) {
if (!err)
console.log(data); // 18.4
});

```

*************************************************

### set(oid, iid, rid, value)
Synchronously set a value to the specified _Resource_.

* At client-side (machine), the `set()` method is usually used to **initialize** a _Resource_, but not to write a value to a _Resource_. You should use the asynchronous `write()` method if you like to write a value to the _Resource_. Since writing something to somewhere may require some special and asynchronous operations, such as writing data to a wire, and writing data to a database.
* At server-side (data center), use `set()` to _store the value of a Resource on the server_ is no problem. For example, when your request of reading a _Resource_ from a remote machine has responded back, you can use `set()` to store that _Resource value_ on the server.

**Arguments:**

1. `oid` (_String_ | _Number_): _Object Id_ of the target.
2. `iid` (_String_ | _Number_): _Object Instance Id_ of the target.
3. `rid` (_String_ | _Number_): _Resource Id_ of the target.
4. `value` (_Primitives_ | _Object_): _Resource_ data or an object with read/write/exec method(s). This method will throw if `value` is given with a function.

**Returns:**

* (_Boolean_): Returns `true` if set successfully, else returns `false` if the _Object Instance_ does not exist (_Resource_ cannot be set).

**Examples:**

```js
so.set('dIn', 0, 'dInState', 1); // true
so.set('dOut', 1, 'dOutState', 0); // true

so.set('dOut', 2, 'dOutState', {
read: function (cb) {
gpioA3.read(function (state) { // assume gpioA3 is a handle to your hardware
cb(null, state);
});
}
}); // true

so.set('dOut', 2, 'dOutState', function (cb) {
gpioA3.read(function (state) {
cb(null, state);
});
}); // throw Error, value cannot be a function
```

*************************************************

### read(oid, iid, rid[, opt], callback)
Asynchronously read the specified _Resource_ value.

**Arguments:**

1. `oid` (_String_ | _Number_): _Object Id_ of the target.
2. `iid` (_String_ | _Number_): _Object Instance Id_ of the target.
3. `rid` (_String_ | _Number_): _Resource Id_ of the target.
4. `opt` (_Object_): An option used to read _Resources_ in restrict mode, default is `{ restrict: false }`. If it is given with `{ restrict: true }`, this method will follow the access control specification defined by IPSO. This option may be set to `true` to respond to a remote _read request_ (access from outside world should be under control).
5. `callback` (_Function_): `function (err, data) { ... }`. Will be called when reading is done or any error occurs, where `data` is the _Resource_ value. (When an error occurs, `so` will pass you a string like `'_notfound_'` with `data`, you can use it as a hint to choose a status code to respond back to the requester.)

* This table show you what results may the callback receive:

| err | data | Description |
|----------------|------------------|--------------------------------------------------------------------|
| Error object | `'_notfound_'` | _Resource_ not found. |
| Error object | `'_unreadable_'` | _Resource_ is unreadable. |
| Error object | `'_exec_'` | _Resource_ is unreadable (Because it is an executable _Resource_). |
| `null` | Depends | _Resource_ is successfully read. |

**Returns:**

* (_none_)

**Examples:**

```js
so.read('temperature', 1, 'sensorValue', function (err, data) {
if (!err)
console.log(data); // 18.4
});

so.read('actuation', 0, 'dimmer', function (err, data) {
if (!err)
console.log(data); // 62
});

so.read('illuminance', 1, 'maxMeaValue', function (err, data) {
if (err) {
console.log(err); // Error: 'Resource is unreadable.'
console.log(data); // '_unreadable_'
}
});

so.read('accelerometer', 2, 'minRangeValue', function (err, data) {
if (err) {
console.log(err); // Error: 'Resource not found.'
console.log(data); // '_notfound_'
}
});

so.read('barometer', 6, 'resetMinMaxMeaValues', function (err, data) {
if (err) {
console.log(err); // Error: 'Resource is unreadable.'
console.log(data); // '_exec_'
}
});
```

*************************************************

### write(oid, iid, rid, value[, opt], callback)
Asynchronously write a value to the specified _Resource_.

**Arguments:**

1. `oid` (_String_ | _Number_): _Object Id_ of the target.
2. `iid` (_String_ | _Number_): _Object Instance Id_ of the target.
3. `rid` (_String_ | _Number_): _Resource Id_ of the target.
4. `value` (_Depends_): The value to write to the specified _Resource_.
5. `opt` (_Object_): An option used to write _Resources_ in restrict mode. Default is `{ restrict: false }` if not given.
6. `callback` (_Function_): `function (err, data) { ... }`. Will be called when writing is done or any error occurs, where `data` is the _Resource_ value written. (When an error occurs, `so` will pass you a string like `'_notfound_'` with `data`, you can use it as a hint to choose a status code to respond back to the requester.)

* This table show you what results may the callback receive:

| err | data | Description |
|----------------|------------------|--------------------------------------------------------------------|
| Error object | `'_notfound_'` | _Resource_ not found. |
| Error object | `'_unwritable_'` | _Resource_ is unwritable. |
| Error object | `'_exec_'` | _Resource_ is unwritable (Because it is an executable _Resource_). |
| `null` | Depends | _Resource_ is successfully write. |

**Returns:**

* (_none_)

**Examples:**

```js
so.write('actuation', 0, 'onOff', 1, function (err, data) {
if (!err)
console.log(data); // 1
});

so.write('temperature', 1, 'sensorValue', 26, function (err, data) {
if (err) {
console.log(err); // Error: 'Resource is unwritable.'
console.log(data); // _unwritable_
}
});

so.write('presence', 3, 'busyToClearDelay', function (err, data) {
if (err) {
console.log(err); // Error: 'Resource not found.'
console.log(data); // '_notfound_'
}
});

so.write('barometer', 6, 'resetMinMaxMeaValues', function (err, data) {
if (err) {
console.log(err); // Error: 'Resource is unwritable.'
console.log(data); // '_exec_'
}
});
```

*************************************************

### exec(oid, iid, rid, args, callback)
Execute the specified _Resource_. The executable _Resource_ is a procedure you've defined, for example, blinking a led for _N_ times when the _Resource_ is invoked.

**Arguments:**

1. `oid` (_String_ | _Number_): _Object Id_ of the target.
2. `iid` (_String_ | _Number_): _Object Instance Id_ of the target.
3. `rid` (_String_ | _Number_): _Resource Id_ of the target.
4. `args` (_Array_): The parameters required by the procedure.
5. `callback` (_Function_): `function (err, data) { ... }`. Will be called when execution is performed or any error occurs, where `data` is anything your procedure like to return back. For example, when a blinking led procedure starts, you may like to return an object `{ status: 'ok', led: 6, times: 10 }` to the callback to tell something about this execution.

* This table show you what results may the callback receive:

| err | data | Description |
|----------------|--------------------|--------------------------------------------------------------------|
| Error object | `'_notfound_'` | _Resource_ not found. |
| Error object | `'_unexecutable_'` | _Resource_ is unexecutable. |
| Error object | `'_badarg_'` | Input arguments is not an array. |
| `null` | Depends | _Resource_ is successfully executed, `data` depends on your will. |

**Returns:**

* (_none_)

**Examples:**

```js
// Assume we have initialized an Object Instance like this:
so.init('foo_object', 0, {
foo: 60,
bar: 'hello',
blink: {
exec: function (args, cb) {
var ledPin = args[0],
times = args[1];

myHardwareController.blinkLed(ledPin, times, function (err) {
if (err)
cb(err);
else
cb(null, { status: 'ok', led: ledPin, times: times });
});
}
}
});

// Execute the blink Resource on it
so.exec('foo_object', 0, 'blink', [ 3, 10 ], function (err, data) {
if (!err)
console.log(data); // { status: 'ok', led: 3, times: 10 }
});

// Execute a Resource that doesn't exist
so.exec('foo_object', 0, 'show', [], function (err, data) {
if (err) {
console.log(err); // Error: 'Resource not found.'
console.log(data); // '_notfound_'
}
});
```

*************************************************

### dump([oid[, iid]][, opt], callback)
Asynchronously dump data from `so`. This method uses the asynchronous `read()` under the hood.

* Given with `oid`, `iid`, and a `callback` to dump data of an _Object Instance_.
- `dump(oid, iid, function (err, data) {})`
- `dump(oid, iid, { restrict: true }, function (err, data) {})`
* Given with `oid` and a `callback` to dump data of an _Object_.
- `dump(oid, function (err, data) {})`
- `dump(oid, { restrict: true }, function (err, data) {})`
* Given with only a `callback` to dump data of whole smart object.
- `dump(function (err, data) {})`
- `dump({ restrict: true }, function (err, data) {})`

**Arguments:**

1. `oid` (_String_ | _Number_): _Object Id_ of the target.
2. `iid` (_String_ | _Number_): _Object Instance Id_ of the target.
3. `opt` (_Object_): An option used to dump _Resources_ in restrict mode. Default is `{ restrict: false }` if not given.
4. `callback` (_Function_): `function (err, data) { }`.

**Returns:**

* (none)

**Examples:**

```js
// Dump Object Instance: 'temperature' sensor with iid = 18
so.dump('temperature', 18, function (err, data) {
if (!err)
console.log(data);
/*
{
sensorValue: 301,
units : 'K'
}
*/
});

// Dump Object: all 'temperature' sensors
so.dump('temperature', function (err, data) {
if (!err)
console.log(data);
/*
{
'0': {
sensorValue: 31,
units : 'C'
},
'1': {
sensorValue: 75,
units : 'F'
},
'18': {
sensorValue: 301,
units : 'K'
}
}
*/
});

// Dump whole smart object
so.dump(function (err, data) {
if (!err)
console.log(data);
/*
{
temperature: {
'0': {
sensorValue: 31,
units : 'C'
},
'1': {
sensorValue: 75,
units : 'F'
},
'18': {
sensorValue: 301,
units : 'K'
}
}
}
*/
});
```

*************************************************

### dumpSync([oid[, iid]])
Synchronously dump data from `so`. This method uses the synchronous `get()` under the hood. This method **should only be used at server-side** (since at server-side, all stored _Objects_ are simply data pieces).

* Given with both `oid` and `iid` to dump data of an _Object Instance_.
* Given with only `oid` to dump data of an _Object_.
* Given with no ids to dump data of whole _Smart Object_.

**Arguments:**

1. `oid` (_String_ | _Number_): _Object Id_ of the target.
2. `iid` (_String_ | _Number_): _Object Instance Id_ of the target.

**Returns:**

* (_Object_): The dumped data, can be from an _Object Instance_, an _Object_, or whole smart object.

**Examples:**

* Example at client-side
```js
// Dump Object: all 'temperature' sensors
so.dumpSync('temperature');
/*
{
'0': {
sensorValue: 31,
units : 'C'
},
'1': {
sensorValue: {
read: '_read_' // a read method will be dumped to a string '_read_'
},
units : 'F'
},
'18': {
sensorValue: 301,
units : 'K'
}
}
*/
```

* Examples at server-side
```js
// Assume we are at server-side.
var myDevice = myController.find('0x12AE3B4D77886644'); // find the device
var so = myDevice.getSmartObject(); // get the smart object on the device

// Dump Object Instance: 'temperature' sensor with iid = 18
so.dumpSync('temperature', 18);
/*
{
sensorValue: 301,
units : 'K'
}
*/

// Dump Object: all 'temperature' sensors
so.dumpSync('temperature');
/*
{
'0': {
sensorValue: 31,
units : 'C'
},
'1': {
sensorValue: 75,
units : 'F'
},
'18': {
sensorValue: 301,
units : 'K'
}
}
*/

// Dump whole smart object
so.dumpSync();
/*
{
temperature: {
'0': {
sensorValue: 31,
units : 'C'
},
'1': {
sensorValue: 75,
units : 'F'
},
'18': {
sensorValue: 301,
units : 'K'
}
},
...
}
*/
```
*************************************************

### isReadable(oid, iid, rid)
To see if a _Resource_ is readable.

**Arguments:**

1. `oid` (_String_ | _Number_): _Object Id_ of the target.
2. `iid` (_String_ | _Number_): _Object Instance Id_ of the target.
3. `rid` (_String_ | _Number_): _Resource Id_ of the target.

**Returns:**

* (_Boolean_): Returns `true` if the _Resource_ is readable, otherwise `false`.

**Examples:**

```js
so.isReadable('temperature', 8, 'sensorValue'); // true
```

*************************************************

### isWritable(oid, iid, rid)
To see if a _Resource_ is writable.

**Arguments:**

1. `oid` (_String_ | _Number_): _Object Id_ of the target.
2. `iid` (_String_ | _Number_): _Object Instance Id_ of the target.
3. `rid` (_String_ | _Number_): _Resource Id_ of the target.

**Returns:**

* (_Boolean_): Returns `true` if the _Resource_ is writable, otherwise `false`.

**Examples:**

```js
so.isWritable('temperature', 8, 'sensorValue'); // false
```

*************************************************

### isExecutable(oid, iid, rid)
To see if a _Resource_ is executable.

**Arguments:**

1. `oid` (_String_ | _Number_): _Object Id_ of the target.
2. `iid` (_String_ | _Number_): _Object Instance Id_ of the target.
3. `rid` (_String_ | _Number_): _Resource Id_ of the target.

**Returns:**

* (_Boolean_): Returns `true` if the _Resource_ is executable, otherwise `false`.

**Examples:**

```js
so.isExecutable('temperature', 8, 'sensorValue'); // false
```