Optimieren einer Funktion mit einem Array?!

Hallo zusammen,

ich habe mir folgende Funktion zusammengebastelt die ich regelmäßig aufrufe um vier DHT22 Sensoren auszulesen und die Daten per MQTT zu verschicken.

void dht22_reading()
{
  //------------DHT22 Sensor 1-------------
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  float h = dht.readHumidity();
  // Read temperature as Celsius (the default)
  float t = dht.readTemperature();

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t)) {
    Serial.println(F("Failed to read from DHT sensor 1!"));
  }
  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t, h, false);

  Serial.print(F("Humidity h1: "));
  Serial.print(h);
  Serial.print(F("%, "));
  Serial.print(F("Temperature t1: "));
  Serial.print(t);
  Serial.print(F("°C, "));
  Serial.print(F("Heat index t1: "));
  Serial.print(hic);
  Serial.println(F("°C"));

  Serial.print(F("Senden der MQTT Nachrichten für Sensor 1: "));
  Serial.print(String(hic).c_str());
  client.publish("/SmartHome/Feldgeraet/Mega2560/DHT1/t/", String(hic).c_str());
  Serial.print(F(" "));
  Serial.println(String(h).c_str());
  client.publish("/SmartHome/Feldgeraet/Mega2560/DHT1/h/", String(h).c_str());


  //------------DHT22 Sensor 2-------------
  h = dht2.readHumidity();
  // Read temperature as Celsius (the default)
  t = dht2.readTemperature();

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t)) {
    Serial.println(F("Failed to read from DHT sensor 2!"));
    return;
  }
  // Compute heat index in Celsius (isFahreheit = false)
  hic = dht2.computeHeatIndex(t, h, false);

  Serial.print(F("Humidity h2: "));
  Serial.print(h);
  Serial.print(F("%, "));
  Serial.print(F("Temperature t2: "));
  Serial.print(t);
  Serial.print(F("°C, "));
  Serial.print(F("Heat index t2: "));
  Serial.print(hic);
  Serial.println(F("°C"));

  Serial.print(F("Senden der MQTT Nachrichten für Sensor 2: "));
  Serial.print(String(hic).c_str());
  client.publish("/SmartHome/Feldgeraet/Mega2560/DHT2/t/", String(hic).c_str());
  Serial.print(F(" "));
  Serial.println(String(h).c_str());
  client.publish("/SmartHome/Feldgeraet/Mega2560/DHT2/h/", String(h).c_str());

  //------------DHT22 Sensor 3-------------
  h = dht3.readHumidity();
  // Read temperature as Celsius (the default)
  t = dht3.readTemperature();

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t)) {
    Serial.println(F("Failed to read from DHT sensor 3!"));
    return;
  }
  // Compute heat index in Celsius (isFahreheit = false)
  hic = dht3.computeHeatIndex(t, h, false);

  Serial.print(F("Humidity h3: "));
  Serial.print(h);
  Serial.print(F("%, "));
  Serial.print(F("Temperature t3: "));
  Serial.print(t);
  Serial.print(F("°C, "));
  Serial.print(F("Heat index t3: "));
  Serial.print(hic);
  Serial.println(F("°C"));

  Serial.print(F("Senden der MQTT Nachrichten für Sensor 3: "));
  Serial.print(String(hic).c_str());
  client.publish("/SmartHome/Feldgeraet/Mega2560/DHT3/t/", String(hic).c_str());
  Serial.print(F(" "));
  Serial.println(String(h).c_str());
  client.publish("/SmartHome/Feldgeraet/Mega2560/DHT3/h/", String(h).c_str());
  
  //------------DHT22 Sensor 4-------------
  h = dht4.readHumidity();
  // Read temperature as Celsius (the default)
  t = dht4.readTemperature();

  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t)) {
    Serial.println(F("Failed to read from DHT sensor 4!"));
    return;
  }
  // Compute heat index in Celsius (isFahreheit = false)
  hic = dht4.computeHeatIndex(t, h, false);

  Serial.print(F("Humidity h4: "));
  Serial.print(h);
  Serial.print(F("%, "));
  Serial.print(F("Temperature t4: "));
  Serial.print(t);
  Serial.print(F("°C, "));
  Serial.print(F("Heat index t4: "));
  Serial.print(hic);
  Serial.println(F("°C"));

  Serial.print(F("Senden der MQTT Nachrichten für Sensor 4: "));
  Serial.print(String(hic).c_str());
  client.publish("/SmartHome/Feldgeraet/Mega2560/DHT4/t/", String(hic).c_str());
  Serial.print(F(" "));
  Serial.println(String(h).c_str());
  client.publish("/SmartHome/Feldgeraet/Mega2560/DHT4/h/", String(h).c_str());
}

