Project in progress

Gorgy Meteo Clock © MIT

My 'Gorgy' clock! Enhanced with an IR remote, a TFT display, a barometer, and a humidity and temperature sensor.

  • 10,182 views
  • 12 comments
  • 48 respects

Components and supplies

About this project

Update 2018-08-07

FINALLY, the schematic is available.

Why this clock?

I always wanted to make a so-called 'Gorgy' Clock. You see them often in music or TV studios. Now I could, so I bought a cheap clock at Ikea and ripped out the inside, making room for the electronics and display.

A commercial Gorgy clock and the Ikea clock I bought:

Because it was to be my bedside clock, I thought of adding some extra features such as an IR remote and barometer- humidity and temperature sensor because I love meteorology.

When I'm awake at night, I have something to look at: temperature (min/max), barometer trend of the last 24 hours and the air pressure change rate, which is a very good indication of pending bad weather.

Wishlist

Alarm clock function

I also would like to use the clock as an alarm clock with a blackbird sound to wake me up using an Adafruit sound card. But my lack of programming skills concerning the necessary menu structure was a stumbling block (so far).

Adjusting the time

Adjusting the time is sort of possible via the menu:

It is poorly implemented (for now), so what I did is assigned a button on the IR remote to set the seconds to zero when I press that button. If the seconds on the clock are <30, the minute stays the same and the seconds are reset to 0. When the seconds on the clock are >30, one minute is added and the seconds are reset to zero.

So with a accurate clock (on my phone), just before the '0' mark I press the button and the clock is synced. Then I'm good for a whole year because the temp compensated RTC is extremely accurate.

Video

On the left the IR remote I use to set the clock, change TFT screens, change LED ring mode, set the seconds to zero and save or load the 24H barometric pressure data to a RAM chip.

Building the clock

I just discovered the possibility to use a laser cutter at a local makerspace location: GREAT! So this way I could make the black acrylic mounting frame for the LED's and TFT display:

On top of that I also cut a piece of heavy weight black paper to cover the gaps around the TFT display. Then I cut a brown acrylic display to enhance the contrast of the LED's and make the gray 7 segment displays less noticeable.

The TFT display

On the small 1.8" TFT display, I now have 5 display options:

As a gimmick, I included a 'thermal comfort indicator' in the form of a traffic light.

The Meteo sensors

When I'm awake at night and a storm is passing I can see the barometric pressure plunging and rising after the storm has passed. Better than looking at the ceiling.

Inside the clock

Code

Code version 2017-03Arduino
The date display now displays the day of the week - day - month. For example Mo 13 - 05
It should compile with Arduino IDE 1.6, maybe not the newer versions of the IDE!!
/*

  GorgyMeteoClock

  2017-07-13 changing date display to also display day-of-the-week
  2017-07-14 small edit: clear date display first and no decimal point

                                                                                            ####    ######     ###     ####
  ##   ##   #####   ######   ##   ##    ####            ##   ##  #######    ####     ##     ##  ##   ##        ##      ##  ##
  ##   ##  ##   ##    ##     ###  ##   ##  ##           ##   ##  ##        ##  ##    ##         ##   ##       ##       ##  ##
  ##   ##  ##         ##     ###  ##  ##                ### ###  ##       ##        ####       ##    #####    #####    ##  ##
  ##   ##   #####     ##     ## # ##  ##                ## # ##  #####    ##        ## #      ##         ##   ##  ##   ##  ##
  ##   ##       ##    ##     ## # ##  ##  ###           ## # ##  ##       ##  ###  ######    ##          ##   ##  ##   ##  ##
  ##   ##  ##   ##    ##     ##  ###   ##  ##           ##   ##  ##        ##  ##  ##   #   ##       ##  ##   ##  ##   ##  ##
  #####    #####   ######   ##   ##    #####           ##   ##  #######    ##### ###   ##  ######    ####     ####     ####

*/

//----------------------------------------------------------------------------------------------------------
// Libraries
//----------------------------------------------------------------------------------------------------------
//

