How i built a physical IoT device and connected it to my bank account.

I’m not a full stack engineer, i live in the terminal, the CLI, and a mental map of clusters of machines i’ll never see.

But sometimes its nice to be able to look at something and passively just know something important about the world around you.

One particular piece of information thats important to just about everyone, is “how much of my pay is still in my bank account”.

This was my goal for the Mondo Meter (pictured above). The simplest possible UX for answering that question.

The physical device is a 3D printed gauge, with a servo connected to the A4 pins on a Particle Photon.

For this project i’m going to connect the Mondo web hooks, to a simple python/flask webapp running on Heroku.

It will catch and decode the webhook, and then POST to the particle.io cloud to update the servo position.

The code thats running on the Photon makes a function (gotoPos) available on the Particle Cloud.

This code is written in the Particle.io C-like language and compiled in their web-ide.

Servo myservo; // create servo object to control a servo

// a maximum of eight servo objects can be created



int pos = 0; // variable to store the servo position

int ll = D7; int gotoPos(String pos) {

myservo.write(pos.toInt());

return pos.toInt();

} void setup()

{

myservo.attach(A4); //Not all pins are created equal

pinMode(ll, OUTPUT);

Spark.function("gotoPos", gotoPos);

}





void loop()

{

}

I can then change the needle position by calling POSTing to:



# about half way between broke and payday curl -X POST \ ' https://api.particle.io/v1/devices/mondo_meter/gotoPos' -d '100' \# about half way between broke and payday

In order to correctly orientate the needle, somewhere between 0 (you’re broke) and 180 degrees (you just got paid), i need to know 2 pieces of information. What is my current balance? and what was my balance right after i last got paid?, (or topped up my Mondo account). Think of this second number as a kind of High Water Mark.

def angle(hwm, bal):

return int(180-(float(bal)/float(hwm)*180))

The Mondo Restful API is great, but we don’t want to keep hitting it so i’m going to register a webhook and then have a simple app on Heroku catch that webhook and remember what the high water mark is.

Right now, you’ll need to be an Alpha customer, and have asked us about obtaining a “client secret” in order to use our API, but pretty soon we’ll have “Personal Access Tokens” github-style that you can use for registering your own webhooks.

We’ve got a pretty amazing internal CLI which is much easier to use than curl (it handles the login and oauth refresh of tokens and has tab completion), so excuse my use of that here. I’ve scrambled all my personal data btw…

First i use the API to lookup what accounts are attached to my user..

mondo> api GET /accounts

{

"accounts": [

{

"account_number": "33123450",

"created": "2015-11-13T18:23:41Z",

"description": "Simon Vans-Colina",

"id": "acc_000012345678912345678",

"sort_code": "000001"

}

]

}

Then i can register a new webhook.

Lets see that webhook we just created.

Oh, yeah, i’ve got another webhook there, one i created to get the format of the json body Mondo will send. I’d better delete that. ❤ requestb.in

mondo> api DELETE /webhooks/webhook_097654323456788765

Cool, now all new transactions will be POSTed to my little heroku app.

What does that look like?

I followed this basic heroku tutorial: https://devcenter.heroku.com/articles/getting-started-with-python-o

and also added the heroku redis plugin.

The code is pretty simple:

import os

import requests

from flask import Flask, request

import redis

import os

import json app = Flask(__name__)

app.debug=True

r = redis.from_url(os.environ.get("REDIS_URL"))

def hello():

return "%s / %s" % (r.get("balance"), r.get("highwatermark")) @app .route('/')def hello():return "%s / %s" % (r.get("balance"), r.get("highwatermark"))

def balance():

return r.get("balance") @app .route('/balance')def balance():return r.get("balance")

def highwatermark():

return r.get("highwatermark") @app .route('/highwatermark')def highwatermark():return r.get("highwatermark")

def catch():

j = json.loads(request.data)

t = j['data']

if t['is_load'] == True:

r.set("highwatermark", int(t['account_balance']))

r.set("balance", int(t['account_balance']))

else:

r.set("balance", t['account_balance']) @app .route('/catch', methods=['POST'])def catch():j = json.loads(request.data)t = j['data']if t['is_load'] == True:r.set("highwatermark", int(t['account_balance']))r.set("balance", int(t['account_balance']))else:r.set("balance", t['account_balance']) if int(t['account_balance']) > int(r.get('highwatermark')):

r.set("highwatermark", int(t['account_balance'])) # here is where we will POST to the particle device to move the needle

return "%s / %s" % (r.get("balance"), r.get("highwatermark"))

This catches and decodes the webhook data and stores the current balance and high water mark (the balance when i topped up, or got paid last).

The code that dispatches the POST to particle cloud looks like this:



h=r.get("highwatermark")

b=r.get("balance")

data={"arg": angle(h,b)} #get the correct angle to send to the servo

headers={'Authorization': token}

req = requests.post("

data=data, \

headers=headers)

return "OK" def dispatch():h=r.get("highwatermark")b=r.get("balance")data={"arg": angle(h,b)} #get the correct angle to send to the servoheaders={'Authorization': token}req = requests.post(" https://api.particle.io/v1/devices/%s/gotoPos " % d, \data=data, \headers=headers)return "OK"

I hope you’ve enjoyed this quick look at the kind of thing you can build with Mondo. If you want to see this in person, sign up to our mailing list at https://getmondo.co.uk, follow @getmondo and me (@simonvc) on twitter and come along to our next hackathon where we’ll be giving out more of the amazing Mondo cards and API keys.