Project tutorial
Beautifully Finished Humidity and Temperature Sensor

Beautifully Finished Humidity and Temperature Sensor © GPL3+

We built a stylish and useful humidity and temperature sensor for our home workshop that uses color to alert us to big swings in humidity.

  • 16,314 views
  • 21 comments
  • 133 respects

Components and supplies

Necessary tools and machines

09507 01
Soldering iron (generic)
Hy gluegun
Hot glue gun (generic)

About this project

The Story Behind This Project

Learn how we built a walnut dovetailed case and used easy-to-find Arduino components to build a stylish and useful humidity and temperature monitor for the wood shop. This DIY project showcases a bit of woodworking with walnut dovetails and beginner electronics using an Arduino Uno and some excellent parts from Adafruit.

We live in Central Texas where we get massive swings in Humidity and Temperature in the Spring, which can be disastrous for certain woodworking projects. This cool project helps alert us when the humidity is changing or starts to get high so we can take precautions like moving our wood projects into the house, or not doing any milling during the high humidity weather. It also looks awesome and has our sweet logo!

We are new to Arduino and Electronics so we learned as we went when making this. We're very excited to make more projects now that we know how easy it is to make great things.

Watch the Detailed Build Video!

How to Make an Arduino Humidity Sensor (Full Build Video)

Code

Arduino Work Shop Sensor CodeArduino
#include <Adafruit_NeoPixel.h>
#include <Adafruit_ST7735.h>
#include <Adafruit_GFX.h>
#include <FastLED.h>
#include <SPI.h>
#include <SD.h>
#include <cactus_io_DHT22.h> // There's a bunch of DHTXX libraries you can find online. They all have varying levels of features.

// Define Pins
#define TFT_CS    10
#define TFT_RST   9
#define TFT_DC    8
#define DHT_PIN   2
#define PIXEL_PIN 6
#define PIXEL_NUM 24
#define SD_PIN    4
#define BMP_BUF   20  

// Global Variables
int currentColor = 9999; //(Numbers correspond to chart. See below.)
CRGB leds[PIXEL_NUM];
Adafruit_ST7735   tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
DHT22 dht(DHT_PIN);
int loopDelay = 2000; //ms

// SETUP
void setup() {
 
  Serial.begin(9600);
  Serial.println("Starting up.");

  // Begin DHT
  dht.begin();

  // Initialize LCD Screen
  tft.initR(INITR_144GREENTAB);

  // Initialize SD Card
  Serial.print("Initializing SD card.");
  if (!SD.begin(SD_PIN)) {
    Serial.println("Failed!");
    return;
  }

  // Set Screen Background to Black
  tft.fillScreen(ST7735_BLACK);

  // Initialize LEDs
  FastLED.addLeds<NEOPIXEL, PIXEL_PIN>(leds, PIXEL_NUM);

  // Let everything catch up before starting loop
  delay(500);

}


// LOOP
void loop() {

  // Get Sensor Data
  dht.readTemperature();
  dht.readHumidity();
  int f = dht.temperature_F; // Degrees in Fahrenheit
  int h = dht.humidity; // Percentage

  // Draw Degrees Icon
  tft.fillCircle(102, 42, 6, ST7735_WHITE);
  tft.fillCircle(102, 42, 4, ST7735_BLACK);

  // Draw Temperature on LCD Screen
  drawTemperature(f);

  // Humidity
  setHumidityColors(h);
  
  //Print Data to Serial Monitor
  Serial.print("Temperature: ");
  Serial.println(f);
  Serial.print("Humidity: ");
  Serial.print(h);
  Serial.println("%");

  // Delay
  delay(1000);
  
}


