Bullwinkle has been deprecated and will no longer be updated -- please use MessageManager instead
Bullwinkle is an easy to use framework for asynchronous agent and device communication. The Bullwinkle library consists of two classes:
- Bullwinkle - The core application - used to add/remove handlers, and send messages.
- Bullwinkle.send - Sends a message to the partner application.
- Bullwinkle.on - Adds a message listener for the specified messageName.
- Bullwinkle.remove - Removes a message listener for the specified messageName.
- Bullwinkle.Package - A packaged message with event handlers.
- Package.onSuccess - Adds a handler that will be invoked if the message is successfully delivered and acknowledged.
- Package.onReply - Adds a handler that will be invoked if the message is replied to.
- Package.onFail - Adds an onFail handler that will be invoked if the send failed.
- retry - A method passed into .onFail handlers that is used to retry sending the message.
To add this library to your project, add #require "bullwinkle.class.nut:2.3.2"
to the top of your agent and device code.
Note You must #require
and instantiate Bullwinkle in both the agent and device code.
Calling the Bullwinkle constructor creates a new Bullwinkle application. An optional options table can be passed into the constructor to override default behaviors.
A table containing any of the following keys may be passed into the Bullwinkle constructor to modify the default behavior:
Key | Data Type | Default Value | Description |
---|---|---|---|
messageTimeout | Integer | 10 | Changes the default timeout required before a message is considered failed. |
retryTimeout | Integer | 60 | Changes the default timeout parameter passed to the retry method. |
maxRetries | Integer | 0 | Changes the default number of times the retry method will function. After this number the retry method will do nothing. If set to 0 there is no limit to the number of retries. |
autoRetry | Boolean | false |
If set to true , Bullwinkle will automatically continue to retry sending a message until maxRetries has been reached when no onFail is supplied. Please note if maxRetries is set to 0, autoRetry will have no limit to the number of times it will retry. |
onError | function | null | Callback to be executed if a low level error is encountered. Currently it is called when too many timers have been created. |
// Initialize using default settings
bull <- Bullwinkle();
options <- { "messageTimeout": 5, // If there is no response from a message in 5 seconds,
// consider it failed
"retryTimeout": 30, // Calling package.retry() with no parameter will retry
// in 30 seconds
"maxRetries": 10, // Limit to the number of retries to 10
"autoRetry": true // Automatically retry 10 times
}
// Initialize using custom settings
bull <- Bullwinkle(options);
Sends a named message to the partner’s Bullwinkle application, and returns a Bullwinkle.Package. The data parameter can be a basic Squirrel type (1
, true
, "A String"
) or more complex data structures such as an array or table, but it must be a serializable Squirrel value.
bull.send("setLights", true); // Turn the lights on
The send() method returns a Bullwinkle.Package object that can be used to attach onFail, onSuccess and onReply handlers.
Adds a message listener (the callback) for the specified messageName. The callback method takes two parameters: message (the message) and reply (a method that can be called to reply to the message).
// Get a message, and do something with it
bull.on("setLights", function(message, reply) {
led.write(message.data);
});
The message parameter is a table that contains some or all of the following keys:
Key | Data Type | Description |
---|---|---|
type | Integer | Bullwinkle message type |
tries | Integer | Number of attempts made to deliver the message |
name | String | Name of the message |
id | Integer | ID of the message |
ts | Integer | Timestamp when message was created |
data | Serializable Squirrel value | data passed into the #send method |
retry | Table | A table containing ts the timestamp of the latest retry and sent a boolean |
latency | Float | Seconds taken to deliver the message |
The second parameter, reply, is a method that can be invoked to reply to the message caught by the .on handler. The reply method takes a parameter, data, representing the information we want to pass back to the partner. The data parameter can be any serializable Squirrel value.
// Get a message, and respond to it
bull.on("temp", function(message, reply) {
// Read the temperature and humidity sensor
local data = tempHumid.read();
// Reply to the message
reply(data);
});
The remove() method removes a message listener that was added with the .on method.
bull.remove("test"); // Don't listen for 'test' messages any more.
A Bullwinkle.Package object represents a message that has been sent to the partner, and has event handlers attached to it. Bullwinkle.Package objects should never be manually constructed: the Bullwinkle.send() method returns a Bullwinkle.Package object.
The onSuccess() method adds an event listener (the callback) that will execute if the partner .on handler receives the message. The callback’s message parameter contains the successfully delivered message, including a tries count and a round-trip latency float in seconds.
bull.send("importantMessage")
.onSuccess(function(message) {
server.log("Done!");
})
.onFail(function(err, message, retry) {
retry();
});
The onReply() method adds an event listener (the callback) that will execute if the partner .on handler replies to the message with the reply() method. The callback takes a single parameter, message, which contains the message information, including a tries count and a round-trip latency float in seconds.
The following example demonstrates how to get real time sensor information with Rocky and Bullwinkle:
// Agent Code
#require "Rocky.class.nut:1.2.3"
#require "Bullwinkle.class.nut:2.3.2"
app <- Rocky();
bull <- Bullwinkle();
app.get("/data", function(context) {
bull.send("temp").onReply(function(message) {
context.send(200, message.data);
});
});
// Device Code
#require "Si702x.class.nut:1.0.0"
#require "Bullwinkle.class.nut:2.3.2"
bull <- Bullwinkle();
i2c <- hardware.i2c89;
i2c.configure(CLOCK_SPEED_400_KHZ);
tempHumid <- Si702x(i2c);
bull.on("temp", function(message, reply){
local result = tempHumid.read();
reply(result);
});
The onFail() method adds an event listener (the callback) that will execute if the partner application does not have a handler for the specified message name, or if the partner fails to respond within a specified period of time (the messageTimeout). The callback method requires three parameters: err, message and retry. If onFail() is used the autoRetry setting will not be envoked. To resend the message you must use the retry callback parameter.
The err parameter describes the error, and will either be BULLWINKLE_ERR_NO_HANDLER
(in the event the partner application does not have a handler for the specified message name), or BULLWINKLE_ERR_NO_RESPONSE
(in the event the partner application fails to respond in the specified timeout period).
The message parameter contains the failed message, including a tries count and a latency float in seconds.
The retry parameter is a method that can be invoked to retry sending the message in a specified period of time. This method must be called synchronously if it is to be called at all. If the retry() method is not called the message will be expired.
bull.send("importantMessage")
.onFail(function(err, message, retry) {
// Try sending the message again in 60 seconds
if (!retry(60)) {
server.error("No more retry attempts are allowed");
}
}).onReply(function(message) {
server.log("Done!");
});
The retry() method is passed into onFail handler, and can be used to try sending the failed message again after the specified timeout has elapsed. If no timeout is specified, the retry message will use the default retryTimeout setting. If the maximum number of retries have been attempted then this function will return false
and no more retries will be attempted, otherwise it will return true
. See onFail for example usage.
Bullwinkle is licensed under the MIT License.