Mqtt blockiert den Code wenn Brocker nicht sendet

digitalRead(Eingang[0] und digitalRead(Eingang[2] ist ein Schalter.

digitalRead(Eingang[1] ein Taster

Gruß Ralf

So, hier nun man fast fertiges Projekt :slight_smile:

#include <ArduinoMqttClient.h>
//#include <Ethernet.h>
#include <WiFi.h>

const char ssid[] = "xxx";
const char password[] = "xxx";
const char hostname[] = "xxx";
WiFiClient wlan;

//Ethernet
//const char hostname[] = "optasolar";
//EthernetClient lanclient;

//MQTT
MqttClient mqttClient(wlan);
const char broker[] = "xxx";
int port = 1883;
const char topic[] = "soc";

//Zeit
const uint32_t timeOut = 1000 * 30;
uint32_t startZeit = millis();



//LED
const int StatusLed[] = { LED_D0, LED_D1, LED_D2, LED_D3 };

const int SocSchaltpunkt[] = { 80, 20 };  // SOC-Schaltpunkt
const int NUM_LED_and_Relais = 4;

//Inputs
const int Eingang[] = { A0, A1, A2, A3, A4, A5, A6, A7 };
const int NUM_PINS = 8;

// Relais
int relais[] = { D0, D1, D2, D3 };

String buff = "";
int soc = 0;
int stufe = 2;
int umschaltsperre = 0;
int speicherMin = 80;



void setup() {
  Serial.begin(9600);
  // Initialize LED_BUILTIN as an output
  pinMode(LED_RESET, OUTPUT);
  pinMode(LEDR, OUTPUT);
  pinMode(LED_USER, OUTPUT);
  // Initialize LED_D0-D3 as an output
  for (int i = 0; i < NUM_LED_and_Relais; i++) {
    pinMode(StatusLed[i], OUTPUT);
    pinMode(relais[i], OUTPUT);
  }
  pinMode(BTN_USER, INPUT);

  for (int i = 0; i < NUM_PINS; i++) {
    pinMode(Eingang[i], INPUT);
  }

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    digitalWrite(LEDR, HIGH);
    delay(500);
    digitalWrite(LEDR, LOW);
    delay(500);
  }
  Serial.println("WiFi verbunden");


  // Ethernet
  //Ethernet.setHostname(hostname);
  //Ethernet.begin();

  // Connect to MQTT broker
  mqttClient.connect(broker, port);
  mqttClient.subscribe("soc");
  // set the message receive callback
  mqttClient.onMessage(onMqttMessage);
}

void getMQTTConnect() {
  //Steuerung, mqtt-Abfrage einschalten
  if (mqttClient.connected()) {
    digitalWrite(LED_USER, LOW);
  } else {
    Serial.print("MQTT connection failed! Error code = ");
    Serial.println(mqttClient.connectError());
    digitalWrite(LED_USER, HIGH);
    delay(5000);
  }
}


void loadType()  //Ladestrom, Ladestufen
{
  if (digitalRead(Eingang[1]) == LOW) {
    umschaltsperre = 0;
  }

  if (umschaltsperre == 0) {
    switch (stufe) {
      case 1:
        digitalWrite(relais[1], HIGH);
        digitalWrite(StatusLed[1], HIGH);
        delay(500);
        digitalWrite(relais[1], LOW);
        digitalWrite(StatusLed[1], LOW);
        stufe = 2;
        umschaltsperre = 1;
        break;

      case 2:
        digitalWrite(relais[1], HIGH);
        digitalWrite(StatusLed[1], HIGH);
        delay(500);
        digitalWrite(relais[1], LOW);
        digitalWrite(StatusLed[1], LOW);
        delay(500);
        digitalWrite(relais[1], HIGH);
        digitalWrite(StatusLed[1], HIGH);
        delay(500);
        digitalWrite(relais[1], LOW);
        digitalWrite(StatusLed[1], LOW);
        stufe = 3;
        umschaltsperre = 1;
        break;

      case 3:
        digitalWrite(relais[1], HIGH);
        digitalWrite(StatusLed[1], HIGH);
        delay(500);
        digitalWrite(relais[1], LOW);
        digitalWrite(StatusLed[1], LOW);
        delay(500);
        digitalWrite(relais[1], HIGH);
        digitalWrite(StatusLed[1], HIGH);
        delay(500);
        digitalWrite(relais[1], LOW);
        digitalWrite(StatusLed[1], LOW);
        delay(500);
        digitalWrite(relais[1], HIGH);
        digitalWrite(StatusLed[1], HIGH);
        delay(500);
        digitalWrite(relais[1], LOW);
        digitalWrite(StatusLed[1], LOW);
        delay(500);
        stufe = 1;
        umschaltsperre = 1;
        break;


      default:
        stufe = 1;
        break;
    }
  }
}

void stufe_1() {
  digitalWrite(relais[1], HIGH);
  digitalWrite(StatusLed[1], HIGH);
  delay(500);
  digitalWrite(relais[1], LOW);
  digitalWrite(StatusLed[1], LOW);
  delay(500);
}


void onMqttMessage(int messageSize) {


  buff = "";

  while (mqttClient.available()) {
    char c = mqttClient.read();
    buff += c;
  }
  soc = buff.toInt();
  Serial.println(soc);
  startZeit = millis();
}

void loop() {

  mqttClient.poll();
  getMQTTConnect();

  //Überrwachung für Ausfall vom Brocker
  if (millis() - startZeit > timeOut) {
    soc = 0;
    digitalWrite(LED_RESET, HIGH);
  } else {
    digitalWrite(LED_RESET, LOW);
  }


  //Steuerung einschalten
  if (digitalRead(Eingang[0]) == HIGH && soc != 0 && soc > speicherMin) {
    digitalWrite(relais[0], HIGH);
    digitalWrite(StatusLed[0], HIGH);
  } else {
    digitalWrite(relais[0], LOW);
    digitalWrite(StatusLed[0], LOW);
  }



  if (digitalRead(Eingang[1]) == HIGH) { loadType(); }
  if (digitalRead(Eingang[2]) == HIGH) {
    speicherMin = SocSchaltpunkt[0];
  } else {
    speicherMin = SocSchaltpunkt[1];
  }
}

Die delay()s musst Du noch auflösen.
Ich komm erst morgen zu irgendwas. Aber die Auflösung hab ich schon angefangen :slight_smile:

Die delay()s musst Du noch auflösen.

Das interessiert ich wie du das machst.

Jung, ich lerne mit 58Jahren noch was dazu :slight_smile:

Junger Hüpfer :grin:
OK, ich bau Dir das fertig, wenn ich den anderen durch habe, den ich schon versprochen hatte.
Und ich las Dir alle 100ms auf dem seriellen Monitor einen tick ausgeben, was mit delays() so nicht gehen würde :slight_smile:

1 Like

Die Delays werden wieder mit millis realsiert?

const uint32_t pause = 500
uint32_t intervallStart = millis()

if (intervallStart + pause < millis()) {
          digitalWrite(relais[1], LOW);
          digitalWrite(StatusLed[1], LOW);
        }

Dann schaffe ich das

Ja.
Aber nicht so, sondern:
AktuelleZeit - letzteZeit "Prüfung auf" Intervall.
Wobei "Prüfung auf" alles sein kann.

Bei Prüfung auf Zeitablauf hat sich >= als sinnvoll erwiesen, und wenn Du auf noch nicht abgelaufen prüfst, dann < als Operant.

Also wäre eine Pause mit
millis()-lastTime>=1000
Die bevorzugte Variante. Du gehst sonst in Gefahr, dass es beim Überlauf von millis() nach gutgehend 49Tagen zu komischen Dingen kommt.

Ist etwas gegen While einzuwenden?

        intervallStart = millis();
        while (millis() - intervallStart <= ontime) {
          digitalWrite(relais[1], HIGH);
          digitalWrite(StatusLed[1], HIGH);
        }
        intervallStart = millis();
        while (millis() - intervallStart <= ontime) {
          digitalWrite(relais[1], LOW);
          digitalWrite(StatusLed[1], LOW);
        }

Ja, weil das wieder blockierend ist. Die Funktion loop() ist im Prinzip schon eine Schleife. Darum heißt sie auch so. Die While Anweisung blockiert die loop() wieder so lange, bis die Bedingung zutrifft. Das ist dann auch wieder nichts anderes als ein delay().

1 Like

Ok, kam mir auch gleich komisch vor. Danke

Erklärung kam ja schon von @Kai-R
Wenn Du das if() benutzt bekommst den selben Effekt, ob das mit der Prüfung auf <= sinnvoll ist, kann nan sich drüber streiten. Ich würde es nicht machen.

Nach meiner Meinung muss die Taktung aus dem Unterprogramm raus und in die Hauptschleife.

Denn nur hier wird der “Timer-Abfrage” regelmäßig überlaufen.

Nein.
Das löst man mit Funktionsaufrufen und entweder mit Übergabeparametern oder schrittketten.

vielleicht hab ich nach dem umsteigen mehr Platz als fürs Handy.

im loop()
rufst Du z.B:
heartBeat(500);

und dann die Funktion:

void heartbeat(const uint32_t freg)
{
  static uint8_t lastTick = 0;

  if (millis() - lastTick > freq)
  {
    lastTick = millis();
    Serial.println(F("TIK"));
  }
}

Als Schrittkette geht das auch, die Du aus dem loop() heraus nur mit schrttKette() aufrufst.


void schrittKette()
{
  static uint8_t myNumber = 0;

  switch (myNumber)
  {
    case 0:
      intervallStart = millis();
      digitalWrite(relais[1], LOW);
      digitalWrite(StatusLed[1], LOW);
      myNumber = 1;
      break;

    case 1:
      if (millis() - intervallStart >= ontime)
      {
        intervallStart = millis();
        digitalWrite(relais[1], HIGH);
        digitalWrite(StatusLed[1], HIGH);
        myNumer = 2
      }

      break;

    case 2:

      // hier auf irgendwas warten, was auslöst
      if (millis() - intervallStart > 10000)
      {
        myNUmber = 0;
      }

      break;
  }
}

Da kann man ggfls. auch Rückgabeparameter setzen, etc...

Ohne Anspruch auf irgendwas - nur damit Du mal siehst, wie das funktionieren kann.

1 Like

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