Skip to content

Instantly share code, notes, and snippets.

@mercdev
Created January 25, 2018 02:52

Revisions

  1. mercdev revised this gist Jan 25, 2018. No changes.
  2. mercdev created this gist Jan 25, 2018.
    294 changes: 294 additions & 0 deletions Blynk_WeMos_D1_R2.ino
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,294 @@
    #define BLYNK_PRINT Serial

    // Blynk app
    #include <BlynkSimpleEsp8266.h>
    #include <RTClib.h>
    #include <WidgetRTC.h>

    // Non Blynk specific, local files
    #include <WiFiUdp.h>
    #include "NTP.h"

    // device hardware specific
    #include <PCF85063TP.h>
    PCD85063TP RTC;


    // WiFi settings
    char ssid[] = "xxx";
    char pass[] = "xxx";

    // Blynk Settings
    char auth[] = "xxxxxx";

    // Blynk Widgets
    WidgetTerminal terminalWidget(V8);
    WidgetRTC rtcWidget; // requires RTC widget in app
    BlynkTimer blynkTimer; // SimpleTimer replacement

    // Sketch variables
    boolean connectInProgress;
    boolean syncBlynkTime = true;
    boolean ntpStarted = false;
    int blynkTimerId;
    int connectTimerId;

    //
    // This is called for all virtual pins that do not have BLYNK_WRITE handler
    //
    BLYNK_WRITE_DEFAULT()
    {
    terminalWidget.print("BLYNK_WRITE for pin V");
    terminalWidget.print(request.pin);
    terminalWidget.println(" not defined.");
    terminalWidget.println("Values: ");
    for (auto i = param.begin(); i < param.end(); ++i)
    {
    terminalWidget.print("* ");
    terminalWidget.println(i.asString());
    }
    terminalWidget.flush();
    }

    //
    // This is called for all virtual pins that do not have BLYNK_READ handler
    //
    BLYNK_READ_DEFAULT()
    {
    terminalWidget.print("BLYNK_READ for pin V");
    terminalWidget.print(request.pin);
    terminalWidget.println(" not defined.");
    terminalWidget.flush();
    }

    //
    // This is called when Blynk has successfully connected
    //
    BLYNK_CONNECTED()
    {
    syncBlynkTime = true; // (re)set time to synchronize with Blynk by default
    rtcWidget.begin(); // sets setSyncProvider internally and immediately call Blynk.sendInternal("rtc", "sync");
    setSyncInterval(5*60); // subsequent time sync interval in seconds (5 minutes), once that interval has elapsed, time will set itself to timeNeedsSync

    // cancel NTP time synchronization
    if (ntpStarted)
    {
    ntpStop();
    ntpStarted = false;
    // reset checkBlynkConnection to default/startup interval of 5 minutes
    blynkTimer.changeInterval(connectTimerId, 300000L);
    blynkTimer.restartTimer(connectTimerId);
    }

    }

    /*
    * Blynk feature was postponed until a later release
    BLYNK_DISCONNECTED()
    {
    #ifdef BLYNK_PRINT
    Serial.println("[_\\|/_] Blynk Disonnected.");
    #endif
    }
    */

    //
    // This is called when Smartphone App is opened
    //
    BLYNK_APP_CONNECTED()
    {
    #ifdef BLYNK_PRINT
    Serial.println("[_\\|/_] Blynk App Connected.");
    #endif
    }

    //
    // This is called when Smartphone App is closed
    //
    BLYNK_APP_DISCONNECTED()
    {
    #ifdef BLYNK_PRINT
    Serial.println("[_\\|/_] Blynk App Disconnected.");
    #endif
    }

    //
    // synchronize the RTC hardware device with our TimeLib provided date/time values
    // The time library is synchronized by the Blynk WidgetRTC on connect
    // NOTE: most RTC's require a battery in order to oscillate, otherwise time doesn't increment on the hardware
    //
    void syncRTCHardware()
    {
    #ifdef BLYNK_PRINT
    char currentTime[16];
    char currentDate[16];
    #endif

    if (!Blynk.connected() && syncBlynkTime)
    {
    #ifdef BLYNK_PRINT
    Serial.println("[_\\|/_] Blynk not connected. Changing to NTP Sync");
    #endif

    syncBlynkTime = false;
    ntpStarted = ntpStart(); // starts the udp listener for NTP sync
    if (ntpStarted)
    {
    setSyncProvider(getNtpTime);
    setSyncInterval(5*60); // 5 minutes

    // change checkBlynkConnection to check every 1 minute
    blynkTimer.changeInterval(connectTimerId, 60000L);
    blynkTimer.restartTimer(connectTimerId);
    }
    else
    {
    #ifdef BLYNK_PRINT
    Serial.println("[_\\|/_] NTP start failed.");
    #endif
    }
    }

    // get the time library status
    // enums: timeNotSet = 0, timeNeedsSync = 1, timeSet = 2
    timeStatus_t timestatus = timeStatus();
    if (timestatus == 0)
    {
    #ifdef BLYNK_PRINT
    Serial.println("[_\\|/_] TimeLib: not set."); // this is where you get concerned
    #endif

    // time library has never been set exit the function so we don't overwrite RTC values
    return;
    }

    if (timestatus == 1)
    {
    // time library needs synchronization, wait for time status to change
    // before comparing RTC
    #ifdef BLYNK_PRINT
    Serial.println("[_\\|/_] TimeLib: needs synchronization.");
    #endif

    return;
    }

    if (timestatus == 2)
    {
    RTC.getTime();

    // check RTC values against the synchronized TimeLib value
    // TODO: change this to do simple unix epoch comparison, PCF85063TP.h doesn't support this
    if ((RTC.year + 2000) != year() || RTC.month != month() || RTC.dayOfMonth != day() || RTC.hour != hour() || RTC.minute != minute() || RTC.second != second())
    {
    #ifdef BLYNK_PRINT
    // display the current values of each
    Serial.println("[_\\|/_] TimeLib: RTC not matched. Resynchronizing RTC.");

    sprintf(currentDate, "%02d/%02d/%04d", month(), day(), year());
    sprintf(currentTime, "%02d:%02d:%02d", hour(), minute(), second());
    Serial.print("[_\\|/_] TimeLib: ");
    Serial.print(currentDate);
    Serial.print (" ");
    Serial.println(currentTime);

    // depending on the RTC library used, the RTC property names could be different
    // i.e. RTC.month vs RTC.month()
    sprintf(currentDate, "%02d/%02d/%04d", RTC.month, RTC.dayOfMonth, RTC.year);
    sprintf(currentTime, "%02d:%02d:%02d", RTC.hour, RTC.minute, RTC.second);
    Serial.print("[_\\|/_] RTC Time: ");
    Serial.print(currentDate);
    Serial.print(" ");
    Serial.println(currentTime);
    #endif

    // set the RTC to TimeLib values here
    RTC.stopClock();
    RTC.fillByYMD(year(), month(), day());
    RTC.fillByHMS(hour(), minute(), second());
    RTC.setTime();
    RTC.startClock();

    return;
    }

    #ifdef BLYNK_PRINT
    Serial.println("[_\\|/_] TimeLib: RTC matches.");
    #endif
    }
    }

    //
    // checks connection to Blynk server and attempts reconnect if needed
    //
    void checkBlynkConnection()
    {
    if (!Blynk.connected() && !connectInProgress)
    {
    connectInProgress = true;

    if(!Blynk.connect())
    {
    #ifdef BLYNK_PRINT
    Serial.println("[_\\|/_] Blynk Connect failed");
    #endif
    }
    else
    {
    #ifdef BLYNK_PRINT
    Serial.println("[_\\|/_] Blynk Connected");
    #endif
    }

    connectInProgress = false; // either it connected or timed out
    }
    }

    int freeRam()
    {
    extern int __heap_start, *__brkval;
    int v;
    return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
    }

    void checkMemory()
    {
    #ifdef BLYNK_PRINT
    Serial.print("[_\\|/_] SRAM: ");
    Serial.println(freeRam());
    #endif
    }

    //
    // all initialization and timer setups go here
    //
    void setup()
    {
    Serial.begin(115200);
    RTC.begin();

    // timer tasks
    blynkTimerId = blynkTimer.setInterval(150000L, syncRTCHardware); // synchronize the RTC every 2.5 minutes
    connectTimerId = blynkTimer.setInterval(300000L, checkBlynkConnection); // check Blynk connection every 5 minutes

    // non-blocking Blynk setup
    Blynk.config(auth, BLYNK_DEFAULT_DOMAIN, BLYNK_DEFAULT_PORT);
    Blynk.disconnect(); // skip connecting to the Blynk server until checkBlynkConnection timer fires

    // this allows setup() to continue/exit and the main loop() to begin without blocking
    blynkTimer.setTimeout(2000L, checkBlynkConnection); // in 2 seconds, do initial connection check
    blynkTimer.setTimeout(10000L, syncRTCHardware); // in 10 seconds, do initial time check
    blynkTimer.setTimeout(3000L, checkMemory);
    }

    // Main processing loop.
    void loop()
    {
    blynkTimer.run();

    // only attempt Blynk-related functions when connected to Blynk
    if (Blynk.connected())
    {
    Blynk.run();
    }
    }