Category Archives: Arduino

Tinkur Park Assist


Val and I recently got a new car – a Subaru Outback.¬† The 12 year old Subaru Forester was still doing ok, but it was time to get a new car with better safety features.¬† However, the new Outback was a bit bigger – length and width.¬† And since we’d used up a significant¬†portion of our garage space for Tinkurlab’s workshop, I wanted to park the Outback as close to the garage door as possible to leave maximum room in front of the car to walk between the workshop and our house.¬† What to do?¬† Hang a tennis ball from the ceiling?¬† Not for a maker!¬† Time for a new project!

Introducing Tinkur Park Assist, a project to help you park your car irresponsibly close to the garage door, with only inches to spare.

“a project to help you park your car irresponsibly close to the garage door, with only inches to spare”


Tinkur Park Assist is pretty simple, consisting of an ultrasonic range sensor to determine the distance between the wall and the car, a big LED for feedback about the distance of the car from the sensor, and an Arduino to make sense of it all.  I initially used an IR distance sensor, but I found that an ultrasonic sensor works much better for the car which is highly reflective and curved.  It seems accurate to within an inch.

I also had the opportunity to design my own housing for the project to hide all the messy wires and electronics.  I chose to 3D print the housing, which was much easier vs. previous housings that were constructed of acrylic milled with a CNC machine.  After a few iterations of the 3D model design, I was able to create a housing that has openings in all the right spots and has an easy to add / remove snap-on lid.

How it Works?

Tinkur¬†Park Assist continuously monitors the distance between the ultrasonic sensor and whatever is in front of it.¬† If the distance hasn’t changed in a while, the LED light turns off.¬† When the distance starts changing, the LED light turns yellow¬†as the object in front of it gets into close range (< 5.5 feet in this case) and turns green when the object is in the ideal range (30 to 38 inches from the sensor in this case).¬† If the object is too close (< 30 inches), the LED turns red.¬† Tinkur Park Assist also saves the 3x last distance values, using the median value for making decisions¬†to reduce false positives from random fluctuations in data (ex. a person walking in front of the sensor).

What’s Next?

I’ll give some time to test Tinkur¬†Park Assist.¬† I think likely iterations may include:

  • Tweaking trigger distances.
  • Increasing the sampling rate for faster LED changes.
  • Tweaking the “no motion detected” logic and thresholds to make sure the LED is off when a car isn’t approaching.

How to Learn More?

Check out the docs and source code at

Check out the 3D model at

Tagged , , , ,

Every Idea Needs a ???

Demo of my hackathon to create an interactive LED display that allows people to add and remove words to a public wall art installation.  1st place overall winner.

Source code available at

TinkurWash – A Talking Dishwasher

I love technology because it enables new ways of solving old problems.

TinkurWash HipChat

Working in an office with only a single kitchen and 50+ busy software engineers, testers, and designers, my coworkers use quite a few dishes throughout each day. The kitchen is the hub of the office – a communal space for eating, talking, and taking a break. However it’s also easy for dishes to pile up, especially since there’s only one dishwasher. ¬†To maximize the capacity of the dishwasher its important to make sure it gets loaded, washed, and emptied as soon as possible so its ready for the next set of dishes. While most of my coworkers help with the dishwasher from time to time, its use isn‚Äôt always optimized with dishes stacking up on the counter and in the sink. ¬†Someone may not realize the dishwasher is full and needs started.¬† Someone else may think the dishwasher is still washing when really its dry and needs unloaded, especially since the office dishwasher‚Äôs status light is on the top of the door and the dishwasher is fairly quiet.


I wanted to give the dishwasher a voice – a social experiment. If the dishwasher could talk to people – telling them when it needs run or when it needs unloaded – would it help optimizing the flow of dishes? Most people want to be helpful, but sometimes they need better instrumentation and information.

TinkurWash v1.0.0

I started prototyping TinkurWash earlier in the year.  The initial concept was to instrument the dishwasher using vibration, temperature, tilt, etc to deduce when the dishwasher is in its various cycles. I wanted to instrument the dishwasher in a non invasive manner, allowing the solution to be added to an existing dishwasher without having to wire directly into the dishwasher. I decided to use an Arduino as the base platform, also deciding to use the Adafruit CC3000 WiFi shield as this project needed to be located near the dishwasher potentially far away from wired networking connections.


The initial prototype used a temperature sensor for heat detection, a piezo sensor for vibration detection, and a tilt sensor for detecting if the door is open, and a RGB led to provide visual feedback about the dishwasher’s status. This was my first time working with a piezo sensor and tilt sensor. When working with new sensors, I start by writing a small unit of code that demonstrates the capabilities of the sensor. I save this sketch in a unit test directory of my project. This not only helps me to learn about the sensor, buy also provides documentation for future reference and a test in case there are issues in the future. These unit examples are especially useful when debugging the sensor after it’s integrates into a larger code base with multiple sensors and other hardware components.


