Overview
Bitdog is an open JSON messaging platform that utilizes a cloud based service bus and Node.js to transport messages between designated endpoints or “nodes”. There are several classes of messages. The two most common classes are data and command.
Data messages are user defined JSON messages containing data and a name. Data messages are routed to any node that has subscribed to data messages of that name. Data messages are also saved in the Bitdog Data Lake so that they can be used to create reports and dashboards. Bitdog Hub is designed to collect local data and pass that data to subscribing nodes and the Bitdog Data Lake via data messages.
Command messages are similar to data message, they are also user defined JSON messages containing data and have a name, but they also have a target node identifier. Command messages are only routed to the target node identified in the message. Command messages are intended to control Bitdog Hub by invoking user defined code when received.
The JSON structure of user defined data in all message is defined by schema. Message types are first registered with the Bitdog Hub. Each message type has a class (command or data), a name, and a schema. Once the message type has been registered, it can be used to send information to other nodes.
Schemas and Commands
Before any message can be sent from a Bitdog Hub, the schema must be defined in code using the createMessageSchema function. This function takes a unique schema name as a parameter and returns an instance of MessageSchema. Once a message schema is created, properties can be added to the schema. MessageSchema has several functions for adding properties of different data types.
The code example below is from extensions/IFTTTExtension.js.
// Create a custom message schema with one string property. var onOffMessageSchema = this.createMessageSchema('OnOff') .addStringProperty('value1', 'off', { values: ['on', 'off'] });
The createMessageSchema function is inherited from the base class of IFTTTExtension. In the example above addStringProperty function adds a new string property to the schema called value1 with possible values limited to “on” and “off” with the default set to “off”. The example below demonstrates the onOffMessageSchema being used to register a”Turn LED on/off” command.using the addCommand function. Every time this Bitdog Hub receives a “Turn LED on/off” command it will execute the function that was registered with it. In this case the function will turn on a LED for 30 seconds regardless of the value passed to it. One of the parameters passed to the function is the message. In this case, the message would have one property “message.value1” that would contain either “on” or “off”.
// Add a command to this hub that turns the LED on and off this.addCommand('Turn LED on/off', onOffMessageSchema, function (message, configuration, logger) { // check if we already have a timer running if (blinkTimer === null) { // turn the LED on by setting pin low rpio.write(ledPin, rpio.LOW); // turn off LED after 30 seconds blinkTimer = setTimeout(function () { rpio.write(ledPin, rpio.HIGH); blinkTimer = null; }, 30000); } })
When a command message is created with this schema the JSON message will look similar to the example below.
{ "h": { "c":"command", "d":"bf9ec555-76cc-5555-979a-96b5f9a5cfff", "n":"Turn LED on/off" }, "d": { "value1":"off" } }
This command message has “h” and “d” properties. The “h” property is the message header and is created automatically by the Bitdog framework. The message header contains the message class “c”, the destination node id “d”, and the name of the command “n”. The “d” is the user defined data. The schema of the message determines the format of this properties. In this case we defined a string property called “value1”.
Only the value of “d” is sent to the command function when it is executed. Its passed to the function as the first parameter called message. In order to access “value1” inside the command function use “message.value1”.
// Add a command to this hub that turns the LED on and off this.addCommand('Turn LED on/off', onOffMessageSchema, function (message, configuration, logger) { ....
Data
Data messages are similar to commands and can use the same schema. The example below demonstrates the onOffMessageSchema being used to register a”Switch Status” data collector.using the addDataCollector function.
// Register data collector and set it to poll every 60 seconds. // Set seconds to -1 to not poll at all. this.addDataCollector('Switch Status', onOffMessageSchema, 60000, function (message, configuration, logger) { // Read the state of the switch pin self.buttonState = rpio.read(buttonPin) ? 'on' : 'off'; message.value1 = self.buttonState; })
Data collectors gather information at regular intervals. At each interval, the data collector executes the configured callback passing a new created message. The callback function can set any of the properties of the message. The message and its data is then sent to Bitdog Cloud for routing.
When a data message is created with onOffMessageSchema schema the JSON message will look similar to the example below.
{ "h": { "c":"data", "n":"Switch Status" }, "d": { "value1":"off" } }
Data collectors can also be configured not to poll by giving it a polling time of -1 as seen in the example below.
this.addDataCollector('Switch Status', onOffMessageSchema,-1, function (message, configuration, logger) { })
As long as the data collector is registered first, data can be sent at anytime whether a data collector is polling or not, as seen in the example below.
// Send a message to the cloud about our new switch state. this.sendData('Switch Status', onOffMessageSchema, function (message, configuration, logger) { message.value1 = self.buttonState; });
Summary
All of the messaging within Bitdog Hub extensions are handled by four main functions:
- createMessageSchema
- addCommand
- addDataCollector
- sendData
Specifics of these functions are covered further in API documentation.