SDS011 Feinstaubsensor, zyklische Abfrage

Hallo liebe Community,

ich versuche gerade einen Feinstaubsensor (SDS011) alle X Minuten aus den Deepsleep zu wecken, dann für X Sekunden laufen zu lassen um dann die Messwerte zu ermitteln und danach wieder schlafen zu schicken.
Dafür habe ich auch einen Beispielcode der gut funktioniert, leider mit delay().
Die Bibliothek habe ich von hier:GitHub - lewapek/sds-dust-sensors-arduino-library: Library for Nova Fitness SDS dust sensors family (SDS011, SDS021)

#include <Arduino.h>
#include <SdsDustSensor.h>

#define PM_SERIAL_RX D7
#define PM_SERIAL_TX D8

SdsDustSensor sds(PM_SERIAL_RX, PM_SERIAL_TX);
float pm25, pm10;

void setup()
{
  Serial.begin(74880);
  while (!Serial)
  {
  } // Wait for Serial to start
  delay(750);
  sds.begin();

  Serial.println();
  Serial.println(sds.queryFirmwareVersion().toString());  // prints firmware version
  Serial.println(sds.setQueryReportingMode().toString()); // ensures sensor is in 'query' reporting mode
}

void loop()
{
  sds.wakeup();
  delay(30000); // working 30 seconds

  PmResult pm = sds.queryPm();
  if (pm.isOk())
  {
    Serial.print("PM2.5 = ");
    Serial.print(pm.pm25);
    Serial.print(", PM10 = ");
    Serial.println(pm.pm10);
  }
  else
  {
    Serial.print("Could not read values from sensor, reason: ");
    Serial.println(pm.statusToString());
  }

  WorkingStateResult state = sds.sleep();
  if (state.isWorking())
  {
    Serial.println("Problem with sleeping the sensor.");
  }
  else
  {
    Serial.println("Sensor is sleeping");
    delay(60000); // wait 1 minute
  }
}

Nun wollte ich das Beispiel mit millis() umsetzen, mein gedanklicher Ansatz war:

#include <Arduino.h>
#include <SdsDustSensor.h>

#define PM_SERIAL_RX D7
#define PM_SERIAL_TX D8

SdsDustSensor sds(PM_SERIAL_RX, PM_SERIAL_TX);
float pm25, pm10;
unsigned long lastMeasurement = 0;

void setup()
{
  Serial.begin(74880);
  while (!Serial)
  {
  } // Wait for Serial to start
  delay(750);
  sds.begin();

  Serial.println();
  Serial.println(sds.queryFirmwareVersion().toString());  // prints firmware version
  Serial.println(sds.setQueryReportingMode().toString()); // ensures sensor is in 'query' reporting mode

  unsigned long now = millis();
  lastMeasurement = now;
}

void loop()
{
  unsigned long now = millis();
  if ((now - lastMeasurement) > 60 * 1000)
  {
    sds.wakeup();
    lastMeasurement = now;
  }
}

also hier, erstmal jede Minute sds.wakeup() aufrufen, aber es gilt ja auch noch dann den Rest des Codes nach weiteren 30 Sekunden auszuführen.

PmResult pm = sds.queryPm();
  if (pm.isOk())
  {
    Serial.print("PM2.5 = ");
    Serial.print(pm.pm25);
    Serial.print(", PM10 = ");
    Serial.println(pm.pm10);
  }
  else
  {
    Serial.print("Could not read values from sensor, reason: ");
    Serial.println(pm.statusToString());
  }

  WorkingStateResult state = sds.sleep();
  if (state.isWorking())
  {
    Serial.println("Problem with sleeping the sensor.");
  }
  else
  {
    Serial.println("Sensor is sleeping");
    delay(60000); // wait 1 minute
  }

Ich weiß das stellt jetzt nicht soviel Eigenleistung dar, aber ich habe etliche Versuche mit weiteren Zeitabfragen und Variablen hinter mir, die immer nur mit einem riesen Knoten im Gehirn und natürlich ohne Lösung, geendet haben.
Vielleicht ist hier jemand so nett um mir auf die Sprünge zu helfen, so das ich zu einem Ergebniss komme.

Ich kenne den Sensor nicht, vermute aber, du musst auch die 30Sek. Aufwachzeit mit berücksichtigen und einbinden.

HotSystems:
Ich kenne den Sensor nicht, vermute aber, du musst auch die 30Sek. Aufwachzeit mit berücksichtigen und einbinden.

Genau das ist ja Inhalt meiner Fragestellung, vielleicht habe ich mich das nicht verständlich genug Ausgedrückt!

Der Sensor läuft nach dem sds.wakeup() selbständig an. Jetzt soll nach 30 Sekunden der 3.Codeblock, den ich im Eröffungspost gezeigt habe, noch ausgeführt werden. Das bekomme ich leider nicht hin.

fckw:
Der Sensor läuft nach dem sds.wakeup() selbständig an. Jetzt soll nach 30 Sekunden der 3.Codeblock, den ich im Eröffungspost gezeigt habe, noch ausgeführt werden. Das bekomme ich leider nicht hin.

Dann setze den 3. Codeblock in eine Funktion und rufe die nach dem wakeup auf.
Vermute allerdings dass deine Rechnung nicht passt. Da sollte besser stehen: (60UL * 1000)

HotSystems:
Dann setze den 3. Codeblock in eine Funktion und rufe die nach dem wakeup auf.
Vermute allerdings dass deine Rechnung nicht passt. Da sollte besser stehen: (60UL * 1000)