// Draw Bitmap - This is for the LCD Screen
void bmpDraw(char *filename, uint8_t x, uint8_t y) {

  File     bmpFile;
  int      bmpWidth, bmpHeight;   // W+H in pixels
  uint8_t  bmpDepth;              // Bit depth (currently must be 24)
  uint32_t bmpImageoffset;        // Start of image data in file
  uint32_t rowSize;               // Not always = bmpWidth; may have padding
  uint8_t  sdbuffer[3*BMP_BUF];   // pixel buffer (R+G+B per pixel)
  uint8_t  buffidx = sizeof(sdbuffer); // Current position in sdbuffer
  boolean  goodBmp = false;       // Set to true on valid header parse
  boolean  flip    = true;        // BMP is stored bottom-to-top
  int      w, h, row, col;
  uint8_t  r, g, b;
  uint32_t pos = 0, startTime = millis();

  if((x >= tft.width()) || (y >= tft.height())) return;

//  Serial.println();
//  Serial.print("Loading Bitmap Image: '");
//  Serial.print(filename);
//  Serial.println('\'');

  // Open requested file on SD card
  if ((bmpFile = SD.open(filename)) == NULL) {
    Serial.print("Bitmap file not found!");
    return;
  }

  // Parse BMP header
  if(read16(bmpFile) == 0x4D42) {
    read32(bmpFile);
    (void)read32(bmpFile);
    bmpImageoffset = read32(bmpFile);
    //Serial.println());
    read32(bmpFile);
    bmpWidth  = read32(bmpFile);
    bmpHeight = read32(bmpFile);
    if(read16(bmpFile) == 1) {
      bmpDepth = read16(bmpFile);
      //Serial.print("Bit Depth: ");
      if((bmpDepth == 24) && (read32(bmpFile) == 0)) {

        goodBmp = true;

        // BMP rows are padded (if needed) to 4-byte boundary
        rowSize = (bmpWidth * 3 + 3) & ~3;

        // If bmpHeight is negative, image is in top-down order.
        // This is not canon but has been observed in the wild.
        if(bmpHeight < 0) {
          bmpHeight = -bmpHeight;
          flip      = false;
        }

        // Crop area to be loaded
        w = bmpWidth;
        h = bmpHeight;
        if((x+w-1) >= tft.width())  w = tft.width()  - x;
        if((y+h-1) >= tft.height()) h = tft.height() - y;

        // Set TFT address window to clipped image bounds
        tft.setAddrWindow(x, y, x+w-1, y+h-1);

        for (row=0; row<h; row++) { // For each scanline...
          if(flip) {
            pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
          } else {
            pos = bmpImageoffset + row * rowSize;
          }
          if(bmpFile.position() != pos) {
            bmpFile.seek(pos);
            buffidx = sizeof(sdbuffer);
          }

          for (col=0; col<w; col++) {
            if (buffidx >= sizeof(sdbuffer)) {
              bmpFile.read(sdbuffer, sizeof(sdbuffer));
              buffidx = 0;
            }

            // Convert pixel from BMP to TFT format, push to display
            b = sdbuffer[buffidx++];
            g = sdbuffer[buffidx++];
            r = sdbuffer[buffidx++];
            tft.pushColor(tft.Color565(r,g,b));
          }
        }
      }
    }
  }

  bmpFile.close();
  if(!goodBmp) Serial.println("BMP format not recognized.");

}

// This is for the Bitmap/LCD Screen
uint16_t read16(File f) {
  uint16_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read(); // MSB
  return result;
}

// This is for the Bitmap/LCD Screen
uint32_t read32(File f) {
  uint32_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read();
  ((uint8_t *)&result)[2] = f.read();
  ((uint8_t *)&result)[3] = f.read(); // MSB
  return result;
}


