FLash OTA, CORE using DEEP SLEEP

I am developping a program which uses DEEP SLEEP with the following line:

Spark.sleep(SLEEP_MODE_DEEP,2); // Goto Deep Sleep for 2 seconds

Before putting my CORE unit to sleep, I have set a delay of 30 seconds, so that I have plenty of time to send my modified program OTA from Web IDE.

I am unable to complete the transfert with the following error message

Error: 500. Please try again later. If the issue persists, please report to hello@particle.io.

I also tried with another program currently working on another CORE unit (no deep sleep); same result

I know for sure that my unit is using WIFI because I can see publication that my program make in the Particle Dasboard.

Does anyone have any suggestions or recommendations to help to resolve my problem.

@Gaston, can you post your code so we can get a better understanding of what you’re doing? :grinning:

Here it is

// Plant moisture monitoring
// by Gaston Paradis July 5, 2015
 
// This program will monitor the soil moisture of a plant and send an email when it need waterning
// Will use DEEP SLEEP to minimized  the usage of battery

#define MOISTPIN_1 A0                   // Pin where the soil moisture sensor is connected
#define READING_FREQUENCY  (1*10*1000)  // Frequency of reading the soil moisture
#define FLAG 1                          // EEPROM memory location to indicate if the minimum have been reached
#define DAY 2                           // EEPROM memory location containning the day the error message have been send

 struct  Content{                       // Create a structure to contain data for each sensor
     char name[15];
     char plant[15];
     int pin;                           // Pin where the soil moisture sensor is connected
     int reading;                       // Will store the reading of the soil moisture for sensor
     int minimum;                       // Level below what an alarm should be send for sensor
     int alarm_from;                    // Publishing should be done only after this hour
     int alarm_to;                      // Publishing should be done only until this hour

 };
 struct Content sensor = {"Sensor #2","Cactus",MOISTPIN_1,0,25,8,23};// Loading variable values
 unsigned long lastloop = 0;            // Use to control the next reading 
 char publishString [40];               // Use to publish to the register
 char publish_event[10];


void setup() {
     Serial.begin(9600);
    Time.zone(-4); // Set time zone to Eastern USA daylight saving time
    // DST Daily Saving Time Second Sunday March until First Sunday vember at 02:00
    //Time.zone(-4); // Set time zone to Eastern USA daylight saving time
    // DST Daily Saving Time Second Sunday March until First Sunday vember at 02:00
    sensor.reading = map(analogRead(sensor.pin), 0, 4100, 100, 0); // Initial reading
    EEPROM.write(FLAG, FALSE);  // The reading is above minimum  set the falg FALSE   INITIAL VALUE
    EEPROM.write(DAY,99);       // Make sure there is no date in the memory 
    delay(2000);        // temporaly to slow down things
    sprintf(publish_event,"Moisture");
    sprintf(publishString,"%u:%u:%u|||%i|||%i",Time.hour(),Time.minute(),Time.second(),sensor.reading,sensor.minimum);
    Spark.publish(publish_event,publishString);
    delay(2000);          // temporaly to slow down things for publication
    
    if(sensor.reading >= sensor.minimum){  // Flag to indicate that minimum has been reached
        Spark.publish("DEBUG setting the flag to FALSEt");
        Serial.println("DEBUG setting the flag to FALSEt") ;
        delay(2000);     
        EEPROM.write(FLAG, TRUE);  // The reading is above minimum  set the falg FALSE
        EEPROM.write(DAY,99);       // Make sure there is no date in the memory 
    }
    
    //Publish need water only once day 
    if ((sensor.reading < sensor.minimum)   // the moisture reading is below the minimum?
                                            // I wish to publish an alarm only within a determine time (not in the midle of the night)
    and ( Time.hour() >sensor.alarm_from)   // the current hour is more than the minimum hour to publish alarm
    and (Time.hour() <sensor.alarm_to)      // the current hour is less that the maximum hour to publish an alarm

        ) {
            Spark.publish("DEBUG below minimum"); 
               if(EEPROM.read(FLAG) == FALSE){ // The flag not being set: first time around MSG
                   // Spark.publish("Need Water");
                    delay(2000);          // temporaly to slow down things for publication
                    //Spark.publish("DEBUG Flag not set");
                    delay(2000);          // temporaly to slow down things for publication
                    EEPROM.write(FLAG, TRUE);   // Set the flag because the minimum has been reached
                    EEPROM.write(DAY, Time.day()); // Remember the date the msg was published
                 }   
                if(EEPROM.read(FLAG == TRUE)) { // We have been here before
                    if(EEPROM.read(DAY) != Time.day() ){ // Stored date is different than current day
                        //Spark.publish("Need Water");
                        delay(2000);          // temporaly to slow down things for publication
                        //Spark.publish("DEBUG Flag set not same date");
                        EEPROM.write(DAY, Time.day()); // Remember the date the msg was published   
                    }
                    else{
                        //Spark.publish("DEBUG Flag set, same date");
                        delay(2000);          // temporaly to slow down things for publication
                    }
                 } 
    }
    delay(30000);  // wait 20 second doing nothing to allow update OTA (Over The Air)
    Spark.sleep(SLEEP_MODE_DEEP,2); // Goto Deep Sleep for 2 seconds
}  
void loop() {
    // The main loop does nothing
    }

