Carli Stringfellow
Published

Work Break Alarm Using Smart Lighting and Room Control

How many hours do you spend sitting down at your desk crunched over a computer? If it is most of your day, then I have a device for you!

BeginnerFull instructions provided5 hours162
Work Break Alarm Using Smart Lighting and Room Control

Things used in this project

Hardware components

Philips hue
Philips hue
×1
Tactile Switch, Top Actuated
Tactile Switch, Top Actuated
×1
Teensy 3.1
Teensy 3.1
×1
Ultrasonic Sensor - HC-SR04 (Generic)
Ultrasonic Sensor - HC-SR04 (Generic)
×1
USB-A to Mini-USB Cable
USB-A to Mini-USB Cable
×1
0.96" OLED 64x128 Display Module
ElectroPeak 0.96" OLED 64x128 Display Module
×1
Gravity: I2C BME280 Environmental Sensor
DFRobot Gravity: I2C BME280 Environmental Sensor
×1
NeoPixel Ring: WS2812 5050 RGB LED
Adafruit NeoPixel Ring: WS2812 5050 RGB LED
×1

Software apps and online services

Arduino IDE
Arduino IDE
Fusion 360
Autodesk Fusion 360

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Custom parts and enclosures

thingiverse by NirDobovizki

Used this robot face design, I am going to design the head and possibly adding some leds as a side project.

faceouter_GfXDWYrtPF.stl

Button Design

Fits perfectly over a tactile button switch

Schematics

Smart Room Controller - Break Alarm with Mood Lighting Fritzing

Schematic

Code

Code Sample

C/C++
/*
 * Project:     Smart_Room_Controller: Cohort 4 Midterm
 * Description: Controls two modes: Default mode (working) and Break mode
 *              to encourge a worker to get up from desk and move their body.
 * Author:      Carli Stringfellow
 * Date:        04-12-2021
 */
 
#include <OneButton.h>
#include <SPI.h>
#include <Ethernet.h>
#include <Encoder.h>
#include <mac.h>
#include <wemo.h>
#include <hue.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_BME280.h>
#include <Adafruit_NeoPixel.h>
#include "colors.h"

//Pixel declarations
 const int PIXELPIN = 21;
 const int PIXELCOUNT = 12;
 int r;
 int p;
 Adafruit_NeoPixel pixel(PIXELCOUNT, PIXELPIN, NEO_GRB + NEO_KHZ800);
 int currentTime;
 int lastSecond;
 
 //Ultrasonic declarations
 const int echoPin = 7; 
 const int trigPin = 6;
 unsigned long duration; // variable for the duration of sound wave travel
 int distance; // variable for the distance measurement
 int lastDistance;
 int dist_cm;
 float inches;
 
 //Bme declarations
 const int chipSelect = 4;
 float tempF;
 float humidRH; 
 Adafruit_BME280 bme;
 char D = 248;
 
 //oled declarations
 const int SCREEN_WIDTH = 128; // OLED display width, in pixels
 const int SCREEN_HEIGHT = 64; // OLED display height, in pixels
 const int SCREEN_ADDRESS = 0x3C; 
 char N = 164;
 const int OLED_RESET = 4; 
 int rot = 0;
 Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
 EthernetClient client;
 bool status;
  
 // Orange and yellow button declarations
 OneButton orangeButton (14, false);
 OneButton yellowButton (15, false);
 bool orangeButtonState;
 bool yellowButtonState;
 const int TEAPOT = 3;
 const int FAN = 2;
 float f = tempF;
 bool manualFan;

// Encoder declarations 
 OneButton encoderButton(20, true, true); 
 Encoder myEnc(22,23);
 bool encoderButtonState = true;
 bool firstRelax = true;
 const int REDLED = 16;
 const int GREENLED = 17;
 int position;
 const int ENMIN = 0;
 const int ENMAX = 96;
 const int HUEMIN = 0;
 const int HUEMAX = 12;
 int HueBri;
 int b = 0;
 // Hue lights arrays used in defaultMode and breakMode functions
 int HueWork[] = {HueBlue, HueGreen, HueBlue, HueIndigo, HueGreen};
 int HueRelax[] = {HueRed, HueYellow, HueOrange, HueRed, HueYellow};

 // Timer Declarations
 unsigned long startTimer;
 bool timerON = true;
 const int sittingDistance = 50;
 const int sittingTime = 15000;
 bool takingBreak;
 
