Skip to content

Instantly share code, notes, and snippets.

@analog-io
Created January 28, 2015 05:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save analog-io/2d1713f47f41a6c600e9 to your computer and use it in GitHub Desktop.
Save analog-io/2d1713f47f41a6c600e9 to your computer and use it in GitHub Desktop.
Water Meter Electric Imp Code
// 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);
// 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