Forum: Mikrocontroller und Digitale Elektronik Was passiert da in einem ESP8266 (12E)?


von Uwe B. (boerge) Benutzerseite


Angehängte Dateien:

Lesenswert?

Moin,

ich bin gerade ein wenig am Experimentieren mit einem ESP8266 im 
DeepSleep-Mode, um den Stromverbrauch eines Sensormodules zu minimieren. 
Dabei kann ich mir zwei Zeiträume während der Verarbeitung im ESP8266 
nicht erkären.

Versuchaufbau:
* das Sensormodul, ein ESP8266-12E, welches nach der Verarbeitung in den 
DeepSleep-Mode geht und nach x Sekunden wieder aufwacht etc.. Zu 
bestimmten Zeitpunkten während der Verabeitung wird jeweils ein Impuls 
an ein GPIO-Pin ausgegeben
* der Stromverbrauch wird mit einer zweiten Schaltung, welches aus einen 
MC und einem INA219-Modul besteht, gemessen. Über oben erwähnte Impulse 
wird die Strommessung getriggert und die Anzahl der Impulse auch im 
Messergebnis mitgeloggt.

Es entsteht dabei angehangenes Diagramm (x-Achse: Zeit in ms, y-Links 
Strom in mA, y-rechts Anzahl der Impulse; blaue Kurve Stromverbrauch, 
grün x.Impuls)

Ich kann mir die langen Zeiten in Abschnitt 6 und 7 nicht erklären.

In Abschnitt 6 läuft dieser Code:
1
// **************************************************************
2
void wifi_connect()
3
{
4
  uint8_t count = 0;
5
  
6
  // Wifi anschalten
7
  WiFi.forceSleepWake();
8
  delay(1);
9
  // kein Laden/Sichern der Wifi-Konfiguration im Flash
10
  WiFi.persistent( false );
11
  // ins WIFI anmelden
12
  WiFi.mode(WIFI_STA);
13
  // feste IP-Konfiguration
14
  WiFi.config(ip, gateway, subnet); 
15
  // wenn Daten im RTC valid, dann mit diesen zuerst den Connect versuchen
16
  if (rtc_valid) {
17
  if (debug) Serial.println("Wifi.begin() mit RTC-Daten.");
18
  WiFi.begin(ssid, password, rtc.vars.wifi_channel, rtc.vars.wifi_ap_mac, true);  
19
  } else {
20
  if (debug) Serial.println("Wifi.begin() ohne RTC-Daten.");
21
    WiFi.begin(ssid, password);
22
  }
23
  WiFi.hostname(hostname);
24
  if (debug) Serial.print("Connect to WiFi: ") ;
25
  while (WiFi.status() != WL_CONNECTED) {
26
  count++;
27
    // nach 5s keine Verbindung mit RTC-Daten zustande gekommen, also doch scannen  
28
  if (count == 100) {
29
      if (debug) Serial.println("neuer Versuch ohne RTC-Daten!!!");
30
    WiFi.disconnect();
31
      delay(10);
32
      WiFi.forceSleepBegin();
33
      delay(10);
34
      WiFi.forceSleepWake();
35
      delay(10);
36
      WiFi.begin(ssid, password);  
37
    }
38
  // nach 15s keine Verbindug zustande gekommen
39
  if (count == 300) {
40
    if (debug) {
41
      Serial.println("...no connection (WLAN)!!!");
42
      Serial.flush();
43
    }
44
    write_rtc_memory((rtc.vars.awake_time+millis()-awake_time));
45
    WiFi.disconnect(true);
46
      delay(1);
47
      WiFi.mode( WIFI_OFF );
48
    ESP.deepSleep(deepsleep_time);
49
  }
50
    delay(50);
51
    if (debug) Serial.print(".");
52
  }
53
  if (debug) {
54
    Serial.println("");
55
    Serial.println("WiFi connected!");
56
    Serial.println(WiFi.localIP());
57
    Serial.println("");
58
  }
59
}
Wobei hier noch zu bemerken ist, dass das Wifi-Modul nach dem Aufwachen 
mittels:
1
WiFi.mode(WIFI_OFF);
2
WiFi.forceSleepBegin();
3
delay(1);
ausgeschaltet wird, da es während des Auslesens der Sensoren ja noch 
nicht benötigt wird.

Weiterhin wird MAC-Adresse und Kanal der vorherigen Verbindung im RTC 
gerettet und mit diesen Daten der erste Verbindungsversuch gestartet 
(möglichst kein Wifi-Scannen, was Zeit kostet). Das angehangene Diagramm 
ist ein solcher erfolgreicher Versuch mit den gesicherten Daten. Und es 
wird mit fester IP etc. gearbeitet, um die Latenzen für DHCP zu 
minimieren.


In Abschnitt 7 folgende Codezeilen:
1
// **************************************************************
2
void mqtt_reconnect ()
3
{
4
  uint8_t count = 0;
5
  // MQTT...
6
  // ...initialisieren
7
  mqtt_client.setServer(mqttServer, mqttPort);
8
  // ...verbinden
9
  while (!mqtt_client.connected()) {
10
    if (debug) Serial.println("Connecting to MQTT...");
11
    if (mqtt_client.connect(mqttClientId, mqttUser, mqttPassword )) {
12
       if (debug) Serial.println("Connected!");  
13
    } else {
14
      if (debug) {
15
        Serial.print("failed with state ");
16
        Serial.print(mqtt_client.state());
17
      }
18
      count++;
19
      delay(100);
20
    }
21
  if (count == 100) {
22
    // keine Verbindung zum Broker, dann wieder schlafen legen
23
      if (debug) {
24
        Serial.println("...no connection (MQTT-Broker)!!!");
25
      Serial.flush();
26
      }
27
      write_rtc_memory((rtc.vars.awake_time+millis()-awake_time));
28
    ESP.deepSleep(deepsleep_time);
29
  }
30
  }
31
}

Ich kann mir konkret folgende Verarbeitungszeiten nicht erklären:
* Abschnitt 6: eigentlich insgesamt, warum dauert das eine ganze 
Sekunde?
* Abschitt 7: 1450ms - ca. 2340ms, welcher in allen Messungen konstant 
ist

Wer kann mir ein paar Tipps geben, was da passiert und wie man das 
abstellen könnte? Hat jemand noch weiter Tipps, um die Verarbeitung 
weiter optimieren zu können?

Grüße & Danke Uwe

von Uwe B. (boerge) Benutzerseite


Lesenswert?

Uwe B. schrieb:
> welches nach der Verarbeitung in den
> DeepSleep-Mode geht

...vielleicht noch eine Ergänzung, falls die Frage kommen sollte, in 
DeepSleep gehe ich mit:
1
ESP.deepSleep(deepsleep_time, WAKE_RF_DISABLED);

Grüße Uwe

von Michael U. (amiga)


Lesenswert?

Hallo,

am Anfang habe ich solche Experimente auch gemacht.
Ende vom Lied: DeepSleep für 300s, aufwachen, normaler WLAN-Connect mit 
fester IP, connect zum MQTT Broker. BME280 im forced-Mode lesen, BH1750 
lesen, Daten per MQTT rausschicken, DeepSleep.
Dauer ca. 2-3s komplett.
Ein ESP32 mit BME280 und MAX44009 verhält sich nahezu identisch, 
sporadisch brauchen beide mal rund 4s bis der WLAN-Connect steht, im 
identischen Umfeld.
Habe ich nicht weiterverfolgt. Eine 18650 LiFePO4 mit 1500mA hält stabil 
2 Monate durch, dann ist laden fällig, reicht mir so.

Gruß aus Berlin
Michael

von Stefan S. (st_schulte)


Lesenswert?

Moin!

Also ich weiß nicht wie vergleichbar der ESP8266 mit dem ESP32 ist,
aber Andreas Spiess ist der Sache beim ESP32 auf den Grund gegangen:
https://youtu.be/CJhWlfkf-5M?t=933
(Link zur Stelle mit dem Graphen des ESP32)
Andreas ist ja Schweitzer, vielleicht fragst Du mal :-)

Gruß,
Stefan

von Stefan F. (Gast)


Lesenswert?

Finde heraus, an welchen Stelle sich deine Code-Ausführung in den beiden 
fraglichen Zeitabschnitten befindet. Ich würde dazu ggf. weitere 
debug-Meldungen hinzufügen. Zeiche das dann im Diagramm ein.

Da du den Wert von deepsleep_time nicht gezeigt hast, kann ich gar nicht 
einmal prüfen, ob diese Zeit mit dem Diagramm überein stimmt.

von Uwe B. (boerge) Benutzerseite


Lesenswert?

Moin,

Stefan ⛄ F. schrieb:
> Da du den Wert von deepsleep_time nicht gezeigt hast, kann ich gar nicht
> einmal prüfen, ob diese Zeit mit dem Diagramm überein stimmt.

...ich denke mal der Wert für deepsleep_time (derzeit bei 2min) ist für 
meine Frage nicht relevant. Das Diagramm zeigt den Stromverbrauch 
während der ESP wach ist... Die Schlafzeiten passen auch zu dieser 
deepsleep_time. Der Stromverbrauch während der Schlafphase entspricht 
auch halbwegs meinen Erwartungen (0.1 - 0.2 mA, wobei aber auch die 
Genauigkeit/Auflösung des INA219 bei diesen geringen Strömen schon eine 
Rolle spielt, sollte man also nicht so ernst nehmen ;-)).

Hier mal der Code meiner setup()-Routine, der loop() ist leer. D.h. also 
die ca. 2.4s in dem Diagramm ist die Laufzeit von setup():
1
// **************************************************************
2
void setup() 
3
{
4
5
  awake_time = millis();
6
  
7
  pinMode(TRIGGER_PIN, OUTPUT);
8
  digitalWrite(TRIGGER_PIN, HIGH);
9
  
10
  pulse_pin(TRIGGER_PIN);      // ==> 1
11
12
  // Wifi ausschalten, da zuerst nur die Sensoren etc. ausgelesen werden sollen
13
  WiFi.mode(WIFI_OFF);
14
  WiFi.forceSleepBegin();
15
  delay(1);
16
17
  pulse_pin(TRIGGER_PIN);  // ==> 2
18
19
  // RTC-Memory auslesen und validieren
20
  ESP.rtcUserMemoryRead(0, (uint32_t *) &rtc.data, sizeof(rtc.data));
21
  if (calculateCRC32((uint8_t*) &rtc.data.data[0], sizeof(rtc.data.data)) == rtc.vars.crc32) {
22
    old_awake_time = rtc.vars.awake_time;
23
    rtc_valid = true;
24
  } else {
25
    old_awake_time = 0;
26
  }
27
28
  pulse_pin(TRIGGER_PIN);  // ==> 3
29
30
  // Konfiguration aus Datei im SPIFFS auslesen
31
  config_read();
32
33
  pulse_pin(TRIGGER_PIN);  // ==> 4
34
35
  // serielle Schnittstelle initialisieren
36
  if (debug) {
37
    Serial.begin(115200);
38
    Serial.println("");
39
    Serial.println("...setup");
40
  }
41
  
42
  Wire.setClock(3400000);
43
  
44
  // BME280
45
  bool status = bme.begin(0x76);  
46
  if (!status) {
47
    if (debug) Serial.println("Could not find a valid BME280 sensor, check wiring!");
48
    while (1);
49
  }
50
  
51
  // BH1750
52
  myLux.powerOn();
53
  myLux.setContHighRes();
54
  
55
  // ADS1115
56
  ads.begin();
57
58
  pulse_pin(TRIGGER_PIN);  // ==> 5
59
60
  // Sensoren auslesen und in Stromsparmode schicken (wenn erforderlich)
61
  sensors_read();
62
  if (debug) {
63
    Serial.println("sensor_read ended.");
64
    Serial.flush();
65
  }
66
67
  pulse_pin(TRIGGER_PIN);  // ==> 6
68
69
  // WiFi initialisieren (incl. Aktivierung Wifi)
70
  wifi_connect();
71
72
  pulse_pin(TRIGGER_PIN);  // ==> 7
73
74
  // MQTT initialisieren
75
  mqtt_reconnect();
76
  
77
  pulse_pin(TRIGGER_PIN);  // ==> 8
78
79
  // MQTT
80
  mqtt_publish_values();
81
  // MQTT-Loop aufrufen, um Telegramm sicher zu versenden
82
  //mqtt_client.loop();
83
  delay(1);
84
85
  pulse_pin(TRIGGER_PIN);  // ==> 9
86
87
  // ESP schlafen legen
88
  if (debug) {
89
    Serial.println("...deepSleep");
90
    Serial.flush();
91
  }
92
  
93
  // aktuelle Wachzeit sowie CRC32 berechnen und in RTC-Memory schreiben
94
  write_rtc_memory((millis()-awake_time));
95
  
96
  pulse_pin(TRIGGER_PIN);  // ==> 10
97
98
  // schlafen gehen
99
  //WiFi.disconnect(true);
100
  //delay(1);
101
  
102
  pulse_pin(TRIGGER_PIN);  // ==> 11
103
  digitalWrite(START_STOP_PIN, LOW);
104
105
  ESP.deepSleep(deepsleep_time, WAKE_RF_DISABLED);
106
  
107
}

Die Routine pulse_pin() erzeugt oben angesprochene Impulse für die 
Auswertung, die Zahlen in den Kommentaren korrespondieren mit den 
Abschnitten (grüne Kurve) im Diagramm. Die Routinen in den Abschnitten 6 
und 7, die mich am meisten interessieren und aus welchen Gründen auch 
immer, sehr lang sind, hatte ich ja oben schon aufgelistet... Dort 
passiert halt nicht sehr viel, aber trotzdem wird jeweils fast eine 
Sekunde "verbraten". Deshalb meine Frage....

Stefan ⛄ F. schrieb:
> Finde heraus, an welchen Stelle sich deine Code-Ausführung in den beiden
> fraglichen Zeitabschnitten befindet. Ich würde dazu ggf. weitere
> debug-Meldungen hinzufügen. Zeiche das dann im Diagramm ein.

Für Abschnitt 6 (wifi_connect) könnte ich noch weiter unterteilen, 
stimmt und werde ich nochmal machen. Abschitt 7 (mqtt_reconnect()) 
besteht eigentlich nur aus mqtt_client.connected() und da finde ich die 
(konstante!) Sekunde "Bedenkzeit" schon recht happig.

Irgendwie werde ich das Gefühl nicht los, dass da Dinge sind, die ich 
mit meinem Code nicht beeinflussen kann und unterlagert noch laufen?

Grüße & Danke Uwe

von Stefan F. (Gast)


Lesenswert?

Uwe B. schrieb:
> Die Routinen in den Abschnitten 6
> und 7, die mich am meisten interessieren und aus welchen Gründen auch
> immer, sehr lang sind, hatte ich ja oben schon aufgelistet..

Der Wifi Verbindungsaufbau dauert typischerweise 1 bis 5 Sekunden.

Den Verbindungsaufbau zum MQTT Server kannst du auf dem Server mal mit 
Wireshark (oder tcpdump) aufzeichnen, dass siehst du welcher der 
Verbindungsteilnehmer langsam ist.

von Timmo H. (masterfx)


Angehängte Dateien:

Lesenswert?

Stefan ⛄ F. schrieb:
> Der Wifi Verbindungsaufbau dauert typischerweise 1 bis 5 Sekunden.
Also bei mir dauert das im Schnitt immer 200ms (connect_time) (Auflösung 
ist aber wegen delay(100) auch nur 100ms ;-), und das ohne statische IP. 
Alle paar Stunden oder Tage verschluckt sicher Router mal, dann dauerts 
auch mal 2 oder 3 Sekunden.
MQTT Connect (mqtttime) dauert meist 20ms bei mir.

Arduino Core 2.6.3
ESP8266 2.4.0
1
void setup() {
2
    int tries = 0;
3
    // put your setup code here, to run once:
4
    Serial.begin(115200);
5
    
6
7
    bool status;
8
    
9
    // default settings
10
    // (you can also pass in a Wire library object like &Wire2)
11
    status = bme.begin(BME280_ADDRESS_ALTERNATE);  
12
    if (!status) {
13
        Serial.println("Could not find a valid BME280 sensor, check wiring!");
14
        //while (1);
15
    }
16
    
17
    //Serial.println("-- Default Test --");
18
    delayTime = 3000;
19
    bme.setSampling(Adafruit_BME280::MODE_FORCED,
20
                    Adafruit_BME280::SAMPLING_X1, // temperature
21
                    Adafruit_BME280::SAMPLING_X1, // pressure
22
                    Adafruit_BME280::SAMPLING_X1, // humidity
23
                    Adafruit_BME280::FILTER_OFF );
24
25
    connect_time = millis();
26
27
    WiFi.mode(WIFI_STA);
28
    WiFi.begin(ssid, password);
29
30
    while (WiFi.status() != WL_CONNECTED) {
31
        delay(100);
32
        Serial.print(".");
33
        if(tries++ > 40){
34
          Serial.println("Conn Timeout");
35
              ESP.deepSleep(60e6);
36
              delay(100);
37
        }
38
39
    }
40
    connect_time = millis()-connect_time;
41
42
    pinMode(15,OUTPUT);
43
    digitalWrite(15, HIGH);
44
45
    Serial.println("");
46
    Serial.println("WiFi connected");
47
    Serial.println("IP address: ");
48
    Serial.println(WiFi.localIP());
49
50
    Serial.println();
51
    client.setServer(mqtt_server, 1883);
52
53
}
54
55
void loop() {
56
    mqtttime = millis();
57
    if (!client.connected()) {
58
        reconnect();
59
    }
60
    mqtttime = millis()-mqtttime;
61
62
    client.loop();
63
    get_BME_Values();
64
    get_Batt_voltage();
65
    publishMQTTdata();
66
    delay(100);
67
    ESP.deepSleep(5*60e6);
68
    delay(100);
69
}
70
71
void reconnect() {
72
  // Loop until we're reconnected
73
74
  while (!client.connected()) {
75
    Serial.print("Attempting MQTT connection...");
76
    // Attempt to connect
77
    if (client.connect("BME280_Client")) {
78
      Serial.println("MQTT connected");
79
    } else {
80
      Serial.print("failed, rc=");
81
      Serial.print(client.state());
82
      Serial.println(" try again in 5 seconds");
83
   
84
      // Wait 5 seconds before retrying
85
      delay(200);
86
    }
87
  }
88
}

: Bearbeitet durch User
von Uwe B. (boerge) Benutzerseite


Lesenswert?

:-(

Timmo H. schrieb:
> Also bei mir dauert das im Schnitt immer 200ms (connect_time) (Auflösung
> ist aber wegen delay(100) auch nur 100ms ;-), und das ohne statische IP.

...da steht nichts anderes im Code, als bei mir. So ganz glaube ich dir 
die 200ms nicht...

Timmo H. schrieb:
> MQTT Connect (mqtttime) dauert meist 20ms bei mir.

....dito

Grüße Uwe

von Timmo H. (masterfx)


Lesenswert?

Uwe B. schrieb:
> ...da steht nichts anderes im Code, als bei mir. So ganz glaube ich dir
> die 200ms nicht...
Siehe Bild oben. Die connect_time wird auch per MQTT an den Server 
gesendet und erzeugt den Plot im Bild. Warum sollte ich lügen?!
Der größte unterschied zu dir ist das ich halt keine statische 
IP-Verwende. Eine statische IP verhindert ja nicht, dass du dich nicht 
trotzdem beim Router anmelden müsstst. Vielleicht ist das sogar 
kontraproduktiv?!
Meine Fritzbox ist übrigens nur die fürs WLAN zuständig, der DHCP läuft 
auf dem ein Vodafone Modem der via LAN an der FB hängt.
1
uint8_t publishMQTTdata(){
2
    char msg[128];
3
    snprintf(msg,128,"{ \"name\": \"BME280\", \"Temp\" : %.2f, \"Pressure\" : %.4f, \"Humidity\": %.2f, \"vBat\" : %.3f }",BME_Data.temp,BME_Data.pressure, BME_Data.humidity, BME_Data.vbat);
4
    client.publish("/balkon/weather", msg);
5
    snprintf(msg,128,"{\"t1\":%ld, \"t2\": %ld }",connect_time, mqtttime);
6
    client.publish("/balkon/stat", msg);
7
8
}

: Bearbeitet durch User
von Uwe B. (boerge) Benutzerseite


Lesenswert?

Uwe B. schrieb:
>> MQTT Connect (mqtttime) dauert meist 20ms bei mir.
>
> ....dito

...hmmm, ausser vielleicht --> macht es einen Unterschied, ob man 
bestimmte Dinge in loop() statt in setup() macht (z.B. das MQTT-Gedöns)?

Grüße Uwe

von Timmo H. (masterfx)


Angehängte Dateien:

Lesenswert?

Kein Plan, kann auch am Router, DHCP oder statischer IP liegen. Einfach 
ausprobieren.
Auf jeden Fall hält mein 750mAh Akku 3-4 Monate (siehe Bild unten recht, 
heute gerade wieder gewechselt nach 104 Tagen)

: Bearbeitet durch User
von Uwe B. (boerge) Benutzerseite


Lesenswert?

Moin,

Timmo H. schrieb:
> Der größte unterschied zu dir ist das ich halt keine statische
> IP-Verwende. Eine statische IP verhindert ja nicht, dass du dich nicht
> trotzdem beim Router anmelden müsstst. Vielleicht ist das sogar
> kontraproduktiv?!

...nach der Theorie eigentlich nicht, da der DHCP-Server keine Lease 
verteilen muss. (In einem meiner (frühen) Experimente könnte man es, 
glaube ich, auch sehen...).

Timmo H. schrieb:
> Warum sollte ich lügen?!

...ist vielleicht falsch rüber gekommen, war nicht so gemeint ;-). Macht 
mich halt nur nachdenklich, da ich keine entscheidenden Unterschiede 
zwischen deinem und meinem Code sehe bzw. keine schlüssige Erklärung 
dafür habe...

Grüße Uwe

von Michael U. (amiga)


Lesenswert?

Hallo,

Timmo H. schrieb:
> Also bei mir dauert das im Schnitt immer 200ms (connect_time) (Auflösung
> ist aber wegen delay(100) auch nur 100ms ;-), und das ohne statische IP.
> Alle paar Stunden oder Tage verschluckt sicher Router mal, dann dauerts
> auch mal 2 oder 3 Sekunden.
> MQTT Connect (mqtttime) dauert meist 20ms bei mir.

grundsätzlich bestätige ich Deine Zeiten, habe aber zuletzt nur mit dem 
ESP32 getestet, da hatte ich um 300ms incl. MQTT-connect in Erinnerung.
Beim ESP32 habe ich eben auch den Effekt, daß er manchmal, heschätzt 
1-2x am Tag bei 5min Raster, lange braucht, dabei dann aber immer stabil 
4-4,2s..
Sollte ich mal meine Stromaufnahme nachmessen? ESP8266/BME280/BH1750 mit 
400mAh haben bei mir nur ca. 3 Wochen durchgehalten.
Ist mir aber eigentlich egal, der Sensor steht auf dem Balkon und der 
Akku ist zum Laden in gut 30s ausgetauscht.

Gruß aus Berlin
Michael

: Bearbeitet durch User
von Uwe B. (boerge) Benutzerseite


Angehängte Dateien:

Lesenswert?

Moin,

Uwe B. schrieb:
> Timmo H. schrieb:
>> Der größte unterschied zu dir ist das ich halt keine statische
>> IP-Verwende. Eine statische IP verhindert ja nicht, dass du dich nicht
>> trotzdem beim Router anmelden müsstst. Vielleicht ist das sogar
>> kontraproduktiv?!
>
> ...nach der Theorie eigentlich nicht, da der DHCP-Server keine Lease
> verteilen muss. (In einem meiner (frühen) Experimente könnte man es,
> glaube ich, auch sehen...).

...ich habe das "DHCP-Experiment" (ohne feste IP; also kein 
wifi.config(...)) mit der jetzigen Konstellation nochmal gefahren. Im 
angehangenen Diagramm sieht man deutlich die Zeit, die der ESP auf die 
IP-Konfiguration wartet...

Man sieht aber auch, dass der Zeitraum davor immer noch unverändert da 
ist, also muss es etwas anderes sein...

Grüße Uwe

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.