Here are the details of my project, which PaulRB has been amazing helping me out with the hardware side of things, and some general coding advice.
http://forum.arduino.cc/index.php?topic=600984.0
I have a generalized coding question so I decided to ask that here.
To summarize the project:
Read two inputs from an alarm panel and write the states to the Blynk app virtual LED's
When Blynk app button is pressed, toggle the alarm 'SET' state.
I had the code running using interrupts and it works for a short time, but after a while the Wemos goes offline, i 'think' due to the server being spammed and rejecting the connection. So I decided to change the code to polling type, with debounce for the two inputs.
Getting to the question:
The two functions are called every 1000ms to check the inputs and update the Blynk app
The debounce code I used from the example is meant to be in void loop.
Is this going to cause me any issues?
My current code:
//v004 Garage alarm (change from interrupts to polling)
//
//
//Project requirements:
//The alarm panel has two outputs, Armed and Sounder
//Poll these two outputs every 1000ms and write the result to a virtual LED (Blynk app on phone)
//The alarm panel has one input SET which can arm or disarm the system
//When a virtual button is pressed (on phone Blynk app) the alarm is armed or unarmed.
//
//
//Issues:
//Previous code used interrupts, but was spamming the local server, causing it to go offline
//(maybe caused by inputs from the alarm giving square wave?)
//v004 changes code to polling with debounce for the two inputs
//
//To do:
//Complete function for debounce read of "Sounder" i.e sounder on or off
//Check - functions are called every 1000ms by timer, but code was written to be in void loop. Is this ok?
//
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <SimpleTimer.h>
char auth[] = ""; //Enter the Auth code which was send by Blynk
char ssid[] = ""; //Enter your WIFI Name
char pass[] = ""; //Enter your WIFI Password
char server[] = "192.168.1.90"; //for local server only
int port = 8080; //for local server only
//Setup constants for the sketch
const byte Armed = D5; // INPUT - is the panel armed, or un-armed/alarmed? (armed = HIGH/3.3V and Unarmed/alarmed = LOW/0V)
const byte Sounder = D6; // INPUT - is the sounder on or off? (Sounder on = LOW/0.33V and Sounder off = HIGH/3.3V)
const byte SET = D4; // OUTPUT - set or unset the alarm (HIGH = unset the alarm, LOW = set the alarm)
//Setup variables for Armed
int ArmedState = digitalRead(Armed); //reads armed state of the alarm (armed = HIGH/3.3V and Unarmed/alarmed = LOW/0V)
int lastArmedState = ArmedState; // the previous read from the input pin
//Setup variables for Sounder
int SounderState = digitalRead(Sounder); //reads state of sounder i.e on or off (Sounder on = LOW/0.33V and Sounder off = HIGH/3.3V)
int lastSounderState = SounderState; // the previous read from the input pin
//Setup variables for debouncing of inputs
unsigned long lastArmedDebounceTime = 0; //setup debounce variable for checkArmed function
unsigned long lastSounderDebounceTime = 0; // setup debounce variable for checkSounder function
unsigned long debounceDelay = 50; // the global debounce time in ms, increase if debounce issues continue
//Setup variable for Blynk virtual pin
static unsigned long last_interrupt_time = 0;
bool LastVirtualButtonState = 0; //"0","FALSE","LOW' means exactly the same
SimpleTimer timer; //setup simple timer to call functions on a timed basis from void loop
void setup()
{
//Setup the previously assigned constants
pinMode(Armed, INPUT); //is the panel armed, or un-armed/alarmed? (armed = HIGH/3.3V and Unarmed/alarmed = LOW/0V)
pinMode(Sounder, INPUT); //is the sounder on or off? (Sounder on = LOW/0.33V and Sounder off = HIGH/3.3V)
pinMode(SET, OUTPUT); //set or unset the alarm (HIGH = unset the alarm, LOW = set the alarm)
digitalWrite(SET, LOW); //ensures the alarm defaults to SET condition after power loss of Wemos
Blynk.begin(auth, ssid, pass, server, port); //connects to Wifi and LOCAL Blynk server (running on raspberry pi)
//write the current states to the Blynk app
Blynk.virtualWrite(V5, (ArmedState * 255)); // writes set or unset state of alarm to Blynk virtual LED pin V5
Blynk.virtualWrite(V6, (!SounderState * 255)); //writes sounder on or off state to Blynk virtual LED pin V6 (inverted logic as sounder is on when at 0V
timer.setInterval(1000L, checkArmed); //Setup a function to be called every second
timer.setInterval(1000L, checkSounder); //Setup a function to be called every second
}
void loop()
{
Blynk.run(); //This function should be called frequently to process incoming commands and perform housekeeping of Blynk connection.
timer.run(); //Initiates SimpleTimer to runs timed functions
}
void checkArmed() //a function run every 1000ms to check if panel is armed or un-armed/alarmed? (armed = HIGH/3.3V and Unarmed/alarmed = LOW/0V)
{
int readingArmed = digitalRead(Armed); // read the state of "Armed" into a local variable:
if (readingArmed != lastArmedState) //has the state changed?
{
lastArmedDebounceTime = millis(); // if yes(state has changed), reset the debouncing timer to the current millis
}
if ((millis() - lastArmedDebounceTime) > debounceDelay) // whatever readingArmed is at, it's been there for longer than the debounce delay, so take it as the actual current state
{
if (readingArmed != ArmedState) // has the armed state has changed?
{
ArmedState = readingArmed; // if yes(state has changed)
{
Blynk.virtualWrite(V5, (ArmedState) * 255); // writes ArmedState to Blnk V5 virtual LED names "Alarm armed?"
}
}
}
lastArmedState = readingArmed; // save the readingArmed. Next time through the function, it'll be the lastArmedState:
}
void checkSounder() //a function run every 1000ms to check if the sounder is on or off? (Sounder on = LOW/0.33V and Sounder off = HIGH/3.3V)
{
//To complete, essentialy the same as checkArmed
}
// BLYNK_WRITE is a function called every time the device gets an update of a Virtual Pin value from the server (e.g. Blynk app virtual button is pressed)
// contains "latching" code to stop long hold being registered as repeated presses.
BLYNK_WRITE(V3)
{
int VirtualButtonState = param.asInt(); // assigning incoming value from pin V3 to a variable
if ((VirtualButtonState) && (!LastVirtualButtonState)) // "VirtualButtonState" is the Blynk virtual button current state |||||| this means same as "if ((VirtualButtonState == 1) && (LastVirtualButtonState == 0))"
//if V3 virtual button is still being pressed, the LastVirtualState is set to 1, and !LastVirtualState will therefore be 0. Hence 1 && 0 condition == 0 and therefore function will not be called.
{
digitalWrite(SET, !digitalRead(SET)); //writes the inverse value to the pin (booleon NOT operator )
Blynk.virtualWrite(V0, digitalRead(SET) * 255); // for information only, writes the state of the keyswitch SET contacts to Blynk virtual LED at V0
}
LastVirtualButtonState = VirtualButtonState; // sets LastVirtualButtonState to the same as pinValue, so if pinValue (V3 button) is high, LastVirtualPinState gets set to high
}
PCB layout for info: