OTA Update Not Processing? Can't Parse Firmware Version

I am attempting to send an update via OTA and am not having any luck. I have incremented the firmware version as instructed in the documentation:

#define BLYNK_FIRMWARE_VERSION "0.2.4"

If I select ‘Lower Firmware Version’ I briefly see the following error: Can't parse firmware version '{1}'. Shipment most likely won't work.

If I select to ‘No Condition’ it will start the process, but after 16 hours has not progressed through the update. The device still shows firmware version 0.2.2 in the dashboard.

The line of code is located after the template ID and template name declarations, which are the first lines of code in the sketch.

Under Shipments, the text states that the shipment is Live, but the bar beneath it is still gray.

Under Shipment Status, it shows ‘Firmware Uploaded’ with a gray indicator dot, while the firmware version still shows 0.2.2.

Does the spacing matter? IE, I think, in the currently running sketch, there is some extraneous spacing between VERSION and “0.2.2”. I noticed this only now while trying to troubleshoot.

As well, I’ve noticed that there is no auth token line in the sketch that is currently running. Should I have put this line in my original sketch? I see it under the Developers Tools → General → Firmware Information, but NOT under Developer Zone → Home → Firmware Configuration. I think this is why I did not add it initially.

Under the details for the shipment, I see the following:

* Firmware Downloaded 1:42:06 PM Today

* New Firmware Requested 1:42:06 PM Today

* Request sent 1:42:03 PM Today

* Firmware Shipment Process Started 1:42:02 PM Today

What next steps should I take for troubleshooting? Thank you for any help.

If you’re running the Edgent example sketch then there should be no auth token in the sketch, as the auth token is defined dynamically when you provision the device.

If you upload an Edgent sketch with an auth token added then you’ll be creating an issue for yourself.

More info about your current sketch and your new sketch would be helpful.

Pete.

It is an Edgent sketch. I have included it below:

#define BLYNK_TEMPLATE_ID "xxxxxxx"
#define BLYNK_TEMPLATE_NAME "Cistern Sensor"

#define BLYNK_FIRMWARE_VERSION "0.2.4"

#define BLYNK_PRINT Serial
//#define BLYNK_DEBUG

#define APP_DEBUG

// Uncomment your board, or configure a custom board in Settings.h
//#define USE_SPARKFUN_BLYNK_BOARD
#define USE_NODE_MCU_BOARD
//#define USE_WITTY_CLOUD_BOARD
//#define USE_WEMOS_D1_MINI

#define LED_PIN BOARD_LED_PIN

#include "BlynkEdgent.h"
#include <Blynk.h>
#include <dummy.h>
#include <Arduino.h>
#include <Ewma.h>

int sensorPin = A0;   // select the input pin for the pressure transducer
int sensorValue;  // variable to store the value coming from the sensor
int filtered; // variable to store exponentially weighted moving average of SensorValue
int val; // variable to store mapped value
float analogVoltage; //variabe to store calculated analog Voltage

//Ewma adcFilter1(0.1);   // Less smoothing - faster to detect changes, but more prone to noise
Ewma adcFilter(0.05);  // More smoothing - less prone to noise, but slower to detect changes

// This function creates the timer object. It's part of Blynk library
BlynkTimer timer;

void myTimer() 
{
    // turn the LED_PIN on so that we know loop is running
  digitalWrite(LED_PIN, HIGH);

  // read the value from the sensor:
  sensorValue = analogRead(sensorPin);

  // apply exponentially weighted moving average to sensorValue to smooth resukts
  // ADC is noisy on NodeMCU
  float filtered = adcFilter.filter(sensorValue);

  // convert sensorValue to analog number
  analogVoltage = filtered * 3.3 / 1023;

  // map(value, fromLow, fromHigh, toLow, toHigh)
  // Cistern is: 2x(56" H x 96" L x ~56" W) = ~3,000 gallons
  // .45v = 0 gallons, .91v = 3000 gallons)
  val = map(analogVoltage*1000, 450, 910, 0, 3000);

  // log Blynk event for various cistern water levels
  // trigger alert when cistern water volume is below 250 gallons
  if (val < 250)
{
    Blynk.logEvent("cistern_water_volume_250", String("Cistern less than 250 gallons: ") + val);
}
  // trigger alert when cistern water volume is below 500 gallons
  if (val < 500)
{
    Blynk.logEvent("cistern_water_volume_500", String("Cistern less than 500 gallons: ") + val);
}
  // trigger alert when cistern water volume is below 750 gallons
  if (val < 750)
{
    Blynk.logEvent("cistern_water_volume_750", String("Cistern less than 750 gallons: ") + val);
}
  // trigger alert when cistern water volume is around 1500 gallons
  if (val > 1485 && val < 1515)
{
    Blynk.logEvent("cistern_water_volume_1500", String("Cistern roughly 1/2 full (~1500 gallons): ") + val);
}
  // trigger alert when cistern water volume is over 3000 gallons
  if (val > 3010)
{
    Blynk.logEvent("cistern_water_volume_3000", String("Cistern over 3000 gallons: ") + val);
} 
  // This function describes what will happen with each timer tick
  // e.g. writing sensor value to datastream VX
  Blynk.virtualWrite(V1, val);
  Blynk.virtualWrite(V2, analogVoltage);
  //  turn the LED_PIN off:
  digitalWrite(LED_PIN, LOW);
}

