Skip to content

Instantly share code, notes, and snippets.

@blindman2k
Forked from davidsulpy/InitialState.class.nut
Last active December 16, 2015 00:48
Show Gist options
  • Save blindman2k/764ddcbbc861f0f10f06 to your computer and use it in GitHub Desktop.
Save blindman2k/764ddcbbc861f0f10f06 to your computer and use it in GitHub Desktop.

InitialState 1.0.0

Initial State is a hosted service that allows you to easily push event based data.

This class wraps Initial State's Event API (aka groker) in an agent side library.

To add this library to your project, add #require "InitialState.class.nut:1.0.0" to the top of your agent code.

Class Usage

Constructor: InitialState(access_key, bucket_key, [bucket_name])

Instantiate the InitialState class with your Access Key and optionally, the Bucket Key and Bucket Name:

Parameter Optional Notes
Access key No Available in the account page
Bucket key Yes User generated bucket id, defaults to Bucket name
Bucket name Yes User generated bucket name, defaults to Electric Imp agentId
#require "InitialState.class.nut:1.0.0"

is <- InitialState(IS_ACCESS_KEY);

Send Events

There are two methods to send events to Initial State. One method is.sendEvent is for singular events. The other method is.sendEvents is for a batch of events. If a third parameter, a callback function, is supplied the callback will be fired when the request is complete. Examples of each usage are below:

sendEvent(key, value, [epoch], [callback])

// send an event 
is.sendEvent("temperature", 72, function(err, data) {
    if (err != null) {
        server.log("Error: " + err);
    }
});

sendEvents(events, [callback])

// send an array of events
is.sendEvents([
    {"key": "temperature", "value": 72},
    {"key": "humidity", "value": 55}
], function(err, data) {
    if (err != null) {
        server.log("Error: " + err);
    }
});

Overriding Event Timestamp

You can optionally override the timestamp of an event by passing in an epoch to the .sendEvent or .sendEvents methods. Here is how to achieve this respectively:

// override timestamp for single event
is.sendEvent("temperature", 72, time());

// override timestamp for multiple events
is.sendEvents([
    {"key": "temperature", "value": 72, "epoch": time() },
    {"key": "humidity", "value": 55, "epoch": time() }
]);

License

The Initial State library is licensed under the MIT License.

// Copyright (c) 2015 Initial State Technologies, Inc.
// This file is licensed under the MIT License
// http://opensource.org/licenses/MIT
class InitialState {
static version = [1,0,0];
_bucketKey = null;
_accessKey = null;
_bucketName = null;
_isBucketCreated = false;
_eventRequestHeaders = null;
constructor(accessKey, bucketKey = null, bucketName = null) {
const _baseUrl = "https://groker.initialstate.com/api/";
const _apiVersion = "~0";
if (!bucketKey) {
bucketKey = split(http.agenturl(), "/").top();
}
if (!bucketName) {
bucketName = bucketKey;
}
_accessKey = accessKey;
_bucketKey = bucketKey;
_bucketName = bucketName;
_eventRequestHeaders = {
"Content-Type": "application/json",
"X-IS-AccessKey": _accessKey,
"X-IS-BucketKey": _bucketKey,
"Accept-Version": _apiVersion
}
}
// Creates a new bucket on the IS server. This is called automatically.
//
// Parameters:
// callback: The function to call on the completion of this request.
//
// Returns: this
function createBucket(callback = null) {
// Prepare the URL and POST data
local url = _baseUrl + "buckets";
local data = http.jsonencode({
"bucketName": _bucketName,
"bucketKey": _bucketKey
});
local headers = {
"Content-Type": "application/json",
"X-IS-AccessKey": _accessKey,
"Accept-Version": _apiVersion
};
// Post the event to the Initial State server
local req = http.post(url, headers, data);
req.sendasync(function(resp) {
local err = null;
local data = null;
if (resp.statuscode == 429) {
// We have been throttled. Try again in a second
imp.wakeup(1, function() {
createBucket(callback);
}.bindenv(this))
return;
} else if (resp.statuscode < 200 || resp.statuscode >= 300) {
// Failure
err = "StatusCode: " + resp.statuscode + ", Message: " + resp.body;
} else {
// Success
data = http.jsonencode(resp.body);
_isBucketCreated = true;
}
// Feed back to the calling function
if (callback) callback(err, data);
}.bindenv(this));
return this;
}
// Sends a single events to the IS server.
//
// Parameters:
// callback: The function to call on the completion of this request.
//
// Returns: this
function sendEvent(eventKey, eventValue, epoch = null, callback = null) {
// Rearrange the optional parameters
if (typeof epoch == "function") {
callback = epoch;
epoch = null;
}
if (epoch == null) {
local d = date();
epoch = format("%d.%s", d.time, format("%0.06f", d.usec / 1000000.0).slice(2));
}
// If we haven't created the bucket, create it now and repeat this function.
if (_isBucketCreated == false) {
createBucket(function(err, data) {
if (err) {
if (callback) callback(err, null)
} else {
sendEvent(eventKey, eventValue, epoch, callback);
}
}.bindenv(this))
return;
}
// Prepare the URL and POST body
local url = _baseUrl + "events";
local eventObject = {
key = eventKey,
value = eventValue,
epoch = epoch
};
local data = http.jsonencode(eventObject);
// Post the event to the Initial State server
local req = http.post(url, _eventRequestHeaders, data);
req.sendasync(function(resp) {
local err = null;
local data = null;
if (resp.statuscode == 429) {
// We have been throttled. Try again in a second
imp.wakeup(1, function() {
sendEvent(eventKey, eventValue, epoch, callback);
}.bindenv(this))
return;
} else if (resp.statuscode < 200 || resp.statuscode >= 300) {
// Failure
err = "StatusCode: " + resp.statuscode + ", Message: " + resp.body;
} else {
// Success
data = resp.body;
}
// Feed back to the calling function
if (callback) callback(err, data);
}.bindenv(this));
return this;
}
// Sends an array of events to the IS server. Each event should be a table containing:
// "key", "value" and "epoch" (optional)
//
// Parameters:
// callback: The function to call on the completion of this request.
//
// Returns: this
function sendEvents(events, callback = null) {
// If we haven't created the bucket, create it now and repeat this function.
if (_isBucketCreated == false) {
createBucket(function(err, data) {
if (err) {
if (callback) callback(err, null)
} else {
sendEvents(events, callback);
}
}.bindenv(this))
return;
}
// Prepare the URL and POST body
local url = _baseUrl + "events";
local data = http.jsonencode(events);
// Post the event to the Initial State server
local req = http.post(url, _eventRequestHeaders, data);
req.sendasync(function(resp) {
local err = null;
local data = null;
if (resp.statuscode == 429) {
// We have been throttled. Try again in a second
imp.wakeup(1, function() {
sendEvents(events, callback);
}.bindenv(this))
return;
} else if (resp.statuscode < 200 || resp.statuscode >= 300) {
// Failure
err = "StatusCode: " + resp.statuscode + ", Message: " + resp.body;
} else {
// Success
data = resp.body;
}
// Feed back to the calling function
if (callback) callback(err, data);
}.bindenv(this));
return this;
}
}
The MIT License (MIT)
Copyright (c) 2015 Initial State Technologies, Inc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment