Relay / Controllino / Schalten über 0 Uhr

Hallo Community,

bin mal wieder auf ein Problem gestoßen und komme momentan nicht zu einer einigermaßen sauberen Lösung.

Grundlegend soll die Routine ein Relay im Controllino schalten. Das Relay soll nach einer festgelegten Startzeit für eine bestimmte Zeit schalten. Drei unterschiedliche Zeiten werden über einen Drehschalter mit 3 Stellungen bzw. 2 Schließern bestimmt.
Ich habe mir gedacht, nicht über millis() zu gehen, um das Relay auch nach Stromausfall wieder weiterlaufen zu lassen.

Ist:
//Button Logic
-->Schalter auslesen und aktuell eingestellte Zeitmodi erfassen.
//RTC
-->RTC auslesen und Tageszeit in Millis seit 0 Uhr umrechnen.
//Relay
-->Startzeitunkt nach geg. Variable in Millisekunden festlegen.
-->Endzeitpunkt in Millisekunden berechnen. (Hier überlauf über 0 Uhr teilweise je nachdem)
-->Relay Schalten

Problem:
-->Wenn die Ausschaltzeit später als 0 Uhr ist wird es Brecherisch.
-->Relay soll natürlich nicht um 0 Uhr kurz ausgehen, sondern konstant durchlaufen
-->Relay triggert beim Hochladen des Codes am Anfang einmal trotz gesetztem digitalWrite LOW im Setup.

Habt ihr Lösungen auf Lager, wie man den Code verbessern kann bzw. gangbar macht?

#include <SPI.h>
#include <Controllino.h>

//BUTTON LOGIC
//switches
const int switchPinPHASE1 = A1;
const int switchPinPHASE2 = A2;

int switchStatePHASE1 = 0;
int switchStatePHASE2 = 0;

bool Mode1;
bool Mode2;
bool Mode3;

//RTC
int h;
int m;
int s;

//Relay
int startTimeHourRelay = 13;//Startstunde
int startTimeMinRelay = 0;//Startminute
int relayPin = 30;

void setup() {
  Serial.begin(9600);
  //BUTTON LOGIC
  //Switches
  pinMode(switchPinPHASE1, INPUT);
  pinMode(switchPinPHASE2, INPUT);

  //RTC
  Controllino_RTC_init();
  /* set time and date by separate values values to the RTC chip */
  /* Day, WeekDay, Month, Year, Hour, Minute, Second); */
  //Controllino_SetTimeDate(12, 4, 1, 17, 15, 41, 23);
  /* or use another possibility and define the time and date by strings, e.g. "Nov 15 2018", "11:41:02" */
  /* following example uses predefined C macros __DATE__ and __TIME__ which represent compilation time */
  Controllino_SetTimeDateStrings(__DATE__, __TIME__); /* set compilation time to the RTC chip */

  //Relay
  digitalWrite(relayPin, LOW);
  pinMode(relayPin, OUTPUT);

}

void loop() {

  //BUTTON LOGIC
  switchStatePHASE1 = digitalRead(switchPinPHASE1);
  switchStatePHASE2 = digitalRead(switchPinPHASE2);

  //3 unterschiedliche Modi aus Drehschalterstellung festlegen
  if (switchStatePHASE1 == HIGH && switchStatePHASE2 == LOW) {
    Mode1 = true;
  } else {
    Mode1 = false;
  }

  if (switchStatePHASE1 == LOW && switchStatePHASE2 == LOW) {
    Mode2 = true;
  } else {
    Mode2 = false;
  }

  if (switchStatePHASE1 == LOW && switchStatePHASE2 == HIGH) {
    Mode3 = true;
  } else {
    Mode3 = false;
  }

  //RTC
  unsigned long timeMillis;
  //Schreibe Zeitvariablen
  h = Controllino_GetHour();
  m = Controllino_GetMinute();
  s = Controllino_GetSecond();

  Serial.print(" t: ");
  Serial.print(h);
  Serial.print(":");
  Serial.print(m);
  Serial.print(":");
  Serial.print(s);

  //Tageszeit in Millisekunden umrechnen
  timeMillis = ( h * 3600000UL + m * 60000UL + s * 1000UL);

  //Relay
  //Startzeit in Millis berechnen
  unsigned long relayStartMillis = startTimeHourRelay * 3600000UL + startTimeMinRelay * 60000UL;

  //Laufzeit je nach Schalterstellung berechnen (20h, 10h, 5h)
  unsigned long relayPhaseTime;
  if (Mode1 == true) {
    relayPhaseTime = 20 * 3600000UL;
  }
  else if (Mode2 == true) {
    relayPhaseTime = 10 * 3600000UL;
  }
  else if (Mode3 == true) {
    relayPhaseTime = 5 * 3600000UL;
  }

  //Ausschaltzeitpunkt festlegen
  unsigned long relayEndMillis = relayStartMillis + relayPhaseTime ;

  Serial.print(" relayStartMillis: ");
  Serial.print(relayStartMillis);

  Serial.print(" relayEndMillis: ");
  Serial.print(relayEndMillis);

  //Wenn die Endzeit über 24 spät ist...
  unsigned long dayOver;
  if (relayEndMillis >= 86399000) {
    dayOver = relayEndMillis - 86399000;
  }

  Serial.print(" dayOver: ");
  Serial.print(dayOver);

  //Schaltlogic bestimmen
  if (86399000 >= timeMillis >= relayStartMillis || 0 <= timeMillis <= dayOver ) {
    digitalWrite(relayPin, HIGH);
  } else {
    digitalWrite(relayPin, LOW);
  }
  Serial.println();
}

Sowas hat noch nie geklappt!

Oder anders:
Das tut mit Sicherheit nicht das, was du dir wünscht

Uninitialisiert

wird manchmal mit einem Wert versehen

Manchmal uninitialisiere Zufallswerte, manchmal beabsichtigte Werte.

Das gleiche wie Oben: Tuts nicht, zudem uninitialisierte Variable benutzt

@ engineeeer
für tägliche Schaltzeiten könntest du:

angenommen du definierst deine Schaltzeiten in HHMM
angenommen du schaltest nur 1x pro Minute

Dann kannst du

onTime 1400
offTime 1300

beim Übergang von 1359 auf 1400 gezielt einschalten
beim Übergang von 1259 auf 1300 gezielt ausschalten

und im Setup (nach einem Neustart) musst dich halt inbasteln.

Vieleicht so:

WENN offTime > onTime und onTime < jetzt und offTime > jetzt DANN einschalten
WENN offTime < onTime und offTime > jetzt und onTime > jetzt DANN einschalten

edit:



//   WENN offTime > onTime und onTime < jetzt und offTime > jetzt DANN einschalten
//   WENN offTime < onTime und offTime > jetzt und onTime > jetzt DANN einschalten

bool isActive(uint16_t time, uint16_t onTime, uint16_t offTime){
 if (offTime > onTime &&  onTime <= time && offTime > time) return true; // innerhalb eines Tages
 if (offTime < onTime && offTime >= time && onTime >= time) return true; // über Mitternacht
 return false;
}

void setup() {
  Serial.begin(115200);
  //                      jetzt  EIN   AUS
  Serial.println(isActive(1430, 1500, 1600)); // inaktiv
  Serial.println(isActive(1530, 1500, 1600)); // aktiv
  Serial.println(isActive(1630, 1500, 1600)); // inaktiv

  Serial.println();
  Serial.println(isActive(1500, 1500, 1600)); // aktiv
  Serial.println(isActive(1600, 1500, 1600)); // inaktiv

  Serial.println();
  Serial.println(isActive(1530, 1600, 1500)); // inaktiv
  Serial.println(isActive(1430, 1600, 1500)); // aktiv
  Serial.println(isActive(1630, 1500, 1600)); // inaktiv

  Serial.println();
  Serial.println(isActive(1500, 1600, 1500)); // aktiv 
  Serial.println(isActive(1600, 1600, 1500)); // inaktiv
}

void loop() {
  // put your main code here, to run repeatedly:

}

für "einmalige Schaltungen für eine bestimmte Zeit versteh ich den Aufriss nicht, denn dann bräuchtest nur den UTC Zeitstempel aus der RTC Zeit nehmen so wie ma halt sonst die millis() nehmen würde.

1 Like

Controllino hat doch eine RTC mit Alarm verbaut, kannst Du die nicht nutzen? Siehe Beispiel DemoRTCAlarm.ino

Bedeutet Stromausfall der Microcontroller hatte keinen Strom mehr und startet neu?

Dann müsstest du die angefangene Schaltzeit einmal pro Sekunde in einen nichtflüchtigen Speicher speichern um bei einem Neustart wieder vom Speicher einlesen.

Brauchst du wirklich Millisekunden Genauigkeit?
Wenn eine Genauigkeit von einer Sekunde auch reicht dann hast du bei unsigned long
49 Tage * 1000 = 49000 Tage = 134 Jahre zur Verfügung.
Soll heißen du ziehst vom Jahr das die RTC ausgibt erst einmal 2023 Jahre ab.
Dann rechnest du von dort aus Jahr Monat Tag Stunde Minute Sekunde
in Sekunden um.
Sozusagen SekundenSumme seit 01.01.2023
Diese Zahl wird durch immer wieder neues Auslesen der RTC aktualisiert.
und dann kannst du für jede Schaltzeit einfach
überprüfen ob die aktuelle Zeit gleich oder größer als die Anzahl SekundenSumme für einen bestimmten Zeitpunkt ist.
Beispiel
aktuelle Uhrzeit ist
01.01.2023 02:05:30
Volle_Jahre = Jahr - 2023 ( = 0)

Volle_JahreSekunden = (2023 - 2023) * 365 * 24 * 3600

Tag_im_Jahr = 1
volle_Tage = Tag_im_Jahr - 1 = 0

SekundenSummeTag = Stunden * 3600 + Minuten * 60 + Sekunden
SekundenGesamtSumme = volle_Tage * 24 * 3600 + SekundenSummeTag

02:05:30 Uhr SekundenSummeTag = 2 * 3600 + 5 * 60 + 30;

SekundenGesamtSumme = 0 * 24 * 3600 + SekundenSummeTag

05.03.2025 04:10:59
Jahr = 2025
Volle_Jahre = Jahr - 2023 ( = 2)

Volle_JahreSekunden = 2 * 365 * 24 * 3600

Tag_im_Jahr = 31+28+31+30+3 (berechnet als Summe TageImMonat[1] bis [5-1])
volle_Tage = Tag_im_Jahr - 1 = 122

04:10:59 Uhr SekundenSummeTag = 4 * 3600 + 10 * 60 + 59;

SekundenGesamtSumme = volle_Tage * 24 * 3600 + SekundenSummeTag

Wenn man die Schaltzeiten nicht fix sind dann kannst du die Berechnen mit
SekundenGesamtSumme zum Zeitpunkt des Einschaltens

AusschaltzeitpunktSekSumme = aktuelleSekundenGesamtSumme + EinschaltDauerInSekunden

if ( aktuelleSekundenGesamtSumme > Ausschaltzeitpunkt) {
ausschalten();
}

Damit kann der Mikrocontroller alle paar Sekunden den Strom verlieren.
Solange die RTC weiterläuft
wird er durch die absoluten Zeitwerte trotzdem zu den richtigen Zeiten schalten.

vgs

Wenn du eine RTC hast, und von der Tageszeit abhängig einmal am Tag schalten willst, kannst du die Überlegungen von @StefanL38 ignorieren, und einfach zwei Fälle unterscheiden:
E Einschaltzeit
A Ausschaltzeit
T Aktuelle Zeit

E<A ? T > E && T < A
E>A ? T > E || T < A

Ob du die Zeiten jetzt als Stunde * 60+Minute oder "militärisch" Stunde * 100+Minute (1500 ist dann 15:00) rechnest, ist egal.
Das sollte eigentlich das gleiche wie @noiasca s Vorschlag sein.

?
Soll das "?" der Ternary-Operator sein?
Wenn ja müsste man das "T > E && T < A" als logische Operation auffassen die ausgewertet wird falls E > A true ist - wo ist dann der Code der im Falle von E < A ausgeführt wird?

Vorausgesetzt meine obige Annahme trifft zu
mehr als die logischen Operationen

T > E && T < A

bzw.

T > E || T < A

auswerten passiert da noch nichts.

Kannst du das mal als compilierbaren code posten?

Ich verzichte jetzt auf weitere Spekulationen aber ich vermute aus dem Bauch heraus
wenn man das in compilierbaren Code übersetzt kommt eine ähnlich große Anzahl an Zeilen heraus wie bei meinem Vorschlag.

Jetzt bin ich gespannt ob du das Gegenteil beweisen kannst. Wenn ja dann freut es mich aufrichtig eine kompaktere Möglichkeit kennengelernt zu haben.

vgs

Was sonst ?

https://www.learncpp.com/cpp-tutorial/comma-and-conditional-operators/

Wenn ich mir das von dir verlinkte Beispiel ansehe
image
dann fehlt da mindestens der Doppelpunkt und der Strichpunkt

Also dann nimm dir doch mal 5 Sekunden Zeit und poste wenigstens als code-snippet wie der compilierbare code dazu aussieht.

x
ich glaube man kann sich das ganze Rumgeplänkel sparen, wenn der TO @engineeeer sich einfach mal die Zeit nehmen würde zu antworten.

1 Like

Nein, der braucht einen Doppelpunkt.
Aber sonst schon die richtige Richtung.

Bitte sehr:

uint16_t E = onTime;
uint16_t A = offTime;
uint16_t T = getCurrentTime();
bool schalten;

if (E < A) schalten= T >= E && T < A;
else  schalten = T >= E || T < A;

digitalWrite (pin, schalten);

Ich hoffe mal, dass das klar genug für dich ist, daraus kompilierbaren Code zu machen.

Mit ternary ginge es noch kompakter, aber die Lesbarkeit tendiert dann mehr zum Quiz, besonders wenn man Formatierung und überflüssige Klammern weg lässt:

digitalwrite (pin ,
 (E < A) ? (T >= E && T < A)
          :(T >= E || T < A)
);

Also ich hab mir jetzt mal kurz Zeit genommen durchzulesen, was hier passiert ist.

Um es kurz zu machen: Stelle bitte ein: DATEI - VOREINSTELLUNGEN - Ausführliche Ausgabe während [x] Kompilierung
Und da drunter: Kompilerwarnungen ALLE

Dann hast Du schon die Hälfte geschafft. Nun nur noch auf die Warnungen reagieren.

Und dann das Ganze mit ein wenig Logik angehen.
Ich habs versucht.
Allerdings bin ich über etwas in Deinem Code gestolpert.
Diese Zeile:

hat mich stutzig gemacht. Und ja. das ist Mist.
Hier hat Controllino etwas versucht, was unsinnig ist.
Den Wochentag als Vorgabe mit zu übergeben macht keinen Sinn und ich hab mich nach dem Grund gefragt, warum man das machen will.
Ich sehe keinen.
Offensichtlich wird die Uhr anders benutzt als vorgesehen. Denn die Information weekday ergibt sich aus dem Datum. Hier wurde das Rad neu erfunden.
Aber gut - ich greife auch auf die Funktionen für die Zeit zurück. Da interressiert mich der Wochentag nicht.
Und ich spare die ganze Umrechnerei in (m)s.

Mach was draus.

// Forensketch - Relaisschaltung über Mitternacht
// https://forum.arduino.cc/t/relay-controllino-schalten-uber-0-uhr/1097679/
// getestet auf einem ARDUINO UNO nur mit seriellem Monitor

#include <SPI.h>
#include <Controllino.h>

//BUTTON LOGIC
//switches
const byte switchPinPHASE1 = A1;
const byte switchPinPHASE2 = A2;
const byte relayPin = 30;

uint8_t onHour = 6;//Startstunde
uint8_t onMinute = 0;//Startminute
uint8_t offHour;
uint8_t offMinute;

bool EIN = HIGH;

void setup()
{
  Serial.begin(9600);
  //BUTTON LOGIC
  //Switches
  pinMode(switchPinPHASE1, INPUT);
  pinMode(switchPinPHASE2, INPUT);
  //RTC
  Controllino_RTC_init();
  /* set time and date by separate values values to the RTC chip */
  /* Day, WeekDay, Month, Year, Hour, Minute, Second); */
  // Controllino_SetTimeDate(12, 4, 1, 17, 15, 41, 23);
  /* or use another possibility and define the time and date by strings, e.g. "Nov 15 2018", "11:41:02" */
  /* following example uses predefined C macros __DATE__ and __TIME__ which represent compilation time */
  // Controllino_SetTimeDateStrings(__DATE__, __TIME__); /* set compilation time to the RTC chip */
  //Relay
  digitalWrite(relayPin, LOW);
  pinMode(relayPin, OUTPUT);
}

void loop()
{
  setOffTime();
  setRelais();
  printSerial();
}
//
void setOffTime()
{
  //BUTTON LOGIC
  bool switchStatePHASE1 = digitalRead(switchPinPHASE1);
  bool switchStatePHASE2 = digitalRead(switchPinPHASE2);
  // unterschiedliche Modi aus Drehschalterstellung festlegen
  if (switchStatePHASE1 == HIGH && switchStatePHASE2 == LOW)
  {
    offHour = 20;
    offMinute = 0;
  }
  else if (switchStatePHASE1 == LOW && switchStatePHASE2 == LOW)
  {
    offHour = 10;
    offMinute = 0;
  }
  else if (switchStatePHASE1 == LOW && switchStatePHASE2 == HIGH)
  {
    offHour = 5;
    offMinute = 0;
  }
  /*
     Wenn die eingestellte offZeit nicht die tatsächliche
     Abschaltzeit, sondern die Laufzeit sein soll, ist
     die StartZeit mit einzurechnen!
     Es fehlt eine Fehlerbehandlung, wenn Laufzeit länger als 24 Stunden
  */
  /*
      offHour+=onHour;
      offMinute+=onMinute;
      while (offMinute>59)
      {
      offMinute-=60;
      offHour++;
      }
      while (offHour>23)
      offHour-=24;
      // day++
  */
}
//
void setRelais()
{
  bool relaisMode = !EIN;
  int8_t h = Controllino_GetHour();
  int8_t m = Controllino_GetMinute();
  if (h < 0 || m < 0)
  {
    Serial.println(F("Uhr defekt!"));
    return;
  }
  uint16_t myTime = 60 * h + m;
  uint16_t onTime = 60 * onHour + onMinute;
  uint16_t offTime = 60 * offHour + offMinute;
  if (onTime > offTime)                                 // ON 23:53 - OFF 00:02
  {
    if (myTime >= onTime || myTime < offTime)
    { relaisMode = EIN; }
  }
  else                                                  // ON 00:02 - OFF 23:53
  {
    if (myTime >= onTime && myTime < offTime)
    { relaisMode = EIN; }
  }
  digitalWrite(relayPin, relaisMode);
}
//
void serialZero(int8_t value)
{
  if (value < 10)
  { Serial.print(0); }
  Serial.print(value);
}
//
void printSerial()
{
  static uint8_t lastSecond = 60;
  byte s = Controllino_GetSecond();
  if (lastSecond != s)
  {
    lastSecond = s;
    Serial.print(F("Time: "));
    serialZero(Controllino_GetHour());
    Serial.print(':');
    serialZero(Controllino_GetMinute());
    Serial.print(':');
    serialZero(s);
    Serial.print(F("\tOnTime: "));
    serialZero(onHour);
    Serial.print(":");
    serialZero(onMinute);
    Serial.print(F("\tOffTime: "));
    serialZero(offHour);
    Serial.print(":");
    serialZero(offMinute);
    Serial.print(F("\tRelais: "));
    Serial.println(digitalRead(relayPin) == EIN ? F("EIN") : F("AUS"));
  }
}

Wenn man das ein paar mal gemacht hat, dann ist das gar nicht schlimm :wink: Ich habe nur die Befürchtung, wenn man es zu oft macht, erschlägt man damit Einsteiger.
Darum habe ich auch das Konstrukt:

  if (onTime > offTime)                                 // ON 23:53 - OFF 00:02
  {
    digitalWrite(relayPin, myTime >= onTime || myTime < offTime);
  }
  else                                                  // ON 00:02 - OFF 23:53
  {
    digitalWrite(relayPin, myTime >= onTime && myTime < offTime);
  }

vermieden und lieber einen zusätzlichen bool verwendet... :slight_smile:

