Project development
In this page i would share my stages of project development .
PROJECT DEVELOPMENT
Here i have shown my journey from the week one as a beginner , what i was building and what i have accomplished at the end .
Focus Assistant: My Journey in Development
Hey there! I'm excited to share my progress on the Focus Assistant project. It's been quite a ride so far. Let me walk you through what I've done and where I'm headed.
What I've Accomplished So Far
-
Basic Design: I've sketched out a rough idea of what I want this little productivity powerhouse to look like. It's nothing fancy yet, but it's a start!
-
3D Model: This is where things get a bit more real. I've created a 3D design . From my experience, having a visual model really helps in planning the next steps.
The below one is tag module
This one is the pomodoro module
My Plans for the Future
Here's what I'm thinking of adding as I move forward:
- Pomodoro Technique: I've used this before, and it's a game-changer for productivity. I'm planning to integrate it into the Focus Assistant.
- Daily Routine Display: Wouldn't it be cool if the device could show your daily schedule? That's on my to-do list.
- Task Reminders: I'm thinking about adding notifications to keep users on track with their tasks.
My Development Process
First, I'll be finalizing the hardware components. From my experience, this can take some time, so I'm giving myself a couple of weeks for this.
Next, I'll dive into the firmware development. This is where the magic happens, turning the hardware into a functional device.
Then, I'll work on implementing those advanced features I mentioned earlier. This is the part I'm most excited about!
Finally, I'll do some testing and make any necessary adjustments. I've learned from past projects that this step is crucial for a polished final product.
Challenges I'm Anticipating
I know from experience that integrating multiple features can be tricky. I'm a bit concerned about making sure everything works smoothly together, especially the Pomodoro timer and the daily routine display.
What I'm Looking Forward To
I can't wait to see this project come to life! I'm particularly excited about the potential to help people manage their time better. As someone who's struggled with productivity, I know how valuable a tool like this can be.
BLOCK DIAGRAM
The below block diagram integrates the devices that i am working on so far for my final project .
INPUT week
In input week i had tested the Rotary encoder .
OUTPUT WEEK
In output week i had tested the oled
INTERFACING AND COMMUNICATION WEEK
In interface and communication week i had the chance to to develop a small app that could communicate with display where peoplen could enter the taska with date and time whiuich could be display on the oled display .
Bill of Materials (BOM) Chart
Product | Cost (Rs) | Purchase Links | Supplier |
---|---|---|---|
Xiao ESP32 C6 | 555*2 | ROBU | FAB INVENTORY |
Rotary Encoder | 39 | ROBU | FAB INVENTORY |
Buzzer | 36 | ROBU | FAB INVENTORY |
E-ink Display | 1,899 | AMAZON | AMAZON |
OLED Display | 224 | ROBU | FAB INVENTORY |
LiPo Battery | 409 | ROBU | FAB INVENTORY |
MP3 Module | 112 | ROBU | ROBU |
Pla filament | 1300/KG | FAB INVENTORY | |
CAPACITOR | 1 | FAB INVENTORY | |
4 PIN JST CONNECTOR | 1 *3 | FAB INVENTORY | |
3 PIN JST CONNECTOR | 1 | FAB INVENTORY | |
Total | 3,829 |
TESTING DIFFERENT DESIGNS
At first i thought about taking a round design , Also i was confused with what size screen should i incorporate so i started cutting a cardboard with the oled size 1.52 inch .
After cutting the boards i was not satisfied with the size and the looks . And i found out that in this design it would trouble integrating all the components in it .
This is me arranging and checking how much size would be looking good and checking that whether its possible to integrate the pcb inside .
Then i have come to a conclusion to design something boxy . so i designed a boxy design with the size of 3.52 inch . And then i have laser cutted birchwood to get a sample like this .
Then i found this is too big for the handy feel . so i became to a conclusion to use much smaller size displays . then i found a 2.72 inch ink display and which i checked the dimesions and which was perfect for my basic need .
FINAL DAYS
I used Canva to edit this image .
SCHEDULE
This is the gant chart schedule that i have prepared for the the completion of my project .
I have used the following webapp to make it posssible .
What will you design?: Here we are going to design the enclosure of two modules , for that i need to consider the facts of the different components that are placed in this .
Also i have to design the the pcbs , the switches , the button and the knob .
What parts and systems will be made?:
The enclosure , button , switches , knob eerything should be fabricated and made . The e ink display and the switches should be connected to the pcb module and the switches should be connected tothe mp3 modukle seperatly , the mp3 module and the pcb will stand as a seperate entity . But the power for the mp3 module will be takenn out from the pcb module by using a jst connector and the (+-) port of mp3module will be soldered with other end of wire that comes from the jst .
Below i have shown the systems that i have made to integrate different compoents .
What processes will be used?
The development process will involve several key stages:
- PCB Design and Manufacturing - Creating custom circuit boards using KiCad for both the main timer and display modules
- 3D Modeling and Printing - Designing and fabricating the enclosure using Fusion 360 and FDM printing
- Laser Cutting : would be used to cut the acrylic .
- Firmware Development - Programming the ESP32 using Arduino IDE/Platform IO with custom libraries for display and connectivity
What questions need to be answered?
-
What is the most effective way to integrate the timer with existing task management systems? .
-
How to connect both the modules using ESPNOW ?.
-
Selecting the task to displayed in the display module using the minutes module.
-
How the integration of app works ?
How will it be evaluated?
If i am able to run the pomodoro timer half the work is done .
Then comes the app integration part to display tasks and the display module connecting via espnow part .
Develop a plan for dissemination of your final project .
Since I want people to learn from and build on my work—but not sell it—I picked CC BY-NC-SA 4.0. This lets others remix and share, as long as they credit me, don’t use it commercially, and share their changes under the same license1.
I always wanted to make a product for my company . If it works good and if i am satisfied with the product i would modify the product and look more into design aspects making it more compact and i would try to hire some developers so i could make it as a product and sell it via online . For that i would make a few ones and do a prelaunch and do some marketing and i would take some feedbacks from people and would try to incorporate that too .
LAST WEEK I HAVE MADE a sub module and i have incorporated different screen displays like Do not disturb , busy etc using Lopaka .
what tasks have been completed, and what tasks remain?
Pcb has been milled and i have made the 3D printed casing and i have been working on the incorporation of switch and i have got that too . next step is to print the full module and incorporate these all and cut the acrylic and incorporate all these things into this and solder the neopixel around the casing and cast this week . For the remaining task an entire module is about to be completed .
what's working? what's not?
I have been looking for any waveshare esp32 setups and i am not finding anything for the eink connection . in the documentation too there is esp32 but i should look into it further .
what questions need to be resolved?
The main question that needs to be resolved is how to properly connect the waveshare eink display with the ESP32. I need to thoroughly review the documentation and possibly find alternative resources or examples for this specific setup. Additionally, I need to determine the optimal method for integrating the neopixel lighting with the final casing design.
what will happen when?
This week, I plan to complete the small module assembly including integrating the PCB, 3D printed casing, switches, and neopixel lighting. The acrylic cutting will be done by the end of this week. Once these components are assembled, I will focus on building the final module and testing the complete system functionality.
what have you learned?
I have learned how much time it would take to design a product , i learned how to test a product part by part so that there is no much wastage . how much iterations it would take to find the perfect fit etc .Also things that you may thnk that may take less time may consume the most amount of time .
In the below image i have attached the major tests that i have performed for the scope of this assignment .
LOPAKA
Lopaka is a website where you could draw freely using the tools available or you could add images into it and you could generate the code for the screen . which could be used to generate graphics for your screen .
This is the image where i have used the help of lopaka to generate code for the Busy Tag to display Busy .
MINUTES TAG MODULE
Below there are 4 sections where i have detailed the component placement the electronic design , the code etc which was made my me during the process of making the Display Tag .
This is the CAD Model that I made
In the below images i have shown how i integrated the components in my minutes display tag module
Below I have attached the schematic that I used to design the small PCB for the display module that could be kept as an indicator.
Then I routed the PCB design so I could mill the PCB.
Then I checked the 3D view to check the alignment and I decided where to keep my OLED display.
Then I placed a hole in a way that my display module is in the center so it suits the circular design that I am going to make. For that, I used Fusion and exported the DXF with the OLED placing and aligned the through hole accordingly.
Then i have made the Pcb and soldered the componennts then i noticed there was an error (that i have forgotted about 2 via holes for the battery connection module . so for that my instructor saheen suggested an idea to vinyl print and took the connection out ) so we did that .
for that we have made jig for the pcb using cardboard .
Then i have pasted vinyl on back of pcb as shown below .
Then to engrave the traces i have used xtools .
Then i have removed the excess vinyl as shown below
This is how it looks after the removal
Then i have used uv glue to stick the vinyl .
since it was a uv glue , i applied some uv light with the help of uv torch which helped me in faster hardening of glue.
This week i have 3d printed some parts of my case .
Below i have shown the smoked acrylic that i have used as part of my display . its smoked so it is not opaque and is visible with a good looking effect .
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Fonts/FreeMono9pt7b.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for SSD1306 display connected using I2C (SDA, SCL pins)
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
void setup() {
Serial.begin(115200); // Initialize Serial for debugging
// initialize with the I2C addr 0x3C (for most OLEDs)
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.clearDisplay();
display.drawRect(10, 9, 106, 44, SSD1306_WHITE);
display.setTextColor(SSD1306_WHITE);
display.setTextWrap(false);
display.setFont(&FreeMono9pt7b);
display.setCursor(39, 29);
display.print("IN A");
display.setCursor(25, 43);
display.print("MEETING");
display.display();
}
void loop() {
// Nothing needed here for static display
}``
MINUTES PRODUCTIVITY TIMER MAIN MODULE
Below there are 4 sections where i have detailed the component placement the electronic design , the code etc which was made my me during the process of making the Minutes Pomodoro module .
Below here the mechansisms and component placement that i have used in integration of minutes pomodoro module .
HERE I HAVE ATTACHED THE SCHEMATIC THE 3D VIEW , THE PCBLAYOUT AND BOM BELOW .
These are the buttons that i have 3d printed for the Minutes Module .
Below i have attached the 3d printed front face of the Module .
here i am checking the button with the front face .
This is the final back body that i have 3d printed
The final Assembly viw of the product from inside .
A more closeup shot . here you could see how i have placed the mp3 module . The mp3 module is placed on a 3D printed sliding mechanism where i screwed the module and the 3d print .
The below image shows the back cover which i have laser cutted .
This is the final photo of Minutes Module After Assembly .
#define pushButton D0
// ntp server code
#include <WiFi.h>
#include "time.h"
#include <Arduino.h>
#include <RotaryEncoder.h>
#define PIN_IN1 D2
#define PIN_IN2 D3
#define ROTARYSTEPS 2
#define ROTARYMIN 0
#define ROTARYMAX 16
RotaryEncoder encoder(PIN_IN1, PIN_IN2, RotaryEncoder::LatchMode::TWO03);
int lastPos = -1;
// Replace these with your Wi-Fi credentials
const char* ssid = "FabGuest";
const char* password = "4fabGUEST";
// NTP server and time zone settings (IST for Kochi, Kerala, India)
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 19800; // GMT+5:30 = 5*3600 + 30*60 = 19800 seconds
const int daylightOffset_sec = 0;
int HOUR, MINUTE, SECOND;
// display code
#include <GxEPD2_BW.h>
#include <Fonts/FreeMonoBold24pt7b.h>
#include <SPI.h>
// Pin definitions
#define EPD_SCK_PIN 19
#define EPD_MOSI_PIN 18
#define EINK_CS 17
#define EINK_RST 23
#define EINK_DC 16
#define EINK_BUSY 22
// Instantiate display class for 2.7" GDEY027T91 (V2)
GxEPD2_BW<GxEPD2_270_GDEY027T91, GxEPD2_270_GDEY027T91::HEIGHT>
display(GxEPD2_270_GDEY027T91(EINK_CS, EINK_DC, EINK_RST, EINK_BUSY));
SPIClass spi = SPIClass(SPI); // Use VSPI for custom pins
void setup() {
pinMode(pushButton, INPUT);
Serial.begin(115200);
encoder.setPosition(10 / ROTARYSTEPS); // start with the value of 10.
// Initialize SPI with your custom pins
spi.begin(EPD_SCK_PIN, -1, EPD_MOSI_PIN, EINK_CS);
// Link SPI to display
display.epd2.selectSPI(spi, SPISettings(4000000, MSBFIRST, SPI_MODE0));
display.init(115200);
display.setRotation(1);
display.setFont(&FreeMonoBold24pt7b);
display.setTextColor(GxEPD_BLACK);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected.");
// Initialize and get the time from NTP
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
}
int PrevMin;
void loop() {
int buttonState = digitalRead(pushButton);
Serial.println(buttonState);
delay(1);
static char timeStr[9]; // "HH:MM:SS" + null terminator
struct tm timeinfo;
if (getLocalTime(&timeinfo)) {
HOUR = timeinfo.tm_hour;
MINUTE = timeinfo.tm_min;
SECOND = timeinfo.tm_sec;
} else {
Serial.println("Failed to obtain time");
}
if (PrevMin != SECOND) {
display.setPartialWindow(19, 50, 223, 31);
display.firstPage();
do {
sprintf(timeStr, "%02d:%02d:%02d", HOUR, MINUTE, SECOND);
display.fillRect(19, 50, 223, 31, GxEPD_WHITE);
display.setCursor(19, 78);
display.print(timeStr);
} while (display.nextPage());
display.hibernate();
PrevMin = SECOND;
}
encoder.tick();
// get the current physical position and calc the logical position
int newPos = encoder.getPosition() * ROTARYSTEPS;
if (newPos < ROTARYMIN) {
encoder.setPosition(ROTARYMIN / ROTARYSTEPS);
newPos = ROTARYMIN;
} else if (newPos > ROTARYMAX) {
encoder.setPosition(ROTARYMAX / ROTARYSTEPS);
newPos = ROTARYMAX;
} // if
if (lastPos != newPos) {
Serial.print(newPos);
Serial.println();
lastPos = newPos;
} // if
}
#include <WiFi.h>
#include <WiFiUdp.h>
#include <NTPClient.h>
#include <GxEPD2_BW.h>
#include <Adafruit_NeoPixel.h>
#include <AiEsp32RotaryEncoder.h>
#include <SPI.h>
// ==== Pin Definitions (Adjusted to Reference) ====
#define ENCODER_CLK 4 // D2
#define ENCODER_DT 0 // D3
#define ENCODER_SW 16 // D0 (pushButton)
#define NEOPIXEL_PIN 5 // You can change if needed
#define BUZZER_PIN 21 // You can change if needed
#define EPD_SCK_PIN 19
#define EPD_MOSI_PIN 18
#define EPD_CS 17
#define EPD_DC 16
#define EPD_RST 23
#define EPD_BUSY 22
#define ROTARY_ENCODER_STEPS 2 // Adjust to your encoder type
// ==== Display Setup ====
GxEPD2_BW<GxEPD2_270_GDEY027T91, GxEPD2_270_GDEY027T91::HEIGHT>
display(GxEPD2_270_GDEY027T91(EPD_CS, EPD_DC, EPD_RST, EPD_BUSY));
SPIClass spi = SPIClass(VSPI); // Use VSPI for custom pins
// ==== NeoPixel Setup ====
Adafruit_NeoPixel pixels(1, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
// ==== Rotary Encoder Setup ====
AiEsp32RotaryEncoder rotaryEncoder(ENCODER_DT, ENCODER_CLK, ENCODER_SW, -1, ROTARY_ENCODER_STEPS);
// ==== WiFi and Time Setup ====
const char* ssid = "FabGuest";
const char* password = "4fabGUEST";
WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "pool.ntp.org", 19800, 60000); // IST offset
// ==== Modes ====
enum AppMode {CLOCK, POMODORO, TASKS, ALARM};
AppMode currentMode = CLOCK;
const int numModes = 4;
// ==== Pomodoro ====
unsigned long pomodoroStartTime = 0;
bool pomodoroActive = false;
const unsigned long pomodoroDuration = 25 * 60 * 1000UL; // 25 min in ms
// ==== Display Throttle ====
unsigned long lastDisplayUpdate = 0;
const unsigned long displayInterval = 1000; // ms
// ==== Rotary Encoder ISR Handler ====
void IRAM_ATTR readEncoderISR() {
rotaryEncoder.readEncoder_ISR();
}
// ==== Setup ====
void setup() {
Serial.begin(115200);
// --- Display SPI Init ---
spi.begin(EPD_SCK_PIN, -1, EPD_MOSI_PIN, EPD_CS);
display.epd2.selectSPI(spi, SPISettings(4000000, MSBFIRST, SPI_MODE0));
display.init(115200);
display.setRotation(1);
display.setTextColor(GxEPD_BLACK);
// --- NeoPixel ---
pixels.begin();
pixels.setPixelColor(0, 0, 0, 0);
pixels.show();
// --- Buzzer ---
pinMode(BUZZER_PIN, OUTPUT);
digitalWrite(BUZZER_PIN, LOW);
// --- Rotary Encoder ---
rotaryEncoder.begin();
rotaryEncoder.setup(readEncoderISR);
rotaryEncoder.setBoundaries(0, numModes - 1, false); // 0 to 3
rotaryEncoder.setAcceleration(0); // No acceleration
pinMode(ENCODER_SW, INPUT_PULLUP);
// --- WiFi ---
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected.");
// --- NTP Time ---
timeClient.begin();
displaySplashScreen();
updateDisplay();
}
// ==== Main Loop ====
void loop() {
rotaryEncoder.loop(); // Must be called regularly
// Handle rotation
static int lastEncoderPos = 0;
int encoderPos = rotaryEncoder.getEncoderValue();
if (encoderPos != lastEncoderPos) {
currentMode = static_cast<AppMode>(encoderPos);
updateDisplay();
lastEncoderPos = encoderPos;
}
// Handle button press (debounced)
if (rotaryEncoder.isEncoderButtonClicked()) {
handleModeAction();
}
// Pomodoro logic
handlePomodoro();
// Throttle e-ink updates (for Pomodoro countdown)
if (currentMode == POMODORO && pomodoroActive && millis() - lastDisplayUpdate > displayInterval) {
updateDisplay();
lastDisplayUpdate = millis();
}
}
// ==== Mode Actions ====
void handleModeAction() {
switch (currentMode) {
case POMODORO:
togglePomodoro();
break;
case CLOCK:
refreshClock();
break;
case TASKS:
// Add task management logic here
break;
case ALARM:
// Add alarm management logic here
break;
}
}
void togglePomodoro() {
if (!pomodoroActive) {
startPomodoro();
} else {
stopPomodoro();
}
}
void startPomodoro() {
pomodoroStartTime = millis();
pomodoroActive = true;
pixels.setPixelColor(0, pixels.Color(255, 0, 0)); // Red
pixels.show();
updateDisplay();
}
void stopPomodoro() {
pomodoroActive = false;
pomodoroStartTime = 0;
pixels.setPixelColor(0, pixels.Color(0, 255, 0)); // Green
pixels.show();
triggerBuzzer();
updateDisplay();
}
void handlePomodoro() {
if (pomodoroActive && (millis() - pomodoroStartTime >= pomodoroDuration)) {
stopPomodoro();
}
}
// ==== Display Functions ====
void updateDisplay() {
display.firstPage();
do {
switch (currentMode) {
case CLOCK: displayClock(); break;
case POMODORO: displayPomodoro(); break;
case TASKS: displayTasks(); break;
case ALARM: displayAlarms(); break;
}
} while (display.nextPage());
}
void displayClock() {
timeClient.update();
display.setCursor(0, 40);
display.setTextSize(2);
display.print("Time: ");
display.print(timeClient.getFormattedTime());
}
void displayPomodoro() {
unsigned long remaining = pomodoroActive ?
pomodoroDuration - (millis() - pomodoroStartTime) : pomodoroDuration;
int minutes = remaining / 60000;
int seconds = (remaining % 60000) / 1000;
display.setCursor(0, 40);
display.setTextSize(2);
display.printf("Pomodoro\n%02d:%02d", minutes, seconds);
}
void displayTasks() {
display.setCursor(0, 40);
display.setTextSize(2);
display.print("Tasks Feature");
}
void displayAlarms() {
display.setCursor(0, 40);
display.setTextSize(2);
display.print("Alarms Feature");
}
void displaySplashScreen() {
display.firstPage();
do {
display.setCursor(0, 40);
display.setTextSize(2);
display.print("Productivity Timer");
display.setCursor(0, 80);
display.setTextSize(1);
display.print("Initializing...");
} while (display.nextPage());
delay(2000);
}
// ==== Buzzer Function ====
void triggerBuzzer() {
for (int i = 0; i < 3; i++) {
digitalWrite(BUZZER_PIN, HIGH);
delay(100);
digitalWrite(BUZZER_PIN, LOW);
delay(100);
}
}
// ==== Helper ====
void refreshClock() {
updateDisplay();
}
SOLDERING
NOTE
This the video where i am soldering the PCB
3D PRINTING
NOTE
This the video where I am 3D printing the components .
LASER CUTTING
NOTE
This the video where i am laser cutting the front panel of the display tag . I also have used it to cut the back panel for pomodoro .
TESTING
NOTE
Here i am testing the functionalities of my core components .
E INK DISPLAY TESTING USING EXAMPLE CODE
ROTARY ENCODER TESTING USING EXAMPLE CODE
ASSEMBLY VIDEOS
NOTE
After the testing and 3d printing the parts and checking the fits , i am assembling down here .
DISPLAY MODULE
MINUTES POMODORO MODULE ASSEMBLY
WORKING
SUCCESS
I have attached the working video below where it shows the individual functionalities .
POMODORO TIMER WORKING
DISPLAY TAG MODULE
FIANL PRESENTATION
FINAL VIDEO
This is the video of my Final Project .