ESP8266 Wemos D1 Mini - Time Input Widget

Sry I forgot.

V0 - ZeRGBa
V5 - Text with notice about Motion Detection
V9 - PIR_timer - 10 seconds
V8 - ALARM_timer - 5 seconds
V11 - ALARM_timerInput Widget
V12 - PIR_timerInput Widget

First Night with the Sketch above does work for the PIR part, but Not for the ALARM part :frowning:

And while I wake up this morning, the whole settings in blynk were resett to default values, so I guess the ESP crashed and rebooted :frowning:

EDIT: Found the problem with the not working Alarm :smiley:

 if (ALARM_status) {
    colorWipe(red, green, blue, 50);
    colorWipe(0, 0, 0, 50);
  }

red green and blue seems to be zero at this point :confused:

and after talking with my girlfriend… she think about that the thunderstorm last night could be possible for the restart of both ESPs… maybe there was a little time where we don’t have any power/electricity.

2 Likes

Hey JustBertC,

while coding and coding and thought my code is ready I’ve got 2 new problems :frowning:

1st: My ESP keep disconnecting after a while to blynk. Also with the WiFi isn’t up. I’ve got this reconnect Sketch, and it seems to not work. I’m not able to ping the IP adresses that are fixed as a static in my router.

2nd: If the time for the PIR is set to 8 pm Start and 6 am Stop and then the alarm timer is set to 7 pm f.e. the alarm effect won’t start at all. If I set Start and Stop or Alarm this way that the Alarm is between Start and Stop of PIR the Alarm will work as intended.

Here is my actual sketch:

#define BLYNK_PRINT Serial

#include <Adafruit_NeoPixel.h>
#include <BlynkSimpleEsp8266.h>
#include <ESP8266WiFi.h>
#include <NTPClient.h>
#include <SPI.h>
#include <SimpleTimer.h>
#include <WiFiUdp.h>

// LED Stuff
#define PIN D5
#define NUM_LEDS 37
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ400);
void showStrip();
void clearStrip();
void setPixel(int, int, int, int);
void fadeToBlack(int, byte);
void ZeRGBa();
void colorWipe(int, int, int, int);
void CylonBounce(int, int, int, int, int, int);
void meteorRain(int, int, int, int, int, boolean, int);

// WiFi Stuff
char auth[] = "********";
char ssid[] = "********";
char pass[] = "********";
char serv[] = "********";

// Variables
int interval = 1000;
unsigned long previousMillis = 0;
unsigned long currentMillis = 0;

int red = 1;
int green = 0;
int blue = 2;

int connectionDelay = 5 * 1000;
int connectionSuccess = 0;

// Motion Sensor Variables
int PIR_pin = D3;
int PIR_val;
int PIR_start = 79200;
int PIR_stop = 21600;
int PIR_timer = 10 * 1000;
int PIR_effect = 1;
char PIR_days_start[] = "1,2,3,4,5,6,7";
bool PIR_days[] = {true, true, true, true, true, true, true};
bool PIR_status = false;
unsigned long PIR_start_millis = 0;

int now;
int finish;
int weekday;

// Alarm Variables
int ALARM_start = 21600;
int ALARM_timer = 60 * 1000;
int ALARM_effect = 4;
char ALARM_days_start[] = "1,2,3,4,5";
bool ALARM_days[] = {true, true, true, true, true, false, false};
bool ALARM_status = false;
unsigned long ALARM_start_millis = 0;

const long utcOffsetInSeconds = 2 * 60 * 60;

unsigned long delayStart = 0;
bool delayRunning = false;

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "10.0.4.1", utcOffsetInSeconds, 24 * 60 * 60 * 1000);

SimpleTimer timer;

void WIFI_check();
void TIME_check();
void PIR_check();
void ALARM_check();

void setup()
{
  Serial.begin(115200);
  Blynk.begin(auth, ssid, pass, serv, 8080);
  timeClient.begin();

  timer.setInterval(5.0 * 1000L, WIFI_check);
  timer.setInterval(0.2 * 1000L, TIME_check);
  timer.setInterval(0.5 * 1000L, PIR_check);
  timer.setInterval(1.0 * 1000L, ALARM_check);

  pinMode(PIR_pin, INPUT);

  timeClient.begin();
  pixels.begin();
  pixels.clear();

  delayStart = millis();
  delayRunning = false;

  Blynk.virtualWrite(V0, red, green, blue);
  Blynk.virtualWrite(V5, "First Start");
  Blynk.virtualWrite(V8, ALARM_timer / 1000);
  Blynk.virtualWrite(V9, PIR_timer / 1000);
  Blynk.virtualWrite(V11, ALARM_start, 0, 0, ALARM_days_start);
  Blynk.virtualWrite(V12, PIR_start, PIR_stop, 0, PIR_days_start);
  Blynk.virtualWrite(V13, PIR_effect);
  Blynk.virtualWrite(V14, ALARM_effect);
}

void loop()
{
  timer.run();
  Blynk.run();
  timeClient.update();

  currentMillis = millis();
  if ((unsigned long)(currentMillis - previousMillis) >= interval) {
    previousMillis = currentMillis;
  }

  if (ALARM_status) {
    if (ALARM_effect == 1) {
      ZeRGBa();
    }
    else if (ALARM_effect == 2) {
      colorWipe(10, 45, 50, 50);
      colorWipe(0, 0, 0, 50);
    }
    else if (ALARM_effect == 3) {
      CylonBounce(255, 0, 0, 4, 20, 60);
    }
    else if (ALARM_effect == 4) {
      meteorRain(255, 127, 127, 10, 64, true, 30);
    }
  }
  else if (PIR_status && !ALARM_status) {

    if (PIR_effect == 1) {
      ZeRGBa();
    }
    else if (PIR_effect == 2) {
      colorWipe(50, 10, 45, 25);
      colorWipe(0, 0, 0, 25);
    }
    else if (PIR_effect == 3) {
      CylonBounce(255, 0, 0, 4, 20, 60);
    }
    else if (PIR_effect == 4) {
      meteorRain(255, 127, 127, 10, 64, true, 30);
    }
  }
  else {
    clearStrip();
  }
}

void WIFI_check()
{
  if (WiFi.status() != WL_CONNECTED) {
    WiFi.begin((char*)ssid, (char*)pass);
    Serial.println("Lost WiFi Connection, trying to reconnect... ");
    connectionSuccess = 1;
  }
  else if (WiFi.status() == WL_CONNECTED && connectionSuccess == 1) {
    Serial.print("Connected to WiFi: ");
    Serial.println(ssid);
    Serial.print("Local IP address: ");
    Serial.println(WiFi.localIP());
    connectionSuccess = 0;
  }
}

void TIME_check()
{
  now = timeClient.getHours() * 60 * 60 + timeClient.getMinutes() * 60 + timeClient.getSeconds();
  weekday = timeClient.getDay();
  if (timeClient.getDay() == 0) {
    weekday = 7;
  }

}

void PIR_check()
{
  // PIR_start/stop >= 0 tracks, if both Start and Stop have time set in Blynk
  if (PIR_days[weekday] && PIR_start >= 0 && PIR_stop >= 0) {

    // Time between 5:00 and 6:00 f.e.
    if (PIR_stop > PIR_start) {
      finish = PIR_stop;
    }

    // Time between 6:00 and 5:00 f.e.
    else if (PIR_stop < PIR_start) {
      finish = PIR_stop + 24 * 60 * 60;

      // Now is at time on the next day after Start
      // Start = 20:00 | Stop = 4:00 | Now = 2:00
      if (now < PIR_start) {
        now = now + 24 * 60 * 60;
      }
    }

    // Check if Now is between Start and Stop
    if (now >= PIR_start && now < finish) {
      PIR_val = digitalRead(PIR_pin);
      if (PIR_val == HIGH) {
        Blynk.virtualWrite(V5, "Motion deteced");
        PIR_status = true;
        PIR_start_millis = currentMillis;
      }
      else {
        Blynk.virtualWrite(V5, "No Motion");
      }

      if (PIR_status) {
        if ((unsigned long)(currentMillis - PIR_start_millis) >= PIR_timer) {
          PIR_status = false;
        }
      }
    }
    else {
      PIR_status = false;
      clearStrip();
    }
  }
}

void ALARM_check()
{
  if (now == ALARM_start && ALARM_days[weekday] && ALARM_start >= 0) {
    clearStrip(); // Strip turned off if other PIR_effects are running while Alarm is triggered
    ALARM_status = true;
    ALARM_start_millis = currentMillis;
  }

  if (ALARM_status) {
    if ((unsigned long)(currentMillis - ALARM_start_millis) >= ALARM_timer) {
      ALARM_status = false;
    }
  }
}

void showStrip() {
  pixels.show();
}

void clearStrip() {
  pixels.fill(0, 0, NUM_LEDS);
  showStrip();
}

void setPixel(int Pixel, int red, int green, int blue) {
  pixels.setPixelColor(Pixel, pixels.Color(red, blue, green));
}

/********************* LED PIR_effectS *********************/

void ZeRGBa() {
  for (int i = 0; i < NUM_LEDS; i++) {
    setPixel(i, red, green, blue);
    showStrip();
  }
}

void colorWipe(int red, int green, int blue, int SpeedDelay) {
  for (uint16_t i = 0; i < NUM_LEDS; i++) {
    setPixel(i, red, green, blue);
    showStrip();
    delay(SpeedDelay);
  }
}

void CylonBounce(int red, int green, int blue, int EyeSize, int SpeedDelay, int ReturnDelay) {

  for (int i = 0; i < NUM_LEDS - EyeSize - 2; i++) {
    //setAll(0, 0, 0);
    clearStrip();
    setPixel(i, red / 10, green / 10, blue / 10);
    for (int j = 1; j <= EyeSize; j++) {
      setPixel(i + j, red, green, blue);
    }
    setPixel(i + EyeSize + 1, red / 10, green / 10, blue / 10);
    showStrip();
    delay(SpeedDelay);
  }

  delay(ReturnDelay);

  for (int i = NUM_LEDS - EyeSize - 2; i > 0; i--) {
    //setAll(0,0,0);
    clearStrip();
    setPixel(i, red / 10, green / 10, blue / 10);
    for (int j = 1; j <= EyeSize; j++) {
      setPixel(i + j, red, green, blue);
    }
    setPixel(i + EyeSize + 1, red / 10, green / 10, blue / 10);
    showStrip();
    delay(SpeedDelay);
  }

  delay(ReturnDelay);
}

void meteorRain(int red, int green, int blue, int meteorSize, int meteorTrailDecay, boolean meteorRandomDecay, int SpeedDelay) {
  //setAll(0,0,0);
  clearStrip();

  for (int i = 0; i < NUM_LEDS + NUM_LEDS; i++) {

    // fade brightness all LEDs one step
    for (int j = 0; j < NUM_LEDS; j++) {
      if ( (!meteorRandomDecay) || (random(10) > 5) ) {
        fadeToBlack(j, meteorTrailDecay);
      }
    }

    // draw meteor
    for (int j = 0; j < meteorSize; j++) {
      if ( ( i - j < NUM_LEDS) && (i - j >= 0) ) {
        setPixel(i - j, red, green, blue);
      }
    }

    showStrip();
    delay(SpeedDelay);
  }
}

void fadeToBlack(int ledNo, byte fadeValue) {
  uint32_t oldColor;
  uint8_t r, g, b;
  int value;

  oldColor = pixels.getPixelColor(ledNo);
  r = (oldColor & 0x00ff0000UL) >> 16;
  g = (oldColor & 0x0000ff00UL) >> 8;
  b = (oldColor & 0x000000ffUL);

  r = (r <= 10) ? 0 : (int) r - (r * fadeValue / 256);
  g = (g <= 10) ? 0 : (int) g - (g * fadeValue / 256);
  b = (b <= 10) ? 0 : (int) b - (b * fadeValue / 256);

  pixels.setPixelColor(ledNo, r, g, b);
}

/********************* LED PIR_effectS *********************/

BLYNK_WRITE(V0)
{
  red = param[0].asInt();
  green = param[1].asInt();
  blue = param[2].asInt();
}

BLYNK_WRITE(V8)
{
  ALARM_timer = param.asInt() * 1000;
}

BLYNK_WRITE(V9)
{
  PIR_timer = param.asInt() * 1000;
}

BLYNK_WRITE(V11)
{
  TimeInputParam t(param);
  if (t.hasStartTime()) {
    ALARM_start = t.getStartHour() * 60 * 60 + t.getStartMinute() * 60 + t.getStartSecond();
  }
  else {
    ALARM_start = -1;
  }
  for (int i = 1; i <= 7; i++) {
    ALARM_days[i] = t.isWeekdaySelected(i);
  }
}

BLYNK_WRITE(V12)
{
  TimeInputParam t(param);
  if (t.hasStartTime()) {
    PIR_start = t.getStartHour() * 60 * 60 + t.getStartMinute() * 60 + t.getStartSecond();
  }
  else {
    PIR_start = -1;
  }
  if (t.hasStopTime()) {
    PIR_stop = t.getStopHour() * 60 * 60 + t.getStopMinute() * 60 + t.getStopSecond();
  }
  else {
    PIR_stop = -1;
  }
  for (int i = 1; i <= 7; i++) {
    PIR_days[i] = t.isWeekdaySelected(i);
  }
}

BLYNK_WRITE(V13)
{
  switch (param.asInt()) {
    case 1: {
        //ZeRGBa
        PIR_effect = 1;
        break;
      }
    case 2: {
        //colorWipe
        PIR_effect = 2;
        break;
      }
    case 3: {
        //Cylon
        PIR_effect = 3;
        break;
      }
    case 4: {
        //Meteor
        PIR_effect = 4;
        break;
      }
  }
}

BLYNK_WRITE(V14)
{
  switch (param.asInt()) {
    case 1: {
        //ZeRGBa
        ALARM_effect = 1;
        break;
      }
    case 2: {
        //colorWipe
        ALARM_effect = 2;
        break;
      }
    case 3: {
        //Cylon
        ALARM_effect = 3;
        break;
      }
    case 4: {
        //Meteor
        ALARM_effect = 4;
        break;
      }
  }
}

That’s what happens if you don’t have a clean void loop, you’ve been told about this at least twice in this thread.

Pete.

Mhhh I thought my void loop () is a lot more clean than before.
Just the effect section. Mhhh thought that is a must have in void loop for proper function and fast reaction after PIR or Alarm is true.

So I will try again this night :slight_smile:

Sry that I’m doing stupid stuff. I’m realy new to this kind of coding (have done it in school 18 years before last time… turbo pascal hrhrhr).

Think about what your code is doing…

Every 500ms you’re calculating whether or not the PIR is in it’s time activation window. This doesn’t not need to be done this often does it? The time activation window check doesn’t need to be done more than once every minute, and could set a flag (pirActive) and all you have to do when you’re checking the PIR is to determine if pirActive is true and the PIR pin has gone HIGH.

The same applies to your ALARM_check function.

You also have a function that checks the time, that’s running every 200ms. Why?

The place to start and stop LED PIR effects based on the state of the PIR is in the function that checks the PIR, not in the void loop.

You need to rethink your program flow and stop doing unnecessary calculations and checks so frequently.

Pete.

Hey PeteKnight,

first night went fine with your suggestions :slight_smile:
Realy much thank you!

That’s what my loop is looking right now:

 void loop()
{
  timer.run();
  Blynk.run();

  currentMillis = millis();
  if ((unsigned long)(currentMillis - previousMillis) >= interval) {
    previousMillis = currentMillis;
  }

}

and here the timers I set in setup:

  timer.setInterval(60 * 1000L, WIFI_check);
  timer.setInterval(60 * 1000L, TIME_check);
  timer.setInterval(1 * 1000L, PIR_check);
  ALARM_running = timer.setInterval(10 * 1000L, ALARM_check);

as you can see I set a global var for the Alarm timer because I now have to change the intervall after Alarm is triggered (every 10 Seconds is too slow for most LED effects). I have to do the same on PIR.

While the check if alarm and PIR should even be possible to be run is inside my time_check function now, I’m asking if it is possible to even stop the timer of ALARM_check and PIR_check to be ever run unless the time_check set a new interval.

