x

Dependents:   20180621_FT813

Files at this revision

API Documentation at this revision

Comitter:
JackB
Date:
Mon Jul 23 12:24:33 2018 +0000
Commit message:
MCP79412

Changed in this revision

MCP79412.cpp Show annotated file Show diff for this revision Revisions of this file
MCP79412.h Show annotated file Show diff for this revision Revisions of this file
TableDayLight.h Show annotated file Show diff for this revision Revisions of this file
TableSummerTime.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 04311b121ac4 MCP79412.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MCP79412.cpp	Mon Jul 23 12:24:33 2018 +0000
@@ -0,0 +1,1808 @@
+#include "MCP79412.h"
+
+MCP79412::MCP79412(PinName sda, PinName scl) : _i2c(sda, scl)
+{
+    _address_RTC = MCP79412_RTC_ADDR << 1;
+    squareWave(SQWAVE_1_HZ);
+//    setTimeZone(1);
+//    dayLightSaving = true;
+    setI2Cfrequency(400000);
+}
+
+void MCP79412::setI2Cfrequency(int freq)
+{
+    _i2c.frequency(freq);
+}
+
+// get a uint8_t containing just the requested bits
+// pass the register address to read, a mask to apply to the register and
+// an uint* for the output
+// you can test this value directly as true/false for specific bit mask
+// of use a mask of 0xff to just return the whole register uint8_t
+// returns true to indicate success
+    /** Get flag
+    * @param reg : register address
+    * @param mask : flag mask
+    * @return The register content
+    */     
+bool MCP79412::getFlag(char reg, char mask, char *flag)
+{
+    char buf[1];
+    buf[0] = reg;
+    int w = _i2c.write(_address_RTC, buf, 1);
+    int r = _i2c.read(_address_RTC, buf, 1);
+    _error = ((w != 0) || (r != 0));
+    // return only requested flag
+    *flag = (buf[0] & mask);
+    return flag == 0 ? false : true;
+}
+
+// set/clear bits in a uint8_t register, or replace the uint8_t altogether
+// pass the register address to modify, a uint8_t to replace the existing
+// value with or containing the bits to set/clear and one of
+// MCP79412_SET/MCP79412_CLEAR/MCP79412_REPLACE
+// returns true to indicate success
+    /** Set flag
+    * @param reg : register address
+    * @param bits : bits to set or reset
+    * @param mode : MCP79412_REPLACE, MCP79412_SET, MCP79412_CLEAR
+    * @return none
+    */     
+void MCP79412::setFlag(char reg, char bits, char mode)
+{
+    char buf[2];
+    buf[0] = reg;
+    // get status register
+    int w = _i2c.write(_address_RTC, buf, 1);
+    int r = _i2c.read(_address_RTC, buf+1, 1);
+    // clear the flag
+    if (mode == MCP79412_REPLACE)
+        buf[1] = bits;
+    else if (mode == MCP79412_SET)
+        buf[1] |= bits;
+    else
+        buf[1] &= ~bits;
+    int w2 = _i2c.write(_address_RTC, buf, 2);
+    _error = ((w != 0) || (r != 0) || (w2 != 0));
+}
+
+// read a register
+int MCP79412::readRegister(char reg)
+{
+//    int w = _i2c.write(_address_RTC, &reg, 1);
+//    char rtn;
+//    int r = _i2c.read(_address_RTC, &rtn, 1);
+//    _error = ((w != 0) || (r != 0));
+//    return rtn;
+
+    char buf[1];
+    buf[0] = reg;
+    int w = _i2c.write(_address_RTC, buf, 1);
+    int r = _i2c.read(_address_RTC, buf, 1);
+    _error = ((w != 0) || (r != 0));
+    return(buf[0]);
+}
+
+// read registers
+void MCP79412::readRegisters(char reg, char *outbuf, char length)
+{
+    char buf[1];
+    buf[0] = reg;
+    int w = _i2c.write(_address_RTC, buf, 1);
+    int r = _i2c.read(_address_RTC, outbuf, length);
+    _error = ((w != 0) || (r != 0));
+}
+
+// write a register
+void MCP79412::writeRegister(int reg, char uint8_t)
+{
+    char buf[2];
+    buf[0] = reg;
+    buf[1] = uint8_t;
+    int w = _i2c.write(_address_RTC, buf, 2);
+    _error = (w != 0);
+}
+
+// write registers
+void MCP79412::writeRegisters(int reg, char *inbuf, char length)
+{
+    char buf[32];
+    buf[0] = reg;
+    for (int i = 1; i <= length; i++) {
+        buf[i] = inbuf[i-1];
+    }
+    int w = _i2c.write(_address_RTC, buf, length+1);
+    _error = (w != 0);
+}
+
+
+// Function to read the mac address from the eeprom
+void MCP79412::getMacAddress(char *mac_address)
+{
+    char buf[1];
+    buf[0] = MAC_LOCATION;
+    int w = _i2c.write(MCP79412_EEPROM_ADDR, buf, 1);
+    int r = _i2c.read(MCP79412_EEPROM_ADDR, mac_address, 6);
+    _error = ((w != 0) || (r != 0));
+}
+
+// Unlock the unique id area and write in the mac address
+void MCP79412::writeMacAddress(char *mac_address)
+{
+    char buf[7];
+    unlockUniqueID();
+    buf[0] = MAC_LOCATION;
+    for (int i = 1; i <= 6; i++) {
+        buf[i] = mac_address[i-1];
+    }
+    int w = _i2c.write(MCP79412_EEPROM_ADDR, buf, 7);
+
+    _error = (w != 0);
+}
+
+// Unlock the unique id area ready for writing
+void MCP79412::unlockUniqueID()
+{
+    // Write 0x55 to the memory location 0x09
+    char buf[2];
+    buf[0] = UNLOCK_ID_REG;
+    buf[1] = UNLOCK_ID_CODE1;
+    int w1 = _i2c.write(MCP79412_RTC_ADDR, buf, 2);
+
+    // Write 0xAA to the memory location 0x09
+    buf[0] = UNLOCK_ID_REG;
+    buf[1] = UNLOCK_ID_CODE2;
+    int w2 = _i2c.write(MCP79412_RTC_ADDR, buf, 2);
+
+    _error = ((w1 != 0) || (w2 != 0));
+}
+
+// Set the date/time, set to 24hr and enable the clock
+// (assumes you're passing in valid numbers)
+void MCP79412::setRtcDateTime(
+  uint8_t second,        // 0-59
+  uint8_t minute,        // 0-59
+  uint8_t hour,          // 1-23
+  uint8_t dayOfWeek,     // 1-7
+  uint8_t dayOfMonth,    // 1-31
+  uint8_t month,         // 1-12
+  uint8_t year)          // 0-99
+{
+    char buf[8];
+    buf[0] = RTC_LOCATION;
+    buf[1] = decToBcd(second) & 0x7f;               // set seconds and disable clock (01111111, Bit 7, ST = 0)
+    buf[2] = decToBcd(minute) & 0x7f;               // set minutes (01111111)
+    buf[3] = decToBcd(hour) & 0x3f;                 // set hours and to 24hr format (00111111, Bit 6 = 0)
+    buf[4] = _BV(VBATEN) | (decToBcd(dayOfWeek) & 0x07);   // set the day and enable battery backup (00000111)|(00001000, Bit 3 = 1)
+    buf[5] = decToBcd(dayOfMonth) & 0x3f;           // set the date in month (00111111)
+    buf[6] = decToBcd(month) & 0x1f;                // set the month (00011111)
+    buf[7] = decToBcd(year);                        // set the year (11111111)
+    int w1 = _i2c.write(MCP79412_RTC_ADDR, buf, 8);
+
+    // Start Clock:
+    buf[0] = RTC_LOCATION;
+    buf[1] = _BV(ST) | decToBcd(second);            // set seconds and enable clock (10000000)
+    int w2 = _i2c.write(MCP79412_RTC_ADDR, buf, 2);
+
+    _error = ((w1 != 0) || (w2 != 0));
+}
+
+// Get the date/time
+void MCP79412::getRtcDateTime(
+  uint8_t *second,
+  uint8_t *minute,
+  uint8_t *hour,
+  uint8_t *dayOfWeek,
+  uint8_t *dayOfMonth,
+  uint8_t *month,
+  uint8_t *year)
+{
+    char buf[8];
+
+    buf[0] = RTC_LOCATION;
+    int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1);
+    int r = _i2c.read(MCP79412_RTC_ADDR, buf, 7);
+
+    _error = ((w != 0) || (r != 0));
+
+    // A few of these need masks because certain bits are control bits
+    *second     = bcdToDec(buf[0] & 0x7f);  // 01111111 0-59
+    *minute     = bcdToDec(buf[1] & 0x7f);  // 01111111 0-59
+    *hour       = bcdToDec(buf[2] & 0x3f);  // 00111111 1-23
+    *dayOfWeek  = bcdToDec(buf[3] & 0x07);  // 00000111 1-7
+    *dayOfMonth = bcdToDec(buf[4] & 0x3f);  // 00111111 1-31
+    *month      = bcdToDec(buf[5] & 0x1f);  // 00011111 1-12
+    *year       = bcdToDec(buf[6]);         // 11111111 0-99
+}
+
+bool MCP79412::checkTimeLost(void)
+{
+    char buf[8];
+    uint8_t second, minute, hour, dayOfWeek, dayOfMonth, month, year;
+    buf[0] = RTC_LOCATION;
+    int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1);
+    int r = _i2c.read(MCP79412_RTC_ADDR, buf, 7);
+
+    _error = ((w != 0) || (r != 0));
+
+    // A few of these need masks because certain bits are control bits
+    second     = bcdToDec(buf[0] & 0x7f);  // 01111111 0-59
+    minute     = bcdToDec(buf[1] & 0x7f);  // 01111111 0-59
+    hour       = bcdToDec(buf[2] & 0x3f);  // 00111111 1-23
+    dayOfWeek  = bcdToDec(buf[3] & 0x07);  // 00000111 1-7
+    dayOfMonth = bcdToDec(buf[4] & 0x3f);  // 00111111 1-31
+    month      = bcdToDec(buf[5] & 0x1f);  // 00011111 1-12
+    year       = bcdToDec(buf[6]);         // 11111111 0-99
+    return (year <= 15) ? true : false;
+}
+
+// Enable the clock without changing the date/time
+void MCP79412::enableClock()
+{
+    // Get the current seconds value as the enable/disable bit is in the same
+    // byte of memory as the seconds value:
+    char buf[2];
+    buf[0] = RTC_LOCATION;
+    int w1 = _i2c.write(MCP79412_RTC_ADDR, buf, 1);
+    int r = _i2c.read(MCP79412_RTC_ADDR, buf, 1);
+
+    int second = bcdToDec(buf[0] & 0x7f);  // 01111111
+
+    // Start Clock:
+    buf[0] = RTC_LOCATION;
+    buf[1] = _BV(ST) | decToBcd(second);     // set seconds and enable clock (10000000, Bit 7, ST = 1)
+    int w2 = _i2c.write(MCP79412_RTC_ADDR, buf, 2);
+
+    _error = ((w1 != 0) || (r != 0) || (w2 != 0));
+}
+
+// Disable the clock without changing the date/time
+void MCP79412::disableClock()
+{
+    // Get the current seconds value as the enable/disable bit is in the same
+    // uint8_t of memory as the seconds value:
+    char buf[2];
+    buf[0] = RTC_LOCATION;
+    int w1 = _i2c.write(MCP79412_RTC_ADDR, buf, 1);
+    int r = _i2c.read(MCP79412_RTC_ADDR, buf, 1);
+  
+    int second = bcdToDec(buf[0] & 0x7f);  // 01111111
+
+    // Stop Clock:
+    buf[0] = RTC_LOCATION;
+    buf[1] = decToBcd(second);     // set seconds and disable clock (01111111, Bit 7, ST = 0)
+    int w2 = _i2c.write(MCP79412_RTC_ADDR, buf, 2);
+
+    _error = ((w1 != 0) || (r != 0) || (w2 != 0));
+}
+
+// Enable the battery
+void MCP79412::enableBattery()
+{
+    // Get the current day value as the enable/disable bit is in the same
+    // uint8_t of memory as the seconds value:
+    char buf[2];
+    buf[0] = DAY_REG;
+    int w1 = _i2c.write(MCP79412_RTC_ADDR, buf, 1);
+    int r = _i2c.read(MCP79412_RTC_ADDR, buf, 1);
+  
+    int day = bcdToDec(buf[0] & 0x07);  // 00000111
+
+    // Start Clock:
+    buf[0] = DAY_REG;
+    buf[1] = _BV(VBATEN) | decToBcd(day);     // set day and enable battery (00001000)
+    int w2 = _i2c.write(MCP79412_RTC_ADDR, buf, 2);
+
+    _error = ((w1 != 0) || (r != 0) || (w2 != 0));
+}
+
+
+// Write a single byte of data to RAM
+void MCP79412::writeRamByte(uint8_t location, uint8_t data)
+{
+    writeRamBytes(location, &data, 1);
+//    char buf[2];
+//    if ((location >= SRAM_START_ADDR) && (location <= SRAM_END_ADDR))
+//    {
+//        buf[0] = location;
+//        buf[1] = data;
+//        int w = _i2c.write(MCP79412_RTC_ADDR, buf, 2);
+//        _error = (w != 0);
+//    }
+}
+
+// Write multiple bytes of data to RAM
+uint8_t MCP79412::writeRamBytes(uint8_t location, uint8_t *data, uint8_t length)
+{
+    uint8_t bytesWritten = 0;
+    char buf[1];
+    buf[0] = location;
+    int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1);
+    _error = (w != 0);
+    for (uint8_t i = 0; i < length; i++) {
+        buf[0] = data[i];
+        int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1); // Returns 0 on success (ack), non-0 on failure (nack)
+        bytesWritten++;
+        if (_error == false) {
+            _error = (w != 0);
+        }
+    }
+    return bytesWritten;
+}
+
+// Read a single byte of data from RAM
+uint8_t MCP79412::readRamByte(uint8_t location)
+{
+    uint8_t data;
+    readRamBytes(location, &data, 1);
+    return data;
+//    char buf[2];
+//    if ((location >= SRAM_START_ADDR) && (location <= SRAM_END_ADDR))
+//    {
+//        buf[0] = location;
+//        int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1);
+//        int r = _i2c.read(MCP79412_RTC_ADDR, buf, 1);
+//
+//        _error = ((w != 0) || (r != 0));
+//
+//        return buf[0];
+//    }
+//    return 0;
+}
+
+// Read multiple bytes of data from RAM
+uint8_t MCP79412::readRamBytes(uint8_t location, uint8_t *data, uint8_t length)
+{
+    uint8_t bytesRead = 0;
+    char buf[1];
+    buf[0] = location;
+    int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1);
+    _error = (w != 0);
+    for (uint8_t i = 0; i < length; i++) {
+        int r = _i2c.read(MCP79412_RTC_ADDR, buf, 1);
+        bytesRead++;
+        data[i] = buf[0];
+        if (_error == false) {
+            _error = (r != 0);
+        }
+    }
+    return bytesRead;
+}
+
+// 64 Bytes SRAM, Battery Backed
+// Write a single byte of data to SRAM
+void MCP79412::writeSramByte(uint8_t location, uint8_t data)
+{
+    writeSramBytes(location, &data, 1);
+//    char buf[2];
+//    if ((location >= SRAM_START_ADDR) && (location <= SRAM_END_ADDR))
+//    {
+//        buf[0] = location;
+//        buf[1] = data;
+//        int w = _i2c.write(MCP79412_RTC_ADDR, buf, 2);
+//        _error = (w != 0);
+//    }
+}
+
+// 64 Bytes SRAM, Battery Backed
+// Write multiple bytes of data to SRAM
+uint8_t MCP79412::writeSramBytes(uint8_t location, uint8_t *data, uint8_t length)
+{
+    uint8_t bytesWritten = 0;
+    char buf[1];
+    buf[0] = location;
+    int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1);
+    _error = (w != 0);
+    for (uint8_t i = 0; i < length; i++) {
+        if ((location >= SRAM_START_ADDR) && (location <= SRAM_END_ADDR))
+        {
+            buf[0] = data[i];
+            int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1); // Returns 0 on success (ack), non-0 on failure (nack)
+            bytesWritten++;
+            if (_error == false) {
+                _error = (w != 0);
+            }
+        }
+        location++;
+    }
+    return bytesWritten;
+}
+
+// 64 Bytes SRAM, Battery Backed
+// Read a single byte of data from SRAM
+uint8_t MCP79412::readSramByte(uint8_t location)
+{
+    uint8_t data;
+    readSramBytes(location, &data, 1);
+    return data;
+//    char buf[2];
+//    if ((location >= SRAM_START_ADDR) && (location <= SRAM_END_ADDR))
+//    {
+//        buf[0] = location;
+//        int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1);
+//        int r = _i2c.read(MCP79412_RTC_ADDR, buf, 1);
+//
+//        _error = ((w != 0) || (r != 0));
+//
+//        return buf[0];
+//    }
+//    return 0;
+}
+
+// 64 Bytes SRAM, Battery Backed
+// Read multiple bytes of data from SRAM
+uint8_t MCP79412::readSramBytes(uint8_t location, uint8_t *data, uint8_t length)
+{
+    uint8_t bytesRead = 0;
+    char buf[1];
+    buf[0] = location;
+    int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1);
+    _error = (w != 0);
+    for (uint8_t i = 0; i < length; i++) {
+        if ((location >= SRAM_START_ADDR) && (location <= SRAM_END_ADDR))
+        {
+            int r = _i2c.read(MCP79412_RTC_ADDR, buf, 1);
+            bytesRead++;
+            data[i] = buf[0];
+            if (_error == false) {
+                _error = (r != 0);
+            }
+        }
+        location++;
+    }
+    return bytesRead;
+}
+
+// 128 Bytes EEPROM
+// Write a single byte of data to EEPROM
+void MCP79412::writeEepromByte(uint8_t location, uint8_t data)
+{
+    writeEepromBytes(location, &data, 1);
+//    char buf[2];
+//    unlockUniqueID();
+//    buf[0] = location & (EEPROM_SIZE - 1);
+//    buf[1] = data;
+//    int w = _i2c.write(MCP79412_EEPROM_ADDR, buf, 2);
+//    _error = (w != 0);
+}
+
+// 128 Bytes EEPROM
+// Unlock the unique id area and write multiple of bytes to EEPROM
+uint8_t MCP79412::writeEepromBytes(uint8_t location, uint8_t *data, uint8_t length)
+{
+    uint8_t bytesWritten = 0;
+    char buf[1];
+    unlockUniqueID();
+    buf[0] = location & (EEPROM_SIZE - 1);  // location & 0x7f
+    int w = _i2c.write(MCP79412_EEPROM_ADDR, buf, 1);
+    _error = (w != 0);
+    for (uint8_t i = 0; i < length; i++) {
+        if (location < EEPROM_SIZE)
+        {
+            buf[0] = data[i];
+            int w = _i2c.write(MCP79412_EEPROM_ADDR, buf, 1); // Returns 0 on success (ack), non-0 on failure (nack)
+            bytesWritten++;
+            if (_error == false) {
+                _error = (w != 0);
+            }
+        }
+        location++;
+    }
+    return bytesWritten;
+}
+
+// 128 Bytes EEPROM
+// Read a single byte of data from EEPROM
+uint8_t MCP79412::readEepromByte(uint8_t location)
+{
+    uint8_t data;
+    readEepromBytes(location, &data, 1);
+    return data;
+//    char buf[2];
+//    if ((location >= SRAM_START_ADDR) && (location <= SRAM_END_ADDR))
+//    {
+//        buf[0] = location;
+//        int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1);
+//        int r = _i2c.read(MCP79412_RTC_ADDR, buf, 1);
+//
+//        _error = ((w != 0) || (r != 0));
+//
+//        return buf[0];
+//    }
+//    return 0;
+}
+
+// 128 Bytes EEPROM
+// Read multiple bytes of data from EEPROM
+uint8_t MCP79412::readEepromBytes(uint8_t location, uint8_t *data, uint8_t length)
+{
+    uint8_t bytesRead = 0;
+    char buf[1];
+    buf[0] = location & (EEPROM_SIZE - 1);  // location & 0x7f
+    int w = _i2c.write(MCP79412_EEPROM_ADDR, buf, 1);
+    _error = (w != 0);
+    for (uint8_t i = 0; i < length; i++) {
+        if (location < EEPROM_SIZE)
+        {
+            int r = _i2c.read(MCP79412_EEPROM_ADDR, buf, 1);
+            bytesRead++;
+            data[i] = buf[0];
+            if (_error == false) {
+                _error = (r != 0);
+            }
+        }
+        location++;
+    }
+    return bytesRead;
+}
+
+/*----------------------------------------------------------------------*
+ * Read the calibration register.                                       *
+ * The calibration value is not a twos-complement number. The MSB is    *
+ * the sign bit, and the 7 LSBs are an unsigned number, so we convert   *
+ * it and return it to the caller as a regular twos-complement integer. *
+ *----------------------------------------------------------------------*/
+int MCP79412::calibRead(void)
+{
+    uint8_t val = readRamByte(CALIB_REG);
+
+    if ( val & 0x80 ) {
+        return -(val & 0x7F);
+    }
+    return val;
+}
+
+/*----------------------------------------------------------------------*
+ * Write the calibration register.                                      *
+ * Calibration value must be between -127 and 127, others result        *
+ * in no action. See note above on the format of the calibration value. *
+ *----------------------------------------------------------------------*/
+void MCP79412::calibWrite(int value)
+{
+    uint8_t calibVal;
+
+    if (value >= -127 && value <= 127) {
+        calibVal = abs(value);
+        if (value < 0) {
+            calibVal += 128;
+        }
+        writeRamByte(CALIB_REG, calibVal);
+    }
+}
+
+/*----------------------------------------------------------------------*
+ * Read the unique ID.                                                  *
+ * User or factory programmable, Protected area                         *
+ * For the MCP79411 (EUI-48), the first two bytes will contain 0xFF.    *
+ * Caller must provide an 8-byte array to contain the results.          *
+ *----------------------------------------------------------------------*/
+void MCP79412::readUniqueId(char *uniqueID)
+{
+    char buf[1];
+    buf[0] = UNIQUE_ID_ADDR;
+    int w = _i2c.write(MCP79412_EEPROM_ADDR, buf, 1);
+    int r = _i2c.read(MCP79412_EEPROM_ADDR, uniqueID, UNIQUE_ID_SIZE);
+    _error = ((w != 0) || (r != 0));
+}
+
+/*----------------------------------------------------------------------------*
+ * Returns an EUI-64 ID. For an MCP79411, the EUI-48 ID is converted to       *
+ * EUI-64. For an MCP79412, calling this function is equivalent to            *
+ * calling readUniqueId(). For an MCP79412, if the RTC type is known, calling *
+ * readUniqueId() will be a bit more efficient.                               *
+ * Caller must provide an 8-byte array to contain the results.                *
+ *----------------------------------------------------------------------------*/
+void MCP79412::getEUI64(char *uniqueID)
+{
+    char rtcID[8];
+
+    readUniqueId(rtcID);
+    if ((rtcID[0] == 0xFF) && (rtcID[1] == 0xFF)) {
+        rtcID[0] = rtcID[2];
+        rtcID[1] = rtcID[3];
+        rtcID[2] = rtcID[4];
+        rtcID[3] = 0xFF;
+        rtcID[4] = 0xFE;
+    }
+    for (uint8_t i = 0; i < UNIQUE_ID_SIZE; i++) {
+        uniqueID[i] = rtcID[i];
+    }
+}
+
+/*----------------------------------------------------------------------*
+ * Check to see if a power failure has occurred. If so, returns TRUE    *
+ * as the function value, and returns the power down and power up       *
+ * timestamps. After returning the time stamps, the RTC's timestamp     *
+ * registers are cleared and the VBAT bit which indicates a power       *
+ * failure is reset.                                                    *
+ *                                                                      *
+ * Note that the power down and power up timestamp registers do not     *
+ * contain values for seconds or for the year. The returned time stamps *
+ * will therefore contain the current year from the RTC. However, there *
+ * is a chance that a power outage spans from one year to the next.     *
+ * If we find the power down timestamp to be later (larger) than the    *
+ * power up timestamp, we will assume this has happened, and well       *
+ * subtract one year from the power down timestamp.                     *
+ *                                                                      *
+ * Still, there is an assumption that the timestamps are being read     *
+ * in the same year as that when the power up occurred.                 *
+ *                                                                      *
+ * Finally, note that once the RTC records a power outage, it must be   *
+ * cleared before another will be recorded.                             *
+ *----------------------------------------------------------------------*/
+bool MCP79412::powerFail(time_t *powerDown, time_t *powerUp)
+{
+    uint8_t day, yr;                //copies of the RTC Day and Year registers
+    struct tm dn, up;               //power down and power up times
+    char buf[8];
+
+    readRamBytes(DAY_REG, &day, 1);
+    readRamBytes(YEAR_REG, &yr, 1);
+    yr = y2kYearToTm(bcdToDec(yr));
+    if ( day & _BV(VBAT) ) {
+        buf[0] = PWRDWN_TS_REG;
+        int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1);
+
+        int r = _i2c.read(MCP79412_RTC_ADDR, buf, 8);       //read both timestamp registers, 8 bytes total
+        dn.tm_sec     = 0;
+        dn.tm_min     = bcdToDec(buf[0]);
+        dn.tm_hour    = bcdToDec(buf[1] & ~_BV(HR1224));     //assumes 24hr clock
+        dn.tm_mday    = bcdToDec(buf[2]);
+        dn.tm_mon     = bcdToDec(buf[3] & 0x1F);             //mask off the day, we don't need it
+        dn.tm_year    = yr;                                 //assume current year
+        up.tm_sec     = 0;
+        up.tm_min     = bcdToDec(buf[4]);
+        up.tm_hour    = bcdToDec(buf[5] & ~_BV(HR1224));     //assumes 24hr clock
+        up.tm_mday    = bcdToDec(buf[6]);
+        up.tm_mon     = bcdToDec(buf[7] & 0x1F);             //mask off the day, we don't need it
+        up.tm_year    = yr;                                 //assume current year
+        
+        *powerDown = mktime(&dn);
+        *powerUp   = mktime(&up);
+
+        //clear the VBAT bit, which causes the RTC hardware to clear the timestamps too.
+        //I suppose there is a risk here that the day has changed since we read it,
+        //but the Day of Week is actually redundant data and the makeTime() function
+        //does not use it. This could be an issue if someone is reading the RTC
+        //registers directly, but as this library is meant to be used with the Time library,
+        //and also because we don't provide a method to read the RTC clock/calendar
+        //registers directly, we won't lose any sleep about it at this point unless
+        //some issue is actually brought to our attention ;-)
+        day &= ~_BV(VBAT);
+        writeRamBytes(DAY_REG, &day , 1);
+
+        //adjust the powerDown timestamp if needed (see notes above)
+        if (*powerDown > *powerUp) {
+            --dn.tm_year;
+            *powerDown = mktime(&dn);
+        }
+        return true;
+    }
+    return false;
+}
+
+/*----------------------------------------------------------------------*
+ * Enable or disable the square wave output.                            *
+ *----------------------------------------------------------------------*/
+void MCP79412::squareWave(Sqwave freq)
+{
+    uint8_t ctrlReg;
+
+    readRamBytes(CTRL_REG, &ctrlReg, 1);
+    if (freq > 3) {
+        ctrlReg &= ~_BV(SQWE);
+    }
+    else {
+        ctrlReg = (ctrlReg & 0xF8) | _BV(SQWE) | freq;
+    }
+    writeRamByte(CTRL_REG, ctrlReg);
+}
+
+/*----------------------------------------------------------------------*
+ * Set an alarm time. Sets the alarm registers only, does not enable    *
+ * the alarm. See enableAlarm().                                        *
+ *----------------------------------------------------------------------*/
+void MCP79412::setAlarm(uint8_t alarmNumber, time_t alarmTime)
+{
+    struct tm *t;
+    uint8_t day;                        // Need to preserve bits in the day (of week) register
+
+    alarmNumber &= 0x01;                // Ensure a valid alarm number
+    readRamBytes(ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG) , &day, 1);
+    t = localtime(&alarmTime);            // Put the time_t into the tm structure
+    
+    char buf[7];
+    buf[0] = ALM0_REG + alarmNumber * (ALM1_REG - ALM0_REG);
+    buf[1] = dec2bcd(t->tm_sec);
+    buf[2] = dec2bcd(t->tm_min);
+    buf[3] = dec2bcd(t->tm_hour);       // Sets 24 hour format (Bit 6 == 0)
+    buf[4] = (day & 0xF8) + t->tm_wday;
+    buf[5] = dec2bcd(t->tm_mday);
+    buf[6] = dec2bcd(t->tm_mon);
+    int w = _i2c.write(MCP79412_RTC_ADDR, buf, 7);
+    _error = (w != 0);
+}
+
+/*----------------------------------------------------------------------*
+ * Enable or disable an alarm, and set the trigger criteria,            *
+ * e.g. match only seconds, only minutes, entire time and date, etc.    *
+ *----------------------------------------------------------------------*/
+void MCP79412::enableAlarm(uint8_t alarmNumber, uint8_t alarmType)
+{
+    uint8_t day;                //alarm day register has config & flag bits
+    uint8_t ctrl;               //control register has alarm enable bits
+
+    alarmNumber &= 0x01;        //ensure a valid alarm number
+    readRamBytes(CTRL_REG, &ctrl, 1);
+    if (alarmType < ALM_DISABLE) {
+        readRamBytes(ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG), &day, 1);
+        day = ( day & 0x87 ) | alarmType << 4;  //reset interrupt flag, OR in the config bits
+        writeRamByte(ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG), day);
+        ctrl |= _BV(ALM0 + alarmNumber);        //enable the alarm
+    }
+    else {
+        ctrl &= ~(_BV(ALM0 + alarmNumber));     //disable the alarm
+    }
+    writeRamByte(CTRL_REG, ctrl);
+}
+
+/*----------------------------------------------------------------------*
+ * Returns true or false depending on whether the given alarm has been  *
+ * triggered, and resets the alarm "interrupt" flag. This is not a real *
+ * interrupt, just a bit that's set when an alarm is triggered.         *
+ *----------------------------------------------------------------------*/
+bool MCP79412::alarm(uint8_t alarmNumber)
+{
+    uint8_t day;                //alarm day register has config & flag bits
+
+    alarmNumber &= 0x01;        //ensure a valid alarm number
+    readRamBytes( ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG), &day, 1);
+    if (day & _BV(ALMIF)) {
+        day &= ~_BV(ALMIF);     //turn off the alarm "interrupt" flag
+        writeRamByte(ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG), day);
+        return true;
+    }
+    return false;
+}
+
+/*----------------------------------------------------------------------*
+ * Sets the logic level on the MFP when it's not being used as a        *
+ * square wave or alarm output. The default is HIGH.                    *
+ *----------------------------------------------------------------------*/
+void MCP79412::out(bool level)
+{
+    uint8_t ctrlReg;
+
+    readRamBytes(CTRL_REG, &ctrlReg, 1);
+    if (level)
+        ctrlReg |= _BV(OUT);
+    else
+        ctrlReg &= ~_BV(OUT);
+    writeRamByte(CTRL_REG, ctrlReg);
+}
+
+/*----------------------------------------------------------------------*
+ * Specifies the logic level on the Multi-Function Pin (MFP) when an    *
+ * alarm is triggered. The default is LOW. When both alarms are         *
+ * active, the two are ORed together to determine the level of the MFP. *
+ * With alarm polarity set to LOW (the default), this causes the MFP    *
+ * to go low only when BOTH alarms are triggered. With alarm polarity   *
+ * set to HIGH, the MFP will go high when EITHER alarm is triggered.    *
+ *                                                                      *
+ * Note that the state of the MFP is independent of the alarm           *
+ * "interrupt" flags, and the alarm() function will indicate when an    *
+ * alarm is triggered regardless of the polarity.                       *
+ *----------------------------------------------------------------------*/
+void MCP79412::alarmPolarity(bool polarity)
+{
+    uint8_t alm0Day;
+
+    readRamBytes(ALM0_DAY, &alm0Day, 1);
+    if (polarity)
+        alm0Day |= _BV(OUT);
+    else
+        alm0Day &= ~_BV(OUT);
+    writeRamByte(ALM0_DAY, alm0Day);
+}
+
+/*----------------------------------------------------------------------*
+ * Check to see if the RTC's oscillator is started (ST bit in seconds   *
+ * register). Returns true if started.                                  *
+ *----------------------------------------------------------------------*/
+bool MCP79412::isRunning(void)
+{
+    char buf[1];
+    buf[0] = (uint8_t)TIME_REG;
+    int w = _i2c.write(MCP79412_RTC_ADDR, buf, 1);
+    int r = _i2c.read(MCP79412_RTC_ADDR, buf, 1);
+    _error = ((w != 0) || (r != 0));
+    return buf[0] & _BV(ST);
+}
+
+/*----------------------------------------------------------------------*
+ * Set or clear the VBATEN bit. Setting the bit powers the clock and    *
+ * SRAM from the backup battery when Vcc falls. Note that setting the   *
+ * time via set() or write() sets the VBATEN bit.                       *
+ *----------------------------------------------------------------------*/
+void MCP79412::vbaten(bool enable)
+{
+    uint8_t day;
+
+    readRamBytes(DAY_REG, &day, 1);
+    if (enable)
+        day |= _BV(VBATEN);
+    else
+        day &= ~_BV(VBATEN);
+
+    writeRamByte(DAY_REG, day);
+    return;
+}
+
+
+
+//bool MCP79412::getSummerTime(void)
+//{
+//    getDateTime(&t);
+//
+//    time_t secondsEpoch = mktime(&t);   // seconds since the Epoch
+//    t = *localtime(&secondsEpoch);
+//    strftime(buffer, 32, "%j", localtime(&secondsEpoch));
+//    int dayOfYearC = atoi(buffer);
+//
+//    strftime(buffer, 32, "%Y", localtime(&secondsEpoch));
+//    int year = atoi(buffer);
+//
+//    int index  = (year - 2011) * 5;
+//    if (index < 0)
+//        index = 0;
+//    if (index > 440)                    // (2099 - 2011) * 5 = 440
+//        index = 440;
+//    
+//    int monthS = atoi(SummerTime[index+1]);
+//    int dayS   = atoi(SummerTime[index+2]);
+//
+//    t.tm_mon   = monthS - 1;            // adjust for tm structure required values
+//    t.tm_mday  = dayS;
+//    secondsEpoch = mktime(&t);   // seconds since the Epoch
+//    t = *localtime(&secondsEpoch);
+//    strftime(buffer, 32, "%j", localtime(&secondsEpoch));
+//    int dayOfYearS = atoi(buffer);
+//
+//    int monthE = atoi(SummerTime[index+3]);
+//    int dayE   = atoi(SummerTime[index+4]);
+//
+//    t.tm_mon   = monthE - 1;            // adjust for tm structure required values
+//    t.tm_mday  = dayE;
+//    secondsEpoch = mktime(&t);   // seconds since the Epoch
+//    t = *localtime(&secondsEpoch);
+//    strftime(buffer, 32, "%j", localtime(&secondsEpoch));
+//    int dayOfYearE = atoi(buffer);
+//
+//    return ((dayOfYearC >= dayOfYearS) && (dayOfYearC < dayOfYearE)) ? true : false;
+//}
+//
+//int MCP79412::dayOfYearC(void)
+//{
+//    getDateTime(&t);
+//
+//    time_t secondsEpoch = mktime(&t);   // seconds since the Epoch
+//    strftime(buffer, 32, "%j", localtime(&secondsEpoch));
+//    return atoi(buffer);
+//}
+//
+//char * MCP79412::getSunRise(void)
+//{
+//    return (char*) SunRise[dayOfYearC()];
+//}
+//
+//char * MCP79412::getSunSet(void)
+//{
+//    return (char*) SunSet[dayOfYearC()];
+//}
+//
+//char * MCP79412::getDayLength(void)
+//{
+//    return (char*) DayLength[dayOfYearC()];
+//}
+//
+//int MCP79412::getSunRiseMinute(void)
+//{
+//    int doy = dayOfYearC();
+//    int h = atoi(substr((char*)SunRise[doy], 0, 2));
+//    int m = atoi(substr((char*)SunRise[doy], 3, 2));
+//    return h * 60 + m;
+//}
+//
+//int MCP79412::getSunSetMinute(void)
+//{
+//    int doy = dayOfYearC();
+//    int h = atoi(substr((char*)SunSet[doy], 0, 2));
+//    int m = atoi(substr((char*)SunSet[doy], 3, 2));
+//    return h * 60 + m;
+//}
+//
+//bool MCP79412::checkSunRise(void)
+//{
+//    int dayOfWeek, mday, month, year, hours, minutes, seconds;
+//    readDateTime(&dayOfWeek, &mday, &month, &year, &hours, &minutes, &seconds);
+//
+//    int absMinute     = hours * 60 + minutes;
+//    int SunRiseMinute = getSunRiseMinute();
+//    int SunSetMinute  = getSunSetMinute();
+//
+//    return ((absMinute >= SunRiseMinute) && (absMinute < SunSetMinute)) ? true : false;
+//}
+
+
+void MCP79412::substr(char *s, char *d, int pos, int len)
+{
+    char *t;
+    s = s+pos;
+    t = s+len;
+    while (s != t) {
+        *d=*s;
+        s++;
+        d++;
+    }
+    *d='\0';
+}
+
+char * MCP79412::substr(char *s, int pos, int len)
+{
+    char *t;
+    char *d;
+    d = buffer;
+    s = s+pos;
+    t = s+len;
+    while (s != t) {
+        *d=*s;
+        s++;
+        d++;
+    }
+    *d='\0';
+    return buffer;
+}
+
+
+
+
+struct tm MCP79412::setSystemDateTime(
+  uint8_t second,        // 0-59
+  uint8_t minute,        // 0-59
+  uint8_t hour,          // 1-23
+  uint8_t dayOfMonth,    // 1-31
+  uint8_t month,         // 1-12
+  uint8_t year)          // 0-99
+{
+    uint8_t dayOfWeek = 1;          // Will be determined
+    // Convert to unix time structure
+    t->tm_sec   = second;           // 0-59
+    t->tm_min   = minute;           // 0-59
+    t->tm_hour  = hour;             // 0-23
+    t->tm_wday  = dayOfWeek - 1;    // 0-6     (0 = Sunday)
+    t->tm_mday  = dayOfMonth;       // 1-31
+    t->tm_mon   = month - 1;        // 0-11
+    t->tm_year  = year + 100;       // 100-199 year since 1900
+    t->tm_isdst = 0;
+    
+//    printf("-> Debug %d %02d-%02d-%03d %02d:%02d:%02d\n", t->tm_wday, t->tm_mday, t->tm_mon, t->tm_year, t->tm_hour, t->tm_min, t->tm_sec);
+
+    secondsEpoch = mktime(t);   // seconds since the Epoch
+    set_time(secondsEpoch);
+
+    // Get weekday 0-6, Sunday as 0 for RTC
+    t = localtime(&secondsEpoch);
+//    printf("-> Debug %d %02d-%02d-%03d %02d:%02d:%02d\n", t->tm_wday, t->tm_mday, t->tm_mon, t->tm_year, t->tm_hour, t->tm_min, t->tm_sec);
+    return *t;
+}
+
+void MCP79412::getSystemDateTime(
+  uint8_t *second,          // 0-59
+  uint8_t *minute,          // 0-59
+  uint8_t *hour,            // 0-23
+  uint8_t *dayOfWeek,       // 1-7     (1 = Sunday) 
+  uint8_t *dayOfMonth,      // 1-31
+  uint8_t *month,           // 1-12
+  uint8_t *year)            // 0-99 year since 2000
+{
+//    struct tm *t;
+//    time_t secondsEpoch;
+
+    // Get system DateTime
+    secondsEpoch = time(NULL);
+    t = localtime(&secondsEpoch);
+
+    // time/date data
+    *second     = (t->tm_sec);          // 0-59
+    *minute     = (t->tm_min);          // 0-59
+    *hour       = (t->tm_hour);         // 0-23
+    *dayOfWeek  = (t->tm_wday + 1);     // 1-7     (1 = Sunday)
+    *dayOfMonth = (t->tm_mday);         // 1-31
+    *month      = (t->tm_mon + 1);      // 1-12
+    *year       = (t->tm_year - 100);   // 0-99 year since 2000
+}
+
+void MCP79412::setRtcToSystemDateTime(void)
+{
+    // Get system DateTime
+    secondsEpoch = time(NULL);
+    t = localtime(&secondsEpoch);
+
+    // Convert from unix time structure
+    uint8_t second     = (t->tm_sec);           // 0-59
+    uint8_t minute     = (t->tm_min);           // 0-59
+    uint8_t hour       = (t->tm_hour);          // 0-23
+    uint8_t dayOfWeek  = (t->tm_wday + 1);      // 1-7     (1 = Sunday)
+    uint8_t dayOfMonth = (t->tm_mday);          // 1-31
+    uint8_t month      = (t->tm_mon + 1);       // 1-12
+    uint8_t year       = (t->tm_year - 100);    // 0-99 year since 2000
+
+    // Set RTC DateTime
+    setRtcDateTime(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
+}
+
+void MCP79412::setSystemToRtcDateTime(void)
+{
+    // Get RTC DateTime
+    getRtcDateTime(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
+
+    // Convert to unix time structure
+    t->tm_sec   = second;           // 0-59
+    t->tm_min   = minute;           // 0-59
+    t->tm_hour  = hour;             // 0-23
+    t->tm_wday  = dayOfWeek - 1;    // 0-6     (0 = Sunday)
+    t->tm_mday  = dayOfMonth;       // 1-31
+    t->tm_mon   = month - 1;        // 0-11
+    t->tm_year  = year + 100;       // 100-199 year since 1900
+    t->tm_isdst = 0;
+    
+    // Set system DateTime
+    secondsEpoch = mktime(t);   // seconds since the Epoch
+    set_time(secondsEpoch);
+}
+
+void MCP79412::setRtcFromTm(struct tm *t)
+{
+//    // Get system DateTime
+//    secondsEpoch = time(NULL);
+//    t = localtime(&secondsEpoch);
+
+    // Convert from unix time structure
+    uint8_t second     = (t->tm_sec);           // 0-59
+    uint8_t minute     = (t->tm_min);           // 0-59
+    uint8_t hour       = (t->tm_hour);          // 0-23
+    uint8_t dayOfWeek  = (t->tm_wday + 1);      // 1-7     (1 = Sunday)
+    uint8_t dayOfMonth = (t->tm_mday);          // 1-31
+    uint8_t month      = (t->tm_mon + 1);       // 1-12
+    uint8_t year       = (t->tm_year - 100);    // 0-99 year since 2000
+
+//    printf("setRtcFromTm %d %02d-%02d-%03d %02d:%02d:%02d\n", dayOfWeek, dayOfMonth, month, year, hour, minute, second);
+
+    // Set RTC DateTime
+    setRtcDateTime(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
+}
+
+struct tm MCP79412::getTmFromRtc(void)
+{
+    // Get RTC DateTime
+    getRtcDateTime(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
+
+    // Convert to unix time structure
+    t->tm_sec   = second;           // 0-59
+    t->tm_min   = minute;           // 0-59
+    t->tm_hour  = hour;             // 0-23
+    t->tm_wday  = dayOfWeek - 1;    // 0-6     (0 = Sunday)
+    t->tm_mday  = dayOfMonth;       // 1-31
+    t->tm_mon   = month - 1;        // 0-11
+    t->tm_year  = year + 100;       // 100-199 year since 1900
+    t->tm_isdst = 0;
+    
+    return *t;
+//    // Set system DateTime
+//    secondsEpoch = mktime(t);   // seconds since the Epoch
+//    set_time(secondsEpoch);
+}
+
+time_t MCP79412::getSecondsEpoch(void)
+{
+    secondsEpoch = time(NULL);
+    return secondsEpoch;
+}
+
+void MCP79412::setSecondsEpoch(time_t t)
+{
+    secondsEpoch = t;
+    set_time(secondsEpoch);
+}
+
+void MCP79412::getRtcDateTimeAsTm(void)
+{
+    // Get RTC DateTime
+    getRtcDateTime(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
+
+    // Convert to unix time structure
+    t->tm_sec   = second;           // 0-59
+    t->tm_min   = minute;           // 0-59
+    t->tm_hour  = hour;             // 0-23
+    t->tm_wday  = dayOfWeek - 1;    // 0-6     (0 = Sunday)
+    t->tm_mday  = dayOfMonth;       // 1-31
+    t->tm_mon   = month - 1;        // 0-11
+    t->tm_year  = year + 100;       // 100-199 year since 1900
+    t->tm_isdst = 0;
+    
+    // Set system DateTime
+    secondsEpoch = mktime(t);   // seconds since the Epoch
+//    time_t t = time(secondsEpoch);
+    
+//    set_time(secondsEpoch);
+}
+
+time_t MCP79412::convertDateTimeToTimestamp(
+  uint8_t second,        // 0-59
+  uint8_t minute,        // 0-59
+  uint8_t hour,          // 0-23
+  uint8_t dayOfMonth,    // 1-31
+  uint8_t month,         // 1-12
+  uint8_t year)          // 0-99 year since 2000
+{
+    // setup time structure for Wed, 28 Oct 2009 11:35:37
+    struct tm t;
+    t.tm_sec  = second;         // 0-59
+    t.tm_min  = minute;         // 0-59
+    t.tm_hour = hour;           // 0-23
+    t.tm_mday = dayOfMonth;     // 1-31
+    t.tm_mon  = month - 1;      // 0-11
+    t.tm_year = year + 100;     // 100-199 year since 1900
+
+//    printf("Debug %d %02d-%02d-%03d %02d:%02d:%02d\n", t.tm_wday, t.tm_mday, t.tm_mon, t.tm_year, t.tm_hour, t.tm_min, t.tm_sec);
+
+    // convert to timestamp and display (1256729737)
+    time_t seconds = mktime(&t);
+//    printf("Time as seconds since January 1, 1970 = %d\n", seconds);
+
+//    char buffer[32];
+//    strftime(buffer, 32, "%a %d-%m-%Y %H:%M:%S\n", localtime(&seconds));
+//    printf("Time: %s", buffer);
+
+    // Get weekday Sunday as 0 (0-6) for RTC
+    struct tm *t2;
+    t2 = localtime(&seconds);
+//    printf("Debug %d %02d-%02d-%03d %02d:%02d:%02d\n", t.tm_wday, t2->tm_mday, t2->tm_mon, t2->tm_year, t2->tm_hour, t2->tm_min, t2->tm_sec);
+//    printf("Weekday %d\n", t2->tm_wday);
+
+    return seconds;
+}
+
+uint8_t MCP79412::getWeekdayFromDate(uint8_t dayOfMonth, uint8_t month, uint8_t year)          // year 0-99
+{
+    // setup time structure for Wed, 28 Oct 2009 11:35:37
+    struct tm t;
+    t.tm_sec  = 0;              // 0-59
+    t.tm_min  = 0;              // 0-59
+    t.tm_hour = 0;              // 0-23
+    t.tm_mday = dayOfMonth;     // 1-31
+    t.tm_mon  = month - 1;      // 0-11
+    t.tm_year = year + 100;     // 100-199 year since 1900
+
+//    printf("Debug %d %02d:%02d:%02d %02d-%02d-%02d\n", t.tm_wday, t.tm_mday, t.tm_mon, t.tm_year, t.tm_hour, t.tm_min, t.tm_sec);
+
+    // convert to timestamp and display (1256729737)
+    time_t seconds = mktime(&t);
+//    printf("Time as seconds since January 1, 1970 = %d\n", seconds);
+
+//    char buffer[32];
+//    strftime(buffer, 32, "%a %d-%m-%Y %H:%M:%S\n", localtime(&seconds));
+//    printf("Time: %s", buffer);
+
+    // Get weekday Sunday as 0 (0-6) for RTC
+    struct tm *t2;
+    t2 = localtime(&seconds);
+//    printf("Debug %d %02d-%02d-%03d %02d:%02d:%02d\n", t2->tm_wday, t2->tm_mday, t2->tm_mon, t2->tm_year, t2->tm_hour, t2->tm_min, t2->tm_sec);
+//    printf("Weekday %d\n", t2->tm_wday);
+
+    return t2->tm_wday;
+}
+
+
+
+
+
+
+
+
+//double MCP79412::clamp(double v)
+//{
+//    const double t = v < 0.0f ? 0.0f : v;
+//    return t > 1.0f ? 1.0f : t;
+//}
+
+
+//bool MCP79412::checkTimeLost(void)
+//{
+////    return (atoi(getFormatedDateTime("%Y")) <= 2015) ? true : false;
+//    return false;
+//}
+
+//
+///*----------------------------------------------------------------------*
+// * Read the current time from the RTC and return it in a tmElements_t   *
+// * structure. Returns false if RTC not present (I2C I/O error).         *
+// *----------------------------------------------------------------------*/
+//boolean MCP79412RTC::read(tmElements_t &tm)
+//{
+//    i2cBeginTransmission(RTC_ADDR);
+//    i2cWrite((uint8_t)TIME_REG);
+//    if (i2cEndTransmission() != 0) {
+//        return false;
+//    }
+//    else {
+//        //request 7 uint8_ts (secs, min, hr, dow, date, mth, yr)
+//        i2cRequestFrom(RTC_ADDR, tmNbrFields);
+//        tm.Second = bcd2dec(i2cRead() & ~_BV(ST));
+//        tm.Minute = bcd2dec(i2cRead());
+//        tm.Hour = bcd2dec(i2cRead() & ~_BV(HR1224));    //assumes 24hr clock
+//        tm.Wday = i2cRead() & ~(_BV(OSCON) | _BV(VBAT) | _BV(VBATEN));    //mask off OSCON, VBAT, VBATEN bits
+//        tm.Day = bcd2dec(i2cRead());
+//        tm.Month = bcd2dec(i2cRead() & ~_BV(LP));       //mask off the leap year bit
+//        tm.Year = y2kYearToTm(bcd2dec(i2cRead()));
+//        return true;
+//    }
+//}
+//
+///*----------------------------------------------------------------------*
+// * Set the RTC's time from a tmElements_t structure.                    *
+// *----------------------------------------------------------------------*/
+//void MCP79412RTC::write(tmElements_t &tm)
+//{
+//    i2cBeginTransmission(RTC_ADDR);
+//    i2cWrite((uint8_t)TIME_REG);
+//    i2cWrite((uint8_t)0x00);                     //stops the oscillator (Bit 7, ST == 0)
+//    i2cWrite(dec2bcd(tm.Minute));
+//    i2cWrite(dec2bcd(tm.Hour));                  //sets 24 hour format (Bit 6 == 0)
+//    i2cWrite(tm.Wday | _BV(VBATEN));             //enable battery backup operation
+//    i2cWrite(dec2bcd(tm.Day));
+//    i2cWrite(dec2bcd(tm.Month));
+//    i2cWrite(dec2bcd(tmYearToY2k(tm.Year)));
+//    i2cEndTransmission();
+//
+//    i2cBeginTransmission(RTC_ADDR);
+//    i2cWrite((uint8_t)TIME_REG);
+//    i2cWrite(dec2bcd(tm.Second) | _BV(ST));    //set the seconds and start the oscillator (Bit 7, ST == 1)
+//    i2cEndTransmission();
+//}
+//
+///*----------------------------------------------------------------------*
+// * Write a single uint8_t to RTC RAM.                                      *
+// * Valid address range is 0x00 - 0x5F, no checking.                     *
+// *----------------------------------------------------------------------*/
+//void MCP79412RTC::ramWrite(uint8_t addr, uint8_t value)
+//{
+//    ramWrite(addr, &value, 1);
+//}
+//
+///*----------------------------------------------------------------------*
+// * Write multiple uint8_ts to RTC RAM.                                     *
+// * Valid address range is 0x00 - 0x5F, no checking.                     *
+// * Number of uint8_ts (nuint8_ts) must be between 1 and 31 (Wire library      *
+// * limitation).                                                         *
+// *----------------------------------------------------------------------*/
+//void MCP79412RTC::ramWrite(uint8_t addr, uint8_t *values, uint8_t nuint8_ts)
+//{
+//    i2cBeginTransmission(RTC_ADDR);
+//    i2cWrite(addr);
+//    for (uint8_t i=0; i<nuint8_ts; i++) i2cWrite(values[i]);
+//    i2cEndTransmission();
+//}
+//
+///*----------------------------------------------------------------------*
+// * Read a single uint8_t from RTC RAM.                                     *
+// * Valid address range is 0x00 - 0x5F, no checking.                     *
+// *----------------------------------------------------------------------*/
+//uint8_t MCP79412RTC::ramRead(uint8_t addr)
+//{
+//    uint8_t value;
+//
+//    ramRead(addr, &value, 1);
+//    return value;
+//}
+//
+///*----------------------------------------------------------------------*
+// * Read multiple uint8_ts from RTC RAM.                                    *
+// * Valid address range is 0x00 - 0x5F, no checking.                     *
+// * Number of uint8_ts (nuint8_ts) must be between 1 and 32 (Wire library      *
+// * limitation).                                                         *
+// *----------------------------------------------------------------------*/
+//void MCP79412RTC::ramRead(uint8_t addr, uint8_t *values, uint8_t nuint8_ts)
+//{
+//    i2cBeginTransmission(RTC_ADDR);
+//    i2cWrite(addr);
+//    i2cEndTransmission();
+//    i2cRequestFrom( (uint8_t)RTC_ADDR, nuint8_ts );
+//    for (uint8_t i=0; i<nuint8_ts; i++) values[i] = i2cRead();
+//}
+//
+///*----------------------------------------------------------------------*
+// * Write a single uint8_t to Static RAM.                                   *
+// * Address (addr) is constrained to the range (0, 63).                  *
+// *----------------------------------------------------------------------*/
+//void MCP79412RTC::sramWrite(uint8_t addr, uint8_t value)
+//{
+//    ramWrite( (addr & (SRAM_SIZE - 1) ) + SRAM_START_ADDR, &value, 1 );
+//}
+//
+///*----------------------------------------------------------------------*
+// * Write multiple uint8_ts to Static RAM.                                  *
+// * Address (addr) is constrained to the range (0, 63).                  *
+// * Number of uint8_ts (nuint8_ts) must be between 1 and 31 (Wire library      *
+// * limitation).                                                         *
+// * Invalid values for nuint8_ts, or combinations of addr and nuint8_ts        *
+// * that would result in addressing past the last uint8_t of SRAM will      *
+// * result in no action.                                                 *
+// *----------------------------------------------------------------------*/
+//void MCP79412RTC::sramWrite(uint8_t addr, uint8_t *values, uint8_t nuint8_ts)
+//{
+//#if defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
+//    if (nuint8_ts >= 1 && (addr + nuint8_ts) <= SRAM_SIZE) {
+//#else
+//    if (nuint8_ts >= 1 && nuint8_ts <= (BUFFER_LENGTH - 1) && (addr + nuint8_ts) <= SRAM_SIZE) {
+//#endif
+//        ramWrite( (addr & (SRAM_SIZE - 1) ) + SRAM_START_ADDR, values, nuint8_ts );
+//    }
+//}
+//
+///*----------------------------------------------------------------------*
+// * Read a single uint8_t from Static RAM.                                  *
+// * Address (addr) is constrained to the range (0, 63).                  *
+// *----------------------------------------------------------------------*/
+//uint8_t MCP79412RTC::sramRead(uint8_t addr)
+//{
+//    uint8_t value;
+//
+//    ramRead( (addr & (SRAM_SIZE - 1) ) + SRAM_START_ADDR, &value, 1 );
+//    return value;
+//}
+//
+///*----------------------------------------------------------------------*
+// * Read multiple uint8_ts from Static RAM.                                 *
+// * Address (addr) is constrained to the range (0, 63).                  *
+// * Number of uint8_ts (nuint8_ts) must be between 1 and 32 (Wire library      *
+// * limitation).                                                         *
+// * Invalid values for nuint8_ts, or combinations of addr and               *
+// * nuint8_ts that would result in addressing past the last uint8_t of SRAM    *
+// * result in no action.                                                 *
+// *----------------------------------------------------------------------*/
+//void MCP79412RTC::sramRead(uint8_t addr, uint8_t *values, uint8_t nuint8_ts)
+//{
+//#if defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
+//    if (nuint8_ts >= 1 && (addr + nuint8_ts) <= SRAM_SIZE) {
+//#else
+//    if (nuint8_ts >= 1 && nuint8_ts <= BUFFER_LENGTH && (addr + nuint8_ts) <= SRAM_SIZE) {
+//#endif
+//        ramRead((addr & (SRAM_SIZE - 1) ) + SRAM_START_ADDR, values, nuint8_ts);
+//    }
+//}
+//
+///*----------------------------------------------------------------------*
+// * Write a single uint8_t to EEPROM.                                       *
+// * Address (addr) is constrained to the range (0, 127).                 *
+// * Can't leverage page write function because a write can't start       *
+// * mid-page.                                                            *
+// *----------------------------------------------------------------------*/
+//void MCP79412RTC::eepromWrite(uint8_t addr, uint8_t value)
+//{
+//    i2cBeginTransmission(MCP79412_EEPROM_ADDR);
+//    i2cWrite( addr & (EEPROM_SIZE - 1) );
+//    i2cWrite(value);
+//    i2cEndTransmission();
+//    eepromWait();
+//}
+//
+///*----------------------------------------------------------------------*
+// * Write a page (or less) to EEPROM. An EEPROM page is 8 uint8_ts.         *
+// * Address (addr) should be a page start address (0, 8, ..., 120), but  *
+// * is ruthlessly coerced into a valid value.                            *
+// * Number of uint8_ts (nuint8_ts) must be between 1 and 8, other values       *
+// * result in no action.                                                 *
+// *----------------------------------------------------------------------*/
+//void MCP79412RTC::eepromWrite(uint8_t addr, uint8_t *values, uint8_t nuint8_ts)
+//{
+//    if (nuint8_ts >= 1 && nuint8_ts <= EEPROM_PAGE_SIZE) {
+//        i2cBeginTransmission(MCP79412_EEPROM_ADDR);
+//        i2cWrite( addr & ~(EEPROM_PAGE_SIZE - 1) & (EEPROM_SIZE - 1) );
+//        for (uint8_t i=0; i<nuint8_ts; i++) i2cWrite(values[i]);
+//        i2cEndTransmission();
+//        eepromWait();
+//    }
+//}
+//
+///*----------------------------------------------------------------------*
+// * Read a single uint8_t from EEPROM.                                      *
+// * Address (addr) is constrained to the range (0, 127).                  *
+// *----------------------------------------------------------------------*/
+//uint8_t MCP79412RTC::eepromRead(uint8_t addr)
+//{
+//    uint8_t value;
+//
+//    eepromRead( addr & (EEPROM_SIZE - 1), &value, 1 );
+//    return value;
+//}
+//
+///*----------------------------------------------------------------------*
+// * Read multiple uint8_ts from EEPROM.                                     *
+// * Address (addr) is constrained to the range (0, 127).                 *
+// * Number of uint8_ts (nuint8_ts) must be between 1 and 32 (Wire library      *
+// * limitation).                                                         *
+// * Invalid values for addr or nuint8_ts, or combinations of addr and       *
+// * nuint8_ts that would result in addressing past the last uint8_t of EEPROM  *
+// * result in no action.                                                 *
+// *----------------------------------------------------------------------*/
+//void MCP79412RTC::eepromRead(uint8_t addr, uint8_t *values, uint8_t nuint8_ts)
+//{
+//#if defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
+//    if (nuint8_ts >= 1 && (addr + nuint8_ts) <= EEPROM_SIZE) {
+//#else
+//    if (nuint8_ts >= 1 && nuint8_ts <= BUFFER_LENGTH && (addr + nuint8_ts) <= EEPROM_SIZE) {
+//#endif
+//        i2cBeginTransmission(MCP79412_EEPROM_ADDR);
+//        i2cWrite( addr & (EEPROM_SIZE - 1) );
+//        i2cEndTransmission();
+//        i2cRequestFrom( (uint8_t)MCP79412_EEPROM_ADDR, nuint8_ts );
+//        for (uint8_t i=0; i<nuint8_ts; i++) values[i] = i2cRead();
+//    }
+//}
+//
+///*----------------------------------------------------------------------*
+// * Wait for EEPROM write to complete.                                   *
+// *----------------------------------------------------------------------*/
+//uint8_t MCP79412RTC::eepromWait(void)
+//{
+//    uint8_t waitCount = 0;
+//    uint8_t txStatus;
+//
+//    do
+//    {
+//        ++waitCount;
+//        i2cBeginTransmission(MCP79412_EEPROM_ADDR);
+//        i2cWrite((uint8_t)0);
+//        txStatus = i2cEndTransmission();
+//
+//    } while (txStatus != 0);
+//
+//    return waitCount;
+//}
+//
+///*----------------------------------------------------------------------*
+// * Read the calibration register.                                       *
+// * The calibration value is not a twos-complement number. The MSB is    *
+// * the sign bit, and the 7 LSBs are an unsigned number, so we convert   *
+// * it and return it to the caller as a regular twos-complement integer. *
+// *----------------------------------------------------------------------*/
+//int MCP79412RTC::calibRead(void)
+//{
+//    uint8_t val = ramRead(CALIB_REG);
+//
+//    if ( val & 0x80 ) return -(val & 0x7F);
+//    else return val;
+//}
+//
+///*----------------------------------------------------------------------*
+// * Write the calibration register.                                      *
+// * Calibration value must be between -127 and 127, others result        *
+// * in no action. See note above on the format of the calibration value. *
+// *----------------------------------------------------------------------*/
+//void MCP79412RTC::calibWrite(int value)
+//{
+//    uint8_t calibVal;
+//
+//    if (value >= -127 && value <= 127) {
+//        calibVal = abs(value);
+//        if (value < 0) calibVal += 128;
+//        ramWrite(CALIB_REG, calibVal);
+//    }
+//}
+//
+///*----------------------------------------------------------------------*
+// * Read the unique ID.                                                  *
+// * For the MCP79411 (EUI-48), the first two uint8_ts will contain 0xFF.    *
+// * Caller must provide an 8-uint8_t array to contain the results.          *
+// *----------------------------------------------------------------------*/
+//void MCP79412RTC::idRead(uint8_t *uniqueID)
+//{
+//    i2cBeginTransmission(MCP79412_EEPROM_ADDR);
+//    i2cWrite(UNIQUE_ID_ADDR);
+//    i2cEndTransmission();
+//    i2cRequestFrom( MCP79412_EEPROM_ADDR, UNIQUE_ID_SIZE );
+//    for (uint8_t i=0; i<UNIQUE_ID_SIZE; i++) uniqueID[i] = i2cRead();
+//}
+//
+///*----------------------------------------------------------------------*
+// * Returns an EUI-64 ID. For an MCP79411, the EUI-48 ID is converted to *
+// * EUI-64. For an MCP79412, calling this function is equivalent to      *
+// * calling idRead(). For an MCP79412, if the RTC type is known, calling *
+// * idRead() will be a bit more efficient.                               *
+// * Caller must provide an 8-uint8_t array to contain the results.          *
+// *----------------------------------------------------------------------*/
+//void MCP79412RTC::getEUI64(uint8_t *uniqueID)
+//{
+//    uint8_t rtcID[8];
+//
+//    idRead(rtcID);
+//    if (rtcID[0] == 0xFF && rtcID[1] == 0xFF) {
+//        rtcID[0] = rtcID[2];
+//        rtcID[1] = rtcID[3];
+//        rtcID[2] = rtcID[4];
+//        rtcID[3] = 0xFF;
+//        rtcID[4] = 0xFE;
+//    }
+//    for (uint8_t i=0; i<UNIQUE_ID_SIZE; i++) uniqueID[i] = rtcID[i];
+//}
+//
+///*----------------------------------------------------------------------*
+// * Check to see if a power failure has occurred. If so, returns TRUE    *
+// * as the function value, and returns the power down and power up       *
+// * timestamps. After returning the time stamps, the RTC's timestamp     *
+// * registers are cleared and the VBAT bit which indicates a power       *
+// * failure is reset.                                                    *
+// *                                                                      *
+// * Note that the power down and power up timestamp registers do not     *
+// * contain values for seconds or for the year. The returned time stamps *
+// * will therefore contain the current year from the RTC. However, there *
+// * is a chance that a power outage spans from one year to the next.     *
+// * If we find the power down timestamp to be later (larger) than the    *
+// * power up timestamp, we will assume this has happened, and well       *
+// * subtract one year from the power down timestamp.                     *
+// *                                                                      *
+// * Still, there is an assumption that the timestamps are being read     *
+// * in the same year as that when the power up occurred.                 *
+// *                                                                      *
+// * Finally, note that once the RTC records a power outage, it must be   *
+// * cleared before another will be recorded.                             *
+// *----------------------------------------------------------------------*/
+//boolean MCP79412RTC::powerFail(time_t *powerDown, time_t *powerUp)
+//{
+//    uint8_t day, yr;                   //copies of the RTC Day and Year registers
+//    tmElements_t dn, up;            //power down and power up times
+//
+//    ramRead(DAY_REG, &day, 1);
+//    ramRead(YEAR_REG, &yr, 1);
+//    yr = y2kYearToTm(bcd2dec(yr));
+//    if ( day & _BV(VBAT) ) {
+//        i2cBeginTransmission(RTC_ADDR);
+//        i2cWrite(PWRDWN_TS_REG);
+//        i2cEndTransmission();
+//
+//        i2cRequestFrom(RTC_ADDR, TIMESTAMP_SIZE);     //read both timestamp registers, 8 uint8_ts total
+//        dn.Second = 0;
+//        dn.Minute = bcd2dec(i2cRead());
+//        dn.Hour = bcd2dec(i2cRead() & ~_BV(HR1224));    //assumes 24hr clock
+//        dn.Day = bcd2dec(i2cRead());
+//        dn.Month = bcd2dec(i2cRead() & 0x1F);           //mask off the day, we don't need it
+//        dn.Year = yr;                                   //assume current year
+//        up.Second = 0;
+//        up.Minute = bcd2dec(i2cRead());
+//        up.Hour = bcd2dec(i2cRead() & ~_BV(HR1224));    //assumes 24hr clock
+//        up.Day = bcd2dec(i2cRead());
+//        up.Month = bcd2dec(i2cRead() & 0x1F);           //mask off the day, we don't need it
+//        up.Year = yr;                                   //assume current year
+//
+//        *powerDown = makeTime(dn);
+//        *powerUp = makeTime(up);
+//
+//        //clear the VBAT bit, which causes the RTC hardware to clear the timestamps too.
+//        //I suppose there is a risk here that the day has changed since we read it,
+//        //but the Day of Week is actually redundant data and the makeTime() function
+//        //does not use it. This could be an issue if someone is reading the RTC
+//        //registers directly, but as this library is meant to be used with the Time library,
+//        //and also because we don't provide a method to read the RTC clock/calendar
+//        //registers directly, we won't lose any sleep about it at this point unless
+//        //some issue is actually brought to our attention ;-)
+//        day &= ~_BV(VBAT);
+//        ramWrite(DAY_REG, &day , 1);
+//
+//        //adjust the powerDown timestamp if needed (see notes above)
+//        if (*powerDown > *powerUp) {
+//            --dn.Year;
+//            *powerDown = makeTime(dn);
+//        }
+//        return true;
+//    }
+//    else
+//        return false;
+//}
+//
+///*----------------------------------------------------------------------*
+// * Enable or disable the square wave output.                            *
+// *----------------------------------------------------------------------*/
+//void MCP79412RTC::squareWave(uint8_t freq)
+//{
+//    uint8_t ctrlReg;
+//
+//    ramRead(CTRL_REG, &ctrlReg, 1);
+//    if (freq > 3) {
+//        ctrlReg &= ~_BV(SQWE);
+//    }
+//    else {
+//        ctrlReg = (ctrlReg & 0xF8) | _BV(SQWE) | freq;
+//    }
+//    ramWrite(CTRL_REG, &ctrlReg, 1);
+//}
+//
+///*----------------------------------------------------------------------*
+// * Set an alarm time. Sets the alarm registers only, does not enable    *
+// * the alarm. See enableAlarm().                                        *
+// *----------------------------------------------------------------------*/
+//void MCP79412RTC::setAlarm(uint8_t alarmNumber, time_t alarmTime)
+//{
+//    tmElements_t tm;
+//    uint8_t day;        //need to preserve bits in the day (of week) register
+//
+//    alarmNumber &= 0x01;        //ensure a valid alarm number
+//    ramRead( ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG) , &day, 1);
+//    breakTime(alarmTime, tm);
+//    i2cBeginTransmission(RTC_ADDR);
+//    i2cWrite( ALM0_REG + alarmNumber * (ALM1_REG - ALM0_REG) );
+//    i2cWrite(dec2bcd(tm.Second));
+//    i2cWrite(dec2bcd(tm.Minute));
+//    i2cWrite(dec2bcd(tm.Hour));                  //sets 24 hour format (Bit 6 == 0)
+//    i2cWrite( (day & 0xF8) + tm.Wday );
+//    i2cWrite(dec2bcd(tm.Day));
+//    i2cWrite(dec2bcd(tm.Month));
+//    i2cEndTransmission();
+//}
+//
+///*----------------------------------------------------------------------*
+// * Enable or disable an alarm, and set the trigger criteria,            *
+// * e.g. match only seconds, only minutes, entire time and date, etc.    *
+// *----------------------------------------------------------------------*/
+//void MCP79412RTC::enableAlarm(uint8_t alarmNumber, uint8_t alarmType)
+//{
+//    uint8_t day;                //alarm day register has config & flag bits
+//    uint8_t ctrl;               //control register has alarm enable bits
+//
+//    alarmNumber &= 0x01;        //ensure a valid alarm number
+//    ramRead(CTRL_REG, &ctrl, 1);
+//    if (alarmType < ALM_DISABLE) {
+//        ramRead(ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG), &day, 1);
+//        day = ( day & 0x87 ) | alarmType << 4;  //reset interrupt flag, OR in the config bits
+//        ramWrite(ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG), &day, 1);
+//        ctrl |= _BV(ALM0 + alarmNumber);        //enable the alarm
+//    }
+//    else {
+//        ctrl &= ~(_BV(ALM0 + alarmNumber));     //disable the alarm
+//    }
+//    ramWrite(CTRL_REG, &ctrl, 1);
+//}
+//
+///*----------------------------------------------------------------------*
+// * Returns true or false depending on whether the given alarm has been  *
+// * triggered, and resets the alarm "interrupt" flag. This is not a real *
+// * interrupt, just a bit that's set when an alarm is triggered.         *
+// *----------------------------------------------------------------------*/
+//boolean MCP79412RTC::alarm(uint8_t alarmNumber)
+//{
+//    uint8_t day;                //alarm day register has config & flag bits
+//
+//    alarmNumber &= 0x01;        //ensure a valid alarm number
+//    ramRead( ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG), &day, 1);
+//    if (day & _BV(ALMIF)) {
+//        day &= ~_BV(ALMIF);     //turn off the alarm "interrupt" flag
+//        ramWrite( ALM0_DAY + alarmNumber * (ALM1_REG - ALM0_REG), &day, 1);
+//        return true;
+//    }
+//    else
+//        return false;
+//}
+//
+///*----------------------------------------------------------------------*
+// * Sets the logic level on the MFP when it's not being used as a        *
+// * square wave or alarm output. The default is HIGH.                    *
+// *----------------------------------------------------------------------*/
+//void MCP79412RTC::out(boolean level)
+//{
+//    uint8_t ctrlReg;
+//
+//    ramRead(CTRL_REG, &ctrlReg, 1);
+//    if (level)
+//        ctrlReg |= _BV(OUT);
+//    else
+//        ctrlReg &= ~_BV(OUT);
+//    ramWrite(CTRL_REG, &ctrlReg, 1);
+//}
+//
+///*----------------------------------------------------------------------*
+// * Specifies the logic level on the Multi-Function Pin (MFP) when an    *
+// * alarm is triggered. The default is LOW. When both alarms are         *
+// * active, the two are ORed together to determine the level of the MFP. *
+// * With alarm polarity set to LOW (the default), this causes the MFP    *
+// * to go low only when BOTH alarms are triggered. With alarm polarity   *
+// * set to HIGH, the MFP will go high when EITHER alarm is triggered.    *
+// *                                                                      *
+// * Note that the state of the MFP is independent of the alarm           *
+// * "interrupt" flags, and the alarm() function will indicate when an    *
+// * alarm is triggered regardless of the polarity.                       *
+// *----------------------------------------------------------------------*/
+//void MCP79412RTC::alarmPolarity(boolean polarity)
+//{
+//    uint8_t alm0Day;
+//
+//    ramRead(ALM0_DAY, &alm0Day, 1);
+//    if (polarity)
+//        alm0Day |= _BV(OUT);
+//    else
+//        alm0Day &= ~_BV(OUT);
+//    ramWrite(ALM0_DAY, &alm0Day, 1);
+//}
+//
+///*----------------------------------------------------------------------*
+// * Check to see if the RTC's oscillator is started (ST bit in seconds   *
+// * register). Returns true if started.                                  *
+// *----------------------------------------------------------------------*/
+//boolean MCP79412RTC::isRunning(void)
+//{
+//    i2cBeginTransmission(RTC_ADDR);
+//    i2cWrite((uint8_t)TIME_REG);
+//    i2cEndTransmission();
+//
+//    //request just the seconds register
+//    i2cRequestFrom(RTC_ADDR, 1);
+//    return i2cRead() & _BV(ST);
+//}
+//
+///*----------------------------------------------------------------------*
+// * Set or clear the VBATEN bit. Setting the bit powers the clock and    *
+// * SRAM from the backup battery when Vcc falls. Note that setting the   *
+// * time via set() or write() sets the VBATEN bit.                       *
+// *----------------------------------------------------------------------*/
+//void MCP79412RTC::vbaten(boolean enable)
+//{
+//    uint8_t day;
+//
+//    ramRead(DAY_REG, &day, 1);
+//    if (enable)
+//        day |= _BV(VBATEN);
+//    else
+//        day &= ~_BV(VBATEN);
+//
+//    ramWrite(DAY_REG, &day, 1);
+//    return;
+//}
+
+///*----------------------------------------------------------------------*
+// * Decimal-to-BCD conversion                                            *
+// *----------------------------------------------------------------------*/
+//uint8_t MCP79412RTC::dec2bcd(uint8_t n)
+//{
+//    return n + 6 * (n / 10);
+//}
+//
+///*----------------------------------------------------------------------*
+// * BCD-to-Decimal conversion                                            *
+// *----------------------------------------------------------------------*/
+//uint8_t __attribute__ ((noinline)) MCP79412RTC::bcd2dec(uint8_t n)
+//{
+//    return n - 6 * (n >> 4);
+//}
+
+// BCD to decimal conversion
+int MCP79412::bcd2dec(int bcd)
+{
+    return(((bcd & 0xF0) >> 4) * 10 + (bcd & 0x0F));
+}
+
+// decimal to BCD conversion
+int MCP79412::dec2bcd(int dec)
+{
+    return((dec / 10) * 16 + (dec % 10));
+}
+
+// Convert normal decimal numbers to binary coded decimal:
+int MCP79412::decToBcd(int val)
+{
+  return ( (val/10*16) + (val%10) );
+}
+
+// Convert binary coded decimal to normal decimal numbers:
+int MCP79412::bcdToDec(int val)
+{
+  return ( (val/16*10) + (val%16) );
+}
diff -r 000000000000 -r 04311b121ac4 MCP79412.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MCP79412.h	Mon Jul 23 12:24:33 2018 +0000
@@ -0,0 +1,345 @@
+/** mbded library for driving the PMAXIM DS3231 Real Time Clock
+* datasheet link : http://datasheets.maximintegrated.com/en/ds/DS3231.pdf
+* breakout       : MACETECH ChronoDot V2.1 High Precision RTC
+* remi cormier 2012
+* WARNING : sda and sdl should be pulled up with 2.2k resistor
+*/
+
+/** Example code
+* @code
+// DS3231 Library test program
+// remi cormier 2012
+
+#include "mbed.h"
+#include "DS3231.h"
+
+Serial pc(USBTX, USBRX);
+
+int hour;
+int minute;
+int second;
+
+int dayOfWeek;
+int date;
+int month;
+int year;  
+   
+DS3231 RTC(p28,p27);
+
+
+int main()
+    {printf("\r\n\nDS3231 Library test program\r\nremi cormier 2012\r\n\n");
+    
+     RTC.setI2Cfrequency(400000);
+    
+     //RTC.writeRegister(DS3231_Aging_Offset,0); // uncomment to set Aging Offset 1LSB = approx. 0.1 ppm according from datasheet = 0.05 ppm @ 21 °C from my measurments
+     
+     RTC.convertTemperature();
+      
+     int reg=RTC.readRegister(DS3231_Aging_Offset);
+     if (reg>127)
+        {reg=reg-256;}
+     pc.printf("Aging offset : %i\r\n",reg);
+         
+     pc.printf("OSF flag : %i",RTC.OSF());
+     pc.printf("\r\n");
+     
+     RTC.readDate(&date,&month,&year);
+     pc.printf("date : %02i-%02i-%02i",date,month,year);
+     pc.printf("\r\n");
+     
+     //RTC.setTime(19,48,45); // uncomment to set time
+     
+     RTC.readTime(&hour,&minute,&second);
+     pc.printf("time : %02i:%02i:%02i",hour,minute,second);
+     pc.printf("\r\n");
+     
+     //RTC.setDate(6,22,12,2012); // uncomment to set date
+     
+     RTC.readDateTime(&dayOfWeek,&date,&month,&year,&hour,&minute,&second);
+     pc.printf("date time : %i / %02i-%02i-%02i %02i:%02i:%02i",dayOfWeek,date,month,year,hour,minute,second);
+     pc.printf("\r\n");
+     
+     pc.printf("temperature :%6.2f",RTC.readTemp());
+     pc.printf("\r\n");
+    }
+* @endcode
+*/
+
+/*
+http://www.cplusplus.com/reference/ctime/strftime/
+%a   Abbreviated weekday name *  Thu
+%A   Full weekday name * Thursday
+%b   Abbreviated month name *    Aug
+%B   Full month name *   August
+%d   Day of the month, zero-padded (01-31)   23
+%e   Day of the month, space-padded ( 1-31)  23
+%F   Short YYYY-MM-DD date, equivalent to %Y-%m-%d   2001-08-23
+%H   Hour in 24h format (00-23)  14
+%j   Day of the year (001-366)   235
+%m   Month as a decimal number (01-12)   08
+%M   Minute (00-59)  55
+%R   24-hour HH:MM time, equivalent to %H:%M 14:55
+%S   Second (00-61)  02
+%T   ISO 8601 time format (HH:MM:SS), equivalent to %H:%M:%S 14:55:02
+%u   ISO 8601 weekday as number with Monday as 1 (1-7)   4
+%V   ISO 8601 week number (00-53)    34
+%w   Weekday as a decimal number with Sunday as 0 (0-6)  4
+%W   Week number with the first Monday as the first day of week one (00-53)  34
+%X   Time representation *   14:55:02
+%y   Year, last two digits (00-99)   01
+%Y   Year    2001
+
+http://www.cplusplus.com/reference/ctime/tm/
+Member   Type    Meaning                        Range
+tm_sec   int     seconds after the minute       0-61*
+tm_min   int     minutes after the hour         0-59
+tm_hour  int     hours since midnight           0-23
+tm_mday  int     day of the month               1-31
+tm_mon   int     months since January           0-11
+tm_year  int     years since 1900    
+tm_wday  int     days since Sunday              0-6     (0 = Sunday)
+tm_yday  int     days since January 1           0-365
+tm_isdst         int Daylight Saving Time flag   
+The Daylight Saving Time flag (tm_isdst) is greater than zero if Daylight Saving Time is in effect,
+zero if Daylight Saving Time is not in effect, and less than zero if the information is not available.
+* tm_sec is generally 0-59. The extra range is to accommodate for leap seconds in certain systems.
+
+http://www.epochconverter.com/programming/c
+Convert from epoch to human readable date
+    time_t     now;
+    struct tm  ts;
+    char       buf[80];
+    // Get current time
+    time(&now);
+    // Format time, "ddd yyyy-mm-dd hh:mm:ss zzz"
+    ts = *localtime(&now);
+    strftime(buf, sizeof(buf), "%a %Y-%m-%d %H:%M:%S %Z", &ts);
+    printf("%s\n", buf);
+
+Convert from human readable date to epoch
+    struct tm t;
+    time_t t_of_day;
+    t.tm_year = 2011-1900;
+    t.tm_mon = 7;           // Month, 0 - jan
+    t.tm_mday = 8;          // Day of the month
+    t.tm_hour = 16;
+    t.tm_min = 11;
+    t.tm_sec = 42;
+    t.tm_isdst = -1;        // Is DST on? 1 = yes, 0 = no, -1 = unknown
+    t_of_day = mktime(&t);
+    printf("seconds since the Epoch: %ld\n", (long) t_of_day)
+
+https://github.com/raburton/esp8266/blob/master/drivers/ds3231.c
+https://github.com/raburton/esp8266/blob/master/drivers/ds3231.h
+
+    // https://www.unixtimestamp.com/
+
+*/
+#include "mbed.h"
+#include "macros.h"
+#include "TableSummerTime.h"
+#include "TableDayLight.h"
+
+#ifndef __MCP79412__H_
+#define __MCP79412__H_
+
+// MCP7941x I2C Addresses
+#define MCP79412_RTC_ADDR       0x6F
+#define MCP79412_EEPROM_ADDR    0x57
+#define MAC_LOCATION 0xF2   // Starts at 0xF0 but we are only interested in 6 bytes.
+#define RTC_LOCATION 0x00
+
+//MCP7941x Register Addresses
+#define TIME_REG            0x00    // 7 registers, Seconds, Minutes, Hours, DOW, Date, Month, Year
+#define DAY_REG             0x03    // the RTC Day register contains the OSCON, VBAT, and VBATEN bits
+#define YEAR_REG            0x06    // RTC year register
+#define CTRL_REG            0x07    // control register
+#define CALIB_REG           0x08    // calibration register
+#define UNLOCK_ID_REG       0x09    // unlock ID register
+#define ALM0_REG            0x0A    // alarm 0, 6 registers, Seconds, Minutes, Hours, DOW, Date, Month
+#define ALM1_REG            0x11    // alarm 1, 6 registers, Seconds, Minutes, Hours, DOW, Date, Month
+#define ALM0_DAY            0x0D    // DOW register has alarm config/flag bits
+#define PWRDWN_TS_REG       0x18    // power-down timestamp, 4 registers, Minutes, Hours, Date, Month
+#define PWRUP_TS_REG        0x1C    // power-up timestamp, 4 registers, Minutes, Hours, Date, Month
+#define TIMESTAMP_SIZE      8       // number of bytes in the two timestamp registers
+#define SRAM_START_ADDR     0x20    // first SRAM address
+#define SRAM_END_ADDR       0x5F    // last SRAM address
+#define SRAM_SIZE           64      // number of bytes of SRAM
+#define EEPROM_SIZE         128     // number of bytes of EEPROM
+#define EEPROM_PAGE_SIZE    8       // number of bytes on an EEPROM page
+#define UNIQUE_ID_ADDR      0xF0    // starting address for unique ID
+#define UNIQUE_ID_SIZE      8       // number of bytes in unique ID
+
+#define UNLOCK_ID_CODE1     0x55    // PROTECTED EEPROM UNLOCK SEQUENCE
+#define UNLOCK_ID_CODE2     0xAA    // PROTECTED EEPROM UNLOCK SEQUENCE
+
+//Control Register bits
+#define OUT     7   // sets logic level on MFP when not used as square wave output
+#define SQWE    6   // set to enable square wave output
+#define ALM1    5   // alarm 1 is active
+#define ALM0    4   // alarm 0 is active
+#define EXTOSC  3   // set to drive the RTC registers from an external oscillator instead of a crystal
+#define RS2     2   // RS2:0 set square wave output frequency: 0==1Hz, 1==4096Hz, 2==8192Hz, 3=32768Hz
+#define RS1     1
+#define RS0     0
+
+//Other Control Bits
+#define ST      7   // Seconds register (TIME_REG) oscillator start/stop bit, 1==Start, 0==Stop
+#define HR1224  6   // Hours register (TIME_REG+2) 12 or 24 hour mode (24 hour mode==0)
+#define AMPM    5   // Hours register (TIME_REG+2) AM/PM bit for 12 hour mode
+#define OSCON   5   // Day register (TIME_REG+3) oscillator running (set and cleared by hardware)
+#define VBAT    4   // Day register (TIME_REG+3) set by hardware when Vcc fails and RTC runs on battery.
+                    // VBAT is cleared by software, clearing VBAT also clears the timestamp registers
+#define VBATEN  3   // Day register (TIME_REG+3) VBATEN==1 enables backup battery, VBATEN==0 disconnects the VBAT pin (e.g. to save battery)
+#define LP      5   // Month register (TIME_REG+5) leap year bit
+
+//Alarm Control Bits
+#define ALMPOL  7   // Alarm Polarity: Defines the logic level for the MFP when an alarm is triggered.
+#define ALMC2   6   // Alarm configuration bits determine how alarms match. See ALM_MATCH defines below.
+#define ALMC1   5
+#define ALMC0   4
+#define ALMIF   3   // Alarm Interrupt Flag: Set by hardware when an alarm was triggered, cleared by software.
+// Note ALM_MATCH_DAY triggers alarm at midnight
+#define ALARM_0 0   // constants for calling functions
+#define ALARM_1 1
+
+#define MCP79412_SET        0
+#define MCP79412_CLEAR      1
+#define MCP79412_REPLACE    2
+
+#define NTP_OFFSET          2208988800ULL
+
+//convenience macros to convert to and from tm years 
+#define  tmYearToCalendar(Y) ((Y) + 1970)  // full four digit year 
+#define  CalendarYrToTm(Y)   ((Y) - 1970)
+#define  tmYearToY2k(Y)      ((Y) - 30)    // offset is from 2000
+#define  y2kYearToTm(Y)      ((Y) + 30)   
+
+enum Sqwave {
+    SQWAVE_1_HZ, 
+    SQWAVE_4096_HZ, 
+    SQWAVE_8192_HZ, 
+    SQWAVE_32768_HZ, 
+    SQWAVE_NONE
+};
+
+enum {
+    ALM_MATCH_SECONDS, 
+    ALM_MATCH_MINUTES, 
+    ALM_MATCH_HOURS, 
+    ALM_MATCH_DAY, 
+    ALM_MATCH_DATE, 
+    ALM_RESERVED_5, 
+    ALM_RESERVED_6, 
+    ALM_MATCH_DATETIME, 
+    ALM_DISABLE
+};
+
+typedef struct DateTime {
+       int year;
+       int mon;
+       int mday;
+       int wday;
+       int yday;
+       int hour;
+       int min;
+       int sec;
+};
+
+class MCP79412 {
+public:
+    DateTime datetime;
+    struct tm *t;
+    time_t secondsEpoch;
+    uint8_t second, minute, hour, dayOfWeek, dayOfMonth, month, year;
+
+    MCP79412(PinName sda, PinName scl);
+    void setI2Cfrequency(int freq);
+    bool getFlag(char reg, char mask, char *flag);
+    void setFlag(char reg, char bits, char mode);
+    int readRegister(char reg);
+    void readRegisters(char reg, char *outbuf, char length);
+    void writeRegister(int reg, char byte);
+    void writeRegisters(int reg, char *inbuf, char length);
+    void getMacAddress(char *mac_address);
+    void writeMacAddress(char *mac_address);
+    void unlockUniqueID();
+    void setRtcDateTime(uint8_t second, uint8_t minute, uint8_t hour, uint8_t dayOfWeek, uint8_t dayOfMonth, uint8_t month, uint8_t year);
+    void getRtcDateTime(uint8_t *second, uint8_t *minute, uint8_t *hour, uint8_t *dayOfWeek, uint8_t *dayOfMonth, uint8_t *month, uint8_t *year);
+    bool checkTimeLost(void);
+    void enableClock();
+    void disableClock();
+    void enableBattery();
+
+    void writeRamByte(uint8_t location, uint8_t data);
+    uint8_t writeRamBytes(uint8_t location, uint8_t *data, uint8_t length);
+    uint8_t readRamByte(uint8_t location);
+    uint8_t readRamBytes(uint8_t location, uint8_t *data, uint8_t length);
+
+    void writeSramByte(uint8_t location, uint8_t data);
+    uint8_t writeSramBytes(uint8_t location, uint8_t *data, uint8_t length);
+    uint8_t readSramByte(uint8_t location);
+    uint8_t readSramBytes(uint8_t location, uint8_t *data, uint8_t length);
+
+    void writeEepromByte(uint8_t location, uint8_t data);
+    uint8_t writeEepromBytes(uint8_t location, uint8_t *data, uint8_t length);
+    uint8_t readEepromByte(uint8_t location);
+    uint8_t readEepromBytes(uint8_t location, uint8_t *data, uint8_t length);
+    
+    int calibRead(void);
+    void calibWrite(int value);
+    void readUniqueId(char *uniqueID);
+    void getEUI64(char *uniqueID);
+    bool powerFail(time_t *powerDown, time_t *powerUp);
+    void squareWave(Sqwave freq);
+    void setAlarm(uint8_t alarmNumber, time_t alarmTime);
+    void enableAlarm(uint8_t alarmNumber, uint8_t alarmType);
+    bool alarm(uint8_t alarmNumber);
+    void out(bool level);
+    void alarmPolarity(bool polarity);
+    bool isRunning(void);
+    void vbaten(bool enable);
+    
+//    bool getSummerTime(void);
+//    int dayOfYearC(void);
+//    char * getSunRise(void);
+//    char * getSunSet(void);
+//    char * getDayLength(void);
+//    int getSunRiseMinute(void);
+//    int getSunSetMinute(void);
+//    bool checkSunRise(void);
+    
+    void substr(char *s, char *d, int pos, int len);
+    char * substr(char *s, int pos, int len);
+    
+    // Mbed dateTime
+    struct tm setSystemDateTime(uint8_t second, uint8_t minute, uint8_t hour, uint8_t dayOfMonth, uint8_t month, uint8_t year);
+    void getSystemDateTime(uint8_t *second, uint8_t *minute, uint8_t *hour, uint8_t *dayOfWeek, uint8_t *dayOfMonth, uint8_t *month, uint8_t *year);
+    void setRtcToSystemDateTime(void);
+    void setSystemToRtcDateTime(void);
+    void setRtcFromTm(struct tm *t);
+    struct tm getTmFromRtc(void);
+    
+    time_t getSecondsEpoch(void);
+    void setSecondsEpoch(time_t t);
+
+    void getRtcDateTimeAsTm(void);
+    time_t convertDateTimeToTimestamp(uint8_t second, uint8_t minute, uint8_t hour, uint8_t dayOfMonth, uint8_t month, uint8_t year);
+    uint8_t getWeekdayFromDate(uint8_t dayOfMonth, uint8_t month, uint8_t year);
+
+    int bcd2dec(int k); // bcd to decimal conversion
+    int dec2bcd(int k); // decimal to bcd conversion
+    int decToBcd(int val);
+    int bcdToDec(int val);
+    
+private :
+    I2C _i2c;
+    char _address_RTC;
+    char buffer[32];
+    bool _error;
+
+
+};
+
+#endif
diff -r 000000000000 -r 04311b121ac4 TableDayLight.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TableDayLight.h	Mon Jul 23 12:24:33 2018 +0000
@@ -0,0 +1,149 @@
+    const char * const SunRise[] = {
+//    const string SunRise[] = {
+        "08:50", "08:50", "08:49", "08:49", "08:49", "08:48", "08:48", "08:47",
+        "08:47", "08:46", "08:45", "08:44", "08:44", "08:43", "08:42", "08:41",
+        "08:40", "08:39", "08:38", "08:37", "08:35", "08:34", "08:33", "08:32",
+        "08:30", "08:29", "08:27", "08:26", "08:24", "08:23", "08:21", "08:20",
+        "08:18", "08:16", "08:15", "08:13", "08:11", "08:09", "08:08", "08:06",
+        "08:04", "08:02", "08:00", "07:58", "07:56", "07:54", "07:52", "07:50",
+        "07:48", "07:46", "07:44", "07:42", "07:40", "07:37", "07:35", "07:33",
+        "07:31", "07:29", "07:27", "07:24", "07:22", "07:20", "07:18", "07:15",
+        "07:13", "07:11", "07:08", "07:06", "07:04", "07:02", "06:59", "06:57",
+        "06:55", "06:52", "06:50", "06:48", "06:45", "06:43", "06:41", "06:38",
+        "06:36", "06:34", "06:31", "06:29", "06:26", "06:24", "06:22", "06:19",
+        "06:17", "07:15", "07:12", "07:10", "07:08", "07:05", "07:03", "07:01",
+        "06:59", "06:56", "06:54", "06:52", "06:49", "06:47", "06:45", "06:43",
+        "06:41", "06:38", "06:36", "06:34", "06:32", "06:30", "06:28", "06:25",
+        "06:23", "06:21", "06:19", "06:17", "06:15", "06:13", "06:11", "06:09",
+        "06:07", "06:05", "06:03", "06:02", "06:00", "05:58", "05:56", "05:54",
+        "05:53", "05:51", "05:49", "05:48", "05:46", "05:45", "05:43", "05:41",
+        "05:40", "05:39", "05:37", "05:36", "05:35", "05:33", "05:32", "05:31",
+        "05:30", "05:29", "05:28", "05:27", "05:26", "05:25", "05:24", "05:23",
+        "05:22", "05:22", "05:21", "05:20", "05:20", "05:19", "05:19", "05:18",
+        "05:18", "05:18", "05:17", "05:17", "05:17", "05:17", "05:17", "05:17",
+        "05:17", "05:17", "05:17", "05:18", "05:18", "05:18", "05:19", "05:19",
+        "05:20", "05:20", "05:21", "05:21", "05:22", "05:23", "05:23", "05:24",
+        "05:25", "05:26", "05:27", "05:28", "05:29", "05:30", "05:31", "05:32",
+        "05:33", "05:35", "05:36", "05:37", "05:38", "05:40", "05:41", "05:42",
+        "05:44", "05:45", "05:46", "05:48", "05:49", "05:51", "05:52", "05:54",
+        "05:55", "05:57", "05:58", "06:00", "06:01", "06:03", "06:05", "06:06",
+        "06:08", "06:09", "06:11", "06:13", "06:14", "06:16", "06:18", "06:19",
+        "06:21", "06:23", "06:24", "06:26", "06:27", "06:29", "06:31", "06:32",
+        "06:34", "06:36", "06:37", "06:39", "06:41", "06:42", "06:44", "06:46",
+        "06:47", "06:49", "06:51", "06:52", "06:54", "06:56", "06:57", "06:59",
+        "07:01", "07:02", "07:04", "07:06", "07:07", "07:09", "07:11", "07:12",
+        "07:14", "07:15", "07:17", "07:19", "07:20", "07:22", "07:24", "07:25",
+        "07:27", "07:29", "07:30", "07:32", "07:34", "07:35", "07:37", "07:39",
+        "07:41", "07:42", "07:44", "07:46", "07:47", "07:49", "07:51", "07:53",
+        "07:54", "07:56", "07:58", "07:59", "08:01", "08:03", "08:05", "08:06",
+        "08:08", "08:10", "08:12", "08:14", "08:15", "08:17", "08:19", "08:21",
+        "08:23", "08:24", "08:26", "07:28", "07:30", "07:32", "07:33", "07:35",
+        "07:37", "07:39", "07:41", "07:43", "07:44", "07:46", "07:48", "07:50",
+        "07:52", "07:54", "07:55", "07:57", "07:59", "08:01", "08:02", "08:04",
+        "08:06", "08:08", "08:09", "08:11", "08:13", "08:14", "08:16", "08:18",
+        "08:19", "08:21", "08:22", "08:24", "08:25", "08:27", "08:28", "08:30",
+        "08:31", "08:32", "08:34", "08:35", "08:36", "08:37", "08:38", "08:39",
+        "08:40", "08:41", "08:42", "08:43", "08:44", "08:45", "08:46", "08:46",
+        "08:47", "08:47", "08:48", "08:48", "08:49", "08:49", "08:49", "08:50",
+        "08:50", "08:50", "08:50", "08:50", "08:50", "08:50"
+    };
+    
+    const char * const SunSet[] = {
+//    const string SunSet[] = {
+        "16:38", "16:39", "16:40", "16:41", "16:43", "16:44", "16:45", "16:47",
+        "16:48", "16:50", "16:51", "16:53", "16:54", "16:56", "16:57", "16:59",
+        "17:01", "17:02", "17:04", "17:06", "17:07", "17:09", "17:11", "17:13",
+        "17:15", "17:16", "17:18", "17:20", "17:22", "17:24", "17:26", "17:28",
+        "17:29", "17:31", "17:33", "17:35", "17:37", "17:39", "17:41", "17:43",
+        "17:44", "17:46", "17:48", "17:50", "17:52", "17:54", "17:56", "17:58",
+        "18:00", "18:01", "18:03", "18:05", "18:07", "18:09", "18:11", "18:13",
+        "18:14", "18:16", "18:18", "18:20", "18:22", "18:24", "18:25", "18:27",
+        "18:29", "18:31", "18:33", "18:34", "18:36", "18:38", "18:40", "18:42",
+        "18:43", "18:45", "18:47", "18:49", "18:50", "18:52", "18:54", "18:56",
+        "18:57", "18:59", "19:01", "19:03", "19:04", "19:06", "19:08", "19:10",
+        "19:11", "20:13", "20:15", "20:17", "20:18", "20:20", "20:22", "20:23",
+        "20:25", "20:27", "20:29", "20:30", "20:32", "20:34", "20:36", "20:37",
+        "20:39", "20:41", "20:43", "20:44", "20:46", "20:48", "20:49", "20:51",
+        "20:53", "20:55", "20:56", "20:58", "21:00", "21:02", "21:03", "21:05",
+        "21:07", "21:08", "21:10", "21:12", "21:13", "21:15", "21:17", "21:18",
+        "21:20", "21:22", "21:23", "21:25", "21:26", "21:28", "21:30", "21:31",
+        "21:33", "21:34", "21:36", "21:37", "21:39", "21:40", "21:41", "21:43",
+        "21:44", "21:45", "21:47", "21:48", "21:49", "21:50", "21:52", "21:53",
+        "21:54", "21:55", "21:56", "21:57", "21:58", "21:59", "22:00", "22:00",
+        "22:01", "22:02", "22:02", "22:03", "22:04", "22:04", "22:05", "22:05",
+        "22:05", "22:06", "22:06", "22:06", "22:06", "22:06", "22:06", "22:06",
+        "22:06", "22:06", "22:06", "22:06", "22:06", "22:05", "22:05", "22:04",
+        "22:04", "22:03", "22:03", "22:02", "22:01", "22:01", "22:00", "21:59",
+        "21:58", "21:57", "21:56", "21:55", "21:54", "21:53", "21:52", "21:50",
+        "21:49", "21:48", "21:46", "21:45", "21:44", "21:42", "21:41", "21:39",
+        "21:38", "21:36", "21:34", "21:33", "21:31", "21:29", "21:27", "21:26",
+        "21:24", "21:22", "21:20", "21:18", "21:16", "21:14", "21:12", "21:10",
+        "21:08", "21:06", "21:04", "21:02", "21:00", "20:58", "20:56", "20:54",
+        "20:52", "20:50", "20:47", "20:45", "20:43", "20:41", "20:38", "20:36",
+        "20:34", "20:32", "20:29", "20:27", "20:25", "20:23", "20:20", "20:18",
+        "20:16", "20:13", "20:11", "20:09", "20:06", "20:04", "20:01", "19:59",
+        "19:57", "19:54", "19:52", "19:50", "19:47", "19:45", "19:42", "19:40",
+        "19:38", "19:35", "19:33", "19:31", "19:28", "19:26", "19:24", "19:21",
+        "19:19", "19:17", "19:14", "19:12", "19:10", "19:07", "19:05", "19:03",
+        "19:00", "18:58", "18:56", "18:54", "18:51", "18:49", "18:47", "18:45",
+        "18:42", "18:40", "18:38", "18:36", "18:34", "18:32", "18:30", "18:28",
+        "18:26", "18:23", "18:21", "17:19", "17:18", "17:16", "17:14", "17:12",
+        "17:10", "17:08", "17:06", "17:04", "17:03", "17:01", "16:59", "16:58",
+        "16:56", "16:54", "16:53", "16:51", "16:50", "16:48", "16:47", "16:46",
+        "16:44", "16:43", "16:42", "16:40", "16:39", "16:38", "16:37", "16:36",
+        "16:35", "16:34", "16:33", "16:32", "16:32", "16:31", "16:30", "16:30",
+        "16:29", "16:29", "16:28", "16:28", "16:27", "16:27", "16:27", "16:27",
+        "16:27", "16:27", "16:27", "16:27", "16:27", "16:27", "16:27", "16:27",
+        "16:28", "16:28", "16:29", "16:29", "16:30", "16:31", "16:31", "16:32",
+        "16:33", "16:34", "16:35", "16:36", "16:37", "16:37"
+    };
+    
+    const char * const DayLength[] = {
+//    const string DayLength[] = {
+        "07:48", "07:49", "07:51", "07:52", "07:54", "07:55", "07:57", "07:59",
+        "08:01", "08:03", "08:05", "08:08", "08:10", "08:13", "08:15", "08:18",
+        "08:20", "08:23", "08:26", "08:29", "08:32", "08:35", "08:38", "08:41",
+        "08:44", "08:47", "08:50", "08:54", "08:57", "09:00", "09:04", "09:07",
+        "09:11", "09:14", "09:18", "09:22", "09:25", "09:29", "09:33", "09:36",
+        "09:40", "09:44", "09:48", "09:52", "09:55", "09:59", "10:03", "10:07",
+        "10:11", "10:15", "10:19", "10:23", "10:27", "10:31", "10:35", "10:39",
+        "10:43", "10:47", "10:51", "10:55", "10:59", "11:03", "11:07", "11:11",
+        "11:15", "11:20", "11:24", "11:28", "11:32", "11:36", "11:40", "11:44",
+        "11:48", "11:52", "11:56", "12:01", "12:05", "12:09", "12:13", "12:17",
+        "12:21", "12:25", "12:29", "12:33", "12:37", "12:42", "12:46", "12:50",
+        "12:54", "12:58", "13:02", "13:06", "13:10", "13:14", "13:18", "13:22",
+        "13:26", "13:30", "13:34", "13:38", "13:42", "13:46", "13:50", "13:54",
+        "13:58", "14:02", "14:06", "14:10", "14:14", "14:18", "14:21", "14:25",
+        "14:29", "14:33", "14:37", "14:40", "14:44", "14:48", "14:52", "14:55",
+        "14:59", "15:03", "15:06", "15:10", "15:13", "15:17", "15:20", "15:23",
+        "15:27", "15:30", "15:33", "15:37", "15:40", "15:43", "15:46", "15:49",
+        "15:52", "15:55", "15:58", "16:01", "16:04", "16:06", "16:09", "16:11",
+        "16:14", "16:16", "16:19", "16:21", "16:23", "16:25", "16:27", "16:29",
+        "16:31", "16:33", "16:34", "16:36", "16:38", "16:39", "16:40", "16:41",
+        "16:43", "16:44", "16:45", "16:45", "16:46", "16:47", "16:47", "16:48",
+        "16:48", "16:48", "16:48", "16:48", "16:48", "16:48", "16:47", "16:47",
+        "16:46", "16:46", "16:45", "16:44", "16:43", "16:42", "16:41", "16:40",
+        "16:38", "16:37", "16:35", "16:34", "16:32", "16:30", "16:28", "16:26",
+        "16:24", "16:22", "16:20", "16:17", "16:15", "16:13", "16:10", "16:08",
+        "16:05", "16:02", "16:00", "15:57", "15:54", "15:51", "15:48", "15:45",
+        "15:42", "15:39", "15:35", "15:32", "15:29", "15:26", "15:22", "15:19",
+        "15:16", "15:12", "15:09", "15:05", "15:02", "14:58", "14:54", "14:51",
+        "14:47", "14:43", "14:40", "14:36", "14:32", "14:28", "14:25", "14:21",
+        "14:17", "14:13", "14:09", "14:06", "14:02", "13:58", "13:54", "13:50",
+        "13:46", "13:42", "13:38", "13:34", "13:30", "13:26", "13:22", "13:18",
+        "13:14", "13:10", "13:06", "13:02", "12:58", "12:54", "12:50", "12:46",
+        "12:42", "12:38", "12:34", "12:30", "12:26", "12:22", "12:18", "12:14",
+        "12:10", "12:06", "12:02", "11:58", "11:54", "11:50", "11:46", "11:42",
+        "11:38", "11:34", "11:30", "11:26", "11:22", "11:18", "11:14", "11:10",
+        "11:06", "11:02", "10:58", "10:54", "10:50", "10:46", "10:42", "10:38",
+        "10:34", "10:30", "10:26", "10:22", "10:18", "10:14", "10:10", "10:06",
+        "10:02", "09:59", "09:55", "09:51", "09:47", "09:43", "09:40", "09:36",
+        "09:32", "09:29", "09:25", "09:21", "09:18", "09:14", "09:11", "09:07",
+        "09:04", "09:00", "08:57", "08:54", "08:50", "08:47", "08:44", "08:41",
+        "08:38", "08:35", "08:32", "08:29", "08:26", "08:23", "08:21", "08:18",
+        "08:15", "08:13", "08:10", "08:08", "08:06", "08:04", "08:01", "07:59",
+        "07:58", "07:56", "07:54", "07:52", "07:51", "07:49", "07:48", "07:47",
+        "07:46", "07:45", "07:44", "07:43", "07:42", "07:42", "07:41", "07:41",
+        "07:41", "07:40", "07:40", "07:40", "07:41", "07:41", "07:41", "07:42",
+        "07:43", "07:43", "07:44", "07:45", "07:46", "07:46"
+    };
diff -r 000000000000 -r 04311b121ac4 TableSummerTime.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TableSummerTime.h	Mon Jul 23 12:24:33 2018 +0000
@@ -0,0 +1,67 @@
+/*
+http://hemel.waarnemen.com/aarde/zomertijd.html#2016
+De zomertijd (of zomeruur) begint in de EU op de laatste zondag van maart en eindigt op de laatste zondag van oktober.
+Dit gebeurt in alle lidstaten op hetzelfde moment.
+In België en Nederland is dat 's nachts om 2 uur wintertijd (of winteruur; MET).
+In het voorjaar betekent dat dat de klok van 2 uur MET wordt omgezet naar 3 uur MEZT,
+zodat de nacht een uur korter duurt.
+In het najaar wordt de klok om 3 uur MEZT teruggezet naar 2 uur MET,
+zodat we een uur langer kunnen slapen (de tijdspanne tussen 2 en 3 uur komt immers tweemaal voor).
+*/
+
+    const char * const SummerTime[] = {
+        "2011", "03", "27", "10", "30",
+        "2012", "03", "25", "10", "28",
+        "2013", "03", "31", "10", "27",
+        "2014", "03", "30", "10", "26",
+        "2015", "03", "29", "10", "25",
+        "2016", "03", "27", "10", "30",
+        "2017", "03", "26", "10", "29",
+        "2018", "03", "25", "10", "28",
+        "2019", "03", "31", "10", "27",
+        "2020", "03", "29", "10", "25",
+        
+        "2021", "03", "28", "10", "31",
+        "2022", "03", "27", "10", "30",
+        "2023", "03", "26", "10", "29",
+        "2024", "03", "31", "10", "27",
+        "2025", "03", "30", "10", "26",
+        "2026", "03", "29", "10", "25",
+        "2027", "03", "28", "10", "31",
+        "2028", "03", "26", "10", "29",
+        "2029", "03", "25", "10", "28",
+        "2030", "03", "31", "10", "27",
+
+        "2031", "03", "30", "10", "26",
+        "2032", "03", "28", "10", "31",
+        "2033", "03", "27", "10", "30",
+        "2034", "03", "26", "10", "29",
+        "2035", "03", "25", "10", "28",
+        "2036", "03", "30", "10", "26",
+        "2037", "03", "29", "10", "25",
+        "2038", "03", "28", "10", "31",
+        "2039", "03", "27", "10", "30",
+        "2040", "03", "25", "10", "28",
+
+        "2041", "03", "31", "10", "27",
+        "2042", "03", "30", "10", "26",
+        "2043", "03", "29", "10", "25",
+        "2044", "03", "27", "10", "30",
+        "2045", "03", "26", "10", "29",
+        "2046", "03", "25", "10", "28",
+        "2047", "03", "31", "10", "27",
+        "2048", "03", "29", "10", "25",
+        "2049", "03", "28", "10", "31",
+        "2050", "03", "27", "10", "30",
+
+        "2051", "03", "26", "10", "29",
+        "2052", "03", "31", "10", "27",
+        "2053", "03", "30", "10", "26",
+        "2054", "03", "29", "10", "25",
+        "2055", "03", "28", "10", "31",
+        "2056", "03", "26", "10", "29",
+        "2057", "03", "25", "10", "28",
+        "2058", "03", "31", "10", "27",
+        "2059", "03", "30", "10", "26",
+        "2060", "03", "28", "10", "31"
+    };