Arduino R4 Wifi NCP OTA

Hi everyone,

I’m struggling to get OTA work with an Arduino R4 Wifi board, which is enabled with Blynk NCP. To start, I followed Blink NCP documentation to flash the board with Platform IO.
The device was then successfully added with the Blynk mobile app and by Wifi pairing with BLE.

Now, when I try to ship a new firmware, I got an error message which says “Download Failure” and in details “device can’t fully download the firmware from server” :
CleanShot 2024-01-20 at 18.50.11

What could I miss here ? OTA should be supported with this board, but maybe something is missing with my code to get it work ? For example, do I need to setup httpclient and url somewhere ? Also I’m not sure if OTA package tagging is mandatory in my case.
Thank you.

// Blynk Definition
#define BLYNK_TEMPLATE_ID "*******"
#define BLYNK_TEMPLATE_NAME "Premium Tank"
#define BLYNK_FIRMWARE_VERSION "0.1.3"
#define BLYNK_PRINT Serial

// URM14 Definition
#define   SLAVE_ADDR                ((uint16_t)0x0C)
#define   TEMP_CPT_SEL_BIT          ((uint16_t)0x01)
#define   TEMP_CPT_ENABLE_BIT       ((uint16_t)0x01 << 1)
#define   MEASURE_MODE_BIT          ((uint16_t)0x01 << 2)
#define   MEASURE_TRIG_BIT          ((uint16_t)0x01 << 3)

// ModbusMaster Definition
#define MAX485_DE      3
#define MAX485_RE_NEG  2

#include <BlynkEdgentNCP.h>
#include <ModbusMaster.h>

// instantiate ModbusMaster object
ModbusMaster node;

//URM14 Index Registers
typedef enum{ 
  ePid,
  eVid,
  eAddr,
  eComBaudrate,
  eComParityStop,
  eDistance,
  eInternalTempreture,
  eExternalTempreture,
  eControl,
  eNoise
}eRegIndex_t;//Sensor register index

//URM14 Function Read
/*
 *@brief Read data from holding register of client
 *
 *@param addr : Address of Client
 *@param reg: Reg index
 *@return data if execute successfully, false oxffff.
 */

uint16_t readData(eRegIndex_t reg)
{
  uint16_t data, result;
  result = node.readHoldingRegisters(reg, 1);
  if (!result == node.ku8MBSuccess){
    Serial.print("failed to read registers! ");
    data = 0xffff;
  }else{
    data = node.getResponseBuffer(0);
    Serial.print("data : ");
    Serial.print(data);
  }
  return data;
}

//URM14 Function Write
/*
 *@brief write data to holding register of client 
 *
 *@param addr : Address of Client
 *@param reg: Reg index
 *@param data: The data to be written
 *@return 1 if execute successfully, false 0.
 */
uint16_t writeData(eRegIndex_t reg, uint16_t data)
{
  uint16_t result;
  result = node.writeSingleRegister(reg, data);
  if (!result == node.ku8MBSuccess){
    Serial.print("Failed to write coil! ");
    return 0;
  }else
    return 1;
}

//Variables Definition
float  dist;
volatile float tempInt;
volatile uint16_t cr = 0;
uint16_t tx = 0;
double nbLCuves = 0; 
double txCuves = 0;
const int total_l = 5000;

//Blynk Functions
BlynkTimer timer;

BLYNK_CONNECTED() {
  BLYNK_LOG("Connected to Blynk 🙌");
  Blynk.syncVirtual(V1);
}

BLYNK_DISCONNECTED() {
  BLYNK_LOG("Blynk disconnected");
}

//ModbusMaster Functions
void preTransmission()
{
  digitalWrite(MAX485_RE_NEG, 1);
  digitalWrite(MAX485_DE, 1);
}

void postTransmission()
{
  delay(300);
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);
}


//=====================Basic Setup ============================
void setup() {
  pinMode(MAX485_RE_NEG, OUTPUT);
  pinMode(MAX485_DE, OUTPUT);
  // Init in receive mode
  delay(300); //accord delay post init
  digitalWrite(MAX485_RE_NEG, 0);
  digitalWrite(MAX485_DE, 0);   
  // Serials initialization
  Serial.begin(19200);
  Serial1.begin(19200);
  delay(3000);
  //*******************************************BLYNK SETUP
  BLYNKSetUp();
  timer.setInterval(1000L, myTimerEvent);
  node.begin(12, Serial1); 
  // Callbacks allow us to configure the RS485 transceiver correctly
  node.preTransmission(preTransmission);
  node.postTransmission(postTransmission);

  cr |= MEASURE_MODE_BIT;//Set bit2 , Set to trigger mode
  cr &= ~(uint16_t)TEMP_CPT_SEL_BIT;//Select internal temperature compensation
  cr &= ~(uint16_t)TEMP_CPT_ENABLE_BIT;//enable temperature compensation
  writeData(eControl, cr); //Writes the setting value to the control register
  delay(100);
}

void BLYNKSetUp(void) {
  BLYNK_LOG("Main firmware: %s", BLYNK_FIRMWARE_VERSION);
  BLYNK_LOG("Build: %s", __DATE__ " " __TIME__);

  // Initialize the Blynk.NCP hardware
  if (Blynk.initNCP()) {
    String ver = Blynk.getNcpVersion();
    BLYNK_LOG("Blynk.NCP firmware: %s", ver.c_str());
  } else {
    BLYNK_LOG("Cannot communicate to Blynk.NCP");
    BLYNK_LOG("  Please ensure you have flashed your board with the Blynk.NCP firmware, before running this example.");
    BLYNK_LOG("  See: https://github.com/blynkkk/BlynkNcpExample");
    return;
  }

  // Print state changes
  Blynk.onStateChange([]() {
    BLYNK_LOG("State: %s", Blynk.getStateString());
  });

  // Set config mode timeout to 30 minutes, for testing purposes
  Blynk.setConfigTimeout(30*60);

  Serial.println("Blynk Connecting");
  Blynk.begin(BLYNK_TEMPLATE_ID, BLYNK_TEMPLATE_NAME);
  Serial.println("Blynk Connected");
}

void myTimerEvent() {
  Serial.println("Creation des variables");
  cr |= MEASURE_TRIG_BIT;//Set trig bit
  writeData(eControl, cr); //Write the value to the control register and trigger a ranging
  delay(300);//Delay of 300ms(minimum delay should be greater than 30ms) is to wait for the completion of ranging
  dist = (float)readData(eDistance) / 10;//Read distance register, one LSB is 0.1mm
  tempInt = (float)readData(eInternalTempreture) / 10.0;//Read the temperature register, one LSB is 0.1℃
  Serial.print("distance = ");
  Serial.print(dist, 1);
  Serial.println("mm");
    delay(100);
    nbLCuves = ((1655 - dist) * total_l / 2300);
    if (nbLCuves <= 0) {
      nbLCuves = 0;
    }
    txCuves = ((nbLCuves / total_l) * 100);
    delay(100);
    //*******************************************BLYNK VIRTUAL WRITE
    Serial.println("Virtual Writing At Blynk");

    Blynk.virtualWrite(V2, nbLCuves);
    Serial.print("nbLCuves=");
    Serial.println(nbLCuves);
    Blynk.virtualWrite(V3, txCuves);
    Serial.print("txCuves=");
    Serial.println(txCuves);
    Blynk.virtualWrite(V4, dist);
    Serial.print("dist=");
    Serial.println(dist);
    Blynk.virtualWrite(V5, tempInt);
    Serial.print("tempInt=");
    Serial.println(tempInt);
  }

void loop() {
  Blynk.run();
  timer.run();  // Initiates BlynkTimer
  delay(1);
}