Sketch für ESP8266 16 Relay

Hallo Zusammen, ich suche jemand der mir den passenden Sketch für die Steuerung der Relaiskarte schreibt. Diese ist simpel...

Es soll ein Shelly das Eingangssignal ON/OFF liefern.

Die 16 Relais sollen der Reihe nach sich Einschslten, mit jedem weiteren ON Zustand soll das nächste Relais Einschalten und so lange an bleiben, wie das ON Signal vom Shelly kommt(alle anderen Relais sollen aus sein). Es soll nur 1 Relais an sein.

Hintergrund: es soll der 6 fach Wasserverteiler von Gardena durch einzelne Magnetventile ersetz werden. Der Wasserverteiler ist eine Art Revolver und setzt immer eine Stufe weiter mit dem Wasserhahn AUF und ZU Signal, was durch den Shelly (Funksteckdose) und Magnetventil realisiert wird

PS ich gebe dafür auch sehr gern etwas...

Das wäre die 8266 16 Relais Platine

Was ist bitte ein Shelly?

W-Lan Schalter. Shelly PM1 z.B.

Bist du dir sicher, dass dein Shelly dauernd ein ON Signal sendet ?

Ja, der Shelly schaltet aktuell das 24V AC Netzteil für das Rainbird Magnetventil und das Magnetventil schaltet nur wenn Spannung anliegt, oder fällt ab, wenn keine Spannung anliegt.

Das ist im prinzip ganz einfach, mit jedem EIN-schalten erhöhst Du einen Zähler um 1 und das jeweilige Relais wird damit ausgewählt.
Was mir fehlt: Was passiert, wenn das Shelly länger aus bleibt?
Soll dann der Wert erhalten bleiben oder dann zurück auf 0?
-> Hintergrund: Wenn Du mit länger Pause den Kanal zurücksetzt, könntest Du zwischendurch einfach anhalten und neu starten - sonst müsstest Du immer bis 16 durchschalten um wieder auf 0 zu kommen.

Was genau schaltet das Shelly ?
Die 24 Volt oder dier 230 Volt ?

Schön wäre natürlich, wenn man den Sketch für 16 Schreibt aber im Sketch eine Option einbaut wenn man nur mit 4 Magnetventilen arbeitet, quasie nur von 1 bis 4 durch arbeitet.

Aber sonst wäre es auch kein Problem, da man ja die Relais am Ende auf das gleich Magnetventil legen kann, sodaß quasie bei 4 Verlauten, daß 1 und das 5 und das 9 und das 13 Relais das gleiche Magnetventil schaltet.

Wenn der Shelly länger aus bleibt äre es ein geniales Feature, daß er z.B. nach 4Stunden wieder beim 1 Relais anfängt.

potententialfrei

lautet die richtige Antwort auf die falsche Frage.

Der Shelly kann alles shalten. Es ist ein Potentialfreier Kontakt und wenn nicht, wird durch Zusatzrelais dies ermöglicht.

Die Vorgabe kann man in die Software giessen oder z.B. mit 2 Eingangspins aka 2 bit auflösen.
Ich kann Dir schnell die 20 zeilen zusammenschreiben. Aber ich hab keinen ESP.

Was hast'n für Hardware?

Das glaub ich unbesehen. Dennoch sagt das nichts darüber, wie du es schaltest.
Aber ok, auch gut.

Ich würde so ein Ding bestellen wollen.... Ist ja fast schon Mundgerecht.

Klasse, wenn du das für mich machen kannst.... Den Obolus machen wir dann per PN......

Aber ich muss erst mal das Ding bestellen....

Du bist doch sonst auch nicht so unbewandert.
Der Shelly kommt mit einem NO zwischen GND und einem Pin.
Dann kommt ein debounce von 100ms rein und ein Timer auf millis()-basis für den reset und ein Zähler der den Umlauf mitzählt.

Gesteuert wird als Ausgabe ein array mit den Pins - fettig. :wink:

Den obolus spar Dir für ein gutes C++ Buch.
Den Zähler bau ich, testen lässt sich das bestimmt mit irgendeinem NodeMCU oder so; Da findet sich vielleicht jemand.

Na denne

1000 Dank, ich order mal so ne Platine....
und melde mich wenn se da ist...

Und ich hab nen paar Zeilen geklimpert.

// forensketch - simpler Zähler und out auf Array
// Relaisplatine schalten - erster Anlauf mit 16 Relais
// https://forum.arduino.cc/t/sketch-fur-esp8266-16-relay/1123972/17

constexpr uint8_t inputPin = 2;                                                          // Eingang
constexpr uint8_t relais[] = {3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18};  // Alle relaispins
constexpr uint8_t relaisNums = sizeof(relais) / sizeof(relais[0]);                       // errechnet die Anzahl der relais

constexpr uint32_t debounceTime = 100;                                                   // großzügig ;)
constexpr uint32_t resetTime  =  1000UL * 60 * 60 * 4; // 1000ms = 1sek * 60 = 1Min *60 = 1Std * 4 = 4 Std

constexpr bool OFF = LOW;                         // Sollten die relais LOW-Aktiv sein, kommt hier HIGH rein.

uint32_t switchTime;                              // Merker für letzten Schaltzustand
uint8_t zaehler;                                  //

void setup()
{
  pinMode(inputPin, INPUT_PULLUP);                // Pin schaltet nach GND
  for (uint8_t b = 0; b < relaisNums; b++)        // durch alle relais zaehlen
  {
    pinMode(relais[b], OUTPUT);                   //
    digitalWrite(relais[b], OFF);                 //
  }
}

void loop()
{
  switch2Zaehler();
  timer2Zaehler();
  setRelais();
}


void switch2Zaehler()                             // Die Funktion löst bei Eingangsflanke HIGH/LOW aus
{
  static bool lastSwitch = false;                 // Merker letzter Zustand
  if (!digitalRead(inputPin))                     // wenn ausgelöst
  {
    if (!lastSwitch)                              // und vorher nicht
    {
      lastSwitch = true;                          // merken das ausgelöst
      zaehler++;                                  // zaehler erhöhen
      if (zaehler > relaisNums)                   // Grenze überschritten?
      { zaehler = 0; }                            // dann zurücksetzen
      switchTime = millis();                      // zeit merken
    }
  }
  else if (millis() - switchTime > debounceTime)  // Entprellt
  {
    lastSwitch = false;                           // und losgelassen
  }
}

void timer2Zaehler()
{
  if (millis() - switchTime > resetTime)          // Zeit abgelaufen
  {
    zaehler = 0;                                  // Vergessenen Shelly...
    //switchTime=millis();
  }
}

void setRelais()
{
  static uint8_t lastZaehler = 0;
  if (lastZaehler != zaehler)                       // Zaehlerstand hat sich geändert
  {
    for (uint8_t b = 0; b < relaisNums; b++)        // Durch alle zaehlen
    {
      digitalWrite(relais[b], OFF);                 // und aus machen
    }
    lastZaehler = zaehler;                          // zaehler merken
  }
  if (zaehler != 0)
  { digitalWrite(zaehler - 1, !OFF); }                // aktuellen zaehler einschalten
}

Das schlimmste sind immer die Kommentare verständlich zu schreiben...
Der hier würde jetzt mit/auf einem UNO laufen.
Das auf den ESP zu bringen, ist Kleinkram. Da müssen nur die Pins angepasst werden - fertig.

Noch'n Nachtrag:
Offensichtlich ist es das Board - Da ist die komplette Anschlussbelegung für die Schieberegister drin.
Also nur umschreiben und gut ist.

1 Like

Das ist echt Mega! Ich werde mein Glück versuchen.

.... und meld ich ....

bei Tasmota gibts eine Pin-Belegung:

