Skip to content

Instantly share code, notes, and snippets.

@marcboon
Last active December 17, 2015 15:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marcboon/5634981 to your computer and use it in GitHub Desktop.
Save marcboon/5634981 to your computer and use it in GitHub Desktop.
Using xively.com to share data between two or more electric imps. The imps can read and update named channels in the same feed, and notify each other after every successful update, so that data is synchronized between imps, without the need for polling. Upon start-up, every imp automatically adds a tag to the feed, containing its unique agent id…
// Xively account credentials
const MyApiKey = YOUR_API_KEY
const MyFeedID = YOUR_FEED_ID
// Class for reading/writing a feed at xively.com (formerly cosm)
class XivelyFeed {
static url = "https://api.xively.com/v2/feeds/"
apiKey = null
feedID = null
constructor(apiKey, feedID) {
this.apiKey = apiKey
this.feedID = feedID
}
// Send data to feed, expects a table with channel:value pairs
function put(data, callback) {
local datastreams = []
foreach(channel, value in data) {
datastreams.push({ "id": channel, "current_value": value })
}
local body = { "version": "1.0.0", "datastreams": datastreams }
local headers = { "X-ApiKey": apiKey, "Content-type": "application/json" }
local req = http.put(url + feedID + ".json", headers, http.jsonencode(body))
req.sendasync(callback)
}
// Get current feed state
function get() {
local headers = { "X-ApiKey": apiKey }
local req = http.get(url + feedID + ".json", headers)
local res = req.sendsync()
server.log("GET: " + res.statuscode)
return res.statuscode == 200 ? http.jsondecode(res.body) : null
}
// Get a datastream (channel)
function getStream(id) {
local feed = get()
if(feed != null) {
foreach(stream in feed.datastreams) {
if(stream.id == id) return stream // stream found
}
}
return null // stream not found
}
// Get tags for this feed as array
function getTags() {
local feed = get()
if(feed != null) {
if("tags" in feed) return feed.tags // return array with tags
else return [] // no tags, return empty array
}
return null // failed to get tags
}
// Set tags for this feed
function setTags(tags) {
local body = { "version": "1.0.0", "tags": tags }
local headers = { "X-ApiKey": apiKey, "Content-type": "application/json" }
local req = http.put(url + feedID + ".json", headers, http.jsonencode(body))
if(req.sendsync().statuscode == 200) {
server.log("tags updated: " + http.jsonencode(tags))
return tags
}
server.log("setTags failed")
return null
}
// Add a tag to this feed
function addTag(tag) {
local tags = getTags()
if(tags != null) {
if(tags.find(tag) == null) {
tags.push(tag)
tags = setTags(tags)
}
}
return tags
}
// Remove a tag from this feed
function removeTag(tag) {
local tags = getTags()
if(tags != null) {
local i = tags.find(tag)
if(i != null) {
tags.remove(i)
tags = setTags(tags)
}
}
return tags
}
}
// Send notification message to other agent
function notifyAgent(agent, state) {
local agentURL = "https://agent.electricimp.com/" + agent
local body = { "agent_id": MyAgentID, "feed_id": MyFeedID, "datastream": state }
local headers = { "Content-type": "application/json" }
local req = http.put(agentURL, headers, http.jsonencode(body))
req.sendasync(null) // send notification without waiting for result (target might be offline)
}
// Post-update handler, notifies other devices
function onUpdate(res) {
server.log("PUT: " + res.statuscode)
local tags = feed.getTags()
if(tags != null) {
// notify agents
local state = feed.getStream("LED")
foreach(tag in tags) {
// agentIDs are prefixed with @
if(tag[0] == '@') {
// Skip self
if(tag != MyAgentID)
notifyAgent(tag.slice(1), state)
}
}
}
}
// Add agentID to this feed's tags when device connects
device.onconnect(function() {
server.log("device connected")
feed.addTag(MyAgentID)
})
// Remove agentID from this feed's tags when device disconnects
device.ondisconnect(function() {
server.log("device disconnected")
feed.removeTag(MyAgentID)
})
// Handler for updates from device
device.on("put", function(data) {
server.log(http.jsonencode(data))
feed.put(data, onUpdate)
})
// Handler for updates from other agents
http.onrequest(function(req, res) {
// send OK response to the sender
res.send(200, "OK")
local feed = http.jsondecode(req.body)
// verify if this is our feed
if("feed_id" in feed && feed.feed_id == MyFeedID) {
device.send("update", feed.datastream)
}
})
// Start agent
server.log("agent started")
// Create xively feed object
feed <- XivelyFeed(MyApiKey, MyFeedID)
// This imp's agentID (agentURL with domain replaced by @)
MyAgentID <- "@" + http.agenturl().slice(29)
server.log("agentID: " + MyAgentID)
// Add agentID to this feed's tags
feed.addTag(MyAgentID)
// Get initial state
state <- feed.getStream("LED")
server.log(http.jsonencode(state))
device.send("update", state)
imp.configure("xively-shared-data-tags", [], [])
sw <- hardware.pin1
led <- hardware.pin2
sw.configure(DIGITAL_IN_PULLUP)
led.configure(DIGITAL_OUT)
agent.on("update", function(data) {
if("id" in data && data.id == "LED") {
local val = data.current_value.tointeger()
server.log("update: " + val)
led.write(val)
}
})
// toggle LED when switch is pressed
function readswitch() {
imp.wakeup(0.05, readswitch)
local now = sw.read()
if(now != prev && now == 0) {
local val = 1 - led.read()
led.write(val)
agent.send("put", { "LED": val })
}
prev = now
}
prev <- sw.read()
readswitch()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment