Skip to content

Instantly share code, notes, and snippets.

@seasider1960
Last active January 23, 2018 17:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seasider1960/f608ce29da70cf11607c6dbb8ddaf0f8 to your computer and use it in GitHub Desktop.
Save seasider1960/f608ce29da70cf11607c6dbb8ddaf0f8 to your computer and use it in GitHub Desktop.
Trump TTG Clock Code
[code]
const String FirmwareVersion = "100003"; //100003 provided multiple time servers and fixed display bugs
//Format _X.XX__
//Hardware is NIXIE CLOCK SHIELD NCS314 by GRA & AFCH (fominalec@gmail.com)
//04/06/2017
/*GRCH Code version 010200 Modified to add:
Obtain time from internet rather than RTC;
Switch control for DST, 12/24 format, LEDs and Edit Mode;
Rotary Encoder control for numerous functions
Tweeting future event time;
Future event monitoring and display;
Auto mode changer for time/date/future event days/future event hrs, mins and seconds;
Motion Sensor to turn off Nixie tubes and log motion detection;
Web server for instructions and configuration;
LCD display;
And to remove:
Beeping song;
Alarm;
"Rotating" LED colors;
Button input control
confirmed to work with HW ver 1.2
*/
#include <SPI.h>
//#include <Wire.h>
#include <ClickButton.h>
#include <TimeLib.h>
#include <Tone.h>
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h> //ADDED LCD LIBRARY FOR DISPLAY
#include <LCD.h>
#include <Dhcp.h>
#include <Dns.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
#include <EthernetClient.h>
#include <EthernetServer.h>
#include <SD.h>
#include <Twitter.h>
#include <Rotary.h>
#include "avr/eeprom.h"
/*******************************************************************************************************
Ethernet & Server
*******************************************************************************************************/
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; //for ethernet shield
//For configuring name of new future event for LCD display
#define REQ_BUF_SZ 90 // size of buffer used to capture HTTP requests
#define LCD_BUF_SZ 21 // size of buffer that stores a line of text for the LCD + null terminator
EthernetServer server(80); // instantiate server object
File webFile; // instantiate file objects for the SD card
File clockFile;
char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
char req_index = 0; // index into HTTP_req buffer
char lcd_buf_1[LCD_BUF_SZ] = {0};// buffer to save LCD line 1 text to
char lcd_buf_2[LCD_BUF_SZ] = {0};// buffer to save LCD line 2 text to -- not used
/*******************************************************************************************************
End Ethernet & Server
*******************************************************************************************************/
/*******************************************************************************************************
Twitter
*******************************************************************************************************/
Twitter twitter("YOUR TOKEN HERE");
String clockSpeak;
boolean tweet = true;
bool tweetSent = false;
unsigned long tweetTime;
unsigned long tweetRange;
unsigned long secondCount;
int lastSecond = 0;
char temp[10];
int prevDay = day();
/*******************************************************************************************************
End Twitter
*******************************************************************************************************/
/*******************************************************************************************************
NTP & Time setup
*******************************************************************************************************/
// NTP Servers:
IPAddress timeServer1(129, 6, 15, 28); // time-a.nist.gov
IPAddress timeServer2(129, 6, 15, 29); // time-b.nist.gov
IPAddress timeServer3(132, 163, 96, 1); //time-a-b.nist.gov
//#define READ_TIME_PROVIDER_MILLIS 600000
EthernetUDP Udp;
unsigned int localPort = 8888; // local port to listen for UDP packets
int8_t timeZone; // default is Eastern Standard Time (USA)
int8_t offSet; // hour difference between local time and FE time
/*******************************************************************************************************
End NTP & Time setup
*******************************************************************************************************/
/*******************************************************************************************************
Declare Arduino Mega pins
*******************************************************************************************************/
const byte pinBuzzer = 2; //for button press sounds
const byte RedLedPin = 3; //PWM output for red LEDs
const byte GreenLedPin = 6; //PWM output for green LEDs
const byte BlueLedPin = 45; //PWM output for blue LEDs
const byte redSwitchPin = 24; // turns on red LED
const byte greenSwitchPin = 26;// turns om green LED
const byte blueSwitchPin = 28; // turns on blue LED
const byte DHVpin = 5; // HIGH turns on MAX1771 driver hight voltage (DHV) 110-220V
const byte pinLowerDots = 8; //HIGH turns on RH neon dot
const byte pinUpperDots = 12; //HIGH turns on LH neon dot
const byte tubesOffPin = 30; // turns on tubes (controls DHVpin)
const byte LEpin = 7; //latching pin for sending data over SPI
const byte webSwitchPin = 32; //Allows access to server - display issues if always on
const byte newEditModeSwitchPin = 22; //Edit mode
const byte tweetSwitchPin = 34; //Tweet now
const byte twelveHrSwitchPin = 36; // 12/24 hour display
const byte dstSwitchPin = 38; //timeZone -1
const byte pinReSet = 46; //Multifuction Selector switch on rotary encoder
const byte motionSensorPin = 42; //for motion sensor
const byte motionSensorLED = 44; //indicator for motion sensor
const byte pin_A = 18; // for rotary encoder (Selector)
const byte pin_B = 19; // for rotary encoder (Selector)
/*******************************************************************************************************
End Declare Arduino Mega pins
*******************************************************************************************************/
/*******************************************************************************************************
Rotary Encoder Variables
*******************************************************************************************************/
unsigned long currentTime;
unsigned long loopTime;
unsigned char encoder_A;
unsigned char encoder_B;
unsigned char encoder_A_prev = 0;
int menuCounter;
/*******************************************************************************************************
End Rotary Encoder Variables
*******************************************************************************************************/
/*******************************************************************************************************
LCD Address and pins
*******************************************************************************************************/
#define I2C_ADDR 0x3F // LCD address - found using I2C scanner
#define BACKLIGHT 3 // Not used because backlight is controlled with potentiometer
#define En_pin 2
#define Rw_pin 1
#define Rs_pin 0
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7
LiquidCrystal_I2C lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin); //lcd pin definitions
/*******************************************************************************************************
End LCD Address and pins
*******************************************************************************************************/
/*******************************************************************************************************
Display Variables
*******************************************************************************************************/
String stringToDisplay = "000000"; // Content of this string is displayed on tubes (must be 6 chars length)
const word fpsLimit = 16666; // 1/60*1.000.000 //limit maximum refresh rate on 60 fps
int menuPosition = 0; // 0 - time
// 1 - date
// 2 - future event hrs, mins and secs
// 3 - future event days
// 4 - Info 1 (LCD only)
// 5 - Info 2 (LCD only)
// 0 1 2 3 4 5 6 7 8 9
word SymbolArray[10] = {65534, 65533, 65531, 65527, 65519, 65503, 65471, 65407, 65279, 65023};
//-- ------------0----- --1--------2-------3------4-------5--------6--------7-------8--------9--------10-------11----- --12-------13-------14-------15--------16
// names: Time, Date, FET, FED, TZone Thour, Tminute, Tsecond, Tday, Tmonth, Tyear, FEhour, FEminute, FEsecond FEDay FEMonth FEYear
// 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
int8_t value[17] = { 3, 0, 0, 0, -5, 0, 0, 0, 0, 0, 0, 12, 00, 00, 20, 1, 21};
int maxValue[17] = { 0, 0, 0, 0, 12, 23, 59, 59, 31, 12, 99, 23, 59, 59, 31, 1, 99};
int minValue[17] = { 0, 0, 0, 0, -12, 00, 00, 00, 1, 1, 00, 00, 00, 00, 1, 1, 00};
#define TimeIndex 0
#define DateIndex 1
#define FETimeIndex 2
#define FEDateIndex 3
#define TZoneIndex 4
#define TimeHoursIndex 5
#define TimeMintuesIndex 6
#define TimeSecondsIndex 7
#define DateDayIndex 8
#define DateMonthIndex 9
#define DateYearIndex 10
#define FEHourIndex 11
#define FEMinuteIndex 12
#define FESecondIndex 13
#define FEDayIndex 14
#define FEMonthIndex 15
#define FEYearIndex 16
#define timeModePeriod 15000 //Time and FE hrs mins and secs
#define dateModePeriod 4000 //Date and FE ddays
long modesChangePeriod = timeModePeriod;
int digits;
/*******************************************************************************************************
End Display Variables
*******************************************************************************************************/
/*******************************************************************************************************
EEPROM Addresses
*******************************************************************************************************/
byte TZoneEEPROMAddress = 0;
byte FEHourEEPROMAddress = 1; // and 2,3 hours, minutes, seconds
byte FEMinuteEEPROMAddress = 2;
byte FESecondEEPROMAddress = 3;
byte FEDayEEPROMAddress = 4; // and 5,6 days, months years
byte FEMonthEEPROMAddress = 5;
byte FEYearEEPROMAddress = 6;
byte offSetEEPROMAddress = 12; // for dst adjustment
const int EEPROM_MIN_ADDR = 13; // for Future Event display (20 characters plus 2)
const int EEPROM_MAX_ADDR = 35;
/*******************************************************************************************************
End EEPROM Addresses
*******************************************************************************************************/
/*******************************************************************************************************
Miscellaneous
*******************************************************************************************************/
unsigned long motionMillis = 1800000; // turns tubes off after 30 minutes if no movement detected
unsigned long motionIntervalMillis; // stops multiple motion notifications
unsigned long timeNowUL; // motion detect timestamp - time_t var would not post to web
int mo; //for Future event month variable
int dd; //for Future event day variable
int yy; //for Future event year variable
int ss; //for Future event second variable
int mi; //for Future event minute variable
int hh; //for Future event hour variable
int RedLight; // red LED value
int GreenLight; //green LED value
int BlueLight; //blue LED vale
bool modeLock = false; //turns off automatic display mode cycling
bool modeChangedByUser = false; //temp interrupt of display cycling
bool transactionInProgress = false;
bool dst = true; // for dst adjust
bool newEditMode = true; //takes edit code out of normal main loop - could make separate function
ClickButton reSetButton(pinReSet, LOW, CLICKBTN_PULLUP); //rotary encoder declaration
Tone tone1; // tone declaration for button press sounds
/*******************************************************************************************************
End Miscellaneous ::::: End Declarations
*******************************************************************************************************/
/*******************************************************************************************************
Setup
*******************************************************************************************************/
void setup()
{
Serial.begin(115200);
timeZone = value[TZoneIndex];
pinMode(10, OUTPUT); // disable w5100 (ethernet) SPI while setting up SD
digitalWrite(10, HIGH); // "
//initialize SD card
Serial.println("Initializing SD card...");
if (!SD.begin(4)) {
Serial.println("ERROR - SD card initialization failed!");
lcd.print(F("SD init failed"));
return; // init failed
}
Serial.println("SUCCESS - SD card initialized.");
// check for index.htm file
if (!SD.exists("Index.htm")) {
Serial.println("ERROR - Can't find index.htm file!");
return; // can't find index file
}
Serial.println("SUCCESS - Found index.htm file.");
// disable w5100 SPI
digitalWrite(10, HIGH);
// takes a second for the w5100 to get ready
delay(2000);
Serial.println("Setting up Ethernet");
if (Ethernet.begin(mac) == 0) {
while (1) {
Serial.println("Failed to configure Ethernet using DHCP");
delay(5000);
}
}
Serial.print("IP number assigned by DHCP is ");
Serial.println(Ethernet.localIP());
Udp.begin(localPort);
Serial.println("Waiting for sync");
setSyncProvider(getNtpTime);
lcd.begin (20, 4); // initialize the LCD
lcd.setBacklightPin(BACKLIGHT, POSITIVE);
lcd.setBacklight(HIGH); //Turn on LCD backlight
lcd.backlight();
lcd.clear();
lcd.print("Local IP Address:");
lcd.setCursor(0, 1);
lcd.print(Ethernet.localIP());
lcd.setCursor(0, 2);
lcd.print("Getting time....");
server.begin();
//Wire.begin();
clockSpeak.reserve(140); //twitter message
digitalWrite(DHVpin, LOW); // off MAX1771 Driver Hight Voltage(DHV) 110-220V
value[FEHourIndex] = EEPROM.read(FEHourEEPROMAddress);
value[FEMinuteIndex] = EEPROM.read(FEMinuteEEPROMAddress);
value[FESecondIndex] = EEPROM.read(FESecondEEPROMAddress);
value[FEDayIndex] = EEPROM.read(FEDayEEPROMAddress);
value[FEMonthIndex] = EEPROM.read(FEMonthEEPROMAddress);
value[FEYearIndex] = EEPROM.read(FEYearEEPROMAddress);
value[TZoneIndex] = (int8_t)EEPROM.read(TZoneEEPROMAddress);
offSet = (int8_t)EEPROM.read(offSetEEPROMAddress);
tone1.begin(pinBuzzer);
pinMode(LEpin, OUTPUT);
pinMode(DHVpin, OUTPUT);
pinMode(pinBuzzer, OUTPUT);
pinMode(dstSwitchPin, INPUT_PULLUP); //Quick DST
pinMode(RedLedPin, OUTPUT);
pinMode(GreenLedPin, OUTPUT);
pinMode(BlueLedPin, OUTPUT);
pinMode(redSwitchPin, INPUT_PULLUP); // Physical red LED switch
pinMode(greenSwitchPin, INPUT_PULLUP); // Physical green LED switch
pinMode(blueSwitchPin, INPUT_PULLUP); // //Physical blue LED switch
pinMode(newEditModeSwitchPin, INPUT_PULLUP); //Physical tubes off switch
pinMode(twelveHrSwitchPin, INPUT_PULLUP); //
pinMode(tweetSwitchPin, INPUT_PULLUP); //
pinMode(webSwitchPin, INPUT_PULLUP); //
pinMode(motionSensorPin, INPUT);//
pinMode(motionSensorLED, OUTPUT);//
pinMode(tubesOffPin, INPUT_PULLUP);
pinMode(pin_A, INPUT_PULLUP);
pinMode(pin_B, INPUT_PULLUP);
pinMode(pinReSet, INPUT_PULLUP);
reSetButton.debounceTime = 50; // Debounce timer in ms
reSetButton.multiclickTime = 80; // time limit for multi clicks
reSetButton.longClickTime = 2000; // time until "long click" registers
currentTime = millis(); //for RE
loopTime = currentTime; //for RE
// SPI setup
SPI.begin(); //
SPI.setDataMode (SPI_MODE3); // Mode 3 SPI
SPI.setClockDivider(SPI_CLOCK_DIV128); // SCK = 16MHz/128= 125kHz
doTest();
if (digitalRead(dstSwitchPin) == LOW) dst = true; else dst = false;
randomSeed(analogRead(A11));
tweetSet();
secondCount = hour() * 60;
secondCount = secondCount * 60;
secondCount = secondCount + minute() * 60;
secondCount = secondCount + second();
if (digitalRead(dstSwitchPin) == LOW);
{
secondCount = secondCount + 3600;
}
Serial.print("secondCount = ");
Serial.println(secondCount);
lcd.clear();
tweetTimeDisplay();
prevDay = day();
}
time_t prevDisplay = 0; // when the digital clock was displayed
time_t timeNow; // to log motion detect time
/***************************************************************************************************************
Main Loop
***************************************************************************************************************/
void loop()
{
if (digitalRead(newEditModeSwitchPin) == HIGH && newEditMode == true) // for exit of edit mode
{
lcd.clear();
digitalWrite(DHVpin, HIGH);
newEditMode = false;
menuCounter = 0;
setSyncProvider(getNtpTime);
}
//tube display is unstable while web and edit functions are enabled
if (digitalRead(webSwitchPin) == LOW || digitalRead(tubesOffPin) == LOW || digitalRead(newEditModeSwitchPin) == LOW) digitalWrite(DHVpin, LOW);
/***************************************************************************************************************
Loop when not in edit mode (aka new edit mode)
***************************************************************************************************************/
if (digitalRead(newEditModeSwitchPin) == HIGH && newEditMode == false)
{
if (prevDay != day())
{
tweetSet();
prevDay = day();
}
// for encoder adjusting brightness of LEDs
if (digitalRead(redSwitchPin) == LOW) analogWrite(RedLedPin, RedLight); else analogWrite(RedLedPin, 0);
if (digitalRead(greenSwitchPin) == LOW) analogWrite(GreenLedPin, GreenLight); else analogWrite(GreenLedPin, 0);
if (digitalRead(blueSwitchPin) == LOW) analogWrite(BlueLedPin, BlueLight); else analogWrite(BlueLedPin, 0);
currentTime = millis();
if (currentTime >= (loopTime + 5)) // 5ms since last check of encoder = 200Hz
{
encoder_A = digitalRead(pin_A); // Read encoder pins
encoder_B = digitalRead(pin_B);
if ((!encoder_A) && (encoder_A_prev)) // A has gone from high to low
{
if (encoder_B) // B is high so clockwise
{
RedLight = RedLight + 25; // increment brightness by 25
GreenLight = GreenLight + 25;
BlueLight = BlueLight + 25;
if (RedLight > 255) RedLight = 0; // if max value exceeded back to 0
if (GreenLight > 255) GreenLight = 0;
if (BlueLight > 255) BlueLight = 0;
}
else // B is low so anti-clockwise
{
RedLight = RedLight - 25;
GreenLight = GreenLight - 25;
BlueLight = BlueLight - 25;
if (RedLight < 0) RedLight = 255;
if (GreenLight < 0) GreenLight = 255;
if (BlueLight < 0) BlueLight = 255;
}
}
encoder_A_prev = encoder_A; // store value of A for next time
loopTime = currentTime; // update loopTime
}
if (timeStatus() != timeNotSet)
{
if (now() != prevDisplay) //update the display only if time has changed
{
prevDisplay = now();
}
}
if (reSetButton.clicks < 0 && modeLock == false)
{
modeLock = true;
tone1.play(1000, 500);
if (menuPosition == TimeIndex || menuPosition == DateIndex || menuPosition == FETimeIndex || menuPosition == FEDateIndex)
{
lcd.setCursor(0, 3);
lcd.print("ML:ON");
}
}
else if (reSetButton.clicks < 0 && modeLock == true) // for locking display on one mode
{
modeLock = false;
tone1.play(1000, 500);
if (menuPosition == TimeIndex || menuPosition == DateIndex || menuPosition == FETimeIndex || menuPosition == FEDateIndex)
{
lcd.setCursor(0, 3);
lcd.print(" ");
}
}
if (modeLock == false) modesChanger(); // for automatic display mode changing
{
doIndication();
}
// motion detection
byte stateMotion = digitalRead(motionSensorPin);
digitalWrite(motionSensorLED, stateMotion);
if (stateMotion == 1)
{
motionMillis = millis();
digitalWrite(DHVpin, HIGH);
}
else if (stateMotion == 0 && millis() - motionMillis > 1800000)
{
digitalWrite(DHVpin, LOW);
digitalWrite(pinUpperDots, LOW);
digitalWrite(pinLowerDots, LOW);
}
if (stateMotion == 1 && millis() - motionIntervalMillis > 5000)
{
time_t timeNow = now();
timeNowUL = timeNow;
logEvent(timeNow);
motionIntervalMillis = millis();
}
// end motion detection
if (lastSecond != second()) //increment second count for triggering tweet
{
secondCount++;
lastSecond = second();
}
if (tweetTime == secondCount && tweetSent == false) // send tweet when second count matches random tweet time selected for the day
{
send_twitter_timeToGo();
}
if (digitalRead(tweetSwitchPin) == LOW && tweetSent == false) // immediate tweet if not already sent
{
send_twitter_timeToGo();
if (tweetSent == true)
{
tweetTime = secondCount;
}
}
// Future event time calculation
int mo = value[FEMonthIndex];
int dd = value[FEDayIndex];
int yy = 2000 + value[FEYearIndex];
int ss = value[FESecondIndex];
int mi = value[FEMinuteIndex];
int hh = offSet + value[FEHourIndex];
tmElements_t time1 = {second(), minute(), hour(), 0, day(), month(), CalendarYrToTm(year())}, // Current time and date
time2 = {ss, mi, hh, 0, dd, mo, CalendarYrToTm(yy)}; // Time to go
uint32_t differenceP = (uint32_t)(makeTime(time2) - makeTime(time1));
struct elapsedTime_tP {
uint8_t Seconds, Minutes, Hours;
uint16_t Days;
} elapsedTimeP;
elapsedTimeP.Seconds = differenceP % 60;
differenceP /= 60; // now it is minutes
elapsedTimeP.Minutes = differenceP % 60;
differenceP /= 60; // now it is hours
elapsedTimeP.Hours = differenceP % 24;
differenceP /= 24; // now it is days
elapsedTimeP.Days = differenceP;
char buf[64];
sprintf(buf, "Elapsed time = %d days, %d hours, %d minutes, %d seconds.\r\n",
elapsedTimeP.Days, elapsedTimeP.Hours, elapsedTimeP.Minutes, elapsedTimeP.Seconds);
// end Future Event time calculation
// dst adjustment for time and future event calculation
if (digitalRead(dstSwitchPin) == LOW && dst == false)
{
value[TZoneIndex] = value[TZoneIndex] + 1;
offSet = offSet + 1;
setSyncProvider(getNtpTime);
dst = true;
}
else if (digitalRead(dstSwitchPin) == LOW && dst == true)
{
dst = true;
}
else if (digitalRead(dstSwitchPin) == HIGH && dst == true)
{
value[TZoneIndex] = value[TZoneIndex] - 1;
offSet = offSet - 1;
setSyncProvider(getNtpTime);
dst = false;
}
else
{
dst = false;
}
// end dst adjustment for time and future event calculation
// display mode cycle on short click of Selector
doIndication();
reSetButton.Update();
if (reSetButton.clicks > 0) //short click
{
modeChangedByUser = true;
tone1.play(1000, 100);
lcd.clear();
menuPosition = menuPosition + 1;
if (menuPosition == FEDateIndex || FETimeIndex)
lcd.home();
clockFile = SD.open("FEName.txt");
if (clockFile)
{
Serial.println(lcd_buf_1);
while (clockFile.available())
{
lcd.write(clockFile.read());
}
clockFile.close();
}
if (menuPosition == TZoneIndex)
{
stringToDisplay = "041392"; // Info Mode 1 Laura's birthday!
lcd.clear();
lcd.print("Time showing is ");
lcd.print(value[TZoneIndex]);
lcd.setCursor(0, 1);
lcd.print("hours from UCT");
if (dst == true)
{
lcd.setCursor(0, 2);
lcd.print("DST switch enabled");
}
lcd.setCursor(0, 3);
lcd.print("Offset is ");
lcd.print(offSet);
lcd.print(" ");
}
if (menuPosition == TimeHoursIndex) //Info Mode 2 Emma's birthday!
{
stringToDisplay = "041595";
lcd.print("Clock IP Address:");
lcd.setCursor(2, 1);
lcd.print(Ethernet.localIP());
lcd.setCursor(0, 2);
lcd.print("Future Event set to: ");
lcd.setCursor(0, 3);
lcd.print(value[FEHourIndex]);
lcd.print(":");
if (value[FEMinuteIndex] < 10)
{
lcd.print("0");
lcd.print(value[FEMinuteIndex]);
}
else
{
lcd.print(value[FEMinuteIndex]);
}
lcd.print(":");
if (value[FESecondIndex] < 10)
{
lcd.print("0");
lcd.print(value[FESecondIndex]);
}
else
{
lcd.print(value[FESecondIndex]);
}
lcd.print(" ");
lcd.print(value[FEMonthIndex]);
lcd.print("/");
lcd.print(value[FEDayIndex]);
lcd.print("/");
lcd.print("20");
lcd.print(value[FEYearIndex]);
}
if (menuPosition == TimeHoursIndex + 1) menuPosition = TimeIndex;
}
// end display mode cycle on short click of Selector
switch (menuPosition) // defines tube and LCD display first four menuPoistions
{
case TimeIndex: //time mode
if (!transactionInProgress) stringToDisplay = updateDisplayString();
if (secondCount % 2 == 1)
{
digitalWrite(pinUpperDots, HIGH);
digitalWrite(pinLowerDots, HIGH);
}
else
{
digitalWrite(pinUpperDots, LOW);
digitalWrite(pinLowerDots, LOW);
}
lcd.home();
tweetTimeDisplay();
lcd.setCursor(0, 2);
lcd.print(" Local time is ");
lcd.setCursor(9, 3);
digitalClockDisplay();
break;
case DateIndex: //date mode
if (!transactionInProgress) stringToDisplay = updateDateString();
digitalWrite(pinUpperDots, HIGH);
digitalWrite(pinLowerDots, HIGH);
lcd.home();
tweetTimeDisplay();
lcd.setCursor(0, 2);
lcd.print(" Today's Date ");
digitalDateDisplay();
break;
case FETimeIndex:
if (elapsedTimeP.Days != 49710) stringToDisplay = PreZero(elapsedTimeP.Hours) + PreZero(elapsedTimeP.Minutes) + PreZero(elapsedTimeP.Seconds);
else if (!transactionInProgress) stringToDisplay = PreZero("0") + PreZero("0") + PreZero("0");
if (secondCount % 2 == 1)
{
digitalWrite(pinUpperDots, HIGH);
digitalWrite(pinLowerDots, HIGH);
}
else
{
digitalWrite(pinUpperDots, LOW);
digitalWrite(pinLowerDots, LOW);
}
if (elapsedTimeP.Days != 49710)
{
lcd.home();
lcd.print(lcd_buf_1);
lcd.setCursor(0, 1);
lcd.print(" Hrs, Mins & Secs ");
lcd.setCursor(0, 2);
lcd.print(" Time To Go ");
lcd.setCursor(6, 3);
lcd.print(elapsedTimeP.Hours);
lcd.print(":");
if (elapsedTimeP.Minutes < 10)
{
lcd.print('0');
}
lcd.print(elapsedTimeP.Minutes);
lcd.print(":");
if (elapsedTimeP.Seconds < 10)
{
lcd.print('0');
}
lcd.print(elapsedTimeP.Seconds);
}
else
{
lcd.home();
lcd.print(lcd_buf_1);
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 2);
lcd.print(" is over. ");
lcd.setCursor(0, 3);
lcd.print(" ");
}
break;
case FEDateIndex:
if (elapsedTimeP.Days == 49710) // default rollover result when future event reached
stringToDisplay = PreZeroDays("000000");
else
stringToDisplay = (elapsedTimeP.Days);
digitalWrite(pinUpperDots, LOW);
digitalWrite(pinLowerDots, LOW);
if (elapsedTimeP.Days != 49710)
{
lcd.home();
lcd.print(lcd_buf_1);
lcd.setCursor(0, 2);
lcd.print(" Days To Go ");
lcd.setCursor(7, 3);
lcd.print(elapsedTimeP.Days);
}
else
{
lcd.home();
lcd.print(lcd_buf_1);
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 2);
lcd.print(" is over. ");
lcd.setCursor(0, 3);
lcd.print(" ");
}
break;
}
//Web form server code
if (digitalRead(webSwitchPin) == LOW)
{
EthernetClient client = server.available(); // try to get client
if (stateMotion == 1 && millis() - motionIntervalMillis > 5000)
{
timeNow = now();
logEvent(timeNow);
motionIntervalMillis = millis();
}
if (client) // got client?
{
boolean currentLineIsBlank = true;
while (client.connected())
{
if (client.available()) // client data available to read
{
char c = client.read(); // read 1 byte (character) from client
// limit the size of the stored received HTTP request
// buffer first part of HTTP request in HTTP_req array (string)
// leave last element in array as 0 to null terminate string (REQ_BUF_SZ - 1)
if (req_index < (REQ_BUF_SZ - 1))
{
HTTP_req[req_index] = c; // save HTTP request character
req_index++;
}
// last line of client request is blank and ends with \n
// respond to client only after last line received
if (c == '\n' && currentLineIsBlank)
{
// send a standard http response header
client.println("HTTP/1.1 200 OK");
// remainder of header follows below, depending on if
// web page or XML page is requested
// Ajax request - send XML file
if (StrContains(HTTP_req, "ajax_inputs"))
{
// send rest of HTTP header
client.println("Content-Type: text/xml");
client.println("Connection: keep-alive");
client.println();
// print the received text to the LCD if found
if (GetLcdText(lcd_buf_1, lcd_buf_2, LCD_BUF_SZ))
{
// lcd_buf_1 and lcd_buf_2 now contain the text from
// the web page
// write the received text to the LCD
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(lcd_buf_1);
SD.remove("FEName.txt");
clockFile = SD.open("FEName.txt", FILE_WRITE);
if (clockFile)
{
clockFile.println(lcd_buf_1);
clockFile.close();
Serial.println("Done");
}
lcd.setCursor(0, 1);
lcd.print(lcd_buf_2);
}
}
else // web page request -- send rest of HTTP header
{
client.println("Content-Type: text/html");
client.println("Connection: keep-alive");
client.println();
// send web page
webFile = SD.open("index.htm"); // open web page file
if (webFile)
{
while (webFile.available())
{
client.write(webFile.read()); // send web page to client
}
webFile.close();
client.println();
client.print("Last movement detected by Clock: ");
client.print(hour(timeNowUL));
client.print(":");
if ((minute(timeNowUL)) < 10) client.print("0");
client.print(minute(timeNowUL));
client.print(":");
if ((second(timeNowUL)) < 10) client.print("0");
client.print(second(timeNowUL));
client.print(" ");
client.print(month(timeNowUL));
client.print("/");
client.print(day(timeNowUL));
client.print("/");
client.print(year(timeNowUL));
}
}
// reset buffer index and all buffer elements to 0
req_index = 0;
StrClear(HTTP_req, REQ_BUF_SZ);
break;
}
// every line of text received from the client ends with \r\n
if (c == '\n') // last character on line of received text
{
currentLineIsBlank = true; // starting new line with next character read
}
else if (c != '\r') // a text character was received from client
{
currentLineIsBlank = false;
}
} // end if (client.available())
} // end while (client.connected())
delay(1); // give the web browser time to receive the data
client.stop(); // close the connection
} // end if (client)
} // end web server code
}
/***************************************************************************************************************
End Main Loop when not in edit mode (aka new edit mode)
***************************************************************************************************************/
else
{
if (lastSecond != second()) // keeps secondCount going during editing
{
secondCount++;
lastSecond = second();
}
if (digitalRead(newEditModeSwitchPin) == LOW && newEditMode == false)
{
lcd.home();
lcd.print("Edit Settings ");
newEditMode = true;
menuCounter = 0;
if (menuCounter == 0)
{
lcd.setCursor(0, 1);
lcd.print("Press Selector 2secs");
lcd.setCursor(0, 2);
lcd.print("Then turn to adjust");
}
lcd.setCursor(0, 3);
lcd.print("Mode /OFF/ to Exit ");
}
if (digitalRead(newEditModeSwitchPin) == LOW && newEditMode == true)
{
currentTime = millis();
if (currentTime >= (loopTime + 5))
{
// 5ms since last check of encoder = 200Hz
encoder_A = digitalRead(pin_A); // Read encoder pins
encoder_B = digitalRead(pin_B);
reSetButton.Update();
if (reSetButton.clicks < 0) //long click
{
menuCounter ++;
tone1.play(1000, 400);
}
if (menuCounter == 1)
{
lcd.home();
lcd.print("Edit Settings ");
lcd.setCursor(0, 1);
lcd.print("Set time zone ");
lcd.setCursor(0, 2);
lcd.print(value[TZoneIndex]);
lcd.print(" from UCT ");
if ((!encoder_A) && (encoder_A_prev)) // A has gone from high to low
{
if (encoder_B) // B is high so clockwise
{
value[TZoneIndex] = value[TZoneIndex] + 1;
if (value[TZoneIndex] > 12) value[TZoneIndex] = -12;
lcd.setCursor(0, 2);
lcd.print(value[TZoneIndex]);
lcd.print(" ");
}
else
{
value[TZoneIndex] = value[TZoneIndex] - 1;
if (value[TZoneIndex] < -12) value[TZoneIndex] = 12;
lcd.setCursor(0, 2);
lcd.print(value[TZoneIndex]);
lcd.print(" ");
}
}
encoder_A_prev = encoder_A; // Store value of A for next time
loopTime = currentTime; // Updates loopTime
}
if (menuCounter == 2)
{
EEPROM.write(TZoneEEPROMAddress, value[TZoneIndex]); //moving on to next menu item saves prior menu value
lcd.setCursor(0, 1);
lcd.print("Set Future Event Yrs");
lcd.setCursor(0, 2);
lcd.print(value[FEYearIndex]);
lcd.print(" ");
if ((!encoder_A) && (encoder_A_prev))
{
if (encoder_B)
{
value[FEYearIndex] = value[FEYearIndex] + 1;
if (value[FEYearIndex] > 99) value[FEYearIndex] = 0;
lcd.setCursor(0, 2);
lcd.print(value[FEYearIndex]);
}
else
{
value[FEYearIndex] = value[FEYearIndex] - 1;
if (value[FEYearIndex] < 0) value[FEYearIndex] = 99;
lcd.setCursor(0, 2);
lcd.print(value[FEYearIndex]);
}
}
encoder_A_prev = encoder_A; // Store value of A for next time
loopTime = currentTime; // Updates loopTime
}
if (menuCounter == 3)
{
EEPROM.write(FEYearEEPROMAddress, value[FEYearIndex]); //moving on to next mene item saves prior menu value
lcd.setCursor(0, 1);
lcd.print("Set Future Event Mth");
lcd.setCursor(0, 2);
lcd.print(value[FEMonthIndex]);
lcd.print(" ");
if ((!encoder_A) && (encoder_A_prev))
{
if (encoder_B)
{
value[FEMonthIndex] = value[FEMonthIndex] + 1;
if (value[FEMonthIndex] > 12) value[FEMonthIndex] = 1;
lcd.setCursor(0, 2);
lcd.print(value[FEMonthIndex]);
lcd.print(" ");
}
else
{
value[FEMonthIndex] = value[FEMonthIndex] - 1;
if (value[FEMonthIndex] < 1) value[FEMonthIndex] = 12;
lcd.setCursor(0, 2);
lcd.print(value[FEMonthIndex]);
lcd.print(" ");
}
}
encoder_A_prev = encoder_A; // Store value of A for next time
loopTime = currentTime; // Updates loopTime
}
if (menuCounter == 4)
{
EEPROM.write(FEMonthEEPROMAddress, value[FEMonthIndex]); //moving on to next mene item saves prior menu value
lcd.setCursor(0, 1);
lcd.print("Set Future Event Day");
lcd.setCursor(0, 2);
lcd.print(value[FEDayIndex]);
lcd.print(" ");
if ((!encoder_A) && (encoder_A_prev))
{
if (encoder_B)
{
value[FEDayIndex] = value[FEDayIndex] + 1;
if (value[FEDayIndex] > 31) value[FEDayIndex] = 1;
lcd.setCursor(0, 2);
lcd.print(value[FEDayIndex]);
lcd.print(" ");
}
else
{
value[FEDayIndex] = value[FEDayIndex] - 1;
if (value[FEDayIndex] < 1) value[FEDayIndex] = 31;
lcd.setCursor(0, 2);
lcd.print(value[FEDayIndex]);
lcd.print(" ");
}
}
encoder_A_prev = encoder_A; // Store value of A for next time
loopTime = currentTime; // Updates loopTime
}
if (menuCounter == 5)
{
EEPROM.write(FEDayEEPROMAddress, value[FEDayIndex]); //moving on to next mene item saves prior menu value
lcd.setCursor(0, 1);
lcd.print("Set Future Event Hr ");
lcd.setCursor(0, 2);
lcd.print(value[FEHourIndex]);
lcd.print(" ");
if ((!encoder_A) && (encoder_A_prev))
{
if (encoder_B)
{
value[FEHourIndex] = value[FEHourIndex] + 1;
if (value[FEHourIndex] > 23) value[FEHourIndex] = 0;
lcd.setCursor(0, 2);
lcd.print(value[FEHourIndex]);
lcd.print(" ");
}
else
{
value[FEHourIndex] = value[FEHourIndex] - 1;
if (value[FEHourIndex] < 0) value[FEHourIndex] = 23;
lcd.setCursor(0, 2);
lcd.print(value[FEHourIndex]);
lcd.print(" ");
}
}
encoder_A_prev = encoder_A; // Store value of A for next time
loopTime = currentTime; // Updates loopTime
}
if (menuCounter == 6)
{
EEPROM.write(FEHourEEPROMAddress, value[FEHourIndex]); //moving on to next mene item saves prior menu value
lcd.setCursor(0, 1);
lcd.print("Set Future Event Min");
lcd.setCursor(0, 2);
lcd.print(value[FEMinuteIndex]);
lcd.print(" ");
if ((!encoder_A) && (encoder_A_prev))
{
if (encoder_B)
{
value[FEMinuteIndex] = value[FEMinuteIndex] + 1;
if (value[FEMinuteIndex] > 59) value[FEMinuteIndex] = 0;
lcd.setCursor(0, 2);
lcd.print(value[FEMinuteIndex]);
lcd.print(" ");
}
else
{
value[FEMinuteIndex] = value[FEMinuteIndex] - 1;
if (value[FEMinuteIndex] < 0) value[FEMinuteIndex] = 59;
lcd.setCursor(0, 2);
lcd.print(value[FEMinuteIndex]);
lcd.print(" ");
}
}
encoder_A_prev = encoder_A; // Store value of A for next time
loopTime = currentTime; // Updates loopTime
}
if (menuCounter == 7)
{
EEPROM.write(FEMinuteEEPROMAddress, value[FEMinuteIndex]); //moving on to next mene item saves prior menu value
lcd.setCursor(0, 1);
lcd.print("Set Future Event Sec");
lcd.setCursor(0, 2);
lcd.print(value[FESecondIndex]);
lcd.print(" ");
if ((!encoder_A) && (encoder_A_prev))
{
if (encoder_B)
{
value[FESecondIndex] = value[FESecondIndex] + 1;
if (value[FESecondIndex] > 59) value[FESecondIndex] = 0;
lcd.setCursor(0, 2);
lcd.print(value[FEDayIndex]);
lcd.print(" ");
}
else
{
value[FESecondIndex] = value[FESecondIndex] - 1;
if (value[FESecondIndex] < 0) value[FESecondIndex] = 59;
lcd.setCursor(0, 2);
lcd.print(value[FESecondIndex]);
lcd.print(" ");
}
}
encoder_A_prev = encoder_A; // Store value of A for next time
loopTime = currentTime; // Updates loopTime
}
if (menuCounter == 8)
{
EEPROM.write(FESecondEEPROMAddress, value[FESecondIndex]); //moving on to next mene item saves prior menu value
lcd.setCursor(0, 1);
lcd.print("Set time zone offset");
lcd.setCursor(0, 2);
lcd.print(offSet);
lcd.print(" vs local time ");
if ((!encoder_A) && (encoder_A_prev))
{
if (encoder_B)
{
offSet = offSet + 1;
if (offSet > 12) offSet = -12;
lcd.setCursor(0, 2);
lcd.print(offSet);
}
else
{
offSet = offSet - 1;
if (offSet < -12) offSet = 12;
lcd.setCursor(0, 2);
lcd.print(offSet);
}
}
encoder_A_prev = encoder_A; // Store value of A for next time
loopTime = currentTime; // Updates loopTime
}
if (menuCounter == 9)
{
EEPROM.write(offSetEEPROMAddress, offSet);
lcd.setCursor(0, 0);
lcd.print("Web /ON/ then ");
lcd.setCursor(0, 1);
lcd.print("go to ");
lcd.print(Ethernet.localIP());
lcd.setCursor(0, 2);
lcd.print("to change event name");
}
if (menuCounter == 10)
{
menuCounter = 0;
}
}
}
} // end edit mode code
}
/***************************************************************************************************************
End Main Loop
***************************************************************************************************************/
String PreZero(int digit)
{
if (digit < 10) return String("0") + String(digit);
else return String(digit);
}
String PreZeroDays(int digit) //LEADING ZEROS FOR DAYS TO GO DISPLAY
{
if (digit < 10) return "00000" + String(digit);
if (digit >= 10)
{
if (digit < 100) return "0000" + String(digit);
}
if (digit >= 100)
{
if (digit < 1000) return "000" + String(digit);
}
if (digit >= 1000)
{
if (digit < 10000) return "00" + String(digit);
}
if (digit >= 10000)
{
if (digit < 100000) return "0" + String(digit);
}
else return String(digit);
}
void doIndication()
{
static unsigned long lastTimeInterval1Started;
if ((micros() - lastTimeInterval1Started) < fpsLimit) return;
//if (menuPosition==TimeIndex || menuPosition == FETimeIndex) doDotBlink();
lastTimeInterval1Started = micros();
digitalWrite(LEpin, LOW); // allow data input
unsigned long long Var64 = 0;
unsigned long long tmpVar64 = 0;
long digits = stringToDisplay.toInt();
Var64 = ~Var64;
tmpVar64 = ~tmpVar64;
Var64 = Var64 & ((SymbolArray[digits % 10]) << 6);
Var64 = Var64 << 48;
digits = digits / 10;
tmpVar64 = (SymbolArray[digits % 10]) << 6;
Var64 |= (tmpVar64 << 38);
digits = digits / 10;
tmpVar64 = (SymbolArray[digits % 10]) << 6;
Var64 |= (tmpVar64 << 28);
digits = digits / 10;
tmpVar64 = (SymbolArray[digits % 10]) << 6;
Var64 |= (tmpVar64 << 18);
digits = digits / 10;
tmpVar64 = (SymbolArray[digits % 10]) << 6;
Var64 |= (tmpVar64 << 8);
digits = digits / 10;
tmpVar64 = (SymbolArray[digits % 10]) << 6>>2;
Var64 |= tmpVar64;
Var64 = (Var64 >> 4);
unsigned int iTmp = 0;
iTmp = Var64 >> 56;
SPI.transfer(iTmp);
iTmp = Var64 >> 48;
SPI.transfer(iTmp);
iTmp = Var64 >> 40;
SPI.transfer(iTmp);
iTmp = Var64 >> 32;
SPI.transfer(iTmp);
iTmp = Var64 >> 24;
SPI.transfer(iTmp);
iTmp = Var64 >> 16;
SPI.transfer(iTmp);
iTmp = Var64 >> 8;
SPI.transfer(iTmp);
iTmp = Var64;
SPI.transfer(iTmp);
digitalWrite(LEpin, HIGH); // allow data input (Transparent mode)
digitalWrite(LEpin, LOW); // latching data
}
String updateDisplayString()
{
static unsigned long lastTimeStringWasUpdated;
if ((millis() - lastTimeStringWasUpdated) > 1000)
{
lastTimeStringWasUpdated = millis();
if (digitalRead(twelveHrSwitchPin) == HIGH) return PreZero(hour()) + PreZero(minute()) + PreZero(second());
else return PreZero(hourFormat12()) + PreZero(minute()) + PreZero(second());
return getTimeNow();
}
return stringToDisplay;
}
String updateDateString()
{
static unsigned long lastTimeDateUpdate = millis();
static String DateString = PreZero(day()) + PreZero(month()) + PreZero(year() % 1000);
if ((millis() - lastTimeDateUpdate) > 1000)
{
lastTimeDateUpdate = millis();
DateString = PreZero(month()) + PreZero(day()) + PreZero(year() % 1000);
}
return DateString;
}
String getTimeNow()
{
return PreZero(hour()) + PreZero(minute()) + PreZero(second());
}
void doTest()
{
Serial.print(F("Firmware version: "));
Serial.println(FirmwareVersion.substring(1, 2) + "." + FirmwareVersion.substring(2, 4));
Serial.println(F("Start Test"));
int adc = analogRead(A3);
float Uinput = 4.6 * (5.0 * adc) / 1024.0 + 0.7;
Serial.print(F("U input="));
Serial.print(Uinput);
analogWrite(RedLedPin, 255);
delay(1000);
analogWrite(RedLedPin, 0);
analogWrite(GreenLedPin, 255);
delay(1000);
analogWrite(GreenLedPin, 0);
analogWrite(BlueLedPin, 255);
delay(1000);
String testStringArray[12] = {"000000", "111111", "222222", "333333", "444444", "555555", "666666", "777777", "888888", "999999", "", ""};
if (Uinput < 10) testStringArray[10] = "000" + String(int(Uinput * 100)); else testStringArray[10] = "00" + String(int(Uinput * 100));
testStringArray[11] = FirmwareVersion;
int dlay = 500;
bool test = 1;
byte strIndex = -1;
unsigned long startOfTest = millis();
digitalWrite(DHVpin, HIGH);
bool digitsLock = false;
while (test)
{
if (digitalRead(pinReSet) == 0) digitsLock = true;
for (int i = 0; i < 12; i++)
{
if ((millis() - startOfTest) > dlay)
{
startOfTest = millis();
if (!digitsLock) strIndex = strIndex + 1;
if (strIndex == 10) dlay = 3000;
if (strIndex == 12) test = 0;
stringToDisplay = testStringArray[strIndex];
long digits = stringToDisplay.toInt();
unsigned long long Var64 = 0;
unsigned long long tmpVar64 = 0;
Var64 = ~Var64;
tmpVar64 = ~tmpVar64;
Var64 = Var64 & ((SymbolArray[digits % 10]) << 6);
Var64 = Var64 << 48;
digits = digits / 10;
tmpVar64 = (SymbolArray[digits % 10]) << 6;
Var64 |= (tmpVar64 << 38);
digits = digits / 10;
tmpVar64 = (SymbolArray[digits % 10]) << 6;
Var64 |= (tmpVar64 << 28);
digits = digits / 10;
tmpVar64 = (SymbolArray[digits % 10]) << 6;
Var64 |= (tmpVar64 << 18);
digits = digits / 10;
tmpVar64 = (SymbolArray[digits % 10]) << 6;
Var64 |= (tmpVar64 << 8);
digits = digits / 10;
tmpVar64 = (SymbolArray[digits % 10]) << 6>>2;
Var64 |= tmpVar64;
Var64 = (Var64 >> 4);
unsigned int iTmp = 0;
digitalWrite(LEpin, HIGH); // allow data input (Transparent mode)
iTmp = Var64 >> 56;
SPI.transfer(iTmp);
iTmp = Var64 >> 48;
SPI.transfer(iTmp);
iTmp = Var64 >> 40;
SPI.transfer(iTmp);
iTmp = Var64 >> 32;
SPI.transfer(iTmp);
iTmp = Var64 >> 24;
SPI.transfer(iTmp);
iTmp = Var64 >> 16;
SPI.transfer(iTmp);
iTmp = Var64 >> 8;
SPI.transfer(iTmp);
iTmp = Var64;
SPI.transfer(iTmp);
digitalWrite(LEpin, LOW); // latching data
}
}
delayMicroseconds(2000);
};
Serial.println(F("Stop Test"));
}
byte decToBcd(byte val) {
// Convert normal decimal numbers to binary coded decimal
return ( (val / 10 * 16) + (val % 10) );
}
byte bcdToDec(byte val) {
// Convert binary coded decimal to normal decimal numbers
return ( (val / 16 * 10) + (val % 16) );
}
bool isValidDate() //Not used
{
int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (value[DateYearIndex] % 4 == 0) days[1] = 29;
if (value[DateDayIndex] > days[value[DateMonthIndex] - 1]) return false;
else return true;
}
void digitalClockDisplay()
{
if (digitalRead(twelveHrSwitchPin) == LOW)
{
lcd.print(hourFormat12());
}
else
{
lcd.print(hour());
}
printDigits(minute());
printDigits(second());
if (digitalRead(twelveHrSwitchPin) == LOW)
{
if (isAM())
{
lcd.print(" AM");
}
else
{
lcd.print(" PM");
}
}
else
{
lcd.print(" ");
}
}
void printDigits(int digits) // utility for digital clock display: prints preceding colon and leading 0
{
lcd.print(":");
if (digits < 10)
lcd.print('0');
lcd.print(digits);
}
/*-------- NTP code ----------*/
const int NTP_PACKET_SIZE = 48; // NTP time is in the first 48 bytes of message
byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets
time_t getNtpTime()
{
bool server1 = true;
bool server2 = true;
bool server3 = true;
while (Udp.parsePacket() > 0) ; // discard any previously received packets
Serial.println("Transmit NTP Request");
sendNTPpacket(timeServer1);
uint32_t beginWait1 = millis();
while (millis() - beginWait1 < 1500) {
int size = Udp.parsePacket();
if (size >= NTP_PACKET_SIZE) {
Serial.println("Receive NTP Response");
Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
unsigned long secsSince1900;
// convert four bytes starting at location 40 to a long integer
secsSince1900 = (unsigned long)packetBuffer[40] << 24;
secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
secsSince1900 |= (unsigned long)packetBuffer[43];
return secsSince1900 - 2208988800UL + (value[TZoneIndex]) * SECS_PER_HOUR;
}
}
Serial.println("No NTP Response from Server1");
//return 0; // return 0 if unable to get the time
server1 = false;
if (server1 == false) {
while (Udp.parsePacket() > 0) ; // discard any previously received packets
Serial.println("Transmit NTP Request");
sendNTPpacket(timeServer2);
uint32_t beginWait2 = millis();
while (millis() - beginWait2 < 1500) {
int size = Udp.parsePacket();
if (size >= NTP_PACKET_SIZE) {
Serial.println("Receive NTP Response");
Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
unsigned long secsSince1900;
// convert four bytes starting at location 40 to a long integer
secsSince1900 = (unsigned long)packetBuffer[40] << 24;
secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
secsSince1900 |= (unsigned long)packetBuffer[43];
return secsSince1900 - 2208988800UL + (value[TZoneIndex]) * SECS_PER_HOUR;
}
}
Serial.println("No NTP Response from Server2");
//return 0; // return 0 if unable to get the time
server2 = false;
}
if (server2 == false) {
while (Udp.parsePacket() > 0) ; // discard any previously received packets
Serial.println("Transmit NTP Request");
sendNTPpacket(timeServer3);
uint32_t beginWait3 = millis();
while (millis() - beginWait3 < 1500) {
int size = Udp.parsePacket();
if (size >= NTP_PACKET_SIZE) {
Serial.println("Receive NTP Response");
Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
unsigned long secsSince1900;
// convert four bytes starting at location 40 to a long integer
secsSince1900 = (unsigned long)packetBuffer[40] << 24;
secsSince1900 |= (unsigned long)packetBuffer[41] << 16;
secsSince1900 |= (unsigned long)packetBuffer[42] << 8;
secsSince1900 |= (unsigned long)packetBuffer[43];
return secsSince1900 - 2208988800UL + (value[TZoneIndex]) * SECS_PER_HOUR;
}
}
Serial.println("No NTP Response from Server3");
return 0; // return 0 if unable to get the time
server3 = false;
}
}
// send an NTP request to the time server at the given address
void sendNTPpacket(IPAddress &address)
{
// set all bytes in the buffer to 0
memset(packetBuffer, 0, NTP_PACKET_SIZE);
// Initialize values needed to form NTP request
// (see URL above for details on the packets)
packetBuffer[0] = 0b11100011; // LI, Version, Mode
packetBuffer[1] = 0; // Stratum, or type of clock
packetBuffer[2] = 6; // Polling Interval
packetBuffer[3] = 0xEC; // Peer Clock Precision
// 8 bytes of zero for Root Delay & Root Dispersion
packetBuffer[12] = 49;
packetBuffer[13] = 0x4E;
packetBuffer[14] = 49;
packetBuffer[15] = 52;
// all NTP fields have been given values, now
// you can send a packet requesting a timestamp:
Udp.beginPacket(address, 123); //NTP requests are to port 123
Udp.write(packetBuffer, NTP_PACKET_SIZE);
Udp.endPacket();
}
void send_twitter_timeToGo()
{
tmElements_t time1 = {second(), minute(), hour(), 0, day(), month(), CalendarYrToTm(year())}, // Current time and date
time2 = {0, 0, 12, 0, 20, 1, CalendarYrToTm(2021)}; // Time to go (Trump)
uint32_t differenceP = (uint32_t)(makeTime(time2) - makeTime(time1));
struct elapsedTime_tP {
uint8_t Seconds, Minutes, Hours;
uint16_t Days;
} elapsedTimeP;
elapsedTimeP.Seconds = differenceP % 60;
differenceP /= 60; // now it is minutes
elapsedTimeP.Minutes = differenceP % 60;
differenceP /= 60; // now it is hours
elapsedTimeP.Hours = differenceP % 24;
differenceP /= 24; // now it is days
elapsedTimeP.Days = differenceP;
char buf[64];
sprintf(buf, "Elapsed time = %d days, %d hours, %d minutes, %d seconds.\r\n",
elapsedTimeP.Days, elapsedTimeP.Hours, elapsedTimeP.Minutes, elapsedTimeP.Seconds);
temp[10] = NULL;
clockSpeak = "Just ";
clockSpeak.concat(elapsedTimeP.Days);
if (elapsedTimeP.Days == 1)
{
clockSpeak.concat(" day, ");
}
else
{
clockSpeak.concat(" days, ");
}
{
clockSpeak.concat(elapsedTimeP.Hours);
}
if (elapsedTimeP.Hours == 1)
{
clockSpeak.concat(" hour, ");
}
else
{
clockSpeak.concat(" hours, ");
}
clockSpeak.concat(elapsedTimeP.Minutes);
if (elapsedTimeP.Minutes == 1)
{
clockSpeak.concat(" minute and ");
}
else
{
clockSpeak.concat(" minutes and ");
}
clockSpeak.concat(elapsedTimeP.Seconds);
if (elapsedTimeP.Seconds == 1)
{
clockSpeak.concat(" second to ");
}
else
{
clockSpeak.concat(" seconds to ");
}
clockSpeak.concat("#MakeAmericaGreatAgain");
twitter_send(); //call send function
}
void twitter_send() {
if (tweet) {
char charBuf[140];
clockSpeak.toCharArray(charBuf, 140);
Serial.println(F("Preparing to tweet message:"));
Serial.println(charBuf);
if (twitter.post(charBuf)) {
int status = twitter.wait();
if (status == 200) {
Serial.println(F("The tweet was sent!"));
lcd.setCursor(0, 0);
lcd.print("Tweeted at: ");
digitalClockDisplay();
tweetSent = true;
}
else {
Serial.print(F("Tweet failed : code "));
Serial.println(status);
lcd.home();
lcd.print("Tweet failed to send");
}
}
else {
Serial.println(F("connection failed."));
}
Serial.println();
}
clockSpeak = "";
}
void tweetSet()
{
tweetTime = random(86400); //seconds in day
secondCount = 1; //(function called at 00:00:01)
Serial.print("New tweet time = ");
Serial.println(tweetTime);
tweetSent = false;
}
void modesChanger()
{
static unsigned long lastTimeModeChanged = millis();
static unsigned long lastTimeAntiPoisoningIterate = millis();
if ((millis() - lastTimeModeChanged) > modesChangePeriod)
{
lastTimeModeChanged = millis();
if (menuPosition == TimeIndex)
{
clearLines();
menuPosition = DateIndex;
modesChangePeriod = dateModePeriod;
}
else if (menuPosition == DateIndex)
{
clearLines();
clockFile = SD.open("FEName.txt");
if (clockFile)
{
Serial.println(lcd_buf_1);
while (clockFile.available())
{
lcd.write(clockFile.read());
}
clockFile.close();
}
menuPosition = FEDateIndex;
modesChangePeriod = dateModePeriod;
}
else if (menuPosition == FEDateIndex)
{
clearLines();
clockFile = SD.open("FEName.txt");
if (clockFile)
{
Serial.println(lcd_buf_1);
while (clockFile.available())
{
lcd.write(clockFile.read());
}
clockFile.close();
}
menuPosition = FETimeIndex;
modesChangePeriod = timeModePeriod;
}
else
{
clearLines();
menuPosition = TimeIndex;
modesChangePeriod = timeModePeriod;
}
if (modeChangedByUser == true) menuPosition = TimeIndex;
modeChangedByUser = false;
}
if ((millis() - lastTimeModeChanged) < 2000)
{
if ((millis() - lastTimeAntiPoisoningIterate) > 100)
{
lastTimeAntiPoisoningIterate = millis();
if (menuPosition == TimeIndex) stringToDisplay = antiPoisoning2(PreZero(day()) + PreZero(month()) + PreZero(year() % 1000), getTimeNow());
}
} else transactionInProgress = false;
}
String antiPoisoning2(String fromStr, String toStr)
{
//static bool transactionInProgress=false;
//byte fromDigits[6];
static byte toDigits[6];
static byte currentDigits[6];
static byte iterationCounter = 0;
if (!transactionInProgress)
{
transactionInProgress = true;
for (int i = 0; i < 6; i++)
{
currentDigits[i] = fromStr.substring(i, i + 1).toInt();
toDigits[i] = toStr.substring(i, i + 1).toInt();
}
}
for (int i = 0; i < 6; i++)
{
if (iterationCounter < 10) currentDigits[i]++;
else if (currentDigits[i] != toDigits[i]) currentDigits[i]++;
if (currentDigits[i] == 10) currentDigits[i] = 0;
}
iterationCounter++;
if (iterationCounter == 20)
{
iterationCounter = 0;
transactionInProgress = false;
}
String tmpStr;
for (int i = 0; i < 6; i++)
tmpStr += currentDigits[i];
return tmpStr;
}
//Page handler for web form
// get the two strings for the LCD from the incoming HTTP GET request
boolean GetLcdText(char *line1, char *line2, int len)
{
boolean got_text = false; // text received flag
char *str_begin; // pointer to start of text
char *str_end; // pointer to end of text
int str_len = 0;
int txt_index = 0;
char *current_line;
current_line = line1;
// get pointer to the beginning of the text
str_begin = strstr(HTTP_req, "&L1=");
for (int j = 0; j < 2; j++) { // do for 2 lines of text
if (str_begin != NULL) {
str_begin = strstr(str_begin, "="); // skip to the =
str_begin += 1; // skip over the =
str_end = strstr(str_begin, "&");
if (str_end != NULL) {
str_end[0] = 0; // terminate the string
str_len = strlen(str_begin);
// copy the string to the buffer and replace %20 with space ' '
for (int i = 0; i < str_len; i++) {
if (str_begin[i] != '%') {
if (str_begin[i] == 0) {
// end of string
break;
}
else {
current_line[txt_index++] = str_begin[i];
if (txt_index >= (len - 1)) {
// keep the output string within bounds
break;
}
}
}
else {
// replace %20 with a space
if ((str_begin[i + 1] == '2') && (str_begin[i + 2] == '0')) {
current_line[txt_index++] = ' ';
i += 2;
if (txt_index >= (len - 1)) {
// keep the output string within bounds
break;
}
}
}
} // end for i loop
// terminate the string
current_line[txt_index] = 0;
if (j == 0) {
// got first line of text, now get second line
str_begin = strstr(&str_end[1], "L2=");
current_line = line2;
txt_index = 0;
}
got_text = true;
}
}
} // end for j loop
return got_text;
}
// sets every element of str to 0 (clears array)
void StrClear(char *str, char length)
{
for (int i = 0; i < length; i++) {
str[i] = 0;
}
}
// searches for the string sfind in the string str
// returns 1 if string found
// returns 0 if string not found
char StrContains(char *str, char *sfind)
{
char found = 0;
char index = 0;
char len;
len = strlen(str);
if (strlen(sfind) > len) {
return 0;
}
while (index < len) {
if (str[index] == sfind[found]) {
found++;
if (strlen(sfind) == found) {
return 1;
}
}
else {
found = 0;
}
index++;
}
return 0;
}
void digitalDateDisplay() // digital clock display of the time
{
lcd.setCursor(10, 3);
if (month() < 10) {
lcd.print("0");
}
lcd.print(month());
printDateDigits(day());
printDateDigits(year());
}
void printDateDigits(int digits) // utility for digital date display: prints preceding slash and leading 0
{
lcd.print("/");
if (digits < 10)
lcd.print('0');
lcd.print(digits);
}
void tweetTimeDisplay()
{
lcd.setCursor(0, 0);
int tweetTimeS = tweetTime % 60;
int tweetTimeMTot = tweetTime / 60;
int tweetTimeM = tweetTimeMTot % 60;
int tweetTimeH = tweetTimeMTot / 60;
if (tweetSent == false)
{
lcd.print("Tweeting at ");
}
else
{
lcd.print("Tweeted at ");
}
if (tweetTimeH < 10)
{
lcd.print("0");
lcd.print(tweetTimeH);
lcd.print(":");
}
else
{
lcd.print(tweetTimeH);
lcd.print(":");
}
if (tweetTimeM < 10)
{
lcd.print("0");
lcd.print(tweetTimeM);
lcd.print(":");
}
else
{
lcd.print(tweetTimeM);
lcd.print(":");
}
if (tweetTimeS < 10)
{
lcd.print("0");
lcd.print(tweetTimeS);
}
else
{
lcd.print(tweetTimeS);
}
}
void clearLines()
{
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 2);
lcd.print(" ");
lcd.setCursor(0, 3);
lcd.print(" ");
}
void logEvent(time_t timeNow)
{
Serial.print("Last movement detected by Clock: ");
showTime(timeNow);
Serial.println();
}
void showTime(time_t timeNow)
{
Serial.print(hour(timeNow));
Serial.print(":");
if ((minute(timeNow)) < 10) Serial.print("0");
Serial.print(minute(timeNow));
Serial.print(":");
if ((second(timeNow)) < 10) Serial.print("0");
Serial.print(second(timeNow));
Serial.print(" ");
Serial.print(day(timeNow));
Serial.print("/");
Serial.print(month(timeNow));
Serial.print("/");
Serial.print(year(timeNow));
}
[/code]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment