#include <Button_SL.hpp>

using ulong = unsigned long int;

//////////////////////////////////////////////////////////////////////////////
/// @brief Helper class for non-blocking execution of
/// code sections at certain intervals.
///
//////////////////////////////////////////////////////////////////////////////
class Interval {
public:
  //////////////////////////////////////////////////////////////////////////////
  /// @brief  Determine whether the specified interval has expired.
  ///
  /// @param duration    Interval duration
  /// @return true       when the interval has elapsed
  /// @return false      interval not elapsed yet
  //////////////////////////////////////////////////////////////////////////////
  bool operator()(const ulong duration) {
    if (false == isStarted) { return start(false); }
    return (millis() - timeStamp >= duration) ? start(true) : false;
  }

private:
  bool start(bool state = false) {
    isStarted = !state;   // Set the value to true on the first call
    timeStamp = millis();
    return state;
  }

private:
  bool isStarted {false};   // Flag = true if the first Operator() call has been made.
  ulong timeStamp {0};
};

// Combines a button object and an additional flag into a data structure.
// The additional flag is required to save an autorelease status after a long button press.
struct ButtonWrapper {
  Btn::ButtonSL btn;
  bool hasReleased;
};

//////////////////////////////////////////////////
// Global constants and variables
//////////////////////////////////////////////////
#define LOWLEVEL_TRIGGER  // Comment out it trigger level is HIGH
#ifdef LOWLEVEL_TRIGGER
enum Trigger : uint8_t {on = LOW, off = HIGH};
#else
enum Trigger : uint8_t {on = HIGH, off = LOW};
#endif

constexpr uint8_t BUTTON_PIN {4};
constexpr uint8_t RELAIS_PIN {5};
constexpr uint8_t SIGNAL_PIN {6};
constexpr ulong INTERVAL_ON_MS {1000};
constexpr ulong INTERVAL_WAIT_MS {5000};

enum class Status : uint8_t { once, onceOn, intervalSignal, interval, intervalOn, intervalWait, off };

ButtonWrapper bwrp {
  {BUTTON_PIN, 3000},   // Long Press is >= 3000 ms
  false
};   
Interval interval;  

//////////////////////////////////////////////////
// Functions
//////////////////////////////////////////////////

Status checkButton(ButtonWrapper &fBwrp, Status fState) {
  switch (fBwrp.btn.tick()) {
    case Btn::ButtonState::shortPressed:
      fState = Status::once;
      fBwrp.hasReleased = false;   // If the autoRelease was triggered by a long button press, this flag is reset here.
      break;
    case Btn::ButtonState::longPressed:
      // If longPressed has been triggered but the button is still not released,
      // do not evaluate any more longPressed status so that the
      // program continues to run normally.
      if (false == fBwrp.hasReleased) {
        fState = Status::intervalSignal;
        fBwrp.hasReleased = true;
      }
      break;
    default: break;
  }
  return fState;
}

//////////////////////////////////////////////////
// Main Program
//////////////////////////////////////////////////
void setup() {
  pinMode(RELAIS_PIN, OUTPUT);
  pinMode(SIGNAL_PIN, OUTPUT);
  digitalWrite(RELAIS_PIN,Trigger::off);
  
  bwrp.btn.begin();
  bwrp.btn.setDebounceTime_ms(40);  // 30 milliseconds are default
  bwrp.btn.releaseOn();   // Releases button as soon as the time for a long button press has been reached.
}

void loop() {
  static Status state {Status::off};
  static bool isIntervalOn {false};

  state = checkButton(bwrp, state);
  // If interval switching is active, a short press of the button cancels it.
  if (true == isIntervalOn && state == Status::once) {
    digitalWrite(RELAIS_PIN, Trigger::off);
    digitalWrite(SIGNAL_PIN, LOW);
    isIntervalOn = false;
    interval(0);
    state = Status::off;
  }
  switch (state) {
    case Status::once:
      digitalWrite(RELAIS_PIN, Trigger::on);
      state = Status::onceOn;
      [[fallthrough]];
    case Status::onceOn:
      if (interval(INTERVAL_ON_MS) == true) {
        digitalWrite(RELAIS_PIN, Trigger::off);
        state = Status::off;
      }
      break;
    case Status::intervalSignal:
      digitalWrite(SIGNAL_PIN, HIGH);
      state = Status::interval;
      [[fallthrough]];
    case Status::interval:
      digitalWrite(RELAIS_PIN, Trigger::on);
      isIntervalOn = true;
      state = Status::intervalOn;
      [[fallthrough]];
    case Status::intervalOn:
      if (interval(INTERVAL_ON_MS) == true) {
        digitalWrite(RELAIS_PIN, Trigger::off);
        state = Status::intervalWait;
      }
      break;
    case Status::intervalWait:
      if (interval(INTERVAL_WAIT_MS) == true) { state = Status::interval; }
      break;
    default: break;
  }
}
Kurzer Tastendruck: Relais für 1 Sekunde an. Langer Tastendruck (3 Sek.): Intervall 1 Sek. an 5 Sek. aus. Kurzer Tastendruck im Intervall-Modus, schaltet diesen aus.
NOCOMNCVCCGNDINLED1PWRRelay Module