Forum: Mikrocontroller und Digitale Elektronik BME680 not running properly


von tres (Gast)


Lesenswert?

Hallo,
ich habe versucht meinen BME680 zum laufen zu bringen aber nach nun mehr 
als 4h bleibt der IAQ Wert immer noch bei dem initial start als aauch 
die accuracy. Was amche ich falsch....? Hier ist mein code

1
#define STATE_SAVE_PERIOD  UINT32_C(360 * 60 * 1000) // 360 minutes - 4 times a day
2
3
#include <WiFi.h>
4
#include <ESPmDNS.h>
5
#include <WiFiUdp.h>
6
#include <ArduinoOTA.h>
7
#include <EEPROM.h>
8
#include "bsec.h"
9
/* Configure the BSEC library with information about the sensor
10
    18v/33v = Voltage at Vdd. 1.8V or 3.3V
11
    3s/300s = BSEC operating mode, BSEC_SAMPLE_RATE_LP or BSEC_SAMPLE_RATE_ULP
12
    4d/28d = Operating age of the sensor in days
13
    generic_18v_3s_4d
14
    generic_18v_3s_28d
15
    generic_18v_300s_4d
16
    generic_18v_300s_28d
17
    generic_33v_3s_4d
18
    generic_33v_3s_28d
19
    generic_33v_300s_4d
20
    generic_33v_300s_28d
21
*/
22
const uint8_t bsec_config_iaq[] = {
23
#include "config/generic_33v_3s_4d/bsec_iaq.txt"
24
};
25
26
27
// Helper functions declarations
28
void checkIaqSensorStatus(void);
29
void errLeds(void);
30
void loadState(void);
31
void updateState(void);
32
33
34
// Create an object of the class Bsec
35
Bsec iaqSensor;
36
uint8_t bsecState[BSEC_MAX_STATE_BLOB_SIZE] = {0};
37
uint16_t stateUpdateCounter = 0;
38
39
String output;
40
41
const char* ssid = "xxx";
42
const char* password = "xxxxx";
43
44
uint8_t i;
45
bool ConnectionEstablished; // Flag for successfully handled connection
46
  
47
#define MAX_TELNET_CLIENTS 2
48
49
WiFiServer TelnetServer(23);
50
WiFiClient TelnetClient[MAX_TELNET_CLIENTS];
51
52
void setup()
53
{
54
  Serial.begin(115200);
55
  Serial.println("Over The Air and Telnet Example");
56
57
  Serial.printf("Sketch size: %u\n", ESP.getSketchSize());
58
  Serial.printf("Free size: %u\n", ESP.getFreeSketchSpace());
59
60
  WiFi.mode(WIFI_STA);
61
  WiFi.begin(ssid, password);
62
  Wire.begin();
63
  iaqSensor.begin(BME680_I2C_ADDR_SECONDARY, Wire);
64
  output = "\nBSEC library version " + String(iaqSensor.version.major) + "." + String(iaqSensor.version.minor) + "." + String(iaqSensor.version.major_bugfix) + "." + String(iaqSensor.version.minor_bugfix);
65
  Serial.println(output);
66
  checkIaqSensorStatus();
67
68
  iaqSensor.setConfig(bsec_config_iaq);
69
  checkIaqSensorStatus();
70
71
  loadState();
72
73
74
  bsec_virtual_sensor_t sensorList[10] = {
75
    BSEC_OUTPUT_RAW_TEMPERATURE,
76
    BSEC_OUTPUT_RAW_PRESSURE,
77
    BSEC_OUTPUT_RAW_HUMIDITY,
78
    BSEC_OUTPUT_RAW_GAS,
79
    BSEC_OUTPUT_IAQ,
80
    BSEC_OUTPUT_STATIC_IAQ,
81
    BSEC_OUTPUT_CO2_EQUIVALENT,
82
    BSEC_OUTPUT_BREATH_VOC_EQUIVALENT,
83
    BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE,
84
    BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY,
85
  };
86
87
  iaqSensor.updateSubscription(sensorList, 10, BSEC_SAMPLE_RATE_LP);
88
  checkIaqSensorStatus();
89
90
  // ... Give ESP 10 seconds to connect to station.
91
  unsigned long startTime = millis();
92
  Serial.print("Waiting for wireless connection ");
93
  while (WiFi.status() != WL_CONNECTED && millis() - startTime < 10000)
94
  {
95
    delay(200);
96
    Serial.print(".");
97
  }
98
  Serial.println();
99
  
100
  while (WiFi.status() != WL_CONNECTED)
101
  {
102
    Serial.println("Connection Failed! Rebooting...");
103
    delay(3000);
104
    ESP.restart();
105
  }
106
107
  Serial.print("IP address: ");
108
  Serial.println(WiFi.localIP());
109
110
  Serial.println("Starting Telnet server");
111
  TelnetServer.begin();
112
  TelnetServer.setNoDelay(true);
113
114
  pinMode(LED_BUILTIN, OUTPUT);  // initialize onboard LED as output
115
116
  // OTA
117
118
  // Port defaults to 8266
119
  // ArduinoOTA.setPort(8266);
120
121
  // Hostname defaults to esp8266-[ChipID]
122
  // ArduinoOTA.setHostname("myesp8266");
123
124
  // No authentication by default
125
  ArduinoOTA.setPassword((const char *)"1234");
126
  
127
  ArduinoOTA.onStart([]() {
128
    Serial.println("Start");
129
  });
130
  
131
  ArduinoOTA.onEnd([]() {
132
    Serial.println("\nEnd");
133
  });
134
  
135
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
136
    Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
137
  });
138
  ArduinoOTA.onError([](ota_error_t error) {
139
    Serial.printf("Error[%u]: ", error);
140
    if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
141
    else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
142
    else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
143
    else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
144
    else if (error == OTA_END_ERROR) Serial.println("End Failed");
145
  });
146
  
147
  ArduinoOTA.begin();
148
}
149
150
void loop() {
151
  //ArduinoOTA.handle(); // Wait for OTA connection
152
  blinkLED();  // Blink LED
153
  Telnet();  // Handle telnet connections
154
  unsigned long time_trigger = millis();
155
  if (iaqSensor.run()) { // If new data is available
156
    output = "time=" +String(time_trigger);
157
    output += ", rawTemperature=" + String(iaqSensor.rawTemperature);
158
    output += ", pressure=" + String(iaqSensor.pressure);
159
    output += ", rawHumidity=" + String(iaqSensor.rawHumidity);
160
    output += ", gasResistance=" + String(iaqSensor.gasResistance);
161
    output += ", iaq=" + String(iaqSensor.iaq);
162
    output += ", iaqAccuracy=" + String(iaqSensor.iaqAccuracy);
163
    output += ", temperature=" + String(iaqSensor.temperature);
164
    output += ", humidity=" + String(iaqSensor.humidity);
165
    output += ", staticIaq=" + String(iaqSensor.staticIaq);
166
    output += ", co2Equivalent=" + String(iaqSensor.co2Equivalent);
167
    output += ", breathVocEquivalent=" + String(iaqSensor.breathVocEquivalent);
168
    TelnetMsg(output);
169
  } else {
170
    checkIaqSensorStatus();
171
  }
172
  delay(30000);
173
}
174
175
void TelnetMsg(String text)
176
{
177
  for(i = 0; i < MAX_TELNET_CLIENTS; i++)
178
  {
179
    if (TelnetClient[i] || TelnetClient[i].connected())
180
    {
181
      TelnetClient[i].println(text);
182
    }
183
  }
184
  delay(10);  // to avoid strange characters left in buffer
185
}
186
      
