Translate

Showing posts with label Clock. Show all posts
Showing posts with label Clock. Show all posts

Saturday 19 May 2018

Synchronised Westerstrand Impulse clock driver.

A while ago, a friend, Alex, asked me how he could drive a synchronised clock he had procured.


It was a Westerstrand clock. The sort that you used to find in factories, offices and schools. It's an electo-mechanical driver, driving a conventional clock display. It doesn't posses any time keeping mechanism.

Now Westerstand are still alive, well and trading since 1906. Their website is here.

Anyway, according to some information gleaned from their website (they still make these things) the clock needs a pulse of 24 volts alternating in polarity to advance a minute. 






I quickly drew up a small circuit, with an arduino and a GPS receiver to drive Alex's clock.... he pronounced it too complicated, and removed his electro-mechnical movement and fitted a quartz clock movement .....

.... that's cheating.

I managed to procure the same clock movement in somewhat distressed condition, and managed to put it all back together.

So what about that proper driver? Good plan. I ditched the GPS receiver, as I have the GPS master clock, and added a 433 MHz receiver to receive the signals.

The clock will "free-run" after being set, using the 490Hz interrupt driven clock, as previously seen on the Arduino analogue clock.

Pulses are sent to the clock by using a small H-bridge.

Now the electronics has no method of knowing where the clock movement is, so before the synchronising signal from the GPS master clock is received, the clock needs to be set to 12 o'clock. I've added a minute and hour button to the PCB to allow the movement to be set.

The code also automatically adjusts for British summer time.




A board is designed...











 Modelled...
















... and turned into reality.

Code and eagle files can be found on my github page at https://github.com/andydoswell/Sync-clock-driver
















Here's a video of it in action...


Saturday 25 February 2017

Arduino "analog" (analogue!!) clock.

I conceived this daft project a while back, after being given a box of surplus moving coil meters...

An Arduino driving three analogue meter movements to show hours, minutes and seconds.

There are lots of designs on the net, so here's another.

Now, I'd seen several clock designs on the net, whereby the Arduino's PWM signal is used to keep accurate time. I must say, whilst the idea is sound, most of the stuff I got hold of and downloaded didn't work for one reason or another.

The idea goes like this...

We couple the PWM output of a pin to an interrupt. We set the PWM output going with a mark to space ratio of 50%. The PWM frequency is governed by the internal architecture of the ATMEGA328, and is derived by some programmable timers, which divide down the clock frequency of the micro. The clock frequency on "posh" arduino boards is generated by a nice crystal (on not-so-posh boards, it may be a ceramic resonator, not so accurate). 16MHz. So dividing down this 16MHz should give quite a low error. Good news. So all we need to do is set up an interrupt, so that every time it sees a rising edge of our PWM signal, it increments a counter.

I measured the frequency of the PWM signal, and on a crystal clocked board, with a ATMEGA328P at 16MHz, it's 490.36Hz. (Due's/ Mega's etc will vary as the micro/clock frequency is different).