@Gaston, lines like this Spark.publish("DEBUG below minimum"); are missing an event name! You should use a non blocking millis() counter instead of the delay(30000); and call Spark.process() in the look to allow background processing:

unsigned long waitOTA;

void setup() {
...
waitOTA = millis();
while (millis() - waitOTA < 30000)
   Spark.process();

Spark.sleep(...

:smile:

This will not compile

if ((sensor.reading < sensor.minimum)   
    and ( Time.hour() > sensor.alarm_from) 
    and (Time.hour() < sensor.alarm_to)      
   )

since in C logical AND operations are written like this

if ((sensor.reading < sensor.minimum)   
    && ( Time.hour() > sensor.alarm_from) 
    && (Time.hour() < sensor.alarm_to)      
   )
1 Like

I would more than happy to improve my code as you are suggesting.
However the issue is that I cannot Flash my code OTA to my CORE unit.

My program is compiling, and it is running, I can see it publishing to my the Dashboard. I cannot flash modification made to my program.

What can I do to get my CORE unit to listen and react to me flashing the code

Thanks for the hint,

My program did compile and it is currently working.

However I am always interested to improve my programming very basic skills. with better techniques.

I will change my program when I can eventually flash my code to my CORE unit, This flashing (or lack of) is the problem that I am trying to resolve.

@Gaston, usually when a Core won’t listen it is due to user code not allowing the background process to run or causes a memory error (array out of bounds, etc.). The suggestions @ScruffR and I made were to avoid both situations. My observation regarding your Spark.publish() calls was not correct HOWEVER you do need to avoid spaces in the event text.

If you wan to OTA to your non-listening core, you will need to do a factory reset, redo the wifi credentials and then flash your code over. Alternatively, you could use Particle CLI to flash your code via USB by putting the Core in DFU mode. :smile:

1 Like

If you’ve got CLI installed, put your Core into DFU mode (see docs how to) and flash via USB the code with @peekay123 improvements regarding 30sec delay.
After you got this sorted OTA should work for future updates.

If you haven’t got CLI and don’t want to install it, you can do a factory reset and then flash updated code OTA.


beaten by seconds :+1:

1 Like

Thank you very much for your help, this is appreciated.

I don’t have Particle CLI install. So, for the time being I will do a reset factory later today and test again.

1 Like

Hi. peekay123.

Should I use the suggested code AS IS.
I insert the unsigned… at the beginning of my program.
Then I cut an paste your suggestion. I am getting a compiling error < error: lvalue required as left operand of assignment> for the line while…

Here is my modified program

// Plant moisture monitoring
// by Gaston Paradis July 5, 2015
 
// This program will monitor the soil moisture of a plant and send an email when it need waterning
// Will use DEEP SLEEP to minimized  the usage of battery

#define MOISTPIN_1 A0                   // Pin where the soil moisture sensor is connected
#define READING_FREQUENCY  (1*10*1000)  // Frequency of reading the soil moisture
#define FLAG 1                          // EEPROM memory location to indicate if the minimum have been reached
#define DAY 2                           // EEPROM memory location containning the day the error message have been send

 struct  Content{                       // Create a structure to contain data for each sensor
     char name[15];
     char plant[15];
     int pin;                           // Pin where the soil moisture sensor is connected
     int reading;                       // Will store the reading of the soil moisture for sensor
     int minimum;                       // Level below what an alarm should be send for sensor
     int alarm_from;                    // Publishing should be done only after this hour
     int alarm_to;                      // Publishing should be done only until this hour

 };
 struct Content sensor = {"Sensor #2","Cactus",MOISTPIN_1,0,25,8,23};// Loading variable values
 char publishString [40];               // Use to publish to the register
 char publish_event[10];
 unsigned long waitOTA;  //used to delay


void setup() {
     Serial.begin(9600);
    Time.zone(-4); // Set time zone to Eastern USA daylight saving time
    // DST Daily Saving Time Second Sunday March until First Sunday vember at 02:00
    //Time.zone(-4); // Set time zone to Eastern USA daylight saving time
    // DST Daily Saving Time Second Sunday March until First Sunday vember at 02:00
    sensor.reading = map(analogRead(sensor.pin), 0, 4100, 100, 0); // Initial reading
    if ((EEPROM.read(FLAG)!= FALSE) or (EEPROM.read(FLAG)!= TRUE )){ //If this is the first time the program run 
                                                                    // a random value will be populated
                                                                    // need to set a value
        EEPROM.write(FLAG, FALSE);  // The reading is above minimum  set the falg FALSE   INITIAL VALUE
        EEPROM.write(DAY,99);       // Make sure there is no date in the memory     
    }
    
    delay(2000);        // temporaly to slow down things
    sprintf(publish_event,"Moisture");
    sprintf(publishString,"%u:%u:%u|||%i|||%i",Time.hour(),Time.minute(),Time.second(),sensor.reading,sensor.minimum);
    Spark.publish(publish_event,publishString);
    delay(2000);          // temporaly to slow down things for publication
    
    if(sensor.reading >= sensor.minimum){  // Flag to indicate that minimum has been reached
        Spark.publish("DEBUG setting the flag to FALSE");
        //Serial.println("DEBUG setting the flag to FALSE") ;
        delay(2000);     
        EEPROM.write(FLAG, TRUE);  // The reading is above minimum  set the falg FALSE
        EEPROM.write(DAY,99);       // Make sure there is no date in the memory 
    }
    
    //Publish need water only once day 
    if ((sensor.reading < sensor.minimum)   // the moisture reading is below the minimum?
                                            // I wish to publish an alarm only within a determine time (not in the midle of the night)
    && ( Time.hour() >sensor.alarm_from)   // the current hour is more than the minimum hour to publish alarm
    && (Time.hour() <sensor.alarm_to)      // the current hour is less that the maximum hour to publish an alarm

        ) {
            Spark.publish("DEBUG below minimum"); 
               if(EEPROM.read(FLAG) == FALSE){ // The flag not being set: first time around MSG
                   // Spark.publish("Need Water");
                    delay(2000);          // temporaly to slow down things for publication
                    //Spark.publish("DEBUG Flag not set");
                    delay(2000);          // temporaly to slow down things for publication
                    EEPROM.write(FLAG, TRUE);   // Set the flag because the minimum has been reached
                    EEPROM.write(DAY, Time.day()); // Remember the date the msg was published
                 }   
                if(EEPROM.read(FLAG == TRUE)) { // We have been here before
                    if(EEPROM.read(DAY) != Time.day() ){ // Stored date is different than current day
                        //Spark.publish("Need Water");
                        delay(2000);          // temporaly to slow down things for publication
                        //Spark.publish("DEBUG Flag set not same date");
                        EEPROM.write(DAY, Time.day()); // Remember the date the msg was published   
                    }
                    else{
                        //Spark.publish("DEBUG Flag set, same date");
                        delay(2000);          // temporaly to slow down things for publication
                    }
                 } 
    }
    //delay(30000);  // wait 20 second doing nothing to allow update OTA (Over The Air)
 waitOTA = millis();
while (millis() = waitOTA < 30000)
   Spark.process();

    
    Spark.sleep(SLEEP_MODE_DEEP,2); // Goto Deep Sleep for 2 seconds
}  
void loop() {
    // The main loop does nothing
    }


@Gaston, your code is missing :wink:

I am brand new to the community. I am using a french keyboard and could not find the character to insert the code properly.

I got it now.

@Gaston, my mistake (keyboard booboo)! This line:
while (millis() = waitOTA < 30000)

should read:
while (millis() - waitOTA < 30000)

The minus symbol is right next to the equal symbol on the keyboard :flushed:

Is 30sec necessary for reliable flashing or could I get away with something far less?

On a Core you should allow for 30sec, since the application and the system firmware need to be transfered.
But if you set up a button or a Spark.function() to enter “OTA mode” these 30sec won’t slow down your normal application sessions.

Thanks; how long should the wait be for a Photon?

Even with the 30sec I sometimes have to flash multiple times even though I get a successful flash message. I’ve noticed this on another device that doesn’t use deep sleep, though it restarts like it was flashed. I’ve gotten into the habit of publishing a version number on startup so I can tell that the new code is actually running but it’s a bit annoying.

Since you have up to 10 sec of delays scattered over your code and your code also will consume some time plus the the time to reconnect on startup, how do you decide when to press “flash”?

As suggested above, only enter OTA mode on demand and then stay there as long as you see fit.

The Photon should take a lot less time than the Core, it usually only needs to update app firmware (unless you’ll transition to a new FW version).

Further more is there a pending issue, where application code was able to interfere with OTA firmware download, which resulted in the device still running old code after apparent successful update.

https://github.com/spark/firmware/issues/375
https://github.com/spark/firmware/issues/257

Thanks for the info. The above is not my code; my code publishes a startup message, takes a few seconds to check some sensors, publishes the result and then does peekay’s Spark.process loop for 30sec. I typically press flash from the Web interface when I see the startup message in the Web dashboard. I’m not near the device so a button won’t help and I figure a function call will have a similar timing issue so overall it’s easier just to flash a few times.

How about this?

uint32_t msTimeout = 10000;  // normal timeout if not OTAing
uint32_t msMillis;

void setup()
{
  Spark.function("waitOTA", extendDelay);
  ...
  msMillis = millis();
  while(millis() - msMillis < msTimeout)
    Spark.process();
  ...
}

int extendDelay(String cmd)
{
  msTimeout = 180000;  // or cmd.toInt() if you want to control it remotely
  msMillis = millis();
}

Alternatively you could listen for the SSE event that gets published each time your Particle comes online, trigger an event to which your device subscribed that will force it into OTA mode.

And lots of other options :wink:

1 Like