// Draw Temperature on LCD Screen
void drawTemperature(int temp) {

  // Get Number of Digits in the Temperature
  int digits = numDigits(temp);
 
  // Define Cursor Positions to Draw Bitmaps
  int x1_2 = 62;
  int x2_2 = 32;
  int x1_3 = 1;
  int x2_3 = 1;
  int x3_3 = 1;
  int y = 38;

  char digit1[12];
  char digit2[12];
  char digit3[12];
  char digitStr1[24];
  char digitStr2[24];
  char digitStr3[24];
  
  // Get First Digit
  itoa(temp % 10, digit1,10); 
  //Serial.println(temp % 10);
  strcpy(digitStr1, "");
  strcat(digitStr1, digit1);
  strcat(digitStr1, ".bmp");

  // Get Second Digit
  if(digits == 2){
    itoa((temp / 10) % 10, digit2,10);
    strcpy(digitStr2, "");
    strcat(digitStr2, digit2);
    strcat(digitStr2, ".bmp");
  }

  // Get Third Digit
  if(digits == 3){
    itoa((temp / 100) % 10, digit3,10);
    strcpy(digitStr3, "");
    strcat(digitStr3, digit3);
    strcat(digitStr3, ".bmp");
  }  
  
  if(digits > 2){
    bmpDraw(digitStr1,x1_3,y);
    bmpDraw(digitStr2,x2_3,y);
    bmpDraw(digitStr3,x3_3,y);
  } else {
    bmpDraw(digitStr1,x1_2,y);
    bmpDraw(digitStr2,x2_2,y);
  }

}


// Get number of digits in temperature to determine placement on screen
int numDigits(int number){

  int valLen = 0;  
  if(number > 99)
    valLen = 3;
  else
    valLen = 2;
  return valLen;

}


// Set LED Colors
void setColors(int r, int g, int b){

  for(int i = 0; i < PIXEL_NUM; i++){
    
    leds[i].setRGB( r, g, b);
    leds[i].fadeLightBy(125);
    FastLED.show();    
    delay(100);
  
  }
  
}


// Determine which colors to use based on Humidity level
void setHumidityColors(int humidity){

  // Humidity Color Chart - This is just something we came up with.
  // Red - 0-17%
  // Orange - 18-34%
  // Yellow - 35-51%
  // Green - 52-68%
  // Blue - 69-85%
  // Purple - 86-100%

  // Define Colors
  int cRed[3] = {255,0,0};
  int cOrange[3] = {255,90,0};
  int cYellow[3] = {255,255,0};
  int cGreen[3] = {0,255,0};
  int cBlue[3] = {0,175,255};
  int cPurple[3] = {255,0,255};

  int range = map(humidity, 0, 100, 0, 6);
  switch (range) {
    case 0:    // Red
      if(currentColor == 0){
        break;
      }
      else {
        setColors(cRed[0], cRed[1], cRed[2]);
        currentColor = 0;
      }
      break;
    case 1:    // Orange
      if(currentColor == 1){
        break;
      }
      else {
        setColors(cOrange[0], cOrange[1], cOrange[2]);
        currentColor = 1;
      }
      break;
    case 2:    // Yellow
      if(currentColor == 2){
        break;
      }
      else {
        setColors(cYellow[0], cYellow[1], cYellow[2]);
        currentColor = 2;
      }
      break;
    case 3:    // Green
      if(currentColor == 3){
        break;
      }
      else {
        setColors(cGreen[0], cGreen[1], cGreen[2]);
        currentColor = 3;
      }
      break;
    case 4:    // Blue
      if(currentColor == 4){
        break;
      }
      else {
        setColors(cBlue[0], cBlue[1], cBlue[2]);
        currentColor = 4;
      }
      break;
    case 5:    // Purple
      if(currentColor == 5){
        break;
      }
      else {
        setColors(cPurple[0], cPurple[1], cPurple[2]);
        currentColor = 5;
      }      
      break;
  }
}

Custom parts and enclosures

Arduino Work Shop Sensor Plans
Shopsensor plans full v2skbtngss

Schematics

Schematic
Fritzing didn't have most of the actual components so I did my best to represent the flow of things.
Capture u2znixkflq
Picture of Actual Setup
Dsc00298 2bludktwby

Comments

Similar projects you might like

Arduino Bluetooth Basic Tutorial

by Mayoogh Girish

  • 454,698 views
  • 42 comments
  • 237 respects

Home Automation Using Raspberry Pi 2 And Windows 10 IoT

Project tutorial by Anurag S. Vasanwala

  • 285,524 views
  • 95 comments
  • 671 respects

Security Access Using RFID Reader

by Aritro Mukherjee

  • 229,411 views
  • 38 comments
  • 236 respects

OpenCat

Project in progress by Team Petoi

  • 196,004 views
  • 154 comments
  • 1,363 respects
Add projectSign up / Login