Hi @Gunner
Here’s my latest code, yes the two timers run at the same time interval. I could set them differently i.e. 300 and 500ms, they would still get called at the same time every 5th call though (correct?).
Thanks
//v009 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.
//
//
//Changelog:
//v004 had issues with Blynk server heartbeat timeouts and app disconnecting and sometimes unresponsive
//v005 combines both armed and sounder functions into one, run by one timer
//v006 added serial to terminal code as per this thread https://community.blynk.cc/t/serial-arduino-to-terminal-blynk/31547/4
//v007 added correct serial to terminal code working correctly - needs rx to tx link on device
//v008 added date/time stamp to terminal widget, required rtc widget on app, and added serial prints when states change
//v009 fixes for terminal repeating (used BlynkTimer and increased timer interval. Optional add Blynk.run to function
//so that more CPU time is allocated for housekeeping. Rewrote serial prints as virtual writes to V1. Search for "v009" to see changes.
//
//Future improvements:
// Change code to Blynk.virtualWrite(vPin, "Random blatherings\n") where required
//
//Optional/not needed? libraries
//#define BLYNK_DEBUG //optional, enable for debugging to serial
//#include <ESP8266WiFi.h> //not needed?
//#include <TimeLib.h> //not needed?
#define BLYNK_PRINT Serial // Defines the object that is used for printing Blynk stuff
#include <BlynkSimpleEsp8266.h>
#include <ESP8266mDNS.h> //for OTA updates
#include <WiFiUdp.h> //for OTA updates
#include <ArduinoOTA.h> //for OTA updates
#include <WidgetRTC.h> //for clock sync
//Blynk credentials
char auth[] = ""; //Enter the Auth code which was send by Blynk
//char auth[] = ""; // v009 TEST Breadboard auth token
//Wifi credentials
char ssid[] = ""; //Enter your WIFI Name
char pass[] = ""; //Enter your WIFI Password
//Server credentials
char server[] = "192.168.1.93"; //LOCAL SERVER ONLY
int port = 8080; //LOCAL SERVER ONLY
//Support for Blynk terminal
WidgetTerminal terminal(V1); //terminal reads from virtual pin specified
//Support for Blynk real time clock
WidgetRTC rtc;
//SimpleTimer timer; //setup simple timer to call functions on a timed basis from void loop
BlynkTimer timer; // v009 improvement http://docs.blynk.cc/#blynk-firmware-blynktimer
//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
void setup()
{
Serial.begin(9600);
Blynk.begin(auth, ssid, pass, server, port); //connects to Wifi and LOCAL Blynk server (running on raspberry pi)
setSyncInterval(60 * 60); // v009 increase time if needed - Sync Blynk real time clock (RTC) interval in seconds (default 10x60 = 10 minutes)
//OTA stuff (update device from Arduino IDE remotely)
ArduinoOTA.onError([](ota_error_t error) { ESP.restart(); });
ArduinoOTA.setHostname("Wemos_no_05_Garage_Alarm");
//ArduinoOTA.setHostname("Wemos_no_01_TEST_GARAGE_ALARM"); // for testing purposes
ArduinoOTA.begin();
//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
//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
//Setup Blynktimers
timer.setInterval(500L, Sent_serial); // Timer calls function to send any serial data to terminal - default 100ms - v009 increase interval if needed
timer.setInterval(500L, checkCombined); //Timer calls function to read state of alarm panel - default 100ms - v009 increase interval if needed
//Optional print free memory to terminal
Blynk.virtualWrite(V1, "Free RAM: ", ESP.getFreeHeap(), " bytes\n"); //v009 optional print free RAM each time the function is called
//Blynk.virtualWrite(V1, "\n" ); //starts new line
}
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
ArduinoOTA.handle(); // For OTA
}
BLYNK_CONNECTED()
{
rtc.begin(); // Synchronize time on connection
serial_print_date_time();
Blynk.virtualWrite(V1, "Server connected\n");
//Blynk.virtualWrite(V1, "\n" ); //starts new line
}
//A function to print current date and time to Blynk terminal widget, gets called from the below functions
void serial_print_date_time()
{
Blynk.virtualWrite(V1, "\n" );
String currentDate = String(day()) + "/" + month() + "/" + year();
String currentTime = String(hour()) + ":" + minute() + ":" + second();
Blynk.virtualWrite(V1, currentDate, " @ ", currentTime, " : ");
}
void Sent_serial() //A function which reads the serial monitor output and send to terminal widget (requires tx and rx pins to be connected together on device).
{
// Sent serial data to Blynk terminal - Unlimited string readed
String content = ""; //null string constant ( an empty string )
char character;
while(Serial.available())
{
character = Serial.read();
content.concat(character);
}
if (content != "")
{
Blynk.virtualWrite (V1, content);
terminal.flush(); // Ensure that data was sent out of device //added by 877dec v009
}
}
void checkCombined()// a combined function to read the "armed" state and the "sounder" state
{
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?"
if (ArmedState == LOW)
{
serial_print_date_time();
Blynk.virtualWrite(V1, "System disarmed"); //writes to terminal widget
terminal.flush(); // Ensure that data was sent out of device
}
else
{
serial_print_date_time();
Blynk.virtualWrite(V1, "System armed"); //writes to terminal widget
terminal.flush(); // Ensure that data was sent out of device
}
}
}
lastArmedState = readingArmed; // save the readingArmed. Next time through the function, it'll be the lastArmedState:
Blynk.run(); //v009 optional extra Blynk.run to allocate more CPU/RAM to the Blynk process, to remove duplicate terminal issues
int readingSounder = digitalRead(Sounder); // read the state of "Armed" into a local variable:
if (readingSounder != lastSounderState) //has the state changed?
{
lastSounderDebounceTime = millis(); // if yes(state has changed), reset the debouncing timer to the current millis
}
if ((millis() - lastSounderDebounceTime) > debounceDelay) // whatever readingSounder is at, it's been there for longer than the debounce delay, so take it as the actual current state
{
if (readingSounder != SounderState) // has the sounder state has changed?
{
SounderState = readingSounder; // if yes(state has changed)
Blynk.virtualWrite(V6, (!SounderState) * 255); // writes SounderState to Blnk V6 virtual LED named "Sounder on?"
if (SounderState == LOW)
{
Blynk.notify("Garage alarm is sounding!"); //only send Blynk app notification when then sounder is ON
serial_print_date_time();
Blynk.virtualWrite(V1, "Sounder activated!"); //writes to terminal widget
terminal.flush(); // Ensure that data was sent out of device
}
else
{
serial_print_date_time();
Blynk.virtualWrite(V1, "Sounder deactivated"); //writes to terminal widget
terminal.flush(); // Ensure that data was sent out of device
}
}
}
lastSounderState = readingSounder; // save the readingSounder. Next time through the function, it'll be the lastSounderState:
}
// 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
if (digitalRead(SET) == LOW)
{
serial_print_date_time();
Blynk.virtualWrite(V1, "System arm request"); //writes to terminal widget
terminal.flush(); // Ensure that data was sent out of device
}
else
{
serial_print_date_time();
Blynk.virtualWrite(V1, "System disarm request"); //writes to terminal widget
terminal.flush(); // Ensure that data was sent out of device
}
}
LastVirtualButtonState = VirtualButtonState; // sets LastVirtualButtonState to the same as pinValue, so if pinValue (V3 button) is high, LastVirtualPinState gets set to high
}