I can’t find anything about if a timer.deleteTimer(ALARM_running); will be fine or if I have to set the intervall after this to something over 1 million seconds :slight_smile:

EDIT: Think I found the solution with timer.disable and timer.enable :slight_smile:

1 Like

Now that you’ve figured-out how to enable and disable timers then the millis() stuff in your void loop should be redundant.

As you’ve realised, you reference the timers in the order in which they are created, with the ID of first one being zero. This makes it a bit messy, especially if you start creating and deleting additional timers, because you’re guessing at what the ID is.
It’s actually possible to give those timer ID’s variable names like this:

  WIFI_check_timer_ID = timer.setInterval(60 * 1000L, WIFI_check);

You’d need to declare WIFI_check_timer_ID as a global integer variable of course.

Pete.

1 Like

mhhh the thing with the millis calculation is still needed in my opinion for the simple task of running a LED effect eg. 10 sec.
Sure I could add an additional timer for this as well and enable and disable it if needed… mhhhh have to thing about it this evening.

Just for my understanding: If I just declare the timer interval in the void setup() and I never need an other interval than just enabling and disabling it. I don’t have to to the stuff with the delete timers and set new ones.

Mhhh I just gave the ALARM and PIR an ID for the timer right now.

Now I have that problem, that my PIR timer will be enabled if the timer_check function detects that it is time to turn on PIR detection. But the PIR seems only to randomly work now. The Alarm is working as intended.

Are you using the previousMillis variable elsewhere? Like for your LED’s?

If not then it isn’t needed.

Edit: Do you want to post your full code again, auth token removed :wink:

Sure.

#define BLYNK_PRINT Serial

#include <Adafruit_NeoPixel.h>
#include <BlynkSimpleEsp8266.h>
#include <ESP8266WiFi.h>
#include <NTPClient.h>
#include <SPI.h>
#include <SimpleTimer.h>
#include <WiFiUdp.h>

// LED Stuff
#define PIN D5
#define NUM_LEDS 37
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUM_LEDS, PIN, NEO_GRB + NEO_KHZ400);
void showStrip();
void clearStrip();
void setPixel(int, int, int, int);
void fadeToBlack(int, byte);
void ZeRGBa();
void colorWipe(int, int, int, int);
void CylonBounce(int, int, int, int, int, int);
void meteorRain(int, int, int, int, int, boolean, int);
void Strobe(int, int, int, int, int, int);

// normal Void Declaration
void WIFI_check();
void TIME_check();
void PIR_time_check();
void PIR_check();
void ALARM_time_check();
void ALARM_check();
void WDAY_and_NOW();

// WiFi Stuff
char auth[] = "******************";
char ssid[] = "******************";
char pass[] = "******************";
char serv[] = "******************";

// Variables
int interval = 1000;
unsigned long previousMillis = 0;
unsigned long currentMillis = 0;

int red = 1;
int green = 0;
int blue = 2;

int connectionSuccess = 0;

// Motion Sensor Variables
int PIR_pin = D3;
int PIR_val;
int PIR_start = 79200;
int PIR_stop = 21600;
int PIR_timer = 10 * 1000;
int PIR_running;
int PIR_effect = 1;
char PIR_days_start[] = "1,2,3,4,5,6,7";
bool PIR_days[] = {true, true, true, true, true, true, true};
bool PIR_status = false;
bool PIR_active = false;
unsigned long PIR_start_millis = 0;

int now;
int finish;
int weekday;

// Alarm Variables
int ALARM_start = 21600;
int ALARM_timer = 60 * 1000;
int ALARM_running;
int ALARM_effect = 4;
char ALARM_days_start[] = "1,2,3,4,5";
bool ALARM_days[] = {true, true, true, true, true, false, false};
bool ALARM_status = false;
unsigned long ALARM_start_millis = 0;

const long utcOffsetInSeconds = 2 * 60 * 60;

unsigned long delayStart = 0;
bool delayRunning = false;
bool debug = false;                                          // debug Serial.print messages

WiFiUDP ntpUDP;
NTPClient timeClient(ntpUDP, "10.0.4.1", utcOffsetInSeconds);
unsigned long TIME_sync_millis = 0;
int TIME_sync_timer = 60;

SimpleTimer timer;

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

  unsigned long started = millis();
  Serial.println();
  WiFi.begin(ssid, pass); //Blynk.begin(auth, ssid, pass, serv, 8080);
  Serial.println(String("Connecting to ") + ssid + " ...");
  while (WiFi.status() != WL_CONNECTED) {
    if (millis() - started < 20 * 1000) {
      yield();
    }
  }
  if (WiFi.status() == WL_CONNECTED) {
    Serial.println("WiFi connected");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
    Serial.println("Wifi works, now try Blynk connection");
    delay(2 * 1000);
    Blynk.config(auth, serv, 8080);
    Blynk.connect(30 * 1000);
    if (Blynk.connected() == true) {
      delay(2000);
      Blynk.run();
      Serial.println("Blynk is online");
    }
  }

  timeClient.begin();

  timer.setInterval(60 * 1000L, WIFI_check);
  timer.setInterval(60 * 1000L, TIME_check);
  ALARM_running = timer.setInterval(1 * 1000L, ALARM_check);
  PIR_running = timer.setInterval(1 * 1000L, PIR_check);

  pinMode(PIR_pin, INPUT);

  timeClient.begin();
  pixels.begin();
  pixels.clear();

  delayStart = millis();
  delayRunning = false;

  Blynk.virtualWrite(V0, red);
  Blynk.virtualWrite(V1, green);
  Blynk.virtualWrite(V2, blue);
  Blynk.virtualWrite(V5, "First Start");
  Blynk.virtualWrite(V8, ALARM_timer / 1000);
  Blynk.virtualWrite(V9, PIR_timer / 1000);
  Blynk.virtualWrite(V11, ALARM_start, 0, 0, ALARM_days_start);
  Blynk.virtualWrite(V12, PIR_start, PIR_stop, 0, PIR_days_start);
  Blynk.virtualWrite(V13, PIR_effect);
  Blynk.virtualWrite(V14, ALARM_effect);
  Blynk.virtualWrite(V20, TIME_sync_timer);
  if (debug) {
    Blynk.virtualWrite(V21, 1);
  }
  else {
    Blynk.virtualWrite(V21, 2);
  }
  timeClient.update();
  timer.disable(ALARM_running);
  timer.disable(PIR_running);

  if (debug) {
    if (timer.isEnabled(ALARM_running)) {
      Blynk.virtualWrite(V22, "ALARM is running");
    }
    else {
      Blynk.virtualWrite(V22, "ALARM is stoped");
    }
    if (timer.isEnabled(PIR_running)) {
      Blynk.virtualWrite(V23, "PIR is running");
    }
    else {
      Blynk.virtualWrite(V23, "PIR is stoped");
    }
  }
}

void loop()
{
  timer.run();
  Blynk.run();

  currentMillis = millis();
  if ((unsigned long)(currentMillis - previousMillis) >= interval) {
    previousMillis = currentMillis;
  }

}

void WIFI_check()
{
  if (WiFi.status() != WL_CONNECTED) {
    WiFi.begin(ssid, pass);
    Serial.println("Lost WiFi Connection, trying to reconnect... ");
    connectionSuccess = 1;
  }
  else if (WiFi.status() == WL_CONNECTED && connectionSuccess == 1) {
    Serial.println("WiFi connected");
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
    Serial.println("Wifi works, now try Blynk connection");
    delay(2 * 1000);
    Blynk.config(auth, serv, 8080);
    Blynk.connect(30 * 1000);
    if (Blynk.connected() == true) {
      delay(2000);
      Blynk.run();
      Serial.println("Blynk is online");
    }
    connectionSuccess = 0;
  }
}

void TIME_check()
{
  if ((unsigned long)(currentMillis - TIME_sync_millis) >= TIME_sync_timer * 60 * 1000) {
    if (debug) {
      Serial.println("Syncing NTP time");
    }
    TIME_sync_millis = currentMillis;
    timeClient.update();
  }

  WDAY_and_NOW();
  ALARM_time_check();
  PIR_time_check();

  if (debug) {
    if (timer.isEnabled(ALARM_running)) {
      Blynk.virtualWrite(V22, "ALARM running again");
    }
    else {
      Blynk.virtualWrite(V22, "ALARM is stoped");
    }
    if (timer.isEnabled(PIR_running)) {
      Blynk.virtualWrite(V23, "PIR running again");
    }
    else {
      Blynk.virtualWrite(V23, "PIR is stoped");
    }
  }
}

void WDAY_and_NOW()
{
  weekday = timeClient.getDay();
  if (debug) {
    Serial.println(String("Zeit: ") + timeClient.getHours() + ":" + timeClient.getMinutes());
  }
  if (timeClient.getDay() == 0) {
    weekday = 7;
  }

  now = timeClient.getHours() * 60 * 60 + timeClient.getMinutes() * 60;
}

void ALARM_time_check()
{
  /*****************************************************
    ALARM Time Check START
  *****************************************************/
  if (now == ALARM_start && ALARM_days[weekday] && ALARM_start >= 0) {
    clearStrip(); // Strip turned off if other PIR_effects are running while Alarm is triggered
    ALARM_status = true;
    ALARM_start_millis = currentMillis;
    timer.enable(ALARM_running);
    if (debug) {
      Serial.println(String("ALARM Effect started at: ") + timeClient.getHours() + ":" + timeClient.getMinutes());
    }
  }
  /*****************************************************
    ALARM Time Check END
  *****************************************************/
}

void PIR_time_check()
{
  /*****************************************************
    PIR Time Check START
  *****************************************************/
  if (PIR_days[weekday] && PIR_start >= 0 && PIR_stop >= 0) {

    // Time between 5:00 and 6:00 f.e.
    if (PIR_start < PIR_stop) {
      finish = PIR_stop;
    }

    // Time between 6:00 and 5:00 f.e.
    else if (PIR_start > PIR_stop) {
      finish = PIR_stop + 24 * 60 * 60;

      // Now is at time on the next day after Start
      // Start = 20:00 | Stop = 4:00 | Now = 2:00
      if (now < PIR_start) {
        now = now + 24 * 60 * 60;
      }
    }
  }

  // Check if Now is between Start and Stop
  if (now >= PIR_start && now < finish && !ALARM_status) {
    //PIR_status = true;
    timer.enable(PIR_running);
    if (debug) {
      Serial.println("PIR Detection IS Active");
    }
  }
  else {
    //PIR_status = false;
    timer.disable(PIR_running);
    if (debug) {
      Serial.println("PIR Detection NOT Active");
    }
  }
  /*****************************************************
    PIR Time Check END
  *****************************************************/
}

