freebird
Status: Experimental, Unstable
About the Logo
TBD
Table of Contents
- Overview
- Features
- Installation
- Basic Usage
- APIs and Events
- Freebird Base Classes
- Advanced Topics
- Appendix
1. Overview
freebird is a Node.js framework that can building a heterogeneous network, such as BLE, ZigBee, CoAP and MQTT Protocols. It easy to deploy in many platforms like PC, Raspberry Pi, Beaglebone or other embedded device. This framework also provides a uniform interface for developers to operate the various protocols device at the same time, and as the Infrastructure of the IoT/WoT. With freebird, you can make Front-end, Cloud and Machine that simply connected with each other.
The freebird framework has three basic classes of Netcore, Device and Gadget that are represent the network controller, remote device and resource of the device, respectively. For the RPC interface, you can create your own transportation to communicate with freebird, like TCP socket, RESTful APIs, WebSocket, and so on.
2. Features
- Cross protocol, such as BLE, ZigBee, CoAP and MQTT.
- Hierarchical data model in Smart Object (IPSO) .
- The local network management center and application gateway.
- Based-on node.js that can easy to integrate machine applications with other services or frameworks, e.g., http server, express, React.js, Angular.js.
- Handle the most basic part of internet of things and help front-end developers build any fascinating GUI and dashboard.
3. Installation
$ npm install freebird --save
4. Basic Usage
var Freebird = require('freebird'),
bleCore = require('freebird-netcore-ble'),
mqttCore = require('freebird-netcore-mqtt'),
coapCore = require('freebird-netcore-coap'),
zigbeeCore = require('freebird-netcore-zigbee');
var freebird = new Freebird([ bleCore, mqttCore, coapCore, zigbeeCore ]);
freebird.start(function (err) {
console.log('Server started');
});
freebird.on('ready', function () {
});
freebird.on('devIncoming', function (dev) {
});
freebird.on('gadIncoming', function (gad) {
});
5. APIs and Events
Basic methods
Network management
new Freebird(netcores[, options])
Create a instance of the Freebird
class. This document will use freebird
to denote the instance.
Arguments:
netcores
(Object | Array): Should be a netcore or an array of netcores.options
(Object): Optional settings for freebird.
Property | Type | Mandatory | Description |
---|
maxDevNum | Number | optional | Capacity of the device box of freebird, which is the maximum number of devices that freebird can store. If not given, a default value 200 will be used. |
maxGadNum | Number | optional | Capacity of the gadget box of freebird, which is the maximum number of gadgets that freebird can store. If not given, a default value 600 will be used. |
dbPath | Object | optional | This object has fileds of device and gadget which is used to specify the file path to tell freebird where you'd like to keep your device or gadget information. |
Returns:
Examples:
var Freebird = require('freebird'),
bleCore = require('freebird-netcore-ble'),
mqttCore = require('freebird-netcore-mqtt'),
coapCore = require('freebird-netcore-coap'),
zigbeeCore = require('freebird-netcore-zigbee');
var options = {
maxDevNum: 100,
maxGadNum: 500
};
var freebird = new Freebird([bleCore, mqttCore, coapCore, zigbeeCore], options);
.findById(type, id)
Find a netcore by name, or find a device/gadget by id. If you like to find a device/gadget by address, using .findByNet()
.
Arguments:
type
(String): Only accepts 'netcore'
, 'device'
, or 'gadget'
to find a netcore, a device, or a gadget, respectively.id
(String | Number): id
is the netcore name when finding for a netcore. id
is a number when finding for a device or a gadget.
Returns:
- (Object): Found component, otherwise
undefined
Examples:
freebird.findById('netcore', 'foo_netcore');
freebird.findById('netcore', 'no_such_netcore');
freebird.findById('device', 88);
freebird.findById('device', 999);
freebird.findById('gadget', 120);
freebird.findById('gadget', 777);
.findByNet(type, ncName[, permAddr[, auxId]])
Find a netcore, a device, or a gadget by network information.
- To find a netcore:
findByNet('netcore', ncName)
- To find a device:
findByNet('device', ncName, permAddr)
- To find a gadget:
findByNet('gadget', ncName, permAddr, auxId)
Arguments:
type
(String): Only accepts 'netcore'
, 'device'
, or 'gadget'
to find a netcore, a device, or a gadget, respectively.ncName
(String): Netcore name.permAddr
(String): Permanent address of the device which is required when finding for a device or a gadget.auxId
(String | Number): Auxiliary id of the gadget which is required when finding for a gadget.
Returns:
- (Object): Found component, otherwise
undefined
Examples:
freebird.findByNet('netcore', 'foo_netcore');
freebird.findByNet('netcore', 'no_such_netcore');
freebird.findByNet('device', 'foo_netcore', '00:0c:29:3e:1b:d2');
freebird.findByNet('device', 'no_such_netcore', '00:0c:29:3e:1b:d2');
freebird.findByNet('device', 'foo_netcore', '00:00:00:00:00:00');
freebird.findByNet('gadget', 'foo_netcore', '00:0c:29:3e:1b:d2', 'humidity/2');
freebird.findByNet('gadget', 'no_such_netcore', '00:0c:29:3e:1b:d2', 'humidity/2');
freebird.findByNet('gadget', 'foo_netcore', '00:00:00:00:00:00', 'humidity/2');
freebird.findByNet('gadget', 'foo_netcore', '00:0c:29:3e:1b:d2', 'no_such_auxId');
.filter(type, pred)
This method returns an array of netcores, devices, or gadgets which contains all elements of pred
returns truthy for.
Arguments:
type
(String): Only accepts 'netcore'
, 'device'
, or 'gadget'
to find netcores, devices, or gadgets that meet the prediction, respectively.pred
(Function): function (obj) {}
, the function invoked per iteration in a netcores, devices, or gadget collection.
Returns:
- (Array): Returns the new filtered array of components
Examples:
freebird.filter('netcore', function (nc) {
return nc.isEnabled();
});
freebird.filter('device', function (dev) {
return dev.isEnabled();
});
freebird.filter('gadget', function (gad) {
return gad.isEnabled();
});
.addTransport(name, transp[, callback])
Add a transportation to freebird for RPC messaging. Please refer to freebird-transport module for more details.
Arguments:
name
(String): Transportation name.transp
(Object): The instance of transportation.callback
(Function): function (err) {}
.
Returns:
Examples:
var http = require('http'),
fbRpc = require('freebird-rpc');
var httpServer = http.createServer().listen(3000),
rpcServer = fbRpc.createServer(httpServer);
freebird.addTransport('rpcTransp', rpcServer, function (err) {
if (err)
console.log(err);
});
.start([callback])
Start the freebird server.
Arguments:
callback
(Function): function (err) {}
. Get called after started.
Returns:
Examples:
freebird.start(function (err) {
if (!err)
console.log('freebird is up');
else
console.log(err);
});
.stop([callback])
Stop the freebird server.
Arguments:
callback
(Function): function (err) {}
. Get called after stopped.
Returns:
Examples:
nc.stop(function (err) {
if (!err)
console.log('freebird is down');
else
console.log(err);
});
.reset(mode[, callback])
Reset the freebird server.
Arguments:
mode
(Number): 0
for a soft reset and 1
for a hard reset.callback
(Function): function (err) {}
. Get called after reset is applied. When freebird restarted, 'ready'
event will be fired.
Returns:
Examples:
freebird.on('ready', function () {
console.log('freebird is ready');
});
freebird.reset(0, function (err) {
if (!err)
console.log('freebird starts to run its reset procedure');
else
console.log(err);
});
.permitJoin(duration[, callback])
Let the freebird allow devices to join the network.
Arguments:
duration
(Number): Duration in seconds for allowing devices to join the network. Set it to 0
can immediately close the admission.callback
(Function): function (err, timeLeft) {}
. Get called when freebird starts/stops to permit joining, where timeLeft
is a number that indicates time left for device joining in seconds, e.g., 180.
Returns:
Examples:
freebird.permitJoin(180, function (err, timeLeft) {
if (!err)
console.log(timeLeft);
});
freebird.permitJoin(0, function (err, timeLeft) {
if (!err)
console.log(timeLeft);
});
.remove(ncName, permAddr, callback)
Remove a remote device from the network.
Arguments:
ncName
(String): Netcore name.permAddr
(String): Permanent address of the device to remove.callback
(Function): function (err, permAddr) {}
. Get called after device removed, where permAddr
is permananet address of that device.
Returns:
Examples:
freebird.remove('mqtt-core', '00:0c:29:ff:ed:7c', function (err, permAddr) {
if (!err)
console.log(permAddr);
});
.ban(ncName, permAddr, callback)
Ban a device from the network. Once a device is banned, it can never join the network unless you unban it.
Arguments:
ncName
(String): Netcore name.permAddr
(String): Permanent address of the device to ban.callback
(Function): function (err, permAddr) {}
. Get called after device banned, where permAddr
is permananet address of that device.
Returns:
Examples:
freebird.ban('mqtt-core', '00:0c:29:ff:ed:7c', function (err, permAddr) {
if (!err)
console.log(permAddr);
});
.unban(ncName, permAddr, callback)
Unban a device.
Arguments:
ncName
(String): Netcore name.permAddr
(String): Permanent address of the device to unban.callback
(Function): function (err, permAddr) {}
. Get called after device unbanned, where permAddr
is permananet address of that device.
Returns:
Examples:
freebird.unban('mqtt-core', '00:0c:29:ff:ed:7c', function (err, permAddr) {
if (!err)
console.log(permAddr);
});
.ping(ncName, permAddr, callback)
Ping a remote device.
Arguments:
ncName
(String): Netcore name.permAddr
(String): Permanent address of the device to ping.callback
(Function): function (err, time) {}
. Get called after ping response comes back, where time
is the round-trip time in milliseconds, e.g., 16.
Returns:
Examples:
freebird.ping('mqtt-core', '00:0c:29:ff:ed:7c', function (err, time) {
if (!err)
console.log(time);
});
.maintain([ncName,][callback])
Maintain the freebird server. This will refresh all devices information by rediscovering the remote device.
Arguments:
ncName
(String): Netcore name. freebird will maintain all netcores if ncName
not given.callback
(Function): function (err) {}
. Get called after maintained.
Returns:
Examples:
freebird.maintain('mqtt-core', function (err) {
if (!err)
console.log('freebird is maintained');
});
********************************************
Events
Event Listener: function (msg) { ... }
-
Event: 'error'
- Emitted when freebird occurs error
- msg:
error object
-
Event: 'ready'
- Emitted when freebird is ready
- msg:
{ netcore: 'mqtt-core' }
-
Event: 'ncEnabled'
- Emitted when a netcore is enabled
- msg:
{ ncName: 'mqtt-core' }
-
Event: 'ncDisabled'
- Emitted when a netcore is disabled
- msg:
{ ncName: 'mqtt-core' }
-
Event: 'ncStarted'
- Emitted when a netcore is started
- msg:
{ ncName: 'mqtt-core' }
-
Event: 'ncStopped'
- Emitted when a netcore is stopped
- msg:
{ ncName: 'mqtt-core' }
-
Event: 'ncPermitJoin'
- Emitted when a netcore is now allowing or disallowing devices to join the network, where
timeLeft
is number of seconds left to allow devices to join the network. - msg:
{ ncName: 'mqtt-core', timeLeft: 60 }
-
Event: 'devIncoming'
- Emitted when a new device is incoming
- msg:
{ ncName: 'mqtt-core', permAddr: '00:0c:29:ff:ed:7c', id: 5, device: device }
-
Event: 'devLeaving'
- Emitted when a device is leaving
- msg:
{ ncName: 'mqtt-core', permAddr: '00:0c:29:ff:ed:7c', id: 5 }
-
Event: 'devReporting'
- Emitted when a report message of certain attribute(s) on a device is coming.
data
property is partial changes of devAttrsObj - msg:
{ ncName: 'mqtt-core', permAddr: '00:0c:29:ff:ed:7c', id: 5, data: devAttrs }
-
Event: 'devNetChanged'
- Emitted when network information of a device has changed.
data
property is partial changes of netInfoObj, _data property is the old netInfoObj value that before changed - msg:
{ ncName: 'mqtt-core', permAddr: '00:0c:29:ff:ed:7c', id: 5, data: netInfoObj, _data: oldValue }
-
Event: 'devStatusChanged'
- Emitted when status of a device has changed. The status can be 'online', 'sleep', 'offline', and 'unknown'.
- msg:
{ ncName: 'mqtt-core', permAddr: '00:0c:29:ff:ed:7c', id: 5, data: 'offline' }
-
Event: 'devPropsChanged'
- Emitted when meta-property(ies) of a device has changed.
data
property is partial changes of devPropsObj, _data property is the old devPropsObj value that before changed - msg:
{ ncName: 'mqtt-core', permAddr: '00:0c:29:ff:ed:7c', id: 5, data: delta, _data: oldValue }
-
Event: 'devAttrsChanged'
- Emitted when attribute(s) on a device has changed.
data
property is partial changes of devAttrsObj, _data property is the old devAttrsObj value that before changed - msg:
{ ncName: 'mqtt-core', permAddr: '00:0c:29:ff:ed:7c', id: 5, data: delta, _data: oldValue }
-
Event: 'gadIncoming'
- Emitted when a new gadget is incoming
- msg:
{ ncName: 'mqtt-core', permAddr: '00:0c:29:ff:ed:7c', auxId: 'magnetometer/0', id: 5, gadget: gadget }
-
Event: 'gadLeaving'
- Emitted when a gadget is leaving
- msg:
{ ncName: 'mqtt-core', permAddr: '00:0c:29:ff:ed:7c', auxId: 'magnetometer/0', id: 5 }
-
Event: 'gadReporting'
- Emitted when a report message of certain attribute(s) on a gadget is coming.
data
property is partial changes of gadAttrsObj - msg:
{ ncName: 'mqtt-core', permAddr: '00:0c:29:ff:ed:7c', auxId: 'magnetometer/0', id: 5, data: delta }
-
Event: 'gadPanelChanged'
- Emitted when panel information of a gadget has changed.
data
property is partial changes of panelInfoObj, _data property is the old panelInfoObj value that before changed - msg:
{ ncName: 'mqtt-core', permAddr: '00:0c:29:ff:ed:7c', auxId: 'magnetometer/0', id: 5, data: delta, _delta: oldVal }
-
Event: 'gadPropsChanged'
- Emitted when meta-property(ies) of a gadget has changed.
data
property is partial changes of gadPropsObj, _data property is the old gadPropsObj value that before changed - msg:
{ ncName: 'mqtt-core', permAddr: '00:0c:29:ff:ed:7c', auxId: 'magnetometer/0', id: 5, data: delta, _delta: oldVal }
-
Event: 'gadAttrsChanged'
- Emitted when attribue(s) on a gadget has changed.
data
property is partial changes of gadAttrsObj, _data property is the old gadAttrsObj value that before changed - msg:
{ ncName: 'mqtt-core', permAddr: '00:0c:29:ff:ed:7c', auxId: 'magnetometer/0', id: 5, data: delta }
-
Event: 'bannedDevIncoming'
- Emitted when a banned device is trying to join the network
- msg:
{ ncName: 'mqtt-core', permAddr: '00:0c:29:ff:ed:7c' }
-
Event: 'bannedDevReporting'
- Emitted when a banned device is trying to report its attributes
- msg:
{ ncName: 'mqtt-core', permAddr: '00:0c:29:ff:ed:7c' }
-
Event: 'bannedGadIncoming'
- Emitted when a banned gadget is trying to join the network
- msg:
{ ncName: 'mqtt-core', permAddr: '00:0c:29:ff:ed:7c', auxId: 'magnetometer/0' }
-
Event: 'bannedGadReporting'
- Emitted when a banned gadget is trying to report its attributes
- msg:
{ ncName: 'mqtt-core', permAddr: '00:0c:29:ff:ed:7c', auxId: 'magnetometer/0' }
6. Freebird Base Classes
freebird-base includes base classes of Netcore, Device, and Gadget that are used in the freebird IoT network and application framework. These classes are abstractions of the network controller, network device, and real appliance, respectively.
Netcore Class
Netcore is a network controller which equips with freebird-defined methods to accomplish operations of network transportation and management. In pratice, the netcore may be a zigbee coordinator (TI CC253X), a BLE central (TI CC254X).
APIs findById()
, findByNet()
, filter()
can help you find the instance of this class. The instance which is denoted as netcore
in this document. Please see NetcoreClass.md for more detail about this class.
Device Class
Device is a wired/wireless machine in the network. For example, a zigbee end-device, a BLE peripheral, a MQTT client, or a CoAP server(LWM2M client).
APIs findById()
, findByNet()
, filter()
can help you find the instance of this class. The instance which is denoted as device
in this document. Please see DeviceClass.md for more detail about this class.
Gadget Class
Gadget represents something specific and functional in our life. For example, a temperature sensor, a light switch, or a barometer.
APIs findById()
, findByNet()
, filter()
can help you find the instance of this class. The instance which is denoted as gadget
in this document. Please see GadgetClass.md for more detail about this class.
7. Advanced Topics
Remote Process Communication (RPC)
freebird is a underlying construction that helps you manage your machine network of different protocol in the same time, like BLE, Zigbee, MQTT or CoAP. With freebird, it is easy and quick to implement IoT webapps.
In the process of establishing webapp, due to the communcation between the web client and the web server is remotely, so you need to build a RPC channel to do Remote Process Communication. There are many ways to implement RPC channel, you can use TCP socket, RESTful APIs, WebSocket, etc. And Developers should define RPC interface according to their application type.
How to add a transport for RPC
There is a module freebird-transport for developers to create their own transportation for RPC, please see the document of how to create the transportation to communicate with freebird framework. After the transportation is created, you can call freebird.addTransport()
to add the transportation to freebird for RPC messaging.
Here is a example of how to create a transportation and add to freebird:
var Freebird = require('freebird'),
bleCore = require('freebird-netcore-ble'),
mqttCore = require('freebird-netcore-mqtt');
var net = require('net'),
Transport = require('freebird-transport');
var freebird = new Freebird([ bleCore, mqttCore ]);
var transp = new Transport(),
server,
client;
server = net.createServer(function (c) {
client = c;
client.on('end', function () {
client = null;
});
client.on('data', function (data) {
transp.receive({ data: data });
});
});
server.listen(4321, function () {
console.log('TCP server starts');
});
transp._send = function (msg, callback) {
var bytes;
if (typeof msg !== 'object')
return setImmediate(callback, new TypeError('msg should be an object'));
if (typeof msg.data === 'string')
msg.data = new Buffer(msg.data);
if (!Buffer.isBuffer(msg.data))
return setImmediate(callback, new TypeError('msg.data should be a string or a buffer'));
bytes = msg.data.length;
if (!client)
return setImmediate(callback, new Error('No client connected'));
client.write(msg.data);
setImmediate(callback, null, bytes);
};
freebird.addTransport('tcpRpsServer', transp);
We have already implemented a transportation freebird-rpc using WebSocket protocol. It provide methods to create RPC client and RPC server for real-time remote communication. The following is a simple example of how to using freebird-rpc
in freebird:
var Freebird = require('freebird'),
bleCore = require('freebird-netcore-ble'),
mqttCore = require('freebird-netcore-mqtt'),
http = require('http'),
fbRPC = require('freebird-rpc');
var freebird = new Freebird([ bleCore, mqttCore ]);
var httpServer = http.createServer();
httpServer.listen(3000);
var transp = fbRpc.createServer(httpServer);
freebird.addTransport('wsRpsServer', transp);
How to add a plugin
[TODO]
8. Appendix
Device Data Format
Network information: netInfoObj
Property | Type | Description |
---|
enabled | Boolean | Tells if this device is enabled. |
joinTime | Number | Device joined time, which is an UNIX(POSIX) time in ms. |
timestamp | Number | Timestamp at the last activity. |
traffic | Object | The traffic record of this device. |
role | String | Device role, which depends on protocol. For example, it may be 'peripheral' of a BLE device. |
parent | String | The parent of this device. It is '0' if the parent is the netcore, otherwise parent's permanent address. |
maySleep | Boolean | Tells whether this device may sleep or not. |
sleepPeriod | Number | The sleep period in seconds. This property is only valid when maySleep is true . |
status | String | Can be 'unknown' , 'online' , 'offline' , or 'sleep' . |
address | Object | The permanent and dynamic adrresses of this device. This object is in the shape of { permanent, dynamic } . |
Attributes on the remote device: devAttrsObj
Property | Type | Description |
---|
manufacturer | String | Manufacturer name |
model | String | Model name |
serial | String | Serial number of this device. |
version | Object | Version tags. This object is in the shape of { hw: '', sw: 'v1.2.2', fw: 'v0.0.8' } |
power | Object | Power source. This object is in the shape of { type: 'battery', voltage: '5 V' } . The type can be 'line', 'battery' or 'harvester'. |
User-defined properties on this device: devPropsObj
Property | Type | Description |
---|
name | String | Human-redable name of this device, default will be an empty string '' if not set. |
description | String | Device description. Default will be an empty string '' if not set. |
location | String | Location of this device. Default will be an empty string '' if not set. |
Others | Depends | Other props |
Gadget Data Format
Panel information: panelInfoObj
- (Object): Panel information about this gadget.
Property | Type | Description |
---|
enabled | Boolean | Indicate whether this gadget is enabled |
profile | String | Profile of this gadget, can be any string, such as 'Home' |
classId | String | Gadget class to tell what kind of an application is on this gadget |
Attributes on the remote gadget: gadAttrsObj
Property | Type | Description |
---|
Others | Depends | Remote attributes depend on classId of gadget. For a temperature sensor, it will have an attribute sensorValue , and may have attributes like units and resetMinMaxMeaValues . The possilbe attributes are listed here. |
User-defined properties on this gadget: gadPropsObj
Property | Type | Description |
---|
name | String | Human-redable name of this gadget, default will be a string of 'unknown' if not set |
description | String | Gadget description. Default will be an empty string '' if not set |
Others | Depends | Other props |