Budgets are far too easy to abandon, and far too personal to discuss with absolute transparency. Our team set out to address this product opportunity gap to help a customer actively keep pace with her budget.

Created: February 3rd, 2016



As a team, we first reflected on common pain points in our lives as consumers, considering circumstances when having "just a bit more” information could meaningfully improve our decision making. We quickly arrived at a realization that human beings are not rational consumers; that we almost look for excuses to spend more; that we often consume disproportionately within (and outside of) our budgets.

We explored conventional displays of consumption behavior in search of inspiration for an appropriately skeumorphic design. Initially, we were drawn to the communication of time passing on an analog watch; we recognized that, through a single 360 degree pass of a clock, X days of consumption and Y dollars of a budget ought go by at roughly the same pace.

For technical reasons related to the servos we used (explained more fully in our process section), we were forced to iterate this design; ultimately, looking further to the various synchronized gauges of a car dashboard, we found an opportunity to communicate something useful, useable and desirable for people spending on their cards without hesitation. 



Step 1: Controlling Hardware

Since we had to control two servos and an RGB LED, we had an issue with having too few pins for PWM. We accidentally used pins that shared the same PWM timer, which was causing glitches. When we switched to the TX and RX pins, the issue resolved.

We also had trouble understanding how to control the servos without burning them out. They don't like zero or 180 degree positions, so we constrained them to between 5 and 175 degree positions.

Step 2:  Pulling Data from Google Sheets

We looked at ways to create a simple web service to take Google Sheets data, digest it, and return a desired output. We ended up publishing the Google Sheets data as a live CSV file, and then used an existing PHP library for processing CSV files to manage the data. We then set up a web hook that pulls the data from the aforementioned PHP file and returns it to the Particle. Once on the Particle, the data string is parsed. 

Step 3: Physical Prototyping

As mentioned in our PROJECT section, we originally wanted to prototype this design in the form of a full-circle clock. However, since the hands need to move independently of each other, geometric constraints would keep it from working even if we used 360 servos. The solution is to use concentric drive shafts that are independently controlled by the two servos, but the mechanical complexity of this solution is outside the scope of this project.



The era of debit and credit card spending makes it especially easy to detach from a sense of financial wellbeing. By syncing with customers' credit and debit cards, Budget Buddy discreetly provides meaningful feedback on the health of its users’ rate of consumption, to help them make more accurate and responsible spending decisions.

This "works-like" prototype of Budget Buddy technology represents how much of a consumer's budget is spent relative to how much of the month is gone.

In its final form, Budget Buddy would be worn on the wrist of its consumer, in order to maximize the utility of the real-time insights it confers. Accordingly, next steps would involve soliciting the support of a mechanical engineer who could iterate in a smaller size and develop the mechanism that would allow us to control each of the clock hands independently of each other. We would also explore a 360 degree range of motion. Later iterations might involve more intricate displays of a rotation of budgets (ie., food, gas, entertainment etc), perhaps communicated via different background LEDs; perhaps they would also involve a linear display of projected proximity to lifetime savings goals, based on projections of repeating recent under-budget behaviors.



Below is the final Particle code and a video of our functioning Budget Buddy prototype. 

Budget Clock
	Budget Clock
  There is a webhook configured to grab data from
	@author Stephen Nomura, Josh Sirchio, Yubing Zhang
	@version 0.3

int rgbLedPins[] = { TX, D0, D1 };
int dayServoPin = A4;
int budgetServoPin = A5;

Servo dayServo;
Servo budgetServo;

float currentDay;
float daysInMonth;
int monthPercent;
int monthAngle;
int monthAnglePrev = -1;

float currentSpend = 0; // initial values prevent servo glitchout
float budget = 1;
int budgetPercent;
int budgetAngle;
int budgetAnglePrev = -1;

int minimumDeg = 10;
int maximumDeg = 170;

void setup(){
  /* SET PINS */
  pinMode(rgbLedPins[0], OUTPUT);
  pinMode(rgbLedPins[1], OUTPUT);
  pinMode(rgbLedPins[2], OUTPUT);

  setRgbLedByHex("#000000", rgbLedPins);

  /* CLOUD */
  // Listen for hook response
  Spark.subscribe("hook-response/getFinancialData", gotFinancialData, MY_DEVICES);


void loop(){


void updateDevice(){
  // update month hand
  Time.zone(-4); // Eastern Time
  currentDay = Time.day();
  /*currentDay = 0;*/
  daysInMonth = getDaysInMonth( Time.month() );
  monthPercent = currentDay / daysInMonth * 100;
  monthAngle = monthPercent * maximumDeg / 100;;
  if( monthAngle != monthAnglePrev ){
    setServoPosition(dayServo, monthAngle, TRUE );
  monthAnglePrev = monthAngle;

  // update budget hand
  budgetPercent = currentSpend / budget * 100;
  budgetAngle = budgetPercent * maximumDeg / 100;;
  if( budgetAngle != budgetAnglePrev ){
    setServoPosition(budgetServo, budgetAngle, FALSE );
  budgetAnglePrev = budgetAngle;

  // update LED
  if( budgetPercent < monthPercent ){
    setRgbLedByHex("#00FF00", rgbLedPins);
  else {
    setRgbLedByHex("FF0000", rgbLedPins);


void updateFinancialData(){
  Particle.publish("getFinancialData"); // trigger webhook

void gotFinancialData(const char *name, const char *data){
  String dataString = String(data);

  // https://stackoverflow.com/questions/11068450/arduino-c-language-parsing-string-with-delimiter-input-through-serial-interfa
  int commaIndex = dataString.indexOf(':');
  String firstValue = dataString.substring(0, commaIndex);
  String secondValue = dataString.substring(commaIndex+1);

  currentSpend = firstValue.toInt();
  budget = secondValue.toInt();

int setServoPosition(Servo &theServo, int angle, bool invert){
  // https://daraghbyrne.github.io/diotlabs/6-controlling-outputs/servo/
  int position = constrain(angle, minimumDeg , maximumDeg);
  if( invert ){
    position = position - 180;
    position = abs( position );
  theServo.write( position );
  return 1;

int setRgbLedByHex(String hex, int pins[]){
  if( hex.startsWith("#") ) hex = hex.substring(1);
  if( hex.length() != 6 ) return -1;
  analogWrite( pins[0], 255 - strtol(hex.substring(0,2),NULL,16) );
  analogWrite( pins[1], 255 - strtol(hex.substring(2,4),NULL,16) );
  analogWrite( pins[2], 255 - strtol(hex.substring(4,6),NULL,16) );
  return 1;

int setLED(String hex){
  setRgbLedByHex(hex, rgbLedPins);
  return 1;

int getDaysInMonth(int month){
  // http://www.engineersgarage.com/c-language-programs/display-number-days-month-using-switch-statement
    case 1:
    case 3:
    case 5:
    case 7:
    case 8:
    case 10:
    case 12:
      return 31;
    case 2:
      return 28; // ignores leap years, whatever
    case 4:
    case 6:
    case 9:
    case 11:
      return 30;
author Stephen Nomura, Josh Sirchio, Yubing Zhang Click to Expand


This project required siloing of responsibilities. Segmentation of duties was framed around sketching code; developing hardware; and documenting our process. The team coordinated deadlines and managed progress remotely, meeting in person to commit to a vision and partition assignments, to troubleshoot collaboratively, and to assemble and test our device. This system delivered a satisfying outcome.

Share this Project


49-713 Designing for the Internet of Things

· 4 members

This course charts the emergence of the now "connected world" to explore the possibilities for future products and connected spaces.


Budgets are far too easy to abandon, and far too personal to discuss with absolute transparency. Our team set out to address this product opportunity gap to help a customer actively keep pace with her budget.