Project tutorial
Work Logger - Log Your Daily Work with a Turn of a Knob

Work Logger - Log Your Daily Work with a Turn of a Knob © GPL3+

The Work Logger helps you log your daily work without any effort - no more spreadsheets needed.

  • 10 views
  • 0 comments
  • 0 respects

Components and supplies

Mkr wifi 1010 usibb9nl4v
Arduino MKR WiFi 1010
×1
09939 01
Rotary potentiometer (generic)
×1
2.13inch E-Ink raw display, three-color
The display is not really required. I used the Work Logger about half an year without it.
×1
wooden case
I created the case out of laser cut plywood. For designing the case I used the awesome service of https://www.festi.info/boxes.py/
×1

Necessary tools and machines

09507 01
Soldering iron (generic)

Apps and online services

About this project

The Work Logger is a little everyday helper to log my working time. It tracks WHEN I am doing WHAT. And it does this with just little turn of a knob.

Problem

As a business analyst, I work in different projects. And in those projects I do different things. At the end of the day I try to remember what I spent my working time on - which is usually not easy after a long day. I used pen and paper, spread sheets and other tools, but they all somehow involved to much effort to use them.

Solution

The hardware Work Logger is basically a turn knob that points to what I am currently working at. So it takes one turn to record my work. As soon as I do not turn the potentiometer any more for 3 seconds it sends the current work position to a google forms questionnaire. Google takes care of adding a timestamp. At the end of the day I have a list of my jobs done on a Google spreadsheet.

Code

worklogger.inoArduino
#include <SPI.h>
#include<WiFiNINA.h>

// display includes
#include <fonts.h>
#include <epdpaint.h>
#include <epd2in13b.h>
#include <epdif.h>


// -----------------------------------------------------------------------
// Variables
// -----------------------------------------------------------------------

const int potPin = A1;          // potentiometer pin
int pot_val = 0;                // Value of potentiometer pin
int pot_val_sum = 0;            // sum of 10 measures of pot_val
int current_position;           // current position
int new_position;               // position read from poti
int stable_count = 0;           // counts how many times current and new position are the same;
char ssid[] = "e.g. AndroidAP";    // your network SSID (name)
char pass[] = "aaa....";        // your network password (use for WPA, or use as key for WEP)
char server[] = "docs.google.com"; // google forms server
int status = WL_IDLE_STATUS;    // 
WiFiSSLClient client;           // client object which does the calls

// --- some variables for the display output
unsigned long start_time;       // stores millis, used to update progress bar
char progress_bar[9] = "[......]"; // progress bar
int progress_bar_pos = 1;

#define COLORED   0
#define UNCOLORED 1

unsigned char image[1024];
Paint paint(image, 28,192);    //width should be the multiple of 8 
Epd epd;
// ------- end of display output variables

String jobs[11] = { 
  "A Admin", 
  "A Testing", 
  "A Analysis", 
  "A Coord",
  "B Admin",
  "B Coord",
  "B Analysis",
  "B Testing",
  "Internal training",
  "internal admin",
  "Pause"
};

// -----------------------------------------------------------------------
// Functions
// -----------------------------------------------------------------------
/*
takes value from the poti and returns the position of the pointer
*/
int calculate_position(float val) {
  int position = 10;
  if(val < 20) position = 0;
  else if(val < 96) position = 1;
  else if(val < 213) position = 2;
  else if(val < 316) position = 3;
  else if(val < 458) position = 4;
  else if(val < 598) position = 5;
  else if(val < 721) position = 6;
  else if(val < 838) position = 7;
  else if(val < 936) position = 8;
  else if(val < 1010) position = 9;
  else position = 10;
  
  return position;
}


/*
Defines job strings for sending to backend
*/
String storeWork(int pos) {

  // the Serial.print commands are just for debugging.
  Serial.print("storing job ");
  Serial.println(jobs[pos]);
  
  String jobdata = jobs[pos];
  jobdata.replace(" ", "%20"); // replace '%20' with empty spaces 

  // https://www.instructables.com/id/Post-to-Google-Docs-with-Arduino/ explains how to get the correct
  // google form url and the endtry id
  if (client.connectSSL(server, 443)) {
    client.print("GET http://docs.google.com/forms/d/e/ <id of your google form> /formResponse?entry.<id of your google forms entry field number>=");
    client.print(jobdata);
    client.println(" HTTP/1.1");
    client.println("Host: docs.google.com");
    client.println("Cache-Control: no-cache");
    client.println("Connection: close");
    client.println();
    }
    // set start time for progress_bar timer
    start_time = millis();

    // reset progress Bar
    for (int i = 1; i < 7; i++) {
      progress_bar[i] = '.';
      }
    progress_bar_pos = 1;

      
     
    drawString(jobdata);

    // drawProgressBar(); //TODO: uncomment if new display is super fast updating
    // currently I do not draw a progress bar after selecting a new job
    
    return "ok";
}

