diff --git a/.github/workflows/compile-examples.yml b/.github/workflows/compile-examples.yml
index 2149fe4c8..fdf0f323b 100644
--- a/.github/workflows/compile-examples.yml
+++ b/.github/workflows/compile-examples.yml
@@ -58,7 +58,7 @@ jobs:
               - name: ArduinoECCX08
               - name: RTCZero
               - name: WiFi101
-              - name: WiFiNINA
+              - source-url: https://github.com/arduino-libraries/WiFiNINA.git
               - name: Arduino_MKRMEM
             sketch-paths: '"examples/utility/Provisioning"'
           # LoRaWAN boards
diff --git a/extras/test/CMakeLists.txt b/extras/test/CMakeLists.txt
index 5269338c7..dd7b3e990 100644
--- a/extras/test/CMakeLists.txt
+++ b/extras/test/CMakeLists.txt
@@ -12,7 +12,6 @@ include_directories(include)
 include_directories(../../src)
 include_directories(../../src/cbor)
 include_directories(../../src/property)
-include_directories(../../src/utility/ota)
 include_directories(external/catch/v2.12.1/include)
 include_directories(external/fakeit/v2.0.5/include)
 
@@ -29,8 +28,6 @@ set(TEST_TARGET ${CMAKE_PROJECT_NAME})
 ##########################################################################
 
 set(TEST_SRCS
-  src/test_OTALogic.cpp
-
   src/test_addPropertyReal.cpp
   src/test_callback.cpp
   src/test_CloudColor.cpp
@@ -46,14 +43,10 @@ set(TEST_SRCS
 
 set(TEST_UTIL_SRCS
   src/util/CBORTestUtil.cpp
-  src/util/OTATestUtil.cpp
   src/util/PropertyTestUtil.cpp
 )
 
 set(TEST_DUT_SRCS
-  ../../src/utility/ota/crc.cpp
-  ../../src/utility/ota/OTALogic.cpp
-
   ../../src/property/Property.cpp
   ../../src/property/PropertyContainer.cpp
   ../../src/cbor/CBORDecoder.cpp
diff --git a/extras/test/include/util/OTATestUtil.h b/extras/test/include/util/OTATestUtil.h
deleted file mode 100644
index 640d422a2..000000000
--- a/extras/test/include/util/OTATestUtil.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2020 Arduino.  All rights reserved.
- */
-
-#ifndef OTA_TEST_DATA_GENERATOR_H_
-#define OTA_TEST_DATA_GENERATOR_H_
-
-/**************************************************************************************
-   INCLUDE
- **************************************************************************************/
-
-#include <stdint.h>
-
-/**************************************************************************************
-   NAMESPACE
- **************************************************************************************/
-
-namespace ota
-{
-
-/**************************************************************************************
-   TYPEDEF
- **************************************************************************************/
-
-union OTAData
-{
-  struct __attribute__((packed))
-  {
-    uint32_t len;
-    uint32_t crc32;
-    uint8_t  bin[256*1024]; /* Maximum flash size of ATSAMD21G18 is 256 KB */
-  } data;
-  uint8_t buf[sizeof(data)];
-};
-
-/**************************************************************************************
-   FUNCTION DECLARATION
- **************************************************************************************/
-
-void generate_valid_ota_data(OTAData & ota_data);
-void generate_invalid_ota_data_crc_wrong(OTAData & ota_data);
-
-/**************************************************************************************
-   NAMESPACE
- **************************************************************************************/
-
-} /* ota */
-
-#endif /* OTA_TEST_DATA_GENERATOR_H_ */
diff --git a/extras/test/src/test_OTALogic.cpp b/extras/test/src/test_OTALogic.cpp
deleted file mode 100644
index b1b8b8139..000000000
--- a/extras/test/src/test_OTALogic.cpp
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * Copyright (c) 2020 Arduino.  All rights reserved.
- */
-
-/**************************************************************************************
-   INCLUDE
- **************************************************************************************/
-
-#include <vector>
-#include <algorithm>
-
-#include <catch.hpp>
-#include <fakeit.hpp>
-
-#include <util/OTATestUtil.h>
-
-#include <OTALogic.h>
-#include <OTAStorage.h>
-
-/**************************************************************************************
-   NAMESPACE
- **************************************************************************************/
-
-using namespace fakeit;
-
-/**************************************************************************************
-   TEST HELPER
- **************************************************************************************/
-
-void simulateOTABinaryReception(OTALogic & ota_logic, ota::OTAData const & ota_test_data)
-{
-  uint32_t bytes_written = 0;
-  uint32_t const bytes_to_write = sizeof(uint32_t) + sizeof(uint32_t) + ota_test_data.data.len;
-  for(; bytes_written < (bytes_to_write - MQTT_OTA_BUF_SIZE); bytes_written += MQTT_OTA_BUF_SIZE)
-  {
-    ota_logic.onOTADataReceived(ota_test_data.buf + bytes_written, MQTT_OTA_BUF_SIZE);
-    ota_logic.update();
-  }
-
-  if(bytes_written < bytes_to_write)
-  {
-    uint32_t const remaining_bytes = (bytes_to_write - bytes_written);
-    ota_logic.onOTADataReceived(ota_test_data.buf + bytes_written, remaining_bytes);
-    ota_logic.update();
-  }
-}
-
-/**************************************************************************************
-   TEST CODE
- **************************************************************************************/
-
-TEST_CASE("No OTA Storage configured", "[OTALogic-01]")
-{
-  /* Perform test */
-  OTALogic ota_logic;
-
-  WHEN("OTALogic::update() is called")
-  {
-    ota_logic.update();
-    THEN("The OTA logic should be in the 'Error' state")
-    {
-      REQUIRE(ota_logic.state()  == OTAState::Error);
-    }
-    THEN("The OTA error should be set to OTAError::NoOTAStorageConfigured")
-    {
-      REQUIRE(ota_logic.error() == OTAError::NoOTAStorageConfigured);
-    }
-  }
-}
-
-/**************************************************************************************/
-
-TEST_CASE("OTAStorage initialisation fails", "[OTAStorage::init() -> returns false]")
-{
-  Mock<OTAStorage> ota_storage;
-
-  /* Configure mock object */
-  When(Method(ota_storage, init)).Return(false);
-  Fake(Method(ota_storage, open));
-  Fake(Method(ota_storage, write));
-  Fake(Method(ota_storage, close));
-  Fake(Method(ota_storage, remove));
-  Fake(Method(ota_storage, rename));
-  Fake(Method(ota_storage, deinit));
-
-
-  /* Perform test */
-  OTALogic ota_logic;
-  ota_logic.setOTAStorage(ota_storage.get());
-
-  WHEN("OTALogic::update() is called")
-  {
-    ota_logic.update();
-    THEN("The OTA logic should be in the 'Error' state")
-    {
-      REQUIRE(ota_logic.state()  == OTAState::Error);
-    }
-    THEN("The OTA error should be set to OTAError::StorageInitFailed")
-    {
-      REQUIRE(ota_logic.error() == OTAError::StorageInitFailed);
-    }
-  }
-}
-
-/**************************************************************************************/
-
-TEST_CASE("OTAStorage opening of storage file fails", "[OTAStorage::open() -> returns false]")
-{
-  Mock<OTAStorage> ota_storage;
-
-  /* Configure mock object */
-  When(Method(ota_storage, init)).Return(true);
-  When(Method(ota_storage, open)).Return(false);
-  Fake(Method(ota_storage, write));
-  Fake(Method(ota_storage, close));
-  Fake(Method(ota_storage, remove));
-  Fake(Method(ota_storage, rename));
-  Fake(Method(ota_storage, deinit));
-
-
-  /* Perform test */
-  OTALogic ota_logic;
-  ota_logic.setOTAStorage(ota_storage.get());
-
-  WHEN("OTALogic::update() is called and some bytes have been received")
-  {
-    uint8_t const SOME_FAKE_DATA[16] = {0};
-    ota_logic.onOTADataReceived(SOME_FAKE_DATA, sizeof(SOME_FAKE_DATA));
-    ota_logic.update();
-    
-    THEN("The OTA logic should be in the 'Error' state")
-    {
-      REQUIRE(ota_logic.state()  == OTAState::Error);
-    }
-    THEN("The OTA error should be set to OTAError::StorageOpenFailed")
-    {
-      REQUIRE(ota_logic.error() == OTAError::StorageOpenFailed);
-    }
-  }
-}
-
-
-/**************************************************************************************/
-
-TEST_CASE("OTAStorage writing to storage file fails", "[OTAStorage::write() -> fails]")
-{
-  Mock<OTAStorage> ota_storage;
-
-  /* Configure mock object */
-  When(Method(ota_storage, init)).Return(true);
-  When(Method(ota_storage, open)).Return(true);
-  When(Method(ota_storage, write)).AlwaysDo([](uint8_t const * const /* buf */, size_t const /* num_bytes */) -> size_t { return 0 /* should return num_bytes in case of success */;});
-  Fake(Method(ota_storage, close));
-  Fake(Method(ota_storage, remove));
-  Fake(Method(ota_storage, rename));
-  Fake(Method(ota_storage, deinit));
-
-
-  /* Perform test */
-  OTALogic ota_logic;
-  ota_logic.setOTAStorage(ota_storage.get());
-
-  WHEN("OTALogic::update() is called and some bytes have been received")
-  {
-    uint8_t const SOME_FAKE_DATA[16] = {0};
-    ota_logic.onOTADataReceived(SOME_FAKE_DATA, sizeof(SOME_FAKE_DATA));
-    ota_logic.update();
-
-    THEN("The OTA logic should be in the 'Error' state")
-    {
-      REQUIRE(ota_logic.state()  == OTAState::Error);
-    }
-    THEN("The OTA error should be set to OTAError::StorageWriteFailed")
-    {
-      REQUIRE(ota_logic.error() == OTAError::StorageWriteFailed);
-    }
-  }
-}
-
-/**************************************************************************************/
-
-TEST_CASE("Data overrun due to receiving too much data", "[OTALogic - Data Overrun]")
-{
-  Mock<OTAStorage> ota_storage;
-
-  /* Configure mock object */
-  When(Method(ota_storage, init)).Return(true);
-  When(Method(ota_storage, open)).Return(true);
-  When(Method(ota_storage, write)).AlwaysDo([](uint8_t const * const /* buf */, size_t const num_bytes) -> size_t { return num_bytes; });
-  Fake(Method(ota_storage, close));
-  Fake(Method(ota_storage, remove));
-  Fake(Method(ota_storage, rename));
-  Fake(Method(ota_storage, deinit));
-
-
-  /* Perform test */
-  OTALogic ota_logic;
-  ota_logic.setOTAStorage(ota_storage.get());
-
-  WHEN("Too much data is received before OTALogic::update() is called again to process the incoming data")
-  {
-    uint8_t const SOME_FAKE_DATA[MQTT_OTA_BUF_SIZE] = {0};
-    ota_logic.onOTADataReceived(SOME_FAKE_DATA, MQTT_OTA_BUF_SIZE);
-    ota_logic.onOTADataReceived(SOME_FAKE_DATA, MQTT_OTA_BUF_SIZE);
-    ota_logic.update();
-
-    THEN("The OTA logic should be in the 'Error' state")
-    {
-      REQUIRE(ota_logic.state()  == OTAState::Error);
-    }
-    THEN("The OTA error should be set to OTAError::ReceivedDataOverrun")
-    {
-      REQUIRE(ota_logic.error() == OTAError::ReceivedDataOverrun);
-    }
-  }
-}
-
-/**************************************************************************************/
-
-TEST_CASE("Valid OTA data is received ", "[OTALogic]")
-{
-  Mock<OTAStorage> ota_storage;
-  std::vector<uint8_t> ota_binary_data;
-
-  /* Configure mock object */
-  When(Method(ota_storage, init)).Return(true);
-  When(Method(ota_storage, open)).Return(true);
-  When(Method(ota_storage, write)).AlwaysDo(
-    [&ota_binary_data](uint8_t const * const buf, size_t const num_bytes) -> size_t
-    {
-      std::copy(buf, buf + num_bytes, std::back_inserter(ota_binary_data));
-      return num_bytes;
-    });
-  Fake(Method(ota_storage, close));
-  Fake(Method(ota_storage, remove));
-  When(Method(ota_storage, rename)).Return(true);
-  Fake(Method(ota_storage, deinit));
-
-
-  /* Generate test data */
-  ota::OTAData valid_ota_test_data;
-  ota::generate_valid_ota_data(valid_ota_test_data);
-
-
-  /* Perform test */
-  OTALogic ota_logic;
-  ota_logic.setOTAStorage(ota_storage.get());
-  simulateOTABinaryReception(ota_logic, valid_ota_test_data);
-
-
-  /* Perform checks */
-  THEN("the complete binary file should have been written to the OTA storage")
-  {
-    REQUIRE(ota_binary_data.size() == valid_ota_test_data.data.len);
-    REQUIRE(std::equal(ota_binary_data.begin(),
-                       ota_binary_data.end(),
-                       valid_ota_test_data.data.bin));
-  }
-
-  THEN("The temporary file UPDATE.BIN.TMP should have been renamed to UPDATE.BIN")
-  {
-    Verify(Method(ota_storage, rename)).Once();
-  }
-
-  THEN("The OTA logic should be in the 'Reset' state")
-  {
-    REQUIRE(ota_logic.state() == OTAState::Reset);
-  }
-
-  THEN("No OTA error should have occurred")
-  {
-    REQUIRE(ota_logic.error() == OTAError::None);
-  }
-}
-
-/**************************************************************************************/
-
-TEST_CASE("Valid OTA data is received but the rename step failed (identical too device being turned off during writing of file)", "[OTALogic - Rename fail]")
-{
-  Mock<OTAStorage> ota_storage;
-
-  /* Configure mock object */
-  When(Method(ota_storage, init)).Return(true);
-  When(Method(ota_storage, open)).Return(true);
-  When(Method(ota_storage, write)).AlwaysDo([](uint8_t const * const /* buf */, size_t const num_bytes) -> size_t { return num_bytes; });
-  Fake(Method(ota_storage, close));
-  Fake(Method(ota_storage, remove));
-  When(Method(ota_storage, rename)).Return(false);
-  Fake(Method(ota_storage, deinit));
-
-
-  /* Generate test data */
-  ota::OTAData valid_ota_test_data;
-  ota::generate_valid_ota_data(valid_ota_test_data);
-
-
-  /* Perform test */
-  OTALogic ota_logic;
-  ota_logic.setOTAStorage(ota_storage.get());
-  simulateOTABinaryReception(ota_logic, valid_ota_test_data);
-
-
-  /* Perform checks */
-  THEN("The OTA logic should be in the 'Error' state")
-  {
-    REQUIRE(ota_logic.state() == OTAState::Error);
-  }
-
-  THEN("The OTA error should be set to OTAError::RenameOfTempFileFailed")
-  {
-    REQUIRE(ota_logic.error() == OTAError::RenameOfTempFileFailed);
-  }
-}
-
-/**************************************************************************************/
-
-TEST_CASE("Invalid OTA data is received ", "[OTALogic - CRC wrong]")
-{
-  Mock<OTAStorage> ota_storage;
-
-
-  /* Configure mock object */
-  When(Method(ota_storage, init)).Return(true);
-  When(Method(ota_storage, open)).Return(true);
-  When(Method(ota_storage, write)).AlwaysDo([](uint8_t const * const /* buf */, size_t const num_bytes) -> size_t { return num_bytes; });
-  Fake(Method(ota_storage, close)); 
-  Fake(Method(ota_storage, remove)); 
-  Fake(Method(ota_storage, rename));
-  Fake(Method(ota_storage, deinit)); 
-
-
-  /* Generate test data */
-  ota::OTAData invalid_valid_ota_test_data_crc_wrong;
-  ota::generate_invalid_ota_data_crc_wrong(invalid_valid_ota_test_data_crc_wrong);
-
-
-  /* Perform test */
-  OTALogic ota_logic;
-  ota_logic.setOTAStorage(ota_storage.get());
-  simulateOTABinaryReception(ota_logic, invalid_valid_ota_test_data_crc_wrong);
-
-
-  /* Perform checks */
-  THEN("there should be no binary file be stored on the OTA storage")
-  {
-    Verify(Method(ota_storage, remove)).Once();
-  }
-
-  THEN("The OTA logic should be in the 'Error' state")
-  {
-    REQUIRE(ota_logic.state() == OTAState::Error);
-  }
-
-  THEN("The OTA error should be set to OTAError::ChecksumMismatch")
-  {
-    REQUIRE(ota_logic.error() == OTAError::ChecksumMismatch);
-  }
-}
\ No newline at end of file
diff --git a/extras/test/src/util/OTATestUtil.cpp b/extras/test/src/util/OTATestUtil.cpp
deleted file mode 100644
index ac7e26026..000000000
--- a/extras/test/src/util/OTATestUtil.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2020 Arduino.  All rights reserved.
- */
-
-/**************************************************************************************
-   INCLUDE
- **************************************************************************************/
-
-#include <util/OTATestUtil.h>
-
-#include <algorithm>
-
-#include <crc.h>
-
-/**************************************************************************************
-   NAMESPACE
- **************************************************************************************/
-
-namespace ota
-{
-
-/**************************************************************************************
-   FUNCTION DEFINITION
- **************************************************************************************/
-
-void generate_valid_ota_data(OTAData & ota_data)
-{
-  /* Set length. Attention: header length (8 bytes for len and crc32 are not included - this is only the payload length. */
-  ota_data.data.len = 64 * 1024;
-  
-  /* Fill array */
-  std::generate(ota_data.data.bin,
-                ota_data.data.bin + ota_data.data.len,
-                [](void) -> uint8_t
-                {
-                  static uint8_t val = 0;
-                  return val++;
-                });
-
-  /* Generate CRC */
-  crc_t crc32 = crc_init();
-  std::for_each(ota_data.data.bin,
-                ota_data.data.bin + ota_data.data.len,
-                [&crc32](uint8_t const data)
-                {
-                  crc32 = crc_update(crc32, &data, 1);
-                });
-  ota_data.data.crc32 = crc_finalize(crc32);
-}
-
-void generate_invalid_ota_data_crc_wrong(OTAData & ota_data)
-{
-  /* Set length. Attention: header length (8 bytes for len and crc32 are not included - this is only the payload length. */
-  ota_data.data.len = 64 * 1024;
-
-  /* Fill array */
-  std::generate(ota_data.data.bin,
-                ota_data.data.bin + ota_data.data.len,
-                [](void) -> uint8_t
-                {
-                  static uint8_t val = 0;
-                  return val++;
-                });
-
-  /* Generate CRC */
-  ota_data.data.crc32 = 0xDEADBEEF;
-}
-
-/**************************************************************************************
-   NAMESPACE
- **************************************************************************************/
-
-} /* ota */
diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp
index 10999e584..f1c2825c1 100644
--- a/src/ArduinoIoTCloudTCP.cpp
+++ b/src/ArduinoIoTCloudTCP.cpp
@@ -28,25 +28,11 @@
   #include "tls/utility/CryptoUtil.h"
 #endif
 
+#include "utility/ota/OTA.h"
 #include "utility/ota/FlashSHA256.h"
-#include "utility/ota/OTAStorage_SNU.h"
-#include "utility/ota/OTAStorage_SFU.h"
-#include "utility/ota/OTAStorage_SSU.h"
 
 #include "cbor/CBOREncoder.h"
 
-/******************************************************************************
-   GLOBAL VARIABLES
- ******************************************************************************/
-
-#if   OTA_STORAGE_SSU
-  static OTAStorage_SSU ota_storage_ssu;
-#elif OTA_STORAGE_SFU
-  static OTAStorage_SFU ota_storage_sfu;
-#elif OTA_STORAGE_SNU
-  static OTAStorage_SNU ota_storage_snu;
-#endif
-
 /******************************************************************************
    GLOBAL CONSTANTS
  ******************************************************************************/
@@ -85,10 +71,11 @@ ArduinoIoTCloudTCP::ArduinoIoTCloudTCP()
 , _shadowTopicIn("")
 , _dataTopicOut("")
 , _dataTopicIn("")
-, _ota_topic_in{""}
 #if OTA_ENABLED
 , _ota_error{static_cast<int>(OTAError::None)}
 , _ota_img_sha256{"Inv."}
+, _ota_url{""}
+, _ota_req{false}
 #endif /* OTA_ENABLED */
 {
 
@@ -151,30 +138,19 @@ int ArduinoIoTCloudTCP::begin(String brokerAddress, uint16_t brokerPort)
   _shadowTopicIn  = getTopic_shadowin();
   _dataTopicOut   = getTopic_dataout();
   _dataTopicIn    = getTopic_datain();
-  _ota_topic_in   = getTopic_ota_in();
-
-#if   OTA_STORAGE_SSU
-  setOTAStorage(ota_storage_ssu);
-#elif OTA_STORAGE_SFU
-  setOTAStorage(ota_storage_sfu);
-#elif OTA_STORAGE_SNU
-  setOTAStorage(ota_storage_snu);
-#endif
+
+#if OTA_ENABLED
+  addPropertyReal(_ota_error, "OTA_ERROR", Permission::Read);
+  addPropertyReal(_ota_img_sha256, "OTA_SHA256", Permission::Read);
+  addPropertyReal(_ota_url, "OTA_URL", Permission::ReadWrite).onSync(DEVICE_WINS);
+  addPropertyReal(_ota_req, "OTA_REQ", Permission::ReadWrite).onSync(DEVICE_WINS).onUpdate(ArduinoIoTCloudTCP::on_OTA_REQ_Update);
+#endif /* OTA_ENABLED */
 
   return 1;
 }
 
 void ArduinoIoTCloudTCP::update()
 {
-#if OTA_ENABLED
-    /* If a _ota_logic object has been instantiated then we are spinning its
-     * 'update' method here in order to process incoming data and generally
-     * to transition to the OTA logic update states.
-     */
-    OTAError const err = _ota_logic.update();
-    _ota_error = static_cast<int>(err);
-#endif /* OTA_ENABLED */
-
   /* Run through the state machine. */
   State next_state = _state;
   switch (_state)
@@ -206,15 +182,6 @@ void ArduinoIoTCloudTCP::printDebugInfo()
   DBG_INFO("MQTT Broker: %s:%d", _brokerAddress.c_str(), _brokerPort);
 }
 
-#if OTA_ENABLED
-void ArduinoIoTCloudTCP::setOTAStorage(OTAStorage & ota_storage)
-{
-  addPropertyReal(_ota_error, "OTA_ERROR", Permission::Read);
-  addPropertyReal(_ota_img_sha256, "OTA_SHA256", Permission::Read);
-  _ota_logic.setOTAStorage(ota_storage);
-}
-#endif /* OTA_ENABLED */
-
 /******************************************************************************
  * PRIVATE MEMBER FUNCTIONS
  ******************************************************************************/
@@ -257,17 +224,11 @@ ArduinoIoTCloudTCP::State ArduinoIoTCloudTCP::handle_SubscribeMqttTopics()
     return State::SubscribeMqttTopics;
   }
 
-  if (!_mqttClient.subscribe(_ota_topic_in))
-  {
-    DBG_ERROR("ArduinoIoTCloudTCP::%s could not subscribe to %s", __FUNCTION__, _ota_topic_in.c_str());
-    return State::SubscribeMqttTopics;
-  }
-
   if (_shadowTopicIn != "")
   {
     if (!_mqttClient.subscribe(_shadowTopicIn))
     {
-      DBG_ERROR("ArduinoIoTCloudTCP::%s could not subscribe to %s", __FUNCTION__, _ota_topic_in.c_str());
+      DBG_ERROR("ArduinoIoTCloudTCP::%s could not subscribe to %s", __FUNCTION__, _shadowTopicIn.c_str());
       return State::SubscribeMqttTopics;
     }
   }
@@ -368,12 +329,6 @@ void ArduinoIoTCloudTCP::handleMessage(int length)
     execCloudEventCallback(ArduinoIoTCloudEvent::SYNC);
     _state = State::Connected;
   }
-
-#if OTA_ENABLED
-  if (_ota_topic_in == topic) {
-    _ota_logic.onOTADataReceived(bytes, length);
-  }
-#endif /* OTA_ENABLED */
 }
 
 void ArduinoIoTCloudTCP::sendPropertiesToCloud()
