Search

Work Logger - Log Your Daily Work With A Turn Of A Knob

About the project

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

Project info

Items used in this project

Hardware components

Arduino MKR1000 Arduino MKR1000 x 1
Rotary Potentiometer Module Rotary Potentiometer Module x 1
2.13inch E-Ink display HAT for Raspberry Pi & Arduino yellow/black/white 3 color e paper 2.13inch E-Ink display HAT for Raspberry Pi & Arduino yellow/black/white 3 color e paper x 1
wooden case 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/ x 1

Software apps and online services

Google Forms Google Forms

Hand tools and fabrication machines

Soldering iron (generic) Soldering iron (generic) x 1

Story

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.ino Arduino

  1. #include <SPI.h>
  2. #include<WiFiNINA.h>
  3.  
  4. // display includes
  5. #include <fonts.h>
  6. #include <epdpaint.h>
  7. #include <epd2in13b.h>
  8. #include <epdif.h>
  9.  
  10.  
  11. // -----------------------------------------------------------------------
  12. // Variables
  13. // -----------------------------------------------------------------------
  14.  
  15. const int potPin = A1; // potentiometer pin
  16. int pot_val = 0; // Value of potentiometer pin
  17. int pot_val_sum = 0; // sum of 10 measures of pot_val
  18. int current_position; // current position
  19. int new_position; // position read from poti
  20. int stable_count = 0; // counts how many times current and new position are the same;
  21. char ssid[] = "e.g. AndroidAP"; // your network SSID (name)
  22. char pass[] = "aaa...."; // your network password (use for WPA, or use as key for WEP)
  23. char server[] = "docs.google.com"; // google forms server
  24. int status = WL_IDLE_STATUS; //
  25. WiFiSSLClient client; // client object which does the calls
  26.  
  27. // --- some variables for the display output
  28. unsigned long start_time; // stores millis, used to update progress bar
  29. char progress_bar[9] = "[......]"; // progress bar
  30. int progress_bar_pos = 1;
  31.  
  32. #define COLORED 0
  33. #define UNCOLORED 1
  34.  
  35. unsigned char image[1024];
  36. Paint paint(image, 28,192); //width should be the multiple of 8
  37. Epd epd;
  38. // ------- end of display output variables
  39.  
  40. String jobs[11] = {
  41. "A Admin",
  42. "A Testing",
  43. "A Analysis",
  44. "A Coord",
  45. "B Admin",
  46. "B Coord",
  47. "B Analysis",
  48. "B Testing",
  49. "Internal training",
  50. "internal admin",
  51. "Pause"
  52. };
  53.  
  54. // -----------------------------------------------------------------------
  55. // Functions
  56. // -----------------------------------------------------------------------
  57. /*
  58. takes value from the poti and returns the position of the pointer
  59. */
  60. int calculate_position(float val) {
  61. int position = 10;
  62. if(val < 20) position = 0;
  63. else if(val < 96) position = 1;
  64. else if(val < 213) position = 2;
  65. else if(val < 316) position = 3;
  66. else if(val < 458) position = 4;
  67. else if(val < 598) position = 5;
  68. else if(val < 721) position = 6;
  69. else if(val < 838) position = 7;
  70. else if(val < 936) position = 8;
  71. else if(val < 1010) position = 9;
  72. else position = 10;
  73. return position;
  74. }
  75.  
  76.  
  77. /*
  78. Defines job strings for sending to backend
  79. */
  80. String storeWork(int pos) {
  81.  
  82. // the Serial.print commands are just for debugging.
  83. Serial.print("storing job ");
  84. Serial.println(jobs[pos]);
  85. String jobdata = jobs[pos];
  86. jobdata.replace(" ", "%20"); // replace '%20' with empty spaces
  87.  
  88. // https://www.instructables.com/id/Post-to-Google-Docs-with-Arduino/ explains how to get the correct
  89. // google form url and the endtry id
  90. if (client.connectSSL(server, 443)) {
  91. 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>=");
  92. client.print(jobdata);
  93. client.println(" HTTP/1.1");
  94. client.println("Host: docs.google.com");
  95. client.println("Cache-Control: no-cache");
  96. client.println("Connection: close");
  97. client.println();
  98. }
  99. // set start time for progress_bar timer
  100. start_time = millis();
  101.  
  102. // reset progress Bar
  103. for (int i = 1; i < 7; i++) {
  104. progress_bar[i] = '.';
  105. }
  106. progress_bar_pos = 1;
  107.  
  108. drawString(jobdata);
  109.  
  110. // drawProgressBar(); //TODO: uncomment if new display is super fast updating
  111. // currently I do not draw a progress bar after selecting a new job
  112. return "ok";
  113. }
  114.  
  115. /*
  116. * Draw String on EPD
  117. */
  118. void drawString(String jobdata) {
  119. // replace %20
  120. jobdata.replace("%20", " ");
  121. // convert String to char Array
  122. char jobchars[30];
  123. jobdata.toCharArray(jobchars,30);
  124. epd.ClearFrame();
  125. paint.SetRotate(ROTATE_90);
  126.  
  127. paint.Clear(UNCOLORED);
  128. paint.DrawStringAt(8, 2, jobchars, &Font16, COLORED);
  129. epd.SetPartialWindowBlack(paint.GetImage(), 50, 16, paint.GetWidth(), paint.GetHeight());
  130.  
  131. epd.DisplayFrame();
  132. };
  133.  
  134. /*
  135. * draw progress bar on EPD
  136. */
  137. void drawProgressBar() {
  138. paint.Clear(UNCOLORED);
  139. paint.DrawStringAt(8,2, progress_bar, &Font16, COLORED);
  140. epd.SetPartialWindowBlack(paint.GetImage(), 20, 16, paint.GetWidth(), paint.GetHeight());
  141. epd.DisplayFrame();
  142. }
  143.  
  144. /*
  145. * update progress_bar string
  146. */
  147. void updateProgressBar() {
  148. // calculate time_past
  149. if (millis() - start_time > 300000) { //do stuff every 5 minutes
  150. if (progress_bar_pos < 7) {
  151. progress_bar[progress_bar_pos] = '=';
  152. progress_bar_pos++;
  153. drawProgressBar();
  154. }
  155. start_time = millis(); // reset time to current
  156. }
  157. }
  158.  
  159. // -----------------------------------------------------------------------
  160. // Setup
  161. // -----------------------------------------------------------------------
  162. void setup() {
  163.  
  164. pinMode(potPin, INPUT);
  165. Serial.begin(9600);
  166. delay(1000);
  167.  
  168. Serial.println("init Display");
  169. // initilize Display
  170. if (epd.Init() != 0) {
  171. Serial.print("e-Paper init failed");
  172. return;
  173. }
  174. // attempt to connect to Wifi network:
  175. while (status != WL_CONNECTED) {
  176. Serial.print("Attempting to connect to SSID: ");
  177. Serial.println(ssid);
  178. // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
  179. status = WiFi.begin(ssid, pass);
  180.  
  181. // wait 10 seconds for connection:
  182. delay(7000);
  183. }
  184. Serial.println("Connected to wifi");
  185. current_position = -1;
  186. }
  187.  
  188. // -----------------------------------------------------------------------
  189. // Loop
  190. // -----------------------------------------------------------------------
  191.  
  192. void loop() {
  193. // read potentiometer value 10 times and get average to flatten out outlier readings
  194. // of the potentiometer
  195. for (int i = 0; i < 10; i++) {
  196. pot_val = analogRead(potPin);
  197. pot_val_sum = pot_val_sum + pot_val;
  198. }
  199. float flat_pot_val = pot_val_sum/10;
  200.  
  201. pot_val_sum = 0; // reset to 0 for next loop.
  202.  
  203. // Serial.println for debug
  204. Serial.println(flat_pot_val);
  205. new_position = calculate_position(flat_pot_val);
  206.  
  207. // only store new job if potentiometer was not moved for one second
  208. // like this I avoid storing several jobs when the user turns the knob all over
  209. // the scale
  210. if (new_position != current_position) {
  211. stable_count = 0;
  212. }
  213. if (stable_count == 1) {
  214. storeWork(new_position);
  215. }
  216. current_position = new_position;
  217. stable_count++;
  218.  
  219. // update progress bar
  220. updateProgressBar();
  221.  
  222. delay(1000);
  223. }

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

Schematics and circuit diagrams

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

Credits

Photo of Arduino

Arduino

Arduino is the world’s leading open-source hardware and software ecosystem. The Company offers a range of software tools, hardware platforms and documentation enabling almost anybody to be creative with technology.

   

Leave your feedback...