Danke für deine Hilfe, ich habe den Rest in eine Funktion gepackt nur um dann festzustellen, das die ja nur einmal aufgerufen wird und meine "zweite If-Abfrage mit i " somit sinnlos ist, der Knoten will nicht platzen. Danke auch für den Hinweis mit dem UL, ich habe dafür jetzt einfach eine globale Variable definiert.

Hier noch mein aktueller Code:

#include <Arduino.h>
#include <SdsDustSensor.h>

#define PM_SERIAL_RX D7
#define PM_SERIAL_TX D8

SdsDustSensor sds(PM_SERIAL_RX, PM_SERIAL_TX);
float pm25, pm10;
unsigned long timer = 60;
unsigned long lastMeasurement = 0;

void setup()
{
  Serial.begin(74880);
  while (!Serial)
  {
  } // Wait for Serial to start
  delay(750);
  sds.begin();

  Serial.println();
  Serial.println(sds.queryFirmwareVersion().toString());  // prints firmware version
  Serial.println(sds.setQueryReportingMode().toString()); // ensures sensor is in 'query' reporting mode

  unsigned long now = millis();
  lastMeasurement = now;
}

void measure(unsigned long t)
{
  if ((t - lastMeasurement) > timer * 500)
  {
    PmResult pm = sds.queryPm();
    if (pm.isOk())
    {
      Serial.print("PM2.5 = ");
      Serial.print(pm.pm25);
      Serial.print(", PM10 = ");
      Serial.println(pm.pm10);
    }
    else
    {
      Serial.print("Could not read values from sensor, reason: ");
      Serial.println(pm.statusToString());
    }

    WorkingStateResult state = sds.sleep();
    if (state.isWorking())
    {
      Serial.println("Problem with sleeping the sensor.");
    }
    else
    {
      Serial.println("Sensor is sleeping");
    }
  }
}

void loop()
{
  unsigned long now = millis();
  if ((now - lastMeasurement) > timer * 1000)
  {
    sds.wakeup();
    lastMeasurement = now;
    measure(now);
  }
}

fckw:
der Knoten will nicht platzen.

Das was Du brauchst ist eine klasssiche Schrittkette.
Ich hab mal was gebastelt - Achtung es ist ungetestet.

// Forensketch - nur geschrieben, nicht kompiliert / ungetestet
#include <Arduino.h>
#include <SdsDustSensor.h>

#define PM_SERIAL_RX D7
#define PM_SERIAL_TX D8

SdsDustSensor sds(PM_SERIAL_RX, PM_SERIAL_TX);
float pm25, pm10;
unsigned long timer = 60;
unsigned long lastMeasurement = 0;

void setup()
{
  Serial.begin(74880);
  while (!Serial)
  {
  } // Wait for Serial to start
  delay(750);
  sds.begin();

  Serial.println();
  Serial.println(sds.queryFirmwareVersion().toString());  // prints firmware version
  Serial.println(sds.setQueryReportingMode().toString()); // ensures sensor is in 'query' reporting mode

  unsigned long now = millis();
  lastMeasurement = now;
}

void measure()
{
  PmResult pm = sds.queryPm();
  if (pm.isOk())
  {
    Serial.print("PM2.5 = ");
    Serial.print(pm.pm25);
    Serial.print(", PM10 = ");
    Serial.println(pm.pm10);
  }
  else
  {
    Serial.print("Could not read values from sensor, reason: ");
    Serial.println(pm.statusToString());
  }

  WorkingStateResult state = sds.sleep();
  if (state.isWorking())
  {
    Serial.println("Problem with sleeping the sensor.");
  }
  else
  {
    Serial.println("Sensor is sleeping");
  }
}

void loop()
{
  if (millis() - lastMeasurement) > timer * 1000)
  {
    schrittkette();
  }
}

void schrittkette()
{
  enum {wecken, aufwachen, messen, setzen};
  static int schritt = wecken;
  static unsigned long lastmillis = millis();
  const unsigned long wakeuptime = 30000;
  switch (schritt)
  {
    case wecken: // sorgt dafür, das der Sensor gestartet wird
      sds.wakeup();
      lastmillis = millis(); // Aufwachstart merken
      schritt = aufwachen; // nächster Schritt:
      break;
    case aufwachen: // wartet "Aufwachzeit" ab - setzt dann nächsten Schritt
      if (millis() - lastmillis > wakeuptime) // Zeit bis aufgewacht abgelaufen?
        // ggfls. kann das auch auf "... antwortet der Sensor"
        // geändert werden
        schritt = messen;
      break;
    case messen:  // Sollte klar sein
      measure();  // ACHTUNG! Hier kann auch ein Rückgabewert ausgewertet werden, ob die Messung erfolgt ist!
      schritt = setzen;
      break;
    case setzen:
      lastMeasurement = millis(); // Und erst hier wird die Zeit gemerkt....
      schritt = wecken; // da lastMeasurement gesetzt ist, wird wecken erst nach dem Ablauf des Timing ausgeführt
      break;
    default:
      schritt = wecken;
      break;
  }
}

Einfach mal einspielen und testen...
Wenn fehler sind, bitte Bescheid geben.

my_xy_projekt:
Das was Du brauchst ist eine klasssiche Schrittkette.
Ich hab mal was gebastelt - Achtung es ist ungetestet.

Einfach mal einspielen und testen...
Wenn fehler sind, bitte Bescheid geben.

Super Vielen Dank, der Code funktioniert erstmal, es hat nur eine Klammer in der Loop gefehlt, auch musste ich die Funktionen entsprechend ihres Aufrufs sortieren, weil VS Code mit PlatformIO plugin sonst Fehler auswirft.

Hier der Code:

#include <Arduino.h>
#include <SdsDustSensor.h>

