Schedule a series of functions in sequence at different intervals over 16 hours

I have a large inflatable balloon that inflates and deflates via a relay controlled fan.

It is suspended from the ceiling and as it deflates I have a winch that pulls the loose fabric up. When it inflates I have a winch let the fabric down.

The relays work and I can get the Arduino to control the different parts but I cannot set up a schedule of events.

In the inflatable are strings of lights that flash on the 1/4 hour and top of the hour like a clocktower. That part of the code seems to be working although it uses and alarm.delay and I think that needs to be removed so it does not hold up the rest of the program but I have had trouble doing that.

For example my goal:
inflate 40 min (while inflating run winch down for 20 min) then stay inflated for 10 min deflate for 10 min (while deflating run winch up for 10 min) stay deflated 30 minutes, inflate for 35 min ( while inflating run winch down for 15 min) stay inflated for 50 min ..... etc for a 16 hr daily sequence.

#include <Wire.h>
#include "RTClib.h"
#include <Time.h>
#include <TimeAlarms.h>

/*-----( Declare Constants and Pin Numbers )-----*/
const int lightPin1 = 30;    // Light #1
const int lightPin2 = 31;    // Light #2
const int lightPin3 = 32;    // Light #3
const int lightPin4 = 33;    // Light #4
const int deflateFanPin = 2;     // Fan #1 Deflate
const int inflateFanPin = 3;     // Fan #2 Inflate
const int deflateDamperPin = 4;     // Damper Motor #1
const int inflateDamperPin = 5;     // Damper Motor #2
const int winchUpPin = 8;     // winch up
const int winchDownPin = 9;    // winch down


/*-----( Declare objects )-----*/
RTC_DS1307 rtc;    // Create a RealTimeClock object

uint32_t syncProvider() //function which sets up the RTC as the source of external time
{
  return rtc.now().unixtime();
}

/*-----( Declare Variables )-----*/
int i;
int ding;
int n;
int hr;
int has15run = 0;
int has30run = 0;
int has45run = 0;
int has00run = 0;
int winchUpState = HIGH;
int winchDownState = HIGH;
int winchUpOK = 1;
int winchDownOK = 1;
unsigned long previousMillisUp = 0;     // will store last time Winch was updated
unsigned long previousMillisDown = 0;     // will store last time Winch was updated\
unsigned long previousMillisUpOK = 0;
unsigned long currentMillis = 0;    // stores the value of millis() in each iteration of loop()
long UpOnTime = 1000;
long UpOffTime = 2000;
long DownOnTime = 1000;
long DownOffTime = 2000;
long Upduration = 5000;
int winchUpseconds;
int winchDownseconds;

void setup()
{
  pinMode(lightPin1, OUTPUT);      // sets the digital pins as output
  pinMode(lightPin2, OUTPUT);
  pinMode(lightPin3, OUTPUT);
  pinMode(lightPin4, OUTPUT);
  pinMode(deflateFanPin, OUTPUT);
  pinMode(inflateFanPin, OUTPUT);
  pinMode(deflateDamperPin, OUTPUT);
  pinMode(inflateDamperPin, OUTPUT);
  pinMode(winchUpPin, OUTPUT);
  pinMode(winchDownPin, OUTPUT);

  digitalWrite(lightPin1, HIGH);        // Prevents relays from starting up engaged
  digitalWrite(lightPin2, HIGH);
  digitalWrite(lightPin3, HIGH);
  digitalWrite(lightPin4, HIGH);
  digitalWrite(deflateFanPin, HIGH);
  digitalWrite(inflateFanPin, HIGH);
  digitalWrite(deflateDamperPin, HIGH);
  digitalWrite(inflateDamperPin, HIGH);
  digitalWrite(winchUpPin, HIGH);
  digitalWrite(winchDownPin, HIGH);

  Serial.begin(57600); // Set up for Serial Monitor to be able to see this work
  Wire.begin();
  rtc.begin();
  rtc.adjust(DateTime(__DATE__, __TIME__)); //comment this out when the RTC has been set
  setSyncProvider(syncProvider);   // the function to get the time from the RTC

  /*-----( Declare alarms )-----*/
  // Alarm.alarmRepeat(8,30,0, inflate);
  // Alarm.alarmRepeat(9,00,0, stayinflated);
  //  Alarm.alarmRepeat(10,00,0, deflate);
  //  Alarm.alarmRepeat(10,30,0, staydeflated);
  //  Alarm.alarmRepeat(11,30,0, inflate);
  //  Alarm.alarmRepeat(12,00,0, stayinflated);
  Alarm.alarmRepeat(14, 45, 0, deflate);
  Alarm.alarmRepeat(14, 46, 0, upWinch);

}//--(end setup )---