/*
 * Draw String on EPD
 */
void drawString(String jobdata) {
  // replace %20
  jobdata.replace("%20", " ");
  
  // convert String to char Array
  char jobchars[30];
  jobdata.toCharArray(jobchars,30);
  
  epd.ClearFrame();
  paint.SetRotate(ROTATE_90);

  paint.Clear(UNCOLORED);
  paint.DrawStringAt(8, 2, jobchars, &Font16, COLORED);
  epd.SetPartialWindowBlack(paint.GetImage(), 50, 16, paint.GetWidth(), paint.GetHeight());

  epd.DisplayFrame();
};

/*
 * draw progress bar on EPD
 */
void drawProgressBar() {
  paint.Clear(UNCOLORED);
  paint.DrawStringAt(8,2, progress_bar, &Font16, COLORED);
  epd.SetPartialWindowBlack(paint.GetImage(), 20, 16, paint.GetWidth(), paint.GetHeight());
  epd.DisplayFrame();
}

/*
 * update progress_bar string
 */
 void updateProgressBar() {
  // calculate time_past
  if (millis() - start_time > 300000) { //do stuff every 5 minutes
    if (progress_bar_pos < 7) {
      progress_bar[progress_bar_pos] = '=';
      progress_bar_pos++;
      drawProgressBar();
      }
    start_time = millis();  // reset time to current
    
    }
  
 }

// -----------------------------------------------------------------------
// Setup
// -----------------------------------------------------------------------
void setup() {

 
  pinMode(potPin, INPUT);
  Serial.begin(9600);
  delay(1000);

Serial.println("init Display");
  // initilize Display
 
 if (epd.Init() != 0) {
    Serial.print("e-Paper init failed");
    return;
  }
    
  // attempt to connect to Wifi network:
  while (status != WL_CONNECTED) {
     
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(7000);
  }
  Serial.println("Connected to wifi");
  
  current_position = -1;
    
}

// -----------------------------------------------------------------------
// Loop
// -----------------------------------------------------------------------

void loop() {
  // read potentiometer value 10 times and get average to flatten out outlier readings 
  // of the potentiometer
  for (int i = 0; i < 10; i++) {
    pot_val = analogRead(potPin);
    pot_val_sum = pot_val_sum + pot_val;
  }
  float flat_pot_val = pot_val_sum/10;

  pot_val_sum = 0; // reset to 0 for next loop.

  // Serial.println for debug
  Serial.println(flat_pot_val);
  new_position = calculate_position(flat_pot_val);

  // only store new job if potentiometer was not moved for one second
  // like this I avoid storing several jobs when the user turns the knob all over 
  // the scale
  if (new_position != current_position) {
    stable_count = 0;
  }
  if (stable_count == 1) {
    storeWork(new_position);
  }
  current_position = new_position; 
  stable_count++;

  // update progress bar
  updateProgressBar();

  delay(1000);
}

Schematics

easy version without display
Wiring of the easy version just having a potentiometer as a turn knob, without the e-paper display.
Breadboard easy epj1prrkzt
full version including e-paper
This schematic shows the full version including the e-paper hat wirings. Since the Arduino MKR 1010 WIFI uses SPI to communicate to the WiFi module, I ran into SPI pin conflicts. So I had to change the Pin definition of my epd2in13b library for the waveshare disply. I changed the file 'epdif.h' like this:

// Pin definition
#define RST_PIN 6
#define DC_PIN 5
#define CS_PIN 4
#define BUSY_PIN 7
Breadboard e paper aab74kqhv5

Comments

Similar projects you might like

Turn Lights On When Approaching Home

Project tutorial by Andrei Florian

  • 15,091 views
  • 33 comments
  • 45 respects

Logifox: The End of E-Waste Has Arrived

Project tutorial by Luis Roda Sánchez and Celia Garrido Hidalgo

  • 6,628 views
  • 0 comments
  • 13 respects

SmartWay

Project tutorial by Andrei Florian

  • 6,684 views
  • 9 comments
  • 14 respects

Fox Advisor

Project tutorial by Celia Garrido Hidalgo

  • 3,860 views
  • 2 comments
  • 13 respects

PhoneLocator

Project tutorial by Andrei Florian

  • 7,412 views
  • 12 comments
  • 28 respects

Measure LUX with Arduino Using BH1750

Project tutorial by afsh_ad

  • 7,260 views
  • 0 comments
  • 4 respects
Add projectSign up / Login