Created
January 28, 2015 05:33
-
-
Save analog-io/2d1713f47f41a6c600e9 to your computer and use it in GitHub Desktop.
Water Meter Electric Imp Code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Create a data stream at data.sparkfun.com, then enter your keys here: | |
local publicKey = "xx" // enter public key here | |
local privateKey = "xx" // enter private key here | |
data_array <- array(800,[0,0,0,0]) | |
total <- 0 | |
conversion <- 4.95/476 | |
local req = http.get("https://data.sparkfun.com/output/"+o_publicKey+"/latest.json"); | |
local response = req.sendsync() | |
local data = http.jsondecode(response.body) | |
total = data[0].cnt_total.tointeger() | |
server.log(total) | |
function bufferRx(data) { | |
data_array <- data | |
local gpm = data_array[1][0].tofloat()*conversion*6.0 | |
local total_gal = total.tofloat()*conversion | |
// Prepare the phant headers | |
local phantHeaders = {"Phant-Private-Key": privateKey, "connection": "close"}; | |
// Create a post request | |
local req = http.post("http://data.sparkfun.com/input/"+publicKey, phantHeaders,"cnt="+gpm+"&cnt_total="+total_gal); | |
total += data_array[1][0] | |
//Send out the request! | |
server.log(gpm+" | "+total_gal+" | "+total+" | "+data_array[1][0]+" | "+data_array[1][1]+" | "+data_array[1][2]+" | "+req.sendsync().statuscode); | |
} | |
function request_handler(request, response) | |
{ | |
try | |
{ | |
// Process incoming http request | |
response.header("access-control-allow-origin", "*"); | |
// If everything worked as expected, send a standard 'OK' status code (200) | |
local r = "{" | |
local i=0 | |
local k=0 | |
r += "\"x\":[" | |
for (i=0;i<data_array[0].len();i++) { | |
if (i!=0) {r += ","} | |
r += data_array[0][i] | |
} | |
r += "]" | |
r+=",\"cnt\":"+data_array[1][0] | |
r+=",\"cnt_hf\":"+data_array[1][1] | |
r+=",\"cnt_lf\":"+data_array[1][2] | |
r+=",\"kalman\":"+data_array[1][3] | |
r+=",\"max\":"+data_array[1][4] | |
r+=",\"min\":"+data_array[1][5] | |
r+=",\"spread\":"+data_array[1][6] | |
r+=",\"amax\":"+data_array[1][7] | |
r+=",\"amin\":"+data_array[1][8] | |
r+=",\"thresh\":"+data_array[1][9] | |
r+="}" | |
response.send(200, r); | |
} | |
catch (exception) | |
{ | |
response.send(500, "Internal Server Error: " + exception); | |
} | |
} | |
device.on("buffer",bufferRx); | |
http.onrequest(request_handler); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Define a class for a ring buffer object with some analysis functions | |
class ring_buffer { | |
_depth = 0 | |
_index = 0 | |
_data = 0 | |
_buff = 0 | |
_fill = 0 | |
constructor(depth) { | |
_depth = depth | |
_data = array(depth,0) | |
_index = 0 | |
} | |
function insert(value) { | |
if (_index < _depth) | |
{ | |
_data[_index] = value | |
_index++ | |
} | |
else | |
{ | |
_data[0] = value | |
_index = 1 | |
} | |
if (_fill<=_depth){ | |
_fill++ | |
} | |
} | |
function z(relative_index){ | |
if ((_index-1-relative_index)>=0) | |
{ | |
return _data[_index-1-relative_index] | |
} | |
else | |
{ | |
return _data[_index-1-relative_index+_depth] | |
} | |
} | |
function dump(){ | |
local i = 0 | |
local buff = array(_fill,0) | |
for (i=0;i<_fill;i++) { | |
buff[i] = z(i) | |
} | |
return buff | |
} | |
function stringify(){ | |
local d = dump() | |
local string = "" | |
local i=0 | |
for (i=0;i<d.len();i++) { | |
string += d[i]+" " | |
} | |
return string | |
} | |
function stats(d){ | |
local min = 32767 | |
local max = -32767 | |
local i | |
for (i=0;i<d;i++) { | |
local t = z(i) | |
if (t>max){max=t} | |
if (t<min){min=t} | |
} | |
return [min,max,max-min] | |
} | |
function fill(){ | |
return _fill | |
} | |
function rolled_over(){ | |
return _fill>_depth | |
} | |
function reset(){ | |
_index = 0 | |
_fill = 0 | |
} | |
} | |
// Define the Sensor Address | |
const ADDR = 0x1C; | |
// Define register map | |
const OUT_X_MSB = "\x01"; | |
const CTRL_REG1 = "\x10"; | |
const CTRL_REG2 = "\x11"; | |
// Some useful bitmasks | |
const ACTIVE = "\x01"; | |
const AUTO_MRST_EN = "\x80"; | |
// Define the i2c periphrial being used | |
i2c <- hardware.i2c89; | |
// Interupt pin | |
int <- hardware.pin7; | |
// Config the i2c periph | |
i2c.configure(CLOCK_SPEED_400_KHZ); | |
// Set to auto reset int flag on read | |
i2c.write(ADDR,CTRL_REG2+AUTO_MRST_EN) | |
// Activate the MAG3110, sample at 80Hz | |
i2c.write(ADDR,CTRL_REG1+ACTIVE) | |
// Read the initial data to clear the isr flag | |
local data = i2c.read(ADDR,OUT_X_MSB,6); | |
// create a buffer for storing data | |
data_buffer <- ring_buffer(800); | |
// We're going to do some global min and max calculations | |
// So init the variables | |
min <- 32767 | |
max <- -32767 | |
// Initialize the threshold | |
thresh <- 0 | |
spread_thresh <- 100 | |
// Debouncing parameter | |
debounce <- 120 | |
// Some bools for oneshots | |
x_lf <- false | |
x_hf <- false | |
// Counters for counting the number of triggers | |
trigs <- 0 | |
x_trigs_lf <- 0 | |
x_trigs_hf <- 0 | |
k <- 0 | |
x_int <- 0 | |
x_int_neg <- 0 | |
// Interupt routine for getting MAG3110 measurements | |
function mag_isr() { | |
// Check for the rising edge | |
if (int.read()==1) | |
{ | |
// Read data from i2c | |
local data = i2c.read(ADDR,OUT_X_MSB,6); | |
// Combine the MSB and LSB into a 16bit value | |
local x = data[0]<<8 | data[1] | |
// Convert 2's compliment | |
if (x & 0x8000) {x = -((~x & 0x7FFF) + 1);} | |
// Detect for min and max, then calculate a new threshold | |
if (x<min) {min = x; thresh = min + (max-min)/2} | |
if (x>max) {max = x; thresh = min + (max-min)/2} | |
// Put data in buffer | |
data_buffer.insert(x) | |
// Get the count spread from the last 20 items | |
local stats = data_buffer.stats(20) | |
local spread = stats[2] | |
// Detect if measured value is above or below the threshold | |
if (x>thresh) { | |
// Logic for oneshot to count the crossing | |
if (!x_hf){ | |
x_hf = true | |
// Increment the high frequency counter | |
x_trigs_hf++ | |
if (spread > spread_thresh){trigs++} | |
} | |
// Integrate the measurement, this is for the debounce algorithim | |
x_int += (x-thresh) | |
// If integral exceeds the debounce parameter, time for the lf count | |
if (x_int>debounce) { | |
// Logic for oneshot to count the crossing | |
if (!x_lf) { | |
x_lf=true | |
// Increment the high frequency counter | |
x_trigs_lf++ | |
if (spread <= spread_thresh){trigs++} | |
// Reset the negative integral | |
x_int_neg = 0 | |
} | |
} | |
} | |
else { | |
// Reset the hf oneshot | |
x_hf = false | |
// Integrate the measurement under the threshold | |
x_int_neg += (thresh-x) | |
// If integral exceeds the threshold, time to reset the lf oneshot | |
if (x_int_neg>debounce) { | |
x_lf = false | |
// Reset the positive integral | |
x_int = 0 | |
} | |
} | |
//determine if buffer has reached the end | |
if (data_buffer.rolled_over()) | |
{ | |
if (spread>spread_thresh) { | |
k = x_trigs_hf | |
} | |
else { | |
k = x_trigs_lf | |
} | |
// Make sure min, max and threshold are stabilized before sending data | |
if ((max-min)>spread_thresh) | |
{ | |
// buffer is at end, send the data back to the agent | |
agent.send("buffer",[data_buffer.dump(),[trigs,x_trigs_hf,x_trigs_lf,k,stats[1],stats[0],stats[2],max,min,thresh]]) | |
} | |
// Reset the trigger counters | |
x_trigs_hf = 0 | |
x_trigs_lf = 0 | |
trigs = 0 | |
//reset the buffer and start all over again | |
data_buffer.reset() | |
} | |
} | |
} | |
// Configure the interrupt pin to run the mag_isr callback | |
int.configure(DIGITAL_IN, mag_isr) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment