MQTT Schleife vorzeitig unterbrechen

Hall0,
je nach gesendetem MQTT Topic Wert löse ich eine for-Schleife aus, die einfach nur bis 10 hochzählt. Publishe ich zb. eine 1, wird sie gestartet, bei 0 beendet, aber natürlich erst, wenn die 10 erreicht ist.
Ist es irgendwie via MQTT möglich, diese for-Schleife vorzeitig zu unterbrechen, also bevor 10 erreicht wird?

Gruß Kymchy

#include <ESP8266WiFi.h>
#include <PubSubClient.h>

/* Globals */
bool looprunning;


// Update these with values suitable for your network.
const char* ssid = "wFRITZ!Box";//put your wifi ssid here.
const char* password = "xxxxxxxxxxxxxxxx";//put your wifi password here.
const char* mqtt_server = "192.168.178.105";

WiFiClient espClient;
PubSubClient client(espClient);
long lastMsg = 0;
char msg[50];
int value = 0;

void setup_wifi() {
   delay(100);
  // We start by connecting to a WiFi network
    Serial.print("Connecting to ");
    Serial.println(ssid);
    WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) 
    {
      delay(500);
      Serial.print(".");
    }
  randomSeed(micros());
  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) 
{
  Serial.print("Command is : [");
  Serial.println(topic);
  int p =(char)payload[0]-'0'; 

  if(p == 0){
    looprunning = false;   
  } else{
    looprunning = true;
  }
  
  Serial.print("gesendeter MQTT Topic Wert: ");
  Serial.println(p);

  Serial.print("looprunning Wert: ");
  Serial.println(looprunning);
    
  Serial.println();
} //end callback

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) 
  {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    //if you MQTT broker has clientID,username and password
    //please change following line to    if (client.connect(clientId,userName,passWord))
    if (client.connect(clientId.c_str()))
    {
      Serial.println("connected");
     //once connected to MQTT broker, subscribe command if any
      client.subscribe("Arduino/Test/Loop/OnOff");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 6 seconds before retrying
      delay(6000);
    }
  }
} //end reconnect()


void loopme(){
  if(looprunning == true){
    for (int i = 0; i < 11; i++) 
      {
      Serial.print("Counter: ");
      Serial.println(i); 
      delay(100);
      }
    delay(1000);
  };
  
}


void setup() {
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);

}

void loop() {
  if (!client.connected()) {
    reconnect();
  } 

client.loop();
loopme();

delay(2000);
}

Hallo,
Du sprichst für mich in Rätseln. Die einzige for Schleife die ich sehe ist die.

void loopme(){
  if(looprunning == true){
    for (int i = 0; i < 11; i++) 
      {
      Serial.print("Counter: ");
      Serial.println(i); 
      delay(100);
      }
    delay(1000);
  };

und die willst Du vorzeitig verlassen ? Abhängig von was ?
Du könntest anstelle der festen 11 eine variable nutzen.
Aber der Sinn der Funktion st mir nicht klar
Heinz

Ja, diese for-Schleife ist gemeint. Die Sinnhaftigkeit sei erstmal dahingestellt, ist nur zu Testzwecken.
Die Schleife wird ausgelöst, wenn, wie ich schon schrieb, der Payload eines MQTT Topic einen bestimmten Wert bekommt. Das geschieht in der Callback Funktion. Ein neuer Payload kann aber nur ausgewertet werden, wenn die For-Schleife mindestens einmal komplett durchgelaufen ist.
Meine Frage ist nun, ob es möglich ist, den Payload des Topic auch innerhalb dieser Scheife auszuwerten, um dann ein Break zu veranlassen.

Ich verstehe es auch immer noch nicht. Aber ein genereller Tip für so was: Vergiss while und for Schleifen und auch delay. Wenn du auf Ereignisse reagieren willst benutzt man Statemaschienen und zum Timing in diesen dann millis. Am besten fängst du noch mal ganz neu an.

die Schleife soll Mal als Animation für einen LED Ring mit 60 LEDs dienen(Laufring). Warum sollte ich das nicht mit einer for-Schleife machen. Das habe ich in einem anderen Sketch schon so realisiert. Ich hatte diesen nur zu Testzwecken eingerichtet, um zu gucken, ob ich in einer Schleife ein MQTT Topic abfragen kann. Um mehr ging es mir nicht.

möchtest du dass
a) dein Sketch während der Animation weiterhin reagiert
oder
b) dein Sketch während der Animation für andere Aktivitäten blockiert ist?

Nur für den Fall dass du dich für b) entscheidest:
Führe aus, warum du "unterbrechen" willst.

ich denke Mal a wäre die richtige Antwort. Da der LED Ring 60 LEDs hat, dauert es eine Zeit, bis die Animation durchgelaufen ist. Die Animation zeigt mir an, ob eine Warmwasserzirkulationspumpe läuft. Diese steuere ich über Alexa. Stelle ich die Zirkulationspumpe ab, soll auch die Animation sofort stoppen. Das läuft jetzt auch schon so, bis auf die Tatsache, dass die Animation eben noch bis zu Ende läuft, wenn die Pumpe schon aus ist. Ist vielleicht etwas kleinkariert, vielleicht wollte ich es zu perfekt machen...
Ich hoffe, dass ich das jetzt einigermaßen verständlich erklärt habe, besser kann ichs, glaube ich, nicht.

na dann mach das ganze halt ohne blockaden:

Schritt 1:

/*
  Etwas laufen lassen nur wenn man es benötigt:
  https://forum.arduino.cc/t/mqtt-schleife-vorzeitig-unterbrechen/1170641/8
  2023-09-22 by noiasca
  code in sketch
*/

bool looprunning = true;

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

void loop() {
  //loopme();
  runNonBlocking();
}

void runNonBlocking() {
  if (looprunning == true) {
    static uint32_t previousMillis = 0;  // store timestamp
    static uint8_t i = 0;                // the iteration counter (old: i from for)
    const uint8_t iMax = 10;             // max iterations
    const uint16_t intervalShort = 100;  // old "delay(100)"
    const uint16_t intervalLong = 1000;  // old "delay(1000)"
    uint16_t interval = intervalShort;   // current interval
    if (i == 0)
      interval = intervalLong;
    if (millis() - previousMillis > interval) {
      previousMillis = millis();
      Serial.print("Counter: ");
      Serial.println(i);
      if (i == iMax) i = 0; else i++;
    }
  }
}

void loopme() {
  if (looprunning == true) {
    for (int i = 0; i < 11; i++)
    {
      Serial.print("Counter: ");
      Serial.println(i);
      delay(100);
    }
    delay(1000);
  };
}

Tipp: schau dir das Beispiel "Blink Without Delay" aus der IDE an.
Arbeite es so lange durch bis du es ohne nachsehen aus dem Kopf hinschreiben kannst.
Damit kannst du jede Nebenläufigkeit erledigen.

Schritt 2:
zum "abschalten" von Pixeln bräuchte man dann vermutlich noch einen else zweig falls looprunning (was wohl besser isAnimationRunning heißen soll) false wäre.

vielen Dank! Das wird mich dann wohl erstmal eine Weile beschäftigen...

Zeige mal die Animation. Ich zeige dir dann, wie es ohne for und delay geht.

vielen Dank!
ich habe es jetzt mit der runNonBlocking() Methode von noiasca gemacht und es funktioniert super.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.