This is a simple kitchen timer but with a twist. You enter the time and hit start and it starts to countdown as per normal, but only while you are around. It uses a passive infra-red detector that is able to detect when warm bodies are close by. When it detects that nobody is nearby, it ticks down at thrice the speed. The pendulum is added so it is easier for the viewer to perceive that time is passing faster. Finally, when the timer hits 0, it sounds a buzzer telling you that you food is cooked. However, to your dismay when you shell your eggs you realise that they are all runny.

Solidworks Files & Code

Tricky Timer


#include <Servo.h>
#include <Wire.h>
#include <Keypad.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>

// OLED display TWI address
#define OLED_ADDR   0x3C
#define LED 2
#define PIR 3
#define SERVO 5
#define BUZZER 4
#define SERVO_CENTER 90

Adafruit_SSD1306 display(-1);
Servo servo;
const byte ROWS = 4; 
const byte COLS = 4; 
char hexaKeys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {6, 7, 8, 9}; 
byte colPins[COLS] = {10, 11, 12, 13};
Keypad customKeypad = Keypad(makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); 


void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(LED, OUTPUT);
  pinMode(BUZZER, OUTPUT);
  pinMode(PIR, INPUT);
  servo.attach(SERVO);

  // initialize and clear display
  display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
  display.clearDisplay();
  display.display();

  display.setTextSize(2);
  display.setTextColor(WHITE);
}

void loop() {
  // put your main code here, to run repeatedly:
  servo.write(90);
  digitalWrite(LED, false);
  display.clearDisplay();
  display.setCursor(0,20);
  display.print("Please set   timer");
  display.display();
  bool first = true;
  char buffer[4];
  int i = 0;
  
  while(true){
    char customKey = customKeypad.getKey();
        
    if(customKey) {
      if (first){
        display.clearDisplay();
        first = false;
        display.setCursor(30,20);
      }
      if (customKey == '#'){
        display.clearDisplay();
        display.setCursor(30,20);
        i = 0;
      }
      else if (customKey == '*') break;
      else if (i < 4) {
        if (i == 2) display.print(':');
        display.print(customKey);
        buffer[i++] = customKey - '0';
      }
      display.display();
    }    
  }
  
  int mins = buffer[0] * 10 + buffer[1];
  int seconds = buffer[2] * 10 + buffer[3]; 
  int delayTime = 500;
  int sweep = SERVO_CENTER;
  bool motionDetected = true;
  
  while(mins || seconds){
    if (seconds % 2 == 0){
      motionDetected = digitalRead(PIR);
      delayTime = motionDetected ? 500 : 166;
      sweep = motionDetected ? 45 : 15;
      digitalWrite(LED, !motionDetected);
    }
    
    servo.write(SERVO_CENTER + sweep);
    delay(delayTime);
    servo.write(SERVO_CENTER - sweep);
    delay(delayTime);

    if (seconds == 0){
      mins--;
      seconds = 60;
    }
    seconds--;
    display.clearDisplay();
    display.setCursor(30,20);
    String message = String(mins) + ":" + String(seconds);
    display.println(message);
    display.display();
  }

  digitalWrite(BUZZER, HIGH);
  while(!customKeypad.getKey()) delay(100);
  digitalWrite(BUZZER, LOW);  
}