Terminal repeating...and lots of connecting to server messages

Would you please test terminal.print() and terminal.println() in conjunction with terminal.flush(), rather than Blynk.virtualWrite().

Yes no problems, I already have that code as I originally wrote it that way. I will post when back at my PC tomorrow. Thanks :+1:

I can’t guarantee this will fix your “Terminal repeating” problem, however, I’m confident the result will be different using terminal.print() / terminal.println() vs Blynk.virtualWrite(Vx, content).

There are two parts to the Terminal widget. There’s the Blynk application part and the device firmware part,

WidgetTerminal terminal(Vx);

If you use Blynk.virtualWrite(Vx, content), you don’t even need to declare the WidgetTerminal terminal(Vx). Blynk.virtualWrite(Vx, content) will still write characters to the terminal widget on the Blynk app, however, I get the sense they’re missing certain “metadata”.

The notion of terminal.flush() is a function of the Terminal widget on the device. There’s “magic” underlying the terminal.print() / terminal.println() commands. For example,

class WidgetTerminal

    virtual size_t write(uint8_t byte) {
        mOutBuf[mOutQty++] = byte;
        if (mOutQty >= sizeof(mOutBuf)) {
            flush();
        }
        return 1;
    }

    virtual void flush() {
        if (mOutQty) {
            Blynk.virtualWriteBinary(mPin, mOutBuf, mOutQty);
            mOutQty = 0;
        }
    }

writes characters to a 64-character buffer (mOutBuf). If the number of characters written exceeds the size of the buffer, the buffer it automagically flushed. Of course, the terminal.flush() function flushes the buffer.

If you’re invoking Blynk.virtualWrite(Vx, content) directly, all of this logic is bypassed.

I vote we test terminal.print() and terminal.println() in conjunction with terminal.flush(), rather than Blynk.virtualWrite(). If that doesn’t solve the problem, we’ll go from there. But this is the way the Terminal widget was intended to be used.

1 Like

@wickedbeernut apologies for the delay, I have been unwell over the weekend :face_with_thermometer:

That makes sense, I will rewrite the code with terminal prints and report back.

Do you think the serial to terminal code could be causing any issues?

@wickedbeernut @Gunner

I have modified the code below, but am getting more duplicate entries than ever! It’s actually lots worse than using the Blynk.virtualWrite(V1, “text”);
(I was just getting server reconnect messages at random times before).

With terminal.print, when I reopen the iOS app after a few minutes inactivity, the screen scrolls very fast and then the duplicate entries are there.

Pasted from terminal:

1/1/1970 @ 0:0:6 Server connected

Free RAM: 46808 bytes

IP: 192.168.1.xx

[6131] 

    ___  __          __

   / _ )/ /_ _____  / /__

  / _  / / // / _ \/  '_/

 /____/_/\_, /_//_/_/\_\

        /___/ v0.6.1 on ESP8266



[6207] Connecting to 192.168.1.xx:xxxx

[6263] Ready (ping: 8ms).

[6404] Time sync: OK

27/3/2019 @ 20:22:47 System disarm request

27/3/2019 @ 20:22:52 System arm request

27/3/2019 @ 20:22:55 System armed

27/3/2019 @ 20:22:59 Sounder activated!

27/3/2019 @ 20:23:4 System disarmed

27/3/2019 @ 20:23:7 System disarm request

27/3/2019 @ 20:23:11 Sounder deactivated

27/3/2019 @ 20:23:14 System arm request

27/3/2019 @ 20:23:17 System armed

1/1/1970 @ 0:0:6 Server connected

Free RAM: 46808 bytes

IP: 192.168.1.xx

[6131] 

    ___  __          __

   / _ )/ /_ _____  / /__

  / _  / / // / _ \/  '_/

 /____/_/\_, /_//_/_/\_\

        /___/ v0.6.1 on ESP8266



[6207] Connecting to 192.168.1.xx:xxx

[6263] Ready (ping: 8ms).

[6404] Time sync: OK

27/3/2019 @ 20:22:47 System disarm request

27/3/2019 @ 20:22:52 System arm request

27/3/2019 @ 20:22:55 System armed

27/3/2019 @ 20:22:59 Sounder activated!

27/3/2019 @ 20:23:4 System disarmed

27/3/2019 @ 20:23:7 System disarm request

27/3/2019 @ 20:23:11 Sounder deactivated

27/3/2019 @ 20:23:14 System arm request

27/3/2019 @ 20:23:17 System armed