Es wird im Prinzip für jeden Sensor hintereinander das gleiche ausgeführt.
Nun habe ich überlegt, ob man das ganze nicht zusammenfassen könnte, mit einem Array in einer for-schleife. Ich bin Anfänger und weiß ga rnicht ob das ganze überhaupt Sinn macht und funktioniert.
Ich habe sowas probiert:

byte dhtS[] = {0, 1, 2, 3};
  for (byte i = 0; i < 4; i = i + 1) {
    Serial.print("Auslesen von Sensor ");
    Serial.println(dhtS[i]);
    float h = dht[i].readHumidity();

das geht natürlich nicht, aber es soll darstellen was ich gerne tun würde. liegt es an der deklaration von i? Ich sehe irgendwie den Wald vor lauter Bäumen nicht. Vielleicht kann mir einer helfen das ich weiter komme.

Was du brauchst ist ein Array aus DHT Objekten

DHT sensors[] = { { 2, DHT22}, { 3, DHT22}, .... };  //hier die Pins angeben

void loop()
{
    for { DHT& sensor : sensors }
    {
       float h = sensor.readHumidity();
       float t = sensor.readTemperature();

       ...
    }
}

Ich danke euch schonmal, weil ich einen großen Schritt weiter gekommen bin. Ich deklariere jetzt das ganze so:

#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
const int maxDHT = 4;
int pins[maxDHT] = {46, 47, 48, 49};
DHT *dht[maxDHT]; // array of 4 pointers to DHTs

und im Setup so:

 for (int n = 0; n < maxDHT; n++)
  {
    dht[n] = new DHT(pins[n], DHTTYPE); // define a sensor at pin 'n' with sensor type DHT11
    dht[n]->begin();
  }

und meine Funktion “dht_reading();” sieht jetzt folgendermaßen aus:

void dht22_reading()
{
  //------------DHT22 Sensoren-------------
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  for (int n = 0; n < maxDHT; n++)
  {
    float h = dht[n]->readHumidity();
    float t = dht[n]->readTemperature();

    // Check if any reads failed and exit early (to try again).
    if (isnan(h) || isnan(t)) {
      Serial.println();
      Serial.print(F("Failed to read from DHT Sensor: "));
      Serial.print(n);
    }
    // Compute heat index in Celsius
    float hic = dht[n]->computeHeatIndex(t, h, false);

    Serial.println();
    Serial.print(F("Humidity h"));
    Serial.print(n);
    Serial.print(F(": "));
    Serial.print(h);
    Serial.print(F("%, "));
    Serial.print(F("Temperature t"));
    Serial.print(n);
    Serial.print(F(": "));
    Serial.print(t);
    Serial.print(F("°C, "));
    Serial.print(F("Heat index t"));
    Serial.print(n);
    Serial.print(F(": "));
    Serial.print(hic);
    Serial.println(F("°C"));

    Serial.print(F("Senden der MQTT Nachrichten für Sensor"));
    Serial.print(n);
    Serial.print(F(": "));
    Serial.print(String(h).c_str());
    //client.publish("/SmartHome/Feldgeraet/Mega2560/DHT1/h/", String(h).c_str());
    Serial.print(F(" "));
    Serial.print(String(hic).c_str());
    //client.publish("/SmartHome/Feldgeraet/Mega2560/DHT1/t/", String(hic).c_str());
  }
}

das funktioniert schonmal sehr gut :smiley: .
Was mir aber nicht klar ist wie ich dem Aufruf

client.publish("/SmartHome/Feldgeraet/Mega2560/DHT*/t/", String(hic).c_str());

dem String da wo ich das * gemacht habe die variable n übergebe.

noiasca:
ich kenne nicht was dein .publish erwartet.

Aber mitteles itoa bekommst du aus einem integer einen string itoa - C++ Reference

apropos Integer: deine for (int n = 0 kannst kürzen auf for (byte n = 0

Also soweit ich rausgefunden habe erwartet es ein char?!?

ein Serial.print habe ich z.B so hinbekommen:

Serial.print("/SmartHome/Feldgeraet/Mega2560/DHT/t" + String(n, DEC) + "/ ");

wenn ich jetzt versuche das auf client.publish zu übertragen, mein Versuch

client.publish(("/SmartHome/Feldgeraet/Mega2560/DHT/t" + String(n, DEC) + "/"), String(t).c_str());

Dann meckert der Compiler mit no matching function for call to 'PubSubClient::publish(StringSumHelper&, const char*)'

muss ich jetzt ein char array anlegen?

const char header[] = "/SmartHome/Feldgeraet/Mega2560/DHT/t"; // ist auch mit Nullterminator

Gruß Tommy

Ihr seid echt super! Meine Funktion sieht jetzt so aus und alles scheint auch zu funktionieren.

void dht22_reading()
{
  //------------DHT22 Sensoren-------------
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  for (byte n = 0; n < maxDHT; n++)
  {
    float h = dht[n]->readHumidity();
    float t = dht[n]->readTemperature();

    // Check if any reads failed and exit early (to try again).
    if (isnan(h) || isnan(t)) {
      Serial.println();
      Serial.print(F("Failed to read from DHT Sensor: "));
      Serial.print(n);
    }
    // Compute heat index in Celsius
    float hic = dht[n]->computeHeatIndex(t, h, false);

    Serial.println();
    Serial.print(F("Humidity h"));
    Serial.print(n);
    Serial.print(F(": "));
    Serial.print(h);
    Serial.print(F("%, "));
    Serial.print(F("Temperature t"));
    Serial.print(n);
    Serial.print(F(": "));
    Serial.print(t);
    Serial.print(F("°C, "));
    Serial.print(F("Heat index t"));
    Serial.print(n);
    Serial.print(F(": "));
    Serial.print(hic);
    Serial.println(F("°C"));

    const char header[] = {"/SmartHome/Feldgeraet/Mega2560/DHT/t\0"}; // mit Nullterminator
    const byte bufferLength = 40;
    char myBuffer [bufferLength];
    char temp[4]; // 3 stellen + \0
    Serial.print(F("Senden der MQTT Nachrichten für Sensor "));
    Serial.print(n);
    Serial.println(F(": "));
    itoa(n, temp, 10);
    strcpy(myBuffer, header);
    strcat(myBuffer, temp);
    Serial.print(myBuffer);
    Serial.print(F(" "));
    Serial.println(String(hic).c_str());
    client.publish(myBuffer, String(hic).c_str());

    const char header2[] = {"/SmartHome/Feldgeraet/Mega2560/DHT/h\0"}; // mit Nullterminator
    char hum[4]; // 3 stellen + \0
    itoa(n, hum, 10);
    strcpy(myBuffer, header2);
    strcat(myBuffer, hum);
    Serial.print(myBuffer);
    Serial.print(F(" "));
    Serial.println(String(h).c_str());
    client.publish(myBuffer, String(h).c_str());
  }
}

ich weiß nicht ob ich das mit der “Doppelverwendung” von myBuffer richtig gemacht habe, ich benötige es für zwei Werte die jeder Sensor leifert. Es funktioniert, aber vielleicht mag sich das nochmal jemand anschauen.

Danke für den Hinweis.

ich habe jetzt folgendes angepasst:

const byte bufferLength = 42;
itoa(n, temp, 7);
itoa(n, hum, 6);

temp hat ja noch ein Vorzeichen und hum geht von 0-100.00, ist meine Änderung richtig?

Der 3. Parameter hat nichts mit Stellen zu tun, sondern ist die Basis des Zahlensystems. Das ist hier immer 10 für Dezimal. Lies dir die Doku der Funktion durch!

Wenn du Nachkommastellen willst brauchst du dtostrf():
https://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html#ga060c998e77fb5fc0d3168b3ce8771d42

Das mit dem Array aus Zeigern auf Objekten ist übrigens unnötig kompliziert. Es geht ja, aber man kann auch die Objekte direkt in ein Array packen

Danke,

jetzt habe ich es so umgebaut:

#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
const int maxDHT =4;
int pins[maxDHT] = {46, 47, 48, 49};
DHT dht[maxDHT] = {DHT(pins[0], DHTTYPE),DHT(pins[1], DHTTYPE ),DHT(pins[2], DHTTYPE),DHT(pins[3], DHTTYPE)};

Im Setup dann so:

for (byte n = 0; n < maxDHT; n++)
  {
    dht[n].begin();
  }

und meine Funktion zum auslesen so:

void dht22_reading()
{
  //------------DHT22 Sensoren-------------
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  for (byte n = 0; n < maxDHT; n++)
  {
    float h = dht[n].readHumidity();
    float t = dht[n].readTemperature();

    // Check if any reads failed and exit early (to try again).
    if (isnan(h) || isnan(t)) {
      Serial.println();
      Serial.print(F("Failed to read from DHT Sensor: "));
      Serial.print(n);
    }
    // Compute heat index in Celsius
    float hic = dht[n].computeHeatIndex(t, h, false);

    Serial.println();
    Serial.print(F("Humidity h"));
    Serial.print(n);
    Serial.print(F(": "));
    Serial.print(h);
    Serial.print(F("%, "));
    Serial.print(F("Temperature t"));
    Serial.print(n);
    Serial.print(F(": "));
    Serial.print(t);
    Serial.print(F("°C, "));
    Serial.print(F("Heat index t"));
    Serial.print(n);
    Serial.print(F(": "));
    Serial.print(hic);
    Serial.println(F("°C"));

    const char header[] = {"/SmartHome/Feldgeraet/Mega2560/DHT/t"};
    const byte bufferLength = 40;
    char myBuffer [bufferLength];
    char temp[4]; // 3 stellen + \0
    Serial.print(F("Senden der MQTT Nachrichten für Sensor "));
    Serial.print(n);
    Serial.println(F(": "));
    itoa(n, temp, 10);
    strcpy(myBuffer, header);
    strcat(myBuffer, temp);
    Serial.print(myBuffer);
    Serial.print(F(" "));
    Serial.println(String(hic).c_str());
    client.publish(myBuffer, String(hic).c_str());

    const char header2[] = {"/SmartHome/Feldgeraet/Mega2560/DHT/h"};
    char hum[4]; // 3 stellen + \0
    itoa(n, hum, 10);
    strcpy(myBuffer, header2);
    strcat(myBuffer, hum);
    Serial.print(myBuffer);
    Serial.print(F(" "));
    Serial.println(String(h).c_str());
    client.publish(myBuffer, String(h).c_str());
  }
}

Jetzt habe ich ein Array direkt aus dem Objekt(Class?) “DHT”? Und “dht” nennt man eine Instanz? Voher bestand das array aus pointer/zeiger auf das Objekt, richtig? :confused:
Dem Compiler ist es ziemlich egal, gleiche größe, ist wahrscheinlich auch logisch ::slight_smile:

Danke für den hilfreichen Input.