[SOLVED] Run Function Once Per Time Period

Hi @harrisonhjones,

Sure!

The program is time based and calls a function which updates a variable (the current time), it does so using a for loop. The incremental value is used to update the variable, however, while it is still within this function you can check the previous value to the new one. If the value has not changed then you can set a boolean variable to false, while if the value is different to true. Thus, giving you a time-dependant function that will only run once per time period.

Loop:

void loop() {
period = updatePeriod();
}

Function:

int updatePeriod() {
    int minSinceMidnight = (Time.local() % 86400) / 60;  // only take the time and drop the date and the drop seconds too
    for (int i=0;i<6;i++) {
      if ( periodStart[day][i] <= minSinceMidnight && minSinceMidnight < periodEnd[day][i] ) {
        if ( period != 0 && i != period ) {periodNotified = false;} else {periodNotified = true;}
        return i;
      }
    }
}

The added period != 0, is only neccesary as period = 0 is initially defined as a global to prevent a false notification while the time has not yet been synced - which occurs during the setup.

Full Source Code:

/* ======================= PRODUCT SETUP ======================= */

bool DEBUG_MODE = true;

/* ======================= LIBRARY IMPORTS ====================== */

#include "application.h"

/* ======================= CONSTANTS ====================== */

/* DEFINE VARIABLES */
String formattedTime;
int day;
String formattedDay;
int period = 0;
int previousPeriod;
int movementVal = 0;
int calibrateTime = 10000;
int pirState = LOW;
bool periodNotified = false;
bool periodStateChange = false;
bool periodChange = false;

/* DEFINE PINOUTS */
int pir = D2;

/* ROOM ALLOCATION ARRAYS */

// FORMAT: [WEEKDAY][PERIOD]
 int reservation[5][6] = {
   {1, 1, 0, 1, 1, 1} ,   /*  initializers for row indexed by 0 | MONDAY */
   {1, 0, 1, 1, 0, 1} ,   /*  initializers for row indexed by 1 | TUESDAY */
   {1, 1, 0, 1, 1, 0} ,   /*  initializers for row indexed by 3 | WEDNESDAY */
   {1, 0, 1, 0, 1, 1} ,   /*  initializers for row indexed by 4 | THURSDAY*/
   {0, 1, 1, 1, 1, 1}     /*  initializers for row indexed by 5 | FRIDAY */
};

char * reserver[5][6] = {
   {"J Collins", "F Tumi", "NULL", "J Collins", "J Collins", "J Collins"} ,   /*  initializers for row indexed by 0 | MONDAY */
   {"J Collins", "NULL", "J Collins", "J Collins", "NULL" "H Jones"} ,   /*  initializers for row indexed by 1 | TUESDAY */
   {"N Bulless", "J Collins", "NULL", "J Collins", "J Collins", "NULL"} ,   /*  initializers for row indexed by 3 | WEDNESDAY */
   {"J Collins", "NULL", "J Collins", "NULL", "J Collins", "J Collins"} ,   /*  initializers for row indexed by 4 | THURSDAY*/
   {"NULL", "J Collins", "J Collins", "L Hewett", "J Collins", "J Collins"}     /*  initializers for row indexed by 5 | FRIDAY */
};

int periodStartHr[5][6] = {
   {9, 10, 11, 12, 13, 14} ,   /*  initializers for row indexed by 0 | MONDAY */
   {9, 10, 11, 12, 13, 14} ,   /*  initializers for row indexed by 1 | TUESDAY */
   {8, 9, 10, 11, 13, 14} ,   /*  initializers for row indexed by 3 | WEDNESDAY */
   {9, 10, 11, 12, 13, 14} ,   /*  initializers for row indexed by 4 | THURSDAY*/
   {9, 10, 11, 12, 13, 14}     /*  initializers for row indexed by 5 | FRIDAY */
};

