teig
Published © GPL3+

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

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

BeginnerFull instructions provided4,770
Work Logger - Log Your Daily Work with a Turn of a Knob

Things used in this project

Hardware components

Arduino MKR WiFi 1010
Arduino MKR WiFi 1010
×1
Rotary potentiometer (generic)
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

Software apps and online services

Google Forms

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Schematics

easy version without display

Wiring of the easy version just having a potentiometer as a turn knob, without the e-paper display.

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

Code

worklogger.ino

Arduino
#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);
}

Credits

teig

teig

2 projects • 5 followers

Comments