-
-
Save seasider1960/f608ce29da70cf11607c6dbb8ddaf0f8 to your computer and use it in GitHub Desktop.
Trump TTG Clock Code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[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("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