void setup() 
{
  // Debug console. Make sure you have the same baud rate selected in your serial monitor
  Serial.begin(9600);
  BlynkEdgent.begin();
  // send data to Blynk every 5 seconds
  timer.setInterval(5000L, myTimer); 
}

void loop() 
{
  BlynkEdgent.run();
  timer.run(); // call the BlynkTimer object
}

I’m assuming from your version number that this is the new sketch that you’re attempting to upload.
I had said…

Without knowing how your new sketch compares to the one you’re currently running, it’s to identify possible issues.

You certainly have some logic issues with the event logging code. For example, a reading of lets say 200 gallons would attempt to log 3 events, as 200 is <250, <500 and <750
In addition, these events would continue to be logged every 5 seconds.

Blynk has a log limit of 100 events per day per device, so you could quickly exceed this limit.

This post explains how to use a flag variable to overcome that issue, although in your case you would need more than one variable…

I’m not sure if it matters, but I’d stick with the format from the example, which has 8 spaces.

Have you tried doing a remote reboot of your device?

Pete.

Thank you for the heads-up on the logging. I will work to remedy that today. It is a good opportunity for me to continue learning.

my apologies, here is the original code:

#define BLYNK_TEMPLATE_ID "xxxxxx"
#define BLYNK_TEMPLATE_NAME "Cistern Sensor"

#define BLYNK_FIRMWARE_VERSION        "0.2.2"

#define BLYNK_PRINT Serial
//#define BLYNK_DEBUG

#define APP_DEBUG

// Uncomment your board, or configure a custom board in Settings.h
//#define USE_SPARKFUN_BLYNK_BOARD
#define USE_NODE_MCU_BOARD
//#define USE_WITTY_CLOUD_BOARD
//#define USE_WEMOS_D1_MINI

#define LED_PIN BOARD_LED_PIN

#include "BlynkEdgent.h"
#include <Blynk.h>
#include <dummy.h>
#include <Arduino.h>
#include <Ewma.h>

int sensorPin = A0;   // select the input pin for the pressure transducer
int sensorValue;  // variable to store the value coming from the sensor
int filtered; // variable to store exponentially weighted moving average of SensorValue
int val; // variable to store mapped value
float analogVoltage; //variabe to store calculated analog Voltage

//Ewma adcFilter1(0.1);   // Less smoothing - faster to detect changes, but more prone to noise
Ewma adcFilter(0.05);  // More smoothing - less prone to noise, but slower to detect changes

// This function creates the timer object. It's part of Blynk library
BlynkTimer timer;

void myTimer() 
{
    // turn the LED_PIN on so that we know loop is running
  digitalWrite(LED_PIN, HIGH);

  // read the value from the sensor:
  sensorValue = analogRead(sensorPin);

  // apply exponentially weighted moving average to sensorValue to smooth resukts
  // ADC is noisy on NodeMCU
  float filtered = adcFilter.filter(sensorValue);

  // convert sensorValue to analog number
  analogVoltage = filtered * 3.3 / 1023;

  // map(value, fromLow, fromHigh, toLow, toHigh)
  val = map(analogVoltage*1000, 450, 1070, 0, 3000);

  // log Blynk event for various cistern water levels
  // trigger alert when cistern water volume is below 250 gallons
  if (val < 250)
{
    Blynk.logEvent("cistern_water_volume_250", String("Cistern less than 250 gallons: ") + val);
}
  // trigger alert when cistern water volume is below 500 gallons
  if (val < 500)
{
    Blynk.logEvent("cistern_water_volume_500", String("Cistern less than 500 gallons: ") + val);
}
  // trigger alert when cistern water volume is below 750 gallons
  if (val < 750)
{
    Blynk.logEvent("cistern_water_volume_750", String("Cistern less than 750 gallons: ") + val);
}
  // trigger alert when cistern water volume is around 1500 gallons
  if (val > 1485 && val < 1515)
{
    Blynk.logEvent("cistern_water_volume_1500", String("Cistern roughly 1/2 full (~1500 gallons): ") + val);
}
  // trigger alert when cistern water volume is over 3000 gallons
  if (val > 3010)
{
    Blynk.logEvent("cistern_water_volume_3000", String("Cistern over 3000 gallons: ") + val);
} 
  // This function describes what will happen with each timer tick
  // e.g. writing sensor value to datastream VX
  Blynk.virtualWrite(V1, val);
  Blynk.virtualWrite(V2, analogVoltage);
  //  turn the LED_PIN off:
  digitalWrite(LED_PIN, LOW);
}

void setup() 
{
  // Debug console. Make sure you have the same baud rate selected in your serial monitor
  Serial.begin(9600);
  BlynkEdgent.begin();
  // send data to Blynk every 5 seconds
  timer.setInterval(5000L, myTimer); 
}

void loop() 
{
  BlynkEdgent.run();
  timer.run(); // call the BlynkTimer object
}

I have upped the timing for data to be sent to every 1 minute, I have also removed the 250 and 500 gallon notifications, and added less than or equal and greater than or equal to the other volumes. This aligns with what I have set within Blynk notifications on the site.

I have also gone to my events for this device and I see the following set:

Every 1 message will trigger the event.

Event will be sent to user only once per day.

Am I on the right track with regard to cleaning up the notifications? Thank you again.

The updated sketch:

#define BLYNK_TEMPLATE_ID "xxxxxxx"
#define BLYNK_TEMPLATE_NAME "Cistern Sensor"

#define BLYNK_FIRMWARE_VERSION        "0.2.4"

#define BLYNK_PRINT Serial
//#define BLYNK_DEBUG

#define APP_DEBUG

// Uncomment your board, or configure a custom board in Settings.h
//#define USE_SPARKFUN_BLYNK_BOARD
#define USE_NODE_MCU_BOARD
//#define USE_WITTY_CLOUD_BOARD
//#define USE_WEMOS_D1_MINI

#define LED_PIN BOARD_LED_PIN

#include "BlynkEdgent.h"
#include <Blynk.h>
#include <dummy.h>
#include <Arduino.h>
#include <Ewma.h>

int sensorPin = A0;   // select the input pin for the pressure transducer
int sensorValue;  // variable to store the value coming from the sensor
int filtered; // variable to store exponentially weighted moving average of SensorValue
int val; // variable to store mapped value
float analogVoltage; //variabe to store calculated analog Voltage

//Ewma adcFilter1(0.1);   // Less smoothing - faster to detect changes, but more prone to noise
Ewma adcFilter(0.05);  // More smoothing - less prone to noise, but slower to detect changes

// This function creates the timer object. It's part of Blynk library
BlynkTimer timer;

void myTimer() 
{
    // turn the LED_PIN on so that we know loop is running
  digitalWrite(LED_PIN, HIGH);

  // read the value from the sensor:
  sensorValue = analogRead(sensorPin);

  // apply exponentially weighted moving average to sensorValue to smooth resukts
  // ADC is noisy on NodeMCU
  float filtered = adcFilter.filter(sensorValue);

  // convert sensorValue to analog number
  analogVoltage = filtered * 3.3 / 1023;

  // map(value, fromLow, fromHigh, toLow, toHigh)
  // Cistern is: 2x(56" H x 96" L x ~56" W) = ~3,000 gallons - Gabe in Pagosa Springs, CO
  // .45v = 0 gallons, .91v = 3000 gallons)
  val = map(analogVoltage*1000, 450, 910, 0, 3000);

  // log Blynk event for various cistern water levels
  // trigger alert when cistern water volume is below 750 gallons
  if (val <= 750)
{
    Blynk.logEvent("cistern_water_volume_750", String("Cistern less than 750 gallons: ") + val);
}
  // trigger alert when cistern water volume is around 1500 gallons
  if (val >= 1485 && val <= 1515)
{
    Blynk.logEvent("cistern_water_volume_1500", String("Cistern roughly 1/2 full (~1500 gallons): ") + val);
}
  // trigger alert when cistern water volume is over 3000 gallons
  if (val >= 3010)
{
    Blynk.logEvent("cistern_water_volume_3000", String("Cistern over 3000 gallons: ") + val);
} 
  // This function describes what will happen with each timer tick
  // e.g. writing sensor value to datastream VX
  Blynk.virtualWrite(V1, val);
  Blynk.virtualWrite(V2, analogVoltage);
  //  turn the LED_PIN off:
  digitalWrite(LED_PIN, LOW);
}

void setup() 
{
  // Debug console. Make sure you have the same baud rate selected in your serial monitor
  Serial.begin(9600);
  BlynkEdgent.begin();
  // send data to Blynk every 1 minute
  timer.setInterval(60000L, myTimer); 
}

void loop() 
{
  BlynkEdgent.run();
  timer.run(); // call the BlynkTimer object
}

I have rebooted the unit remotely without a change in status. I am also noticing the device constantly going offline then coming back online. The unit is plugged directly into the same outlet as a wifi extended and is within 2’ of said outlet and extender.

Are there any other logs or notifications that I can look at to help me understand what’s happening? My firmware update shows to be uploaded and live, but the firmware is still showing version 2.2 and the bar under Live is still gray.

I appreciate your efforts to further educate me. I have made the afore mentioned changes to the sketch, but I am still having trouble uploading. At this point is my only option to manually reflash the new sketch, in person?

Thank you for any insight.

It’s difficult to say, but it’s looking like you will need to do a physical update rather than OTA.

Your latest code hasn’t taken on board my comments about the need to use a series of “flag” variables to prevent constant events being logged whilst the various water level conditions exist. Changing how often alerts are sent to the user doesn’t stop the event logging continuing in the background, and the 24 hour event limits being breached.

Do you have a second device set-up locally for testing and evaluation?

Pete.

Unfortunately, I do not have a second device set up in the same manner. I did not plan for such common sense.

You were completely correct regarding using “flag” variables. Somehow I skipped right past that part. I have modified my code based upon the code in your post, but I am unsure about how to handle the different alerts that I want to be sent. Basically, I’m not entirely sure that I am implementing the “flag” variables in the correct manner for my desired outcomes. Here is my code, relying heavily upon the code in the post that you shared. Does this seem to fit the bill?

#define BLYNK_TEMPLATE_ID "xxxxxx"
#define BLYNK_TEMPLATE_NAME "Cistern Sensor"

#define BLYNK_FIRMWARE_VERSION        "0.2.5"

#define BLYNK_PRINT Serial
//#define BLYNK_DEBUG

#define APP_DEBUG

// Uncomment your board, or configure a custom board in Settings.h
#define USE_NODE_MCU_BOARD

#define LED_PIN BOARD_LED_PIN

#include "BlynkEdgent.h"
#include <Blynk.h>
#include <dummy.h>
#include <Arduino.h>
#include <Ewma.h>

int sensorPin = A0;   // select the input pin for the pressure transducer
int sensorValue;  // variable to store the value coming from the sensor
int filtered; // variable to store exponentially weighted moving average of SensorValue
int val; // variable to store mapped value
float analogVoltage; //variabe to store calculated analog Voltage
float high_threshold = 3010.0;     // We will send an alert if the cistern volume exceeds this value
float midhigh_threshold = 1485.0;     // We will send an alert when the cistern volume reaches this value
float midlow_threshold = 1515.0;     // We will send an alert when the cistern volume reaches this value
float low_threshold = 750.0;     // We will send an alert if the cistern volume drops below this value
bool alert_sent = false;      // Flag to track if an alert has been sent for an over-temp event

//Ewma adcFilter1(0.1);   // Less smoothing - faster to detect changes, but more prone to noise
Ewma adcFilter(0.05);  // More smoothing - less prone to noise, but slower to detect changes

// This function creates the timer object. It's part of Blynk library
BlynkTimer timer;

void myTimer() 
{
    // turn the LED_PIN on so that we know loop is running
  digitalWrite(LED_PIN, HIGH);

  // read the value from the sensor:
  sensorValue = analogRead(sensorPin);

  // apply exponentially weighted moving average to sensorValue to smooth resukts
  // ADC is noisy on NodeMCU
  float filtered = adcFilter.filter(sensorValue);

  // convert sensorValue to analog number
  analogVoltage = filtered * 3.3 / 1023;

  // map(value, fromLow, fromHigh, toLow, toHigh)
  // Cistern is: 2x(56" H x 96" L x ~56" W) = ~3,000 gallons
  // .45v = 0 gallons, .91v = 3000 gallons)
  val = map(analogVoltage*1000, 450, 910, 0, 3000);

  // This function describes what will happen with each timer tick
  // e.g. writing sensor value to datastream VX
  Blynk.virtualWrite(V1, val);
  Blynk.virtualWrite(V2, analogVoltage);

  // log Blynk event for various cistern water levels
  // trigger alert when cistern water volume is below 750 gallons
  if (val <= low_threshold && alert_sent == false)
  // we get here if the cistern volume is below the low_threshold value and no alert has been sent yet for this low-volume situation
{
    Blynk.logEvent("cistern_water_volume_750", String("Cistern water volume is: ") + val);
    alert_sent = true; // set the flag to indicate that an alert has been sent for this over-temp situation   
}
  else if(val <= low_threshold && alert_sent == true) 
  {
    // we get here if the cistern water volume is less than or equal to the threshold
    // but it was previously above the threshold
    // We now want to clear the alert_sent flag so that new alerts can be sent    
    alert_sent = false; // reset the flag so that a future over-temp situation will trigger an alert               
  }
  // trigger alert when cistern water volume is around 1500 gallons
  if (val >= midlow_threshold && val <= midhigh_threshold)
  // we get here if the cistern volume is between the midlow_threshold value and midhigh_threshold and no alert has been sent yet for this volume situation
{
    Blynk.logEvent("cistern_water_volume_1500", String("Cistern water volume is: ") + val);
    alert_sent = true; // set the flag to indicate that an alert has been sent for this over-temp situation
}
  else if(val <= midlow_threshold && val >= midhigh_threshold && alert_sent == true) 
  {
    // we get here if the cistern water volume is less than or equal to the threshold
    // but it was previously above the threshold
    // We now want to clear the alert_sent flag so that new alerts can be sent    
    alert_sent = false; // reset the flag so that a future over-temp situation will trigger an alert               
  }
  // trigger alert when cistern water volume is over 3000 gallons
  if (val >= high_threshold && alert_sent == false)
  // we get here if the cistern volume is above the high_threshold value and no alert has been sent yet for this over-volume situation
{
    Blynk.logEvent("cistern_water_volume_3000", String("Cistern water volume is: ") + val);  // trigger the notification
    alert_sent = true; // set the flag to indicate that an alert has been sent for this over-temp situation      
}
  else if(val <= high_threshold && alert_sent == true) 
  {
    // we get here if the cistern water volume is less than or equal to the threshold
    // but it was previously above the threshold
    // We now want to clear the alert_sent flag so that new alerts can be sent    
    alert_sent = false; // reset the flag so that a future over-temp situation will trigger an alert               
  }

  //  turn the LED_PIN off:
  digitalWrite(LED_PIN, LOW);
}

void setup() 
{
  // Debug console. Make sure you have the same baud rate selected in your serial monitor
  Serial.begin(9600);
  BlynkEdgent.begin();
  // send data to Blynk every 1 minute
  timer.setInterval(60000L, myTimer); 
}

void loop() 
{
  BlynkEdgent.run();
  timer.run(); // call the BlynkTimer object
}

It’s difficult to advise, as you haven’t described your intended operating behaviour.

If it were my system, and I wanted to monitor the contents of a water tank which supplied a property, I’d want it to work like this:
If the tank is full, then the level drops below the 3000 gallon mark I’d like to be alerted to this (once).
If it then dropped below the 1500 gallon mark I’d like to receive another alert
If it then dropped below the 750 gallon mark I’d like to be alerted to that fact also.

If the water level then went above 750 gallons, say to 1000 gallons, but again dropped below 750 gallons, I’d like to receive the 750 gallon alert again.
The same applies to situations where the level goes above the other trigger points for a while then drops down again.

It was on this basis that I said…

By using a single variable, you will receive one alert when the water drops below 3000 gallons, and no further alerts when it drops lower. I’d use three flags: lower, middle and upper.

Personally, I wouldn’t use the convoluted nested if statements that you have, I’d use switch / case instead. Here’s a bit of untested pseudocode as an example…

switch (val)
{
case > 3000 // Water level is above 3000 gal - clear all flags
// Send the value to Blynk
// Clear the lower, middle and upper flag variables
break;

case 1500 ... 3000: //  Water level is between 1500 and 3000 gallons
  // Check if upper flag is set. If not, log an event and set the flag
  // Send the value to Blynk
  // Clear the lower and middle flag variables
  break;

case 750 ... 1499: // Water level is between 750 and 1500 gallons
  // Check if middle flag is set. If not, log an event and set the flag
  // Send the value to Blynk
  // Clear the lower  flag variable
  break;

case <750: // Water level is below 750 gallons
  // Check if lower flag is set. If not, log an event and set the flag
  // Send the value to Blynk
  break;

}

Personally, I’d assemble a test rig which allows you to test code updates locally before you ship them via OTA.

Pete.

1 Like