187
void Telnet()
188
{
189
  // Cleanup disconnected session
190
  for(i = 0; i < MAX_TELNET_CLIENTS; i++)
191
  {
192
    if (TelnetClient[i] && !TelnetClient[i].connected())
193
    {
194
      Serial.print("Client disconnected ... terminate session "); Serial.println(i+1); 
195
      TelnetClient[i].stop();
196
    }
197
  }
198
  
199
  // Check new client connections
200
  if (TelnetServer.hasClient())
201
  {
202
    ConnectionEstablished = false; // Set to false
203
    
204
    for(i = 0; i < MAX_TELNET_CLIENTS; i++)
205
    {
206
      // Serial.print("Checking telnet session "); Serial.println(i+1);
207
      
208
      // find free socket
209
      if (!TelnetClient[i])
210
      {
211
        TelnetClient[i] = TelnetServer.available(); 
212
        
213
        Serial.print("New Telnet client connected to session "); Serial.println(i+1);
214
        
215
        TelnetClient[i].flush();  // clear input buffer, else you get strange characters
216
        TelnetClient[i].println("Welcome!");
217
        
218
        TelnetClient[i].print("Millis since start: ");
219
        TelnetClient[i].println(millis());
220
        
221
        TelnetClient[i].print("Free Heap RAM: ");
222
        TelnetClient[i].println(ESP.getFreeHeap());
223
  
224
        TelnetClient[i].println("----------------------------------------------------------------");
225
        
226
        ConnectionEstablished = true; 
227
        
228
        break;
229
      }
230
      else
231
      {
232
        // Serial.println("Session is in use");
233
      }
234
    }
235
236
    if (ConnectionEstablished == false)
237
    {
238
      Serial.println("No free sessions ... drop connection");
239
      TelnetServer.available().stop();
240
      // TelnetMsg("An other user cannot connect ... MAX_TELNET_CLIENTS limit is reached!");
241
    }
242
  }
243
244
  for(i = 0; i < MAX_TELNET_CLIENTS; i++)
245
  {
246
    if (TelnetClient[i] && TelnetClient[i].connected())
247
    {
248
      if(TelnetClient[i].available())
249
      { 
250
        //get data from the telnet client
251
        while(TelnetClient[i].available())
252
        {
253
          Serial.write(TelnetClient[i].read());
254
        }
255
      }
256
    }
257
  }
258
}
259
260
////////////////////////////////////////////////////////////////////////////////////////
261
// Blink function with telnet output
262
263
const long interval = 2000;
264
int ledState = LOW;
265
unsigned long previousMillis = 0;
266
267
void blinkLED()
268
{
269
  unsigned long currentMillis = millis();
270
271
  // if enough millis have elapsed
272
  if (currentMillis - previousMillis >= interval)
273
  {
274
    previousMillis = currentMillis;
275
276
    // toggle the LED
277
    ledState = !ledState;
278
    digitalWrite(LED_BUILTIN, ledState);
279
280
    String ledStateMsg = "LED State = ";
281
    ledStateMsg += ledState;
282
    TelnetMsg(ledStateMsg);
283
  }
284
}
285
// Helper function definitions
286
void checkIaqSensorStatus(void)
287
{
288
  if (iaqSensor.status != BSEC_OK) {
289
    if (iaqSensor.status < BSEC_OK) {
290
      output = "BSEC error code : " + String(iaqSensor.status);
291
      Serial.println(output);
292
      for (;;)
293
        errLeds(); /* Halt in case of failure */
294
    } else {
295
      output = "BSEC warning code : " + String(iaqSensor.status);
296
      Serial.println(output);
297
    }
298
  }
299
300
  if (iaqSensor.bme680Status != BME680_OK) {
301
    if (iaqSensor.bme680Status < BME680_OK) {
302
      output = "BME680 error code : " + String(iaqSensor.bme680Status);
303
      Serial.println(output);
304
      for (;;)
305
        errLeds(); /* Halt in case of failure */
306
    } else {
307
      output = "BME680 warning code : " + String(iaqSensor.bme680Status);
308
      Serial.println(output);
309
    }
310
  }
311
  iaqSensor.status = BSEC_OK;
312
}
313
314
void errLeds(void)
315
{
316
  pinMode(LED_BUILTIN, OUTPUT);
317
  digitalWrite(LED_BUILTIN, HIGH);
318
  delay(100);
319
  digitalWrite(LED_BUILTIN, LOW);
320
  delay(100);
321
}
322
323
void loadState(void)
324
{
325
  if (EEPROM.read(0) == BSEC_MAX_STATE_BLOB_SIZE) {
326
    // Existing state in EEPROM
327
    Serial.println("Reading state from EEPROM");
328
329
    for (uint8_t i = 0; i < BSEC_MAX_STATE_BLOB_SIZE; i++) {
330
      bsecState[i] = EEPROM.read(i + 1);
331
      Serial.println(bsecState[i], HEX);
332
    }
333
334
    iaqSensor.setState(bsecState);
335
    checkIaqSensorStatus();
336
  } else {
337
    // Erase the EEPROM with zeroes
338
    Serial.println("Erasing EEPROM");
339
340
    for (uint8_t i = 0; i < BSEC_MAX_STATE_BLOB_SIZE + 1; i++)
341
      EEPROM.write(i, 0);
342
343
    EEPROM.commit();
344
  }
345
}
346
347
void updateState(void)
348
{
349
  bool update = false;
350
  /* Set a trigger to save the state. Here, the state is saved every STATE_SAVE_PERIOD with the first state being saved once the algorithm achieves full calibration, i.e. iaqAccuracy = 3 */
351
  if (stateUpdateCounter == 0) {
352
    if (iaqSensor.iaqAccuracy >= 3) {
353
      update = true;
354
      stateUpdateCounter++;
355
    }
356
  } else {
357
    /* Update every STATE_SAVE_PERIOD milliseconds */
358
    if ((stateUpdateCounter * STATE_SAVE_PERIOD) < millis()) {
359
      update = true;
360
      stateUpdateCounter++;
361
    }
362
  }
363
364
  if (update) {
365
    iaqSensor.getState(bsecState);
366
    checkIaqSensorStatus();
367
368
    Serial.println("Writing state to EEPROM");
369
370
    for (uint8_t i = 0; i < BSEC_MAX_STATE_BLOB_SIZE ; i++) {
371
      EEPROM.write(i + 1, bsecState[i]);
372
      Serial.println(bsecState[i], HEX);
373
    }
374
375
    EEPROM.write(0, BSEC_MAX_STATE_BLOB_SIZE);
376
    EEPROM.commit();
377
  }
378
}

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