int periodStartMin[5][6] = {
  {5, 0, 10, 5, 40, 35} ,   /*  initializers for row indexed by 0 | MONDAY */
  {5, 0, 10, 5, 40, 35} ,   /*  initializers for row indexed by 1 | TUESDAY */
  {50, 45, 55, 50, 20, 35} ,   /*  initializers for row indexed by 3 | WEDNESDAY */
  {5, 0, 10, 5, 40, 35} ,   /*  initializers for row indexed by 4 | THURSDAY */
  {5, 0, 10, 5, 40, 35}     /*  initializers for row indexed by 5 | FRIDAY */
};

int periodEndHr[5][6] = {
   {10, 10, 12, 13, 14, 15} ,   /*  initializers for row indexed by 0 | MONDAY */
   {10, 10, 12, 13, 14, 15} ,   /*  initializers for row indexed by 1 | TUESDAY */
   {9, 10, 11, 12, 14, 15} ,   /*  initializers for row indexed by 3 | WEDNESDAY */
   {10, 10, 12, 13, 14, 15} ,   /*  initializers for row indexed by 4 | THURSDAY*/
   {10, 10, 12, 13, 14, 15}     /*  initializers for row indexed by 5 | FRIDAY */
};

int periodEndMin[5][6] = {
   {0, 55, 5, 0, 35, 30} ,   /*  initializers for row indexed by 0 | MONDAY */
   {0, 55, 5, 0, 35, 30} ,   /*  initializers for row indexed by 1 | TUESDAY */
   {45, 40, 50, 45, 15, 30} ,   /*  initializers for row indexed by 3 | WEDNESDAY */
   {0, 55, 5, 0, 35, 30} ,   /*  initializers for row indexed by 4 | THURSDAY*/
   {0, 55, 5, 0, 35, 30}     /*  initializers for row indexed by 5 | FRIDAY */
};

int periodStart[5][6];
int periodEnd[5][6];

/* ======================= SYSTEM SETUP ====================== */

STARTUP(
  WiFi.selectAntenna(ANT_AUTO);
  System.enableUpdates();
  );
SYSTEM_MODE(MANUAL);
SYSTEM_THREAD(ENABLED);

/* ======================= SETUP CODE (RUN ONCE) ====================== */

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

  pinMode(pir, INPUT);

  WiFi.connect(WIFI_CONNECT_SKIP_LISTEN);
  int DBG = 0;
  while (!WiFi.ready()) {
    if (DBG == 0) {Serial.println("Wi-Fi Antenna Not Ready."); DBG = 1;}
    } while (WiFi.ready()) {
    Serial.println("Wi-Fi Antenna Ready. v2");
    Serial.println("W-Fi Connecting.");
    Particle.connect();
    while (!Particle.connected()) {
    } while (Particle.connected()) {
        Serial.println("W-Fi Connected.");
        Particle.syncTime();
        setPeriodTimes();
        delay(2000);
        updateTime();
        Serial.println(formattedTime);
        Serial.println(formattedDay);
        Serial.println(period);
        notify("boot", "IoT Sensor now online.");
        Serial.println("Setup Complete.");
    break;
    }
    break;
  }
  //setPeriodTimes();
}

/* ======================= MAIN CODE (RUN REPEATEDLY) ====================== */

void loop() {
  updateTime();
  if (Particle.connected()) {Particle.process();};
  while (Particle.connected()) {
    delay(2000);
    updateTime();
    checkMode();
    updateMotion();

    Serial.println(formattedTime);
    Serial.println(formattedDay);
    Serial.println(period);

    delay(10000);

    //if (periodChange = true) { periodNotified = false; } else { periodNotified = true; }

    //if ( i != period ) {periodChange = true;} else {periodChange = false;}

    if (reservation[day][period] == 0) {
      if (pirState == HIGH) {
        //IF NO RESERVATION AND MOVEMENT --> OFFER BOOKING (After timeout, +PUBLISH OPP)
        // SECOND DEVELOPMENT CYCLE TO ALLOW BOOKING
        notify("vacant", "G16 is currently not booked, but movement has been detected.");
      } else {
        //IF NO RESERVATION AND NO BOOKING --> PUBLISH OPPOURTUNITY
        notify("vacant", "G16 is currently vacant.");
      }
    } else if (reservation[day][period] == 1) {
      //NOTIFY RESERVED
      notify("reserved", "G16 is currently reserved.");
    }
    Particle.process();
    break;
  }
}