void ALARM_check()
{
  if (debug) {
    Serial.println(String("ALARM was running at: ") + timeClient.getHours() + ":" + timeClient.getMinutes() + ":" + timeClient.getSeconds());
  }

  if (ALARM_status) {
    if ((unsigned long)(currentMillis - ALARM_start_millis) >= ALARM_timer) {
      ALARM_status = false;
      clearStrip();
      timer.disable(ALARM_running);
      if (debug) {
        Serial.println(String("ALARM Effect ended at: ") + timeClient.getHours() + ":" + timeClient.getMinutes());
      }
    }
    else {
      if (ALARM_effect == 1) {
        ZeRGBa();
      }
      else if (ALARM_effect == 2) {
        colorWipe(10, 45, 50, 50);
        colorWipe(0, 0, 0, 50);
      }
      else if (ALARM_effect == 3) {
        CylonBounce(255, 0, 0, 4, 20, 60);
      }
      else if (ALARM_effect == 4) {
        meteorRain(255, 127, 127, 10, 64, true, 30);
      }
      else if (ALARM_effect == 5) {
        // Slower:
        // Strobe(0xff, 0x77, 0x00, 10, 100, 1000);
        Strobe(255, 0, 255, 10, 50, 1000);
      }
    }
  }
}

void PIR_check()
{
  if (debug) {
    Serial.println(String("PIR was running at: ") + timeClient.getHours() + ":" + timeClient.getMinutes() + ":" + timeClient.getSeconds());
  }
  //if (PIR_status) {
    PIR_val = digitalRead(PIR_pin);
    if (PIR_val == HIGH) {
      Blynk.virtualWrite(V5, "Motion detected");
      PIR_active = true;
      PIR_start_millis = currentMillis;
      if (debug) {
        Serial.println(String("PIR Effect started at: ") + timeClient.getHours() + ":" + timeClient.getMinutes());
      }
    }
    else {
      Blynk.virtualWrite(V5, "no Motion");
    }
    if (PIR_active) {
      if ((unsigned long)(currentMillis - PIR_start_millis) >= PIR_timer) {
        PIR_active = false;
        clearStrip();
        timer.disable(PIR_running);
        //timer.deleteTimer(PIR_running);
        //PIR_running = timer.setInterval(10 * 1000L, PIR_check);
        if (debug) {
          Serial.println(String("PIR Effect ended at: ") + timeClient.getHours() + ":" + timeClient.getMinutes());
        }
      }
      else {
        if (PIR_effect == 1) {
          ZeRGBa();
        }
        else if (PIR_effect == 2) {
          colorWipe(50, 10, 45, 25);
          colorWipe(0, 0, 0, 25);
        }
        else if (PIR_effect == 3) {
          CylonBounce(255, 0, 0, 4, 20, 60);
        }
        else if (PIR_effect == 4) {
          meteorRain(255, 127, 127, 10, 64, true, 30);
        }
        else if (PIR_effect == 5) {
          // Slower:
          // Strobe(0xff, 0x77, 0x00, 10, 100, 1000);
          Strobe(255, 0, 255, 10, 50, 1000);
        }
      }
    }
  //}
}

void showStrip() {
  pixels.show();
}

void clearStrip() {
  pixels.fill(0, 0, NUM_LEDS);
  showStrip();
}

void setPixel(int Pixel, int red, int green, int blue) {
  pixels.setPixelColor(Pixel, pixels.Color(red, blue, green));
}

/********************* LED PIR_effectS *********************/

void ZeRGBa() {
  for (int i = 0; i < NUM_LEDS; i++) {
    setPixel(i, red, green, blue);
    showStrip();
  }
}

void colorWipe(int red, int green, int blue, int SpeedDelay) {
  for (uint16_t i = 0; i < NUM_LEDS; i++) {
    setPixel(i, red, green, blue);
    showStrip();
    delay(SpeedDelay);
  }
}

void CylonBounce(int red, int green, int blue, int EyeSize, int SpeedDelay, int ReturnDelay) {

  for (int i = 0; i < NUM_LEDS - EyeSize - 2; i++) {
    //setAll(0, 0, 0);
    clearStrip();
    setPixel(i, red / 10, green / 10, blue / 10);
    for (int j = 1; j <= EyeSize; j++) {
      setPixel(i + j, red, green, blue);
    }
    setPixel(i + EyeSize + 1, red / 10, green / 10, blue / 10);
    showStrip();
    delay(SpeedDelay);
  }

  delay(ReturnDelay);

  for (int i = NUM_LEDS - EyeSize - 2; i > 0; i--) {
    //setAll(0,0,0);
    clearStrip();
    setPixel(i, red / 10, green / 10, blue / 10);
    for (int j = 1; j <= EyeSize; j++) {
      setPixel(i + j, red, green, blue);
    }
    setPixel(i + EyeSize + 1, red / 10, green / 10, blue / 10);
    showStrip();
    delay(SpeedDelay);
  }

  delay(ReturnDelay);
}

void meteorRain(int red, int green, int blue, int meteorSize, int meteorTrailDecay, boolean meteorRandomDecay, int SpeedDelay) {
  //setAll(0,0,0);
  clearStrip();

  for (int i = 0; i < NUM_LEDS + NUM_LEDS; i++) {

    // fade brightness all LEDs one step
    for (int j = 0; j < NUM_LEDS; j++) {
      if ( (!meteorRandomDecay) || (random(10) > 5) ) {
        fadeToBlack(j, meteorTrailDecay);
      }
    }

    // draw meteor
    for (int j = 0; j < meteorSize; j++) {
      if ( ( i - j < NUM_LEDS) && (i - j >= 0) ) {
        setPixel(i - j, red, green, blue);
      }
    }

    showStrip();
    delay(SpeedDelay);
  }
}