void setup() {
  pixel.begin();
  pixel.show();
  pixel.setBrightness(20);
  Serial.begin(9600); //Turns on serial monitor
  bme.begin(0x76); // Turns on bme sensor
  pinMode(trigPin, OUTPUT); // Sets the trigPin as an OUTPUT
  pinMode(echoPin, INPUT); // Sets the echoPin as an INPUT
  display.setRotation(rot); // Sets rotation to rot = 0
  lastDistance = 0; 

  
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
    if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
      for(;;); // Don't proceed, loop forever
    }
  // Show initial display buffer contents on the screen --
  // the library initializes this with an Adafruit splash screen.
  display.display();
  delay(2000); // Pause for 2 seconds
  display.clearDisplay(); // Clears display buffer
  
  // orangebutton set up
  orangeButton.attachClick(orangeClick);
  orangeButton.setClickTicks(500);
  orangeButton.setPressTicks(2000);
 
  //yellowbutton set up
  yellowButton.attachClick(yellowClick);
  yellowButton.setClickTicks(500);
  yellowButton.setPressTicks(2000);

  //encoderbutton set up
  pinMode(REDLED,OUTPUT);
  pinMode(GREENLED,OUTPUT);
  encoderButton.attachClick(encoderClick);
  encoderButton.attachLongPressStart(resetToDefault);
  encoderButton.setClickTicks(500);
  encoderButton.setPressTicks(2500);

  // Ensures all SPI devices are off
  pinMode(10, OUTPUT);
  digitalWrite(10, HIGH);
  pinMode(4, OUTPUT);
  digitalWrite(4, HIGH);
  
  //Start ethernet connection
  status = Ethernet.begin(mac);
    if (!status) {
      Serial.printf("failed to configure Ethernet using DHCP \n");
      //no point in continueing 
      while(1);
    }
}

void loop() {
  ultraSonic();
  
  orangeButton.tick(); // checks teapot buttonstate
 
  yellowButton.tick(); // checks fan buttonstate
 
  encoderButton.tick(); // encoder controls brightness and toggles hues on/off 
   
  if(!takingBreak) {
  defaultMode(); // Calls main function (the working mode)
  }
//    breakMode();

}
void orangeClick() { // Toggles teapot wemo
  orangeButtonState = !orangeButtonState;
    if(orangeButtonState) {
      switchON(TEAPOT);
    }
    else {
     switchOFF(TEAPOT); 
    }
//  Serial.printf("orangeButtonState = %i", orangeButtonState);
}

void yellowClick() { // Toggles fan wemo
  yellowButtonState = !yellowButtonState;
  manualFan = true;
       if(yellowButtonState) {
        switchON(FAN);
      }
      else {
        switchOFF(FAN);
      }
  
//  Serial.printf("yellowButtonState = %i", yellowButtonState);
}
void encoderClick() { // turns hues off
  encoderButtonState = !encoderButtonState;
//  Serial.printf("encoderButtonState = %i\n", encoderButtonState);
}