Excellent, so all we need to do is add a second on every time our counter hits 490 (Let's forget about the 0.36, shall we?). It should keep reasonable time.


After running for a day or so, the drift (caused by the 0.36 Hz left over) does become noticeable, but I recon it's no worse than a DS1307 RTC. So, to correct for this drift, I'll add in a 433MHz radio receiver module, and make it updatable from the GPS Master Clock project. Excellent.

So after a bit of tinkering this was born...


I've added three momentary push buttons, which allows the time to be set manually, and a "Cal" button. Once cal is pressed, the PWM output is switched off for 10 seconds, and then set to 100% for 10 seconds. This allows the user to set the zero mechanically on the meters, and the FSD (Full scale deflection) on the meter using the three pots, R7,R9 and R11. All three of my meters require 1mA for FSD, yours may vary, and you can alter the value of R7, R9 and R11 to suit your meters.

Each meter is driven by a small transistor. With my meters needing just 1mA, there's absolutely no reason why I couldn't just eliminate the transistor and drive the meters directly from the output of the micro to ground. I've added them in, just in case I need some more current, or decide to drive them from a higher voltage source than 5V. 

There's two toggle switches too... 

The 24 hour select switch changes the hour display from 0-24 hours to 0-12 (actually 12:00 or 0:00 is 0 on the meter, but it'll make sense in a minute)

The smooth select switch I'm rather pleased with. I started out wanting the seconds meter to move smoothly, rather that "tick" once a second. I coded this, and then thought I'd apply the same to the hours and minutes. This has one very pleasing effect. All the meters are moving smoothly. so the hour meter will read halfway between 1 and 2 when it's 1:30 ... same with the minutes. It also means that FSD on the hours meter occurs at 23:59 (in 24h mode or 11:59 in 12h mode), rather than going straight from 23 to 0 ..... 

Now, one big issue is daylight saving time. My master clock transmits GMT. I've added a routine that detects BST (British Summer Time) and adds an hour on if required. I've blatantly stolen this routine from here, , and modified it because I'm avoiding the time.h library (although I've no reason too!).

So a prototype is created....

Some meters selected, and calibrated ...












... and a clock created!...



Here's the code ...

Monday 12 September 2016

Arduino Astronomical Clock (and pond pump controller) - now with master clock update!

Well, the DS1307 clock module has a tendency to drift about a bit on my Pond pump controller. It can lose a few minutes each month. Irritating at best.

Now the GPS master clock as been created, it should be fairly easy to synchronise the DS1307 with the 433MHz data from the master clock.

The receiver hardware is connected to 5 volts, GND and it's data line is connected to pin 9 of the Arduino. The antenna is simply 17cm of stiff wire.



Once again, the wonderful Virtualwire library is used, and we simply call the receiver routine (remoteClockSet) in the main loop to see if any data has been received. If it has, update the DS1307, and recalculate the sun rise and set times.

There's a few more variables to declare to deal with the incoming time, and, to be honest the whole thing was written a while ago, and is now horribly un-weildy, and could do with a damn good tidy up and re-write, but it works.

No more difting clock!

Here's the code.


Friday 22 July 2016

Arduino GPS master clock with 433/315 MHz transmitter

I've got a few clock projects in the back of my mind, and this is a bit of an aside to them all. I also wish to upgrade the Astronomical clock project, as the DS1307 often drifts about, losing and gaining seconds as it feel like it...

The idea is to have a master clock, GPS locked with built in 433 MHz transmitter, which will send an accurate time signal to the other clocks to bring them into sync. The transmitter will be triggered randomly, at least once every 24 hours, or by a push button connected to pin 12.

I'll be re-using the code from the quick and dirty 7-segment GPS clock here, and some of the code for the transmit function from the dehumidifier project.

I've added a 4x20 LCD display, with I2C piggyback interface board, and the u-blox GPS module we've used in the GPS logger.

The GPS module will be configured by the sketch itself, to 200mS refresh rate.

There's two sketches, the GPS clock itself, and a simple test receiver sketch to check everything's working as it should.

The I2C display is a generic display, purchased from eBay, and uses the PCF8574 I2C receiver IC. I tried a couple of different libraries, but eventually settled with the library from https://bitbucket.org/fmalpartida/new-liquidcrystal/downloads which works well with my display.
Well also use the virtual wire library to handle our comms, https://www.pjrc.com/teensy/td_libs_VirtualWire.html and the most excellent TinyGPS++ http://arduiniana.org/libraries/tinygpsplus/

There's an LED connected to pin 9, which blinks on and off every time the seconds are updated.

Here's the schematic...




... and the hardware lashed up for testing.

The second arduino is acting as our test receiver. There's no RF module in there as yet.. It's coupled to the clock arduino, GND is coupled, and pin 10 on the clock is connected to pin 9 on the receiver board. It's also supplying 5V to the other board.







Here's the data being displayed. Date (in UK format DD/MM/YYYY) , UTC time, latitude, longitude, no of satellites in use, horizontal dilution of precision and the number of seconds until the next transmission.







Here's the output from our terminal window, connected to the receiver board, showing the time and date are being correctly received when A3 is pulled to ground.




So, the final build looks like this...

You can see the antenna is simply a straight piece of wire, 173mm long (for 433 MHz modules, other frequencies will need a different length)


And assembled. Managed to cut the right sized hole for the display for once!











Here's the GPS receiver, which I'm going to mount remotely on the roof, so it get's good reception. I've stuck it into of a water-proof IP rated box, and fitted a Buccaneer connector.









OK, so to the code....

This is the transmitter code:



and the test receiver code...



Now all that remains is to box it up, and create some clocks!

Tuesday 25 August 2015

Request from Raminda Subhashana - Arduino astronomical clock controller with over-ride! De-luxe!

Well, I've not always got time for this sort of thing, but one of my readers, Raminda has sent a request in...

Hi, Nice project Just checked it is working, perfect appreciate that. One thing I need to add Button to off light manually in Auto mode, but it should switch on automatically next day. please help me to add it. Thanks. on Pond Pump Controller Update!

Thanks Raminda, a great idea. Sometimes it's difficult to fathom things out, especially when you are trying to learn, and don't have anyone to ask.

OK, so it looks like Raminda is using my Pond pump controller to switch on and off some lights during the night. Great idea.

So, we'll need to add a push button in to switch our over-ride on. A1 isn't doing anything, so we'll hook up a momentary push button (S1) to pin A1 and GND. That's all the hardware we'll need to modify (Note I've made some amendments to the diagram from previous)