@@ -415,6 +370,52 @@ int ArduinoIoTCloudTCP::write(String const topic, byte const data[], int const l
   return 0;
 }
 
+#if OTA_ENABLED
+void ArduinoIoTCloudTCP::on_OTA_REQ_Update()
+{
+  ArduinoCloud.onOTARequest();
+}
+
+void ArduinoIoTCloudTCP::onOTARequest()
+{
+  DBG_VERBOSE("ArduinoIoTCloudTCP::%s _ota_req = %s", __FUNCTION__, _ota_req ? "true" : "false");
+  DBG_VERBOSE("ArduinoIoTCloudTCP::%s _ota_url = %s", __FUNCTION__, _ota_url.c_str());
+
+  if (_ota_req)
+  {
+    /* Clear the request flag. */
+    _ota_req = false;
+
+    /* Status flag to prevent the reset from being executed
+     * when HTTPS download is not supported.
+     */
+    bool ota_download_success = false;
+
+#if OTA_STORAGE_SNU
+    /* Just to be safe delete any remains from previous updates. */
+    WiFiStorage.remove("/fs/UPDATE.BIN.LZSS");
+    WiFiStorage.remove("/fs/UPDATE.BIN.LZSS.TMP");
+
+    /* Trigger direct download to nina module. */
+    uint8_t nina_ota_err_code = 0;
+    if (!WiFiStorage.downloadOTA(_ota_url.c_str(), &nina_ota_err_code))
+    {
+      DBG_ERROR("ArduinoIoTCloudTCP::%s error download to nina: %d", __FUNCTION__, nina_ota_err_code);
+      _ota_error = static_cast<int>(OTAError::DownloadFailed);
+      return;
+    }
+
+    /* The download was a success. */
+    ota_download_success = true;
+#endif /* OTA_STORAGE_SNU */
+
+    /* Perform the reset to reboot to SxU. */
+    if (ota_download_success)
+      NVIC_SystemReset();
+  }
+}
+#endif
+
 /******************************************************************************
  * EXTERN DEFINITION
  ******************************************************************************/
diff --git a/src/ArduinoIoTCloudTCP.h b/src/ArduinoIoTCloudTCP.h
index 2e9200725..3dc76dc61 100644
--- a/src/ArduinoIoTCloudTCP.h
+++ b/src/ArduinoIoTCloudTCP.h
@@ -35,11 +35,6 @@
 
 #include <ArduinoMqttClient.h>
 
-#if OTA_ENABLED
-  #include "utility/ota/OTALogic.h"
-  #include "utility/ota/OTAStorage.h"
-#endif /* OTA_ENABLED */
-
 /******************************************************************************
    CONSTANTS
  ******************************************************************************/
@@ -80,10 +75,6 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass
     inline String   getBrokerAddress() const { return _brokerAddress; }
     inline uint16_t getBrokerPort   () const { return _brokerPort; }
 
-#if OTA_ENABLED
-    void setOTAStorage(OTAStorage & ota_storage);
-#endif /* OTA_ENABLED */
-
 
   private:
     static const int MQTT_TRANSMIT_BUFFER_SIZE = 256;
@@ -124,12 +115,12 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass
     String _shadowTopicIn;
     String _dataTopicOut;
     String _dataTopicIn;
-    String _ota_topic_in;
 
 #if OTA_ENABLED
-    OTALogic _ota_logic;
     int _ota_error;
     String _ota_img_sha256;
+    String _ota_url;
+    bool _ota_req;
 #endif /* OTA_ENABLED */
 
     inline String getTopic_stdin    () { return String("/a/d/" + getDeviceId() + "/s/i"); }
@@ -138,7 +129,6 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass
     inline String getTopic_shadowin () { return ( getThingId().length() == 0) ? String("")                            : String("/a/t/" + getThingId() + "/shadow/i"); }
     inline String getTopic_dataout  () { return ( getThingId().length() == 0) ? String("/a/d/" + getDeviceId() + "/e/o") : String("/a/t/" + getThingId() + "/e/o"); }
     inline String getTopic_datain   () { return ( getThingId().length() == 0) ? String("/a/d/" + getDeviceId() + "/e/i") : String("/a/t/" + getThingId() + "/e/i"); }
-    inline String getTopic_ota_in   () { return String("/a/d/" + getDeviceId() + "/ota/i"); }
 
     State handle_ConnectPhy();
     State handle_SyncTime();
@@ -153,6 +143,10 @@ class ArduinoIoTCloudTCP: public ArduinoIoTCloudClass
     void requestLastValue();
     int write(String const topic, byte const data[], int const length);
 
+#if OTA_ENABLED
+    static void on_OTA_REQ_Update();
+    void onOTARequest();
+#endif
 };
 
 /******************************************************************************
diff --git a/src/utility/ota/OTAStorage.h b/src/utility/ota/OTA.h
similarity index 67%
rename from src/utility/ota/OTAStorage.h
rename to src/utility/ota/OTA.h
index 4029f81dd..208d5e616 100644
--- a/src/utility/ota/OTAStorage.h
+++ b/src/utility/ota/OTA.h
@@ -15,36 +15,38 @@
    a commercial license, send an email to license@arduino.cc.
 */
 
-#ifndef ARDUINO_OTA_STORAGE_H_
-#define ARDUINO_OTA_STORAGE_H_
+#ifndef ARDUINO_OTA_LOGIC_H_
+#define ARDUINO_OTA_LOGIC_H_
 
 /******************************************************************************
  * INCLUDE
  ******************************************************************************/
 
-#include <stdlib.h>
-#include <stdint.h>
-#include <stdbool.h>
+#include <AIoTC_Config.h>
+#if OTA_ENABLED
 
-/******************************************************************************
- * CLASS DECLARATION
- ******************************************************************************/
-
-class OTAStorage
-{
-public:
+#if OTA_STORAGE_SNU
+  #include <SNU.h>
+#endif /* OTA_STORAGE_SNU */
 
-  virtual ~OTAStorage() { }
+#if OTA_STORAGE_SSU
+  #include <SSU.h>
+#endif /* OTA_STORAGE_SSU */
 
+#if OTA_STORAGE_SFU
+  #include <SFU.h>
+#endif /* OTA_STORAGE_SFU */
 
-  virtual bool   init  () = 0;
-  virtual bool   open  () = 0;
-  virtual size_t write (uint8_t const * const buf, size_t const num_bytes) = 0;
-  virtual void   close () = 0;
-  virtual void   remove() = 0;
-  virtual bool   rename() = 0;
-  virtual void   deinit() = 0;
+/******************************************************************************
+ * TYPEDEF
+ ******************************************************************************/
 
+enum class OTAError : int
+{
+  None           = 0,
+  DownloadFailed = 1,
 };
 
-#endif /* ARDUINO_OTA_STORAGE_H_ */
+#endif /* OTA_ENABLED */
+
+#endif /* ARDUINO_OTA_LOGIC_H_ */
diff --git a/src/utility/ota/OTALogic.cpp b/src/utility/ota/OTALogic.cpp
deleted file mode 100644
index b04b4d9f2..000000000
--- a/src/utility/ota/OTALogic.cpp
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
-   This file is part of ArduinoIoTCloud.
-
-   Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
-
-   This software is released under the GNU General Public License version 3,
-   which covers the main part of arduino-cli.
-   The terms of this license can be found at:
-   https://www.gnu.org/licenses/gpl-3.0.en.html
-
-   You can be released from the requirements of the above licenses by purchasing
-   a commercial license. Buying such a license is mandatory if you want to modify or
-   otherwise use the software for commercial activities involving the Arduino
-   software without disclosing the source code of your own applications. To purchase
-   a commercial license, send an email to license@arduino.cc.
-*/
-
-/******************************************************************************
- * INCLUDE
- ******************************************************************************/
-
-#ifndef HOST
-  #include <AIoTC_Config.h>
-#else
-  #define OTA_ENABLED (1)
-#endif
-#if OTA_ENABLED
-
-#include "OTALogic.h"
-
-#ifndef HOST
-  #include <Arduino.h>
-  #include <Arduino_DebugUtils.h>
-#else
-  #include <algorithm> /* for std::min, otherwise Arduino defines min() */
-  using namespace std;
-#endif
-
-#include <string.h>
-
-/******************************************************************************
- * CTOR/DTOR
- ******************************************************************************/
-
-OTALogic::OTALogic()
-: _is_configured{false}
-, _ota_storage{nullptr}
-, _ota_state{OTAState::Init}
-, _ota_error{OTAError::None}
-{
-  init_mqtt_ota_buffer();
-  init_ota_binary_data();
-}
-
-/******************************************************************************
- * PUBLIC MEMBER FUNCTIONS
- ******************************************************************************/
-
-void OTALogic::setOTAStorage(OTAStorage & ota_storage)
-{
-  _ota_storage = &ota_storage;
-  _is_configured = true;
-}
-
-OTAError OTALogic::update()
-{
-  /* This if clause should never happen. None the less we
-   * should insure ourselves against this scenario because
-   * otherwise we'll have a nullptr dereferencing.
-   */
-  if (!_is_configured) {
-    _ota_state = OTAState::Error;
-    _ota_error = OTAError::NoOTAStorageConfigured;
-    return _ota_error;
-  }
-
-  OTAState prev_ota_state;
-  /* The purpose of this loop is to allow the transition of
-   * more than one state per a singular call of 'update'. If
-   * no state transitition takes place then the loop is exited
-   * because it means that external input (such as the arrival)
-   * of new data is required.
-   */
-  do
-  {
-    prev_ota_state = _ota_state;
-    switch(_ota_state)
-    {
-    case OTAState::Init:           _ota_state = handle_Init          (); break;
-    case OTAState::Idle:           _ota_state = handle_Idle          (); break;
-    case OTAState::StartDownload:  _ota_state = handle_StartDownload (); break;
-    case OTAState::WaitForHeader:  _ota_state = handle_WaitForHeader (); break;
-    case OTAState::HeaderReceived: _ota_state = handle_HeaderReceived(); break;
-    case OTAState::WaitForBinary:  _ota_state = handle_WaitForBinary (); break;
-    case OTAState::BinaryReceived: _ota_state = handle_BinaryReceived(); break;
-    case OTAState::Verify:         _ota_state = handle_Verify        (); break;
-    case OTAState::Rename:         _ota_state = handle_Rename        (); break;
-    case OTAState::Reset:          _ota_state = handle_Reset         (); break;
-    case OTAState::Error:                                                break;
-    }
-  } while(_ota_state != prev_ota_state);
-
-  return _ota_error;
-}
-
-void OTALogic::onOTADataReceived(uint8_t const * const data, size_t const length)
-{
-  size_t const bytes_available = (MQTT_OTA_BUF_SIZE - _mqtt_ota_buf.num_bytes);
-  if(length <= bytes_available)
-  {
-    memcpy(_mqtt_ota_buf.buf + _mqtt_ota_buf.num_bytes, data, length);
-    _mqtt_ota_buf.num_bytes += length;
-  }
-  else
-  {
-    _ota_state = OTAState::Error;
-    _ota_error = OTAError::ReceivedDataOverrun;
-  }
-}
-
-/******************************************************************************
- * PRIVATE MEMBER FUNCTIONS
- ******************************************************************************/
-
-OTAState OTALogic::handle_Init()
-{
-#ifndef HOST
-  DBG_VERBOSE("OTALogic::%s", __FUNCTION__);
-#endif
-  if (_ota_storage->init()) {
-    return OTAState::Idle;
-  } else {
-    _ota_error = OTAError::StorageInitFailed;
-    return OTAState::Error;
-  }
-}
-
-OTAState OTALogic::handle_Idle()
-{
-  if(_mqtt_ota_buf.num_bytes > 0) {
-    return OTAState::StartDownload;
-  }
-  return OTAState::Idle;
-}
-
-OTAState OTALogic::handle_StartDownload()
-{
-#ifndef HOST
-  DBG_VERBOSE("OTALogic::%s", __FUNCTION__);
-#endif
-  if(_ota_storage->open()) {
-    return OTAState::WaitForHeader;
-  } else {
-    _ota_error = OTAError::StorageOpenFailed;
-    return OTAState::Error;
-  }
-}
-
-OTAState OTALogic::handle_WaitForHeader()
-{
-#ifndef HOST
-  DBG_VERBOSE("OTALogic::%s", __FUNCTION__);
-#endif
-  if(_mqtt_ota_buf.num_bytes >= OTA_BINARY_HEADER_SIZE) {
-    return OTAState::HeaderReceived;
-  }
-  return OTAState::WaitForHeader;
-}
-
-OTAState OTALogic::handle_HeaderReceived()
-{
-  /* The OTA header has been received, let's extract it
-   * from the MQTT OTA receive buffer.
-   */
-  union OTAHeader
-  {
-    struct __attribute__((packed))
-    {
-      uint32_t len;
-      uint32_t crc32;
-    } header;
-    uint8_t buf[sizeof(header)];
-  };
-
-  OTAHeader ota_header;
-  memcpy(ota_header.buf, _mqtt_ota_buf.buf, OTA_BINARY_HEADER_SIZE);
-
-  /* Assign the extracted header values to the member variables */
-  _ota_bin_data.hdr_len   = ota_header.header.len;
-  _ota_bin_data.hdr_crc32 = ota_header.header.crc32;
-
-#ifndef HOST
-  DBG_VERBOSE("OTALogic::%s: header length = %d", __FUNCTION__, _ota_bin_data.hdr_len);
-  DBG_VERBOSE("OTALogic::%s: header crc32 = %X", __FUNCTION__, _ota_bin_data.hdr_crc32);
-#endif
-
-  /* Reset the counter which is responsible for keeping tabs on how many bytes have been received */
-  _ota_bin_data.bytes_received = 0;
-
-  /* Initialize the CRC variable for calculating the CRC32 of the received data package */
-  _ota_bin_data.crc32 = crc_init();
-
-  /* Eliminate the header from the receive buffer and transition to WaitForBinary state. */
-  memcpy(_mqtt_ota_buf.buf,
-         _mqtt_ota_buf.buf + OTA_BINARY_HEADER_SIZE,
-         _mqtt_ota_buf.num_bytes - OTA_BINARY_HEADER_SIZE);
-  _mqtt_ota_buf.num_bytes -= OTA_BINARY_HEADER_SIZE;
-
-  return OTAState::WaitForBinary;
-}
-
-OTAState OTALogic::handle_WaitForBinary()
-{
-  if (_mqtt_ota_buf.num_bytes > 0) {
-    return OTAState::BinaryReceived;
-  }
-  return OTAState::WaitForBinary;
-}
-
-OTAState OTALogic::handle_BinaryReceived()
-{
-  /* Write to OTA storage */
-  if(_ota_storage->write(_mqtt_ota_buf.buf, _mqtt_ota_buf.num_bytes) != _mqtt_ota_buf.num_bytes)
-  {
-    _ota_error = OTAError::StorageWriteFailed;
-    return OTAState::Error;
-  }
-
-  /* Update CRC32 */
-  _ota_bin_data.crc32 = crc_update(_ota_bin_data.crc32, _mqtt_ota_buf.buf, _mqtt_ota_buf.num_bytes);
-
-  /* Update received data counters and clear MQTT OTA receive buffer */
-  _ota_bin_data.bytes_received += _mqtt_ota_buf.num_bytes;
-  _mqtt_ota_buf.num_bytes = 0;
-
-#ifndef HOST
-  DBG_VERBOSE("OTALogic::%s: %d bytes written", __FUNCTION__, _ota_bin_data.bytes_received);
-#endif
-
-  if(_ota_bin_data.bytes_received >= _ota_bin_data.hdr_len) {
-    _ota_storage->close();
-    _ota_bin_data.crc32 = crc_finalize(_ota_bin_data.crc32);
-    return OTAState::Verify;
-  }
-
-  return OTAState::WaitForBinary;
-}
-
-OTAState OTALogic::handle_Verify()
-{
-#ifndef HOST
-  DBG_VERBOSE("OTALogic::%s", __FUNCTION__);
-#endif
-  if(_ota_bin_data.crc32 == _ota_bin_data.hdr_crc32) {
-    return OTAState::Rename;
-  } else {
-    _ota_storage->remove();
-    _ota_error = OTAError::ChecksumMismatch;
-    return OTAState::Error;
-  }
-}
-
-OTAState OTALogic::handle_Rename()
-{
-#ifndef HOST
-  DBG_VERBOSE("OTALogic::%s", __FUNCTION__);
-#endif
-  if(_ota_storage->rename()) {
-    _ota_storage->deinit();
-    return OTAState::Reset;
-  }
-  else {
-    _ota_error = OTAError::RenameOfTempFileFailed;
-    return OTAState::Error;
-  }
-}
-
-OTAState OTALogic::handle_Reset()
-{
-#if !defined(HOST) && !defined(ESP8266)
-  /* After completion of the reset a second stage bootloader
-   * such as the SFU is examining the OTA storage medium for
-   * the existence of a binary update file. Should such a file
-   * exist the 2nd stage bootloader if performing the firmware
-   * update before starting the application, otherwise the app
-   * is started directly.
-   */
-#ifndef HOST
-  DBG_VERBOSE("OTALogic::%s", __FUNCTION__);
-  delay(250);
-#endif
-  NVIC_SystemReset();
-#endif /* HOST */
-  return OTAState::Reset;
-}
-
-void OTALogic::init_mqtt_ota_buffer()
-{
-  memset(_mqtt_ota_buf.buf, 0U, sizeof(_mqtt_ota_buf.buf));
-  _mqtt_ota_buf.num_bytes = 0;
-}
-
-void OTALogic::init_ota_binary_data()
-{
-  _ota_bin_data.hdr_len        = 0;
-  _ota_bin_data.hdr_crc32      = 0;
-  _ota_bin_data.bytes_received = 0;
-  _ota_bin_data.crc32          = crc_init();
-}
-
-#endif /* OTA_ENABLED */
diff --git a/src/utility/ota/OTALogic.h b/src/utility/ota/OTALogic.h
deleted file mode 100644
index 3f3a3c31f..000000000
--- a/src/utility/ota/OTALogic.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
-   This file is part of ArduinoIoTCloud.
-
-   Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
-
-   This software is released under the GNU General Public License version 3,
-   which covers the main part of arduino-cli.
-   The terms of this license can be found at:
-   https://www.gnu.org/licenses/gpl-3.0.en.html
-
-   You can be released from the requirements of the above licenses by purchasing
-   a commercial license. Buying such a license is mandatory if you want to modify or
-   otherwise use the software for commercial activities involving the Arduino
-   software without disclosing the source code of your own applications. To purchase
-   a commercial license, send an email to license@arduino.cc.
-*/
-
-#ifndef ARDUINO_OTA_LOGIC_H_
-#define ARDUINO_OTA_LOGIC_H_
-
-/******************************************************************************
- * INCLUDE
- ******************************************************************************/
-
-#ifndef HOST
-  #include <AIoTC_Config.h>
-#else
-  #define OTA_ENABLED (1)
-#endif
-#if OTA_ENABLED
-
-#include "OTAStorage.h"
-
-#include "crc.h"
-
-/******************************************************************************
- * CONSTANT
- ******************************************************************************/
-
-static size_t const MQTT_OTA_BUF_SIZE = 256;
-
-/******************************************************************************
- * TYPEDEF
- ******************************************************************************/
-
-enum class OTAState
-{
-  Init, Idle, StartDownload, WaitForHeader, HeaderReceived, WaitForBinary, BinaryReceived, Verify, Rename, Reset, Error
-};
-
-enum class OTAError : int
-{
-  None                   = 0,
-  StorageInitFailed      = 1,
-  StorageOpenFailed      = 2,
-  StorageWriteFailed     = 3,
-  ChecksumMismatch       = 4,
-  ReceivedDataOverrun    = 5,
-  RenameOfTempFileFailed = 6,
-  NoOTAStorageConfigured = 7
-};
-
-/******************************************************************************
- * CLASS DECLARATION
- ******************************************************************************/
-
-class OTALogic
-{
-
-public:
-
-  OTALogic();
-
-
-  void setOTAStorage(OTAStorage & ota_storage);
-
-
-  OTAError update();
-  void onOTADataReceived(uint8_t const * const data, size_t const length);
-
-#ifdef HOST
-  inline OTAState state() const { return _ota_state; }
-  inline OTAError error() const { return _ota_error; }
-#endif
-
-
-private:
-
-  typedef struct
-  {
-    size_t  num_bytes;
-    uint8_t buf[MQTT_OTA_BUF_SIZE];
-  } sMQTTOTABuffer;
-
-  typedef struct
-  {
-    uint32_t hdr_len;
-    uint32_t hdr_crc32;
-    uint32_t bytes_received;
-    crc_t    crc32;
-  } sOTABinaryData;
-
-  bool _is_configured;
-  OTAStorage * _ota_storage;
-  OTAState _ota_state;
-  OTAError _ota_error;
-  sMQTTOTABuffer _mqtt_ota_buf;
-  sOTABinaryData _ota_bin_data;
-
-  static size_t const OTA_BINARY_HEADER_SIZE = sizeof(_ota_bin_data.hdr_len) + sizeof(_ota_bin_data.hdr_crc32);
-
-  OTAState handle_Init();
-  OTAState handle_Idle();
-  OTAState handle_StartDownload();
-  OTAState handle_WaitForHeader();
-  OTAState handle_HeaderReceived();
-  OTAState handle_WaitForBinary();
-  OTAState handle_BinaryReceived();
-  OTAState handle_Verify();
-  OTAState handle_Rename();
-  OTAState handle_Reset();
-
-  void init_mqtt_ota_buffer();
-  void init_ota_binary_data();
-
-};
-
-#endif /* OTA_ENABLED */
-
-#endif /* ARDUINO_OTA_LOGIC_H_ */
diff --git a/src/utility/ota/OTAStorage_SFU.cpp b/src/utility/ota/OTAStorage_SFU.cpp
deleted file mode 100644
index c5046d595..000000000
--- a/src/utility/ota/OTAStorage_SFU.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
-   This file is part of ArduinoIoTCloud.
-
-   Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
-
-   This software is released under the GNU General Public License version 3,
-   which covers the main part of arduino-cli.
-   The terms of this license can be found at:
-   https://www.gnu.org/licenses/gpl-3.0.en.html
-
-   You can be released from the requirements of the above licenses by purchasing
-   a commercial license. Buying such a license is mandatory if you want to modify or
-   otherwise use the software for commercial activities involving the Arduino
-   software without disclosing the source code of your own applications. To purchase
-   a commercial license, send an email to license@arduino.cc.
-*/
-
-/******************************************************************************
- * INCLUDE
- ******************************************************************************/
-
-#include <AIoTC_Config.h>
-#if OTA_STORAGE_SFU
-
-#include "OTAStorage_SFU.h"
-
-#include <Arduino_DebugUtils.h>
-
-/******************************************************************************
- * CONSTANTS
- ******************************************************************************/
-
-static char const SFU_UPDATE_FILENAME[]      = "UPDATE.BIN";
-static char const SFU_TEMP_UPDATE_FILENAME[] = "UPDATE.BIN.TMP";
-
-/******************************************************************************
- * CTOR/DTOR
- ******************************************************************************/
-
-OTAStorage_SFU::OTAStorage_SFU()
-: _file{nullptr}
-{
-
-}
-
-/******************************************************************************
- * PUBLIC MEMBER FUNCTIONS
- ******************************************************************************/
-
-bool OTAStorage_SFU::init()
-{
-  flash.begin();
-  if(SPIFFS_OK != filesystem.mount()) {
-    DBG_ERROR("OTAStorage_SFU::init - mount() failed with error code %d", filesystem.err());
-    return false;
-  }
-
-  if(SPIFFS_OK != filesystem.check()) {
-    DBG_ERROR("OTAStorage_SFU::init - check() failed with error code %d", filesystem.err());
-    return false;
-  }
-
-  return true;
-}
-
-bool OTAStorage_SFU::open()
-{
-  filesystem.clearerr();
-  _file = new File(filesystem.open(SFU_TEMP_UPDATE_FILENAME, CREATE | WRITE_ONLY| TRUNCATE));
-  if(SPIFFS_OK != filesystem.err()) {
-    DBG_ERROR("OTAStorage_SFU::open - open() failed with error code %d", filesystem.err());
-    delete _file;
-    return false;
-  }
-  return true;
-}
-
-size_t OTAStorage_SFU::write(uint8_t const * const buf, size_t const num_bytes)
-{
-  return _file->write(const_cast<uint8_t *>(buf), num_bytes);
-}
-
-void OTAStorage_SFU::close()
-{
-  _file->close();
-  delete _file;
-}
-
-void OTAStorage_SFU::remove()
-{
-  filesystem.remove(SFU_TEMP_UPDATE_FILENAME);
-}
-
-bool OTAStorage_SFU::rename()
-{
-  return (SPIFFS_OK == filesystem.rename(SFU_TEMP_UPDATE_FILENAME, SFU_UPDATE_FILENAME));
-}
-
-void OTAStorage_SFU::deinit()
-{
-  filesystem.unmount();
-}
-
-#endif /* OTA_STORAGE_SFU */
diff --git a/src/utility/ota/OTAStorage_SFU.h b/src/utility/ota/OTAStorage_SFU.h
deleted file mode 100644
index c22099bee..000000000
--- a/src/utility/ota/OTAStorage_SFU.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
-   This file is part of ArduinoIoTCloud.
-
-   Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
-
-   This software is released under the GNU General Public License version 3,
-   which covers the main part of arduino-cli.
-   The terms of this license can be found at:
-   https://www.gnu.org/licenses/gpl-3.0.en.html
-
-   You can be released from the requirements of the above licenses by purchasing
-   a commercial license. Buying such a license is mandatory if you want to modify or
-   otherwise use the software for commercial activities involving the Arduino
-   software without disclosing the source code of your own applications. To purchase
-   a commercial license, send an email to license@arduino.cc.
-*/
-
-#ifndef ARDUINO_OTA_STORAGE_SFU_H_
-#define ARDUINO_OTA_STORAGE_SFU_H_
-
-/******************************************************************************
- * INCLUDE
- ******************************************************************************/
-
-#include <AIoTC_Config.h>
-#if OTA_STORAGE_SFU
-
-#include "OTAStorage.h"
-
-#include <SFU.h>
-
-#include <Arduino_MKRMEM.h>
-
-/******************************************************************************
- * CLASS DECLARATION
- ******************************************************************************/
-
-class OTAStorage_SFU : public OTAStorage
-{
-public:
-
-           OTAStorage_SFU();
-  virtual ~OTAStorage_SFU() { }
-
-
-  virtual bool   init  () override;
-  virtual bool   open  () override;
-  virtual size_t write (uint8_t const * const buf, size_t const num_bytes) override;
-  virtual void   close () override;
-  virtual void   remove() override;
-  virtual bool   rename() override;
-  virtual void   deinit() override;
-
-
-private:
-
-  File  * _file;
-
-};
-
-#endif /* OTA_STORAGE_SFU */
-
-#endif /* ARDUINO_OTA_STORAGE_SFU_H_ */
diff --git a/src/utility/ota/OTAStorage_SNU.cpp b/src/utility/ota/OTAStorage_SNU.cpp
deleted file mode 100644
index c3325b11b..000000000
--- a/src/utility/ota/OTAStorage_SNU.cpp
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
-   This file is part of ArduinoIoTCloud.
-
-   Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
-
-   This software is released under the GNU General Public License version 3,
-   which covers the main part of arduino-cli.
-   The terms of this license can be found at:
-   https://www.gnu.org/licenses/gpl-3.0.en.html
-
-   You can be released from the requirements of the above licenses by purchasing
-   a commercial license. Buying such a license is mandatory if you want to modify or
-   otherwise use the software for commercial activities involving the Arduino
-   software without disclosing the source code of your own applications. To purchase
-   a commercial license, send an email to license@arduino.cc.
-*/
-
-/******************************************************************************
- * INCLUDE
- ******************************************************************************/
-
-#include <AIoTC_Config.h>
-#if OTA_STORAGE_SNU
-
-#include "OTAStorage_SNU.h"
-
-#include <WiFiStorage.h>
-
-/******************************************************************************
- * CONSTANTS
- ******************************************************************************/
-
-static char const SNU_UPDATE_FILENAME[]      = "/fs/UPDATE.BIN.LZSS";
-static char const SNU_TEMP_UPDATE_FILENAME[] = "/fs/UPDATE.BIN.TMP.LZSS";
-
-/******************************************************************************
- * PUBLIC MEMBER FUNCTIONS
- ******************************************************************************/
-
-bool OTAStorage_SNU::init()
-{
-  /* Ensure that there are no remains of previous
-   * aborted downloads still existing in the memory
-   * of the nina module.
-   */
-  WiFiStorage.remove(SNU_TEMP_UPDATE_FILENAME);
-  return true;
-}
-
-bool OTAStorage_SNU::open()
-{
-  /* There's no need to explicitly open the file
-   * because when writing to it the file will always
-   * be opened with "ab+" mode and closed after each
-   * call to 'write'.
-   */
-  return true;
-}
-
-size_t OTAStorage_SNU::write(uint8_t const * const buf, size_t const num_bytes)
-{
-  WiFiStorageFile file(SNU_TEMP_UPDATE_FILENAME);
-
-  /* We have to write in chunks because otherwise we exceed the size of
-   * the SPI buffer within the nina module.
-   */
-  size_t bytes_written = 0;
-  size_t const WRITE_CHUNK_SIZE = 32;
-  
-  for(; bytes_written < (num_bytes - WRITE_CHUNK_SIZE); bytes_written += WRITE_CHUNK_SIZE)
-  {
-    if (file.write(buf + bytes_written, WRITE_CHUNK_SIZE) != WRITE_CHUNK_SIZE)
-      return bytes_written;
-  }
-
-  bytes_written += file.write(buf + bytes_written, num_bytes - bytes_written);
-
-  return bytes_written;
-}
-
-void OTAStorage_SNU::close()
-{
-  /* Files are closed after each file operation on the nina side. */
-}
-
-void OTAStorage_SNU::remove()
-{
-  WiFiStorage.remove(SNU_TEMP_UPDATE_FILENAME);
-}
-
-bool OTAStorage_SNU::rename()
-{
-  return WiFiStorage.rename(SNU_TEMP_UPDATE_FILENAME, SNU_UPDATE_FILENAME);
-}
-
-void OTAStorage_SNU::deinit()
-{
-  /* Nothing to do */
-}
-
-#endif /* OTA_STORAGE_SNU */
diff --git a/src/utility/ota/OTAStorage_SNU.h b/src/utility/ota/OTAStorage_SNU.h
deleted file mode 100644
index c9fbc2619..000000000
--- a/src/utility/ota/OTAStorage_SNU.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
-   This file is part of ArduinoIoTCloud.
-
-   Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
-
-   This software is released under the GNU General Public License version 3,
-   which covers the main part of arduino-cli.
-   The terms of this license can be found at:
-   https://www.gnu.org/licenses/gpl-3.0.en.html
-
-   You can be released from the requirements of the above licenses by purchasing
-   a commercial license. Buying such a license is mandatory if you want to modify or
-   otherwise use the software for commercial activities involving the Arduino
-   software without disclosing the source code of your own applications. To purchase
-   a commercial license, send an email to license@arduino.cc.
-*/
-
-#ifndef ARDUINO_OTA_STORAGE_SNU_H_
-#define ARDUINO_OTA_STORAGE_SNU_H_
-
-/******************************************************************************
- * INCLUDE
- ******************************************************************************/
-
-#include <AIoTC_Config.h>
-#if OTA_STORAGE_SNU
-
-#include <SNU.h>
-
-#include "OTAStorage.h"
-
-/******************************************************************************
- * CLASS DECLARATION
- ******************************************************************************/
-
-class OTAStorage_SNU : public OTAStorage
-{
-public:
-
-  virtual ~OTAStorage_SNU() { }
-
-
-  virtual bool   init  () override;
-  virtual bool   open  () override;
-  virtual size_t write (uint8_t const * const buf, size_t const num_bytes) override;
-  virtual void   close () override;
-  virtual void   remove() override;
-  virtual bool   rename() override;
-  virtual void   deinit() override;
-
-};
-
-#endif /* OTA_STORAGE_SNU */
-
-#endif /* ARDUINO_OTA_STORAGE_SNU_H_ */
diff --git a/src/utility/ota/OTAStorage_SSU.cpp b/src/utility/ota/OTAStorage_SSU.cpp
deleted file mode 100644
index a8023ac1d..000000000
--- a/src/utility/ota/OTAStorage_SSU.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
-   This file is part of ArduinoIoTCloud.
-
-   Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
-
-   This software is released under the GNU General Public License version 3,
-   which covers the main part of arduino-cli.
-   The terms of this license can be found at:
-   https://www.gnu.org/licenses/gpl-3.0.en.html
-
-   You can be released from the requirements of the above licenses by purchasing
-   a commercial license. Buying such a license is mandatory if you want to modify or
-   otherwise use the software for commercial activities involving the Arduino
-   software without disclosing the source code of your own applications. To purchase
-   a commercial license, send an email to license@arduino.cc.
-*/
-
-/******************************************************************************
-   INCLUDE
- ******************************************************************************/
-
-#include <AIoTC_Config.h>
-#if OTA_STORAGE_SSU
-
-#include "OTAStorage_SSU.h"
-
-/******************************************************************************
-   CONSTANTS
- ******************************************************************************/
-
-static char const SSU_UPDATE_FILENAME[] = "UPDATE.BIN.LZSS";
-static char const SSU_CHECK_FILE_NAME[] = "UPDATE.OK";
-
-/******************************************************************************
-   PUBLIC MEMBER FUNCTIONS
- ******************************************************************************/
-
-bool OTAStorage_SSU::init()
-{
-  if (!_fileUtils.begin())
-    return false;
-
-  if (_fileUtils.listFile(SSU_UPDATE_FILENAME) > 0)
-    if (!_fileUtils.deleteFile(SSU_UPDATE_FILENAME))
-      return false;
-
-  if (_fileUtils.listFile(SSU_CHECK_FILE_NAME) > 0)
-    if (!_fileUtils.deleteFile(SSU_CHECK_FILE_NAME))
-      return false;
-}
-
-bool OTAStorage_SSU::open()
-{
-  return true;
-}
-
-size_t OTAStorage_SSU::write(uint8_t const* const buf, size_t const num_bytes)
-{
-  _fileUtils.appendFile(SSU_UPDATE_FILENAME, (const char*)buf, num_bytes);
-  return num_bytes;
-}
-
-void OTAStorage_SSU::close()
-{
-  /* Nothing to do */
-}
-
-void OTAStorage_SSU::remove()
-{
-  _fileUtils.deleteFile(SSU_UPDATE_FILENAME);
-}
-
-bool OTAStorage_SSU::rename()
-{
-  /* Create a file 'UPDATE.OK' which is used by the SSU
-   * 2nd stage bootloader to recognise that the update
-   * went okay. Normally this is done by renaming 'UPDATE.BIN.TMP'
-   * to 'UPDATE.BIN' but the SARE module does not support
-   * a rename function.
-   */
-  char c = 'X';
-  return (_fileUtils.appendFile(SSU_CHECK_FILE_NAME, &c, sizeof(c)) == sizeof(c));
-}
-
-void OTAStorage_SSU::deinit()
-{
-  /* Nothing to do */
-}
-
-#endif /* OTA_STORAGE_SSU */
diff --git a/src/utility/ota/OTAStorage_SSU.h b/src/utility/ota/OTAStorage_SSU.h
deleted file mode 100644
index 99f1bf6ec..000000000
--- a/src/utility/ota/OTAStorage_SSU.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
-   This file is part of ArduinoIoTCloud.
-
-   Copyright 2020 ARDUINO SA (http://www.arduino.cc/)
-
-   This software is released under the GNU General Public License version 3,
-   which covers the main part of arduino-cli.
-   The terms of this license can be found at:
-   https://www.gnu.org/licenses/gpl-3.0.en.html
-
-   You can be released from the requirements of the above licenses by purchasing
-   a commercial license. Buying such a license is mandatory if you want to modify or
-   otherwise use the software for commercial activities involving the Arduino
-   software without disclosing the source code of your own applications. To purchase
-   a commercial license, send an email to license@arduino.cc.
-*/
-
-#ifndef ARDUINO_OTA_STORAGE_SSU_H_
-#define ARDUINO_OTA_STORAGE_SSU_H_
-
-/******************************************************************************
- * INCLUDE
- ******************************************************************************/
-
-#include <AIoTC_Config.h>
-#if OTA_STORAGE_SSU
-
-#include <SSU.h>
-
-#include "OTAStorage.h"
-
-#include <GSMFileUtils.h>
-
-/******************************************************************************
- * CLASS DECLARATION
- ******************************************************************************/
-
-class OTAStorage_SSU : public OTAStorage
-{
-public:
-
-  virtual ~OTAStorage_SSU() { }
-
-
-  virtual bool   init  () override;
-  virtual bool   open  () override;
-  virtual size_t write (uint8_t const * const buf, size_t const num_bytes) override;
-  virtual void   close () override;
-  virtual void   remove() override;
-  virtual bool   rename() override;
-  virtual void   deinit() override;
-
-private:
-
-   GSMFileUtils _fileUtils;
-
-};
-
-#endif /* OTA_STORAGE_SSU */
-
-#endif /* ARDUINO_OTA_STORAGE_SSU_H_ */