#define PM_SERIAL_RX D7
#define PM_SERIAL_TX D8

SdsDustSensor sds(PM_SERIAL_RX, PM_SERIAL_TX);
float pm25, pm10;
unsigned long timer = 60;
unsigned long lastMeasurement = 0;

void setup()
{
  Serial.begin(74880);
  while (!Serial)
  {
  } // Wait for Serial to start
  delay(750);
  sds.begin();

  Serial.println();
  Serial.println(sds.queryFirmwareVersion().toString());  // prints firmware version
  Serial.println(sds.setQueryReportingMode().toString()); // ensures sensor is in 'query' reporting mode
}

void measure()
{
  PmResult pm = sds.queryPm();
  if (pm.isOk())
  {
    Serial.print("PM2.5 = ");
    Serial.print(pm.pm25);
    Serial.print(", PM10 = ");
    Serial.println(pm.pm10);
  }
  else
  {
    Serial.print("Could not read values from sensor, reason: ");
    Serial.println(pm.statusToString());
  }

  WorkingStateResult state = sds.sleep();
  if (state.isWorking())
  {
    Serial.println("Problem with sleeping the sensor.");
  }
  else
  {
    Serial.println("Sensor is sleeping");
  }
}

void schrittkette()
{
  enum
  {
    wecken,
    aufwachen,
    messen,
    setzen
  };
  static int schritt = wecken;
  static unsigned long lastmillis = millis();
  const unsigned long wakeuptime = 30000;
  switch (schritt)
  {
  case wecken: // sorgt dafür, das der Sensor gestartet wird
    sds.wakeup();
    lastmillis = millis(); // Aufwachstart merken
    schritt = aufwachen;   // nächster Schritt:
    break;
  case aufwachen:                           // wartet "Aufwachzeit" ab - setzt dann nächsten Schritt
    if (millis() - lastmillis > wakeuptime) // Zeit bis aufgewacht abgelaufen?
      // ggfls. kann das auch auf "... antwortet der Sensor"
      // geändert werden
      schritt = messen;
    break;
  case messen: // Sollte klar sein
    measure(); // ACHTUNG! Hier kann auch ein Rückgabewert ausgewertet werden, ob die Messung erfolgt ist!
    schritt = setzen;
    break;
  case setzen:
    lastMeasurement = millis(); // Und erst hier wird die Zeit gemerkt....
    schritt = wecken;           // da lastMeasurement gesetzt ist, wird wecken erst nach dem Ablauf des Timing ausgeführt
    break;
  default:
    schritt = wecken;
    break;
  }
}

void loop()
{
  if ((millis() - lastMeasurement) > timer * 1000)
  {
    schrittkette();
  }
}

Danke nochmal, so habe ich eine gute Basis um weiter zu machen!

fckw:
Super Vielen Dank, der Code funktioniert erstmal, es hat nur eine Klammer in der Loop gefehlt, auch musste ich die Funktionen entsprechend ihres Aufrufs sortieren, weil VS Code mit PlatformIO plugin sonst Fehler auswirft.

Danke nochmal, so habe ich eine gute Basis um weiter zu machen!

Wie geil ist das denn...
Ich hab das gerade noch nachgebaut..
Mit seriellen Ausgaben, da bin ich auch auf die fehlende Klammer gestossen...

#include <Arduino.h>
#include <SdsDustSensor.h>

#define PM_SERIAL_RX D7
#define PM_SERIAL_TX D8

SdsDustSensor sds(PM_SERIAL_RX, PM_SERIAL_TX);
float pm25, pm10;
unsigned long timer = 60;
unsigned long lastMeasurement = 0;

void setup()
{
  Serial.begin(115200);
  while (!Serial)
  {
  } // Wait for Serial to start
  delay(750);
  sds.begin();

  Serial.println();
  Serial.println(sds.queryFirmwareVersion().toString());  // prints firmware version
  Serial.println(sds.setQueryReportingMode().toString()); // ensures sensor is in 'query' reporting mode

  unsigned long now = millis();
  lastMeasurement = now;
}

void measure()
{
  PmResult pm = sds.queryPm();
  if (pm.isOk())
  {
    Serial.print("PM2.5 = ");
    Serial.print(pm.pm25);
    Serial.print(", PM10 = ");
    Serial.println(pm.pm10);
  }
  else
  {
    Serial.print("Could not read values from sensor, reason: ");
    Serial.println(pm.statusToString());
  }

  WorkingStateResult state = sds.sleep();
  if (state.isWorking())
  {
    Serial.println("Problem with sleeping the sensor.");
  }
  else
  {
    Serial.println("Sensor is sleeping");
  }
}

void loop()
{
  if ((millis() - lastMeasurement) > timer * 1000)
  {
    schrittkette();
  }
}

void schrittkette()
{
  enum {wecken, aufwachen, messen, setzen};
  static int schritt = wecken;
  static unsigned long lastmillis = millis();
  const unsigned long wakeuptime = 30000;
  switch (schritt)
  {
    case wecken: // sorgt dafür, das der Sensor gestartet wird
      Serial.println(F("Wecken"));
      sds.wakeup();
      lastmillis = millis(); // Aufwachstart merken
      schritt = aufwachen; // nächster Schritt:
      break;
    case aufwachen: // wartet "Aufwachzeit" ab - setzt dann nächsten Schritt
      Serial.println(F("aufwachen"));
      if (millis() - lastmillis > wakeuptime) // Zeit bis aufgewacht abgelaufen?
        // ggfls. kann das auch auf "... antwortet der Sensor"
        // geändert werden
        schritt = messen;
      break;
    case messen:  // Sollte klar sein
      Serial.println(F("messen"));
      measure();  // ACHTUNG! Hier kann auch ein Rückgabewert ausgewertet werden, ob die Messung erfolgt ist!
      schritt = setzen;
      break;
    case setzen:
      Serial.println(F("setzen"));
      lastMeasurement = millis(); // Und erst hier wird die Zeit gemerkt....
      schritt = wecken; // da lastMeasurement gesetzt ist, wird wecken erst nach dem Ablauf des Timing ausgeführt
      break;
    default:
      Serial.println(F("DEFAULT!"));
      schritt = wecken;
      break;
  }
}

Meine Ausgaben (runtergekürzt):

21:21:09.239 -> 
21:21:10.266 -> Firmware version [year.month.day]: -1.-1.-1
21:21:11.295 -> Mode: undefined
21:22:11.282 -> Wecken
21:22:13.336 -> aufwachen

21:22:43.335 -> aufwachen
21:22:43.335 -> aufwachen
21:22:43.335 -> aufwachen
21:22:43.335 -> aufwachen
21:22:43.335 -> aufwachen
21:22:43.335 -> messen
21:22:44.363 -> Could not read values from sensor, reason: Not available
21:22:45.389 -> Sensor is sleeping
21:22:45.389 -> setzen

Und ja, er startet neu.

Was Du jetzt machen musst, ist das setzen noch verändern.
DA(!) muss das schlafengehen rein.

Und ja, er startet neu.

Was Du jetzt machen musst, ist das setzen noch verändern.
DA(!) muss das schlafengehen rein.

Ich glaube ich brauche den Schritt setzten garnicht, weil ich alles (deepsleep) in der measure() Funktion ausführe.
Was meinst du mit, "Und ja, er startet neu."?
Besten Dank!

fckw:
Ich glaube ich brauche den Schritt setzten garnicht, weil ich alles (deepsleep) in der measure() Funktion ausführe.
Was meinst du mit, "Und ja, er startet neu."?
Besten Dank!

Ich würde das mit dem schlafen gehen eben nicht im Messzyklus machen, sondern selbst bestimmen, das
a) der Messzyklus erfolgreich war
b) ein Timeout eingetreten ist (Sensor defekt/nicht geantwortet what ever)
Und erst dann die Schrittkette dahin führen, das der sensor wieder schlafen geht.
Ich hab die libnur geladen, aber keinen Sensor. Da (siehe meinen SerMon) der Sleep wieder aus der Messung aktiviert wird, ist das kritisch - Du kannst nicht innerhalb der Schrittkette darauf reagieren.

[edit]
Doch Du brauchst das setzen:
lastMeasurement = millis(); // Und erst hier wird die Zeit gemerkt....
Mit dieser Zeile wird festgelegt, wann der letzte Schritt erfolgte.
Mit der Var lastMeasurement kommst Du im Loop wieder an und erst wenn dort der Wert überschritten ist, geht es wieder von vorne los - Das war der "Neustart"
[/edit]

Meinen Nachsatz vergiss. Er war nur, weil der "Sensor geht schlafen" eingetreten war und ich nicht erneut auf das aufwachen warten wollte - aber das wird auch angezeigt :wink:

Meine Ausgabe:

22:46:25.255 -> 
22:46:26.315 -> Firmware version [year.month.day]: -1.-1.-1
22:46:27.309 -> Mode: undefined
22:47:27.329 -> Wecken
22:47:29.360 -> aufwachen


22:47:59.383 -> aufwachen
22:47:59.383 -> messen
22:48:00.410 -> Could not read values from sensor, reason: Not available
22:48:01.403 -> Sensor is sleeping
22:48:01.403 -> Nicht gemessen! - Wecke Sensor erneut auf!
22:48:01.436 -> unbekannter Zustand - gehe zu wecken
22:48:01.436 -> Wecken
22:48:03.458 -> aufwachen

mit diesem Code:

#include <Arduino.h>
#include <SdsDustSensor.h>

#define PM_SERIAL_RX D7
#define PM_SERIAL_TX D8

SdsDustSensor sds(PM_SERIAL_RX, PM_SERIAL_TX);
float pm25, pm10;
unsigned long timer = 60;
unsigned long lastMeasurement = 0;

void setup()
{
  Serial.begin(115200);
  while (!Serial)
  {
  } // Wait for Serial to start
  delay(750);
  sds.begin();

  Serial.println();
  Serial.println(sds.queryFirmwareVersion().toString());  // prints firmware version
  Serial.println(sds.setQueryReportingMode().toString()); // ensures sensor is in 'query' reporting mode

  unsigned long now = millis();
  lastMeasurement = now;
}

int measure()
{
  signed int stat = -1;
  PmResult pm = sds.queryPm();
  if (pm.isOk())
  {
    Serial.print("PM2.5 = ");
    Serial.print(pm.pm25);
    Serial.print(", PM10 = ");
    Serial.println(pm.pm10);
    stat = 0;
  }
  else
  {
    Serial.print("Could not read values from sensor, reason: ");
    Serial.println(pm.statusToString());
    stat = 1;
  }

  WorkingStateResult state = sds.sleep();
  if (state.isWorking())
  {
    Serial.println("Problem with sleeping the sensor.");
  }
  else
  {
    Serial.println("Sensor is sleeping");
  }
  return stat;
}

void loop()
{
  if ((millis() - lastMeasurement) > timer * 1000)
  {
    schrittkette();
  }
}