void defaultMode() { //this is work mode as the most time is spent here
  pixel.clear();
  display.clearDisplay();
  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw WHITE text
  display.setCursor(0,0);             // Start at top-left corner
  
  tempF = 1.8*(bme.readTemperature())+32; // Converts celsius to fahrenheit
  display.printf("Tempurature is %0.1f%c\n" ,tempF, D);
//  Serial.printf("Tempurature is %0.1f\n" ,tempF);

  humidRH = bme.readHumidity(); // displays humidity
  display.printf("Humidity is %0.1f\n" ,humidRH);
//  Serial.printf("Humidity is %0.1f\n" ,humidRH);
  display.printf("Distance:\n%0.01f inches\n\n", inches);
  display.printf("\n");
  display.printf("\n");

  display.printf("You are in WORK MODE");
  display.display();

    if(manualFan == false) {
      if(tempF >= 75){
      yellowClick();
      }
    }

  position = myEnc.read(); //sets parameter for encoder
  
    if (position > 96) {
      position = 96;
      myEnc.write(96);
    }
  
    if (position < 0) {
          position = 0;
          myEnc.write(0);  
    }
  // default (work mode) lighting  
  HueBri = map(position, ENMIN, ENMAX, HUEMIN, HUEMAX); //maps encoder to huebrightness
//  Serial.printf("%i", HueBri);
  currentTime = millis();
    if((currentTime-lastSecond) > 1000) {
      for(b=1; b<=5; b++) {
        if(encoderButtonState == true) {
          digitalWrite(REDLED,LOW);
          digitalWrite(GREENLED,HIGH);
          setHue(b, true, HueWork[b-1], HueBri*20, 190);
          }
        else {
          digitalWrite(REDLED,HIGH);
          digitalWrite(GREENLED,LOW);
          setHue(b, false, HueWork[b-1], 0, 0);
        }
      }
        lastSecond = millis();
    }        
    if(timerON) {
    if((millis() - startTimer) > sittingTime) {
      if(inches <= sittingDistance) {
        breakMode();
        timerON = false;
        Serial.printf("timer: \n", timerON);
      }
    }
  }
  pixel.show();
  pixel.clear();
}


void breakMode() { // automatic mode triggered by ultrasonic wave in inches
  takingBreak = true;
  display.clearDisplay();
  display.setTextSize(1);             // Normal 1:1 pixel scale
  display.setTextColor(SSD1306_WHITE);        // Draw WHITE text
  display.setCursor(0,0);             // Start at top-left corner
  
  display.printf("\n");
  display.printf("Time to Relax\n");
  display.printf("\n");
  display.printf("Take a Break\n");
  display.printf("\n");
  display.printf("STRETCH YOUR BODY\n");
  display.printf("\n");
  display.display();

  for(b=1; b<=5; b++) {
    setHue(b, true, HueRelax[b-1], 255, 255);
  }
  // flashes pixel ring in different colors to simulate an alarm
   pixel.clear();
    for(p=0;p<PIXELCOUNT;p++) {
      r = random(0x000000, 0xFFFFFF);
      pixel.fill(r,p,12);
      pixel.show();
    }
   Serial.printf("Timer status:\n", timerON);
 }

void resetToDefault() { // Uses longpress on the encoder to reset to default mode
  takingBreak = false; 
  defaultMode();
  manualFan = false;
  timerON = true;
  firstRelax = true;
  startTimer = millis();
  pixel.clear();
}
void ultraSonic() {
  //Sends ultrasonic pulse
  digitalWrite(trigPin, LOW); // Clears the trigPin condition
  delayMicroseconds(2);
  
  // Sets the trigPin HIGH (ACTIVE) for 10 microseconds
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  
  // Reads the echoPin, returns the sound wave travel time in microseconds
  duration = pulseIn(echoPin, HIGH);
  // Calculates the distance
  distance = duration * 0.34 / 2; // time passed * speed of sound divided by 2 (go and back)
  dist_cm = distance / 10;
  inches = dist_cm * 0.3937;
  
  // Displays the distance on the Serial Monitor
 
    Serial.printf("Distance:\n%0.02f inches\n\n", inches);
    lastDistance = distance;
}

Smart Room Controller - Break Alarm with Mood Lighting

This is a smart room controller that allows control over the lighting and two wemo outlets. There are two modes: default (working) mode and break mode which is triggered by a user not moving from a certain distance for a certain amount of time. The user is able to turn on and off a room fan and a teapot using buttons and control the brightness of the room from their desk using an encoder.

Credits

Carli Stringfellow

Carli Stringfellow

3 projects • 4 followers
Hello! My name is Carli Stringfellow. I am a beginner developer gaining experience in electronics, hardware design, and C++ coding.

Comments