#include <SPI.h>                // SPI interface library
// -> http://arduino.cc/en/Reference/SPI
#include <Time.h>               // Arduino (new) Time library
// -> http://www.pjrc.com/teensy/td_libs_Time.html
#include <Timezone.h>           // facilitate time zone conversions and automatic DST adjustments.
//https://github.com/JChristensen/Timezone
#include <Wire.h>               // Enable this line if using Arduino Uno, Mega, etc.
//
#include <LedControl.h>         // Maxim 7219 displays library
// -> http://playground.arduino.cc/Main/LEDMatrix
#include <OneWire.h>            // OneWire lets you access 1-wire devices made by Maxim/Dallas,
// such as DS18S20, DS18B20, DS1822.
// http://www.pjrc.com/teensy/td_libs_OneWire.html
// http://milesburton.com/Dallas_Temperature_Control_Library
#include <IRremote.h>           //
#include "ClickButton.h"        // A simple one-button Arduino library to get short and long clicks,
// multiple clicks (double click, triple click etc.).
// Click-and-hold is also possible.
// -> https://code.google.com/p/clickbutton/
#include <Adafruit_GFX_AS.h>    // Adafruit Core graphics library
#include <Adafruit_ST7735_AS.h> // Adafruit 1.8" TFT
#include "Adafruit_HTU21DF.h"   // Adafruit HTU21D-F Temperature & Humidity Sensor
#include <Streaming.h>
#include <Adafruit_Sensor.h>    // Adafruit Unified Sensor Driver
#include <Adafruit_BMP183.h>    // Adafruit BMP183 Barometric Pressure + Temp sensor
#include "eeprom_routines.h"    // EEprom routines for storing data
//#include "RotaryEncoder.h"    // smallest and best rotary lib I have seen...
// https://code.google.com/p/arduino-rotary-encoder-with-velocity/
//----------------------------------------------------------------------------------------------------------
// I2C addresses
//----------------------------------------------------------------------------------------------------------
#define CHRONODOT_ADDRESS    0x68       // Chronodot I2C address
#define BH1750_ADDRESS       0x23       // BH1750 Lux Sensor I2C address
#define TSL2561_ADDRESS      0x39       // Lux Sensor I2C address
#define HTU21DF_ADDRESS      0x40       // Humidity Sensor I2C address
#define EEPROM_ADDRESS       0x50       // EEprom address for storing barametric array data etc.

//----------------------------------------------------------------------------------------------------------
// Humidity Sensor init
//----------------------------------------------------------------------------------------------------------
Adafruit_HTU21DF htu21df = Adafruit_HTU21DF();

//----------------------------------------------------------------------------------------------------------
// Barometric pressure sensor init
//----------------------------------------------------------------------------------------------------------
#define BMP183_CLK  52  // SCK to SPI Clock
#define BMP183_SDO  50  // MISO
#define BMP183_SDI  51  // MOSI
#define BMP183_CS   42  // CS: Chip Select Pin
// initialize BMP183 sensor with hardware SPI
Adafruit_BMP183 bmp183 = Adafruit_BMP183(BMP183_CS);

// or initialize with software SPI and use any 4 pins
//                                    CLK SDO SDI CS);
//Adafruit_BMP183 bmp = Adafruit_BMP183( 3, 6, 2, 7);

//----------------------------------------------------------------------------------------------------------
// DS18B20 initialization
//----------------------------------------------------------------------------------------------------------
OneWire  ds(46); // define Onewire instance DS
// address: 0x28, 0xF0, 0xEC, 0xE2, 0x04, 0x00, 0x00, 0x47

//----------------------------------------------------------------------------------------------------------
// IRreceiver initialization
//----------------------------------------------------------------------------------------------------------
IRrecv irrecv(44);
decode_results irReceive;

//----------------------------------------------------------------------------------------------------------
// Adafruit 1.8" TFT display init
//----------------------------------------------------------------------------------------------------------
//Connect to hardware SPI on Mega2560:

#define sclk 52 // Uno:13  // Don't change
#define mosi 51 // Uno:11  // Don't change
#define cs   48 // Uno:9
#define dc   49 // Uno:8
#define rst  47 // Uno:7  // you can also connect this to the Arduino reset

Adafruit_ST7735_AS tft = Adafruit_ST7735_AS(cs, dc, rst);       // Invoke custom library

// or use any pins but a little slower
//                                    cs  dc mosi sclk, rst);
//Adafruit_ST7735 tft = Adafruit_ST7735(10, 9, 11, 13, 8);

// define colors for TFTdisplay
#define BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define ORANGE  0xFD20
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF
#define LGRAY   0xC618
#define DGRAY   0x8410

//----------------------------------------------------------------------------------------------------------
// Maxim 7219 Matrix Display initialization
//----------------------------------------------------------------------------------------------------------
//***** Please set the number of devices you have *****
// But the maximum default of 8 MAX72XX wil also work.
// LedConrol( DATAIN(SDI/MOSI), CLOCK, CS/LOAD , NUMBER OF MAXIM CHIPS,)
LedControl maxim = LedControl(40, 36, 38, 3, false); // Define pins for Maxim 72xx and how many 72xx we use
//LedControl maxim = LedControl(40, 39, 38, 3, false); // Define pins for Maxim 72xx and how many 72xx we use
//LedControl maxim = LedControl(11, 13, 6, 1, false); // Define pins for Maxim 72xx and how many 72xx we use

//----------------------------------------------------------------------------------------------------------
// Rotary encoder
//----------------------------------------------------------------------------------------------------------
//RotaryEncoder encoder(A0,A1,1,1,1);
//#define BUTTON_SELECT_PIN A2

//----------------------------------------------------------------------------------------------------------
// Miscellaneous
//----------------------------------------------------------------------------------------------------------
// Adafruit TFT screen things
#if defined(__SAM3X8E__)
#undef __FlashStringHelper::F(string_literal)
#define F(string_literal) string_literal
#endif

//----------------------------------------------------------------------------------------------------------
// Daylight Savings Time calculation parameters
//----------------------------------------------------------------------------------------------------------
//Europe, Amsterdam Time Zone (ZT = DST, WT = DST)
TimeChangeRule myZT = {"ZT", Last, Sun, Mar, 2, +120};    //Daylight time = UTC +2 hours
TimeChangeRule myWT = {"WT", Last, Sun, Oct, 3, +60};     //Standard time = UTC +1  hours
Timezone myTZ(myZT, myWT);

//----------------------------------------------------------------------------------------------------------
// RTC DS3231 stuff
//----------------------------------------------------------------------------------------------------------
// set SQW output DS3231 RTC chip
#define SQW_FREQ SQWAVE_1_HZ        // 0b00000000     1Hz
//#define SQW_FREQ SQWAVE_4096_HZ   // 0b00001000  1024Hz
//#define SQW_FREQ SQWAVE_1024_HZ   // 0b00010000  4096Hz
//#define SQW_FREQ SQWAVE_8192_HZ   // 0b00010000  4096Hz
//#define SQW_FREQ SQWAVE_NONE      // DISABLE


//----------------------------------------------------------------------------------------------------------
// EEPROM
//----------------------------------------------------------------------------------------------------------
// memory start address to for barometer array data
#define BAROGRAPH_START_ADDRESS 100


//----------------------------------------------------------------------------------------------------------
// Variable and array defenitions
//----------------------------------------------------------------------------------------------------------
// define Maxim 7219 display parameters
#define TIMEDISPLAY              1           // first Maxim 7219 in 'daisychain' must be '0', next '1' etc.
#define SECONDSDISPLAY           2           // first Maxim 7219 in 'daisychain' must be '0', next '1' etc.
#define DATEDISPLAY              0

//----------------------------------------------------------------------------------------------------------
// LED pins
//----------------------------------------------------------------------------------------------------------
#define ERRORLED 36

//----------------------------------------------------------------------------------------------------------
// PWM brightness ports
//----------------------------------------------------------------------------------------------------------
#define MARKERS_HOURS   10 // PWM
#define MARKERS_MINUTES 11 // PWM
#define TFT_LIGHT       12 // Lite - this is the PWM input for the backlight control. Connect to 3-5VDC to turn on the
// backlight. Connect to ground to turn it off. Or, you can PWM at any frequency.
//----------------------------------------------------------------------------------------------------------
// Buttons definition
//----------------------------------------------------------------------------------------------------------
// create 3 Clickbutton instances, one for each button
#define BUTTON_SELECT_PIN      A0
#define BUTTON_UP_PIN          A1
#define BUTTON_DOWN_PIN        A2

ClickButton buttonUp(BUTTON_UP_PIN, LOW, CLICKBTN_PULLUP);
ClickButton buttonDown(BUTTON_DOWN_PIN, LOW, CLICKBTN_PULLUP);
ClickButton buttonSelect(BUTTON_SELECT_PIN, LOW, CLICKBTN_PULLUP);


//// user input actions
//enum {NO_ACTION, BTN_CLICK, BTN_DOUBLE_CLICK, BTN_HOLD, ROTATE_L, ROTATE_R}; // used for rotary
enum {NO_ACTION, BTN_SELECT, BTN_SELECT_HOLD, BTN_UP, BTN_DOWN, LED_RING_MODE, MEMORY_RESET, EEPROM_WRITE_BARO, EEPROM_READ_BARO};
//----------------------------------------------------------------------------------------------------------
// Related to the State Machine
//----------------------------------------------------------------------------------------------------------
// The different states of the system
enum states
{
  STATE_MAIN,
  STATE_TEMP_DISPLAY,
  STATE_HUMIDITY_DISPLAY,
  STATE_TIME_DETAIL,
  STATE_BAROGRAPH,
  STATE_BAROGRAPH_TREND,
  STATE_MENU_ALARM_TIME,
  STATE_MENU_SET_ALARM_HOUR,
  STATE_MENU_SET_ALARM_MINUTES,
  STATE_MENU_SECONDS_RING,
  STATE_MENU_SET_SECONDS_RING_MODE,
  STATE_MENU_LCD_MODE,
  STATE_MENU_SET_LCD_MODE,
  STATE_MENU_TIME,
  STATE_MENU_SET_TIME_HOUR,
  STATE_MENU_SET_TIME_MINUTES,
  STATE_MENU_DATE,
  STATE_MENU_SET_DAY,
  STATE_MENU_SET_MONTH,
  STATE_MENU_SET_YEAR,
  STATE_MENU_BAROGRAPH,
  STATE_MENU_SET_SEA_LEVEL_PRESSURE,
  STATE_MENU_SET_PRESSURE_CORRECTION,
};
states currState;       // Holds the current state of the system