GPIO # Component
GPIO00 User
GPIO01 User
GPIO02 User
GPIO03 User
GPIO04 User
GPIO05 74x595 OE
GPIO09 User
GPIO10 User
GPIO12 74x595 RCLK
GPIO13 74x595 SRCLK
GPIO14 74x595 SER
GPIO15 User
GPIO16 User
GPIO17 User

du könntest dir eine Funktion schreiben, die statt an digitalWrite auf die shift register ausgibt. Da du eh immer nur ein Relais einschalten willst, sollte das eigentlich ziemlich einfach sein.

edit mal zum testen:

/*
    expand outputs with shift registers
    activate one output after another
    https://forum.arduino.cc/t/sketch-fur-esp8266-16-relay/1123972

    2023-05-07 by noiasca
    sketch in tread
*/

const uint8_t buttonPin = 19; // a button 
const uint8_t stcpPin = 12;   // GPIO12 	74x595 RCLK/STCP
const uint8_t shcpPin = 13;   // GPIO13 	74x595 SRCLK/SHCP
const uint8_t serPin = 14;    // GPIO14 	74x595 SER/DS
const uint8_t oePin = 5;      // GPIO05 	74x595 OE/output enable active low

const uint8_t output[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}; // the used outputs, can also be used to change the order of the outputs
//const uint8_t output[] {0, 8, 7, 15};
int actual = -1;              // the actual output. -1 = all off

// generic shift out to two 74HC595 shift registers
void hc595Write(uint8_t pin, uint8_t val) {
  if (pin > 15) return;       // sanitize input
  static uint16_t state = 0;  // remember the state of all outputs in a bitmask
  if (val == HIGH) {
    state |= (1 << pin);      // activate the pin in the bitmask
  }
  else {
    state &= ~(1 << pin);     // deactivate the pin in the bitmask
  }
  digitalWrite(stcpPin, LOW);
  shiftOut(serPin, shcpPin, MSBFIRST, state >> 8);   // send the higher nibble to second 74HC595
  shiftOut(serPin, shcpPin, MSBFIRST, state & 0xFF); // send the lower nibble to first 74HC595
  digitalWrite(stcpPin, HIGH);
}

// switch on next output
void next() {
  actual++;
  if (actual >= sizeof(output)) {
    actual = 0;      // wrap around
  }
  hc595Write(output[actual], HIGH);  // switch on new
  Serial.println(output[actual]);
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println("Hello, ESP32!");
  pinMode(buttonPin, INPUT);
  pinMode(stcpPin, OUTPUT);
  pinMode(shcpPin, OUTPUT);
  pinMode(serPin, OUTPUT);
  pinMode(oePin, OUTPUT);
  digitalWrite(oePin, LOW); // enable the output

  /*
    // only testing
    hc595Write(0, HIGH);  // single write
    delay(500);
    hc595Write(0, LOW);
    delay(500);
    hc595Write(8, HIGH);
    delay(500);
    hc595Write(0, LOW);
  */
} 

void loop() {
  //"state change detection" taken from the IDE example and modified for this sketch
  static int lastButtonState = HIGH;         // needs to be static as it must survive the local scope of loop
  // read the pushbutton input pin:
  int buttonState = digitalRead(buttonPin);  // a local variable is ok as we read in each iteration of loop
  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == HIGH) {
      // if the current state is HIGH then the button went from off to on:
      //Serial.println("on");
      next();
    } else {
      // if the current state is LOW then the button went from on to off:
      // switch off old
      hc595Write(output[actual], LOW);
    }
    // Delay a little bit to avoid bouncing
    delay(50);
  }
  // save the current state as the last state, for next time through the loop
  lastButtonState = buttonState;

  //delay(10);     // only for this simulator!!!
}


1 Like

So soll es funktionieren., Ah, nein nicht ganz, der Input Knopf, soll nur bei Dauernter Betätigung, die LED Abschalten, wenn der Knopf los gelassen wird, muss auch die LED ausgehen.

Gibt es da einen Unterschied zum ESP8266 ?