Create time out for Spark.connect()?

Good points I will try writing some different code to test it.

Ok, so here is the second attempt, using the timer to shutdown the connect process. It compiles but I have not tested it. Also finally learnt how to use the spark libraries. So the include statement is a bit easier. Can someone else load this as I have my spark core testing my Pixy Camera Rover and I don’t want to break it again.

Of course Spark.io could always send me a few Cores (like a class set=15 one per two students), so I can continue trying to make Spark products easier to use :wink:

// This #include statement was automatically added by the Spark IDE.
#include "SparkIntervalTimer/SparkIntervalTimer.h"

// Attempt number 2 
// check Spark Core for Wifi on startup, if no wifi then allow it to run none-cloud dependent activities.





SYSTEM_MODE(SEMI_AUTOMATIC);


// Create IntervalTimer object
IntervalTimer myTimer;


// Pre-define ISR callback functions
void checkWifi(void);


//const uint8_t ledPin = D7;		// LED for first Interval Timer


void setup(void) {
    pinMode(D7, OUTPUT);  

    digitalWrite(D7,HIGH);      // blink D7 fast once before timer activated
    delay(40);
    digitalWrite(D7,LOW);

    myTimer.begin(checkWifi, 20000, uSec);   // check for wifi and shutdown if no connection after 20 seconds
    delay(50);
    
    Spark.connect();   // try to connect
    
    
    
    digitalWrite(D7,HIGH);      // blink D7 slow twice when timer activated (checks if blocking)
    delay(500);
    digitalWrite(D7,LOW);
    delay(500); 
    
    digitalWrite(D7,HIGH);     
    delay(500);
    digitalWrite(D7,LOW);

  
}


volatile unsigned long myConnect = 0; // use volatile for shared variables: 0 just starting, 1 connected, 2 no connectivity, 99 first timer done


void checkWifi(void) {
    if (myConnect != 0){  // not the first activation of the timer
    
      if (WiFi.ready()){   // this loop should wait 20 seconds to occur
          myConnect = 1;   // means wifi got connected
      } else {
           Spark.disconnect(); 
           WiFi.off();
           myConnect =2;   // means no wifi
      }
       myTimer.end();  // no mater what happens shut down the timer since we only want it to work once
       
       
       
    } else {
        myConnect = 99;  // identifies the first run has completed.
        
    }
       
}

int myLoop;


void loop() {

  if (myConnect == 1) {         // do your wifi connected loop
    digitalWrite(D7,HIGH);      // blink D7 fast to show that Wifi is working
    delay(100);
    digitalWrite(D7,LOW);
    delay(100);    
    // other statements here
  }
  
  if (myConnect == 2) {            // do your no wifi loop
    digitalWrite(D7,HIGH);         // leave D7 on to show manual mode   
    // other statements here  
  }

  if (myConnect == 1 || myConnect == 2) {           // do statements that are for either wifi or no wifi modes
    // other statements here  
  }
  
  

}

.
.
.
.

Here is information about the Pixy Camera Rover, it follows a certain color. I still have to tweak some values so the rover doesn’t go racing down the street.

That thread is at https://community.spark.io/t/how-to-make-a-spark-toy-car-heel-like-a-dog/10762/15

The github site is at:

1 Like

Almost there, I think.

After the amout of effort you already put into this, I’d like to suggest these adaptions
At this point I haven’t tested them myself, but just from experience this should work - and I’ll test it soon and correct if required :wink:
Edit: This is now working code, but in my tests I’ve got the impression, all that interrupt/timer effort is not needed anyhow, since Spark.connect() doesn’t seem to block anymore (despite still being stated to be and as I remember it to have been)
@mdma, has anything been changed “recently” that hasn’t found its way into the docs? Or am I imagining things?

// This #include statement was automatically added by the Spark IDE.
#include "SparkIntervalTimer/SparkIntervalTimer.h"

SYSTEM_MODE(SEMI_AUTOMATIC);

// Create IntervalTimer object
IntervalTimer myTimer;

// Pre-define ISR callback functions
void checkWifi(void);

volatile uint8_t isrTriggered = 0;

const unsigned long CONNECT_TIMEOUT = 30000;
unsigned long lastMillis;    // it's always good to have this for non-blocking delays