/***************************************************************************************************************************************************

  ##   ##    ##     ######   ######     ##     ######   ##       #######   #####
  ##   ##    ##     ##   ##    ##       ##     ##   ##  ##       ##       ##   ##
  ##   ##   ####    ##   ##    ##      ####    ##   ##  ##       ##       ##
  ## ##    ## #    ######     ##      ## #    ######   ##       #####     #####
  ## ##   ######   ## ##      ##     ######   ##   ##  ##       ##            ##
   ###    ##   #   ##  ##     ##     ##   #   ##   ##  ##       ##       ##   ##
   ###   ###   ##  ##   ##  ######  ###   ##  ######   ######   #######   #####

****************************************************************************************************************************************************/
#define plotLimitH                    130 // graph plotlimit Horizontal 
#define plotRangeH                    130 // graph plot size Horizontal
#define plotLimitV                    115 // graph plotlimit Vertical
#define plotRangeV                    100 // graph plot size Vertical
// Horizontal Grid lines
#define grid24HstartpositionXaxis       0
#define grid24HstartpositionYaxis      15
#define grid24HlineSpacing             20
#define grid24HlinePixelSpacing         2
#define grid24HlinePixelSpacing1H       5
#define grid24HlinePixelSpacing2H      10
#define grid24HlinePixelSpacing4H      20
#define grid24XaxisTicksStart           5
// Vertical Grid lines
#define grid24VstartpositionXaxis      10
#define grid24VstartpositionYaxis      15
#define grid24VlineSpacing             20
#define grid24VlinePixelSpacing         2
#define grid24VlinePixelSpacing10Hpa   20
#define grid24VlinePixelSpacing5Hpa    10

#define GRIDCOLOR          LGRAY
#define PLOTCOLOR          BLUE
#define XAXISCOLOR         WHITE
#define YAXISCOLOR         WHITE
#define XTEXTCOLOR         WHITE
#define YTEXTCOLOR         WHITE
#define PRESSUREVALUECOLOR GREEN
#define TEMPVALUECOLOR     MAGENTA
#define HYGROVALUECOLOR    ORANGE