Mit && verknüpfen wird dann wohl besser sein. Danke

Ich dachte mir wenn ich direkt auf Millis umrechne, spare ich mir extra Verwurstelungen mit Stunden und Minuten und vereinfache das etwas. War jedoch nur eine Idee. Villeicht doch einfacher einfach nur mit h und m zu rechnen....

Ok die schaue ich mir auf jedenfall mal an, danke!

Ok das wäre natürlich auch eine säuberliche Lösung. Habe mir Speichern noch keine Erfahrung bisher, wäre aber auch gut um Variablen einzuspeichern wenn diese übers HMI geändert wurden.

Also der Startzeitpunkt soll veränderbar sein. Die Laufzeiten über den Drehschalter...I

So ähnlich hatte ich auch schonmal ein Versuch, schaue ich mir auf jedenfall nochmal an. Villeicht war ein flüchtiger Logigfehler drin...

Sorry war bis jetzt nicht am PC. Danke für die Antworten! Habe ich eine konkrete Frage überlesen?

Dachte die Zeile ist da um die Zeit einzustellen wenn man den Code hochlädt. Ähnlich wie bei den herkömmlichen RTS´s.

Da muss ich mir erstmal reinwursteln in den Code.
Danke für die zahlreichen Kommentare. Werd mir alles jetzt nochmal in Ruhe durchlesen und mein Code hinfriemeln. Ich stelle diesen dann wieder hier rein, kann aber ein paar Tage dauern...
Danke !!!

Ja.
Aber der zweite Parameter ist der Wochentag. Und der ist überflüssig.
Versuch mal was passiert, wenn Du den zweiten Parameter änderst und aus der 4 eine 5 machst.
Wenn sich dann der Wochentag ändert, obwohl das Datum gleich bleibt, ist das kompletter Unsinn.

Ich habs nur aufgeteilt. Schmeiss den mal auf den Controllino und mach den seriellen Monitor an.
Du bekommst alle Sekunde eine Ausgabe.
Wenn Du die Uhr stellst, dann so das Mitternacht zur Kontrolle nicht allzu spät ist und es sollte tun.

Sollte die Schaltlogik falsch sein, will heissen das relais zieht an, obwohl aus sein soll, dann musst Du die Logik umdrehen. Zeile:

einfach in LOW ändern. Rest bleibt wie er ist.

1 Like

Ich habe keinen Controllino, kann daher auch nicht testen.

Die RTC-Bibliothek scheint auf der RTClib zu basieren, ohne alle Funktionalitäten übernommen zu haben. Grundlage aller vieler Zeitrechnungen bildet eigentlich die Unixzeit, die es als unixtime oder epoch oder sowas gibt. Das sind die Sekunden ab 1.1.1970 oder einem anderen Startzeitpunkt. Mit diesen Zahlen kann man dann normal rechnen oder vergleichen.

Im Beispiel datecalc.ino findest Du Beispiele wie

TimeSpan ts1 = dt6 - dt5;
showTimeSpan("dt6-dt5", ts1);

Die Bibliothek unterstützt auch Vergleichsoperatoren.

Für den Fall, Du möchtest noch mehr mit Zeiten machen, könnte es hilfreich sein, die RTClib zu nutzen.

"aller" ist etwas zu hoch gegriffen.
Stimmt schon, wenn es um Zeitstempel mit Datum und Uhrzeit geht.
Aber wenn es nur drum geht zu entscheiden, ob 17:00 zwischen 18:00 und 06:00 liegt oder außerhalb, ist die Umrechnung auf UTC, bilden der unixtime und ein Vergleich mit Datentyp long etwas umständlich.

Schlampig formuliert, habe ich korrigiert.

Deswegen hatte ich ja auf "Für den Fall ..." eingeschränkt. Schade finde ich, daß die Controllino-Bibliothek diese Funktionalitäten nicht gleich eingebaut hat, wäre für den Anwenderkreis bestimmt hilfreich.

1 Like

Habe jetzt mal eine Code zusammen der scheinbar nach ein paar Test funktioniert.
Das Problem das das Relais beim Upload einmal triggert besteht nach wie vor. Ansonsten sollte das ganze soweit funktionieren meine ich.
Ich habe dennoch die Zeit in Millisekunden umgerechnet weil mir das psychisch irgendwie einfacher vorkommt mit einer Zahl von 0 bis 23:59:59 ( 233 600 000 + 5960 000 + 59*1000) zu rechnen. Ich denke es ist nicht die Ultimative Lösung aber es funktioniert soweit.....

#include <SPI.h>
#include <Controllino.h>

//BUTTON LOGIC
//switches
const byte switchPinPHASE1 = A1;
const byte switchPinPHASE2 = A2;
const byte relayPin = 30;

uint8_t onHour = 18;//Startstunde
uint8_t onMinute = 0;//Startminute
uint8_t offHour;
uint8_t offMinute;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  //BUTTON LOGIC
  //Switches
  pinMode(switchPinPHASE1, INPUT);
  pinMode(switchPinPHASE2, INPUT);
  //RTC
  Controllino_RTC_init();
  /* set time and date by separate values values to the RTC chip */
  /* Day, WeekDay, Month, Year, Hour, Minute, Second); */
  Controllino_SetTimeDate(12, 4, 1, 17, 19, 38, 0);
  /* or use another possibility and define the time and date by strings, e.g. "Nov 15 2018", "11:41:02" */
  /* following example uses predefined C macros __DATE__ and __TIME__ which represent compilation time */
  // Controllino_SetTimeDateStrings(__DATE__, __TIME__); /* set compilation time to the RTC chip */
  //Relay
  digitalWrite(relayPin, LOW);
  pinMode(relayPin, OUTPUT);
}

void loop() {

  int8_t h = Controllino_GetHour();
  int8_t m = Controllino_GetMinute();
  int8_t s = Controllino_GetSecond();

  unsigned long timeInMillis = h * 3600000UL + m * 60000UL + s * 1000;
  unsigned long ONtimeInMillis = onHour * 3600000UL + onMinute * 60000UL;

  Serial.print("t:");
  Serial.print(h);
  Serial.print(":");
  Serial.print(m);
  Serial.print(":");
  Serial.print(s);

  Serial.print(" timeInMillis: ");
  Serial.print(timeInMillis);

  //BUTTON LOGIC
  bool switchStatePHASE1 = digitalRead(switchPinPHASE1);
  bool switchStatePHASE2 = digitalRead(switchPinPHASE2);

  unsigned long OFFtimeInMillis;//unsigned long OFFtimeInMillis = h * 3600000UL + m * 60000UL;
  // unterschiedliche Modi aus Drehschalterstellung festlegen
  if (switchStatePHASE1 == HIGH && switchStatePHASE2 == LOW) {
    OFFtimeInMillis = ONtimeInMillis + 20 * 3600000UL;
  }
  else if (switchStatePHASE1 == LOW && switchStatePHASE2 == LOW) {
    OFFtimeInMillis = ONtimeInMillis + 10 * 3600000UL;
  }
  else if (switchStatePHASE1 == LOW && switchStatePHASE2 == HIGH) {
    OFFtimeInMillis = ONtimeInMillis + 5 * 3600000UL;
  }
  Serial.print(" OFFtimeInMillis: ");
  Serial.print(OFFtimeInMillis);

  unsigned long midnightMillis = 23 * 3600000UL + 59 * 60000UL + 59 * 1000UL;
  //Serial.print(" testEndZeit 23 Uhr: ");
  //Serial.print(testEndZeit);

  //Unterscheidung ob vor oder nach Mitternacht
  if (OFFtimeInMillis <= midnightMillis ) {
    if (timeInMillis >= ONtimeInMillis && timeInMillis <= OFFtimeInMillis) {
      digitalWrite(relayPin, HIGH);
    } else {
      digitalWrite(relayPin, LOW);
    }
  }
  if (OFFtimeInMillis >= midnightMillis) {
    if (timeInMillis >= ONtimeInMillis && timeInMillis <= midnightMillis || timeInMillis <= (OFFtimeInMillis - midnightMillis)) {
      digitalWrite(relayPin, HIGH);
    }
    else {
      digitalWrite(relayPin, LOW);
    }
  }
  Serial.println();
}

Danke für Deine Rückmeldung :slightly_smiling_face:

1 Like