Introduction: TOYL Task Tracker

Don’t you just hate it when you’re planning to work or worse, are in the middle of a work session and a notification comes in on your phone—a “quick check” becomes hours later.
Also, do you know how much time you work on certain tasks in relation to the time you have allocated for work per week?

Enter the TOYL Task Tracker. It enables you to switch off your phone and focus on work, while simultaneously enabling you to set up the amount of time you’d like to work per week—say 60 hours—and the tasks that you’d like to get done. When you sit down for a session, you get an idea of how much time you have left for your overall work. The Tracker has two modes: Timer, where you’ve preset how much time you’d like to spend per task per week, and Stopwatch, where you can simply start-stop the timer after selecting a task.



  • Adafruit Feather Huzzah
  • Adafruit FeatherWing
  • Male header pins
  • Female header pins
  • 500mAh battery
  • 100K ohm resistors x2
  • Insulation tape
  • Stranded wire
  • Wire strippers
  • Solder Fan


  • Opaque acrylic sheet 24”x18”
  • Double sided tape
  • Access to a laser cutter
  • Vector software

Step 1: Solder Your Circuit

Solder the female header pins to the Feather Huzzah. This tutorial is useful for the Feather Huzzah hardware setup. Then, solder the male header pins to the FeatherWing. Soldering them in this manner allows you to join and separate the Feather Wing from the Feather Huzzah when required. This is especially handy when you need to add resistors to your FeatherWing, which is the next step. Connect 100K ohm resistors from each pin 0 and 2, connected to 3V.

Setup your Feather Huzzah hardware

Setup your Feather Wing hardware

Step 2: Add Your Code

This code is an adaptation of Lesson 5 Internet of Things code, Time permitting, I would have like to replace the Preceptitaton service with one that tracks tasks that are added via the ToDosit IFTTT applet. At the moment you would have to manually input a set of tasks and use Button A to cycle through them. In addition, I would have liked to have coded the timer to count in minutes and stop when switching to the next task. A huge thank you to Becky Stern for creating base code for the timer and cycling through tasks. If you are interested in connecting the project to the internet, I would highly recommend going through this set of classes.

