You are on page 1of 17

Envirometer 1.

2
Electronic clock and temperature/humidity
environment indicator

Basics
The Envirometer is a clock as well as an electronic temperature/humidity and environment
quality indicator. It can be powered either by a USB connector or by a 9V power supply. It is
housed in a custom plastic enclosure and is intended for indoors use.

The front panel has four LED indicators, four switches and an LCD data display.

Page 1 of 17
Operation

The meaning of the front panel switches is as follows:

Switch 1 down: the unit is asleep and only the display is on. Internally, the unit is not
interrogating the clock or the temperature/humidity sensors. If switch 1 is down, no other LEDs
will light up and the display will only display “sleeping”:

EXTRA SET
ON ENV. INFO CLOCK

OFF CLOCK

Switch 1 up: the unit is now a digital clock, displaying time (normally without seconds), date,
and day of week in 24-hour format only (since it is meant to display UTC in a ham radio shack).
The green LED lights up to indicate powered-on status:

Page 2 of 17
Switch 2 up: assuming the unit is on, setting switch 2 up lights up the yellow LED and makes
the unit into a temperature/humidity display (with the temperature in ºC):

Switch 3 is the “show extra info” switch. When UP, this lights the red LED (if S2 is also UP):

In clock mode (switch 2 down), setting switch 3 up adds seconds and rough temperature (as
measured by the real-time clock, which is slightly less accurate - but can provide a useful
“quick check”).

In environment mode (switch 2 up), setting switch 3 up:

• Adds environment status indication. This extra display adds a text status indicator that will,
on the display, ash an indicator either showing “GOOD” (normal comfort range), “MARG”
(marginal, or slightly uncomfortable) or “POOR” (temp/humidity combination is in the
uncomfortable range).

• At the same time, the according green, yellow or red LEDs will emit a slow ash (every 2.5
seconds, the LED turns o brie y), where green means Good, yellow means Marginal and
red means Poor.

Page 3 of 17
fl
ff
fl
fl
The temperature below that indicator is the DHT22’s calculated “heat index” in ºC. This is an
alternate “apparent heat” indicator.

The “good/marginal/poor” status is calculated using the following graph, where the
“comfortable” zone is calculated as in the graph, and the delineation of the outer “still
comfortable” (=marginal) range (and hence also the “poor” range) is closely approximated:

Switch 4 is a switch in the prototype, but will be replaced by a pushbutton. If the unit is in
clock mode, pushing that button for 3 seconds puts the clock in the “time set” mode, and the
blue LED lights up. (If the unit is not in clock mode, switch 4 does nothing).

To set the time, simply wait until the variable you wish to change comes up, and then press the
button the required number of times until the value is right. Then wait: saving occurs
automatically. After all variables have been shown, the unit returns to clock display mode and
the blue LED turns o .

Page 4 of 17
ff
Technical details
The unit uses an Arduino Uno R3 as its controller. The clock is a DS3231 Real-Time Clock
module, and the temp/hum sensor is an internally mounted DHT22. To ensure an accurate
reading, the DHT22 is mounted right behind one of the openings in the back panel.

Circuit diagram:

SW 4-1
SW4 should be pushbutton
(down = GND)

ss
LED 4-1

4x 220 Ohm

DHT22

sss

Page 5 of 17
Internals and rear view:

AUTHOR: Michael Willems

www.michaelwillems.ca

michael@willems.ca

Page 6 of 17
Arduino Code:

/* RTC-mw_v2-boxed.ino
* Author: MICHAEL WILLEMS
* Date: 2021/07/07
* Function: Digital Clock using Arduino with RTC, plus DHT22 temp/hum sensor with
* "comfort zone" indicator.
* switch/LED function detailed in manual
* Version: 1.1 */