I’m happy to try anything else you can suggest!
Thanks

//v010 Garage alarm (see changelog below)
//
//
//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.
//v010 added delay between timer functions. More fixes for terminal repeats (changed Blynk.virtualWrite for terminal.print).
//
//Future improvements:
// Change code to Blynk.virtualWrite(vPin, "Random blatherings\n")
// Blynk.virtualWrite(V1, "\n" );   //starts new line


#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[] = ""; // v009 TEST Breadboard auth token
//Wifi credentials
char ssid[] = "";  //Enter your WIFI Name
char pass[] = "";  //Enter your WIFI Password
//Server credentials
char server[] = ""; //LOCAL SERVER ONLY
int port = xxxx;  //LOCAL SERVER ONLY


//Support for Blynk terminal
WidgetTerminal terminal(V1); //terminal reads from virtual pin specified, possibly not needed when using "Blynk.virtualWrite(Vx, content)"

//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_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
  delay(100); //added 100ms delay to ensure timers do not get called at the same time
  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
   terminal.print("Free RAM: ");      //v010
   terminal.print(ESP.getFreeHeap()); //v010
   terminal.println(" bytes");        //v010
   terminal.flush();                  //v010

}



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();
  terminal.println("Server connected");        //v010
  terminal.flush();                           //v010
}



//A function to print current date and time to Blynk terminal widget, gets called from the below functions
void serial_print_date_time()
{
  //v010 changes below
  String currentDate = String(day()) + "/" + month() + "/" + year();
  String currentTime = String(hour()) + ":" + minute() + ":" + second();
  terminal.print(currentDate);
  terminal.print(" @ ");
  terminal.print(currentTime);
  terminal.print(" ");
}



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 != "") 
  {
   terminal.print(content); // v010
   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();
          terminal.println("System disarmed"); //v010
          terminal.flush();   // Ensure that data was sent out of device
        }

        else
        {
          serial_print_date_time();
          terminal.println("System armed"); //v010
          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();
          terminal.println("Sounder activated!"); //v010
          terminal.flush();   // Ensure that data was sent out of device
          }

          else
          {
          serial_print_date_time();
          terminal.println("Sounder deactivated"); //v010
          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();
     terminal.println("System arm request"); //v010
     terminal.flush();   // Ensure that data was sent out of device
    }

    else
    {
     serial_print_date_time();
     terminal.println("System disarm request"); //v010
     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
}

I’m a bit confused (aren’t we all!).

When I use this approach I use Serial.print for everything. The function then mirrors all of the serial monitor output to the terminal as well. That way, if your device is connected to your PC by serial connection you get the output in the serial monitor, plus it appears in the Blynk terminal screen anyway.
I don’t get any duplication of output.
My version of Sent_serial() uses Blynk.virtualWrite instead of terminal.print(content) and terminal.flush()

Here’s my version, including a switch to disable the terminal output if desired:

  void Send_Serial()
  {
    // Sends serial data to Blynk as well as the serial monitor
    //(handy for setups where the MCU isn't connected to serial because OTA is being used)
    // Note that a jumper is needed between Tx and Rx, which needs to be removed 
    // if doing a serial flash upload (but this is not necessary for OTA flash upload)
  
    if (terminal_output_enabled)
    {    
      String content = "";
      char character;
      while(Serial.available())
      {
        character = Serial.read();
        content.concat(character);
      }
      if (content != "")
      {
        Blynk.virtualWrite (Widget_Terminal, content);
      }
    } 
  } //end of void Send_Serial

I found it necessary to add this line immediately after Serial.begin, to give a larger serial buffer to avoid lost characters:

  Serial.setRxBufferSize(1024); // Increase the serial buffer size

After that, everything is done as a Serial.print and appears in as normal in the serial monitor and in the terminal widget (with a slight lag, as I tend to run my timer every 1000 millis rather than 500), provided the terminal_output_enabled boolean variable is set to true.

Pete.

Have you tried placing a " yield(); " in your while loops? This will allow the CPU to process other requests and may reduce timeout, disconnect / reconnect cycles.

You may be getting timed out and then reconnect just as often in each case.
The fact that you are seeing more messages may only be due to the buffer getting flushed more often.

Can we try commenting out this line,

timer.setInterval(500L, Sent_serial);

I don’t see where the Sent_serial function serves a purpose in the context of this sketch.

It redirects anything that the Blynk library would normally print to the serial monitor to the terminal. That’s where the Blynk logo, version number, IP address and ping time comes from.
I think that turning it off will solve the duplicate problem, but I think that my solution, which is to send all messages to the terminal; via this routine as Serial.prints is better.

Pete

@PeteKnight thanks for the helpful send_serial code, I will implement that now and report back.

BUT… interestingly the repeated terminal code appears even when the Wemos is not powered up. I was curious and tested it this way:

  1. Clear terminal window on iOS app and reset Wemos
  2. Wait a second until Blynk logo etc. appears
  3. Unplug Wemos from power
  4. Press home button to background the app
  5. Used other apps for a few minutes, switched back to Blynk - no terminal repeats
  6. Left phone locked and did not use for around 5mins, switched back to Blynk - terminal repeats as per below:
1/1/1970 @ 0:0:3 Server connected

Free RAM: 46928 bytes

Fi

[3069] IP: 192.168.1.xx

[3069] 

    ___  __          __

   / _ )/ /_ _____  / /__

  / _  / / // / _ \/  '_/

 /____/_/\_, /_//_/_/\_\

        /___/ v0.6.1 on ESP8266



[3145] Connecting to 192.168.1.xx:8080

[3207] Ready (ping: 10ms).

[3347] Time sync: OK

1/1/1970 @ 0:0:3 Server connected

Free RAM: 46928 bytes

Fi

[3069] IP: 192.168.1.xx

[3069] 

    ___  __          __

   / _ )/ /_ _____  / /__

  / _  / / // / _ \/  '_/

 /____/_/\_, /_//_/_/\_\

        /___/ v0.6.1 on ESP8266



[3145] Connecting to 192.168.1.xx:8080

[3207] Ready (ping: 10ms).

[3347] Time sync: OK

Could this be an app issue? (I’m using latest Blynk app v2.25.0 (3) for iOS).

I will try your code and report back soon - thank you! :smile:

I’m using iOS version 2.25.0 (3) on one device and iOS 2.26.0 (2) (beta) on another - both with Blynk cloud server though, and don’t have any problems using the approach I mentioned above.

Pete.

1 Like

@PeteKnight
Very strange, I tried with the new code below and am still getting terminal repeats, it’s only when the phone is locked for several minutes.

//v011 Garage alarm (see changelog below)
//
//
//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.
//v010 added delay between timer functions. More fixes for terminal repeats (changed Blynk.virtualWrite for Serial.print).
//v011 changed send_terminal function as per PeteKnight (Blynk forum), changed terminal prints to serial prints. Removed unneeded comments.
//
//
//Future improvements:
// Change code to Blynk.virtualWrite(vPin, "Random blatherings\n")
// Blynk.virtualWrite(V1, "\n" );   //starts new line
//


//#define BLYNK_DEBUG  //optional, enable for debugging to serial 

#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[] = ""; // v011 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.xx"; //LOCAL SERVER ONLY
int port = xxxx;  //LOCAL SERVER ONLY


//Support for Blynk terminal
WidgetTerminal terminal(V1); //terminal reads from virtual pin specified, possibly not needed when using "Blynk.virtualWrite(Vx, content)"
bool terminal_output_enabled = true;

//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);
  Serial.setRxBufferSize(1024); // Increase the serial buffer size //v011 improvement
  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(1000L, Send_Serial);    // Timer calls function to send any serial data to terminal - default 100ms  - v009 increase interval if needed //v011 increased to 1000ms
  delay(500);                               //added 100ms delay to ensure timers do not get called at the same time
  timer.setInterval(1000L, checkCombined);  //Timer calls function to read state of alarm panel - default 100ms  - v009 increase interval if needed //v011 increased to 1000ms

  //Optional print free memory to terminal
   Serial.print("v011 Garage alarm"); 
   Serial.print("Free RAM: ");      
   Serial.print(ESP.getFreeHeap()); 
   Serial.println(" bytes");     
}



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();
  Serial.println("Server connected");     
}



//A function to print current date and time to Blynk terminal widget, gets called from the below functions
void serial_print_date_time()
{
  String currentDate = String(day()) + "/" + month() + "/" + year();
  String currentTime = String(hour()) + ":" + minute() + ":" + second();
  Serial.print(currentDate);
  Serial.print(" @ ");
  Serial.print(currentTime);
  Serial.print(" ");
}



//New function by PeteKnight (Blynk forum)
  void Send_Serial()
  {
    // Sends serial data to Blynk as well as the serial monitor (handy for setups where the MCU isn't connected to serial because OTA is being used)
    // Note that a jumper is needed between Tx and Rx, which needs to be removed if doing a serial flash upload (but this is not necessary for OTA flash upload)
  
    if (terminal_output_enabled)
    {    
      String content = "";
      char character;
      while(Serial.available())
      {
        character = Serial.read();
        content.concat(character);
      }
      if (content != "")
      {
        Blynk.virtualWrite (V1, content);
      }
    } 
  } //end of void Send_Serial



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();
          Serial.println("System disarmed"); //v010
        }

        else
        {
          serial_print_date_time();
          Serial.println("System armed"); //v010
        }
    }
  }
  
  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();
          Serial.println("Sounder activated!"); //v010
          }

          else
          {
          serial_print_date_time();
          Serial.println("Sounder deactivated"); //v010
          }
        
     }
  }
  
  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();
     Serial.println("System arm request"); //v010
    }

    else
    {
     serial_print_date_time();
     Serial.println("System disarm request"); //v010
    }
  }

  LastVirtualButtonState = VirtualButtonState;  // sets LastVirtualButtonState to the same as pinValue, so if pinValue (V3 button) is high, LastVirtualPinState gets set to high
}

Should I perhaps try with the Blynk cloud?
EDIT - I am testing now…
EDIT 2- tested and getting same duplicated entries after locking phone for a few minutes…

PS - side issue, any ideas how clean up my terminal output timings? I think when Blynk server is connected the code jumps to BLYNK.CONNECTED() before the setup prints have occured.
Also the time does not have chance to synchronize so i get 0/0/1970 @ 0:0:0

BLYNK_CONNECTED()
{
  rtc.begin();  // Synchronize time on connection
  serial_print_date_time();
  Serial.println("Server connected");     
}

As currently it’s all coming out jumbled up:

[69] Connecting to 877wifi

[574] Connected to WiFi

[574] IP: 192.168.1.xx

[574] 

    ___  __          __

   / _ )/ /_ _____  / /__

  / _  / / // / _ \/  '_/

 /____/_/\_, /_//_/_/\_\

        /___/ v0.6.1 on ESP8266



[647] Connecting to 192.168.1.xx:8080

[703] Ready (ping: 5ms).

0/0/1970 @ 0:0:0 Server connected

[5704] Connecting to 192.168.1.xx:8080

[5716] Ready (ping: 7ms).

1/1/1970 @ 0:0:5 Server connected

[5856] Time sync: OK

v011 Garage alarmFree RAM: 46144 bytes

Thanks :smile:

You should probably try Blynk cloud. You could also try uninstalling and re-installing the App.

Pete.

@PeteKnight
Many thanks for your help so far!

I have tried these one at a time:

  1. adjusted code for Blynk cloud server
  2. deleted and re-installed app
  3. disabled background refresh
  4. turned off terminal widget “add new line” and “auto scroll”

Result:
Same terminal repeats.

Perhaps it’s the iOS app/iOS itself, I’m on iOS 12.1.2 for information.
Should I report the issue?

Or is there anything else I can try?

I understand if people are losing interest - so am I :laughing:

Give me a couple of hours and I’ll upload your latest code to a device and give it a go myself to see if I get the same results and whether anything else springs to mind in the process.

Pete.

1 Like

I’m on 12.1.4
Do you have an update available?

Pete.

Thanks - that’s very good of you :smile: I look forward to your results.

PS - I’m staying on 12.1.2 as I like to jailbreak my phone (it’s not currently jailbroken and never has been since the last restore). I can’t imagine that would be the cause, but you never know…

I only jailbreak for the CarBridge tweak which allows me to have custom apps mirrored to my cars HUD (Blynk being one of those I will mirror) :smile:
Link if you’re interested

Okay, it’s doing the same thing for me…

then if I hit the stop button in the app, followed by the run button, it goes back to this:

the duplicate lines aren’t appearing in the serial monitor on the PC, just in the terminal.

It seems that the app has to be running in the background for around 3-5 minutes before it will do this.

Pete.

1 Like

It would seem you’ve confirmed that it’s the exact same issue reported in February (and never resolved?) …

@PeteKnight thanks you for taking the time to check this :smile:

I’m glad it’s not just me, I can also confirm that pressing the stop button in the app, followed by the run button, it goes back to normal ‘non-repeated’. I guess this is a quick fix for now.

Where would be best to report the bug? (github maybe).

@wickedbeernut yes it would seems to be exactly the same problem that @italex33 reported. I went down the route of thinking it was code related as several posts also went that way, including mine :wink: