Project keeps going offline - alarm panel retrofit

Hi all,

Could I get some advice on why this Blynk project keeps going offline. I don’t think I am spamming the server.

The problem is, when it goes offline the interrupts are not captured. It leads me to wonder whether I should code to read high or low instead, in that case I think I need a new function which can be called by a timer - correct?

Some info on the project:
Wemos D1 mii
iOS Blynk app with plenty of credits

Two inputs from an alarm panel (alarm set state, and sounder on/off state)
One output to the alarm panel (close or open a link via relay, to set/unset alarm)
(see notes in codes for full descriptions)

Any help appreciated :slight_smile:

//v001 - Wemos D1 mini - garage alarm
//
//Blynk app "Garage alarm"
//Blynk documentation and help https://docs.blynk.cc/


#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>


char auth[] = ""; //Enter the Auth code which was send by Blink

char ssid[] = "";  //Enter your WIFI Name
char pass[] = "";  //Enter your WIFI Password

const byte AlarmState = D5; // INPUT - is the alarm set, or unset/alarmed? (Set = LOW/0V and Unset/alarmed = HIGH/3.3V)
const byte SounderActive = D7; // INPUT - is the sounder on or off? (Sounder on = LOW/0.33V and Sounder off = HIGH/3.3V)
const byte SetAlarm = D6; // OUTPUT - set or unset the alarm (HIGH = unset the alarm,  LOW = set the alarm)


//Setup Blynk virtual pin states
static unsigned long last_interrupt_time = 0;  
bool LastVirtualButtonState = 0; // "0", "FALSE", "LOW' means exactly the same


void setup()
{
  pinMode(AlarmState, INPUT);         // is the alarm set, or unselt/alarmed? (Set = LOW/0V and Unset/alarmed = HIGH/3.3V)
  pinMode(SounderActive, INPUT);     //is the sounder on or off? (Sounder on = LOW/0.33V and Sounder off = HIGH/3.3V)
  pinMode(SetAlarm, OUTPUT);         // set or unset the alarm (HIGH = unset the alarm,  LOW = set the alarm)
  digitalWrite(SetAlarm, LOW);      //ensures the alarm defaults to SET condition after power loss of Wemos
  
  Blynk.begin(auth, ssid, pass);   //connects to WiFi network, then connects to Blynk server
  
  
  //read the current state of the alarm
int lastAlarmState = digitalRead(AlarmState);    //reads state of the alarm i.e. set or unset
int lastSounderActive = digitalRead(SounderActive);  // reads state of sounder i.e on or off

//write the current state to the Blynk app
 Blynk.virtualWrite(V5, (!lastAlarmState * 255));      // writes set or unset state of alarm to Blynk virtual LED pin V5
 Blynk.virtualWrite(V6, (!lastSounderActive * 255));   //  writes sounder on or off state to Blynk virtual LED pin V6 


//set up interupts to capture changes of state
  attachInterrupt(digitalPinToInterrupt(AlarmState), updateAlarmState, CHANGE);         // upon change of state - call the function updateAlarmState
  attachInterrupt(digitalPinToInterrupt(SounderActive), updateSounderActive, CHANGE);   // upon change of state - call the function updateSounderActive
}



void loop()
{
 Blynk.run();  // This function should be called frequently to process incoming commands and perform housekeeping of Blynk connection.
}



void updateAlarmState()  // a function called by a CHANGE interrupt, which write the input state to a Blynk virtual LED
{
 Blynk.virtualWrite(V5, !digitalRead(AlarmState)*255);   //Using ! to invert the write, to match the alarm panel logic
}


void updateSounderActive()  // a function called by a CHANGE interrupt, which write the input state to a Blynk virtual LED
{
Blynk.virtualWrite(V6, !digitalRead(SounderActive)*255); //Using ! to invert the write, to match the alarm panel logic
}



// BLYNK_WRITE is a function called every time device gets an update of a Virtual Pin value from the server (or app): e.g. Blynk app virtual button is pressed
// Contains virtual button "latching" code
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(SetAlarm, !digitalRead(SetAlarm));       //writes the inverse value to the pin  (booleon NOT operator )
    Blynk.virtualWrite(V0, digitalRead(SetAlarm)*255);    //writes the new state to the Blynk app LED at V0
  }
  
  LastVirtualButtonState = VirtualButtonState;  // sets LastVirtualButtonState to the same as pinValue, so if pinValue (V5 button) is high, LastVirtualPinState gets set to high
}



You should read this document:

Pete.

Thanks Pete,

That was my next step to re-write the code with timers.

But…can you see anything in my existing code which is causing the offline problem? As it seems that void loop is clean already.

Thanks

Apologies, I looked at your code on my phone, expecting to see a cluttered void loop and thought that’s what I was seeing, I missed the closing curly bracket at the end of the void loop!

Back to looking at the code properly now :no_mouth:

I wonder if your interrupts are being called multiple times, because of contact bounce on whatever is doing the switching. I see that one of them is a sounder, could this be producing a square wave signal that your code is seeing as multiple interrupts and causing it to flood the server?

Maybe try putting some Serial.prints in there, Amy e including the current millis value to get an idea of how frequently these interrupt handler routines are being called?

I’d normally advocate the use of interrupts, as they save polling pins constantly with timers, if you’re monitoring something like a a push button. This makes the push button more responsive, but you almost always need some form of denouncing code.
If your alarm is producing latching outputs that stay activated for reliably long periods of time (in milliseconds) then polling these pins using timers might be a better solution.

Apologies again for not studying your code in more detail first time around - lesson learned!

Pete.

Ha no problems, I have missed those curly brackets a few times myself!

I think you are correct in that it could be bouncing, I have the project breadboarded at the moment and am just shorting them down to 0 or 3.3V with a DuPont cable.

I’ll try and stick with the interrupts and try the serial output, or introduce some denounce code, the final project when connected probably won’t need that though.

Many thanks for the comprehensive answer! :smile:

Here is some inspiration to get you started: https://www.arduino.cc/en/tutorial/debounce

BUT, you’re not allowed to use millis() within an ISR so you have to use micros() instead I think.

Please wright a pretty sub-routine and post the code here so I can steal from you! :rofl: :kissing_heart: You’ll never know when you might need it. :nerd_face:

It’s actually a interesting problem if it’s “bounce” related and I’m looking forward to see how you solve it. I’ve kinda stayed long long away from ISR since my “radio days”. @PeteKnight knows what I’m talking about :yum:

Hi distans,

Thank you. I already hit this issue in the past with a button bouncing, and have the working code after some help from Arduino forums particularly a user called 3dgeo. I’ll post it here when I am on my pc no problems :smile:

One thing I need to find out, is when the app goes offline and comes back online, how to get it to sync to match the hardware state?

Yes, I’d forgotten about the issue supposed issue with millis and interrupts. I wonder if that is just an Arduino thing, because I’ve successfully used millis in a debounce routine on a Wemo D1 Mini.

So it’s really the device that’s going offline, it’s just the app that reporting this to you.
The way to sync the device with the Blynk server is to use Blynk.syncVirtual(VPin).
There is a SyncAll function, but most people say it’s best to avoid that and just call a Sync on the Vpins you’re using.

You mention that the project is breadboarded at the moment. I’ve see so many issued caused by faulty breadboard connections that if I’m having problems that’s where I tend to look first. Many of the Chinese made breadboards don’t have great mechanical contacts, so it’s very easy to get intermittent faults or dirty connections that constantly switch between high and low until you touch the connection and it starts working again. It might be worth taking a look at that area.

Pete.

Thanks @PeteKnight for the info.
Looking back now I’m not sure I did use interrupts with my debounce code, I will keep looking.

I’m a bit confused with using “Blynk.syncVirtual(VPin)” with my code. I have two inputs (D5 and D6) which I want the Blynk virtual LED’s to match.

I have no control over the inputs, they come from a remote panel.

If one of the inputs changes state (e.g.from high to low) while the app is offline, how will the Blynk iOS app know to “catch up”?

I will do more reading in the meantime, thanks!

The Blynk app re-synchronises with the server when the app is opened. Sometimes you’ll see the ‘juggling balls’ while this is happening. All you need to do is make sure the server is updated with the latest data, which you’re already doing.

Pete.