/* -----------------------------------------------------------------------------------
INCLUDES, DEFS, ETC:
------------------------------------------------------------------------------------*/
#include <LiquidCrystal.h> // for LCD display
#include <DHT.h> // for temp/humidity sensor DHT22
#include <DS3231.h> // for real-time clock
#include <Wire.h> // for I2C comms
#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
#define DHTPIN 10
DHT dht(DHTPIN, DHTTYPE);
DS3231 Clock;
boolean Century=false;
boolean h12;
boolean PM;
byte ADay, AHour, AMinute, ASecond, ABits;
boolean ADy, A12h, Apm;
char *dayString[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
int second,minute,hour,date,month,year,val,dow,temp;
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int button = 13;
int spaces;
boolean ledstate = false;
boolean led2state = false;
long buttonTimer = 0;
long longPressTime = 1000;
long exitSetupTime = 4000;
boolean buttonActive = false;
boolean longPressActive = false;
int greenled = 6;
int yellowled = 7;
int redled = 8;
int blueled = 9;
unsigned long counter;
float h;
float t;
float hic;

Page 7 of 17

/* -----------------------------------------------------------------------------------
SETUP:
------------------------------------------------------------------------------------*/
void setup(){
// pinMode(led, OUTPUT);
pinMode(greenled, OUTPUT);
pinMode(yellowled, OUTPUT);
pinMode(redled, OUTPUT);
pinMode(blueled, OUTPUT);
pinMode (A3, INPUT); //switch 1
pinMode (A2, INPUT); //switch 2
pinMode (A1, INPUT); //switch 3
pinMode (A0, INPUT); //switch 4
pinMode(button,INPUT);
Wire.begin();
dht.begin();
Serial.begin(115200);
lcd.begin(16,2);
lcd.print("ENVIROMETER V1.1");
lcd.setCursor(0,1);
lcd.print("Starting.... ");
delay(250);
digitalWrite (blueled, HIGH);
digitalWrite (greenled, HIGH);
digitalWrite (yellowled, HIGH);
digitalWrite (redled, HIGH);
delay(250);
for(int i=0;i<6;i++){ // now display some moving dots...
spaces=0;
while (spaces<i){
spaces=spaces+1;
lcd.print(" ");
}
lcd.print(".");
lcd.setCursor(10,1);
delay(250);
}
digitalWrite (blueled, LOW);
digitalWrite (greenled, LOW);
digitalWrite (yellowled, LOW);
digitalWrite (redled, LOW);
lcd.setCursor(15,1);
lcd.print(" ");
delay(500);
lcd.clear(); // let's clear the display and led, and start.
counter=millis();
digitalWrite(blueled, LOW);
}

Page 8 of 17

/* -----------------------------------------------------------------------------------
MAIN LOOP:
------------------------------------------------------------------------------------*/
void loop()
{
// Display green led if switch one is on:
if (digitalRead(A3) == LOW) {
digitalWrite (greenled, LOW);
digitalWrite (yellowled, LOW);
digitalWrite (redled, LOW);
lcd.setCursor(0,0);
lcd.print(" SLEEPING ");
lcd.setCursor(0,1);
lcd.print(" ");
return; //exit and do nothing else, for we are sleeping
}
else {
digitalWrite (greenled, HIGH);
}

// The box is on, so now display the other LEDs:


//
if (digitalRead(A2) == LOW) {
digitalWrite (yellowled, LOW);
}
else {
digitalWrite (yellowled, HIGH);
}

if (digitalRead(A1) == LOW) {
digitalWrite (redled, LOW);
}
else if (digitalRead(A2)== HIGH){
digitalWrite (redled, HIGH);
}
else {
digitalWrite (redled, LOW);
}

//
// Now we test if we want to display humidity/temp (else, move on to being a clock)
//
if (digitalRead(A2)==HIGH) { // Switch 2 is up? Then we display hum/temp
if (millis()-counter > 2300) { // Only sample every >2 seconds
h = dht.readHumidity(); // Read humidity
t = dht.readTemperature()-0.5; // Read temp in C less correction (0.5C)
hic = dht.computeHeatIndex(t, h, false); // Compute heat index in C
lcd.setCursor(0,0);
lcd.print("HUMID TEMP ");

Page 9 of 17

lcd.setCursor(0,1);
lcd.print (h,1);
lcd.print ("% ");
lcd.setCursor(6,1);
lcd.print (t,1);
lcd.print ("C ");
if (digitalRead(A1)==HIGH) {
lcd.setCursor(12,1);
lcd.print (hic,1);
}
if (h<((-0.417*t)+47.2-10) or h>((-1.71*t)+104+10) or t<((h-264)/-11.3-2) or
t>((h-421)/-15.8+2)) {
//uncomfortable!
if (digitalRead(A1)==HIGH) {
digitalWrite(redled, LOW);
delay(200);
digitalWrite(redled, HIGH);
lcd.setCursor(12,0);
lcd.print ("POOR");
}
}
else if (h<((-0.417*t)+47.2) or h>((-1.71*t)+104) or t<((h-264)/-11.3) or
t>((h-421)/-15.8)) {
//marginal...
if (digitalRead(A1)==HIGH) {
digitalWrite(yellowled, LOW);
delay(200);
digitalWrite(yellowled, HIGH);
lcd.setCursor(12,0);
lcd.print ("MARG");
}
}
else {
//comfzone
if (digitalRead(A1)==HIGH) {
digitalWrite(greenled, LOW);
delay(200);
digitalWrite(greenled, HIGH);
lcd.setCursor(12,0);
lcd.print ("GOOD");
}
}
counter = millis(); //reset counter
}
} //end of hum/temp display

else { //if sw2 = low then we are a clock


ReadDS3231();
if (digitalRead(button) == HIGH) {
if (buttonActive == false) {

Page 10 of 17

buttonActive = true;
buttonTimer = millis();
}
if ((millis() - buttonTimer > longPressTime) && (longPressActive == false)) {
longPressActive = true;
ledstate = !ledstate;
digitalWrite (blueled, ledstate);
setclock(); ///the set clock
}
} else {
if (buttonActive == true) {
if (longPressActive == true) {
longPressActive = false;
}
}
buttonActive = false;
}
} //end of clock bit (sw2=low)
} //end of loop

/* -----------------------------------------------------------------------------------
FUNCTIONS:
------------------------------------------------------------------------------------*/

//------------------------------
// read and display time
//------------------------------
void ReadDS3231()
{
int second,minute,hour,date,month,year,pm;
second=Clock.getSecond();
minute=Clock.getMinute();
hour=Clock.getHour(h12,PM);
date=Clock.getDate();
month=Clock.getMonth(Century);
year=Clock.getYear();
temp=Clock.getTemperature();
dow=Clock.getDoW();
//------print line 1:----------------------------
lcd.setCursor(0,0);
lcd.print(" 20");
lcd.print(year); // year (2 digits)
lcd.print('-');
if (month<10){
lcd.print("0"); // leading zero
}
lcd.print(month,DEC); // month
lcd.print('-');
if (date<10){

Page 11 of 17

lcd.print("0"); // leading zero


}
lcd.print(date,DEC); // date
lcd.print(" ");
lcd.print(dayString[dow]); // day of week
lcd.print(" ");

//-------print line 2:---------------------------


lcd.setCursor(0,1);
lcd.print(" ");
if (hour<10) {
lcd.print("0");
}
lcd.print(hour,DEC);
lcd.print(':');
if (minute<10){
lcd.print("0");
}
lcd.print(minute,DEC);

if (digitalRead(A1)== HIGH) {
digitalWrite (redled, HIGH);
lcd.print(':');
if (second<10){
lcd.print("0");
}
lcd.print(second,DEC);
lcd.print(" ");
lcd.print(temp-4); //adjusted for accuracy
lcd.print(" ");
}
else {
lcd.print (" ");
}
}

//------------------------------
// SET THE CLOCK:
//------------------------------
void setclock(){
long settimer;
lcd.clear();
lcd.print("SET TIME/DATE");
delay(1000);
lcd.setCursor(0,0);
lcd.print("Press only to");
lcd.setCursor(0,1);
lcd.print("CHANGE,then wait");
delay(2000);

Page 12 of 17

int second,minute,hour,date,month,year,pm;
second=Clock.getSecond();
minute=Clock.getMinute();
hour=Clock.getHour(h12,PM);
date=Clock.getDate();
month=Clock.getMonth(Century);
year=Clock.getYear();
temp=Clock.getTemperature();
dow=Clock.getDoW();

lcd.clear();
settimer=millis();
buttonActive = false;
while (millis() - settimer < exitSetupTime) { // here we loop to set something
lcd.setCursor(0,0);
lcd.print("SET DAY OF WEEK");
lcd.setCursor(4,1);
lcd.print("(1=Monday)");
lcd.setCursor(0,1);
lcd.print (dow);
if (digitalRead(button) == HIGH) {
settimer=millis();
if (buttonActive == false) {
buttonActive = true;
dow++;
if (dow>7){
dow=1;
}
Clock.setDoW(dow);
lcd.setCursor(0,1);
lcd.print (dow);
}
else{
buttonActive == false;
}
}
else {
if (buttonActive = true) {
buttonActive = false;
}
}
}

lcd.clear();
settimer=millis();
buttonActive = false;
while (millis() - settimer < exitSetupTime) { // here we loop to set something
lcd.setCursor(0,0);
lcd.print("SET YEAR ");
lcd.setCursor(0,1);

Page 13 of 17

lcd.print("20");
lcd.print (year, DEC);
if (digitalRead(button) == HIGH) {
settimer=millis();
if (buttonActive == false) {
buttonActive = true;
year++;
if (year>30){
year=20;
}
Clock.setYear(year);
lcd.setCursor(0,1);
lcd.print("20");
lcd.print (year);
}
else{
buttonActive == false;
}
}
else {
if (buttonActive = true) {
buttonActive = false;
}
}
}

lcd.clear();
settimer=millis();
buttonActive = false;
while (millis() - settimer < exitSetupTime) { // here we loop to set something
lcd.setCursor(0,0);
lcd.print("SET MONTH ");
lcd.setCursor(0,1);
lcd.print (month, DEC);
if (digitalRead(button) == HIGH) {
settimer=millis();
if (buttonActive == false) {
buttonActive = true;
month++;
if (month>12){
month=1;
}
Clock.setMonth(month);
lcd.setCursor(0,1);
lcd.print (month);
lcd.print (" ");
}
else{
buttonActive == false;
}

Page 14 of 17

}
else {
if (buttonActive = true) {
buttonActive = false;
}
}
}

lcd.clear();
settimer=millis();
buttonActive = false;
while (millis() - settimer < exitSetupTime) { // here we loop to set something
lcd.setCursor(0,0);
lcd.print("SET DATE ");
lcd.setCursor(0,1);
lcd.print (date, DEC);
if (digitalRead(button) == HIGH) {
settimer=millis();
if (buttonActive == false) {
buttonActive = true;
date++;
if (date>31){
date=1;
}
Clock.setDate(date);
lcd.setCursor(0,1);
lcd.print (date);
lcd.print (" ");
}
else{
buttonActive == false;
}
}
else {
if (buttonActive = true) {
buttonActive = false;
}
}
}

lcd.clear();
settimer=millis();
buttonActive = false;
while (millis() - settimer < exitSetupTime) { // here we loop to set something
lcd.setCursor(0,0);
lcd.print("SET HOUR ");
lcd.setCursor(0,1);
lcd.print (hour, DEC);
if (digitalRead(button) == HIGH) {
settimer=millis();

Page 15 of 17

if (buttonActive == false) {
buttonActive = true;
hour++;
if (hour>23){
hour=0;
}
Clock.setHour(hour);
lcd.setCursor(0,1);
lcd.print (hour);
lcd.print (" ");
}
else{
buttonActive == false;
}
}
else {
if (buttonActive = true) {
buttonActive = false;
}
}
}

lcd.clear();
settimer=millis();
buttonActive = false;
while (millis() - settimer < exitSetupTime) { // here we loop to set something
lcd.setCursor(0,0);
lcd.print("SET MINUTE ");
lcd.setCursor(0,1);
lcd.print (minute, DEC);
if (digitalRead(button) == HIGH) {
settimer=millis();
if (buttonActive == false) {
buttonActive = true;
minute++;
if (minute>59){
minute=0;
}
Clock.setMinute(minute);
lcd.setCursor(0,1);
lcd.print (minute);
lcd.print (" ");
Clock.setSecond(0);
}
else{
buttonActive == false;
}
}
else {
if (buttonActive = true) {

Page 16 of 17

buttonActive = false;
}
}
}

// now we timed out and it's back to displaying the time


lcd.clear();
longPressActive = false;
ledstate = !ledstate;
digitalWrite (blueled, ledstate);
}

Page 17 of 17

You might also like