The agent firmware is a lot longer, but as you’ll see in a second, that’s because it contains two large chunks of code that do more general jobs.
The first thing the agent does when it boots up is to check and see if it’s just rebooted and already knows the device ID. Whenever the agent has to go and get the deviceID from the device, it saves it in the imp cloud with server.save() as soon as it gets the update. This way, if the agent ever restarts, it can grab the ID right away without even having to check in with the device by calling server.load():
// Device ID used to create new channels in this feed for each new turkey probe
config <- server.load();
if (!("myDeviceId" in config)) {
// grab the pre-saved device ID from the server if it's there
// if it isn't, we've never seen this device before (or the server forgot - unlikely!)
// we will request a device ID from the device if we make it past class declarations without
// the device doing an "I just woke up" check-in.
config.myDeviceId <- null;
}
Next, we run into a giant function with a very big multi-line string in it. This function is called prepWebpage, and all it does is concatenate a few strings together. These strings just so happen to be a web site. This web site is the web UI for the BBQ thermometer, and it’s what you see when you request the agentURL in a browser. Because the agent has the ability to set up its own HTTP handler, it can respond to certain requests by serving up this very long string — basically, the agent acts like a tiny web server. The web site even includes some simple javascript that runs on the client machine.
After the website, the agent has a function that keeps track of activity on the device and uses a timer and some simple heuristics to figure out if the device should go to sleep to save battery.
function checkSleepTimer() {imp.wakeup(TIMER_DEC_INTERVAL, checkSleepTimer);
sleepTimer -= TIMER_DEC_INTERVAL;
if (sleepTimer 30) {
sleepTimer += 60;
} else {
sleepTimer += delta * 2;
}
}
// don't let the sleep timer exceed the preset max.
if (sleepTimer > MAX_SLEEP_TIMER) {sleepTimer = MAX_SLEEP_TIMER};
local tempStr = format("%.1f",data.temp);
server.log("Temp: "+tempStr+" F");
// post the datapoint to the Xively feed
postToXively(tempStr, "temperature");
// check for low-battery issues
server.log("Battery: "+data.vbat+" V");
if (!lowBattAlarm && (data.vbat LOW_BATT_THRESH)) {
// clear the low batt alarm and post it to xively
lowBattAlarm = 0;
postToXively(lowBattAlarm, "lowbatt")
server.log("Low battery alert cleared.");
}
});
Because of how this device is wired up, it actually won’t ever trigger the low battery alarm; this was included for a similar device that was powered off of a pair of AA lithium batteries without a regulator between the batteries and the imp, so the imp could look at the battery voltage directly. The code was left in just in case anyone gets intrepid and builds one inside the original housing!
Near the bottom of the agent firmware, we see one of the most important parts of the agent: the HTTP request handler. This handler parses incoming HTTP requests and defines how the agent should respond.
http.onrequest(function(request, res) { server.log("Agent got new HTTP Request");
// we need to set headers and respond to empty requests as they are usually preflight checks
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers","Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
if (request.path == "/sleep" || request.path == "/sleep/") {
device.send("sleep",0);
res.send(200, "Going to Sleep");
} else {
server.log("Agent got unknown request");
res.send(200, WEBPAGE);
}
});
Most of the requests to the agent are going to be requests just for the web page, so requests without additional parameters just get the web page as a response. There’s also a “hook” here for external services to tell the imp to go to sleep, which the web page doesn’t use.
Lastly, the agent instantiates a Xively Client object which it will use during runtime to post data to the Xively stream, requests the deviceID if necessary, and starts running the sleep timer:
server.log("Turkey Probe Agent Started.");
// instantiate our Xively client
xivelyClient <- Xively.Client(XIVELY_API_KEY);
// in case we've just restarted the agent, but not the device, call the device for
// the device ID in 1 second if it doesn't ping us with an "I just booted" message
imp.wakeup(1, function() {
if (config.myDeviceId == null) { device.send("needDeviceId",0); } else { prepWebpage(); };
});
// start running the auto-sleep watchdog timer
checkSleepTimer();
And that’s all there is to it!
Good luck and bon appetit :)