An automated work desk light, AC control, and assistant...
This project came to life when I started wondering if I had left the work desk light on? Is the soldering iron still on? I needed some automation at my desk to reliably determine when I'm at my desk and do a few things:
- Switch on the strip light when I sit down.
- Give me the ability to turn on the bright LED desk light
- Ability to DIM all lighting
- Give me the ability to turn on the desk AC (soldering iron, etc)
- Ability to use a single touch switch for all activity
- Know when I LEAVE the desk and turn off everything.
- Give Basic desk temp/humidity
- Be expandable for future additions of sensors and probes to assist with development
The MosFETs are SMD but can be easily soldered to a three pin header for breadboarding... these FETs have a very low (2v) gate voltage along with a very low on resistance of about 200 mOhms enabling these to switch high currents without much dissipation.
The 10 watt LED should be attached to a heat sink... I used a CPU cooler heat sink readily available and then just attached the LED to it using heat-sink tape.
Once you assemble the circuit, load this sketch and have fun! I look to enhance this as I use it and will update this when that happens.
Once you assemble the circuit, load this sketch and have fun! I look to enhance this as I use it and will update this when that happens.
/*
* Workdesk Assistant
* Tim Stoddard
* Released to public domain with this credit given
* Press switch:
* short < 1 sec to toggle between 'panels'
* medium 2 sec to light 10w LED on panel 1 only
* long 3 sec to turn on AC on panel 1 only
* really long 4 sec unused
*
* Note you can define different uses of the presses on each 'panel'
* You can code any number of 'panels' ... don't forget to code the activities for that panel
* as needed.
*/
// Define some pins...
#define StripLED 5
#define acPlug 4 // controlled AC
#define MainLED 3
#define psw 12
//display
#define sclk 13 // SCL in Sainsmart
#define mosi 11 // SDA
#define cs 10
#define dc 9
#define rst 8
#define bright A0
#define range A1
#define lcdBacklite 6 //LCD pwm dimmer
#include <Adafruit_GFX.h> // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library
#include <SPI.h>
#include <dht.h>
dht DHT;
#define DHT11_PIN 7
Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, rst);// instantiate the panel
int v = 0;// variable to hold the ADC value from pot
int r = 0;// variable to hold the ADC range value
bool mLED = false;
bool sLED = false;
bool ACplug = false;
unsigned long rTimeout = 0;
unsigned long dhtTimeout = 0;
unsigned long distTimeout = 0;
unsigned long buttonTime = 0;
unsigned long currentButtonTime = 0;
unsigned long lastButtonTime = 0;
const int numReadings = 100;
const float Vi = 4.95/512;// sonar scaling vcc/512
const float adcV = 4.95/1024;// aDC scaling vcc/1024
uint16_t readings[numReadings]; // the readings from the analog input
uint16_t readIndex = 0; // the index of the current reading
uint16_t total = 0; // the running total
uint16_t average = 0; // the average
uint16_t currT = 0;
uint16_t lastT = 0;
uint16_t currH = 0;
uint16_t lastH = 0;
float currD = 0;
float lastD = 0;
bool buttonActive = false;
uint16_t buttonState = 0;// button press 1 to 4
uint16_t lastButtonState = 0;// button press 1 to 4
uint16_t displayButtonState = 0;// button press 1 to 4
uint16_t currentButtonState = 0;// button press 1 to 4
uint16_t currentPanel = 0;
uint16_t lastPanel = 1;// forces initial screen write
uint16_t selectPanel = 0;
uint16_t dispMode = 0;// display mode
unsigned long getButtonTime(void){
if(digitalRead(psw)&& !buttonActive){
buttonActive = true;
buttonTime = millis(); // set start of time measurement
}
if(buttonActive && (!digitalRead(psw))){
buttonActive=false;
return millis()-buttonTime;
}
return 0;
}
void setup() {
// set 3,5 pins as outputs for PWM
pinMode(StripLED, OUTPUT);
pinMode(MainLED, OUTPUT);
pinMode(acPlug, OUTPUT);
pinMode(psw,INPUT);
// turn them all off
digitalWrite(StripLED,LOW);
digitalWrite(MainLED,LOW);
digitalWrite(acPlug,LOW);
analogReference(DEFAULT);// make sure Vref is VCC
Serial.begin(9600);
// initialize all the readings to 0:
for (int thisReading = 0; thisReading < numReadings; thisReading++) {
readings[thisReading] = 0;
}
tft.initR(INITR_BLACKTAB); // initialize a ST7735S chip
int chk = DHT.read11(DHT11_PIN);
switch(chk)// sync up/initialize the DHT11
tft.setTextWrap(false);
tft.fillScreen(ST7735_BLACK);
tft.setCursor(0,0);
tft.setTextColor(ST7735_WHITE);
tft.setTextSize(2);
panelMain();
// tft.println(Vi,6);// print the sonar scaling
// tft.println(adcV,6);// print the adc scaling
}
uint16_t getbuttonState(void){
currentButtonTime = getButtonTime();
if(currentButtonTime){
// lastButtonTime = printValue(lastButtonTime,currentButtonTime,ST7735_YELLOW,10,153,1);
if(currentButtonTime<500){
return 1; // short press
}else if (currentButtonTime<1500){
return 2; // regular press
}else if (currentButtonTime<3000){
return 3; // long press
}else{
return 4; // really long press
}
}else{
return 0;
}
}
void loop() {
// check for a button state and act on it ... include checking for a specific panel to issolate
// press type to only that panel
buttonState = getbuttonState();
if(buttonState){
displayButtonState = buttonState;// store the button state for display
switch (buttonState){
case 1: // short press
if (++selectPanel>2){selectPanel=0;} // change to increase number of panels
currentPanel = panel(selectPanel);
break;
case 2: // medium press 2 sec
if(currentPanel==0){mLED=!mLED;} // toggle the 10w LED
break;
case 3: // long press 3 sec
if(currentPanel==0){ACplug=!ACplug;} // toggle the AC line
break;
case 4: // really long press 4 sec
// unused so far
break;
}
}
lastPanel = printValue(lastPanel,currentPanel,ST7735_BLUE,123,153,1);// display panel number at lower right corner of panel
lastButtonState = printValue(lastButtonState,displayButtonState,ST7735_GREEN,0,153,1);// display last button state at lower left corner of panel
activity(currentPanel);// do panel activity of currently selected panel
// read the 'dimmer' pot and generate a PWM to dim the LEDs
v=analogRead(bright);// read the pot
v=map(v,0,1024,0,255);// map the 10 bit value to 8 bit value for PWM
/* Get and calculate the range */
// subtract the last reading:
total = total - readings[readIndex];
// read from the sensor:
readings[readIndex] = analogRead(range);
// add the reading to the total:
total = total + readings[readIndex];
// advance to the next position in the array:
readIndex = readIndex + 1;
// if we're at the end of the array...
if (readIndex >= numReadings) {
readIndex = 0;// ...wrap around to the beginning:
}
r = total / numReadings;// calculate the average distance
r = (r*adcV)/Vi;// convert to inches
// if the range sensor indicates a close presence in inches, turn on the strip LED
if(r<36){
analogWrite(StripLED,v);// PWM command brightness is 0-255
rTimeout = millis();
}else if(millis() - rTimeout > 30000){ //30 secs timer before turning off LED
digitalWrite(StripLED,LOW);
mLED = false;
ACplug = false;
} // Turn on or off the MainLED based on the mLED bool variable
if(mLED){
analogWrite(MainLED,v);// PWM command brightness is 0-255
tft.setCursor(50,153);
tft.setTextSize(1);
tft.setTextColor(ST7735_WHITE);
tft.println("LED");
}else{
digitalWrite(MainLED,LOW);
tft.setCursor(50,153);
tft.setTextSize(1);
tft.setTextColor(tft.Color565(64, 64, 64));
tft.println("LED");
}
if(ACplug){
digitalWrite(acPlug,HIGH);
tft.setCursor(32,153);
tft.setTextSize(1);
tft.setTextColor(ST7735_YELLOW);
tft.println("AC");
}else{
digitalWrite(acPlug,LOW);
tft.setCursor(32,153);
tft.setTextSize(1);
tft.setTextColor(tft.Color565(64, 64, 64));
tft.println("AC");
}
}
uint16_t panel(uint16_t i){
if(currentPanel!=i){
switch(i){
case 0:
panelMain();
break;
case 1:
panelSensors();// turn on the sensors panel
lastD = 0;// reset last readings to force update
lastT = 0;
lastH = 0;
break;
case 2:
panelBlank();
break;
}
// display the last button state at bottom left of display
tft.setCursor(0,153);
tft.setTextSize(1);
tft.setTextColor(ST7735_GREEN);
tft.print(displayButtonState);
return i;
}
}
void activity(uint16_t a){
switch(a){
case 1:
activitySensors();
break;
}
}
void panelMain(){
tft.fillScreen(ST7735_BLACK);
tft.setCursor(0,0);
tft.setTextColor(0x867D);
tft.setTextSize(2);
tft.println("Workdesk");
tft.println("Assistant");
}
void panelBlank(void){
tft.fillScreen(ST7735_BLACK);
tft.setCursor(0,64);
tft.setTextColor(ST7735_BLUE);
tft.setTextSize(2);
tft.println(" BLANK");
}
void panelSensors(void){
tft.fillScreen(ST7735_BLACK);
tft.setCursor(0,0);
tft.setTextColor(ST7735_BLUE);
tft.setTextSize(2);
tft.println("Temp: ");
tft.print("Hmty: ");
tft.setCursor(0,64);
tft.println("Dist:");
}
void activitySensors(void){
//update distance
if(millis()-distTimeout > 250){ // every 250 milliseconds
lastD = printValue(lastD,r,ST7735_YELLOW,60,64,2);
distTimeout=millis();
}
//update temp and Humity
if(millis()-dhtTimeout > 5000){ // every 5 seconds
printDTH();
dhtTimeout=millis();
}
}
uint16_t printValue(uint16_t last,uint16_t current,uint16_t color,uint16_t col,uint16_t row,uint16_t textsize){
if(last != current){
tft.setTextColor(ST7735_BLACK);
tft.setTextSize(textsize);
tft.setCursor(col,row);
tft.print(last);
tft.setTextColor(color);
tft.setCursor(col,row);
tft.print(current);
}
return current;
}
void printDTH(void){
int chk = DHT.read11(DHT11_PIN);
switch(chk)
tft.setTextWrap(false);
currT = DHT.temperature * 1.8 + 32;
lastT = printValue(lastT,currT,ST7735_YELLOW,60,0,2);
currH = DHT.humidity;
lastH = printValue(lastH,currH,ST7735_YELLOW,60,16,2);
}
No comments:
Post a Comment