void schrittkette()
{
  enum {wecken, aufwachen, messen, setzen};
  static int schritt = wecken;
  static unsigned long lastmillis = millis();
  const unsigned long wakeuptime = 30000;
  static int messzyklen = 0;
  const int maxmesszyklen = 5;
  switch (schritt)
  {
    case wecken: // sorgt dafür, das der Sensor gestartet wird
      Serial.println(F("Wecken"));
      sds.wakeup();
      lastmillis = millis(); // Aufwachstart merken
      schritt = aufwachen; // nächster Schritt:
      break;
    case aufwachen: // wartet "Aufwachzeit" ab - setzt dann nächsten Schritt
      Serial.println(F("aufwachen"));
      if (millis() - lastmillis > wakeuptime) // Zeit bis aufgewacht abgelaufen?
        // ggfls. kann das auch auf "... antwortet der Sensor"
        // geändert werden
        schritt = messen;
      break;
    case messen:  // Sollte klar sein
    {
      Serial.println(F("messen"));
      signed int rueckgabe = measure(); // Die Funktion gibt jetzt einen Wert zurück!
      if (rueckgabe == -1 || rueckgabe == 1)
      {
        messzyklen++;
        Serial.println(F("Nicht gemessen! - Wecke Sensor erneut auf!"));
        schritt = wecken;
      }
      if ((messzyklen > maxmesszyklen) || (rueckgabe == 0))
      {
        Serial.println(F("Maximale Messzyklen erreicht - Schluß! / oder Werte gesammelt"));
        messzyklen = 0;
        schritt = setzen;
      }
      else
      {
        Serial.println(F("unbekannter Zustand - gehe zu wecken"));
        schritt = wecken;
      }
      break;
    }
    case setzen:
      Serial.println(F("setzen"));
      lastMeasurement = millis(); // Und erst hier wird die Zeit gemerkt....
      schritt = wecken; // da lastMeasurement gesetzt ist, wird wecken erst nach dem Ablauf des Timing ausgeführt
      break;
    default:
      Serial.println(F("DEFAULT!"));
      schritt = wecken;
      break;
  }
}

Da siehst Du, was geht und das Du ggfls. auf irgendwas und wie reagieren kannst.

na dann....

[Nachtrag:]
Ich hab das mal ohne serielle Ausgabe vom "aufwachen" gemacht:

23:00:30.757 -> 
23:00:31.784 -> Firmware version [year.month.day]: -1.-1.-1
23:00:32.812 -> Mode: undefined
23:01:32.807 -> Wecken
23:02:04.840 -> messen
23:02:05.869 -> Could not read values from sensor, reason: Not available
23:02:06.898 -> Sensor is sleeping
23:02:06.898 -> Nicht gemessen! - Wecke Sensor erneut auf!
23:02:06.898 -> unbekannter Zustand - gehe zu wecken
23:02:06.932 -> Wecken
23:02:38.938 -> messen
23:02:39.966 -> Could not read values from sensor, reason: Not available
23:02:40.993 -> Sensor is sleeping
23:02:40.993 -> Nicht gemessen! - Wecke Sensor erneut auf!
23:02:40.993 -> unbekannter Zustand - gehe zu wecken
23:02:40.993 -> Wecken
23:03:13.050 -> messen
23:03:14.077 -> Could not read values from sensor, reason: Not available
23:03:15.071 -> Sensor is sleeping
23:03:15.071 -> Nicht gemessen! - Wecke Sensor erneut auf!
23:03:15.105 -> unbekannter Zustand - gehe zu wecken
23:03:15.105 -> Wecken
23:03:47.143 -> messen
23:03:48.171 -> Could not read values from sensor, reason: Not available
23:03:49.166 -> Sensor is sleeping
23:03:49.166 -> Nicht gemessen! - Wecke Sensor erneut auf!
23:03:49.199 -> unbekannter Zustand - gehe zu wecken
23:03:49.199 -> Wecken
23:04:21.207 -> messen
23:04:22.266 -> Could not read values from sensor, reason: Not available
23:04:23.259 -> Sensor is sleeping
23:04:23.259 -> Nicht gemessen! - Wecke Sensor erneut auf!
23:04:23.292 -> unbekannter Zustand - gehe zu wecken
23:04:23.292 -> Wecken
23:04:55.327 -> messen
23:04:56.355 -> Could not read values from sensor, reason: Not available
23:04:57.349 -> Sensor is sleeping
23:04:57.349 -> Nicht gemessen! - Wecke Sensor erneut auf!
23:04:57.382 -> Maximale Messzyklen erreicht - Schluß! / oder Werte gesammelt
23:04:57.382 -> setzen

my_xy_projekt:
Da siehst Du, was geht und das Du ggfls. auf irgendwas und wie reagieren kannst.

na dann....

[Nachtrag:]
Ich hab das mal ohne serielle Ausgabe vom "aufwachen" gemacht:

Spitze, danke für den Input. Habe deinen Code gleich mal ausprobiert und "studiert". Ich habe nur ein paar Anpassungen an den seriellen Ausgaben gemacht und bis jetzt nur den "gut Zustand getestet" (Sensor ok).

Hier mein Code:

#include <Arduino.h>
#include <SdsDustSensor.h>

#define PM_SERIAL_RX D7
#define PM_SERIAL_TX D8

SdsDustSensor sds(PM_SERIAL_RX, PM_SERIAL_TX);
float pm25, pm10;
unsigned long timer = 60;
unsigned long lastMeasurement = 0;

void setup()
{
  Serial.begin(74880);
  while (!Serial)
  {
  } // Wait for Serial to start
  delay(750);
  sds.begin();

  Serial.println();
  Serial.println(sds.queryFirmwareVersion().toString());  // prints firmware version
  Serial.println(sds.setQueryReportingMode().toString()); // ensures sensor is in 'query' reporting mode
}

