Arduino Library Reference

Below is the list of OTAdrive library methods.

Method Description
setInfo Sets general information about your firmware. You should call this method first.
useMD5Matcher Enable/Disable using firmware MD5 to decide whether to start the update or not.
updateFirmwareInfo Returns data about new firmware on the OTAdrive if available. It's useful to show users some data before starting the update progress.
updateFirmware Updates firmware from the OTAdrive server, if a newer version is available.
sendAlive Sends a request to the server containing the last status of the device
onUpdateFirmwareProgress Sets your callback method for updating firmware progress
syncResources Syncs SPIFFS files with the OTAdrive server
setFileSystem Sets the fileSystem object. You have to call it before using syncResources()
timeTick A helper for periodical syncing
getConfigs Deprecated, use getJsonConfigs
getJsonConfigs Gets device configuration as a json string
getConfigValues Gets device configuration as a key-value easy to use object
useSSL Enables SSL secure connection mode in the whole library
setChipId Override the chip serial number.

setInfo

void setInfo(String apiKey,String firmwareVersion)

You have to call setInfo once and before any usage of OTAdrive library.

void setup()
{
  ...
  // Set ApiKey and firmware version of your device
  // Remember, You have to change the version field before
  //   upload the firmware.bin to the OTAdrive
  OTADRIVE.setInfo("c0af643b-4f90-4905-9807-db8be5164cde", "v@2.5.5");
}

useMD5Matcher

void useMD5Matcher(bool useMd5)

There are two strategies to decide update the device's firmware from the OTAdrive or not.

  • Version Matching: The legacy method is to check version code matching. In this mechanism, the library starts to update if the version number of the device's firmware is different from the version number of the firmware that is set to the device's group belongs.
  • MD5 Matching: This mechanism is used by the OTAdrive library as the default strategy from v1.1.10. In this mechanism, The version number is ignored and the library starts to update if the MD5 checksum of the device's firmware is different from the MD5 checksum of the firmware that is set to the device's group belongs. That means if every single byte of the firmware changes, the library detects it and starts to download the firmware from the OTAdrive.
void setup()
{
  ...
  OTADRIVE.setInfo("c0af643b-4f90-4905-9807-db8be5164cde", "v@2.5.5");
  OTADRIVE.useMD5Matcher(true); // or useMD5Matcher(false);
}

updateFirmwareInfo

updateInfo updateFirmwareInfo()

This method calls to update firmware API and gets the status of the new firmware if a newer(different) version is available on the OTAdrive server. You can show the information to the user.

auto uinf = OTADRIVE.updateFirmwareInfo();
if (uinf.available)
{
  Serial.printf("A new version %s with size %dBytes available.\n", uinf.version.c_str(), uinf.size);
  // wait user to click OK button to start download
  for (uint8_t time = 0; time < 30; time++)
  {
    if (digitalRead(BTN_ON))
    {
      OTADRIVE.updateFirmware();
    }
  }
}

updateFirmware

updateInfo updateFirmware(bool reboot = true)

This method calls update firmware API and updates your ESP8266/ESP32 firmware if a newer(different) version available on the OTAdrive server. You can show the update progress to users by using onUpdateFirmwareProgress event.
After successfull firmware update, the device should reset. If you want to do something before restart (for exampl save some value), you should pass reboot parameter as false, then you have to call ESP.restart() yourself.

// The device will reboot here on success update
auto r = OTADRIVE.updateFirmware();
Serial.printf("Update result is: %s\n", r.toString().c_str());

sendAlive

bool sendAlive()

The method sends a request to the OTAdrive sever, includes the statuses of the device such as firmware version, battery voltage, RSSI, etc. Just call this method every time you want.

OTADRIVE.sendAlive();

onUpdateFirmwareProgress

void onUpdateFirmwareProgress(THandlerFunction_Progress fn)

If you want to show update progressbar to the device's user, You can use this method to get download percentage of the new firmware.
The method has two parameters, total contains size of the new firmware and progress contains the number of downloaded bytes.
Following code shows how to show a update progressbar.

void onUpdateProgress(int progress, int totalt)
{
  static int last = 0;
  int progressPercent = (100 * progress) / totalt;
  Serial.print("*");
  if (last != progressPercent && progressPercent % 10 == 0)
  {
    // print every 10%
    Serial.printf("%d", progressPercent);
  }
  last = progressPercent;
}

void setup()
{
  ...
  OTADRIVE.onUpdateFirmwareProgress(onUpdateProgress);
}

syncResources

bool syncResources()

This method calls resource API and downloads new files from the server to local storage (SPIFFS or LittleFS). If you modify files on the server, this method detects changes and replaces the old file with the modified file.

// sync local files with OTAdrive server
OTADRIVE.syncResources();

setFileSystem

void setFileSystem(FS *fileObj)

If you have resources (HTML, JS, MP3, JPG, etc.) for the update, The library should download and save them to the device storage with a suitable file system. There are at least two different kinds of file systems developed for ESP MCUs, The SPIFFS, and The LittleFS. The library will choose The SPIFFS for ESP32 and The LittleFS for ESP8266 automatically. If you want to change the file system handler to something else, you should call this method.

OTADRIVE.setFileSystem(/*pointer to your file system object*/)

timeTick

bool timeTick(uint16_t seconds)

This method helps you to manage intervals between each update/sync operation between your device and the OTAdrive.
The following example shows how to check and update firmware every 5 minutes (300 seconds).

void loop()
{
  ...
  if (OTADRIVE.timeTick(300))
  {
    auto r = OTADRIVE.updateFirmware();
    Serial.printf("Update result is: %s\n", r.toString().c_str());
  }
}

getConfigs

String getConfigs()

Deprecated. Check getJsonConfigs

getJsonConfigs

String getJsonConfigs()

This method calls configuration API and gets the configuration of the device from the server. It returns a string containing JSON configurations.

String c = OTADRIVE.getConfigs();
Serial.printf("configuration: %s\n", c.c_str());

getConfigValues

OTAdrive_ns::KeyValueList getConfigValues()

This method calls configuration API and gets the configuration of the device from the server as an object of key-values. for example imagine following json as your configuration.

{
    "speed":180,
    "alarm":{
        "number":"+188554436",
        "msg1":"Fire, please help",
        "msg2":"Emergency, please help"
    }
}

Then your code to load configuration should be something like this.

// define key-value object in global
OTAdrive_ns::KeyValueList configs;
int speed = 100;
String alarm_num;
String alarm_msg1;
String alarm_msg2;
...
// download configs
configs = OTADRIVE.getConfigValues();
// validate and apply configs
if (configs.containsKey("speed"))
{
    speed = configs.value("speed").toInt();
    Serial.printf("configuration parameter [speed]: %d\n", speed);
}

if(configs.containsKey("alarm.number"))
    alarm_num = configs.value("alarm.number");

if(configs.containsKey("alarm.msg1"))
    alarm_msg1 = configs.value("alarm.msg1");

if(configs.containsKey("alarm.msg2"))
    alarm_msg1 = configs.value("alarm.msg2");

useSSL

void useSSL(bool ssl)

Enables using SSL secure connection in the whole library. You should call this method once in the setup procedure.

void setup()
{
    ...
    OTADRIVE.setInfo(APIKEY, FW_VER);
    // enable SSL secure connection
    OTADRIVE.useSSL(true);
}

After enabling the SSL, you should initialize and pass a SecureClient object to methods.

{
    ...
    WiFiClientSecure ssl_client;
    ssl_client.setCACert(otadrv_ca);

    
    OTADRIVE.updateFirmwareInfo(ssl_client);
    OTADRIVE.updateFirmware(ssl_client);
    OTADRIVE.getConfigValues(ssl_client);
    OTADRIVE.syncResources(ssl_client);
    ...
}

Extra security

You can validate peer certificate and check it yourself. The following code helps you to ensure there is no man-in-the-middle during the OTA operations.

bool checkPeer(WiFiClientSecure &ssl_client)
{
  // We should check that SSL certificate on the server is belongs to
  // the "otadrive.com" or it may be an fake middle SSL.
  // This make the connection procedure a bit slower
  if (ssl_client.connect("otadrive.com", 443))
  {
    auto peer = ssl_client.getPeerCertificate();
    if (peer == NULL)
    {
      log_e("Faild to get SSL peer");
      return false;
    }
    
    if (peer->subject.val.p == nullptr)
    {
      log_e("Faild to get correct SSL peer");
      return false;
    }

    if (strncmp((char *)peer->subject.val.p, "*.otadrive.com", 14) == 0 ||
        strncmp((char *)peer->subject.val.p, "otadrive.com", 12) == 0)
    {
      log_i("Certificate valid for otadrive.com");
    }
    else
    {
      log_e("Certificate is not valid %s", peer->subject.val.p);
      return false;
    }
  }
  else
  {
    log_e("Faild to connect SSL peer");
    return false;
  }
  return true;
}

setChipId

void setChipId(String id)

The library uses the chip's MAC address as the device serial number. If you want to use something else as the serial number, you have to call this method after setInfo on the setup procedure.

void setup()
{
    ...
    OTADRIVE.setInfo(APIKEY, FW_VER);
    // change the serial number to something else
    // for example obtain it from gsm modem IMEI, external EEPROM uid, etc.
    String mySerial = some_method();
    OTADRIVE.setChipId(mySerial);
}