This was a bit of a tricky project for me. I had several idea’s that seemed to bypass either the Arduino or p5.js completely. So, after my board kicked the bucket at 3 in the morning, I went back to the drawing board. Lately, I’ve been struggling with task management in terms of mustering up the courage to even begin. I was researching memory and multitasking for another class, when I stumbled upon something called The Pomodoro Technique. This is a technique that uses a timer to break down tasks into intervals of 25 minutes. The idea is to focus on something for 25 minutes straight, take a short break, then tackle another 25 minutes.
Using an RFID reader and tags, I sought to physicalize the interaction of changing tasks to intentionally bring awareness to the switch. These tags are labeled with my current class schedule, plus a personal passion project. You can scan in the task you want to focus on and a full screen time will take over the browser window. When 25 minutes have passed, the user will be notified by LED light. In addition, a small accomplishment dot is added to the task. You can collect up to three right now, however if you switch tasks in the middle of another, you will not get a dot.
#include <SPI.h>
#include <MFRC522.h>
#define SS_PIN 10
#define RST_PIN 9
MFRC522 newReader(SS_PIN, RST_PIN); // Create MFRC522 instance.
String id = "";
//--------NEOPIXEL SETUP --------
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
static const int PIN = 8;
static const int NUMPIXELS = 1;
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRBW + NEO_KHZ800);
//--------INCOMING CASE STATE--------
int caseState;
//--------OUTGOING CASE STATE--------
static const int neutralState = 0;
static const int thesisState = 1;
static const int rmeState = 2;
static const int mtiState = 3;
static const int cdfState = 4;
static const int personalState = 5;
int sendState = neutralState;
//--------TIME--------
unsigned long lastSampleTime = 0;
unsigned long sampleInterval = 300000; // in ms 5 minutes
void setup() {
Serial.begin(9600); // Initialize serial communications with the PC
SPI.begin(); // Init SPI bus
newReader.PCD_Init(); // Init MFRC522 card
Serial.println("Scan PICC to see UID and type...");
pixels.begin();
}
void loop() {
unsigned long now = millis();
pixelOff();
if (Serial.available() > 0) {
caseState = Serial.read();
}
getID();
if (lastSampleTime + sampleInterval < now) {
lastSampleTime = now;
if (caseState == 6) {
pixelBlink();
} else {
pixelOff();
}
}
}
void pixelBlink() {
pixels.setPixelColor(0, pixels.Color(138, 70, 215));
pixels.show(); // This sends the updated pixel color to the hardware.
delay(500);
pixels.setPixelColor(0, pixels.Color(0, 0, 0));
pixels.show(); // This sends the updated pixel color to the hardware.
delay(500);
}
void pixelOff() {
pixels.setPixelColor(0, pixels.Color(0, 0, 0));
pixels.show(); // This sends the updated pixel color to the hardware.
}
void getID() {
// Getting ready for Reading PICCs
if ( ! newReader.PICC_IsNewCardPresent()) { //If a new PICC placed to RFID reader continue
return 0;
}
if ( ! newReader.PICC_ReadCardSerial()) { //Since a PICC placed get Serial and continue
return 0;
}
// Serial.print("Card UID:");
for (byte i = 0; i < newReader.uid.size; i++) {
// Create a RFID Hexdecimal String
id += String(newReader.uid.uidByte[i], HEX);
// Serial.print(newReader.uid.uidByte[i] < 0x10 ? " 0" : " ");
}
// Convert to Uppercase
id.toUpperCase();
// If it is this card, do something
if (id == "B0A167A") {
sendState = thesisState;
// Serial.println("Card One: Thesis");
// Serial.print("State: ");
// Serial.println(sendState);
}
if (id == "B0DECE7A") {
sendState = rmeState;
// Serial.println("Card Two: Responsive Mobile Environments");
// Serial.print("State: ");
// Serial.println(sendState);
}
if (id == "702E89C") {
sendState = mtiState;
// Serial.println("Card Three: Making Things Interactive");
// Serial.print("State: ");
// Serial.println(sendState);
}
if (id == "3078E49B") {
sendState = cdfState;
// Serial.println("Card Four: Communication Design Fundamentals");
// Serial.print("State: ");
// Serial.println(sendState);
}
if (id == "50611A9C") {
sendState = personalState;
// Serial.println("Card Five: Personal Projects");
// Serial.print("State: ");
// Serial.println(sendState);
}
Serial.write (sendState);
// Reset Id
id = "";
// Serial.println();
newReader.PICC_HaltA();
newReader.PCD_StopCrypto1();
}
//---Serial---
var serial;
var portName = '/dev/cu.usbmodem1411';
//---Incoming Case State---
var caseState;
//---Outgoing Case State---
var accomplishState;
//---Color---
var c;
var thesisColor;
var rmeColor;
var mtiColor;
var cdfColor;
var personalColor;
//---Canvas---
var xLen = 1000;
var yLen = 700;
//---Squares & Grid---
let squares = [];
let bubbles0 = [];
let bubbles1 = [];
let bubbles2 = [];
let bubbles3 = [];
let bubbles4 = [];
//---Time---
var time = 1500;
var timer0 = time;
var timer1 = time;
var timer2 = time;
var timer3 = time;
var timer4 = time;
//---Counter---
var count0 = 0;
var count1 = 0;
var count2 = 0;
var count3 = 0;
var count4 = 0;
//---Converts Time to minutes and seconds---
function convertTime(s){
var minutes = floor(s / 60);
var seconds = s % 60;
return nf(minutes,2) + "m " + nf(seconds,2) + "s"; // formats to look like "00m 00s"
}
function setup() {
createCanvas(xLen, yLen);
serial = new p5.SerialPort();
// now set a number of callback functions for SerialPort
serial.on('list', printList);
serial.on('connected', serverConnected);
serial.on('open', portOpen);
serial.on('data', serialEvent);
serial.on('error', serialError);
serial.on('close', portClose);
serial.list();
serial.open(portName);
// setting task squares as well as accomplished "dots" through objects
for (let i=0; i<5; i++){
for(let j =0; j<3; j++){
let x = 0 + 200 * i;
let y = 550;
let w = 200;
let h = 150;
let gridX = 50;
let gridY = 625;
let offset = 50;
let gridR = 10;
squares[i] = new Square(x,y,w,h);
bubbles0[j] = new Bubble(gridX + offset*j, gridY, gridR);
bubbles1[j] = new Bubble(200 + gridX + offset*j, gridY, gridR);
bubbles2[j] = new Bubble(400 + gridX + offset*j, gridY, gridR);
bubbles3[j] = new Bubble(600 + gridX + offset*j, gridY, gridR);
bubbles4[j] = new Bubble(800 + gridX + offset*j, gridY, gridR);
}
}
}
function draw() {
// put drawing code here
// background(255);
checkIncoming(); // checks the incoming state and runs the proper timer
statusBar(); // keeps the tabs with what tasks, right now classes
bubbleKeeper(); // keeps the circles that tick when time has been accomplished
}
function bubbleKeeper(){
for(let i=0; i < bubbles0.length; i++){ // accomplish bubbles for thesis
noStroke();
// bubbles[i].show(0);
if (count0 == 1){
bubbles0[0].show(0);
}
if (count0 == 2){
bubbles0[0].show(0);
bubbles0[1].show(0);
}
if (count0 == 3){
bubbles0[0].show(0);
bubbles0[1].show(0);
bubbles0[2].show(0);
}
}
for(let i=0; i < bubbles1.length; i++){ // accomplish bubbles for RME
noStroke();
// bubbles[i].show(0);
if (count1 == 1){
bubbles1[0].show(0);
}
if (count1 == 2){
bubbles1[0].show(0);
bubbles1[1].show(0);
}
if (count1 == 3){
bubbles1[0].show(0);
bubbles1[1].show(0);
bubbles1[2].show(0);
}
}
for(let i=0; i < bubbles2.length; i++){ // accomplish bubbles for MTI
noStroke();
// bubbles[i].show(0);
if (count2 == 1){
bubbles2[0].show(0);
}
if (count2 == 2){
bubbles2[0].show(0);
bubbles2[1].show(0);
}
if (count2 == 3){
bubbles2[0].show(0);
bubbles2[1].show(0);
bubbles2[2].show(0);
}
}
for(let i=0; i < bubbles3.length; i++){ // accomplish bubbles for CDF
noStroke();
// bubbles[i].show(0);
if (count3 == 1){
bubbles3[0].show(0);
}
if (count3 == 2){
bubbles3[0].show(0);
bubbles3[1].show(0);
}
if (count3 == 3){
bubbles3[0].show(0);
bubbles3[1].show(0);
bubbles3[2].show(0);
}
}
for(let i=0; i < bubbles4.length; i++){ // accomplish bubbles for Passion Projects
noStroke();
// bubbles[i].show(0);
if (count4 == 1){
bubbles4[0].show(0);
}
if (count4 == 2){
bubbles4[0].show(0);
bubbles4[1].show(0);
}
if (count4 == 3){
bubbles4[0].show(0);
bubbles4[1].show(0);
bubbles4[2].show(0);
}
}
}
function statusBar(){
textSize(20);
textAlign(CENTER);
textStyle(BOLD);
var textY = 575;
//---Using these to change the color of the timer background based on the class
thesisColor = color(236,195,211);
rmeColor = color(247,161,171);
mtiColor = color(250,116,86);
cdfColor = color(252,195,135);
personalColor = color(242,240,181);
//---Setting up the squares based on color
for(let i =0; i<squares.length; i++){
noStroke();
squares[0].show(thesisColor);
squares[1].show(rmeColor);
squares[2].show(mtiColor);
squares[3].show(cdfColor);
squares[4].show(personalColor);
}
fill(0);
noStroke();
text("THESIS", 100, textY);
text("RME", 300, textY);
text("MTI", 500, textY);
text("CDF", 700, textY);
text("PASSION", 900, textY);
}
function checkIncoming(){
textSize(200);
textAlign(CENTER);
if (caseState == 1){ // THESIS
if (frameCount % 60 == 0 && timer0 > 0) { // if the frameCount is divisible by 60, then a second has passed. it will stop at 0
timer0 --;
}
if (timer0 == 0){ // if time reaches zero, task accomplished
timer0 = time; // timer resets to 25minutes (1500 seconds)
count0++; // counter adds one
accomplishState = 6; // sends notification to arudino to light up light
} else{
accomplishState = 5;
}
if (count0 > 3){
count0=0; // resets after three rounds
}
background(color(236,195,211));
fill(0);
noStroke();
text(convertTime(timer0), width/2, height*.5);
}
if (caseState == 2){ //RME
if (frameCount % 60 == 0 && timer1 > 0) { // if the frameCount is divisible by 60, then a second has passed. it will stop at 0
timer1 --;
}
if (timer1 == 0){
timer1 = time;
count1++;
accomplishState = 6;
} else{
accomplishState = 5;
}
if (count1 > 3){
count1=0;
}
background(color(247,161,171));
fill(0);
noStroke();
text(convertTime(timer1), width/2, height*.5);
}
if (caseState == 3){ // MTI
if (frameCount % 60 == 0 && timer2 > 0) { // if the frameCount is divisible by 60, then a second has passed. it will stop at 0
timer2 --;
}
if (timer2 == 0){
timer2 = time;
count2++;
accomplishState = 6;
} else{
accomplishState = 5;
}
if (count2 > 3){
count2=0;
}
background(color(250,116,86));
fill(0);
noStroke();
text(convertTime(timer2), width/2, height*.5);
}
if (caseState == 4){ // CDF
if (frameCount % 60 == 0 && timer3 > 0) { // if the frameCount is divisible by 60, then a second has passed. it will stop at 0
timer3 --;
}
if (timer3 == 0){
timer3 = time;
count3++;
accomplishState = 6;
} else{
accomplishState = 5;
}
if (count3 > 3){
count3=0;
}
background(color(252,195,135));
fill(0);
noStroke();
text(convertTime(timer3), width/2, height*.5);
}
if (caseState == 5){ // PERSONAL
if (frameCount % 60 == 0 && timer4 > 0) { // if the frameCount is divisible by 60, then a second has passed. it will stop at 0
timer4 --;
}
if (timer4 == 0){
timer4 = time;
count4++;
accomplishState = 6;
} else{
accomplishState = 5;
}
if (count4 > 3){
count4=0;
}
background(color(242,240,181));
fill(0);
noStroke();
text(convertTime(timer4), width/2, height*.5);
}
serial.write(accomplishState);
}
class Square{ // object class for bottom squares
constructor(x,y,w,h){
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
show(c){
fill(c);
rect(this.x, this.y, this.w, this.h);
}
}
class Bubble { // onject class for dots
constructor(x, y, r) {
this.x = x;
this.y = y;
this.r = r;
}
show(c) {
// stroke(90);
// strokeWeight(1);
fill(c);
ellipse(this.x, this.y, this.r * 2);
}
}
//-----SERIAL FUNCTIONS-----
function printList(portList) {
for (var i = 0; i < portList.length; i++) {
print(i + " " + portList[i]);
}
}
function serverConnected() {
print('serverConnected');
}
function portOpen() {
print('portOpen');
}
function serialEvent() {
var incoming = serial.read();
caseState = incoming;
}
function serialError(err) {
print('serialError ' + err);
}
function portClose() {
print('portClose');
}