void setup(void) {
    pinMode(D7, OUTPUT);  

    digitalWrite(D7,HIGH);   // blink D7 fast once before timer activated
    delay(40);
    digitalWrite(D7,LOW);

    // this would only wait 20ms since uSec is micro seconds
    // myTimer.begin(checkWifi, 20000, uSec);   // check for wifi and shutdown if no connection after 20 seconds
    // the other time scale is half-milliseconds (hence 2*)
    myTimer.begin(checkWifi, 2 * CONNECT_TIMEOUT, hmSec);
    
    lastMillis = millis();  // store soft-delay reference time
    
    // try to connect
    isrTriggered = 0;
    Spark.connect();
    if (!isrTriggered)
    {   // only wait if connection attempt succeeded
        myTimer.end();  // don't disconnect prematurely
    
        while ((millis() - lastMillis) < CONNECT_TIMEOUT)
        {
            digitalWrite(D7, HIGH); 
            delay(50);             // flash LED about 10Hz
            Spark.process();
            digitalWrite(D7, LOW);  
            delay(50);             // flash LED about 10Hz
        } 
        Spark.disconnect();  // missed your chance for OTA flashing
    }
    WiFi.off();  // deactivate WiFi in any case  
}

// no need to re-check inside loop() now
void loop()
{
    digitalWrite(D7, HIGH); 
    delay(500);            // flash LED about 10Hz
    digitalWrite(D7, LOW);  
    delay(500);            // flash LED about 10Hz
}

void checkWifi(void) 
{
    isrTriggered = 1;
    Spark.disconnect();  // no more required inside ISR
}

Edit: Fixed some build error - Spark.connect() does not return any success/fail indicatior :frowning:

1 Like

Thanks @ScruffR. I just found another thread that might be useful.

Yep, that’s the one that introduced SYSTEM_MODE().
Only after this it became even possible to squeeze in some code before Spark.connect() that might be able to stop any running connection attempt.

Nothing has changed since the last release in October 2014. Afaict, Spark.connect() will never block, since it just calls WiFi.connect(), which is non-blocking, and sets a flag to cause the background thread to connect to the cloud.

What about this then?

When the user calls Spark.connect(), the user code will be blocked, and the Core will attempt to negotiate a connection. This connection will block until either the Core connects to the Cloud or an interrupt is fired that calls Spark.disconnect().

http://docs.spark.io/firmware/#system-modes-semi-automatic-mode

@ScruffR, @mdma perhaps some test code is in order to establish if Spark.connect() or WiFi.connect() actually block user code or not. The story until now has been that user code will block when the cloud connection is LOST in AUTOMATIC mode but SEMI_AUTOMATIC and MANUAL mode scenarios are not so clear. It would be good to understand the behavior once and for all :stuck_out_tongue:

1 Like

As my code above suggests, it actually doesn’t block in SEMI_AUTOMATIC - which contradicts the official docs, tho’.

After the call to Spark.connect() the 10Hz blinking starts immediately, even when my router is off.

Thanks @ScruffR, just as I thought. So running SEMI_AUTOMATIC seems like the best scenario for user code controlling the Cloud connection. :smiley:

2 Likes

Thanks @ScruffR and @peekay123!

So what it seems like to me is this problem is solved.

If you would like to try connecting without blocking, put the Spark Core in SEMI_AUTOMATIC mode and call Spark.connect() . If you want to cancel it, just wait for millis() or the like and call Spark.disconnect() and/or Wifi.off() .

Did I get it right?

I hope the docs will be updated if there are any inconsistencies.

1 Like

Can we finish this thread with some code that actually compiles.

So should this work? Reminder that I do not have a core I can check this on just yet. If someone could try it that would be useful.

SYSTEM_MODE(SEMI_AUTOMATIC);

int myConnect=0;

void setup() {
   
   pinMode(D7, OUTPUT);  
   Spark.connect();
   
   delay(5000);
   delay(5000);
   delay(5000);
   delay(5000);
   
   if (WiFi.ready()){   
        myConnect = 1;   // means wifi got connected
    } else {
        Spark.disconnect(); 
        WiFi.off();
        myConnect =2;   // means no wifi
        digitalWrite(D7,HIGH);     // D7 high says no wifi but spark working fine.
      }
}

void loop() {
    
    // put generic code here
    
    if (myConnect == 1){   // only put code here that needs wifi
        digitalWrite(D7,HIGH);     // fast blink says Wifi connected
        delay(50);
        digitalWrite(D7,LOW); 
        delay(50);        
    }
    
    
    if (myConnect == 2){   // only put code here that is fine with no wifi

    }
}