/*

If Period NOT RESERVED --> Check motion --> If motion --> Allow reservation --> UPDATE SOCIAL
If Period RESERVED --> UPDATE SOCIAL

*/

/* ======================= ALL FUNCTIONS ====================== */

/* NOTIFYER FUNCTIONS */

void notify(char type[], char data[]) {

  if ( type == "boot" ) {
    Particle.publish("IoTRoomSensor-Boot-G16", data, PRIVATE);
  }
  Serial.println(periodNotified);
  Serial.println(periodStateChange);

  if ( !periodNotified || periodStateChange ) {
    if ( type == "reserved" ) {
      Serial.println("Notification: Reserved");
      Particle.publish("IoTRoomSensor-StateRed-G16", data, PRIVATE);
      periodNotified = true;
    } else if ( type == "vacant" ) {
      Serial.println("Notification: Vacant");
      Particle.publish("IoTRoomSensor-StateGreen-G16", data, PRIVATE);
      periodNotified = true;
    }
}
  return;
}

void updateTime() {
  formattedDay = Time.format(Time.now(), "%A");
  formattedTime = Time.format(Time.now(), "%I:%M%p");
  day = Time.weekday();
  weekdayAlignment();
  period = updatePeriod();
  return;
}

/* PERIOD CONTROL FUNCTIONS */

int updatePeriod() {
  if (day == 6 || day == 7 ) {
    return 7;
  }
    int minSinceMidnight = (Time.local() % 86400) / 60;  // only take the time and drop the date and the drop seconds too
    for (int i=0;i<6;i++) {
      if ( periodStart[day][i] <= minSinceMidnight && minSinceMidnight < periodEnd[day][i] ) {
        if ( period != 0 && i != period ) {periodNotified = false;} else {periodNotified = true;}
        return i;
      }
    }
}

void setPeriodTimes() {
  for (int x=0; x<5; x++) {
    for (int y=0; y<6; y++) {
      int timeConvertStart = (periodStartHr[x][y] * 60) + periodStartMin[x][y];
      int timeConvertEnd = (periodEndHr[x][y] * 60) + periodEndMin[x][y];
      periodStart[x][y] = timeConvertStart;
      periodEnd[x][y] = timeConvertEnd;
      if (DEBUG_MODE) {
        Serial.print("Day: ");
        Serial.print(x+1);
        Serial.print(" | Period: ");
        Serial.print(y+1);
        Serial.print(" | Start Time: ");
        Serial.print(periodStart[x][y]);
        Serial.print(" | End Time: ");
        Serial.println(periodEnd[x][y]);
    }
    }
  }
  return;
}

void weekdayAlignment() {
  if (day == 1) {
    day = 7;
  } else if (day == 2) {
    day = 1;
  } else if (day == 3) {
    day = 2;
  } else if (day == 4) {
    day = 3;
  } else if (day == 5) {
    day = 4;
  } else if (day == 6) {
    day = 5;
  } else if (day == 7) {
    day = 6;
  }
  return;
}

/* OFFLINE MODE DURING NON-WEEKDAYS */

void offlineMode() {
  Serial.println("--Offline Mode--");
  delay(1500);
  while (period == 7) {
    updatePeriod();
    System.sleep(300);
  }
  return;
}

void checkMode() {
  if (period == 7) {
    offlineMode();
    System.reset();
  }
  return;
}

/* PIR SESNOR FUNCTIONS */

void updateMotion() {
  //if (periodCheck and notReserved) {
    if (calibrated()) {
      readPIR();
      reportPIR();
    }
  //}
  return;
}

bool calibrated() {
  return millis() - calibrateTime > 0;
}

void readPIR() {
  movementVal = digitalRead(pir);
}

void reportPIR() {
  if (movementVal == HIGH) {
    if (pirState == LOW) {
      //Particle.publish("designingiot/s15/motion");
      Serial.println("Motion Detected, Sir.");
      pirState = HIGH;
    }
  } else {
    if (pirState == HIGH) {
      pirState = LOW;
    }
  }
}

Have a good day,

Sam

1 Like