tres schrieb:
> Was amche ich falsch....?
Lies bitte mal die Bedienungsanleitung über dem Texteingabefeld. Da 
steht:
1
Antwort schreiben
2
Wichtige Regeln - erst lesen, dann posten!
3
 * ...
4
 * Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

tres schrieb:
> Was amche ich falsch....?
Wie ist deine Schaltung?
Hast du ein Speicheroszi und/oder einen Logikanalyzer?

: Bearbeitet durch Moderator
von tres (Gast)


Lesenswert?

Der BME680 ist ganz normal ueber i2c bus angeschlossen und kann auch 
ausgelesen werden...Temperatur etc. kommen an mit vernuenftigen Werten

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Dort steht "die Kalibrierung kann bis zu 12h dauern":
https://sensebox.de/projects/de/2020-04-05-innenraumluftqualitaet-station#kalibrierungswert

Und dort sind mehrere Zeiten angegeben:
https://community.bosch-sensortec.com/t5/MEMS-sensors-forum/Reference-for-VOC-calibration-of-BME680/td-p/18714/page/2

Die Seite 1 dieses Threads hat auch noch interessante Infos...

von Testr (Gast)


Lesenswert?

Aber der Code stimmt so?

von bastler (Gast)


Lesenswert?

Wenn der so gepostet wird schaut den sich keiner an.

Es gibt schon Gründe, warum man vorher was lesen sollte, vielleicht ist 
es ja mit dem Code genau so.

von Wolfgang (Gast)


Lesenswert?

tres schrieb:
> Hier ist mein code

Um festzustellen, ob es an deiner Hardware oder an deiner Software 
liegt, könntest du versuchsweise einen Code aufspielen, der vermutlich 
nicht zum ersten Mal auf einem Controller landet, z.B.
https://github.com/adafruit/Adafruit_BME680

Nur um erstmal mit dem Sensor umgehen zu lernen, dürfte der ganze 
WiFi-Kram auch erstmal eher in die Rubrik Spielerei gehören.

von Michael U. (amiga)


Lesenswert?

Hallo,

Wolfgang schrieb:
> tres schrieb:
>> Hier ist mein code
>
> Um festzustellen, ob es an deiner Hardware oder an deiner Software
> liegt, könntest du versuchsweise einen Code aufspielen, der vermutlich
> nicht zum ersten Mal auf einem Controller landet, z.B.
> https://github.com/adafruit/Adafruit_BME680
>
> Nur um erstmal mit dem Sensor umgehen zu lernen, dürfte der ganze
> WiFi-Kram auch erstmal eher in die Rubrik Spielerei gehören.

Er benutzt die Bosch-Lib, Adafruit nicht...
Die aktuelle Version der bsec-Lib braucht etliche Stunden bis sie 
wenigstens auf Status 1 geht und reagiert auf größere Änderungen  am 
Anfang (mehrere Tage!) gern damit von Stus 3 wieder auf 0 oder 1 
zufallen.
Hängt stark von der Änderung im Umfeld ab, meiner liegt zu name an der 
Balkontür, wenn die ein paar Minuten auf war braucht er "ewig" bis er 
wieder auf Status 3 ist.

Gruß aus Berlin
Michael

von Jonas (Gast)


Lesenswert?

Ein unangenehmer Sensor.
Offensichtlich schwierig in Betrieb zu nehmen.
Schwierig anzusteuern.
Bosch macht auch noch so ein Geheimnis aus den Details.
Teuer.
Rentiert sich wenigstens die Genauigkeit?