@rocksetta, this should work, but there are some things to improve.

  • Why use multiple consecutive delay() statements instead of one big one - even Arduino would allow up to 65535 and the Core 2^32 - 1
  • Have you had a look at the “soft delay”, I’ve used in my sample code? This is the prefered way to do long delays. This way you could keep the delays as short as needed, since you can check for state changes inside the loop.
  • Do you actually mean to let the cloud on, if it’s there? This didn’t seem so in the OP.
  • Are you intending to have more than two states for myConnect - if not I’d go for 0/1 with preset 0 and if(myConnect) ... else
  1. I thought delays over 20 seconds messed up calls to spark.process(), but if not it isn’t a big deal.

  2. Good idea with the soft delays. My code took about 6 minutes to write so it may have a few issues. I still haven’t got confirmation if the code works as my Core is busy with another project. That would be very helpful.

  3. If the core connects to the Cloud, great let it continue. Trying to make the code as simple as possible so that if someone wants to change it they can.

  4. The zero “0” state was for when you do not know yet if there is a connection or not. 1 = Good Cloud connection, 2 = No Cloud connection. Really doesn’t matter either way, I originally wanted to make the myConnect variable boolean, but sometimes when debugging code integers are just easier to work with.

  1. delay() was adapted in a quite early stage to internally call Spark.process() once every second of a long delay.

  2. My code is confirmed to work. Just strip away the interrupt part - since it’s not needed - and put in what you want :wink:

  3. :+1:

  4. You can still print booleans as integers for debugging and I can’t see any real difference between “no cloud yet” (0) and “no cloud later” (2) :wink:

  1. Good to know
  2. Please show your new code as the interrupt and volatile variable show up in about 5 places, and all of this is supposed to be helping beginners.
  3. Actually 0, 1, 2 is needed since 0 and 1 does not prove Wifi has been disconnected and could show a false positive. But seriously we just want working code, let the academics stress about correctness.

Anyway, got tired of waiting for someone to test my code so I thought I would include it in my Rover. Here is the slightly changed code that works:
With Wifi in range, it connects quickly breaths cyan, waits 20 seconds and then flashes D7 fast to show Wifi Cloud connectivity.
Without Wifi nearby it flashes green for 20 seconds then shows solid D7 HIGH and strangely breaths cyan??

Here is the code:

SYSTEM_MODE(SEMI_AUTOMATIC);

int myConnect = 0;      // means neither connected or disconnected yet

void setup() {

   pinMode(D7, OUTPUT);  
   Spark.connect();             // non-blocking attempt to connect to Wifi

   delay(20000);   // wait 20 seconds at startup


   if (WiFi.ready()){   
        myConnect = 1;   // means wifi got connected
    } else {
        Spark.disconnect(); 
        WiFi.off();
        myConnect =2;   // means no wifi cloud connectivity
        digitalWrite(D7,HIGH);     // D7 high says no wifi but spark working fine.
      }
}

void loop() {

    // put your generic code here that works if Wifi connected or not

    if (myConnect == 1){   // only put code here that needs wifi
    
        digitalWrite(D7,HIGH);     // fast blink says Wifi connected
        delay(50);
        digitalWrite(D7,LOW); 
        delay(50);    
        
        // put your code here that needs wifi Cloud connectivity
    }


    if (myConnect == 2){   // only put code here that is fine with no wifi
    
      // put your code here that runs without Wifi Cloud connectivity
      // LED D7 should be HIGH to prove Wifi has been disconnected

    }
}

You can try using this:

void setup(){
  pinMode(led,OUTPUT);
  digitalWrite(led,HIGH);
}

void loop(){
    if(WiFi.ready() && !Spark.connected()){
      Spark.connect();
    }
    else
      WiFi.connect();
  }

  digitalWrite(led,!digitalRead(led));
  delay(1000);
}
2 Likes

Actually not quite :wink:
All of this shoud be helping you to get up to speed and being an advocate of the paradigm to lead people to knowledge rather than chewing it up and pre-thinking it for them, I'd trust you'll be able to work it out :+1:

As the idiomatic saying about teaching how to fish is (most the time) better than handing a fish - as a physics teacher, I'd guess you'd seen from experience, that things your pupils had to work for stuck better in their mind than what was merely presented to them.

I disagree, the Hello World program (which is what we are making) is made to get students started so that they can put time into their own projects. But I am too busy to argue. I will just teach my method and ignore yours. :wink: