BlynkTimer Question

Platform: Arduino UNO WiFi Rev 2
Arduino 1.8.8

I need a timer to make sure a garage door goes completely open or closed within a specified travel time. There are two limit switches, one activated when the door is closed and one activated when the door is open. Both are Normally Open. When the door starts going up, the bottom limit switch will go open (upper switch is already open). Both are open during door travel. When the door is completely open, the bottom limit switch will be open and the upper switch will be closed.

Timer Requirements: I want to set up a timer such that, if the door doesnā€™t go completely open or closed within X seconds after starting, I will get an alert. If the door goes completely open or closed in less than X seconds, the timer expires and doesnā€™t trigger anything. The timer should be reused on the next door opening or closing. Or the timer could be destroyed and a new timer created for the next door opening or closing.

I donā€™t need entire code (Iā€™ve got a Garage Door State Machine running) - just need help with the BlynkTimer functions to be able to start, expire/stop, and restart a timer.

Function setTimeout(unsigned long d, timer_callback f) looked promising, but ā€œafter the callback f has been called, the interval is deleted, therefore the value timerId is no longer valid.ā€ (per the Arduino SimpleTimer Library Docs.

I tested setTimeout below and Timer2 is no longer enabled after f has been called.

Do you have any ideas how to code this using BlynkTimer? Should I delete a timer and create a new one?

Thanks for any help on this!

#include <WiFiNINA.h>
#include <BlynkSimpleWiFiNINA.h>

int timer2;
BlynkTimer timer;

void OnceOnlyTask() {
  Serial.println("This timer only triggers once");

// Debug print lines:
  Serial.print("Timer number: ");
  Serial.println(timer2);
  Serial.print("Timer is enabled: ");
  Serial.println(timer.isEnabled(timer2));
  Serial.println("Restarting timer");
  timer.restartTimer(timer2);
}

void setup() {
  Serial.begin(9600);

  Serial.println("SimpleTimer Example");
  Serial.println("Timer2 is set to trigger only once after 1 second");
  Serial.println();

  timer2 = timer.setTimeout(1000, OnceOnlyTask);
}

void loop() {
  timer.run();
//  Is timer2 enabled after f executes?
  if ((millis() % 3000) == 0){
    Serial.print("Timer is enabled: ");
    Serial.println(timer.isEnabled(timer2));
  }
}

Replying to my own question aboveā€¦
After a bit of reflection, I realized that this is a very basic timer function that should probably be performed without the library. I took this inspiration from Robin2ā€™s suggestion in Simple timer function for arduino; Reply #1 where he wrote ā€œHave a look at the demo several things at a time which illustrates how to manage timing with millis(). It is quite straightforward. You could wrap that up in a library if you want to but it will just make the code longer and more complex for the same end result. Libraries are great when they work but a real PITA when they donā€™t. I prefer to spend my time fixing my problems rather than trying to figure out what a library is doing that it should not be doing (or vice versa).ā€

A few basic lines of code solved it (excerpts below from my finite state machine).

#1: In state DOOR_OPEN, when door starts to close, calculate the maximum permissible end timeā€¦

if (limitSwitchOpenState == HIGH) {                // Door starting to close
    timeDoorTravelEnd = millis() + maxTravelTime;  // Time door has to be closed by
    branchToState(DOOR_LOWERING);
}

#2: then, in state DOOR_LOWERING, watch for timer expiration or door going closed, whichever happens firstā€¦

if (millis() > timeDoorTravelEnd) {          // Timer expired
    branchToState(DOOR_FAULT);               // Move to Door Fault state
}

if (limitSwitchClosedState == LOW) {         // Door fully closed
    branchToState(DOOR_CLOSED);              // Move to Door Closed state
}

In your case you are using that type of timer in the wrong place.

Timers do NOT need to be started in the setup() it is just that that is the best place to start interval timers that run from then on.

But as you discovered, a setTimeout() timer is a one shot deal. If you want to run it again, your simply use the same command again, wherever it is most useful in your code.

However, as far as possible bugs go in both SimpleTmer and BlynkTimer, I have noticed that when using Timer IDā€™s and associated ID based commands (most notably deleteTimer() in my experiments) that it will completely stop the first timer called in your codeā€¦ apparently never to work again?? To ā€œsolveā€ this, I simply create a first sacrificial timeout timer that does nothingā€¦

1 Like

@Gunner @vshymanskyy is it so hard to ā€œrepairā€ this library? I found this bug rather annoyindā€¦

1 Like

I worked around the problem using 2 timers :wink:

/***************** Library for real-time clock *****************/
#include <WidgetRTC.h>
BlynkTimer timer,timer2;
WidgetRTC rtc;


void setup(){

timer.setInterval(450L, blinkLedWidget);
timer.setInterval(530L, ImageWidget);
timer.setInterval(1020L, UpTime);
timer.setInterval(32000, clockDisplay);
timer.setInterval(60730L, activetoday);
timer.setInterval(63160L, TempUpdate);
timer.setInterval(68100L, connectionstatus);
timer.setInterval(70980L, dallas);

TimerConso=timer2.setInterval(2030L,consumption);
timer2.disable(TimerConso);
}

I havenā€™t a clue :stuck_out_tongue: ā€¦ I must leave that up to smrtr people.

But what usually works for me is this as the first timer in my setup

  timer.setTimeout(10L, []() {
    // Sacrificial Timer
  });

From then on everything seems to work as expected with IDs and special timer commands like timer.deleteTimer(ID); etc.

1 Like

Just WOW! This is terrible. No wonder I was pulling my hair out trying to use BlynkTimer. I donā€™t know how much longer I would have played around before stumbling onto that bug.

You and @Blynk_Coeur are a huge help on this.

Since I have to include the Blynk library anyway, is there any memory overhead penalty for using BlynkTimer compared to the two lines of millis() and a defined interval (such as I did above)?

Set timer expiration timeā€¦

timeDoorTravelEnd = millis() + maxTravelTime;

then, have we passed the expiration-time?

if (millis() > timeDoorTravelEnd) {          // Timer expired
branchToState(DOOR_FAULT);                   // Move to Door Fault state
}

Iā€™m sure the Blynk people are extremely busy, but a bug like this should have been squashed long ago (speaking as a noob to Blynk).

1 Like

It is a SimpleTimer bug (I have tested it with non-Blynk code), so it wasnā€™t really Blynkā€™s initial issue. And probably not a common use case (with IDs and special commands) so not as prominent an issueā€¦

Heck, took me over a year of fiddling with various fancy timer based routines to finally realise there even was an issue!! (and not just from my strange experiments), let alone what it was or how to solve it. But hopefully it can be figured out eventually.

1 Like

A post was split to a new topic: Exception error with MCP23017 and BlynkTimer