von Michael U. (amiga)


Lesenswert?

Hallo,

Jonas schrieb:
> Ein unangenehmer Sensor.
> Offensichtlich schwierig in Betrieb zu nehmen.
> Schwierig anzusteuern.
Jaein zu allem. ;)

> Bosch macht auch noch so ein Geheimnis aus den Details.
> Teuer.
Hier ja.
> Rentiert sich wenigstens die Genauigkeit?

Wenn das Dateidatum stimmt läuft er hier seit Anfang 2020.
Nur aus Neugier gekauft...
So wie ich es inzwischen verstanden habe: es ist ein Umweltsensor für 
Innenräume. Das sagt aus, daß über längere Zeit Zustandsdaten - von was 
auch immer - gesammelt und bewertet werden. Am einem Arbeitsplatz hat er 
nach einiger Zeit gelernt, wie die Luft dort normalerweise ist und das 
ist dann ok für ihn als Luftqualität. Ergibt also durchaus Warnungen 
wenn plötzlich bestimme unerwünschte Sachen auftauche usw.
Das macht die BSEC-Lib von Bosch wohl durchaus gut.
In meiner Raucherbude hat er so nach 2 Wochen die Erkenntnis gewonnen 
daß das hier wohl Normal ist. Beim Lüften fällt er dann in Ohnmacht, am 
Anfang eben dann of wieder Status 1 oder 0 für "ich blicke hier nicht 
mehr durch".
Das lernt er aber mit der BSEC wirklich über die Zeit.
Mein Bekannter (Nichtraucher) hat die gleiche Erfahrung gemacht, 
allerdings steht seiner günstiger im Zimmer. Er hat auch die 
CO2-Auswertung noch mit reingenommen, ich bisher nicht. Die aktuelle 
BSEC habe ich Anfang Oktober eingebaut und mit Arduino 1.8.19 und ESP 
3.0.2 compiliert, wollte nur schauen, ob damit noch alles läuft.
Der IAQ-Wert wird bis max. 250 scaliert, auswertewn könnte man also 
größeren Änderungen innerhalb relativ kurzer Zeit. Zeit 10-15min, 
Änderung um 30-50 innerhalb dieser Zeit.
Eine praktische Verwendungung habe ich eigentlich nicht, aber nun ist er 
eben da...

Gruß aus Berlin
Michael

von Jonas (Gast)


Lesenswert?

Danke Michael, sehr interessant. Also quasi ein Sensor mit eingebauter 
Intelligenz :)
Habe auch noch 2 Exemplare in der Schublade, mal aus Neugier gekauft.
Selber bin ich was die Luftqualität betrifft mit CO2- und Mikropartikel- 
Sensor zufrieden. Interessant wäre aber für mich, ob Raucherqualm der 
zuweilen vom Balkon unter mir in die Wohnung zieht mit dem Bosch 
sensibel genug detektierbar wäre daß die Fenster schnell genug 
geschlossen werden könnten.

von Michael U. (amiga)


Lesenswert?

Hallo,

Jonas schrieb:
> Interessant wäre aber für mich, ob Raucherqualm der
> zuweilen vom Balkon unter mir in die Wohnung zieht mit dem Bosch
> sensibel genug detektierbar wäre daß die Fenster schnell genug
> geschlossen werden könnten.

Das wirst Du vermutlich nur durch Versuch und einen längeren Zeitraum 
raus bekommen. Mit dem Meßzyklen der BSEC-Lib habe ich nicht 
experimetiert, meiner steht auf generic_33v_3s_4d.
Ich laß mir die Daten alle paar Minuten per MQTT schicken, habe die aber 
nie in die vorhandene Datenbank gelegt um sowas mal auswerten zu 
können...
Die Adafruit BME680 Lib nutzt meines Wissens eigene Rechenreien, habe 
ich damals aber nur angetestet und dann die Bosch-Lib eingebunden.

Gruß aus Berlin
Michael

von Jonas (Gast)


Lesenswert?

Michael U. schrieb:
> Das wirst Du vermutlich nur durch Versuch und einen längeren Zeitraum
> raus bekommen.

Ich bin skeptisch weil meine Nichtraucher-Nase da sehr schnell ist. Auf 
jeden Fall klingt die Selbstlern- Funktionalität sehr verlockend. Kennst 
Du / kennt wer eine fertige BME Lösung inkl. Bosch-Lib deren fertige 
Werte man (seriell) abgreifen kann?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.