Create a gist now

Instantly share code, notes, and snippets.

@alexbain /agent.nut
Last active Feb 15, 2016

What would you like to do?
Electric Imp code (agent & device) for a laundry monitoring device. Read more at $BLOG_POST (tbd)
// Run on Agent
// Thresholds to adjust for better accuracy
dataThreshold <- 300; // Minimum accelerometer value to count as ON
onThreshold <- 24; // Number of ON samples before machine enters RUNNING state
offThreshold <- 60; // Number of OFF samples before machine enters OFF state
// State variable
running <- false;
// Keep track of counts
onCount <- 0;
offCount <- 0;
// Twilio
twilioURL <- "https://USER:PASS@api.twilio.com/2010-04-01/Accounts/ID/Messages.json";
twilioHeaders <- { "Content-Type": "application/x-www-form-urlencoded" };
twilioNumber <- "+14155551212";
// Array of phone numbers to be contacted with the laundry is done
phoneNumbers <- ["+14155555555", "+14155555556"];
// Firebase
logToFirebase <- false;
firebaseURL <- "https://FIREBASE_URL.firebaseIO.com/data.json";
firebaseHeaders <- { "Content-Type": "application/json" };
// Called every time the imp emits data
device.on("data", function(data) {
// Is there enough accelerometer activity for the device to be considered ON?
if (data >= dataThreshold) {
onCount = onCount + 1;
// Prevent overflow errors by resetting onCount when it gets close to limit
if (onCount >= 65500) {
onCount = onThreshold;
}
// If the device has been ON for long enough, set running state to be true
if (onCount >= onThreshold) {
running = true;
// Running, so reset offCount
offCount = 0;
}
// debug / logs
if (running == true) {
server.log(format("ON - RUNNING (%f), onCount (%d), offCount (%d)", data, onCount, offCount));
} else {
server.log(format("ON (%f), onCount (%d), offCount (%d)", data, onCount, offCount));
}
// Imp is not recording much accelerometer movement, so device seems to be OFF
} else {
offCount = offCount + 1;
// Prevent overflow errors by resetting offCount when it gets close to limit
if (offCount >= 65500) {
offCount = offThreshold;
}
// Has the device been off for long enough to be "done"?
if (offCount >= offThreshold) {
// Was the device previously running?
if (running == true) {
// This means that the laundry had been running, and is now done.
// Send an SMS to each phone number in the phoneNumbers array.
foreach (number in phoneNumbers) {
local body = format("To=%s&From=%s&Body=The%%20laundry%%20is%%20done.", number, twilioNumber);
local request = http.post(twilioURL, twilioHeaders, body);
local response = request.sendasync(function(done) {});
}
// debug / logs
server.log("!!!! Emitting OFF event !!!!");
}
// Reset on count
onCount = 0;
// Machine is no longer running
running = false;
}
// debug / logs
if (running == true) {
server.log(format("OFF - WAS RUNNING (%f), onCount (%d), offCount (%d)", data, onCount, offCount));
} else {
server.log(format("OFF (%f), onCount (%d), offCount (%d)", data, onCount, offCount));
}
}
if (logToFirebase == true) {
// Build a post request to Firebase to log the data
local body = format("{\"amount\": %f, \"running\": %s, \".priority\": %d}", data, running ? "true" : "false", time());
local request = http.post(firebaseURL, firebaseHeaders, body);
// Send the data to Firebase async
local response = request.sendasync(function(done) {});
}
});
total <- 0; // Sum of % change from all samples
n <- 0; // Counter for number of samples read
last <- 1; // Previous reading of magnitude
function readSensor() {
// Time interval
local interval = 0.02;
// Get source voltage, should be 3.3V
local vRef = hardware.voltage();
// Read in ADC values from accelerometer
local adcRx = hardware.pin1.read();
local adcRy = hardware.pin2.read();
local adcRz = hardware.pin5.read();
// server.log(format("Raw ADC values: %f, %f, %f", adcRx, adcRy, adcRz));
// Convert 16bit ADC accelerometer values (0-65535) into voltage
local voltsRx = (adcRx * vRef) / 65535.0;
local voltsRy = (adcRy * vRef) / 65535.0;
local voltsRz = (adcRz * vRef) / 65535.0;
// server.log(format("Voltages: %f, %f %f", voltsRx, voltsRy, voltsRz));
// Subtract 0g (1.5V at 3V, 1.65V at 3.3V)
local deltaVoltsRx = voltsRx - (vRef / 2);
local deltaVoltsRy = voltsRy - (vRef / 2);
local deltaVoltsRz = voltsRz - (vRef / 2);
// server.log(format("Adjusted voltages %f, %f, %f", deltaVoltsRx, deltaVoltsRy, deltaVoltsRz));
// Convert from voltage to g, using sensitivity of 300mV
local rX = deltaVoltsRx / 0.3;
local rY = deltaVoltsRy / 0.3;
local rZ = deltaVoltsRz / 0.3;
// server.log(format("Gs: %f, %f, %f", rX, rY, rZ));
// Compute magnitude of force
local magnitude = math.sqrt(math.pow(rX,2) + math.pow(rY, 2) + math.pow(rZ, 2));
// Compute % change since last reading
local change = math.fabs((magnitude - last)/last) * 100.0;
// Store magnitude in last for next time
last = magnitude;
// Log magnitude and percent change
// server.log(format("magnitude: %f, change amount: %f", magnitude, change));
// Increment total with % change, increment N
total = total + change;
n = n + 1;
// Log data to server once ever 250 samples (5 seconds)
if (n >= 250) {
agent.send("data", total);
n = 0;
total = 0;
}
// Sleep until time to read sensor again
imp.wakeup(interval, readSensor);
}
// X input
hardware.pin1.configure(ANALOG_IN);
// Y input
hardware.pin2.configure(ANALOG_IN);
// Z input
hardware.pin5.configure(ANALOG_IN);
// Start reading the sensor
readSensor();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment