Preventing MKR WiFi 1010 from endless connection attempts if network unavailable

I am working on a project using a MKR WiFi 1010 mounted in an Iono MKR case/shield for industrial use. The project is for vending machines where the general idea is to use an interrupt to count pulses from a Coin Validator and if successful use the Iono's relay to activate a solenoid in the machine.

First, all of this works great if the MKR is able to connect to the IOT cloud. Where I seem to be running into issues is when it is unable to connect to the WiFi (for example incorrect SSID). From what I have read in the forums so far, the WiFi blocks interrupts while trying to connect which from the output seems to be retrying every 500 milliseconds.

The use of WiFi and the cloud is just to report that a sale was made so the machine can be monitored remotely but... if it gets disconnected or can't connect in the first place, I need the machine to continue to operate and count pulses.

So what I have been trying to figure out is if there is a way to have it give up on trying to connect and hijacking the interrupt so the machine will function despite the lack of WiFi. Alternatively, it seems that I could maybe move the interrupt to another pin to count the pulses as thats the main thing I need to have working regardless of it being connected.

Here is the code I am using now. I am happy to pair it down to the essentials if that would be better. For example, a good chunk of the code is there to control the NeoPixel strips in the machine.

/* 
  Sketch generated by the Arduino IoT Cloud Thing "Untitled"
  https://create.arduino.cc/cloud/things/736079f9-336b-4385-adc5-09a6bfb2e3b4

  Arduino IoT Cloud Variables description

  The following variables are automatically generated and updated when changes are made to the Thing

  String vend_state;
  int dollars;

*/

/*
Iono Pin Assignments
DI1 = Pulse Pin (blue wire to 5VO, orange to DI1)
DI6 = LED strip pin (set jumper to BYP which maps to pin 1)??
DI2 = Micro switch pin (yellow to 5VO, green to DI2)
DO4 = Solenoid Relay (open for wiring)

1) Coin validator pulse length should be set to 150
2) IONO DI5 and DI6 jumpers should be set to BYP (bypass)

*/

#include <Iono.h>
#include "arduino_secrets.h"
#include "thingProperties.h"


#include <Adafruit_NeoPixel.h>


// ------ SETTINGS ------------------------------------------------------------
int price = 10; // Price of the items to vend
int dollars_per_pulse = 10; //Dollars per pulse/set of pulses, usually 1-4
int happy_dance_length = 23000; //Length in miliseconds

// ------Validator Setup ------------------------------------------------------

volatile int pulses = 0; // counting the pulses sent
//volatile int dollars = 0; this is defined in the thing.properties for iot
volatile int read_validator = 0;
int vending = 0;
int vend_validated = 0;
int vend_solenoid = 0;
int vend_credits = 0 ;

// Variables to cancel a vend if it sits too long (5 min (300000ms default)
// This is just to prevent the solenoid from taying engaged if someting happens
long vend_cancel_delay = 300000; // 5 mins
long vend_start = 0;
long vend_diff = 0;

// String vend_state = "WAITING"; this is defined in the thing.properties for iot


// LIGHTING SETUP -----------------------------------------------------------

#define LED_PIN 1
#define LED_COUNT 66
Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);



void setup() {

 
  // Initialize serial and wait for port to open:
  Serial.begin(9600);
  // This delay gives the chance to wait for a Serial Monitor without blocking if none is found
  delay(1500); 

 


  
  //------- AST SETUP -------------------------------------
  Serial.println("Iono Setup - Start");
  Iono.setup();

  // Subscribe to the vaidator pin
  //Iono.subscribeDigital(DI1, 49, &count_pulses);
  // Not sure if the best number to use for the second option
  // The idea is that it's a min length between pulses?
  Iono.subscribeDigital(DI1, 20, &count_pulses);

  // Subscribe to the microswitch
  //Iono.subscribeDigital(DI2, 10, &vend_end);

  Serial.println("Iono Setup - Done");
 
  Serial.println("Waiting for CASH");
  vend_state = "START";
   
  // Make sure the solenoid is off
  Iono.write(DO4, LOW);
    
  
  //delay(500);
  pulses = 0;



  // TEST - Set the DAC to output 3.3v on the A01 pin on the IONO
  // This is to power the logic level shifter
  analogWriteResolution(10);
  analogWrite(A0, 300);

  // Startup the lights
  strip.begin();
  //Set the indicator for IOT cloud to red
  strip.setPixelColor(0, 255, 0, 0);
  strip.show(); 
  lights_idle();
  vend_state = "WAITING";
  


  Serial.println("Arduino Cloud - Start");
 
 
 
 // Defined in thingProperties.h
  initProperties();

  // Connect to Arduino IoT Cloud
  ArduinoCloud.begin(ArduinoIoTPreferredConnection);
  

 
  setDebugMessageLevel(3);
  ArduinoCloud.printDebugInfo();


  ArduinoCloud.addCallback(ArduinoIoTCloudEvent::CONNECT, doThisOnConnect);
  ArduinoCloud.addCallback(ArduinoIoTCloudEvent::SYNC, doThisOnSync);
  ArduinoCloud.addCallback(ArduinoIoTCloudEvent::DISCONNECT, doThisOnDisconnect);
  
    Serial.println("Arduino Cloud - Done");

    
  
}