After integrating the unit examples together, the next step was to learn how to use this instrumentation to determine the state of the dishwasher.  I temporarily mounted an Arduino with sensors to the dishwasher. I ran the dishwasher and recorded a log of sensor readings over time to understand the values that occurred during washing, drying, unloading, etc. Vibration steadily increased as the dishwasher began fling with water, washed, and rinsed the dishes. Temperature rose more slowly, peaking part way through the washing and rinsing cycle and continuing through the drying cycles. So how to use this information?


I outlined the questions I needed to answer.


Is the dishwasher running?
When the dishwasher is not running, there is very little vibration and it occurs inconsistently when it does occur.  These random vibrations might occur when opening the dishwasher to add dirty dishes, opening an nearby cabinet, or even walking nearby. However when the dishwasher is washing and rinsing it generates significant and fairly sustained vibration over a long period of time. However, the levels of vibration can very between different dishwashers, so I implemented a function to baseline the ambient vibration when TinkurWash boots up. I also implemented a median library and function which records the 10 most recent vibration readings, using the median value to eliminate outlier data. When the median vibration is greater than 3x the baseline vibration, the dishwasher is assumed to be in a running status.  The LED also changes color when the dishwasher is in a washing status.


Is the dishwasher drying?
When the dishwasher is drying, vibrations return to near baseline levels, however temperature continues to remain high during drying. While a temperature sensor did provide the ability to measure temperature and dedice the drying cycle length, it also required mounting the temperature sensor fairly close to the dishwasher. After some consideration of the best mounting options, I decided to remove the sensor. From a user’s perceptive, they could remove the dishes from the dishwasher after the washing cycle and dry the dishes by hand – a realistic scenario. Therefore, I added another state to differentiate between washing and drying, changing the LED color as well to provide a visual indicator so a user can take action if desired. ¬†Since I removed the temperature sensor, I simplified the drying status using a 60 minute timer to approximate the length of the drying cycle. While I may add a temperature sensor in the future, the timer solution seemed adequate for an initial minimal viable product.

TinkurWash Beta Testing at Work

Is the dishwasher done and needs unloaded?
When the 60 minute timer completes, the dishwasher is assumed to be in a clean status and ready to be unloaded. Using a tilt sensor, I could determine when the dishwasher door was open. Based on timing my own usage, it seemed to take me at least a few minutes to fully unload the dishwasher. Therefore, similar to the drying state solution of using a timer, if the dishwasher door is open for more than 60 seconds it’s called beside red to be unloaded.


Is the dishwasher ready to be loaded with dirty dishes?
This one is a bit trickier. How does one measure when a dishwasher needs to be washed. ¬†As a user, you‚Äôll probably know that you like to run the dishwasher every night after dinner or just have packed it full of dishes and know it needs washed. ¬†For now, TinkurWash provides visual feedback via its LED that it’s ready for dirty dishes and washing, however, it’s the users responsibility to run it. In the future, I anticipate using data collected from the sensors to determine the users patterns and proactively ask them if the dishwasher needs to be run based on those patterns.



There are a variety of ways TinkurWash can communicate with users.
TinkurWash has a large diffused RGB led so users can easily see its status from just a glance.

TinkurWash Status Colors

In addition to providing glanceable visual feedback about the status of the dishwasher, it is also integrated with our company’s chat tool – HipChat. Each of our teams had their own HipChat room in addition to a whole company chat room used for questions, news, or just chatting. TinkurWash posts messages to the company wide chat room when it starts washing or finishes drying, providing real time information that will hopefully help my coworkers take care of the dishes.


Every 30 seconds TinkurWash connects to Xively, a service for storing and retrieving IoT data.  TinkurWash stores the median vibration value, the tilt value, the dishwasher door status, the dishwasher status, and an uptime value since the last reboot.  These values are useful for debugging, are used with another integration with Zapier to post messages to HipChat, and also store the data for future use in algorithms to determine when to recommend running the dishwasher and other potentially other insights.

Learning and Pivoting

TinkurWash has had many pivots along the way Рas most projects do.  While I plan to discuss some of these in more detailed standalone posts to provide lessons learned, , the following major pivots occurred:


After having issues mounting and monitoring vibration using a piezo sensor, I switched to using a 3 axis accelerometer. ¬†A¬†accelerometer can be used to measure movement over time, which provided to add an even greater level of granularity to the vibration instrumentation. ¬†The accelerometer also replaced the tilt sensor, providing the ability to determine if the dishwasher door is tilted and again providing much greater granularity.¬† While the accelerometer ($15) is 700% the cost of a piezo ($1) and tilt ($1) sensors it’s much more reliable and is still a very acceptable costs for a hobby project.¬† While the outcome was much better, refactoring hardware + software is somewhat more involved than refactoring software alone.


