text: #include "Arduino.h"
  #include <ESP8266WiFi.h>
  #include <ESP8266HTTPClient.h>
  #include <ESP8266httpUpdate.h>
  #include <time.h>
  
  #include "DTF_ESP8266Update.h"
  
  const char* rootCACertificate PROGMEM = \
  "-----BEGIN CERTIFICATE-----\n" \
  "MIIFFjCCAv6gAwIBAgIRAJErCErPDBinU/bWLiWnX1owDQYJKoZIhvcNAQELBQAw\n" \
  "TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n" \
  "cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMjAwOTA0MDAwMDAw\n" \
  "WhcNMjUwOTE1MTYwMDAwWjAyMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3Mg\n" \
  "RW5jcnlwdDELMAkGA1UEAxMCUjMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\n" \
  "AoIBAQC7AhUozPaglNMPEuyNVZLD+ILxmaZ6QoinXSaqtSu5xUyxr45r+XXIo9cP\n" \
  "R5QUVTVXjJ6oojkZ9YI8QqlObvU7wy7bjcCwXPNZOOftz2nwWgsbvsCUJCWH+jdx\n" \
  "sxPnHKzhm+/b5DtFUkWWqcFTzjTIUu61ru2P3mBw4qVUq7ZtDpelQDRrK9O8Zutm\n" \
  "NHz6a4uPVymZ+DAXXbpyb/uBxa3Shlg9F8fnCbvxK/eG3MHacV3URuPMrSXBiLxg\n" \
  "Z3Vms/EY96Jc5lP/Ooi2R6X/ExjqmAl3P51T+c8B5fWmcBcUr2Ok/5mzk53cU6cG\n" \
  "/kiFHaFpriV1uxPMUgP17VGhi9sVAgMBAAGjggEIMIIBBDAOBgNVHQ8BAf8EBAMC\n" \
  "AYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMBMBIGA1UdEwEB/wQIMAYB\n" \
  "Af8CAQAwHQYDVR0OBBYEFBQusxe3WFbLrlAJQOYfr52LFMLGMB8GA1UdIwQYMBaA\n" \
  "FHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEBBCYwJDAiBggrBgEFBQcw\n" \
  "AoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzAnBgNVHR8EIDAeMBygGqAYhhZodHRw\n" \
  "Oi8veDEuYy5sZW5jci5vcmcvMCIGA1UdIAQbMBkwCAYGZ4EMAQIBMA0GCysGAQQB\n" \
  "gt8TAQEBMA0GCSqGSIb3DQEBCwUAA4ICAQCFyk5HPqP3hUSFvNVneLKYY611TR6W\n" \
  "PTNlclQtgaDqw+34IL9fzLdwALduO/ZelN7kIJ+m74uyA+eitRY8kc607TkC53wl\n" \
  "ikfmZW4/RvTZ8M6UK+5UzhK8jCdLuMGYL6KvzXGRSgi3yLgjewQtCPkIVz6D2QQz\n" \
  "CkcheAmCJ8MqyJu5zlzyZMjAvnnAT45tRAxekrsu94sQ4egdRCnbWSDtY7kh+BIm\n" \
  "lJNXoB1lBMEKIq4QDUOXoRgffuDghje1WrG9ML+Hbisq/yFOGwXD9RiX8F6sw6W4\n" \
  "avAuvDszue5L3sz85K+EC4Y/wFVDNvZo4TYXao6Z0f+lQKc0t8DQYzk1OXVu8rp2\n" \
  "yJMC6alLbBfODALZvYH7n7do1AZls4I9d1P4jnkDrQoxB3UqQ9hVl3LEKQ73xF1O\n" \
  "yK5GhDDX8oVfGKF5u+decIsH4YaTw7mP3GFxJSqv3+0lUFJoi5Lc5da149p90Ids\n" \
  "hCExroL1+7mryIkXPeFM5TgO9r0rvZaBFOvV2z0gp35Z0+L4WPlbuEjN/lxPFin+\n" \
  "HlUjr8gRsI3qfJOQFy/9rKIJR0Y/8Omwt/8oTWgy1mdeHmmjk7j1nYsvC9JSQ6Zv\n" \
  "MldlTTKB3zhThV1+XWYp6rjd5JW1zbVWEkLNxE7GJThEUG3szgBVGP7pSWTUTsqX\n" \
  "nLRbwHOoq7hHwg==\n" \
  "-----END CERTIFICATE-----\n";
  
  void setSystemTime()
  {
      configTime(0, 0, "pool.ntp.org", "time.nist.gov");
  
      #ifdef DTF_DEBUG
      Serial.print(F("Waiting for NTP time sync: "));
      #endif
  
      time_t now = time(nullptr);
      while (now < 8 * 3600 * 2) {
          yield();
          delay(500);
          #ifdef DTF_DEBUG
          Serial.print(F("."));
          #endif
          now = time(nullptr);
      }
  
      #ifdef DTF_DEBUG
      Serial.println(F(""));
      #endif
      struct tm timeinfo;
      gmtime_r(&now, &timeinfo);
  
      #ifdef DTF_DEBUG
      Serial.print(F("Current time: "));
      Serial.print(asctime(&timeinfo));
      #endif
  }
  
  void DTF_ESP8266Update::DTF_UpdateStart() {
      #ifdef DTF_DEBUG
      Serial.println("Callback: OTA Update Started");
      #endif
  }
  
  void DTF_ESP8266Update::DTF_UpdateFinished() {
      #ifdef DTF_DEBUG
      Serial.println("Callback: OTA Update Finished Successfully");
      #endif
  }
  
  void DTF_ESP8266Update::DTF_UpdateProgress(int _current, int _total) {
      static int last_percentage = 0;
      if (last_percentage >= 100) {
          return;
      }
  
      int percentage = (int)((float)_current/(float)_total * 100);
  
      if ((percentage >= (last_percentage + 10)) || percentage == 100) {
          last_percentage = percentage;
          #ifdef DTF_DEBUG
          Serial.print("+");
          if (percentage >= 100) {
              Serial.println();
          }
          #endif
      }
  }
  
  DTF_UpdateResponse DTF_ESP8266Update::getFirmwareUpdate(const char* updateUrl, const char* currentVersion, bool setTime)
  {
      static BearSSL::X509List x509(rootCACertificate);
      
      #ifdef DTF_DEBUG
      Serial.println("Checking for firmware updates");
      #endif
  
      // Ensure the current time is set and accurate
      if (setTime)
      {
          setSystemTime();
      }
  
      // Create a secure client using the Let's Encrypt certificate
      BearSSL::WiFiClientSecure client;
      client.setTrustAnchors(&x509);
      client.setTimeout(20); // 20 second timeout
  
      // Callbacks setting
      ESPhttpUpdate.onStart(DTF_UpdateStart);
      ESPhttpUpdate.onEnd(DTF_UpdateFinished);
      ESPhttpUpdate.onProgress(DTF_UpdateProgress);
  
      // The following line invokes the update library and will send all necessary headers
      // to Deploy the Fleet for it to decision an update. Make sure the version argument
      // is always accurate as this is used to determine if a device needs an update or not.
      // Get the URL from your product dashboard in Deploy the Fleet
      t_httpUpdate_return ret = ESPhttpUpdate.update(client, updateUrl, currentVersion);
  
      switch (ret) {
          case HTTP_UPDATE_FAILED:
              #ifdef DTF_DEBUG
              Serial.printf("HTTP_UPDATE_FAILED Error (%d): %s\n", ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str());
              #endif
              return DTF_UpdateResponse::UPDATE_FAILED;
              break;
  
          case HTTP_UPDATE_NO_UPDATES:
              #ifdef DTF_DEBUG
              Serial.println("No updates are available for this device.");
              #endif
              return DTF_UpdateResponse::NO_UPDATE_AVAILABLE;
              break;
      }
  }