void fadeToBlack(int ledNo, byte fadeValue) {
  uint32_t oldColor;
  uint8_t r, g, b;

  oldColor = pixels.getPixelColor(ledNo);
  r = (oldColor & 0x00ff0000UL) >> 16;
  g = (oldColor & 0x0000ff00UL) >> 8;
  b = (oldColor & 0x000000ffUL);

  r = (r <= 10) ? 0 : (int) r - (r * fadeValue / 256);
  g = (g <= 10) ? 0 : (int) g - (g * fadeValue / 256);
  b = (b <= 10) ? 0 : (int) b - (b * fadeValue / 256);

  pixels.setPixelColor(ledNo, r, g, b);
}

void Strobe(int red, int green, int blue, int StrobeCount, int FlashDelay, int EndPause) {
  for(int j = 0; j < StrobeCount; j++) {
    for (int i = 0; i < NUM_LEDS; i++) {
      setPixel(i, red, green, blue);
      showStrip();
    }
    showStrip();
    delay(FlashDelay);
    clearStrip();
    delay(FlashDelay);
  }

 delay(EndPause);
}

/********************* LED PIR_effectS *********************/

BLYNK_WRITE(V0)
{
  red = param.asInt();
}

BLYNK_WRITE(V1)
{
  green = param.asInt();
}

BLYNK_WRITE(V2)
{
  blue = param.asInt();
}

BLYNK_WRITE(V8)
{
  ALARM_timer = param.asInt() * 1000;
}

BLYNK_WRITE(V9)
{
  PIR_timer = param.asInt() * 1000;
}

BLYNK_WRITE(V11)
{
  TimeInputParam t(param);
  if (t.hasStartTime()) {
    ALARM_start = t.getStartHour() * 60 * 60 + t.getStartMinute() * 60 + t.getStartSecond();
  }
  else {
    ALARM_start = -1;
  }
  for (int i = 1; i <= 7; i++) {
    ALARM_days[i] = t.isWeekdaySelected(i);
  }
}

BLYNK_WRITE(V12)
{
  TimeInputParam t(param);
  if (t.hasStartTime()) {
    PIR_start = t.getStartHour() * 60 * 60 + t.getStartMinute() * 60 + t.getStartSecond();
  }
  else {
    PIR_start = -1;
  }
  if (t.hasStopTime()) {
    PIR_stop = t.getStopHour() * 60 * 60 + t.getStopMinute() * 60 + t.getStopSecond();
  }
  else {
    PIR_stop = -1;
  }
  for (int i = 1; i <= 7; i++) {
    PIR_days[i] = t.isWeekdaySelected(i);
  }
  WDAY_and_NOW();
  PIR_time_check();
}

BLYNK_WRITE(V13)
{
  switch (param.asInt()) {
    case 1: {
      //ZeRGBa
      PIR_effect = 1;
      break;
    }
    case 2: {
      //colorWipe
      PIR_effect = 2;
      break;
    }
    case 3: {
      //Cylon
      PIR_effect = 3;
      break;
    }
    case 4: {
      //Meteor
      PIR_effect = 4;
      break;
    }
    case 5: {
      //Strobe
      PIR_effect = 5;
      break;
    }
  }
}

BLYNK_WRITE(V14)
{
  switch (param.asInt()) {
    case 1: {
      //ZeRGBa
      ALARM_effect = 1;
      break;
    }
    case 2: {
      //colorWipe
      ALARM_effect = 2;
      break;
    }
    case 3: {
      //Cylon
      ALARM_effect = 3;
      break;
    }
    case 4: {
      //Meteor
      ALARM_effect = 4;
      break;
    }
    case 5: {
      //Strobe
      ALARM_effect = 5;
      break;
    }
  }
}

BLYNK_WRITE(V20)
{
  TIME_sync_timer = param.asInt();
  if (debug) {
    Serial.println(String("Time Synchronisation every: ") + TIME_sync_timer + "Minutes");
  }
}

BLYNK_WRITE(V21)
{
  int debug_switch = param.asInt();
  if (debug_switch == 1) {
    debug = true;
  }
  else {
    debug = false;
  }
}

Yes, after looking at your code, as my last post states and as @PeteKnight said, this check is not doing anything:

if ((unsigned long)(currentMillis - previousMillis) >= interval) {
    previousMillis = currentMillis;
}

Also you are using delay() in your LED sequences which as a one off is sometimes OK but when doing this inside FOR loops, the delays add up and interfere with Blynk.run() - (I know - been there, done that)

#define NUM_LEDS 37
---
colorWipe(10, 45, 50, 50);
---
void colorWipe(int red, int green, int blue, int SpeedDelay) {
  for (uint16_t i = 0; i < NUM_LEDS; i++) {
    setPixel(i, red, green, blue);
    showStrip();
    delay(SpeedDelay);
  }
}

So here for example, you will have a delay of: 50 * 37 = 1,850 millis / 2s

1 Like

Your code is still far too complicated and you’re not doing yourself any favours in the long term with your choice of variable names.

When you come back to this code in future, you’re going to think that ALARM_running is a flag to tell you whether or not the alarm is running, when actually it’s the timer ID for the ALARM_check timer. Why not do what I suggested and call it something like ALARM_check_timer_ID?

Also, I see that you’re using simpletimer rather than Blynktimer. There is a bug in simpletimer which affects the timer with ID=0. You can create a dummy sacrificial timer with ID 0, or use Blynktimer which doesn’t have this bug, and has a few nice extra features built-in.

When I started programming (it was a while ago!), we wrote our program out on paper first, the tested it on paper before queuing to use the computer terminal and keying the program in and compiling it. One thing I learned from that was do do a block diagram of the main processes when you’re first designing your code structure.
If you did this with your code you’d realise that you should have a process which checks if it’s one of the days/times when the alarm should be on and the PIR should be active. You’d only need to do this check once per minute at most, as minutes are your maximum granularity for your time input widgets, and you’d then test two flags to indicate if the alarm and PIR are active. You would do this OUTSIDE of the PIR detection process, in a single function which runs every 1 minute.
You would then use these flags in one of two ways:
a) don’t check the PIR outside of it’s active hours (disable it’s timer) or
b) continue to check the PIR at all times, but also check the flag to see if you need to do anything with the fact that the PIR has triggered.

I tried to explain this approach earlier, but you haven’t adopted it in your current code, and it makes your code much more complex to follow (and more likely to have bugs as a result, and more likely to result in Blynk disconnections because of the unnecessary processing).

Pete.

2 Likes

Thanks to both of you again :slight_smile:

Will try adopt as much as I can from your suggestions. This evening I didn‘t had time for Coding, so I will Report back tomorrow.

Blynk Disconnects seams to be gone!

Pete, I will try to Go with Option a)

So the PIR Check Must be inside an own void with its own timer. I mean That Check of the PIR oh Motion is detected or Not. What is the Minimum time you would recommend for this timer? 1 Minute is far too long.

The millis thing will be done tomorrow as well :slight_smile:

Personally, I’d attach a software interrupt to the pin that the PIR is connected to. That way you don’t need to check the status of the pin, it will automatically trigger a function when it goes HIGH (assuming that’s how you configure the interrupt). You’d probably need some debounce code on the interrupt, as you might not get a 100% clean on/off signal, but that’s not difficult to do.

Pete.

1 Like

Ok, I’m back from work now and will try my best. Pls be a bit patient with me… have to translate everything into german to understand it right and maybe because of that and because I’m a noob I will make new faults.

But this kind of forum makes it realy helpfull in learning this stuff!

First I will try to remove all “millis()” and implement Blynk.timer. If that is running as intended I will try to adopt everything else. Today arrived 3 more ESP8266, my living rooms LEDs are coming :smiley:
10 more from china are on their way (unfurtunately I destroyed 3 of them in the early phase of building everything together).

Hopefully you’re not driving LED strips directly from the ESPs.

Pete.

1 Like

Nope :slight_smile:

That was because I missplace by one pin the ESP on the socket… stupid I know… the other 2… I can’t remember :slight_smile:

I’ve got a 12V powersupply with 12v LEDs and the Wemos D1 Mini. Between the power supply and the wemos and of course the PIR is step down converter to 5v. But that is working realy good right now.

Pete one question… don’t know if I understand the TimerID right => an ID is a Number for myself. But in every example sketch I found to this topic just says “TimerID” as you did. So am I wrong if i change my timers in this way?

  WIFI_0 = timer.setInterval(60 * 1000L, WIFI_check);
  TIME_1 = timer.setInterval(60 * 1000L, TIME_check);
  ALARM_2 = timer.setInterval(1 * 1000L, ALARM_check);
  PIR_3 = timer.setInterval(0.5 * 1000L, PIR_check);

or do you mean

  WIFI_timerId = timer.setInterval(60 * 1000L, WIFI_check);
  TIME_timerId = timer.setInterval(60 * 1000L, TIME_check);
  ALARM_timerId = timer.setInterval(1 * 1000L, ALARM_check);
  PIR_timerId = timer.setInterval(0.5 * 1000L, PIR_check);

I don’t really understand your question.
When you create a new timer, it’s automatically assigned an ID by the simpletimer/Blynktimer library.
The first timer you create is given the ID of 0, the second is 1, the third is 2 etc.

However, it gets messy when you start deleting timers, as that free-up up a slot which is allocated to the next one you create. It is also a bit messy when you’re referring to timer number 3 in your code and it’s no clear (unless to go and check back to where your timers were created) what this timer does.

If you’re using multiple timers and enabling/disabling them, and deleting/creating others then it’s much better to give those ID’s a reference that you can work with.

int WIFI_check_timer_ID; // Declare a global variable to reference the timer that checks the Wi-Fi connection

WIFI_check_timer_ID = timer.setInterval(60 * 1000L, WIFI_check); // Crearte the timer and store it's ID in the variable WIFI_check_timer_ID

Serial.print("WIFI_check_timer_ID = ");
Serial.Println (WIFI_check_timer_ID);

The result in the serial monitor will be:

WIFI_check_timer_ID = 0

You can then do:

timer.disable(WIFI_check_timer_ID);

which is neater, less confusing and more transparent than:

timer.disable(0);

Does this help?

Pete.

1 Like

Yeah now I understand, but this was the way I did it before anybody of you told me something about this :smiley:
but first I only did it for the PIR for testing… just some sketches posts above from me. but yeah, now it is clear for me.

A friend told me, that the blynktimer could possibly be related to the connection to the blynk server. If that is not up the timer may not work? Is that true? If so I have to roll back to “millis()” to be a bit more independent. Yeah I’m hosting the server in my local network by myself, but I want to have a clear and everytime running solution.

Blynktimer is basically simpletimer with some bug fixes and improvements.

It’s built in to the Blynk library so doesn’t have to be declared, and it isn’t dependent on a connection to the Blynk server. Use Blynktimer.

Pete.

1 Like