I finally wanted to have a proper housing for this project. In the past, I’ve used boxes or storage containers as a poor mans housing for my projects.  I had cutting acrylic with my CNC machine in the past, but hadn’t made a useable housing for a project.  After having the opportunity to see the Adafruit Raspberry Pi Thermal Printer housing when assembling a printer kit, I saw how awesome an acrylic housing can be and an example of how to fabricate one.  After a few pivots of the design using cardboard in inlace of acrylic, I fabricated a slot fit acrylic housing, learning lots of lessons Рand breaking a few bits Рalong the way.  I also hope to write another poshope to write another post on this topic in the future.


After getting TinkurWash‚Äôs sensors and code fairly reliable, I started noticing it stopped posting data anywhere from a few hours to a few days. ¬†After reading around the internet about the CC3000 WiFi chip, I read about similar stability issues. ¬†After trying a few different solutions, including a firmware upgrade, I ultimately implemented a watchdog timer that resets TinkurWash if a successful network connection isn’t made every 60 seconds. ¬†Before resetting, TinkurWash stores it’s current state into non volatile EEPROM memory, reloading the state variables from EEPROM after rebooting.

Source Code


What’s Next

While I certainly have some ideas for new features to enhance the smartness of TinkurWash, including more advanced algorithms using historical data, for now my primary focus is beta testing in the office to monitor stability, learn about any unanticipated real world scenarios, and collect user feedback.

TinkurCrate – Where’s The Dog?!


One of my favorite things about the Internet of Things is “giving a voice to things”. ¬†And who’s more deserving of a voice – and a Twitter account – than our roommate’s dog, Tyr. ¬†Tyr, an English Springer Spaniel enjoys running, playing with his toys, and hanging out in his crate. ¬†In fact, he’s got a fancy crate located in a prime location in our living room. ¬†TinkurCrate is the first in a series of projects to learn more about Tyr’s activities and connect him to the IoT. ¬†TinkurCrate uses an Arduino with Ethernet and a proximity sensor to determine when Tyr is in his crate. ¬†The Arduino posts the data to Xively for storage, which sends Web Hook triggers to Xively when Tyr enters and exits his crate – triggering Tweets on TinkurLab’s IO Twitter account –¬†@TinkurLabIO.





Wiring for the project is pretty simple, just connect the proximity sensor to the Arduino Ethernet shield as follows:

  • Red to 5v
  • Black to Ground
  • Yellow to Analog Pin 5

TinkurCrate Wiring



<br />/*<br /><br />Published:  2014<br />Author:     Adam - TINKURLAB<br />Web:<br /><br />Copyright:  This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.<br /><br />Contributors:<br />-Xively code based on<br />-Median library<br /><br /><%%KEEPWHITESPACE%%> */<br /><br />#include &lt;SPI.h&gt;<br />#include &lt;Ethernet.h&gt;<br />#include "RunningMedian.h"<br /><br />#define APIKEY         "xxxxxxxxxxx" // replace your Xively API Key here<br />#define FEEDID         xxxxxxxxxxx // replace your Xively Feed ID here<br />#define USERAGENT      "TinkurCrate" // user agent is the project name<br /><br />// assign a MAC address for the ethernet controller.<br />// Newer Ethernet shields have a MAC address printed on a sticker on the shield<br />// fill in your address here:<br />byte mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // replace your Mac Address here<br /><br />// fill in an available IP address on your network here,<br />// for manual configuration:<br />//IPAddress ip(10,0,1,20);<br />// initialize the library instance:<br />EthernetClient client;<br /><br />char server[] = "";   // name address for xively API<br /><br />unsigned long lastConnectionTime = 0;          // last time you connected to the server, in milliseconds<br />boolean lastConnected = false;                 // state of the connection last time through the main loop<br />const unsigned long postingInterval = 10*1000; //delay between updates to<br /><br />int modeSwitch = 1;<br /><br />int incrate = 0;<br /><br />RunningMedian proximityLast10 = RunningMedian(10);<br /><br />int timesincrate = 0;<br /><br />int sensorReading = 0;<br /><br />int sensorReadingMedian = 0;<br /><br />void setup() {<br /><%%KEEPWHITESPACE%%>  // Open serial communications and wait for port to open:<br /><%%KEEPWHITESPACE%%>  Serial.begin(9600);<br /><br /><%%KEEPWHITESPACE%%>  delay(2000);<br /><br /><%%KEEPWHITESPACE%%> // Connect to network amd obtain an IP address using DHCP<br /><%%KEEPWHITESPACE%%>  if (Ethernet.begin(mac) == 0)<br /><%%KEEPWHITESPACE%%>  {<br /><%%KEEPWHITESPACE%%>    Serial.println("DHCP Failed, reset Arduino to try again");<br /><%%KEEPWHITESPACE%%>    Serial.println();<br /><%%KEEPWHITESPACE%%>  }<br /><%%KEEPWHITESPACE%%>  else<br /><%%KEEPWHITESPACE%%>  {<br /><%%KEEPWHITESPACE%%>    Serial.println("Arduino connected to network using DHCP");<br /><%%KEEPWHITESPACE%%>    Serial.println();<br /><%%KEEPWHITESPACE%%>  }<br />}<br /><br />void loop() {<br /><br /><%%KEEPWHITESPACE%%>  if (modeSwitch == 1)<br /><%%KEEPWHITESPACE%%>  {<br /><%%KEEPWHITESPACE%%>    // read the analog sensor:<br /><%%KEEPWHITESPACE%%>    sensorReading = analogRead(A5);<br /><br /><%%KEEPWHITESPACE%%>    proximityLast10.add(sensorReading);<br /><br /><%%KEEPWHITESPACE%%>    sensorReadingMedian = proximityLast10.getMedian();<br /><br /><%%KEEPWHITESPACE%%>    Serial.println();<br /><br /><%%KEEPWHITESPACE%%>    Serial.print("Proximity: ");<br /><%%KEEPWHITESPACE%%>    Serial.println(sensorReading);<br /><br /><%%KEEPWHITESPACE%%>    Serial.print("Median Proximity: ");<br /><%%KEEPWHITESPACE%%>    Serial.print(sensorReadingMedian);<br /><%%KEEPWHITESPACE%%>    Serial.print(" w/ ");<br /><%%KEEPWHITESPACE%%>    Serial.print(proximityLast10.getCount());<br /><%%KEEPWHITESPACE%%>    Serial.println(" samples");<br /><br /><%%KEEPWHITESPACE%%>    delay(1000);<br /><br /><%%KEEPWHITESPACE%%>    if (sensorReadingMedian &gt; 160)<br /><%%KEEPWHITESPACE%%>    {<br /><%%KEEPWHITESPACE%%>      incrate = 1;<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    if (sensorReadingMedian &lt; 100)<br /><%%KEEPWHITESPACE%%>    {<br /><%%KEEPWHITESPACE%%>      incrate = 1;<br /><%%KEEPWHITESPACE%%>    }<br /><br /><%%KEEPWHITESPACE%%>    Serial.print("Is In Crate: ");<br /><%%KEEPWHITESPACE%%>    Serial.println(incrate);<br /><br /><%%KEEPWHITESPACE%%>    Serial.println();<br /><br /><%%KEEPWHITESPACE%%>  }<br /><br /><%%KEEPWHITESPACE%%>  // convert the data to a String<br /><%%KEEPWHITESPACE%%>  String dataString = "proximity,";<br /><%%KEEPWHITESPACE%%>  dataString += String(sensorReadingMedian);<br /><br /><%%KEEPWHITESPACE%%>  // you can append multiple readings to this String to<br /><%%KEEPWHITESPACE%%>  // send the xively feed multiple values<br /><%%KEEPWHITESPACE%%>  dataString += "\nincrate,";<br /><%%KEEPWHITESPACE%%>  dataString += String(incrate);<br /><br /><%%KEEPWHITESPACE%%>  // if there's incoming data from the net connection.<br /><%%KEEPWHITESPACE%%>  // send it out the serial port.  This is for debugging<br /><%%KEEPWHITESPACE%%>  // purposes only:<br /><%%KEEPWHITESPACE%%>  if (client.available()) {<br /><%%KEEPWHITESPACE%%>    char c =;<br /><%%KEEPWHITESPACE%%>    Serial.print(c);<br /><%%KEEPWHITESPACE%%>  }<br /><br /><%%KEEPWHITESPACE%%>  // if there's no net connection, but there was one last time<br /><%%KEEPWHITESPACE%%>  // through the loop, then stop the client:<br /><%%KEEPWHITESPACE%%>  if (!client.connected() &amp;&amp; lastConnected) {<br /><%%KEEPWHITESPACE%%>    Serial.println();<br /><%%KEEPWHITESPACE%%>    Serial.println("disconnecting.");<br /><br /><%%KEEPWHITESPACE%%>    resetMode();<br /><br /><%%KEEPWHITESPACE%%>    client.stop();<br /><br /><%%KEEPWHITESPACE%%>  }<br /><br /><%%KEEPWHITESPACE%%>  // if you're not connected, and ten seconds have passed since<br /><%%KEEPWHITESPACE%%>  // your last connection, then connect again and send data:<br /><%%KEEPWHITESPACE%%>  if(!client.connected() &amp;&amp; (millis() - lastConnectionTime &gt; postingInterval)) {<br /><br /><%%KEEPWHITESPACE%%>    modeSwitch = 2;<br /><br /><%%KEEPWHITESPACE%%>    sendData(dataString);<br /><%%KEEPWHITESPACE%%>  }<br /><%%KEEPWHITESPACE%%>  // store the state of the connection for next time through<br /><%%KEEPWHITESPACE%%>  // the loop:<br /><%%KEEPWHITESPACE%%>  lastConnected = client.connected();<br /><br />}<br /><br />// this method makes a HTTP connection to the server:<br />void sendData(String thisData) {<br /><br /><%%KEEPWHITESPACE%%>  // if there's a successful connection:<br /><%%KEEPWHITESPACE%%>  if (client.connect(server, 80)) {<br /><%%KEEPWHITESPACE%%>    Serial.println("connecting...");<br /><%%KEEPWHITESPACE%%>    // send the HTTP PUT request:<br /><%%KEEPWHITESPACE%%>    client.print("PUT /v2/feeds/");<br /><%%KEEPWHITESPACE%%>    client.print(FEEDID);<br /><%%KEEPWHITESPACE%%>    client.println(".csv HTTP/1.0");<br /><%%KEEPWHITESPACE%%>    client.println("Host:");<br /><%%KEEPWHITESPACE%%>    client.print("X-ApiKey: ");<br /><%%KEEPWHITESPACE%%>    client.println(APIKEY);<br /><%%KEEPWHITESPACE%%>    client.print("Content-Length: ");<br /><%%KEEPWHITESPACE%%>    client.println(thisData.length());<br /><br /><%%KEEPWHITESPACE%%>    // last pieces of the HTTP PUT request:<br /><%%KEEPWHITESPACE%%>    client.println("Content-Type: text/csv");<br /><%%KEEPWHITESPACE%%>    client.println("Connection: close");<br /><%%KEEPWHITESPACE%%>    client.println();<br /><br /><%%KEEPWHITESPACE%%>    // here's the actual content of the PUT request:<br /><%%KEEPWHITESPACE%%>    client.println(thisData);<br /><%%KEEPWHITESPACE%%>    Serial.println(thisData);<br /><br /><%%KEEPWHITESPACE%%>    client.println();<br /><br /><%%KEEPWHITESPACE%%>  }<br /><%%KEEPWHITESPACE%%>  else {<br /><%%KEEPWHITESPACE%%>    // if you couldn't make a connection:<br /><%%KEEPWHITESPACE%%>    Serial.println("connection failed");<br /><%%KEEPWHITESPACE%%>    Serial.println();<br /><%%KEEPWHITESPACE%%>    Serial.println("disconnecting.");<br /><%%KEEPWHITESPACE%%>    client.stop();<br /><%%KEEPWHITESPACE%%>  }<br /><%%KEEPWHITESPACE%%>   // note the time that the connection was made or attempted:<br /><%%KEEPWHITESPACE%%>  lastConnectionTime = millis();<br />}<br /><br />void resetMode()<br />{<br /><%%KEEPWHITESPACE%%> modeSwitch = 1;<br /><%%KEEPWHITESPACE%%> incrate = 0;<br />}<br />