Then , we need to think about the code. We'll need to define a flag to control the status of our over-ride. We'll set it to false to start with,

// Over-Ride feature flag for Raminda Subhashana
boolean OverRideFlag = false;

OK. Now we need to tell the arduino what we need pin A1 to be doing... Add this line to the setup..




    pinMode(A1,INPUT);// Over ride push button connected to A1 (and GND)
    digitalWrite(A1,HIGH);


This tells the arduino that A1 is an input, and we want to pull it high when the button is open circuit.

Now in the Loop we need to check the status of the button.

       buttonstate = digitalRead(A1);// check to see if our override button is pressed, if it is, set the flag
       if (buttonstate == LOW ) {
         OverRideFlag=true;
       }        

Here we set the temporary variable buttonstate (also used elsewhere) to the value of A1, if it's low, we set our OverRideFlag to be true.

Finally we need to check the status of the flag, when we come to set the status of the relay, so we need to modify two lines of code...

      if (TimeMins >= Sunrise && TimeMins <=Sunset+60 && tempC>=2 && OverRideFlag==false) { //If it's after sunrise and before sunset + 1 hour, and it's not frozen, and our override isn't set, switch our relay on

I think the comment there is self-explanitory!

We also need to reset the flag once the sun comes up again:
    // Reset Override flag if the sun is up!
    if (TimeMins == Sunrise) {
      OverRideFlag = false;
    }

There's no need to specifically set the relay off, as this is taken care of in the else statement.

So, there you go Raminda, but I have a concern. What if we change our mind? What happens if we want to un-overide it?!?!

ahh... OK , we can change the code slightly to flip the status of the flag everytime the button is pressed.. ON-OFF-ON-OFF  etc . This might suffer with switch bounce, in which case we'll need a slight delay, but it worked ok with me (because of the delay in the loop).

       buttonstate = digitalRead(A1);// check to see if our override button is pressed, if it is, change the status of the flag
       if (buttonstate == LOW ) {
         OverRideFlag = ~OverRideFlag;
       }       
The ~ sign means NOT and is a boolean operator. So our flag is now NOT what it was before, so flips from true to false, or false to true!
The whole code should now look like this:
// Dawn & Dusk controller with frost protection. A special revision for Raminda Subhashana to control some lights.
// 5th December 2014. Modified 17th April 2015. Modified 25 August 2015
// (C) A.G.Doswell 2014 & 2015
// License: The MIT License (See full license at the bottom of this file)
//
// Date and time functions using a DS1307 RTC connected via I2C and Wire lib
//
// Designed to control a relay connected to pin A3. Pin goes low during daylight hours and high during night. Relay uses active low, so is
// "On" during the day. This is connected to the fountain pump in my garden.
//
// Time is set using a rotary encoder with integral push button. The Encoder is connected to interrupt pins D2 & D3 (and GND), 
// and the push button to pin analogue 0 (and GND)
// The RTC is connections are: Analogue pin 4 to SDA. Connect analogue pin 5 to SCL.
// A 2 x 16 LCD display is connected as follows (NOTE. This is NOT conventional, as interrupt pins are required for the encoder)
//  Arduino LCD  
//  D4      DB7
//  D5      DB6
//  D6      DB5
//  D7      DB4
//  D12     RS
//  D13     E
// 
// In this revision, there is a Dallas 18B20 Temperature sensor connected to pin 8, enabling frost protection. This is pulled up to +5volts via a 4.7K resistor.
//
// Use: Pressing and holding the button will enter the clock set mode (on release of the button). Clock is set using the rotary encoder. 
// The clock must be set to UTC.
// Pressing and releasing the button quickly will display the current sun rise and sun set times. Pressing the button again will enter the mode select menu. 
// Modes are AUTO: On when the sun rises, off when it sets.
//           AUTO EXTEND : same as above but goes off 1 hour after sunet (nice for summer evenings!) 
//           ON: Permanently ON
//           OFF: Permanently OFF (Who'd have guessed it?)
//
// Change the LATTITUDE and LONGITUDE constant to your location.
// Use the address finder from http://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.html to find the address of your temperature sensor and enter it where required in DeviceAddress.
// 28th Dec 2014 - Slowed the rate at which the temperature is requested down to once per minute. It has improved the clock display, and solved an issue whereby the temp sensor wasn't always ready to send data, and hung up.
// 10th Jan 2015 - Altered the method of updating the temp to something simpler and more sensible!
// 17th April 2015 - Stored Mode settings in EEPROM
//
// Be sure to visit my website at http://andydoz.blogspot.com

#include <Wire.h>
#include "RTClib.h" // from https://github.com/adafruit/RTClib
#include <LiquidCrystal.h>
#include <Encoder.h> // from http://www.pjrc.com/teensy/td_libs_Encoder.html
#include <TimeLord.h> // from http://swfltek.com/arduino/timelord.html. When adding it to your IDE, rename the file, removing the "-depreciated" 
#include <OneWire.h> // from http://playground.arduino.cc/Learning/OneWire
#include <DallasTemperature.h> // from http://www.hacktronics.com/code/DallasTemperature.zip. When adding this to your IDE, ensure the .h and .cpp files are in the top directory of the library.
#include <EEPROM.h> 

#define ONE_WIRE_BUS 8 // Data wire from temp sensor is plugged into pin 8 on the Arduino
OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices
DeviceAddress outsideThermometer = { 0x28, 0x1A, 0x1A, 0x3E, 0x06, 0x00, 0x00,0xC7 }; // use the address finder from http://www.hacktronics.com/Tutorials/arduino-1-wire-address-finder.html to find the address of your device.
RTC_DS1307 RTC; // Tells the RTC library that we're using a DS1307 RTC
Encoder knob(2, 3); //encoder connected to pins 2 and 3 (and ground)
LiquidCrystal lcd(12, 13, 7, 6, 5, 4); // I used an odd pin combination because I need pin 2 and 3 for the interrupts.
//the variables provide the holding values for the set clock routine
int setyeartemp; 
int setmonthtemp;
int setdaytemp;
int sethourstemp;
int setminstemp;
int setsecs = 0;
int maxday; // maximum number of days in the given month
int TimeMins = 0; // number of seconds since midnight
int TimerMode = 2; //mode 0=Off 1=On 2=Auto
int TimeOut = 10;
int TimeOutCounter;

// These variables are for the push button routine
int buttonstate = 0; //flag to see if the button has been pressed, used internal on the subroutine only
int pushlengthset = 3000; // value for a long push in mS
int pushlength = pushlengthset; // set default pushlength
int pushstart = 0;// sets default push value for the button going low
int pushstop = 0;// sets the default value for when the button goes back high

int knobval; // value for the rotation of the knob
boolean buttonflag = false; // default value for the button flag
float tempC; // Temperature

// Over-Ride feature flag for Raminda Subhashana
boolean OverRideFlag = false;


const int TIMEZONE = 0; //UTC
const float LATITUDE = 20.00, LONGITUDE = -2.00;  // set YOUR position here 
int Sunrise, Sunset; //sunrise and sunset expressed as minute of day (0-1439)
TimeLord myLord; // TimeLord Object, Global variable
byte sunTime[]  = {0, 0, 0, 1, 1, 13}; // 17 Oct 2013
int SunriseHour, SunriseMin, SunsetHour, SunsetMin; //Variables used to make a decent display of our sunset and sunrise time.
DallasTemperature sensors(&oneWire); // Pass our oneWire reference to Dallas Temperature.

void setup () {
    //Serial.begin(57600); //start debug serial interface
    Wire.begin(); //start I2C interface
    RTC.begin(); //start RTC interface
    lcd.begin(16,2); //Start LCD (defined as 16 x 2 characters)
    lcd.clear(); 
    pinMode(A0,INPUT);//push button on encoder connected to A0 (and GND)
    digitalWrite(A0,HIGH); //Pull A0 high
    pinMode(A1,INPUT);// Over ride push button connected to A1 (and GND)
    digitalWrite(A1,HIGH);
    pinMode(A3,OUTPUT); //Relay connected to A3
    digitalWrite (A3, HIGH); //sets relay off (default condition)
    sensors.begin();
    sensors.setResolution(outsideThermometer, 12); // set the resolution to 12 bits (why not?!)
    
    //Checks to see if the RTC is runnning, and if not, sets the time to the time this sketch was compiled, also sets default mode to 2 and writes to EEPROM
    DateTime now = RTC.now();
    lcd.clear();
    lcd.print("Waiting for RTC");
    delay (60000);// wait a minute for the RTC to sort itself out.
    if (! RTC.isrunning()) {
    RTC.adjust(DateTime(__DATE__, __TIME__));
    EEPROM.update (0,0); // set the auto mode as 0 (off) for default
    }
  
 
   lcd.print("Raminda Subhashana");
   lcd.setCursor(0, 1);
   lcd.print("Light Controller");
   delay (2000);
   lcd.clear();
   lcd.print("Version 1.32");
   lcd.setCursor(0, 1);
   lcd.print("(C) A.G.Doswell ");
   delay (5000);
   lcd.clear();
    //Timelord initialisation
    myLord.TimeZone(TIMEZONE * 60);
    myLord.Position(LATITUDE, LONGITUDE);
    CalcSun ();
    TimerMode = EEPROM.read (0); // Read TimerMode from EEPROM
    delay (1000);
}
           
void printTemperature(DeviceAddress deviceAddress)
{
  lcd.setCursor (9,1);
  tempC = sensors.getTempC(deviceAddress);
  if (tempC == -127.00) {
    lcd.print("Err");
  } else {
    
    lcd.print(tempC);
    lcd.print((char)0xDF);
    lcd.print("C ");
   
  }
}


void loop () {
    

  
    DateTime now = RTC.now(); //get time from RTC
    //Display current time
    lcd.setCursor (0,0);
    lcd.print(now.day(), DEC);
    lcd.print('/');
    lcd.print(now.month());
    lcd.print('/');
    lcd.print(now.year(), DEC);
    lcd.print(" ");
    lcd.setCursor (0,1);
    lcd.print(now.hour(), DEC);
    lcd.print(':');
    if (now.minute() <10) 
      {
        lcd.print("0");
      }
    lcd.print(now.minute(), DEC);
    lcd.print(':');
    if (now.second() <10) 
      {
        lcd.print("0");
      }
    lcd.print(now.second());
    lcd.print(" ");
    
    //current time in minutes since midnight (used to check against sunrise/sunset easily)
    TimeMins = (now.hour() * 60) + now.minute();
   
    
    //Get and display temp every minute
    if (now.second() == 7) {
      sensors.requestTemperatures(); // Request temperature
      delay (249);
      printTemperature(outsideThermometer); // display on lcd.
     
    }
    
    // Calculate sun times once a day at a minute past midnight
    if (TimeMins == 1) {
      lcd.clear();
      CalcSun ();
    }
    
    // Reset Override flag if the sun is up!
    if (TimeMins == Sunrise) {
      OverRideFlag = false;
    }
         
    
    if (TimerMode ==2) {
      if (TimeMins >= Sunrise && TimeMins <=Sunset-1 && tempC>=2 && OverRideFlag==false) { //If it's after sunrise and before sunset, and it's not frozen, and our override isn't set, switch our relay on
          digitalWrite (A3, LOW);
          lcd.setCursor (13,0);
          lcd.print ("On ");
        }
        else {  //otherwise switch it off
          digitalWrite (A3, HIGH);
          lcd.setCursor (13,0);
          lcd.print ("Off");
        }
      }
       if (TimerMode ==3) {
      if (TimeMins >= Sunrise && TimeMins <=Sunset+60 && tempC>=2 && OverRideFlag==false) { //If it's after sunrise and before sunset + 1 hour, and it's not frozen, and our override isn't set, switch our relay on
          digitalWrite (A3, LOW);
          lcd.setCursor (13,0);
          lcd.print ("On ");
        }
        else {  //otherwise switch it off
          digitalWrite (A3, HIGH);
          lcd.setCursor (13,0);
          lcd.print ("Off");
        }
      }
       if (TimerMode ==0) { // Off
         digitalWrite (A3, HIGH);
         lcd.setCursor (13,0);
         lcd.print ("Off");
       }
     
       if (TimerMode ==1 && tempC>=2) { // TimerMode is On, but it's not frozen
         digitalWrite (A3, LOW);
         lcd.setCursor (13,0);
         lcd.print ("On ");
       }
       
       buttonstate = digitalRead(A1);// check to see if our override button is pressed, if it is, change the status of the flag
       if (buttonstate == LOW ) {
         OverRideFlag = ~OverRideFlag;
       }        

    
    pushlength = pushlengthset;
    pushlength = getpushlength ();
    delay (10);
    
    if (pushlength <pushlengthset) {
      lcd.clear ();
      ShortPush ();   
      lcd.clear ();
    }
    
       
       //This runs the setclock routine if the knob is pushed for a long time
       if (pushlength >pushlengthset) {
         lcd.clear();
         DateTime now = RTC.now();
         setyeartemp=now.year(),DEC;
         setmonthtemp=now.month(),DEC;
         setdaytemp=now.day(),DEC;
         sethourstemp=now.hour(),DEC;
         setminstemp=now.minute(),DEC;
         setclock();
         pushlength = pushlengthset;
       };
}

//sets the clock
void setclock (){
   setyear ();
   lcd.clear ();
   setmonth ();
   lcd.clear ();
   setday ();
   lcd.clear ();
   sethours ();
   lcd.clear ();
   setmins ();
   lcd.clear();
   RTC.adjust(DateTime(setyeartemp,setmonthtemp,setdaytemp,sethourstemp,setminstemp,setsecs)); //set the DS1307 RTC
   CalcSun (); //refresh the sunrise and sunset times
   delay (1000);
   
}

// subroutine to return the length of the button push.
int getpushlength () {
  buttonstate = digitalRead(A0);  
       if(buttonstate == LOW && buttonflag==false) {     
              pushstart = millis();
              buttonflag = true;
          };
          
       if (buttonstate == HIGH && buttonflag==true) {
         pushstop = millis ();
         pushlength = pushstop - pushstart;
         buttonflag = false;
       };
       return pushlength;
}
// The following subroutines set the individual clock parameters
int setyear () {
   lcd.setCursor (0,0);
    lcd.print ("Set Year");
    pushlength = pushlengthset;
    pushlength = getpushlength ();
    if (pushlength != pushlengthset) {
      return setyeartemp;
    }

    lcd.setCursor (0,1);
    knob.write(0);
    delay (50);
    knobval=knob.read();
    if (knobval < -1) { //bit of software de-bounce
      knobval = -1;
    }
    if (knobval > 1) {
      knobval = 1;
    }
    setyeartemp=setyeartemp + knobval;
    if (setyeartemp < 2014) { //Year can't be older than currently, it's not a time machine.
      setyeartemp = 2014;
    }
    lcd.print (setyeartemp);
    lcd.print("  "); 
    setyear();
}
  
int setmonth () {

   lcd.setCursor (0,0);
    lcd.print ("Set Month");
    pushlength = pushlengthset;
    pushlength = getpushlength ();
    if (pushlength != pushlengthset) {
      return setmonthtemp;
    }

    lcd.setCursor (0,1);
    knob.write(0);
    delay (50);
    knobval=knob.read();
    if (knobval < -1) {
      knobval = -1;
    }
    if (knobval > 1) {
      knobval = 1;
    }
    setmonthtemp=setmonthtemp + knobval;
    if (setmonthtemp < 1) {// month must be between 1 and 12
      setmonthtemp = 1;
    }
    if (setmonthtemp > 12) {
      setmonthtemp=12;
    }
    lcd.print (setmonthtemp);
    lcd.print("  "); 
    setmonth();
}

int setday () {
  if (setmonthtemp == 4 || setmonthtemp == 5 || setmonthtemp == 9 || setmonthtemp == 11) { //30 days hath September, April June and November
    maxday = 30;
  }
  else {
  maxday = 31; //... all the others have 31
  }
  if (setmonthtemp ==2 && setyeartemp % 4 ==0) { //... Except February alone, and that has 28 days clear, and 29 in a leap year.
    maxday = 29;
  }
  if (setmonthtemp ==2 && setyeartemp % 4 !=0) {
    maxday = 28;
  }
  
   lcd.setCursor (0,0);
    lcd.print ("Set Day");
    pushlength = pushlengthset;
    pushlength = getpushlength ();
    if (pushlength != pushlengthset) {
      return setdaytemp;
    }

    lcd.setCursor (0,1);
    knob.write(0);
    delay (50);
    knobval=knob.read();
    if (knobval < -1) {
      knobval = -1;
    }
    if (knobval > 1) {
      knobval = 1;
    }
    setdaytemp=setdaytemp+ knobval;
    if (setdaytemp < 1) {
      setdaytemp = 1;
    }
    if (setdaytemp > maxday) {
      setdaytemp = maxday;
    }
    lcd.print (setdaytemp);
    lcd.print("  "); 
    setday();
}

int sethours () {
    lcd.setCursor (0,0);
    lcd.print ("Set Hours");
    pushlength = pushlengthset;
    pushlength = getpushlength ();
    if (pushlength != pushlengthset) {
      return sethourstemp;
    }

    lcd.setCursor (0,1);
    knob.write(0);
    delay (50);
    knobval=knob.read();
    if (knobval < -1) {
      knobval = -1;
    }
    if (knobval > 1) {
      knobval = 1;
    }
    sethourstemp=sethourstemp + knobval;
    if (sethourstemp < 1) {
      sethourstemp = 1;
    }
    if (sethourstemp > 23) {
      sethourstemp=23;
    }
    lcd.print (sethourstemp);
    lcd.print("  "); 
    sethours();
}

int setmins () {

   lcd.setCursor (0,0);
    lcd.print ("Set Mins");
    pushlength = pushlengthset;
    pushlength = getpushlength ();
    if (pushlength != pushlengthset) {
      return setminstemp;
    }

    lcd.setCursor (0,1);
    knob.write(0);
    delay (50);
    knobval=knob.read();
    if (knobval < -1) {
      knobval = -1;
    }
    if (knobval > 1) {
      knobval = 1;
    }
    setminstemp=setminstemp + knobval;
    if (setminstemp < 0) {
      setminstemp = 0;
    }
    if (setminstemp > 59) {
      setminstemp=59;
    }
    lcd.print (setminstemp);
    lcd.print("  "); 
    setmins();
}

int setmode () { //Sets the mode of the timer. Auto, On or Off

    lcd.setCursor (0,0);
    lcd.print ("Set Mode");
    pushlength = pushlengthset;
    pushlength = getpushlength ();
    if (pushlength != pushlengthset) {
      EEPROM.update (0,TimerMode); //write the mode setting to EEPROM
      return TimerMode;
    }

    lcd.setCursor (0,1);
    knob.write(0);
    delay (50);
    knobval=knob.read();
    if (knobval < -1) {
      knobval = -1;
    }
    if (knobval > 1) {
      knobval = 1;
    }
    TimerMode=TimerMode + knobval;
    if (TimerMode < 0) {
      TimerMode = 0;
    }
    if (TimerMode > 3) {
      TimerMode=3;
    }
    if (TimerMode == 0) {
    lcd.print("Off        ");
    lcd.print("  "); 
    }
    if (TimerMode == 1) {
    lcd.print("On         ");
    lcd.print(" "); 
    }
    if (TimerMode == 2) {
    lcd.print("Auto       ");
    lcd.print("  "); 
    }
    if (TimerMode == 3) {
    lcd.print("Auto Extend");
    lcd.print("  "); 
    }
    setmode ();
}

int CalcSun () { //Calculates the Sunrise and Sunset times
    DateTime now = RTC.now();
    sunTime[3] = now.day(); // Give Timelord the current date
    sunTime[4] = now.month();
    sunTime[5] = now.year();
    myLord.SunRise(sunTime); // Computes Sun Rise.
    Sunrise = sunTime[2] * 60 + sunTime[1]; // Sunrise returned in minutes past midnight
    SunriseHour = sunTime[2];
    SunriseMin = sunTime [1];
    sunTime[3] = now.day(); // Uses the Time library to give Timelord the current date
    sunTime[4] = now.month();
    sunTime[5] = now.year();
    myLord.SunSet(sunTime); // Computes Sun Set.
    Sunset = sunTime[2] * 60 + sunTime[1]; // Sunset returned in minutes past midnight
    SunsetHour = sunTime[2];
    SunsetMin = sunTime [1];
}

void ShortPush () {
  //This displays the calculated sunrise and sunset times when the knob is pushed for a short time.
for (long Counter = 0; Counter < 604 ; Counter ++) { //returns to the main loop if it's been run 604 times 
                                                     //(don't ask me why I've set 604,it seemed like a good number)
  lcd.setCursor (0,0);
  lcd.print ("Sunrise ");
  lcd.print (SunriseHour);
  lcd.print (":");
  if (SunriseMin <10) 
     {
     lcd.print("0");
     }
  lcd.print (SunriseMin);
  lcd.setCursor (0,1);
  lcd.print ("Sunset ");
  lcd.print (SunsetHour);
  lcd.print (":"); 
    if (SunsetMin <10) 
     {
     lcd.print("0");
     }
  lcd.print (SunsetMin);        

    
  //If the knob is pushed again, enter the mode set menu
  pushlength = pushlengthset;
  pushlength = getpushlength ();
  if (pushlength != pushlengthset) {
    lcd.clear ();
    TimerMode = setmode ();

  }
  
}

}
/*
 * Copyright (c) 2015 Andrew Doswell
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHOR(S) OR COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */


Hope this helps! Have fun and check back soon!

PS. Some users are having trouble with contact bounce... Add C1/C2, R5 & R6...