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);