Source code also available on GitHub at


Xively Setup

Xively is a service for powering the Internet of Things, providing API access for data storage, data retrieval, triggers, and data charting.  After registering for a free Xively account, perform the following steps:

1) Add Device.

2) Add Channels for “incrate” and “proximity”.


3) Setup Triggers for “incrate” status change. ¬†One Trigger calls the Zappier “Entering Crate” Zap, and the other Trigger calls the Zappier “Exiting Crate” Zap.



Zapier Setup

Zapier is a service for orchestrating and automating the Internet of Things and popular online services.  After registering for a free Zapier account, perform the following steps:

1) Create a new Zap, using a Web Hook – Catch Hook event, triggering a Twitter – Crate Tweet event.


2) Authorize your Twitter account if needed, and add a Filter to only trigger when the Xively trigger is “1” (when the dog enters the crate).


3) Setup a Message to post to Twitter and save the Zap.


You can view Tyr’s live status at¬† and his Tweets at¬†@TinkurLabIO.

What’s Next

While TinkurCrate is a good beginning, I hope to add a few more sensors to Tyr’s world. ¬†Possibilities include:

  • Pressure sensors to determine when Tyr is on the sofa
  • Continuity sensor to determine when Tyr’s water bowl is empty
  • Processing visualization of Tyr’s in crate / out of crate activity by time of day and day of week

Have any other ideas or suggestions.  Tweet @TinkurLab.



Das Bot 2.0 – Now with more beer!

How quickly time goes by. ¬†It seems like we only just completed Das Bot v1.0, but with Oktoberfest 2012 quickly approaching we started one of the biggest projects we’ve completed to date – Das Bot 2.0. ¬†Instrumented¬†beer on a grand scale!

The final setup, ready for the party to start.


Das Bot is a system for monitoring and controlling access to beer through RFID tags. Built on top of an internet-connected Arduino, the system accepts an RFID tag,¬†checks¬†to make sure you’re registered, opens the solenoid valves in the beer lines, lets you pour a beer and monitors how much you’ve poured, saves the data to a database, and prints out a receipt. Oh, and there’s prize badges you can win as well. There were three beers on tap this year (a homebrewed Dunkelweizen, a homebrewed Hefeweizen, and a Hofbrauhaus Oktoberfest) and each beer was tracked independently.

The Hardware

Das Bot contains the following pieces of hardware:

  • Arduino (with Ethernet shield) – the brains of the operation. This¬†micro controller¬†is what reads the RFID tags, talks to the PHP/MySQL site, controls the solenoid valves, prints to the thermal printer, and reads the data from the flow meters.
  • RFID Reader – reads the values from the RFID chips and sends the value to the Arduino.
  • 3 Solenoid Valves – similar to the ones on Adafruit’s site, these valves are normally closed (restricting access to vital beer) and are only opened when the Arduino gives the go ahead. After 10 seconds of no beer flowing, they close again. Since these draw more current and run at 12v, we used an old 12v wall wart we had laying around to power these (through the relay).
  • RelayThis relay controls the power to the solenoids.
  • 3 Flow Meters – we used the ones from Adafruit to send the flow data to the Arduino.
  • Thermal Printer – printed a welcome message, current stats, and final pour total for each pour.
  • Electrical Box – from the big box home improvement store, this water (and beer-proof) project enclosure was perfect for housing the Arduino, printer, and other electrical components.
  • RGB LED – when the light turns blue, pour your beer
  • Piezzo Buzzer – something this complicated needs to beep. Ours beeps when an RFID is successfully read.
  • Jockey Box – this converted cooler has a 7-pass plate chiller inside and once covered with ice, chills the beer as it flows through. This means no need to keep the kegs in giant plastic tubs with 800lbs of ice.
  • Tap Handles – no jockey box is complete without custom milled tap handles.
  • The Override Switch – this can not be over-appreciated. Buried in an undisclosed location was a switch that would override the arduino and open the solenoid valves. In the event of catastrophic failure, this is the switch represented the difference between beer and no beer. I’m always going to support the side with beer.

Closeup shot of the solenoids

The override switch. Luckily, this wasn’t needed this year. But it’s nice to know it’s there.


The Software

The hardware was almost the easy part of this project. We had experience with Das Bot v1.0, so adding some additional sensors wasn’t too difficult. The hard part was getting everything to talk to each other at the right times, with the right data.
Here’s what the software side looked like:
  • Arduino code – this is the air traffic control system. When an RFID chip is read, it sends the data to a web service and gets back the user’s current status. If they’re not registered, they get one (and ONLY one) free beer before they’re required to register. The flow meters are opened and activity from the meters is recorded. After 10 seconds of no flow, the system closes the valves and sends the pour volume data to the web service. The Arduino then prints out a receipt listing pour volumes and any badges that were won on this pour.
  • PHP/MySQL – a website used to store and present data during the party. The web service components were built using some simple PHP with a MySQL back end. The dashboard (running on an iPad taped inside the kitchen window during the party) presented current keg stats, leaderboards, badge summary, and other interesting bits of info. We also included the calibration for the flow meters in the database to allow for different keg sizes and to help more accurately record the data.

The welcome message displayed once an RFID tag is scanned

 The Dashboard

Want to become mayor of the Hofbrauhaus? Brag about having the largest drinking vessel? Why not turn an entire party into a drinking game? With all of the data we were collecting, it seemed natural to present this information back to the user. The thermal printer can only present so much data. The kegs were also under the table, making the “just lift it to see how much is left” method rather difficult. So, we created the dashboard to give a quick way to see how much fun we were having (note to self: next year, add a “fun” meter).

The dashboard presented the current leaders, the amount of beer consumed for each keg, the 5 most recent pours, and some other random stats. Some badges were mysteries, only visible once unlocked. Others were hinted at by the icon. Either way, the best way to win a badge was to drink beer. Actually, that was the only way.

How much fun are we having right now? Oh, THAT much. This was displayed on an iPad safely taped to the inside of the kitchen window. It was visible from the taps.

Future Enhancements

Some ideas for the 2013 Oktoberfest:

  • Integrate the photobooth¬†– haven’t been inside the booth in the last hour? No beer for you!
  • More badges to win – need target different needs in people’s psyche, not just the “I drank more than you did” desire
  • Allow “offline” badges – someone won the beer stein race, but we’ll never remember who it was. We’ll need a way to award spot badges from mobile devices.
  • More notifications when a badge is won – I’m thinking car horns, disco balls, or fireworks. Perhaps all three.
  • Breathalyzer integration – imagine tracking this against the volume consumed overlayed with the photobooth pictures. None of our friends will ever be politicians.


Additional images from the project:


RFID chips. Everyone got one. There were also zip ties to attach the chips to your beer stein.

The custom tap handles came out well.

The system, all condensed.

Water and electricity don’t mix, so we taped the electronics inside the cooler to the lid.

Additional photos can be found on Flickr




*Disclaimer – Please note that this system was built for responsible adults. EVERY person in the “leader boards” either spent the night (and likely much of the next day) at the location or were driven home by a designated driver. We might mix water, beer, and electricity together from time to time, but we certainly don’t drink and drive.

Tagged , , , , ,

BBQ Lab (v1.3) – Dashboard

While BBQ Lab captures all sorts of good data – its equally important to make that data into useful information that can easily be used. ¬†While BBQ Lab has always used Google Charts for visual graphs and trending, BBQ Lab v1.3 included quite a few new visualizations including the new “gauge” view that has a round gauge for each metric – smoker temperature, smoker humidity, food temperature, and smoke density. ¬†Each gauge contains a min and max value and is color coded for ideal (green), ok (yellow), and bad (red) ranges, which allow for easy viewing.


BBQ Lab 1_3 Screenshot 1.fw


BBQ Lab v1.3 also includes “over time trends” to show trends in the metrics over time. ¬†This can be useful to identify trends and take action. ¬†Ex. smoke density is decreasing – add wood.

BBQ Lab 1_3 Screenshot 2.fw


The data can also be correlated together to provide meaningful information about “events”. ¬†In this event, more wood was added to the smoker. ¬†The act of opening the smoker to add wood decreased the temperature by allowing hot air our and cool air in. ¬†The wood is also soaked in water to prolong its smoking; however, this initially reduces the smoke output until some of the water evaporates, which also temporarily increased the humidity. ¬†Therefore, ¬†this series of data could be correlated together programmatically¬†to identify a “wood added” event.

BBQ Lab 1_3 Correlation Analysis New Wood.fw



BBQ Lab (v1.3) – Smoke Density

BBQ is about low, slow, and smoke. And while the temperature sensors in BBQ Lab have already take care of the low and slow part, none of the instrumentation really addresses the smoke part. ¬†So the newest upgrade to BBQ Lab in v1.3 is the addition of a smoke sensor that measures the smoke in parts per million. ¬†I’m not actually as concerned with the exact measurement of the smoke as I am within the ability to relatively measure it throughout the duration off a BBQ.

The sensor is relatively simple – a MQ-2 sensor that detects the presence of smoke in parts per million and outputs an analog voltage that corresponds to the measurement range of the sensor. A 0 voltage corresponds to the low range of the sensor and a 1023 voltage corresponds to the high range of the sensor. Everything else in between represents gradients between the ranges. I any case what matters to me is identifying a reading that corresponds what I consider “good smoke output” and displaying the measurements via the trending graphs and real time alerts so I can take action based on the information.
BBQ Lab Propane Sensor

MQ-2 Smoke Sensor

BBQ Lab Propane Sensor

Knob to Adjust Sensitivity

I also ordered a bunch of other gas sensors, including a MQ-6 sensor that detects the presence of propane gas, which I’m to use to detect when the smoker’s flame blows out – such as on windy days. ¬†I’m also working on adding a automated propane control value that throttles the propane to achieve an ideal temperature – so the sensor can be used as part of a safety control system.
Hopefully I’ll be making a BBQed Brisket this week – so stay tuned for notes, pictures, and video.
Tagged , , , ,

Das Bot – Instrumented Beer

Oktoberfest is a big thing – BFD – in our household. We love beer, we love sausage, and we love hanging out with our friends. So what better way to celebrate those things then an annual Oktobesfest party. Our first “Fest” was held one week before my wife and I got married in 2008. It was informal and ad hoc – some bratwurst sausages, six packs of good beer, and friends sitting around a firepit on our side patio. Since those days, Fest has grown into a much bigger affair, complete with an Oktoberfest tent, photobooth, stump, homemade sausages, and homemade beer compliments of Matt and Matt – two of our friends who are also excellent beer brewers.

We first hosted the Matt’s beers at the second Fest, creating The Trasherator out of a large rubber trashcan fitted with 3x beer taps and ample space for ice and 3x 1/6 beer kegs. So what could make this situation any better you ask. Das Bot! ¬†Das Bot is an Instrumented version of The Trasherator that measures how much beer is consumed by each guest and keeps a running total of consumption complete with a leader board of stats.
The scenario works like this:

  1. A new drinker pickups a small key chain RFID tag and swipes it over Das Bot’s tag reader. A led light blinks confirming the tag has been read.
  2. If its a new drinker, Das Bot prints a message using a thermal receipt printer welcomes the drinker, asking the drinker to register, and advising the drinker they will recieve one beer without registering. If its an existing drinker, Das Bot prints a message with the drinkers consumption total.
  3. Das Bot opens solenoid valve in the beer lines enabling the flow of beer. The drinker has up to 10 seconds of inactive beer flow to pour as much beer as they want. As the beer is being pored, Das Bot is keeping track of how many ounces have been poured using a flowmeter in the beer line.
  4. Once the drinker has stopped pouring beer, Das Bot prints a message with the drinkers new total consumption and a summary of the top three consumers.
  5. Das Bot also has a web interface tat can be accessed via desktop and mobile web browsers enabling drinkers to register, provide their nickname, and check the overall leader board and % of beer renaming in the keg.