<p>// Instructables Internet of Things Class sample code<br>// Circuit Displays Internet Data
// Weather data is collected in a feed
// Multiple NeoPixels visualize the weather condition
// Modified by Becky Stern 2017
// based on the Adafruit IO Subscription Example</p><p>// Adafruit invests time and resources providing this open source code.
// Please support Adafruit and open source hardware by purchasing
// products from Adafruit!
// Written by Todd Treece for Adafruit Industries
// Copyright (c) 2016 Adafruit Industries
// Licensed under the MIT license.
// All text above must be included in any redistribution.</p><p>/************************ Adafruit IO Configuration *******************************</p><p>/ visit if you need to create an account,
// or if you need your Adafruit IO key.
#define IO_USERNAME    "YourUsernameHere"
#define IO_KEY         "YourIOKeyHere"</p><p>/******************************* WIFI Configuration **************************************/</p><p>#define WIFI_SSID       "WifiName"
#define WIFI_PASS       "WifiPassword"</p><p>#include "AdafruitIO_WiFi.h"
AdafruitIO_WiFi io(IO_USERNAME, IO_KEY, WIFI_SSID, WIFI_PASS);</p><p>/************************ Main Program Starts Here *******************************/
#include </p><p>#include 
#include </p><p>#define OLED_RESET 3
Adafruit_SSD1306 display(128, 32, &Wire, OLED_RESET);</p><p>// this constant won't change:
const int buttonPinA = 0;     // the pins that the pushbuttons are attached to
const int buttonPinB = 16;    // this one already has a pullup resistor, the other two need one
const int buttonPinC = 2;</p><p>// Variables will change:
int buttonAPushCounter = 0;   // counter for the number of button presses
int buttonAState = 0;         // current state of the button
int lastButtonAState = 0;     // previous state of the button</p><p>// Variables will change:
int buttonBPushCounter = 0;   // counter for the number of button presses
int buttonBState = 0;         // current state of the button
int lastButtonBState = 0;     // previous state of the button</p><p>// Variables will change:
int buttonCPushCounter = 0;   // counter for the number of button presses
int buttonCState = 0;         // current state of the button
int lastButtonCState = 0;     // previous state of the button</p><p>String displayForecast = "unknown";</p><p>int timerVal = 0;
unsigned long lastStartTime = 0;
bool timerEnabled = 0;</p><p>AdafruitIO_Feed *precipitation = io.feed("precipitation"); // set up the 'precipitation' feed
//AdafruitIO_Feed *taskmanager = io.feed("taskmanager"); // set up the 'taskmanager' feed</p><p>void setup() {
  pinMode(buttonPinA, INPUT);
  pinMode(buttonPinB, INPUT_PULLUP);
  pinMode(buttonPinC, INPUT);</p><p>  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // Address 0x3C for 128x32</p><p>  // Show initial display buffer contents on the screen --
  // the library initializes this with an Adafruit splash screen.
  delay(2000); // Pause for 2 seconds</p><p>  // Clear the buffer.
  display.clearDisplay();</p><p>  // start the serial connection
  Serial.begin(115200);</p><p>  // connect to
  Serial.print("Connecting to Adafruit IO");
  // set up a message handler for the 'precipitation' feed.
  // the handleMessage function (defined below)
  // will be called whenever a message is
  // received from adafruit io.
  precipitation->onMessage(handleMessage);</p><p>  // wait for a connection
  while(io.status() < AIO_CONNECTED) {
  }</p><p>  // we are connected
  Serial.println(io.statusText());</p><p>}</p><p>void loop() {</p><p>  //; is required for all sketches.
  // it should always be present at the top of your loop
  // function. it keeps the client connected to
  //, and processes any incoming data.;</p><p>    // read the pushbutton input pin:
  buttonAState = digitalRead(buttonPinA);
  buttonBState = digitalRead(buttonPinB);
  buttonCState = digitalRead(buttonPinC);</p><p>  // compare the buttonState to its previous state
  if (buttonAState != lastButtonAState || buttonBState != lastButtonBState || buttonCState != lastButtonCState) {
    // if the state has changed, increment the counter
    if (buttonAState == LOW) {
      // if the current state is LOW then the button was pressed
      Serial.print("number of A button pushes:  ");
    if (buttonBState == LOW) {
      // if the current state is LOW then the button was pressed
      Serial.print("number of B button pushes:  ");
      Serial.println("Starting timer");
      timerEnabled = 1;
      lastStartTime = millis();
    if (buttonCState == LOW) {
      // if the current state is LOW then the button was pressed
      Serial.print("number of C button pushes:  ");
      Serial.println("Stopping timer");
      timerEnabled = 0;
 if (timerEnabled == 1){ // increment the timer only when it's been started
  timerVal = (millis() - lastStartTime)/1000;
  }</p><p>  //display position 1 - forecast
//  if (buttonAPushCounter % 3 == 0) {
//    display.clearDisplay();
//    display.setTextSize(1);
//    display.setTextColor(WHITE);
//    display.setCursor(0,0);
//    display.print("Forecast: ");
//    display.println(displayForecast);
//    display.setCursor(0,16);
//    display.println("second line ");
//    display.println("example content");
//    display.display();
//    //delay(2000);
//  }</p><p>  //display position 1 - Task 1
  if (buttonAPushCounter % 3 == 0) {
    display.println("Research - Interviews");
    display.print("Timer: ");
  }</p><p>  //display position 2 - Task 2
  if (buttonAPushCounter % 3 == 1) {
    display.println("Making Studio - Code");
    display.print("Timer: ");
  }</p><p>  //display position 3 - Task 3
  if (buttonAPushCounter % 3 == 2) {
    display.println("DSV - Sketching");
    display.print("Timer: ");
  // save the current state as the last state,
  //for next time through the loop
  lastButtonAState = buttonAState;
  lastButtonBState = buttonBState;
  lastButtonCState = buttonCState;</p><p>}</p><p>// this function is called whenever a message
// is received from Adafruit IO. it was attached to
// the feed in the setup() function above.
void handleMessage(AdafruitIO_Data *data) {
  </p><p>  String forecast = data->toString(); // store the incoming weather data in a string
  Serial.print("received <- ");
  displayForecast = forecast;
  //the following strings store the varous IFTTT weather report words I've discovered so far
  String task1 = String("Task 1");
  String rain = String("Rain");
  String lightrain = String("Light Rain");
  String rainshower = String ("Rain Shower");
  String AMshowers = String ("AM Showers");
  String rainandsnow = String("Rain and Snow");
  String snow = String("Snow");
  String snowshower = String("Snow Shower");
  String cloudy = String("Cloudy");
  String mostlycloudy = String("Mostly Cloudy");
  String partlycloudy = String("Partly Cloudy");
  String clearsky = String("Clear");
  String fair = String("Fair");
  String sunny = String("Sunny");</p><p>  // These if statements compare the incoming weather variable to the stored conditions, and control the NeoPixels accordingly.
  // if there's rain in the forecast
  if (forecast.equalsIgnoreCase(rain) || forecast.equalsIgnoreCase(lightrain) || forecast.equalsIgnoreCase(rainshower) || forecast.equalsIgnoreCase(AMshowers)){
    Serial.println("precipitation in the forecast today");</p><p>  }
  // if there's snow in the forecast
  if (forecast.equalsIgnoreCase(snow) || forecast.equalsIgnoreCase(rainandsnow) || forecast.equalsIgnoreCase(snowshower)){
    Serial.println("precipitation in the forecast today");</p><p>  }
  // if there's sun in the forecast
  if (forecast.equalsIgnoreCase(clearsky) || forecast.equalsIgnoreCase(fair) || forecast.equalsIgnoreCase(sunny)){
    Serial.println("some kind of sun in the forecast today");</p><p>  }
  // if there're clouds in the forecast
  if (forecast.equalsIgnoreCase(cloudy) || forecast.equalsIgnoreCase(mostlycloudy) || forecast.equalsIgnoreCase(partlycloudy)){
    Serial.println("cloudy sky in the forecast today");</p><p>   }</p><p>  

Step 3: Create the Container / Shell

For the shell, start by determining what size you would like your frame to be, or you could download my file. Once you determine the size you can use MakerCase to create the layout for the vector file.

Run the file through the laser cutter - it should take about 5 minutes. Thereafter put the shell together.

I didn’t account for the width of the material which makes my buttons difficult to reach. I still need to find a way to attach them. They are also very small which makes them difficult to work with.