int measure()
{
  signed int stat = -1;
  PmResult pm = sds.queryPm();
  if (pm.isOk())
  {
    Serial.print("PM2.5 = ");
    Serial.print(pm.pm25);
    Serial.print(", PM10 = ");
    Serial.println(pm.pm10);
    stat = 0;
  }
  else
  {
    Serial.print("Could not read values from sensor, reason: ");
    Serial.println(pm.statusToString());
    stat = 1;
  }

  WorkingStateResult state = sds.sleep();
  if (state.isWorking())
  {
    Serial.println("Problem with sleeping the sensor.");
  }
  else
  {
    Serial.println("Sensor is sleeping");
  }
  return stat;
}

void schrittkette()
{
  enum
  {
    wecken,
    aufwachen,
    messen,
    setzen
  };
  static int schritt = wecken;
  static unsigned long lastmillis = millis();
  const unsigned long wakeuptime = 30000;
  static int messzyklen = 0;
  const int maxmesszyklen = 5;
  switch (schritt)
  {
  case wecken: // sorgt dafür, das der Sensor gestartet wird
    Serial.println(F("Wecken"));
    sds.wakeup();
    lastmillis = millis(); // Aufwachstart merken
    schritt = aufwachen;   // nächster Schritt:
    break;
  case aufwachen: // wartet "Aufwachzeit" ab - setzt dann nächsten Schritt
  {
    if (millis() - lastmillis > wakeuptime) // Zeit bis aufgewacht abgelaufen?
    {
      Serial.println(F("Messzeit erreicht"));
      schritt = messen;
    }
    break;
  }
  case messen: // Sollte klar sein
  {
    Serial.println(F("Sensor auslesen"));
    signed int rueckgabe = measure(); // Die Funktion gibt jetzt einen Wert zurück!
    if (rueckgabe == -1 || rueckgabe == 1)
    {
      messzyklen++;
      Serial.println(F("Nicht gemessen! - Wecke Sensor erneut auf!"));
      schritt = wecken;
    }
    if ((messzyklen > maxmesszyklen) || (rueckgabe == 0))
    {
      Serial.print(F("Anzahl der Messzyklen: "));
      Serial.println(messzyklen);
      Serial.println(F("Warte auf neues wecken"));
      messzyklen = 0;
      schritt = setzen;
    }
    else
    {
      Serial.println(F("unbekannter Zustand - gehe zu wecken"));
      schritt = wecken;
    }
    break;
  }
  case setzen:
    Serial.println(F("setzen"));
    lastMeasurement = millis(); // Und erst hier wird die Zeit gemerkt....
    schritt = wecken;           // da lastMeasurement gesetzt ist, wird wecken erst nach dem Ablauf des Timing ausgeführt
    break;
  default:
    Serial.println(F("DEFAULT!"));
    schritt = wecken;
    break;
  }
}

void loop()
{
  if ((millis() - lastMeasurement) > timer * 1000)
  {
    schrittkette();
  }
}

Und hier noch dazu die serielle Ausgabe:

Firmware version [year.month.day]: 18.11.16
Mode: query
Wecken
Messzeit erreicht
Sensor auslesen
PM2.5 = 328.80, PM10 = 546.30
Sensor is sleeping
Anzahl der Messzyklen: 0
Warte auf neues wecken
setzen
Wecken
Messzeit erreicht
Sensor auslesen
PM2.5 = 291.90, PM10 = 514.30
Sensor is sleeping
Anzahl der Messzyklen: 0
Warte auf neues wecken
setzen
Wecken
Messzeit erreicht
Sensor auslesen
PM2.5 = 285.00, PM10 = 509.40
Sensor is sleeping
Anzahl der Messzyklen: 0
Warte auf neues wecken
setzen
Wecken
Messzeit erreicht
Sensor auslesen
PM2.5 = 250.90, PM10 = 459.90
Sensor is sleeping
Anzahl der Messzyklen: 0
Warte auf neues wecken
setzen
Wecken
Messzeit erreicht
Sensor auslesen
PM2.5 = 234.30, PM10 = 439.50
Sensor is sleeping
Anzahl der Messzyklen: 0
Warte auf neues wecken
setzen
Wecken
Messzeit erreicht
Sensor auslesen
PM2.5 = 244.20, PM10 = 456.60
Sensor is sleeping
Anzahl der Messzyklen: 0
Warte auf neues wecken
setzen
Wecken
Messzeit erreicht
Sensor auslesen
PM2.5 = 216.00, PM10 = 412.10
Sensor is sleeping
Anzahl der Messzyklen: 0
Warte auf neues wecken
setzen

fckw:
Ich habe nur ein paar Anpassungen an den seriellen Ausgaben gemacht und bis jetzt nur den "gut Zustand getestet" (Sensor ok).

Na siehste - gar nicht schlimm :wink:
Du kannst auch die Weckzeit versuchen zu verkürzen, indem Du prüfst, ob der Sensor schon verfügbar ist.
Dann wäre die Zeit ein Timeout-Kriterium, was zum Abbruch führt.

Zudem würde ich sds.sleep(); ins letzte case schieben - aber das ist wohl Geschmackssache...

Alles gut!

my_xy_projekt:
Na siehste - gar nicht schlimm :wink:
Du kannst auch die Weckzeit versuchen zu verkürzen, indem Du prüfst, ob der Sensor schon verfügbar ist.
Dann wäre die Zeit ein Timeout-Kriterium, was zum Abbruch führt.

Zudem würde ich sds.sleep(); ins letzte case schieben - aber das ist wohl Geschmackssache...

Alles gut!

Der Sensor liefert unmitterlbar nach dem WakeUp schon Werte (pm.isOk), die 30sec will ich nur für einen Spülvorgang.
Funktionsprinzip: Der Sensor saugt Luft in eine Messkammer und ermittelt mit einem Laser die enthaltenen Partikel in zwei größen.

Den Code im letzten case werde ich wohl noch entsprechend anpassen.
Grüße

fckw:
Spülvorgang.
Funktionsprinzip: Der Sensor saugt Luft in eine Messkammer und ermittelt mit einem Laser die enthaltenen Partikel in zwei größen.

Jetzt hast mich neugierig gemacht... und ich fand:
https://www.amazon.de/dp/B07911ZY9W
Da steht tatsächlich:

Principle of the Laserstreuung, can the Partikelkonzentration

Gibt es dazu keine englischen Worte ???

Aber nettes Teil... Mal sehen, wenn und wenn ja, wann meine Wetterstation Formen annimmt.

Wenn ich Amazon.de auf Englisch stelle, sehe ich

The SDS011 with the Principle of the laser dispersion, the particle concentration between 0.3 and 10 in the air available. It is stable and reliable with digital output and built-in fan.

  1. Accurate and reliable: laser detection, stable, good consistency;
  2. Quick response: response time is less than 10 seconds when scene changes.
  3. Easy integration: UART output (or IO output can be customized), built-in fan.
  4. High Resolution: 0.3ug/m3 resolution.
    Report incorrect product information.

Auf Deutsch erscheint:

The SDS011 with the Principle of the Laserstreuung, can the Partikelkonzentration between 0,3 and 10 in the air available. Es ist mit Digitalausgang und eingebautem Lüfter stabil und zuverlässig.

  1. Genaue und zuverlässige: Laser-Erkennung, stabil, gute Konsistenz;
  2. Schnelle Antwort: Antwortzeit ist weniger als 10 Sekunden, wenn sich die Szene ändert.
  3. Einfache Integration: UART-Ausgang (oder IO-Ausgang kann angepasst werden), Lüfter eingebaut;
  4. Hohe Auflösung: Auflösung von 0,3ug / m3.
    Falsche Produktinformationen melden

Das hat ein Chinese von Hand übersetzt (und paar Worte vergessen), denke ich. Wo kommt das Wort "can" her?
Hat immerhin 0.3 nach 0,3 übersetzt !

my_xy_projekt:
Da siehst Du, was geht und das Du ggfls. auf irgendwas und wie reagieren kannst.

na dann....

Jetzt habe die "Schrittkette" um ein case (Count) erweitert. Es soll jede Minute ein Variable hochgezählt werden um nach x Durchläufen ins nächste case springen.

case count:
  {
    counter++;
    Serial.println(counter);
    lastMeasurement = millis();

    if (counter == 2)
    {
      schritt = wecken;
    }
    break;
  }

Soweit funktioniert es, aber was ich nicht verstehe, warum wird diese if-Bedingung erst durchlaufen, nachdem "counter" auf 3 gezählt hat, was mache ich falsch?

Hier noch mein ganzer Code:

#include <Arduino.h>
#include <SdsDustSensor.h>
#include "DHTesp.h"

#define PM_SERIAL_RX D7
#define PM_SERIAL_TX D8

SdsDustSensor sds(PM_SERIAL_RX, PM_SERIAL_TX);
DHTesp dht;

float humidity;
float temperature;
float pm25, pm10;
const unsigned long timer = 60;
unsigned long lastMeasurement = 0;

void setup()
{
  Serial.begin(74880);
  while (!Serial)
  {
  } // Wait for Serial to start
  delay(750);
  sds.begin();

  Serial.println();
  Serial.println(sds.queryFirmwareVersion().toString());  // prints firmware version
  Serial.println(sds.setQueryReportingMode().toString()); // ensures sensor is in 'query' reporting mode
  sds.sleep();

  dht.setup(0, DHTesp::DHT22);
  humidity = dht.getHumidity();
  temperature = dht.getTemperature();
  Serial.print(F("Temperature: "));
  Serial.print(temperature, 2);
  Serial.print(F("°C \t"));
  Serial.print(F("Humidity: "));
  Serial.print(humidity, 1);
  Serial.println(F("%"));
}

int measure()
{
  signed int stat = -1;
  PmResult pm = sds.queryPm();
  if (pm.isOk())
  {
    Serial.print(F("PM2.5 = "));
    Serial.print(pm.pm25);
    Serial.print(F(", PM10 = "));
    Serial.println(pm.pm10);
    stat = 0;

    //humidity = dht.getHumidity();
    //temperature = dht.getTemperature();

    Serial.print(F("Temperature: "));
    Serial.print(temperature, 2);
    Serial.print(F("°C \t"));
    Serial.print(F("Humidity: "));
    Serial.print(humidity, 1);
    Serial.println(F("%"));
  }
  else
  {
    Serial.print(F("Could not read values from sensor, reason: "));
    Serial.println(pm.statusToString());
    stat = 1;
  }

  WorkingStateResult state = sds.sleep();
  if (state.isWorking())
  {
    Serial.println(F("Problem with sleeping the sensor."));
  }
  else
  {
    Serial.println(F("Sensor is sleeping"));
  }
  return stat;
}

void schrittkette()
{
  enum
  {
    count,
    wecken,
    aufwachen,
    messen,
    setzen
  };
  static int schritt = count;
  static unsigned long lastmillis = millis();
  const unsigned long wakeuptime = 10000;
  static int messzyklen = 0;
  const int maxmesszyklen = 5;
  static int counter = 0;

  switch (schritt)
  {
  case count:
  {
    counter++;
    Serial.println(counter);
    lastMeasurement = millis();

    if (counter == 2)
    {
      schritt = wecken;
    }
    break;
  }
  case wecken: // sorgt dafür, das der Sensor gestartet wird
    Serial.println(F("Wecken"));
    sds.wakeup();
    lastmillis = millis(); // Aufwachstart merken
    schritt = aufwachen;   // nächster Schritt:
    break;
  case aufwachen: // wartet "Aufwachzeit" ab - setzt dann nächsten Schritt
  {
    if (millis() - lastmillis > wakeuptime) // Zeit bis aufgewacht abgelaufen?
    {
      Serial.println(F("Messzeit erreicht"));
      schritt = messen;
    }
    break;
  }
  case messen: // Sollte klar sein
  {
    Serial.println(F("Sensor auslesen"));
    signed int rueckgabe = measure(); // Die Funktion gibt jetzt einen Wert zurück!
    if (rueckgabe == -1 || rueckgabe == 1)
    {
      messzyklen++;
      Serial.println(F("Nicht gemessen! - Wecke Sensor erneut auf!"));
      schritt = wecken;
    }
    if ((messzyklen > maxmesszyklen) || (rueckgabe == 0))
    {
      Serial.print(F("Anzahl der Messzyklen: "));
      Serial.println(messzyklen);
      Serial.println(F("Warte auf neues wecken"));
      messzyklen = 0;
      schritt = setzen;
    }
    else
    {
      Serial.println(F("unbekannter Zustand - gehe zu wecken"));
      schritt = wecken;
    }
    break;
  }
  case setzen:
    Serial.println(F("setzen"));
    counter = 0;
    schritt = count;
    break;
  default:
    Serial.println(F("DEFAULT!"));
    schritt = count;
    break;
  }
}

void loop()
{
  if ((millis() - lastMeasurement) > timer * 500)
  {
    schrittkette();
  }
}

Ich habe "counter" auch schon global deklariert und im "loop" hochgezählt, leider gleiches Ergebniss.

fckw:
Jetzt habe die "Schrittkette" um ein case (Count) erweitert. Es soll jede Minute ein Variable hochgezählt werden um nach x Durchläufen ins nächste case springen.

Ich habe "counter" auch schon global deklariert und im "loop" hochgezählt, leider gleiches Ergebniss.

Ich bin noch am überlegen, was Du willst..

switch (schritt)
  {
  case count:
  {
    counter++;
    Serial.println(counter);
    lastMeasurement = millis();

    if (counter == 2)
    {
      schritt = wecken;
    }
    break;
  }

lastMeasurement wäre bei Dir mit der aktuellen Zeit gesetzt
Damit ist die Bedingung

 if ((millis() - lastMeasurement) > timer * 500)

für die nächsten 500ms nicht erfüllt.

Das führt zu folgender Konstellation:

  1. nach dem Start vergehen 500 ms bis die Bedingung erfüllt ist.
  2. dann geht es ins case count
  3. dann wieder 500 ms Ruhe
  4. dann wieder case count
  5. dann wieder 500 ms Ruhe
  6. dann wieder case count
  7. Jetzt ist der Zähler ereicht - > nächster Schritt soll wecken sein.
  8. Da Du aber lastMeasurement wieder gesetzt hast:
  9. wieder 500ms Ruhe
  10. erst jetzt geht es ins wecken.

Wenn Du die Schrittkette nicht alle 500ms sondern alle 5Sekunden beginnen willst, ändere den Parameter in der Bedingung. also von 500 (ms) auf 5000 (ms) (5000/1000=5sekunden)

Du kannst das auch mit dem count machen.
Dann das if komplett aus dem loop raus und im case count die Bedingung rein und dort den nächsten Schritt setzen.

my_xy_projekt:
Ich bin noch am überlegen, was Du willst..

Im Prinzip will ich einen zusätzlichen Schritt (Count) der jede Minute durchlaufen wird, damit ich dort z.B einen DHT Sensor auslesen kann, der Rest der Kette soll nach X durchläufen abgearbeitet werden.

lastMeasurement wäre bei Dir mit der aktuellen Zeit gesetzt
Damit ist die Bedingung

 if ((millis() - lastMeasurement) > timer * 500)

für die nächsten 500ms nicht erfüllt.

Danke ich denke ich habe das Problem erkannt, aber noch keine Lösung.
PS: Die Zeit wird ja noch mit einem Faktor multipliziert (timer = 60), also sind es zum hier zum testen 30 Sec.

fckw:
Im Prinzip will ich einen zusätzlichen Schritt (Count) der jede Minute durchlaufen wird, damit ich dort z.B einen DHT Sensor auslesen kann, der Rest der Kette soll nach X durchläufen abgearbeitet werden.

Dann muss das anders werden.

Variante 1:
zusätzliche Bedingung für den Sensor schaffen.

 void loop()
{
  static dhtmillis = 0;
  if (millis() - dhtmillis > 2000)
  {
    readhum();
    dhtmillis = millis();
  }
  if ((millis() - lastMeasurement) > timer * 500)
  {
    schrittkette();
  }
}

void readhum()
{
  //Hier alles rund um den Sensor
}

Die Alternative mit der Schrittkette wäre:

    case count:
      {
        if ((counter == 0 || counter == 5))
        {
          readhum();
        }
        if (counter > 9)
        {
          schritt = wecken;
// [edit] und hier den counter wieder zurücksetzen ;)
        }
        break;
      }

finde ich aber persönlich zu unübersichtlich und nicht sauber genug getrennt.