Smart Focus Cloud

by rohanbarnwal in Circuits > Microcontrollers

24 Views, 0 Favorites, 0 Comments

Smart Focus Cloud

Heading.png

Staying focused in a world full of notifications is difficult. Most productivity tools live inside the same device that distracts us β€” our phones.

So instead of building another mobile app, I created a physical desk companion.

Smart Focus Cloud is a 3D-printed, cloud-shaped Pomodoro timer powered by ESP32-S3. It combines:

  1. ⏱ Pomodoro focus timer
  2. 🌑 Temperature & humidity monitoring
  3. 🎨 Animated border progress indicator
  4. πŸ”” Smart audio feedback
  5. πŸ–¨ Custom aesthetic enclosure

This project blends embedded systems, UI design, and product-style packaging into one clean build.

Supplies

Electronics

  1. ESP32-S3 (with touchscreen display)
  2. DHT11 temperature & humidity sensor
  3. Active buzzer
  4. Jumper wires / custom wiring
  5. Power cable

Mechanical

  1. 3D printed cloud enclosure (PLA recommended)
  2. Mounting screws
  3. Internal supports (printed)

Tools

  1. Soldering iron
  2. Computer with Arduino IDE
  3. USB cable for programming


Building the Core Electronics

Subheading (6).png

The ESP32-S3 acts as the brain of the project.

It handles:

  1. UI rendering
  2. Touch input
  3. Timer logic
  4. Sensor readings
  5. Buzzer control

Connections Overview:

  1. DHT11 β†’ Connected to GPIO pin
  2. Buzzer β†’ Digital output pin
  3. Display β†’ Integrated with ESP32-S3 board

Once everything is connected:

  1. Upload the code using Arduino IDE
  2. Power the board
  3. Verify that temperature and humidity readings appear

At this stage, the device works β€” but it’s still a prototype.

Programming the Pomodoro Logic

WhatsApp Image 2026-03-01 at 2.26.43 PM (1).jpeg
WhatsApp Image 2026-03-01 at 2.26.43 PM.jpeg

The software includes multiple screens:

🏠 Home Screen

Displays:

  1. β€œReady To Focus?”
  2. Live temperature
  3. Live humidity

⏱ Work Setup Screen

  1. Set hours, minutes, seconds
  2. Increase/decrease values
  3. Touch feedback with beep sound

πŸ’€ Break Selection Screen

Choose break duration:

5 / 10 / 15 / 20 / 25 / 30 / 40 / 50 minutes

β–Ά Running Mode

  1. Countdown timer
  2. Play / Pause
  3. Reset option
  4. Triple beep when session ends


Designing & 3D Printing the Cloud Enclosure (With JUSTWAY)

download (10) - Copy.png

A bare PCB with wires works for testing.

But when you want to:

  1. Present at exhibitions
  2. Showcase at demo days
  3. Build a portfolio project
  4. Make your hardware look product-ready

Presentation becomes critical.

So I designed a custom cloud-shaped enclosure.

πŸ”Ή Design Goals

  1. Perfect display alignment
  2. Hidden internal wiring
  3. Secure mounting structure
  4. Smooth, rounded aesthetic
  5. Desk-friendly size

To achieve a clean and professional finish, the enclosure can be manufactured using high-quality 3D printing services like JUSTWAY.

JUSTWAY offers:

  1. Rapid prototyping with quick turnaround
  2. High-detail 3D printing (resin for aesthetic finish, nylon for durability)
  3. CNC machining for metal enclosures
  4. Injection molding for scaling production
  5. Urethane casting for low-volume production

For a project like Smart Focus Cloud, professional 3D printing ensures:

  1. Better surface finish
  2. Accurate tolerances
  3. Stronger structural integrity
  4. A product-grade appearance

These services don’t change how your circuit works β€” they change how your project is perceived.

And perception plays a huge role in hardware design.

Code

#include <Arduino.h>
#include <Wire.h>
#define LGFX_ESP32_S3_BOX_V3
#include <LGFX_AUTODETECT.hpp>
#include <LovyanGFX.hpp>
#include <DHT.h>

static LGFX lcd;

#define DHTPIN 40
#define DHTTYPE DHT11
#define BUZZER_PIN 9

#define W 320
#define H 240

DHT dht(DHTPIN, DHTTYPE);

enum ScreenState { HOME, WORK_SETUP, BREAK_SELECT, RUNNING };
ScreenState screen = HOME;

struct TouchPoint { int16_t x,y; bool touched; };
TouchPoint lastTouch={0,0,false};

// ================= TIMER =================
int work_h=0, work_m=0, work_s=0;
int totalWorkSeconds=0;
int totalBreakSeconds=0;
int initialDuration=0;

bool running=false;
bool isBreak=false;
int selectedField=0;

unsigned long lastTick=0;
int progressPixels=0;

// ================= SOUND =================
void doubleBeep(){
for(int i=0;i<2;i++){
tone(BUZZER_PIN,2000,70);
delay(120);
}
}

void tripleBeep(){
for(int i=0;i<3;i++){
tone(BUZZER_PIN,2500,120);
delay(180);
}
}

// ================= TOUCH =================
TouchPoint readTouch(){
TouchPoint p={0,0,false};
uint16_t x,y;
if(lcd.getTouch(&x,&y)){
p.x=x; p.y=y; p.touched=true;
}
return p;
}

// ================= UI =================
void whiteScreen(){
lcd.fillScreen(TFT_WHITE);
lcd.setTextColor(TFT_BLACK);
}

void drawButton(int x,int y,int w,int h,String txt){
lcd.fillRoundRect(x,y,w,h,8,TFT_BLACK);
lcd.setTextColor(TFT_WHITE);
lcd.setTextDatum(middle_center);
lcd.drawString(txt,x+w/2,y+h/2);
}

void showPopup(String l1,String l2){
lcd.fillRoundRect(40,70,240,100,15,TFT_BLACK);
lcd.setTextColor(TFT_WHITE);
lcd.setFont(&fonts::Font2);
lcd.setTextDatum(middle_center);
lcd.drawString(l1,W/2,105);
lcd.drawString(l2,W/2,125);
delay(2000);
}

// ================= PROGRESS DRAW =================
void drawProgressStep(){

if(initialDuration<=0) return;

int sec = isBreak?totalBreakSeconds:totalWorkSeconds;
float progress = 1.0 - ((float)sec / initialDuration);
if(progress<0) progress=0;
if(progress>1) progress=1;

int perimeter = 2*(W+H);
int targetPixels = perimeter * progress;

while(progressPixels < targetPixels){

int p = progressPixels;

if(p < W){
lcd.drawPixel(p,0,TFT_BLACK);
}
else if(p < W+H){
lcd.drawPixel(W-1,p-W,TFT_BLACK);
}
else if(p < W+H+W){
lcd.drawPixel(W-1-(p-(W+H)),H-1,TFT_BLACK);
}
else{
lcd.drawPixel(0,H-1-(p-(W+H+W)),TFT_BLACK);
}

progressPixels++;
}
}

// ================= HOME =================
void drawHome(){
whiteScreen();
lcd.setFont(&fonts::FreeSansBold18pt7b);
lcd.setTextDatum(middle_center);
lcd.drawString("Ready To Focus?",W/2,90);

float t=dht.readTemperature();
float h=dht.readHumidity();

lcd.setFont(&fonts::Font4);
lcd.drawString("Temp: "+String(t,1)+" C",W/2,170);
lcd.drawString("Hum : "+String(h,1)+" %",W/2,205);

screen=HOME;
}

// ================= WORK SETUP =================
void drawWorkSetup(){
whiteScreen();
lcd.setFont(&fonts::Font7);
lcd.setTextDatum(middle_center);

char buf[20];
sprintf(buf,"%02d:%02d:%02d",work_h,work_m,work_s);
lcd.drawString(buf,W/2,90);

int baseX=W/2-90;
if(selectedField==0) lcd.fillRect(baseX,125,40,4,TFT_BLACK);
if(selectedField==1) lcd.fillRect(baseX+60,125,40,4,TFT_BLACK);
if(selectedField==2) lcd.fillRect(baseX+120,125,40,4,TFT_BLACK);

lcd.setFont(&fonts::Font4);
drawButton(30,170,80,45,"+");
drawButton(120,170,80,45,"-");
drawButton(210,170,80,45,"->");

screen=WORK_SETUP;
}

// ================= BREAK SELECT =================
int breakOptions[8]={5,10,15,20,25,30,40,50};

void drawBreakSelect(){
whiteScreen();
lcd.setFont(&fonts::Font4);
lcd.setTextDatum(middle_center);
lcd.drawString("Select Break (min)",W/2,30);

int idx=0;
for(int r=0;r<3;r++){
for(int c=0;c<3;c++){
if(idx>=8) break;
int x=30+c*95,y=60+r*55;
drawButton(x,y,80,45,String(breakOptions[idx]));
idx++;
}
}
screen=BREAK_SELECT;
}

// ================= RUNNING =================
void drawRunning(){
whiteScreen();
progressPixels=0;

lcd.setFont(&fonts::Font7);
lcd.setTextDatum(middle_center);

int sec=isBreak?totalBreakSeconds:totalWorkSeconds;
int hh=sec/3600;
int mm=(sec%3600)/60;
int ss=sec%60;

char buf[20];
sprintf(buf,"%02d:%02d:%02d",hh,mm,ss);
lcd.drawString(buf,W/2,90);

lcd.setFont(&fonts::Font4);
drawButton(60,170,90,45,running?"Pause":"Play");
drawButton(170,170,90,45,"Reset");

screen=RUNNING;
}

// ================= TIMER UPDATE =================
void updateTimer(){

if(!running) return;

if(millis()-lastTick>=1000){
lastTick=millis();

if(!isBreak){
if(totalWorkSeconds>0) totalWorkSeconds--;
else{
running=false;
tripleBeep();
showPopup("Break Time!","Relax πŸ™‚");
isBreak=true;
running=true;
initialDuration=totalBreakSeconds;
drawRunning();
return;
}
}
else{
if(totalBreakSeconds>0) totalBreakSeconds--;
else{
running=false;
tripleBeep();
showPopup("Back To Work Buddy","Lets Go πŸ’ͺ");
work_h=work_m=work_s=0;
totalWorkSeconds=0;
totalBreakSeconds=0;
isBreak=false;
drawHome();
return;
}
}

drawRunning();
}

drawProgressStep();
}

// ================= TOUCH =================
void handleTouch(int x,int y){

if(screen==HOME){
drawWorkSetup();
}

else if(screen==WORK_SETUP){

if(y>60 && y<130){
if(x>W/2-100 && x<W/2-40) selectedField=0;
else if(x>W/2-20 && x<W/2+40) selectedField=1;
else if(x>W/2+60 && x<W/2+120) selectedField=2;
drawWorkSetup();
return;
}

if(x>30&&x<110&&y>170&&y<215){
doubleBeep();
if(selectedField==0) work_h++;
if(selectedField==1&&work_m<59) work_m++;
if(selectedField==2&&work_s<59) work_s++;
}

if(x>120&&x<200&&y>170&&y<215){
doubleBeep();
if(selectedField==0&&work_h>0) work_h--;
if(selectedField==1&&work_m>0) work_m--;
if(selectedField==2&&work_s>0) work_s--;
}

if(x>210&&x<290&&y>170&&y<215){
totalWorkSeconds=work_h*3600+work_m*60+work_s;
initialDuration=totalWorkSeconds;
drawBreakSelect();
return;
}

drawWorkSetup();
}

else if(screen==BREAK_SELECT){
for(int i=0;i<8;i++){
int r=i/3,c=i%3;
int bx=30+c*95,by=60+r*55;
if(x>bx&&x<bx+80&&y>by&&y<by+45){
doubleBeep();
totalBreakSeconds=breakOptions[i]*60;
running=true;
lastTick=millis();
initialDuration=totalBreakSeconds;
drawRunning();
return;
}
}
}

else if(screen==RUNNING){

if(x>60&&x<150&&y>170&&y<215){
doubleBeep();
running=!running;
drawRunning();
}

if(x>170&&x<260&&y>170&&y<215){
doubleBeep();
running=false;
work_h=work_m=work_s=0;
totalWorkSeconds=0;
totalBreakSeconds=0;
isBreak=false;
drawHome();
}
}
}

// ================= SETUP =================
void setup(){
lcd.init();
lcd.setBrightness(255);
dht.begin();
pinMode(BUZZER_PIN,OUTPUT);
drawHome();
}

// ================= LOOP =================
void loop(){
TouchPoint t=readTouch();
if(t.touched && !lastTouch.touched){
handleTouch(t.x,t.y);
}
lastTouch=t;
updateTimer();
}

Final Thoughts

Smart Focus Cloud started as a simple Pomodoro timer.

It evolved into:

  1. A focus companion
  2. A hardware packaging experiment
  3. A UI design project
  4. A product development journey

The biggest lesson?

Anyone can build a working circuit.

But turning it into something that looks and feels like a finished product β€” that’s where true hardware innovation begins.