void loop() {

  //Serial.println("looping");


  if ( ArduinoIoTPreferredConnection.getStatus() == (NetworkConnectionState::CONNECTED)) {
    Serial.println("CONNECTED");
    ArduinoCloud.update();
  }

  // Test DAC output on A0 - IONO A01
  analogWriteResolution(10);
  analogWrite(A0, 300);

  
  //seem to need to update the variable before updating the cloud
  vend_state = vend_state;


  
  //-------AST LOOP--------------------------
  
  Iono.process();

  //delay(10);                             

  // If the dollar count (credits) is higher than the price
  // This also supports tracking actual dollar amounts from a Bill validator
  if (vending == 1) {

    // Cancel the vend if it sits too long.      
    vend_diff = millis() - vend_start;
    if ( vend_diff > vend_cancel_delay) {
      vend_cancel();
    }            
          
    vend_begin();        
  }

  if (Iono.read(DI2) == LOW) {
    Serial.println("MICRO SWITCH");
    vend_end();
    
  }

}


void count_pulses(uint8_t pin, float value) { 
  
    // if statement is to replace checking RISING or FALLING   
    if (value == HIGH) {
      read_validator = 1;
      pulses += 1; 
      Serial.print("Pulse: ");
      Serial.println(pulses);


      //  Credit reached after 4 pulses
      if ( pulses == 4) {
          dollars += dollars_per_pulse;
          
          //Set the vend cancel timer
          vend_start = millis();
          
          Serial.print("Total Credit $");
          Serial.println(dollars);
          pulses = 0;
          read_validator = 0;
          vend_validated = 1;
          vending = 1;

      }          
    }
}


void vend_begin() {      

      // Activate solenoid
      if (vend_solenoid == 0 and vending == 1) {
        vend_state = "VEND START";
        lights_vend();
        Serial.println("Solenoid: ON");
        Iono.write(DO4, HIGH); 
        vend_solenoid = 1;
      }   

}


   
//void vend_end(uint8_t pin, float value) { //Needed if using the Iono Interrupts
void vend_end() {

    vend_state = "VEND COMPLETE";
    ArduinoCloud.update();

    //if (vending == 1 and value) { //Needed if using the Iono Interrupts
    if (vending == 1 ) {

          Iono.write(DO4, LOW);   
          Serial.println("Solenoid: OFF");      
          vend_solenoid = 0;          
         
          // Reset the variables
          vending = 0;
          vend_validated = 0;
          vend_solenoid = 0; 

          // Subtract the credits
          dollars -= price;
 
          // Set back to a waiting state
          vend_state = "WAITING";
          Serial.print("STATE: ");
          Serial.println(vend_state);
          Serial.print("DOLLARS: $");
          Serial.println(dollars);          

          // Do the happy light dance
          lights_happy();
          

          if (dollars >= price) {
            vending = 1;
            vend_state = "READY";        
            vend_begin();        
          } 
          else {
            lights_idle();
          }
          
    }
    

}

void vend_cancel() {
    Iono.write(DO4, LOW);   
    Serial.println("Solenoid: OFF");      
             
   
    // Reset the variables
    vending = 0;
    vend_validated = 0;
    vend_solenoid = 0; 
  
    // Subtract the credits
    dollars -= price;

    vend_state = "CANCELLED";
    Serial.print("STATE: ");
    Serial.println(vend_state);
    Serial.print("DOLLARS: $");
    Serial.println(dollars);
    lights_cancel();
    delay(10000);
    lights_idle();
}



void lights_idle() {
  uint32_t color_white = strip.Color(150,120,30);


  strip.setBrightness(100);
  strip.fill(color_white, 1,LED_COUNT); 

  strip.show();

}

void lights_vend() {
  uint32_t color_green = strip.Color(115,181,0);
  
  strip.fill(color_green, 1,LED_COUNT);
  strip.show();  

  
}

void lights_cancel() {
  uint32_t color_red = strip.Color(255,0,0);
  
  strip.fill(color_red, 1,LED_COUNT);
  strip.show();  

  
}


void lights_happy() {

  int direction = 0;
  int brightness = 1;

  // Calculate the number of loop steps based on the happy_dance_time
  int step_time = 10;
  int dance_steps = happy_dance_length / step_time;
  
  // Enable Relay DO1 for accessory control
  Iono.write(DO1, HIGH);

  uint32_t color_magenta = strip.Color(255,0,255);
  strip.setBrightness(100);
  strip.fill(color_magenta, 1,LED_COUNT);
  strip.show();
 
  for (int i = 1; i <= dance_steps; i++) {
    if (brightness >= 99) {
      direction = 1;
    }
    else if (brightness <= 1) {
      direction = 0;
    }
   
    if (direction == 0) {
      brightness += 3;
    }
    else {
      brightness -= 3;
    }

    strip.setBrightness(brightness);
    strip.show();

    delay(step_time);
    //Serial.print("Brightness");
    //Serial.println(brightness);
  }
  

  // Disableble Relay DO1 for accessory control
  Iono.write(DO1, LOW);

  vend_state = "WAITING";
  
  
}


void doThisOnConnect(){
  /* add your custom code here */
  Serial.println("Board successfully connected to Arduino IoT Cloud");
  strip.setPixelColor(0, 0, 0, 255);
  strip.show();
}
void doThisOnSync(){
  /* add your custom code here */
  Serial.println("Thing Properties synchronised");
}
void doThisOnDisconnect(){
  /* add your custom code here */
  Serial.println("Board disconnected from Arduino IoT Cloud");
  strip.setPixelColor(0, 255, 0, 0);
  strip.show();
}

Also here is the thingProperties code as well

// Code generated by Arduino IoT Cloud, DO NOT EDIT.

#include <ArduinoIoTCloud.h>
#include <Arduino_ConnectionHandler.h>

const char SSID[]     = SECRET_SSID;    // Network SSID (name)
const char PASS[]     = SECRET_OPTIONAL_PASS;    // Network password (use for WPA, or use as key for WEP)


String vend_state;
int dollars;



void initProperties(){

  ArduinoCloud.addProperty(vend_state, READ, ON_CHANGE, NULL);
  ArduinoCloud.addProperty(dollars, READ, ON_CHANGE, NULL);

}

WiFiConnectionHandler ArduinoIoTPreferredConnection(SSID, PASS);


Hi @inventart

It should be possible to stop the re-connection attempts by adding false as a second parameter to the ArduinoCloud.begin() function:

ArduinoCloud.begin(ArduinoIoTPreferredConnection, false);

Thanks Martin! So I gave that a try and it seems after reading a bit as well that the false parameter disables the watch dog timer. From what I understand, the timer is in place to allow the board to auto-resetting if something goes wrong. In this case conection attempts still allow the ArduinoCloud.update() to run which is what resets the watch dog timer. So for example here is my output

Connection to "schoolhouse" failed
Retrying in  "500" milliseconds
Connection to "schoolhouse" failed
Retrying in  "500" milliseconds
MICRO SWITCH
Connection to "schoolhouse" failed
Retrying in  "500" milliseconds

So it seems the connection attempt is blocking while attempting to connect and only allowing the loop to run in-between. When I hold the Microswitch it only outputs for the brief moment the board loops. So I am not sure if it is the lack of time for the interrupts to run and count the 4 pulses that mean a coin was dropped or, if the interrupt is actually taken over by the wifi connection. Either way it still only ends up reading the pulses once it has successfully connected to the IOT Cloud

Have a great night!
Dan

Just to add, I was able to get it to go into a vend state but I had to rapid fire coins into the token unit to get it to catch 4 pulses and go into vend. Then I also had to catch the microswitch in-between the connection attempts to get it to vend and go back to the waiting state.

Connection to "schoolhouse" failed
Retrying in  "500" milliseconds
Connection to "schoolhouse" failed
Retrying in  "500" milliseconds
Connection to "schoolhouse" failed
Retrying in  "500" milliseconds
Pulse: 4
Total Credit $10
Solenoid: ON
Connection to "schoolhouse" failed
Retrying in  "500" milliseconds
Connection to "schoolhouse" failed
Retrying in  "500" milliseconds
Connection to "schoolhouse" failed
Retrying in  "500" milliseconds
MICRO SWITCH
Connection to "schoolhouse" failed
Retrying in  "500" milliseconds
Solenoid: OFF
STATE: WAITING
DOLLARS: $0

So the issue seems to be more that it's just blocking while attempting to connect. So the solution I guess I do need is to get it to give up after "X" attempts

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.