Das Bot v1.0 was a big project so I enlisted the help of my friend Matt. Matt and I only started the project in earnest about a week and a half before Fest. We started with a envisioning session with a whiteboard, identifying the overall features and process flow, and discussing implementation plans and potential risks. We self assigned work based on our abilities and focusing on higher risk features first. While Matt worked on the enclosure, mounting, and wiring, I wrote code for each individual component – the RFID reader, the solenoid, the flowmeter, the Ethernet network interface and web service calls. After figuring out the electrical interfaces and code for each component, I started coding them together into the over process. Matt and I would periodically break to discuss progress, make additional implementation decisions, and help each other with impediments. We worked this way for a few nights, making steady progress. Matt also created the web service interface and web site. After some hasty testing Fest was upon us. As a final feature we added a kill switch that would bypass the system allowing beer to flow freely in the event of a malfunction. There’s noting worse for a beer dispensing robot then angry beer drinkers with no beer.

“There’s noting worse for a beer dispensing robot then angry beer drinkers with no beer…”

And so the day came – the day of Fest. With all the other preparations we were a bit rushed to setup Das Bot but successfully installed it on a single 1/6 keg. At first, all seemed well. But soon we found that Das Bot was only pouring for 10 seconds regardless of if there was flow or no flow. Translation – only 10 seconds of beer. Not enough to fill a 1L stein. Angry beer drinkers. They put up with it for a bit, but we eventually activated the kill switch to placate the drinkers.
A few weeks later Matt and I sat down to triage the bug. It turns out we missed a single line of code that activated a pull up resistor on the Arduino board that stabalized the reading from the flowmeter. Turns out the flowmeter wasn’t registering any flow they tripping the 10 second cut off and thereby angering the beer drinkers. One line of code. Sigh. But we fixed it! And did more extensive testing this time. Das Bot is patiently waiting for the next Fest – and maybe a few summer BBQs (for beta testing of course).


  • Arduino Uno
  • Arduino Ethernet Shield
  • Solenoid value
  • Flowmeter
  • RFID reader
  • Thermal receipt printer and paper
  • PHP code and Database and server running Apache and mySQL
  • Website
  • Misc supplies ‚Äď wire, tools, etc

Das Bot v.Next Potential Features

  • Badges awarded for certain achievements
  • Adding support for additional beer lines
  • Improving packaging to allow for faster setup and teardown, especially for quick connections for beer inflow and outflow lines
  • Addition of breathalyzer to track each users progression over time
  • Itegration with the Photubooth that earns credits that can be redeemed for beer
  • Integration with Twitter


Tagged , ,

Visualization and RoadLogger

As I recently tweeted, “Information is no longer a scarce resource – attention is”. ¬†While technology, the internet, and the web of things have made amazing things possible, they have also given rise to vast amounts of information that are accessible almost anywhere at anytime. ¬†Given this overload of information and often trying to find better way to determine what information is relevant and to improve the effectiveness¬†of¬†consuming¬†it, I’ve recently found myself intrigued by data visualization – taking lots of data, analyzing¬†it , and presenting it in a visual way that conveys a different point of view then the data could alone. ¬†As a photographer, the phase “a picture is worth a¬†thousand¬†words” comes to mind. ¬†And so to learn a bit more about this area of tinkuring, a few months ago I started reading¬†Visualize This: The FlowingData Guide to Design, Visualization, and Statistics¬†in which Nathan Yah¬†describes his approach to visualization, including tools, approach, design – quite an interesting mash up of¬†disciplines.

Realizing the first step towards visualization if to have data to¬†analyze, I created a Arduino project called RoadLogger to use on a roadtrip to New England last summer with Val. ¬†RoadLogger (v1.0) logged the location, speed, altitude, direction, and driver of our car ever second, using a USB GPS antenna and a microSD card to data storage. ¬†While I haven’t had time to post info about RoadLogger and finish¬†analyzing¬†the 32,000+ datapoints, I’ve been thinking about what might be interesting way to analyize the data and present it visually. ¬†Here’s a quick list of thoughts:

  • How many miles did each driver drive?
  • What was our average speed per state?
  • Who was the faster driver?
  • What was the average time from 0 – 60 mph per driver?
Any other ideas?

Until I get around to doing some more work on this project, check out my first basic¬†visualization¬†“Am I A Foodie”¬†at another one of my blogs Until It’s Done.


Tagged , , ,