void  loop() 
{
  currentMillis = millis();
  blinkClock();
  nightLights();
  //digitalClockDisplay();
  //Alarm.delay(1000); // wait one second
  //digitalWrite(winchUpPin, LOW);
  //digitalWrite(winchUpPin, HIGH);
  // digitalWrite(winchDownPin, LOW);
  //digitalWrite(winchDownPin, HIGH);
  //winchUpOK = true;
  //upWinch();
  //downWinch();
  inflate();
  //deflate();
  //stayinflated();
  //staydeflated();
}

void upWinch ()
{
  unsigned long currentMillis = millis();
  if ((winchUpState == HIGH) && (winchUpOK = true) && (currentMillis - previousMillisUp >= UpOnTime))
  {
    {
      winchUpState = LOW;  // Turn it on
      previousMillisUp = currentMillis;  // Remember the time
      digitalWrite(winchUpPin, winchUpState);  // Update the winch pin
    }
  }
  else if ((winchUpState == LOW) && (currentMillis - previousMillisUp >= UpOffTime))
  {
    winchUpState = HIGH;  // turn it off
    previousMillisUp = currentMillis;   // Remember the time
    digitalWrite(winchUpPin, winchUpState);  // Update the winch pin
  }
}

void downWinch ()
{
  
  if ((winchDownState == HIGH) && (currentMillis - previousMillisDown >= DownOnTime))
  {

    winchDownState = LOW;  // Turn it on
    previousMillisDown = currentMillis;  // Remember the time
    digitalWrite(winchDownPin, winchDownState);  // Update the winch pin

  }
  else if ((winchDownState == LOW) && (currentMillis - previousMillisDown >= DownOffTime))
  {
    winchDownState = HIGH;  // turn it off
    previousMillisDown = currentMillis;   // Remember the time
    digitalWrite(winchDownPin, winchDownState);  // Update the winch pin
  }
}


void inflate ()
{
  digitalWrite(inflateFanPin, LOW); // Turn on inflate fan
  digitalWrite(deflateFanPin, HIGH); // Make sure deflate fan is off
  digitalWrite(deflateDamperPin, HIGH); // Make sure deflate damper is closed
  //  digitalWrite(inflateDamperPin, LOW);  // Open inflate damper (not used in current project)
  // winchDownOK = true;
}

void deflate ()
{
  digitalWrite(inflateFanPin, HIGH); // Make sure inflate fan is off
  digitalWrite(deflateFanPin, LOW); // Turn on deflate fan
  digitalWrite(deflateDamperPin, LOW); // Open deflate damper
  // digitalWrite(inflateDamperPin, HIGH); // Make sure inflate damper is closed (not used in current project)
  // winchUpOK = true;
}

void stayinflated ()
{
  inflate ();
  winchDownOK = false;
}

void staydeflated ()
{
  deflate ();
  winchUpOK = false;
}

(rest of the code)

