Self Synchronizing Wifi Clock, V2

Since my last encounter with a self synchronizing wifi clock I ended up learning how to implement my own display driver. Unfortunately the display died on me when testing it on a new power supply (which appeared to be malfunctioning afterwards) and so I have been thinking of porting my code to use the Adafruit 2.8″ display.  Pretty much most of the functionality remains from what I’ve made before, the most interesting thing I wanted to add this time was making use of the resistive touch screen. I could easily made a basic GUI to adjust settings and so on, but by some unknown reason I can’t get the touch positioning to work reliable on the Due board. Though it does function on Uno, Uno does not offer the needed program space (I’m at 40~50k). So, all together there is not much to it, but here is what I ended up with:

Next, I’ll check if there is the possibility to hook it up to Raspberry Pi and control it using NodeJS. Enjoy the holidays, see you in 2015!

Advertisements

One thought on “Self Synchronizing Wifi Clock, V2

  1. Experimental source code:

    /*
    This program queries an NTP time server to get the current NTP time
    (seconds since 1/1/1900, UTC (GMT)), then uses the Arduino’s internal
    timer to keep relative time. The clock is re-synchronized roughly
    once per day. This minimizes NTP server misuse/abuse. It displays time
    and also takes a temperature reading from the ADT7410 I2C temp sensor.
    Internet connection goes through the Adafruit C3300 breakout board, it
    reads the Wifi configuration from SD card on boot. Temperature samples
    and according time stamps are also stored on the SD card.
    Does only apply for Arduino Due devices because sketch size > 50kbytes

    ADT7410 13/16-bit digital temperature sensor
    RED (VDD): 2.7 … 5.5V
    BROWN (GND): 0V
    Arduino due, wires:
    PURPLE 1 (SCL): SCL (pin 21)
    PURPLE 2 (SDA): SDA = (pin 20)
    Arduino IDE 1.5.6-r2 compatible
    */

    #include
    #include
    #include
    #include
    #include
    #include
    #include
    #include “utility/sntp.h”

    //ADT7410 config
    #define ADT7410_I2C_ADDRESS 0x48
    #define tempRegister 0x00
    #define configRegister 0x03
    #define selectCode16bitMode 0x80

    //Touchscreen X+ X- Y+ Y- pins
    #define YP A3 // must be an analog pin, use “An” notation!
    #define XM A2 // must be an analog pin, use “An” notation!
    #define YM 7 // can be a digital pin
    #define XP 8 // can be a digital pin

    // This is calibration data for the raw touch data to the screen coordinates
    #define TS_MINX 150
    #define TS_MINY 120
    #define TS_MAXX 920
    #define TS_MAXY 940

    #define MINPRESSURE 10
    #define MAXPRESSURE 1000

    //tft colors
    #define BLACK 0x0000
    #define BLUE 0x001F
    #define RED 0xF800
    #define GREEN 0x07E0
    #define CYAN 0x07FF
    #define MAGENTA 0xF81F
    #define YELLOW 0xFFE0
    #define WHITE 0xFFFF

    // For better pressure precision, we need to know the resistance
    // between X+ and X- Use any multimeter to read it
    // For the one we’re using, its 300 ohms across the X plate
    TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);

    //TFT SPI PINS
    #define TFT_CS 8
    #define TFT_DC 9
    Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);

    // C3300 interrupt and control pins
    #define ADAFRUIT_CC3000_IRQ 3 // MUST be an interrupt pin!
    // These can be any two pins
    #define ADAFRUIT_CC3000_VBAT 5
    #define ADAFRUIT_CC3000_CS 10 // Wifi Chip Select pin
    #define ADAFRUIT_SDCARD_CS 4 // SD Card Chip Select pin
    /*
    Use hardware SPI for the remaining pins. Due has SPI header, for an UNO
    SCK = 13
    MISO = 12
    MOSI = 11
    */

    //WLAN config
    Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,
    SPI_CLOCK_DIVIDER); // you can change this clock speed

    //connection timeout vars
    const unsigned long
    connectTimeout = 15L * 1000L, // Max time to wait for server connection
    responseTimeout = 15L * 1000L; // Max time to wait for data from server

    //Arguments to SNTP client constructor:
    // 1 – Primary Network Time Server URL (can be NULL)
    // 2 – Secondary Network Time Server URL (also can be NULL)
    // 3 – Local UTC offset in minutes (US Eastern Time is UTC – 5:00
    // 4 – Local UTC offset in minutes for Daylight Savings Time (US Eastern DST is UTC – 4:00
    // 5 – Enable Daylight Savings Time adjustment (not implemented yet, so use false please)
    sntp mysntp = sntp(“0.be.pool.ntp.org”, “time.nist.gov”, (short)(1 * 60), (short)(1 * 60), false);

    //vars where we store the config data read from SD card
    #define CONF_ARRAY_LENGTH 32 /* Max 32 chars */
    char wlan_ssid[CONF_ARRAY_LENGTH] = {‘W’,’i’,’t’,’t’,’e’};
    char wlan_pass[CONF_ARRAY_LENGTH] = { ‘1’,’2′,’3′,’4′,’p’,’a’,’t’,’r’,’i’,’c’,’k’,’4′,’3′,’2′,’1′};
    int wlan_security = 3; // Security can be WLAN_SEC_UNSEC (0), WLAN_SEC_WEP (1), WLAN_SEC_WPA (2) or WLAN_SEC_WPA2 (3)

    // Type SNTP_Timestamp is 64-bit NTP time. High-order 32-bits is seconds since 1/1/1900
    // Low order 32-bits is fractional seconds
    SNTP_Timestamp_t now;

    // Type NetTime_t contains NTP time broken out to human-oriented values:
    // uint16_t millis; ///< Milliseconds after the second (0..999)
    // uint8_t sec; ///< Seconds after the minute (0..59)
    // uint8_t min; ///< Minutes after the hour (0..59)
    // uint8_t hour; ///< Hours since midnight (0..23)
    // uint8_t mday; ///< Day of the month (1..31)
    // uint8_t mon; ///< Months since January (0..11)
    // uint16_t year; ///< Year.
    // uint8_t wday; ///< Days since Sunday (0..6)
    // uint8_t yday; ///< Days since January 1 (0..365)
    // bool isdst; ///< Daylight savings time flag, currently not supported
    NetTime_t timeExtract;

    //var that hold the amount of milliseconds between arduino boot and last NTP request
    long programTimeLastNTPrequest;
    //time between each NTP request (120000L = 2min, 3600000L = 1h, 86400000L = 1d)
    const long NTP_UPDATE_TIMER = 86400000L;

    //some vars
    byte lastClockValue_Second;
    byte lastClockValue_Day;

    const char* VERSION = "2.0";

    /////////////////////////////////////////////////////////////////////////////////////////////////////

    void setup(void)
    {
    Serial.begin(9600);
    while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
    }
    Serial.print(F("SmartClock V")); Serial.print(VERSION); Serial.println(F("\n"));

    setupTFT();

    Serial.println(F("\nInitialising ADT7410 …"));
    tft.println("Initialising ADT7410 temp sensor…");
    Wire.begin(); // join i2c bus (address optional for master)
    setTempSensor16bitMode();

    setupCC3000();
    updateClock();

    tft.println("boot success");
    Serial.println(F("\n\nReady!\n"));
    tft.fillScreen(ILI9341_BLACK);
    delay(500);

    mysntp.ExtractNTPTime(mysntp.NTPGetTime(&now, true), &timeExtract);
    updateColon();
    printClock();
    printTemp();
    printDate();
    }

    void setupTFT()
    {
    Serial.println(F("\nInitialising TFT shield …"));
    tft.begin();

    tft.fillScreen(ILI9341_BLUE);
    // origin = left,top landscape (USB left upper)
    tft.setRotation(1);

    tft.setCursor(0 , 0);
    tft.setTextColor(ILI9341_WHITE);
    tft.setTextSize(2);
    tft.print("SmartClock V");tft.println(VERSION);
    tft.setTextSize(1);
    tft.println("tft initialized");
    }

    //setup CC3000 wifi adapter
    // beware not to set too much tft code here, can block the wifi adapter!
    void setupCC3000()
    {
    Serial.println(F("\nInitialising CC3000 Wifi adapter …"));
    tft.println("Initialising C3300 Wifi… ");
    if (!cc3000.begin()) {
    Serial.println(F("Unable to initialise CC3000 Wifi adapter! Check your wiring?"));
    for(;;);
    }

    Serial.println(F("\nChecking firmware version… "));
    uint16_t firmware = checkFirmwareVersion();
    if ((firmware != 0x113) && (firmware != 0x118)) {
    Serial.println(F("Wrong firmware version!"));
    for(;;);
    }

    Serial.println(F("\nRetrieving MAC address… "));
    displayMACAddress();

    Serial.println(F("\nDeleting old connection profiles"));
    if (!cc3000.deleteProfiles()) {
    Serial.println(F("Failed!"));
    while(1);
    }

    /* Attempt to connect to an access point */
    Serial.print(F("\nAttempting to connect to ")); Serial.println(wlan_ssid);
    //tft.print("Attempting to connect to "); tft.println(wlan_ssid);

    /* NOTE: Secure connections are not available in 'Tiny' mode! */
    if (!cc3000.connectToAP(wlan_ssid, wlan_pass, wlan_security)) {
    Serial.println(F("Failed!"));
    while(1);
    }

    Serial.print(F("Connected to ")); Serial.println(wlan_ssid);
    tft.print("connected to SSID: "); tft.println(wlan_ssid);

    /* Wait for DHCP to complete */
    Serial.println(F("Request DHCP"));
    while (!cc3000.checkDHCP()) {
    delay(100); // ToDo: Insert a DHCP timeout!
    }

    /* Display the IP address DNS, Gateway, etc. */
    while (!displayConnectionDetails()) {
    delay(1000);
    }

    //set NTP request timer to a value which allows an NTP request at boot
    programTimeLastNTPrequest = millis() + NTP_UPDATE_TIMER*4;

    Serial.print(F("Boot time: "));
    Serial.print(programTimeLastNTPrequest/1000);
    Serial.println(F("s"));
    }

    // Tries to read the CC3000's internal firmware patch ID
    uint16_t checkFirmwareVersion(void)
    {
    uint8_t major, minor;
    uint16_t version = 0;

    #ifndef CC3000_TINY_DRIVER
    if(!cc3000.getFirmwareVersion(&major, &minor))
    {
    Serial.println(F("Unable to retrieve the firmware version!\r\n"));
    }
    else
    {
    Serial.print(F("C3300 Firmware V. : "));
    Serial.print(major); Serial.print(F(".")); Serial.println(minor);
    version = major; version < programTimeLastNTPrequest + NTP_UPDATE_TIMER) //do a new NTP request each 2 minutes
    {
    updateClock();
    }
    else if ( (millis() + NTP_UPDATE_TIMER * 2 ) lastClockValue_Second && timeExtract.sec < lastClockValue_Second +2)
    {
    //update each second the ':'
    updateColon();
    }
    else if (timeExtract.sec == 0 && lastClockValue_Second == 59)
    {
    //update each minute the clock
    updateColon();
    printClock();
    printTemp();

    if (timeExtract.mday != lastClockValue_Day)
    printDate();
    }

    delay(50); //rest a bit
    }

    //update clock through NTP servers
    void updateClock()
    {
    bool succes = false;

    while (!succes)
    {
    Serial.print(F("Synchronizing with NTP server… "));
    succes = mysntp.UpdateNTPTime(); //try update

    if (succes)
    {
    Serial.println(F("* Synced"));
    programTimeLastNTPrequest = millis();
    }
    else
    {
    Serial.println(F("* Sync failed, retrying"));
    }
    }
    }

    bool drawColon = true;
    void updateColon()
    {
    Serial.println(timeExtract.sec);
    lastClockValue_Second = timeExtract.sec;

    if(drawColon)
    {
    tft.setTextColor(WHITE, BLACK);

    drawColon = false;
    }
    else
    {
    tft.setTextColor(BLACK, BLACK);
    drawColon = true;
    }
    tft.setTextSize(5);
    tft.setCursor(150, 5);
    tft.println(":");
    }

    //print time and temperature
    void printClock()
    {
    Serial.print(F("Current local time is: "));
    Serial.print(timeExtract.hour); Serial.print(F(":")); Serial.print(timeExtract.min); Serial.print(F(":"));Serial.println(timeExtract.sec);

    tft.setTextColor(WHITE, BLACK);
    tft.setTextSize(5);
    tft.setCursor(90, 5);
    if (timeExtract.hour<10)
    tft.print("0");
    tft.println(timeExtract.hour);
    tft.setCursor(180, 5);
    if (timeExtract.min<10)
    tft.print("0");
    tft.println(timeExtract.min);
    }

    //print temperature
    void printTemp()
    {
    Serial.print(" *** temperature: ");
    float temp = readTemp();
    Serial.print(temp); //do a temperature readout
    Serial.println(" degrees Celcius");

    tft.setTextColor(YELLOW, BLACK);
    tft.setTextSize(4);
    tft.setCursor(30, 90);
    tft.print(temp);tft.println(" gr.C");
    }

    //print date
    void printDate()
    {
    lastClockValue_Day = timeExtract.mday;

    tft.setTextColor(CYAN, BLACK);
    tft.setTextSize(3);
    tft.setCursor(65, 55);
    if(timeExtract.mday < 10)
    tft.print('0');
    tft.print(timeExtract.mday);
    if(timeExtract.mon 0xA0) {
    sign=0; //negative
    } else {
    sign=1; //positive
    }

    //concat MSB&LSB
    float tempValue = MSB * 256;
    tempValue+=LSB;

    //BIN to DEC
    if(!(sign)){
    tempValue-=65536;
    }
    tempValue/=128;

    return tempValue;
    }

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s