//////////////////////////////////////////////////////////////////////////////// //(c) 2013-2016, Roman Stec // Last modified: 10-Oct-2016 // HARDWARE: // Arduino Mega R3 - mandatory // Arduino Uno - can be used but with too many limitations - not recommended // Arduino Micro Pro - can be used but with too many limitations - not recommended // Arduino Nano - can be used but with too many limitations - not recommended // RTC DS3231 - mandatory // Ethernet Shield R3 - optional // ENC28J60 can be used but with huge amount of limitations - absolutely not recommended // TFT 1.8" ST7735 - optional // paralel or serial LCD 16x2 - optional // UART TTL to RS232C converter (attached to Serial1 - TX1 + RX1) - optional // 2x TMP36 - optional (attached to A2, A3) // 2x PIR - optional (attached to A0, A1) //------------------------------------------------------------------------------ // I2C Serial LCD note: // SAINSMART_I2C_16x2_IS_PRESENT: // SainSmart IIC/I2C/TWI Serial LCD Module Shield // http://www.sainsmart.com/sainsmart-iic-i2c-twi-serial-2004-20x4-lcd-module-shield-for-arduino-uno-mega-r3.html // MJKDZ_I2C_16x2_IS_PRESENT: // MJKDZ IIC/I2C/TWI/SPI Serial Interface Board For LCD Display // http://www.mjkdz.com/forum.php?mod=viewthread&tid=2&highlight=I2C%2B1602 //------------------------------------------------------------------------------ //I have several different Arduinos and the next lines define, for which Arduino I decided to compile a project - uncomment only one line!!! //Inspect next section for specific hardware configuration #define NUMBER0 //#define NUMBER1 //#define NUMBER2 //#define NUMBER3 //#define NUMBER4 //#define NUMBER9 //#define ARDUINONANO //#define ARDUINOMICROPRO //#define ARDUINOUNO /* uncomment next line if two TMP36 are connected */ //#define TMP36_IS_PRESENT /* uncomment next line if updating time in the RTC chip is allowed or comment out next line if updating time in the RTC chip is disallowed */ //#define ENABLE_RTC_UPDATE //////////////////////////////////////////////////////////////////////////////// //#include #include //Library Time.zip downloaded from http://www.pjrc.com/teensy/td_libs_Time.html #include #include //////////////////////////////////////////////////////////////////////////////// //---- *** COM3 Arduino Mega 2560 R3 #0 *** --------------- #if defined(NUMBER0) #define ETHERNET_IS_PRESENT #define DHCP_RETRY_PERIOD 300 //#define PIR_IS_PRESENT //#define LCD16x2_IS_PRESENT #define SAINSMART_I2C_16x2_IS_PRESENT //#define MJKDZ_I2C_16x2_IS_PRESENT #define LCD_UPDATE_PERIOD 1 #endif //---- *** COM4 Arduino Mega 2560 R3 #1 + Ethernet Shield R3 *** --------------- #if defined(NUMBER1) #define ETHERNET_IS_PRESENT #define DHCP_RETRY_PERIOD 300 #define ADAFRUIT_ST7735_IS_PRESENT #define LCD_UPDATE_PERIOD 1 #endif //---- *** COM5 Arduino Mega 2560 R3 #2 + Ethernet Shield R3 *** --------------- #if defined(NUMBER2) #define ETHERNET_IS_PRESENT #define DHCP_RETRY_PERIOD 300 #define SAINSMART_I2C_16x2_IS_PRESENT #define LCD_UPDATE_PERIOD 1 #endif //---- *** COM6 Arduino Mega 2560 R3 #3 + Ethernet Shield R3 *** --------------- #if defined(NUMBER3) #define ETHERNET_IS_PRESENT #define DHCP_RETRY_PERIOD 300 #define ADAFRUIT_ST7735_IS_PRESENT #define LCD_UPDATE_PERIOD 1 //#define SECOND_SERIAL_IS_PRESENT #endif //---- *** COM7 Arduino Mega 2560 R3 #4 *** --------------- #if defined(NUMBER4) #define ETHERNET_IS_PRESENT #define DHCP_RETRY_PERIOD 300 #define MJKDZ_I2C_16x2_IS_PRESENT #define LCD_UPDATE_PERIOD 1 #endif //---- *** COM8 Arduino DUE R3 #1 *** --------------- #if defined(NUMBER8) #define DHCP_RETRY_PERIOD 60 #define LCD_UPDATE_PERIOD 1 #endif //---- *** COM9 Arduino Mega 2560 R3 #1 + Ethernet Shield R3 (EtherMega) *** --- #if defined(NUMBER9) #define ETHERNET_IS_PRESENT #define DHCP_RETRY_PERIOD 300 #define LCD_UPDATE_PERIOD 1 #define SAINSMART_I2C_16x2_IS_PRESENT #endif //---- *** COM13 Arduino Nano V3.0 #1 *** --------------- #if defined(ARDUINONANO) #define ENC28J60_IS_PRESENT #define DHCP_RETRY_PERIOD 300 #define LCD_UPDATE_PERIOD 1 #endif //---- *** COM14 Arduino Micro Pro #1 *** --------------- #if defined(ARDUINOMICROPRO) #define ENC28J60_IS_PRESENT #define DHCP_RETRY_PERIOD 300 #define LCD_UPDATE_PERIOD 1 #endif //---- *** COM15 Arduino Uno R3 #1 + Ethernet Shield R3 *** --------------- #if defined(ARDUINOUNO) #define ETHERNET_IS_PRESENT #define DHCP_RETRY_PERIOD 300 #define LCD_UPDATE_PERIOD 1 #endif //////////////////////////////////////////////////////////////////////////////// #if defined(ETHERNET_IS_PRESENT) #include #include #endif #if defined(ENC28J60_IS_PRESENT) #include #include #include "ethernet_comp.h" #include #include "Dhcp.h" #include "IPAddress.h" #include "utility/Enc28J60Network.h" #include "UIPClient.h" #include "UIPServer.h" #include "UIPUdp.h" #endif //////////////////////////////////////////////////////////////////////////////// #if defined(ETHERNET_IS_PRESENT) or defined(ENC28J60_IS_PRESENT) // Find the nearest server // http://www.pool.ntp.org/zone/ // or // http://support.ntp.org/bin/view/Servers/StratumTwoTimeServers // IPAddress timeServer(192, 43, 244, 18); // time.nist.gov NTP server // IPAddress timeServer(193, 79, 237, 14); // ntp1.nl.net NTP server // IPAddress timeServer(132, 163, 4, 101); // time-a.timefreq.bldrdoc.gov // IPAddress timeServer(132, 163, 4, 102); // time-b.timefreq.bldrdoc.gov // IPAddress timeServer(132, 163, 4, 103); // time-c.timefreq.bldrdoc.gov // IPAddress timeServer(195, 113, 144, 201);// tik.cesnet.cz // IPAddress timeServer(195, 113, 144, 238);// tak.cesnet.cz // IPAddress timeServer(195, 113, 144, 201);// ntp.cesnet.cz // IPAddress timeServer(147, 251, 48, 140); // 0.cz.pool.ntp.org // IPAddress timeServer(93, 185, 101, 77); // ntp.ipv4.cz IPAddress timeServer(217, 31, 202, 100); // ntp.nic.cz // IPAddress timeServer(10,102,77,71); // local time server //////////////////////////////////////////////////////////////////////////////// EthernetUDP Udp; #define LOCALUDPPORT 8888 #define SDCARDPin 4 bool fixedipenabled = false; #endif //------------------------------------------------------------------------------ #define NTP_CHECK_PERIOD 3600 #define NTP_RETRY_CHECK_PERIOD 60 #define REPORTDS_TIME_PERIOD 60 volatile bool ntp_interrupt_in_progress = false; volatile bool NTPworking = false; volatile bool NTPsetstime = false; volatile bool NTPasked = false; //////////////////////////////////////////////////////////////////////////////// #if defined(NUMBER0) and defined(ETHERNET_IS_PRESENT) byte MACAddress[6] = { // 0x90, 0xA2, 0xDA, 0x0D, 0xFE, 0x93 }; 0x4C, 0x72, 0xB9, 0x02, 0x61, 0x93 }; #endif #if defined(NUMBER1) and defined(ETHERNET_IS_PRESENT) byte MACAddress[6] = { 0x90, 0xA2, 0xDA, 0x0D, 0xFE, 0x94 }; #endif #if defined(NUMBER2) and defined(ETHERNET_IS_PRESENT) byte MACAddress[6] = { 0x90, 0xA2, 0xDA, 0x0D, 0xFE, 0x95 }; #endif #if defined(NUMBER3) and defined(ETHERNET_IS_PRESENT) byte MACAddress[6] = { 0x90, 0xA2, 0xDA, 0x0D, 0xFE, 0x96 }; #endif #if defined(NUMBER4) and defined(ETHERNET_IS_PRESENT) byte MACAddress[6] = { 0x90, 0xA2, 0xDA, 0x0D, 0xFE, 0x97 }; #endif #if defined(NUMBER5) and defined(ETHERNET_IS_PRESENT) #endif #if defined(NUMBER6) and defined(ETHERNET_IS_PRESENT) #endif #if defined(NUMBER7) and defined(ETHERNET_IS_PRESENT) #endif #if defined(NUMBER8) and defined(ETHERNET_IS_PRESENT) byte MACAddress[6] = { 0x90, 0xA2, 0xDA, 0x0D, 0xFE, 0x97 }; #endif #if defined(NUMBER9) and defined(ETHERNET_IS_PRESENT) byte MACAddress[6] = { 0x90, 0xA2, 0xDA, 0x0D, 0xFE, 0x99 }; #endif #if defined(ARDUINONANO) and defined(ENC28J60_IS_PRESENT) byte MACAddress[6] = { 0x90, 0xA2, 0xDA, 0x0D, 0xFE, 0x9A }; #endif #if defined(ARDUINOUNO) and defined(ETHERNET_IS_PRESENT) byte MACAddress[6] = { 0x90, 0xA2, 0xDA, 0x0D, 0xFE, 0x98 }; #endif //////////////////////////////////////////////////////////////////////////////// #if defined(LCD16x2_IS_PRESENT) #define LCD_IS_PRESENT #include #include LiquidCrystal lcd(8, 13, 9, 4, 5, 6, 7); #endif //////////////////////////////////////////////////////////////////////////////// #if defined(SAINSMART_I2C_16x2_IS_PRESENT) #define LCD_IS_PRESENT #include #include #define I2C_ADDR 0x27 // define your I2C address of PCF8574A #define BACKLIGHT_PIN 3 #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, BACKLIGHT_PIN, POSITIVE); #endif #if defined(MJKDZ_I2C_16x2_IS_PRESENT) #define LCD_IS_PRESENT #include #include #define I2C_ADDR 0x20 // define your I2C address of PCF8574x #define BACKLIGHT_PIN 7 #define En_pin 4 #define Rw_pin 5 #define Rs_pin 6 #define D4_pin 0 #define D5_pin 1 #define D6_pin 2 #define D7_pin 3 LiquidCrystal_I2C lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin, BACKLIGHT_PIN, NEGATIVE); #endif //////////////////////////////////////////////////////////////////////////////// #if defined(ADAFRUIT_ST7735_IS_PRESENT) #if defined(__AVR_ATmega2560__) #define cs 53 //CS #define sclk 52 //SCK #define mosi 51 //SDA #define dc 49 //A0 #define rst 48 #endif #if defined(__AVR_ATmega328P__) #define cs 10 //CS #define sclk 13 //SCK #define mosi 11 //SDA #define dc 9 //A0 #define rst 8 //RESET #endif //------------------------------------------------------------------------------ #include // Core graphics library #include // Hardware-specific library Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, rst); String LastOutString = ""; #endif //////////////////////////////////////////////////////////////////////////////// #define TIME_SYSTEM_CLOCK 0b0000000000000001 #define TIME_RTC_CLOCK 0b0000000000000010 #define TIME_FORMAT_SMTP_DATE 0b0000000000000100 #define TIME_FORMAT_SMTP_MSGID 0b0000000000001000 #define TIME_FORMAT_HUMAN 0b0000000000010000 #define TIME_FORMAT_HUMAN_SHORT 0b0000000000100000 #define TIME_FORMAT_TIME_ONLY 0b0000000001000000 #define TIME_FORMAT_TIME_ONLY_WO_COLON 0b0000000010000000 #define TIME_FORMAT_DATE_ONLY 0b0000000100000000 #define DAYLIGHTSAVING_START_MONTH 3 // brezen #define DAYLIGHTSAVING_START_HOUR 2 // 2:00:00 -> 3:00:00 #define DAYLIGHTSAVING_STOP_MONTH 10 // rijen #define DAYLIGHTSAVING_STOP_HOUR 2 // 3:00:00 -> 2:00:00 #define DAYLIGHTSAVING_TIMESHIFT 1 // 1 hodina #define TIME_ZONE_INT 1 #define TIME_ZONE_NODST "+0100" #define TIME_ZONE_DST "+0200" String TIME_ZONE = TIME_ZONE_NODST; time_t time_dhcp_retry = 0; time_t time_last_ntp_check = 0; time_t time_last_reportDS = 0; time_t time_last_lcd = 0; time_t rtc_now = 0; time_t rtc_epoch = 0; //tmElements_t tm; //////////////////////////////////////////////////////////////////////////////// #define DS3231_ADDRESS 104 int rtc_second; //00-59; int rtc_minute; //00-59; int rtc_hour;//1-12 - 00-23; int rtc_weekday;//1-7 int rtc_day;//01-31 int rtc_month;//01-12 int rtc_year;//0-99 + 2000; #define TEMPERATURE_SENSOR_DS3231 0 // RTC - zde muze byt cokoli krome A2 a A3, coz je 16 a 17 #define TEMPERATURE_SENSOR_TMP36_1 A2 // TMP36 inside #define TEMPERATURE_SENSOR_TMP36_2 A3 // TMP36 outside #define MAX_TEMPERATURE_EXCEED 111.11 // Celsius, bad sensor if exceed bool RTCworking = false; //////////////////////////////////////////////////////////////////////////////// #define BAUD_RATE 115200 //////////////////////////////////////////////////////////////////////////////// #define BUFFERSIZE 105 static char buffer[BUFFERSIZE + 1]; const char TextInfo0 [] PROGMEM = "\r\n\xA9 2013-2016, Roman \x8Atec\r\n\r\nGet NTP and RTC chip time\r\n=========================\r\nv 0.31"; const char TextInfo1 [] PROGMEM = "\r\nUninitialized RTC time and temperature:"; const char TextInfo2 [] PROGMEM = "Waiting for DHCP lease ..."; #if defined(ADAFRUIT_ST7735_IS_PRESENT) const char TextInfo3 [] PROGMEM = "Failed to configure IPv4 for using Dynamic Host Configuration Protocol!"; const char TextInfo4 [] PROGMEM = "Dynamic Host ConfigurationProtocol passed."; #else const char TextInfo3 [] PROGMEM = "Failed to configure IPv4 for using Dynamic Host Configuration Protocol!"; const char TextInfo4 [] PROGMEM = "Dynamic Host Configuration Protocol passed."; #endif const char TextInfo5 [] PROGMEM = "Board IP address"; const char TextInfo6 [] PROGMEM = "Network subnet mask"; const char TextInfo7 [] PROGMEM = "Network gateway IP address"; const char TextInfo8 [] PROGMEM = "DNS IP address"; const char TextInfo9 [] PROGMEM = "\r\nThe network interface MAC address"; const char TextInfo10[] PROGMEM = "Waiting to obtain the accurate time from NTP server "; const char TextInfo11[] PROGMEM = "Sending NTP request... "; const char TextInfo12[] PROGMEM = "and NTP responses.\r\nNTP time: "; const char TextInfo13[] PROGMEM = "No NTP Response."; const char TextInfo14[] PROGMEM = "Failed to get the current time from NTP server."; const char TextInfo15[] PROGMEM = "RTC time: "; #if defined(ADAFRUIT_ST7735_IS_PRESENT) const char TextInfo16[] PROGMEM = " RTC chip does not need to be updated."; const char TextInfo17[] PROGMEM = "RTC needs to be updated. Current time difference is"; #else const char TextInfo16[] PROGMEM = "RTC chip does not need to be updated."; const char TextInfo17[] PROGMEM = "RTC needs to be updated. Current time difference is "; #endif const char TextInfo18[] PROGMEM = " second(s)."; const char TextInfo19[] PROGMEM = "RTC chip has been successfully updated."; const char TextInfo20[] PROGMEM = "Error setting time to RTC."; const char TextInfo21[] PROGMEM = "Error setting date to RTC."; const char TextInfo22[] PROGMEM = "RTC time and temperature: "; const char TextInfo23[] PROGMEM = "Failed to get the current time from RTC chip."; const char TextInfo24[] PROGMEM = "No data (temperature sensor error)."; const char TextInfo25[] PROGMEM = "Failed to get current time neither from the NTP server nor the RTC chip."; const char TextInfo26[] PROGMEM = " TMP36: "; const char TextInfo27[] PROGMEM = "Unable to compare NTP and RTC time (RTC is not present?)"; const char TextInfo28[] PROGMEM = "Error calling function: function ComposeTimeStamp requires time source (CPU or RTC)."; const char TextInfo29[] PROGMEM = "Failed to configure IPv4 for using Fixed IP address!"; const char * const TextItemPointers[] PROGMEM = { TextInfo0, TextInfo1, TextInfo2, TextInfo3, TextInfo4, TextInfo5, TextInfo6, TextInfo7, TextInfo8, TextInfo9, TextInfo10, TextInfo11, TextInfo12, TextInfo13, TextInfo14, TextInfo15, TextInfo16, TextInfo17, TextInfo18, TextInfo19, TextInfo20, TextInfo21, TextInfo22, TextInfo23, TextInfo24, TextInfo25, TextInfo26, TextInfo27, TextInfo28, TextInfo29 }; #define WELCOME_MESSAGE 0 #define UNINITIALIZED_RTC_MESSAGE 1 #define DHCP_WAIT_MESSAGE 2 #define DHCP_FAIL_MESSAGE 3 #define DHCP_PASS_MESSAGE 4 #define IP_MESSAGE 5 #define MASK_MESSAGE 6 #define GATEWAY_MESSAGE 7 #define DNS_MESSAGE 8 #define MAC_MESSAGE 9 #define NTP_WAIT_MESSAGE 10 #define NTP_SEND_MESSAGE 11 #define NTP_RESPONSES_MESSAGE 12 #define NTP_NO_RESPONSE_MESSAGE 13 #define NTP_ERROR_MESSAGE 14 #define RTC_TIME_MESSAGE 15 #define RTC_OK_MESSAGE 16 #define RTC_NEED_SYNC_MESSAGE 17 #define SECONDS_MESSAGE 18 #define RTC_SYNC_MESSAGE 19 #define RTC_TF_MESSAGE 20 #define RTC_DF_MESSAGE 21 #define INFO_MESSAGE 22 #define RTC_ERROR_MESSAGE 23 #define TEMPERATURE_ERRROR_MESSAGE 24 #define TIME_ERRROR_MESSAGE 25 #define SENSORS_MESSAGE 26 #define RTC_NOT_PRESENT 27 #define TIMESOURCE_ERRROR_MESSAGE 28 #define FIXED_IP_USED_MESSAGE 29 //////////////////////////////////////////////////////////////////////////////// /*-------- Output subroutines ----------*/ //////////////////////////////////////////////////////////////////////////////// /* //override printf output int my_putc(char outtext, FILE *t){ Serial.write( outtext ); #if defined(SECOND_SERIAL_IS_PRESENT) Serial1.write( outtext ); #endif #if defined(ADAFRUIT_ST7735_IS_PRESENT) tft.print( outtext ); #endif }; */ //distribute output to two serial lines and LCD display void MySerialPrint(String displaytext) { Serial.print( displaytext ); #if defined(SECOND_SERIAL_IS_PRESENT) Serial1.print( displaytext ); #endif }; void MyPrint(String text) { MySerialPrint( text ); #if defined(ADAFRUIT_ST7735_IS_PRESENT) tft.print( text ); #endif }; void MyPrintLn(String text) { MySerialPrint( text + "\r\n" ); #if defined(ADAFRUIT_ST7735_IS_PRESENT) tft.println( text ); #endif }; //////////////////////////////////////////////////////////////////////////////// /*-------- Time subroutines ----------*/ //////////////////////////////////////////////////////////////////////////////// time_t EvaluateDaylightSavingTime(time_t result) { if ( ( ( // plati od (month(result) == DAYLIGHTSAVING_START_MONTH) // breznove and (month(nextSunday(result)) == (DAYLIGHTSAVING_START_MONTH + 1)) // posledni nedele and ( (weekday(result) != 1) or (hour(result) >= DAYLIGHTSAVING_START_HOUR) // od dvou hodin rano ) ) or (month(result) > DAYLIGHTSAVING_START_MONTH) // a v nasledujich mesicich ) and ( ( // plati do (month(result) == DAYLIGHTSAVING_STOP_MONTH) // rijnove and (month(nextSunday(result)) == DAYLIGHTSAVING_STOP_MONTH) // posledni nedele ) or ( (month(result) == DAYLIGHTSAVING_STOP_MONTH) and (month(nextSunday(result)) == (DAYLIGHTSAVING_STOP_MONTH + 1)) and (weekday(result) == 1) and (hour(result) < DAYLIGHTSAVING_STOP_HOUR) ) or (month(result) < DAYLIGHTSAVING_STOP_MONTH) // a v predchozich mesicich ) ) { result = result + DAYLIGHTSAVING_TIMESHIFT * SECS_PER_HOUR; TIME_ZONE = TIME_ZONE_DST; } else { TIME_ZONE = TIME_ZONE_NODST; }; return result; }; //////////////////////////////////////////////////////////////////////////////// byte decToBcd(byte val) { return ( (val / 10 * 16) + (val % 10) ); }; byte bcdToDec(byte val) { return ( (val / 16 * 10) + (val % 16) ); }; //////////////////////////////////////////////////////////////////////////////// bool set_rtc_datum() { Wire.beginTransmission(DS3231_ADDRESS); Wire.write(3);//set register to day Wire.write(decToBcd(rtc_weekday)); Wire.write(decToBcd(rtc_day)); Wire.write(decToBcd(rtc_month)); Wire.write(decToBcd(rtc_year - 2000)); if ( Wire.endTransmission() == 0 ) { return true; } else { return false; }; }; bool set_rtc_time() { Wire.beginTransmission(DS3231_ADDRESS); Wire.write(0);//set register to time Wire.write(decToBcd(rtc_second)); Wire.write(decToBcd(rtc_minute)); Wire.write(decToBcd(rtc_hour)); if ( Wire.endTransmission() == 0 ) { return true; } else { return false; }; }; bool get_rtc_datum() { Wire.beginTransmission(DS3231_ADDRESS); Wire.write(3);//set register to day Wire.endTransmission(); if ( Wire.requestFrom(DS3231_ADDRESS, 4) == 4 ) { //get 4 bytes(day,date,month,year); rtc_weekday = bcdToDec(Wire.read()); rtc_day = bcdToDec(Wire.read()); rtc_month = bcdToDec(Wire.read()); rtc_year = bcdToDec(Wire.read()) + 2000; RTCworking = true; return true; } else { RTCworking = false; return false; }; }; bool get_rtc_time() { Wire.beginTransmission(DS3231_ADDRESS); Wire.write(0);//set register to time Wire.endTransmission(); if ( Wire.requestFrom(DS3231_ADDRESS, 3) == 3 ) { //get 3 bytes (seconds,minutes,hours); rtc_second = bcdToDec(Wire.read() & 0x7f); rtc_minute = bcdToDec(Wire.read()); rtc_hour = bcdToDec(Wire.read() & 0x3f); return true; } else { return false; }; }; float get_rtc_temperature() { Wire.beginTransmission(DS3231_ADDRESS); Wire.write(17);//set register to DS3132 internal temperature sensor Wire.endTransmission(); if ( Wire.requestFrom(DS3231_ADDRESS, 2) == 2 ) { float ttc = (float)(int)Wire.read(); byte portion = Wire.read(); if (portion == 0b01000000) ttc += 0.25; if (portion == 0b10000000) ttc += 0.5; if (portion == 0b11000000) ttc += 0.75; return ttc; } else { return MAX_TEMPERATURE_EXCEED; }; }; bool read_rtc(time_t& cas) { static tmElements_t tmelem; if ( get_rtc_datum() ) { get_rtc_time(); /* time_t temptime; temptime = now(); setTime( rtc_hour,rtc_minute,rtc_second,rtc_day,rtc_month,rtc_year ); cas = now(); setTime(temptime); */ tmelem.Year = rtc_year - 1970; tmelem.Month = rtc_month; tmelem.Day = rtc_day; tmelem.Hour = rtc_hour; tmelem.Minute = rtc_minute; tmelem.Second = rtc_second; cas = makeTime(tmelem); return true; } else { return false; }; }; //////////////////////////////////////////////////////////////////////////////// /*-------- FLASH ROM subroutine ----------*/ //////////////////////////////////////////////////////////////////////////////// String GetTextFromFlashMemory(int ItemIndex) //function to return string by index { int i = 0; char c; while ((c != '\0') and (i < BUFFERSIZE)) { c = pgm_read_byte(pgm_read_word(&TextItemPointers[ItemIndex]) + i); buffer[i] = c; i++; } buffer[i] = '\0'; return String(buffer); } //////////////////////////////////////////////////////////////////////////////// /*-------- PrintTime subroutines ----------*/ //////////////////////////////////////////////////////////////////////////////// String ComposeZerosLeadedNumber(unsigned long int MyNumber, byte NumberOfCharacters) { String TempString = ""; for (byte index = 1; index <= NumberOfCharacters; index++) { TempString = "0" + TempString; }; TempString = TempString + String(MyNumber); int ifrom = TempString.length() - NumberOfCharacters; int ito = TempString.length(); return TempString.substring(ifrom, ito); }; String ComposeTimeStamp(unsigned int details, time_t datum) { String strday; String strmonth; String stryear; String strhour; String strminute; String strsecond; String strweekday; int myvalue; if ( ((details bitand TIME_RTC_CLOCK) != TIME_RTC_CLOCK) and ((details bitand TIME_SYSTEM_CLOCK) != TIME_SYSTEM_CLOCK) ) { strday = GetTextFromFlashMemory(TIMESOURCE_ERRROR_MESSAGE); return strday; }; if ((details bitand TIME_RTC_CLOCK) == TIME_RTC_CLOCK) { if (datum <= 0) { if ( !read_rtc(datum) ) { if ( NTPworking ) { strday = GetTextFromFlashMemory(RTC_ERROR_MESSAGE); } else { strday = GetTextFromFlashMemory(TIME_ERRROR_MESSAGE); }; return strday; }; }; }; if ((details bitand TIME_SYSTEM_CLOCK) == TIME_SYSTEM_CLOCK) { if (datum <= 0) { datum = now(); }; }; datum = EvaluateDaylightSavingTime(datum); strday = ComposeZerosLeadedNumber(day(datum), 2); myvalue = month(datum); if ((details bitand TIME_FORMAT_SMTP_DATE) == TIME_FORMAT_SMTP_DATE) { strmonth = monthShortStr(myvalue); } else { strmonth = ComposeZerosLeadedNumber(myvalue, 2); }; stryear = String(year(datum)); strhour = ComposeZerosLeadedNumber(hour(datum), 2); strminute = ComposeZerosLeadedNumber(minute(datum), 2); strsecond = ComposeZerosLeadedNumber(second(datum), 2); int tweekday; if (details bitand TIME_RTC_CLOCK) { tweekday = rtc_weekday; } else { tweekday = weekday(datum); }; if ((details bitand TIME_FORMAT_HUMAN) == TIME_FORMAT_HUMAN) { strweekday = dayStr(tweekday); } else { strweekday = dayShortStr(tweekday); }; if ((details bitand TIME_FORMAT_HUMAN) == TIME_FORMAT_HUMAN) { return String(strday + "." + strmonth + "." + stryear + " " + strhour + ":" + strminute + ":" + strsecond + " " + strweekday); } else { if ((details bitand TIME_FORMAT_HUMAN_SHORT) == TIME_FORMAT_HUMAN_SHORT) { return String(strday + "." + strmonth + "." + stryear + " " + strhour + ":" + strminute + ":" + strsecond + " ");//20 characters for LCD } else { if ((details bitand TIME_FORMAT_TIME_ONLY) == TIME_FORMAT_TIME_ONLY) { return String(strhour + ":" + strminute + ":" + strsecond); } else { if ((details bitand TIME_FORMAT_TIME_ONLY_WO_COLON) == TIME_FORMAT_TIME_ONLY_WO_COLON) { return String(strhour + " " + strminute + " " + strsecond); } else { if ((details bitand TIME_FORMAT_DATE_ONLY) == TIME_FORMAT_DATE_ONLY) { return String(strday + "." + strmonth + "." + stryear); } else { if ((details bitand TIME_FORMAT_SMTP_MSGID) == TIME_FORMAT_SMTP_MSGID) { return String(stryear + strmonth + strday + strhour + strminute + strsecond + ".") + String(millis()); } else { return String(strweekday + ", " + strday + " " + strmonth + " " + stryear + " " + strhour + ":" + strminute + ":" + strsecond + " " + TIME_ZONE); }; }; }; }; }; }; }; //////////////////////////////////////////////////////////////////////////////// /*-------- NTP subroutines ----------*/ //////////////////////////////////////////////////////////////////////////////// #define NTP_PACKET_SIZE 48 // NTP time is in the first 48 bytes of message //////////////////////////////////////////////////////////////////////////////// time_t getNtpTime() { #if defined(ETHERNET_IS_PRESENT) or defined(ENC28J60_IS_PRESENT) if ( ntp_interrupt_in_progress == false ) { ntp_interrupt_in_progress = true; NTPasked = true; MySerialPrint(GetTextFromFlashMemory(NTP_SEND_MESSAGE)); while (Udp.parsePacket() > 0); // discard any previously received packets byte packetBuffer[NTP_PACKET_SIZE]; //buffer to hold incoming & outgoing packets memset(packetBuffer, 0, NTP_PACKET_SIZE); 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 packetBuffer[12] = 49; packetBuffer[13] = 0x4E; packetBuffer[14] = 49; packetBuffer[15] = 52; Udp.beginPacket(timeServer, 123); //NTP requests are to port 123 Udp.write(packetBuffer, NTP_PACKET_SIZE); Udp.endPacket(); delay(1500); volatile time_t result = 0; volatile int size = Udp.parsePacket(); if ( size >= NTP_PACKET_SIZE ) { Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer volatile 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]; result = secsSince1900 - 2208988800UL + TIME_ZONE_INT * SECS_PER_HOUR; NTPworking = true; NTPsetstime = true; } else { NTPworking = false; MySerialPrint(GetTextFromFlashMemory(NTP_NO_RESPONSE_MESSAGE) + "\r\n"); } ntp_interrupt_in_progress = false; return result; }; return 0; #endif }; //////////////////////////////////////////////////////////////////////////////// bool MaintainTimeSources(bool force) { String OutString = ""; if ( (NTPasked) or (force) ) { NTPasked = false; time_t avr_now = 0; time_t timediff = 0; if ( !read_rtc(rtc_now) ) { rtc_now = 0; }; avr_now = now(); if (NTPworking) { MySerialPrint(GetTextFromFlashMemory(NTP_RESPONSES_MESSAGE)); MySerialPrint(ComposeTimeStamp(TIME_SYSTEM_CLOCK bitor TIME_FORMAT_HUMAN, avr_now)); MySerialPrint(", SYS Epoch: " + String( avr_now ) + "\r\n"); } else { MySerialPrint(GetTextFromFlashMemory(NTP_ERROR_MESSAGE) + "\r\n"); return false; }; if (RTCworking) { MySerialPrint(GetTextFromFlashMemory(RTC_TIME_MESSAGE)); MySerialPrint(ComposeTimeStamp(TIME_RTC_CLOCK bitor TIME_FORMAT_HUMAN, rtc_now)); MySerialPrint(", RTC Epoch: " + String( rtc_now ) + "\r\n"); String strSign = ""; if ( rtc_now > avr_now ) { timediff = rtc_now - avr_now; strSign = "+"; } else { timediff = avr_now - rtc_now; strSign = "-"; }; #if defined(ADAFRUIT_ST7735_IS_PRESENT) #define ST7735_SILVER 0xC618 #define ST7735_GRAY 0x8410 tft.setTextSize(1); tft.setCursor(0, 79); tft.setTextColor(ST7735_BLACK, ST7735_BLACK); tft.print(LastOutString); tft.setCursor(0, 79); //tft.setTextColor(ST7735_GRAY, ST7735_BLACK); tft.setTextColor(ST7735_WHITE, ST7735_BLACK); #endif if ( timediff == 0 ) { OutString = GetTextFromFlashMemory(RTC_OK_MESSAGE); MyPrintLn(OutString); } else { OutString = GetTextFromFlashMemory(RTC_NEED_SYNC_MESSAGE) + strSign + String(timediff) + GetTextFromFlashMemory(SECONDS_MESSAGE); MyPrintLn(OutString); #if defined(ENABLE_RTC_UPDATE) rtc_second = second(); rtc_minute = minute(); rtc_hour = hour(); rtc_weekday = weekday(); rtc_day = day(); rtc_month = month(); rtc_year = year(); if ( !set_rtc_time() ) { MySerialPrint(GetTextFromFlashMemory(RTC_TF_MESSAGE) + "\r\n"); } else { if ( !set_rtc_datum() ) { MySerialPrint(GetTextFromFlashMemory(RTC_DF_MESSAGE) + "\r\n"); } else { MySerialPrint(GetTextFromFlashMemory(RTC_SYNC_MESSAGE) + "\r\n"); }; }; #endif }; #if defined(ADAFRUIT_ST7735_IS_PRESENT) tft.setTextColor(ST7735_GREEN, ST7735_BLACK); LastOutString = OutString; #endif } else { MySerialPrint(GetTextFromFlashMemory(RTC_NOT_PRESENT) + "\r\n"); }; return true; }; return false; }; //////////////////////////////////////////////////////////////////////////////// bool checkntp() { #if defined(ETHERNET_IS_PRESENT) or defined(ENC28J60_IS_PRESENT) MySerialPrint(GetTextFromFlashMemory(NTP_WAIT_MESSAGE)); for (byte thisByte = 0; thisByte < 4; thisByte++) { MySerialPrint(String(timeServer[thisByte], DEC)); if ( thisByte < 3 ) { MySerialPrint("."); }; }; MySerialPrint(" ...\r\n"); NTPsetstime = false; setSyncProvider(getNtpTime); //variables avr_now and rtc_now must be filled in getNtpTime if (( !NTPsetstime ) and ( NTPworking ) ) { setTime(getNtpTime()); //call getNtpTime if setSyncProvider not yet call getNtpTime }; bool ReturnState = MaintainTimeSources(true); if ( !ReturnState ) { setTime(rtc_now); //call getNtpTime if setSyncProvider not yet call getNtpTime }; return ReturnState; #else return false; #endif }; //////////////////////////////////////////////////////////////////////////////// /*-------- DHCP subroutine ----------*/ //////////////////////////////////////////////////////////////////////////////// bool checkdhcp() { bool ipassigned = false; #if defined(ETHERNET_IS_PRESENT) or defined(ENC28J60_IS_PRESENT) #if defined(ADAFRUIT_ST7735_IS_PRESENT) tft.fillScreen(ST7735_BLACK); tft.setTextColor(ST7735_YELLOW, ST7735_BLACK); tft.setTextSize(1); tft.setCursor(0, 0); #endif MyPrint(GetTextFromFlashMemory(MAC_MESSAGE)); MySerialPrint(" = "); #if defined(ADAFRUIT_ST7735_IS_PRESENT) tft.println(); #endif for (byte thisByte = 0; thisByte < 6; thisByte++) { if ( MACAddress[thisByte] < 16 ) { MyPrint("0"); }; String hexString = String(MACAddress[thisByte], HEX); hexString.toUpperCase(); MyPrint(hexString); if ( thisByte < 5 ) { MyPrint(":"); }; }; MyPrintLn(""); #if defined(ADAFRUIT_ST7735_IS_PRESENT) tft.println(); #endif MyPrintLn(GetTextFromFlashMemory(DHCP_WAIT_MESSAGE)); if ( fixedipenabled ) { IPAddress fixedIPaddress(10, 11, 6, 6); IPAddress fixedIPdns(8, 8, 8, 8); IPAddress fixedIPgateway(10, 11, 0, 1); IPAddress fixedIPsubnet(255, 255, 0, 0); Ethernet.begin(MACAddress, fixedIPaddress, fixedIPdns, fixedIPgateway, fixedIPsubnet); MyPrintLn(GetTextFromFlashMemory(FIXED_IP_USED_MESSAGE)); ipassigned = true; } else { if ( Ethernet.begin(MACAddress) == 0 ) { MyPrintLn(GetTextFromFlashMemory(DHCP_FAIL_MESSAGE)); } else { MyPrintLn(GetTextFromFlashMemory(DHCP_PASS_MESSAGE)); ipassigned = true; }; }; if ( ipassigned ) { #if defined(ADAFRUIT_ST7735_IS_PRESENT) delay(2000); tft.fillScreen(ST7735_BLACK); tft.setTextColor(ST7735_YELLOW, ST7735_BLACK); tft.setTextSize(1); tft.setCursor(0, 0); #endif MyPrint(GetTextFromFlashMemory(IP_MESSAGE)); MySerialPrint(" = "); #if defined(ADAFRUIT_ST7735_IS_PRESENT) tft.println(); #endif for (byte thisByte = 0; thisByte < 4; thisByte++) { MyPrint(String(Ethernet.localIP()[thisByte], DEC)); if ( thisByte < 3 ) { MyPrint("."); }; }; MyPrintLn(""); #if defined(ADAFRUIT_ST7735_IS_PRESENT) tft.println(); #endif MyPrint(GetTextFromFlashMemory(MASK_MESSAGE)); MySerialPrint(" = "); #if defined(ADAFRUIT_ST7735_IS_PRESENT) tft.println(); #endif for (byte thisByte = 0; thisByte < 4; thisByte++) { MyPrint(String(Ethernet.subnetMask()[thisByte], DEC)); if (thisByte < 3) { MyPrint("."); }; }; MyPrintLn(""); #if defined(ADAFRUIT_ST7735_IS_PRESENT) tft.println(); #endif MyPrint(GetTextFromFlashMemory(GATEWAY_MESSAGE)); MySerialPrint(" = "); for (byte thisByte = 0; thisByte < 4; thisByte++) { MyPrint(String(Ethernet.gatewayIP()[thisByte], DEC)); if (thisByte < 3) { MyPrint("."); }; }; MyPrintLn(""); #if defined(ADAFRUIT_ST7735_IS_PRESENT) tft.println(); #endif MyPrint(GetTextFromFlashMemory(DNS_MESSAGE)); MySerialPrint(" = "); #if defined(ADAFRUIT_ST7735_IS_PRESENT) tft.println(); #endif for (byte thisByte = 0; thisByte < 4; thisByte++) { MyPrint(String(Ethernet.dnsServerIP()[thisByte], DEC)); if (thisByte < 3) { MyPrint("."); }; }; MyPrint("\r\n"); Udp.begin(LOCALUDPPORT); #if defined(ADAFRUIT_ST7735_IS_PRESENT) delay(10000); tft.fillScreen(ST7735_BLACK); #endif return true; } else { return false; }; #else return false; #endif }; //////////////////////////////////////////////////////////////////////////////// float ComposeTemperatureValue(byte sensor) { String TempStr = ""; // Convert Analog value to temperature // 10 mV na 1 stupen Celsia/Kevina float TemperatureC1, TemperatureC2; if ( sensor == TEMPERATURE_SENSOR_DS3231 ) { TemperatureC1 = get_rtc_temperature(); } else { do { TemperatureC1 = (((analogRead(sensor) * (5000.0 / 1024)) - 750) / 10) + 25; delay(10); TemperatureC2 = (((analogRead(sensor) * (5000.0 / 1024)) - 750) / 10) + 25; } while ( TemperatureC1 != TemperatureC2 ); }; return TemperatureC1; }; //////////////////////////////////////////////////////////////////////////////// String ComposeTemperatureString(byte sensor, bool displaytype) { String TempStr = ""; // Convert Analog value to temperature // 10 mV na 1 stupen Celsia/Kevina float TemperatureC = ComposeTemperatureValue(sensor); if ( TemperatureC < MAX_TEMPERATURE_EXCEED ) { char buffer[16]; TempStr = dtostrf(TemperatureC, 5, 2, buffer); if ( displaytype ) { TempStr = TempStr + "\xDF\x43"; //oC for Asian Character Set } else { TempStr = TempStr + "\xB0\x43"; //oC for Western Character Set }; } else { //error message TempStr = GetTextFromFlashMemory(TEMPERATURE_ERRROR_MESSAGE); }; return TempStr; }; //////////////////////////////////////////////////////////////////////////////// void ShowTime(bool ForceShowTemperature) { if ( time_last_lcd + LCD_UPDATE_PERIOD <= now() ) { time_last_lcd = now(); String PrtString; #if defined(ADAFRUIT_ST7735_IS_PRESENT) tft.setTextColor(ST7735_GREEN, ST7735_BLACK); tft.setTextSize(2); tft.setCursor(21, 0); PrtString = ComposeTimeStamp(TIME_SYSTEM_CLOCK bitor TIME_FORMAT_DATE_ONLY, 0) + " "; tft.print(PrtString); tft.setTextSize(3); tft.setCursor(9, 53); PrtString = ComposeTimeStamp(TIME_SYSTEM_CLOCK bitor TIME_FORMAT_TIME_ONLY, 0); tft.print(PrtString); #endif #if defined(LCD_IS_PRESENT) lcd.setCursor(0, 0); PrtString = ComposeTimeStamp(TIME_RTC_CLOCK bitor TIME_FORMAT_TIME_ONLY, 0) + " " + ComposeTemperatureString(TEMPERATURE_SENSOR_DS3231, true); lcd.print(PrtString); lcd.setCursor(0, 1); PrtString = ComposeTimeStamp(TIME_RTC_CLOCK bitor TIME_FORMAT_DATE_ONLY, 0); lcd.print(PrtString); #endif if ( ( time_last_reportDS + REPORTDS_TIME_PERIOD <= now() ) or ( ForceShowTemperature )) { time_last_reportDS = now(); #if defined(ADAFRUIT_ST7735_IS_PRESENT) tft.setTextSize(3); tft.setCursor(18, 107); PrtString = ComposeTemperatureString(TEMPERATURE_SENSOR_DS3231, false); tft.print(PrtString); #endif //order to avoid distortion running NTP process console print is omited if ( !NTPasked ) { MySerialPrint(GetTextFromFlashMemory(INFO_MESSAGE)); MySerialPrint(ComposeTimeStamp(TIME_RTC_CLOCK bitor TIME_FORMAT_HUMAN, 0)); MySerialPrint(" "); MySerialPrint(ComposeTemperatureString(TEMPERATURE_SENSOR_DS3231, false)); #if defined(TMP36_IS_PRESENT) MySerialPrint(GetTextFromFlashMemory(SENSORS_MESSAGE)); MySerialPrint(ComposeTemperatureString(TEMPERATURE_SENSOR_TMP36_1, false)); MySerialPrint(" "); MySerialPrint(ComposeTemperatureString(TEMPERATURE_SENSOR_TMP36_2, false)); #endif #if defined(PIR_IS_PRESENT) MySerialPrint(" PIRs: " + String(analogRead(0)) + " " + String(analogRead(1))); #endif MySerialPrint("\r\n"); }; }; #if defined(ADAFRUIT_ST7735_IS_PRESENT) or defined(LCD_IS_PRESENT) delay(490); #endif #if defined(ADAFRUIT_ST7735_IS_PRESENT) tft.setTextSize(3); tft.setCursor(9, 53); PrtString = ComposeTimeStamp(TIME_SYSTEM_CLOCK bitor TIME_FORMAT_TIME_ONLY_WO_COLON, 0); tft.print(PrtString); #endif #if defined(LCD_IS_PRESENT) lcd.setCursor(0, 0); PrtString = ComposeTimeStamp(TIME_RTC_CLOCK bitor TIME_FORMAT_TIME_ONLY_WO_COLON, 0) + " " + ComposeTemperatureString(TEMPERATURE_SENSOR_DS3231, true); lcd.print(PrtString); #endif }; }; //////////////////////////////////////////////////////////////////////////////// void setup() { /* //override printf output fdevopen( &my_putc, 0); */ Serial.begin(BAUD_RATE); #if defined(SECOND_SERIAL_IS_PRESENT) Serial1.begin(BAUD_RATE); #endif #if defined(LCD_IS_PRESENT) lcd.begin(16, 2); lcd.clear(); #endif #if defined(ADAFRUIT_ST7735_IS_PRESENT) #define LCDbacklightPin 3 pinMode(LCDbacklightPin, OUTPUT); //digitalWrite(LCDbacklightPin, HIGH); analogWrite(LCDbacklightPin, 255); delay(5000); tft.initR(INITR_BLACKTAB); //tft.initR(INITR_GREENTAB); //tft.initR(INITR_REDTAB); tft.setRotation(1); tft.setTextWrap(true); tft.fillScreen(ST7735_BLACK); tft.setTextColor(ST7735_RED, ST7735_YELLOW); tft.setTextSize(3); tft.setCursor(8, 50); tft.println("RTC test"); tft.setTextColor(ST7735_WHITE, ST7735_BLACK); tft.setTextSize(1); tft.setCursor(0, 0); tft.println(GetTextFromFlashMemory(WELCOME_MESSAGE)); #endif Wire.begin(); #if defined(TMP36_IS_PRESENT) pinMode(TEMPERATURE_SENSOR_TMP36_1, INPUT); pinMode(TEMPERATURE_SENSOR_TMP36_2, INPUT); #endif #if defined(ADAFRUIT_ST7735_IS_PRESENT) tft.setTextColor(ST7735_WHITE, ST7735_BLACK); tft.setTextSize(2); tft.setCursor(0, 80); #endif #if defined(ETHERNET_IS_PRESENT) pinMode(SDCARDPin, OUTPUT); digitalWrite(SDCARDPin, HIGH); #endif #if defined(ETHERNET_IS_PRESENT) or defined(ENC28J60_IS_PRESENT) // delay for terminal for (byte index = 10; index > 0; index--) { delay(1000); MyPrint(String(index) + " "); }; MyPrintLn(""); #else #if defined(ADAFRUIT_ST7735_IS_PRESENT) tft.fillScreen(ST7735_BLACK); #endif #endif MySerialPrint(GetTextFromFlashMemory(WELCOME_MESSAGE) + "\r\n"); time_t rtc_uninitialized_time = 0; if ( read_rtc(rtc_uninitialized_time) ) { setTime(rtc_uninitialized_time); }; MySerialPrint(GetTextFromFlashMemory(UNINITIALIZED_RTC_MESSAGE) + "\r\n"); MySerialPrint(ComposeTimeStamp(TIME_RTC_CLOCK bitor TIME_FORMAT_HUMAN, rtc_uninitialized_time)); MySerialPrint(" "); MySerialPrint(ComposeTemperatureString(TEMPERATURE_SENSOR_DS3231, false) + "\r\n"); }; //////////////////////////////////////////////////////////////////////////////// void loop() { if ( checkdhcp() ) { while (true) { if ( checkntp() ) { time_last_ntp_check = now(); } else { time_last_ntp_check = now() - NTP_CHECK_PERIOD + NTP_RETRY_CHECK_PERIOD; }; while ( time_last_ntp_check + NTP_CHECK_PERIOD > now() ) { ShowTime(false); MaintainTimeSources(false); //if NTP server was asked by system time updater, show results }; }; } else { if ( rtc_epoch == 0 ) { if ( read_rtc(rtc_epoch) ) { setTime(rtc_epoch); }; }; time_dhcp_retry = now(); bool FirstTime = true; while ( time_dhcp_retry + DHCP_RETRY_PERIOD >= now() ) { ShowTime(FirstTime); if ( FirstTime ) { FirstTime = false; }; }; }; }; ////////////////////////////////////////////////////////////////////////////////