char* strDOW[8] = {"null", "Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag"};
int strDOWlength[8] = {0, 6, 7, 7, 8, 9, 7, 8};
char* strMonth[13] = {"null", "Jan", "Feb", "Mrt", "Apr", "Mei", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"};
//char* strMonth[13] = {"null","Januari","Februari","Maart","April","Mei","Juni","Juli","Augustus","September","Oktober","November","December"};


byte readWeatherdataInterval                 = 12;

bool secondsRingUpdated                      = false;
bool tftMainUpdated                          = false;
bool tftTimeUpdated                          = false;
bool tftBarographUpdated                     = false;
bool tftBaroTrendUpdated                     = false;



int baroTrendValue = 0;
int baroTrend = 0;
enum {NA, ZEER_SNEL_DALEND, SNEL_DALEND, DALEND, LANGZAAM_DALEND, STABIEL, LANGZAAM_STIJGEND, STIJGEND, SNEL_STIJGEND, ZEER_SNEL_STIJGEND};
bool pressureDataUpdated                     = false;
bool pressureDataStored                      = false;
bool pressureDataToEEprom                    = false;
bool pressureDataFromEEprom                  = false;
long pressureSample                          = 0;
long pressure                                = 0;
long pressureMin                             = 0;
long pressureMax                             = 0;
int minPressureHour = 0;
int minPressureMinute = 0;
int maxPressureHour = 0;
int maxPressureMinute = 0;


int testpressure                             = 980;
int step                                     = 5;
int previousPressureMin                      = 0;
int previousPressureMax                      = 0;
int meanSeaLevelPressure                     = 10155;
int pressureCorrection                      = 2;
bool resetBarograph                          = false;

int countdown = 10800;

int x                                        = 0;
int plotvalueP                               = 0;
int plotvalueP1                              = 0;
int plotvalueT                               = 0;
bool highScale                               = false;
bool currentScale                            = false;
int barometerData[132];                                     // array to hold barometric data
unsigned int readings = 0;
int pressureHourAvarage[130];
int pressureHourlyTrend = 0;

unsigned long timer1                         = millis();
unsigned long lastRotation                   = millis();
unsigned long lastUpdate1                    = millis();
bool startup                                 = true;
int q;


// Humidity related variables
int humidity                                 = 0;
int climateComfort                           = 0;
int minHumidity = 0;
int maxHumidity = 0;
int minHumidityHour = 0;
int minHumidityMinute = 0;
int maxHumidityHour = 0;
int maxHumidityMinute = 0;
bool humidityMemoryReset = false;

#define ccRED 0
#define ccYELLOW 1
#define ccGREEN 2


// temperature variables
bool temperatureMemoryReset                  = true;
int tempCelcius         = 0;
int minTemp = 0;
int maxTemp = 0;
int minTempHour = 0;
int minTempMinute = 0;
int maxTempHour = 0;
int maxTempMinute = 0;
//@1
byte tCount;
byte present = 0;
byte data[12];
byte addr[8] = {0x28, 0xF0, 0xEC, 0xE2, 0x04, 0x00, 0x00, 0x47};


// Time related variables
bool setSecondsToZero = false;
int previousDay                                  = 0;
int lastMinute                               = 0;
time_t t;
byte previousSecond = 0;
byte previousMinute = 0;
byte previousHour = 0;
int TMPsecond;                                           // holds time & date while setting the time
int TMPminute;
int TMPhour;
int TMPweekday;
int TMPday;
int TMPmonth;
int TMPyear;
int daylightSavingTime = 0;
bool daylightSavingTimeHasChanged = false;
boolean RTCERROR                             = true;        // flag to check RTC communication, used in SHOW_TIME_DATE_WEATHER_DATE_WEATHER and SHOW_DATE
short dayNumber;   //Returns the number of day in the year
short weekNumber;  //Returns the number of the week in the year

byte alarmHour                               = 8;
byte alarmMinute                             = 30;


bool sw1                                     = true;
bool stateChange                             = false;
int userAction                               = 0;
int previousMenu                             = 0;
volatile unsigned long timeOfLastButtonPress = 0;
bool secondsRingFull                         = true;
bool lcdScrollModeAuto                       = false;
bool needToSaveTime                          = false;
bool needToUpdateBarograph                   = false;
bool needToUpdateTFT                         = false;
bool isWaitingforTimeout                     = false;

//Brightness
byte brightnessTimeDisplay                   = 1;   // value from 0-15
byte brightnessSecondsRing                   = 0;   // value from 0-15
byte brightnessDateDisplay                   = 3;   // value from 0-15
byte brightnessMinuteMarkers                 = 505; // USE PWM value from 0 - 512, higher is dimmer
byte brightnessHourMarkers                   = 512; // USE PWM value from 0 - 512
byte brightnessLcdBacklight                  = 420; // USE PWM value from 0 - 512


bool irRemote = false;

byte ledRingMode = 0;
bool ledRingModeIsChanged = false;

int sec = 0;



// Define Interrupt function

volatile boolean updateTime = false;

// DS3231 1Hz pulse ISR
void pulseISR()
{
  updateTime = true;
}










/***************************************************************************************************************************************************

                                                 ##      ##
  #####   #######  ######   ##   ##  ######     ##        ##
  ##   ##  ##         ##     ##   ##  ##   ##    ##        ##
  ##       ##         ##     ##   ##  ##   ##   ##          ##
  #####   #####      ##     ##   ##  ######    ##          ##
      ##  ##         ##     ##   ##  ##        ##          ##
  ##   ##  ##         ##     ##   ##  ##         ##        ##
  #####   #######    ##      #####   ##         ##        ##
                                                 ##      ##

****************************************************************************************************************************************************/


void setup()
{
  //DEBUG
  pinMode(A8,  OUTPUT);
  pinMode(A9,  OUTPUT);
  pinMode(A10, OUTPUT);
  pinMode(A11, OUTPUT);
  //END DEBUG ;)


  pinMode(ERRORLED, OUTPUT);
  pinMode(TFT_LIGHT, OUTPUT);
  pinMode(MARKERS_HOURS, OUTPUT);
  pinMode(MARKERS_MINUTES, OUTPUT);
  pinMode(53, OUTPUT);                    // Set to OUTPUT NEEDED FOR SPI HARDWARE MASTER MODE

  Wire.begin();                           // start I2C
  irrecv.enableIRIn();                    // Start the IR remote receiver

  Serial.begin(115200);                   // start Serial for debug purposes

  //RTC.squareWave(SQW_FREQ);               // Set RTC DS3231 SQW frequency (1 Hz in this case)
  attachInterrupt(0, pulseISR, RISING);   // DS3231 sends an 1Hz pulse - we use this to update the display

  readRTC();
  setTime(TMPhour, TMPminute, TMPsecond, TMPday, TMPmonth, TMPyear);

  //setTime(2, 59, 45, 25, 10, 15); // test for change to winter time
  //setTime(1, 59, 45, 29, 3, 15); // test for change to summer time
  //timeDateToTemporaryMem();
  //writeRTC();

  // store current DST value in variable to check if DST is changed
  daylightSavingTime = myTZ.locIsDST(now());


  //setTime(RTC.get());
  //setSyncProvider(RTC.get);             // set RTC as the Syncprovider
  //setSyncInterval(5);                   // time in sec of resync with RTC

  // clear barometer pressure data array
  for (int i = 0; i <= 130; i++)
  {
    barometerData[i] = 0;
  }

  initTFT();                              // Initialize the TFT screen
  clearTFT();
  init7SegDisplay();                      // initialize 7 segment display
  initHumiditySensor();                   // start Humidity Sensor
  initBaroSensor();                       // initialize Pressure sensor
  brightnessAdj();

  requestTemperature();
  readHumidity();

  // initialize array
  for (int i = 0; i < 133; i++)
  {
    barometerData[i] = 0;
  }

  currState = STATE_MAIN;                 // Initial state of the FSM

}



/***************************************************************************************************************************************************

                                        ##      ##
  ##         ###      ###    ######     ##        ##
  ##        ## ##    ## ##   ##   ##    ##        ##
  ##       ##   ##  ##   ##  ##   ##   ##          ##
  ##       ##   ##  ##   ##  ######    ##          ##
  ##       ##   ##  ##   ##  ##        ##          ##
  ##        ## ##    ## ##   ##         ##        ##
  ######     ###      ###    ##         ##        ##
                                        ##      ##

****************************************************************************************************************************************************/


void loop()
{


  if (updateTime == true)
  {
    updateTime = false;
    executeState();
  }

  userAction = checkUserAction();
  if (userAction != NO_ACTION) // user has pressed a button
  {
    processAction(userAction);
  }
  else if (isWaitingforTimeout == true && millis() - timeOfLastButtonPress > 5000)
  {
    isWaitingforTimeout = false;
    clearTFT();
    clearTimeDisplay();
    clearDateDisplay();
    clearSecondsDisplay();
    startup = true;
    currState = STATE_MAIN;
  }

}















/***************************************************************************************************************************************************

   ####   ##   ##  ##   ##           ##   ##   #####   #######  ######              ##       ####   ######   ######     ###    ##   ##
  ##  ##  ##   ##  ##  ##            ##   ##  ##   ##  ##       ##   ##             ##      ##  ##    ##       ##      ## ##   ###  ##
  ##       ##   ##  ## ##             ##   ##  ##       ##       ##   ##            ####    ##         ##       ##     ##   ##  ###  ##
  ##       #######  ####              ##   ##   #####   #####    ######             ## #    ##         ##       ##     ##   ##  ## # ##
  ##       ##   ##  ## ##             ##   ##       ##  ##       ## ##             ######   ##         ##       ##     ##   ##  ## # ##
  ##  ##  ##   ##  ##  ##            ##   ##  ##   ##  ##       ##  ##            ##   #    ##  ##    ##       ##      ## ##   ##  ###
   ####   ##   ##  ##   ##            #####    #####   #######  ##   ##          ###   ##    ####     ##     ######     ###    ##   ##

****************************************************************************************************************************************************/
// check for user input
int checkUserAction()
{
  //////////////////////////////////
  // check for IR remote commands //
  //////////////////////////////////
  if (irrecv.decode(&irReceive))
  {
    switch (irReceive.value)
    {
      case 0x1C3B939F: // "Menu" key
        userAction = BTN_SELECT_HOLD;
        irRemote = true;// needed to check for IR input!
        break;

      case 0x75E8EBA3: // "Select" key
        userAction = BTN_SELECT;
        irRemote = true;
        break;

      case 0x150ADC43: // "Up" key
        userAction = BTN_UP;
        irRemote = true;
        break;

      case 0xA8A8B363: // "Play"

        irRemote = true;
        break;

      case 0x6551963F: // "Down"
        userAction = BTN_DOWN;
        irRemote = true;
        break;

      case 0x2560B67:  // "+" key
        userAction = EEPROM_WRITE_BARO;
        irRemote = true;
        break;

      case 0x5655FCFF: // "-" key
        userAction = EEPROM_READ_BARO;
        irRemote = true;
        break;

      case 0x3C1B0E83: // "|<<" key

        break;

      case 0xB55AE2FF: // ">>|" key
        readArray(); // Debug. read array and display on Serial Monitor
        readRTC(); // DEBUG. read RTC time and update system time
        setTime(TMPhour, TMPminute, TMPsecond, TMPday, TMPmonth, TMPyear);
        break;

      case 0xD293DA9F: // "Spatial" key
        userAction = MEMORY_RESET;
        irRemote = true;
        break;

      case 0xF761B2A3: // "Power" key

        break;

      case 0x12284AC3: // "Shuffle" key

        break;

      case 0x509BADB:  // "Repeat" key
        userAction = LED_RING_MODE;
        irRemote = true;
        ledRingModeIsChanged = true;
        break;
    }// switch

    //Serial.println(results.value, HEX);
    irrecv.resume(); // Receive the next value
  }

  // if IR remote is used, activate time-out function, used in the settings menu
  if (irRemote == true)
  {
    irRemote = false;
    timeOfLastButtonPress = millis();
    return userAction;
  }

  ////////////////////////////
  // check for button input //
  ////////////////////////////

  // no IR signals received, next check for button input

  // check state of each button
  buttonUp.Update();
  buttonDown.Update();                    // 1 = short click, -1 = long click (>1 second)
  buttonSelect.Update();                  // 0 = no input, Duh!

  if (buttonSelect.clicks != 0)           // check for user action of SELECT BUTTON
  {
    int clicks = buttonSelect.clicks;
    if (clicks > 1) clicks = 1;         // no double clicks...

    switch (clicks)
    {
      case 1:                         // Select button is pressed 1x
        userAction = BTN_SELECT;
        break;

      case -1:                        // Select button is pressed 1x for > 1 second
        userAction = BTN_SELECT_HOLD;
        break;
    }
  }
  else if (buttonUp.clicks == 1)               // check for user action of UP BUTTON
  {
    userAction = BTN_UP;
  }
  else if (buttonDown.clicks == 1)             // check for user action of DOWN BUTTON
  {
    userAction = BTN_DOWN;
  }
  // no IR commands or button press
  else
  {
    userAction = NO_ACTION;
  }

  if (userAction != NO_ACTION)
  {
    timeOfLastButtonPress = millis();
  }

  return userAction;
}

/***************************************************************************************************************************************************

  ######   ######     ###      ####   #######   #####    #####              ##       ####   ######   ######     ###    ##   ##
  ##   ##  ##   ##   ## ##    ##  ##  ##       ##   ##  ##   ##             ##      ##  ##    ##       ##      ## ##   ###  ##
  ##   ##  ##   ##  ##   ##  ##       ##       ##       ##                 ####    ##         ##       ##     ##   ##  ###  ##
  ######   ######   ##   ##  ##       #####     #####    #####             ## #    ##         ##       ##     ##   ##  ## # ##
  ##       ## ##    ##   ##  ##       ##            ##       ##           ######   ##         ##       ##     ##   ##  ## # ##
  ##       ##  ##    ## ##    ##  ##  ##       ##   ##  ##   ##           ##   #    ##  ##    ##       ##      ## ##   ##  ###
  ##       ##   ##    ###      ####   #######   #####    #####           ###   ##    ####     ##     ######     ###    ##   ##

****************************************************************************************************************************************************/
// change state of the "state machine" based on the user input;
// also perform one-time actions required by the change of state (e.g. clear display);
void processAction(int userAction)
{
  // Uses the current state to decide what to process
  switch (currState)
  {
    case STATE_MAIN:                      //---------------------{ 0 }--{ STATE MAIN }--------------------

      if (userAction == BTN_SELECT_HOLD)
      {
        currState = STATE_MENU_ALARM_TIME;
        stateChange = true;
        isWaitingforTimeout = true;
        clearTFT();
        clearTimeDisplay();
        clearDateDisplay();
        clearSecondsDisplay();
        drawSettingsMenu();
      }

      if (userAction == BTN_DOWN)
      {
        clearTFT();
        currState = STATE_TEMP_DISPLAY;
        stateChange = true;
      }

      if (userAction == BTN_UP)
      {
        clearTFT();
        currState = STATE_BAROGRAPH_TREND;
        stateChange = true;
      }

      if (userAction == LED_RING_MODE)
      {
        ledRingMode++;
        if (ledRingMode > 3)
        {
          ledRingMode = 0;
        }
      }

      break;
    case STATE_TEMP_DISPLAY:              //---------------------{ 1 }--{ STATE TEMP DISPLAY }--------------------

      if (userAction == BTN_SELECT_HOLD)
      {
        currState = STATE_MENU_ALARM_TIME;
        stateChange = true;
        isWaitingforTimeout = true;
        clearTFT();
        clearTimeDisplay();
        clearDateDisplay();
        clearSecondsDisplay();
        drawSettingsMenu();
      }

      if (userAction == BTN_DOWN)
      {
        clearTFT();
        currState = STATE_HUMIDITY_DISPLAY;
        stateChange = true;
      }

      if (userAction == BTN_UP)
      {
        clearTFT();
        currState = STATE_MAIN;
        stateChange = true;
      }

      if (userAction == LED_RING_MODE)
      {
        ledRingMode++;
        if (ledRingMode > 3)
        {
          ledRingMode = 0;
        }
      }

      if (userAction == MEMORY_RESET)
      {
        temperatureMemoryReset = true;
        minTemp = maxTemp = tempCelcius;
        minTempHour =  maxTempHour = hour();
        minTempMinute = maxTempMinute = minute();
      }

      break;
    case STATE_HUMIDITY_DISPLAY:               //---------------------{ 2 }--{ STATE HUMIDITY DISPLAY }--------------------

      if (userAction == BTN_SELECT_HOLD)
      {
        currState = STATE_MENU_ALARM_TIME;
        stateChange = true;
        isWaitingforTimeout = true;
        clearTFT();
        clearTimeDisplay();
        clearDateDisplay();
        clearSecondsDisplay();
        drawSettingsMenu();
      }

      if (userAction == BTN_DOWN)
      {
        clearTFT();
        currState = STATE_TIME_DETAIL;
        stateChange = true;
      }

      if (userAction == BTN_UP)
      {
        clearTFT();
        currState = STATE_TEMP_DISPLAY;
        stateChange = true;
      }

      if (userAction == LED_RING_MODE)
      {
        ledRingMode++;
        if (ledRingMode > 3)
        {
          ledRingMode = 0;
        }
      }

      if (userAction == MEMORY_RESET)
      {
        humidityMemoryReset = true;
        minHumidity = maxHumidity = humidity;
        minHumidityHour =  maxHumidityHour = hour();
        minHumidityMinute = maxHumidityMinute = minute();
      }

      break;
    case STATE_TIME_DETAIL:               //---------------------{ 3 }--{ STATE TIME DETAIL }--------------------

      if (userAction == BTN_SELECT_HOLD)
      {
        currState = STATE_MENU_ALARM_TIME;
        stateChange = true;
        isWaitingforTimeout = true;
        clearTFT();
        clearTimeDisplay();
        clearDateDisplay();
        clearSecondsDisplay();
        drawSettingsMenu();
      }

      if (userAction == BTN_DOWN)
      {
        clearTFT();
        currState = STATE_BAROGRAPH;
        stateChange = true;
      }

      if (userAction == BTN_UP)
      {
        clearTFT();
        currState = STATE_HUMIDITY_DISPLAY;
        stateChange = true;
      }

      if (userAction == MEMORY_RESET)
      {
        setSecondsToZero = true;
      }

      if (userAction == LED_RING_MODE)
      {
        ledRingMode++;
        if (ledRingMode > 3)
        {
          ledRingMode = 0;
        }
      }

      break;
    case STATE_BAROGRAPH:                 //---------------------{ 4 }--{ STATE BAROGRAPH }--------------------

      if (userAction == BTN_SELECT_HOLD)
      {
        currState = STATE_MENU_ALARM_TIME;
        stateChange = true;
        isWaitingforTimeout = true;
        clearTFT();
        clearTimeDisplay();
        clearDateDisplay();
        clearSecondsDisplay();
        drawSettingsMenu();
      }

      if (userAction == BTN_DOWN)
      {
        clearTFT();
        currState = STATE_BAROGRAPH_TREND;
        stateChange = true;
      }

      if (userAction == BTN_UP)
      {
        clearTFT();
        currState = STATE_TIME_DETAIL;
        stateChange = true;
      }

      if (userAction == EEPROM_WRITE_BARO)
      {
        // + button of remote pressed: store barometer pressur data array in EEPROM
        pressureDataToEEprom = true;
      }

      if (userAction == EEPROM_READ_BARO)
      {
        // + button of remote pressed: store barometer pressur data array in EEPROM
        pressureDataFromEEprom = true;
      }

      if (userAction == LED_RING_MODE)
      {
        ledRingMode++;
        if (ledRingMode > 3)
        {
          ledRingMode = 0;
        }
      }

      break;
    case STATE_BAROGRAPH_TREND:           //---------------------{ 5 }--{ STATE BAROGRAPH TREND }--------------------

      if (userAction == BTN_SELECT_HOLD)
      {
        currState = STATE_MENU_ALARM_TIME;
        stateChange = true;
        isWaitingforTimeout = true;
        clearTFT();
        clearTimeDisplay();
        clearDateDisplay();
        clearSecondsDisplay();
        drawSettingsMenu();
      }

      if (userAction == BTN_DOWN)
      {
        clearTFT();
        currState = STATE_MAIN;
        stateChange = true;
      }

      if (userAction == BTN_UP)
      {
...

This file has been truncated, please download it to see its full contents.

Schematics

schematic

Comments

Similar projects you might like

Arduino Bluetooth Basic Tutorial

by Mayoogh Girish

  • 455,169 views
  • 42 comments
  • 239 respects

Home Automation Using Raspberry Pi 2 And Windows 10 IoT

Project tutorial by Anurag S. Vasanwala

  • 285,569 views
  • 95 comments
  • 672 respects

Security Access Using RFID Reader

by Aritro Mukherjee

  • 229,462 views
  • 38 comments
  • 237 respects

OpenCat

Project in progress by Team Petoi

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