void Blink4Times()
{
  // Serial.println("Alarm: - turn lights on and off in sequence at 15 minutes");
  turnOffLights ();
  Alarm.delay(1000); // wait one second
  digitalWrite(lightPin1, LOW);
  Alarm.delay(1000); // wait one second
  digitalWrite(lightPin1, HIGH);
  digitalWrite(lightPin2, LOW);
  Alarm.delay(1000); // wait one second
  digitalWrite(lightPin2, HIGH);
  digitalWrite(lightPin3, LOW);
  Alarm.delay(1000); // wait one second
  digitalWrite(lightPin3, HIGH);
  digitalWrite(lightPin4, LOW);
  Alarm.delay(1000); // wait one second
  digitalWrite(lightPin4, HIGH);
  Alarm.delay(2000); // wait two seconds
  turnOffLights ();
}

void turnOffLights ()
{
  digitalWrite(lightPin1, HIGH); // Make sure all lights are off
  digitalWrite(lightPin2, HIGH); // Make sure all lights are off
  digitalWrite(lightPin3, HIGH); // Make sure all lights are off
  digitalWrite(lightPin4, HIGH); // Make sure all lights are off
}

void turnOnLights ()
{
  digitalWrite(lightPin1, LOW); // Make sure all lights are on
  digitalWrite(lightPin2, LOW); // Make sure all lights are on
  digitalWrite(lightPin3, LOW); // Make sure all lights are on
  digitalWrite(lightPin4, LOW); // Make sure all lights are on
}

void Blink15Min()
{
  if (minute() == 15 && has15run == 0)
  {
    n = 1;
    blinkCount();
    has15run = 1;
    has00run = 0;
  }
  else if (minute() == 30 && has30run == 0)
  {
    n = 2;
    blinkCount();
    has30run = 1;
  }
  else if (minute() == 45 && has45run == 0)
  {
    n = 3;
    blinkCount();
    has45run = 1;
    has30run = 0;
  }
  else if (minute() == 0 && has00run == 0)
  {
    n = 4;
    blinkCount();
    blinkHour();
    has00run = 1;
    has45run = 0;
  }
}

void blinkCount()
{
  for (i = 0; i < n; i++)
  {
    Blink4Times();
  }
}

void blinkHour()
{
  if (hour() <= 12)
  {
    hr = (hour());
  }
  else if (hour() > 12)
  {
    hr == hour() - 12;
  }
  for (i = 0; i < hr; i++)
  {
    blinkAll();
  }
  turnOffLights();
}

void blinkAll ()
{
  turnOnLights ();
  Alarm.delay(2000); // wait one second between clock display
  turnOffLights ();
  Alarm.delay(1000); // wait one second between clock display

}

void digitalClockDisplay()
{
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.println();
}

void printDigits(int digits)
{
  Serial.print(":");
  if (digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

void blinkClock()
{
  if ( (minute() % 15) == 0)
  {
    Blink15Min();
  }
  turnOffLights ();
}

void nightLights()
{
  if ( hour() > 12 && hour() <= 24)
  {
    turnOnLights ();
  }
  else if ( hour() >= 0 && hour() <= 6)
  {
    turnOnLights ();
  }
  else
  {
    turnOffLights ();
  }
}

[/code]

The demo several things at a time illustrates how to manage timing using millis() so that it does not block other activities.

...R

Robin2 - I have been using your tutorial and have read that entire thread. I modified the upWinch and downWinch functions to work with the correct additive interval millis() timer.

I also think I added a state with the check for winchUpOK and winchDownOK true or false.

The inflate and deflate functions switch this state.

What I do not understand is how to put everything in an irregular timed sequence such as

For example my goal:
inflate 40 min (while inflating run winch down for 20 min) then stay inflated for 10 min deflate for 10 min (while deflating run winch up for 10 min) stay deflated 30 minutes, inflate for 35 min ( while inflating run winch down for 15 min) stay inflated for 50 min ..... etc for a 16 hr daily sequence.

void  loop()
{
  currentMillis = millis();
  //blinkClock();
  //nightLights();
  //digitalClockDisplay();
  //Alarm.delay(1000); // wait one second
  //digitalWrite(winchUpPin, LOW);
  //digitalWrite(winchUpPin, HIGH);
  // digitalWrite(winchDownPin, LOW);
  //digitalWrite(winchDownPin, HIGH);
  //winchUpOK = true;

  //downWinch();
  //inflate();
  //deflate();
  upWinch();
  switchwinch();
  //stayinflated();
  //staydeflated();
}

void switchwinch () {
  digitalWrite(winchUpPin, winchUpState);  // Update the winch pin
  digitalWrite(winchUpPin, winchUpState);	  // Update the winch pin
  digitalWrite(winchDownPin, winchDownState);  // Update the winch pin 
  digitalWrite(winchDownPin, winchDownState);	  // Update the winch pin
}

void upWinch ()
{
  if (winchUpState == HIGH) {
    if (winchUpOK == true) {
      if (currentMillis - previousMillisUp >= UpOnTime) {
        winchUpState = LOW;  // Turn it on
        previousMillisUp += UpOnTime;  // Remember the time
      }
     }
    }
  else {
    if (currentMillis - previousMillisUp >= UpOffTime) {
       winchUpState = HIGH;  // turn it off
       previousMillisUp += UpOffTime;   // Remember the time
    }
  }
}

void downWinch () {
  if (winchDownState == HIGH) {
    if (winchDownOK == true) {
    if (currentMillis - previousMillisDown >= DownOnTime) {
       winchDownState = LOW;  // Turn it on
       previousMillisDown += DownOnTime;  // Remember the time
     }
    }
  }
  else {
    if (currentMillis - previousMillisDown >= DownOffTime) {
    winchDownState = HIGH;  // turn it off
    previousMillisDown += DownOffTime;   // Remember the time
    }
  }
}

ive always found it easier to change time to a counter.

you have a rtc so I would have used something like

get clock

if prev_min != min //depending on the type of rtc code you are using use the min name
counter1++
counter2++

prev_min=min // works for seconds, mins, hours

the arduino will see the change in the clock and advance the counter

use the counter to make something happen then use counter=0 so it will do it again

works well with a if argument as you can have that fail to a else counter=0 so it wont count until a second condition is meet.

@gpop1 - Are you saying that i should not use millis() at all?

Do I use a state machine to make the schedule?

How do I set the duration of each event or function?

I am confused.

Lukinio:
@gpop1 - Are you saying that i should not use millis() at all?

Do I use a state machine to make the schedule?

How do I set the duration of each event or function?

I am confused.

you can use millis with out a problem but its hard to keep track of that in your own head. You know what you want and when you want it so using a event to trip the next event is easier than trying to calculate events based on millis.

im not a great programmer so keeping it simple helps.

something like inflate and deflate controls could be written in a if statement using the same counter
just using larger/smaller if arguements

There should be no problem using millis() unless it is important to stay synchronized with clock time. Millis() may run a bit fast or slow depending on how accurate the 16MHz clock is.

I think you need to write down the steps you want to happen in chronolgical order and one step on each line (I mean write down on paper or in a text editor, not in code).

In several things at a time there are different timers for different LEDs and you will similarly need different timers for your activities. What is probably different about your project is that (for example) the end of one activity may need to trigger the start of another.

In the list of steps it might help to have different columns for the different timers.

The Thread planning and implementing a program illustrates the idea of listing the steps - although for somewhat different reasons.

In the piece of code you have posted in Reply #3 you have the millis() code within your upWinch() and downWinch() functions. In many situations that is exactly how I would do it. But if you want to call those functions at specific times then it probably makes more sense to figure out the time in an upDateActions() function which calls upWinch() etc at the appropriate moments - and have none of the timing in the upWinch() etc functions.

And if you do need an RTC for accuracy all of the above still applies - just use the RTC instead of millis()

...R