Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

ESP8266 (ESP-07), DHT22, serwer WWW - Po pewnym czasie strona się nie wyświetla.

sq9etc 28 Mar 2020 18:15 2283 52
  • #1
    sq9etc
    Level 12  
    Skopiowałem żywcem program z tej strony:
    ESP8266 DHT11/DHT22 Temperature and Humidity Web Server with Arduino IDE

    Niestety po dłuższym czasie (1 - 2 dni) strona WWW przestaje się wyświetlać w przeglądarce. Widać, że urządzenie żyje, ponieważ miga niebieska dioda na płytce, w chwili wysyłania komunikatów na port szeregowy.
    Czy ktoś się spotkał z podobnym przypadkiem i może coś podpowiedzieć?
    Układ jest podłączony jak na tym schemacie:
    Link
    Do you have a problem with Arduino? Ask question. Visit our forum Arduino.
  • #2
    khoam
    Level 41  
    Z jaką wersją menadżera płytek ESP8266 skompilowałeś ten program? Najnowsza wersja to 2.6.3.
  • #3
    kaczakat
    Level 33  
    Sprawdź działanie strony wysyłając jakiś licznik sekund. Wyeliminuje to zawieszanie się spowodowane DHT. Czasem ktoś narzeka, że co jakiś czas czujnik potrafi się zawiesić i pomaga jedynie odłączenie zasilania. Ja tego nie zauważyłem, ale nie testowałem jakoś długo stabilności działania. Taki czujnik można zasilić z pinu uC i jeśli przestanie odpowiadać zrobić ON/OFF. Ale to trzeba jakoś ogarnąć w kodzie.
  • #4
    khoam
    Level 41  
    sq9etc wrote:
    Niestety po dłuższym czasie (1 - 2 dni) strona WWW przestaje się wyświetlać w przeglądarce.

    W tym programie, do którego podałeś link, w pętli loop() w ogóle nie jest sprawdzany bieżący status klienta sieci WiFi (ESP pracuje w trybie STA) - to też może być przyczyną takiego zachowania. Możesz to zweryfikować, spróbuj odpingować ESP, kiedy przestanie się wyświetlać strona.
  • #5
    sq9etc
    Level 12  
    khoam wrote:
    Z jaką wersją menadżera płytek ESP8266 skompilowałeś ten program? Najnowsza wersja to 2.6.3.

    Gdzie to można sprawdzić? Arduino IDE 1.8.12. Jeśli chodzi o wersje biblioteki do obsługi ESP8266, która wyświetla się w menadżerze płytek, to tak, jest to wersja 2.6.3.
  • #6
    khoam
    Level 41  
    sq9etc wrote:
    Jeśli chodzi o wersje biblioteki do obsługi ESP8266, która wyświetla się w menadżerze płytek, to tak, jest to wersja 2.6.3.

    Tak, o to mi chodziło. Spróbuj przetestować pingowanie do ESP, kiedy nie masz dostępu do strony.
  • #7
    sq9etc
    Level 12  
    kaczakat wrote:
    Czasem ktoś narzeka, że co jakiś czas czujnik potrafi się zawiesić i pomaga jedynie odłączenie zasilania.

    Też mam ten problem. Gdy połączyłem zalinkowany program z tym Network Time Protocol to miałem taki efekt. Dodałem sobie na stronie wyświetlanie daty i czasu oprócz temperatury i wilgotności. Po kilkudziesięciu minutach, do kilku godzin przestawały się pojawiać odczyty z DHT, a czas się zmieniał. Dołożyłem coś takiego, że gdy 3 razy czujnik nie zwróci prawidłowych wartości to robiłem ESP.reset. Niestety to nie pomogło. Musiałem wyłączyć i włączyć zasilanie układu. Po tym przez jakiś czas działało i znowu było to samo. Moduł resetował mi się w kółko po każdych nieudanych trzech próbach odczytu z DHT.

    Dodano po 4 [minuty]:

    khoam wrote:
    sq9etc wrote:
    Jeśli chodzi o wersje biblioteki do obsługi ESP8266, która wyświetla się w menadżerze płytek, to tak, jest to wersja 2.6.3.

    Tak, o to mi chodziło. Spróbuj przetestować pingowanie do ESP, kiedy nie masz dostępu do strony.

    O tym pingu nie pomyślałem, to jest jakaś myśl. Jak tak się stanie to sprawdzę. Na razie działa od prawie dwóch dni.
  • #8
    khoam
    Level 41  
    Do obsługi sensorów DHT11/22 zdecydowanie lepszą biblioteką dla ESP jest DHTesp niż Adafruit m.in. lepsza jest diagnostyka błędów dla DHT.
    https://github.com/beegee-tokyo/DHTesp
  • #9
    sq9etc
    Level 12  
    Możliwe, może kiedyś sprawdzę. Ale takie zachowanie czujnika sugeruje, że to nie jest problem software'owy, no chyba, że chodzi o oprogramowanie wbudowane czujnika. Po resecie chyba wszystko powinno się przeinicjalizować i działać normalnie.
  • #10
    sq9etc
    Level 12  
    sq9etc wrote:
    kaczakat wrote:
    Czasem ktoś narzeka, że co jakiś czas czujnik potrafi się zawiesić i pomaga jedynie odłączenie zasilania.

    Też mam ten problem. Gdy połączyłem zalinkowany program z tym Network Time Protocol to miałem taki efekt. Dodałem sobie na stronie wyświetlanie daty i czasu oprócz temperatury i wilgotności. Po kilkudziesięciu minutach, do kilku godzin przestawały się pojawiać odczyty z DHT, a czas się zmieniał. Dołożyłem coś takiego, że gdy 3 razy czujnik nie zwróci prawidłowych wartości to robiłem ESP.reset. Niestety to nie pomogło. Musiałem wyłączyć i włączyć zasilanie układu. Po tym przez jakiś czas działało i znowu było to samo. Moduł resetował mi się w kółko po każdych nieudanych trzech próbach odczytu z DHT.

    Dziś znowu mnie to spotkało.
    Tak wygląda fragment zrzutu do pliku z RealTerma:
    Code:
    ...
    
    Local time: 2020-04-03 07:20:49
    Temperature: 22.00ÂşC
    Humidity: 48.70%
    020-04-03 07:20:49


    Local time: 2020-04-03 07:20:59
    Temperature: 22.00ÂşC
    Humidity: 48.70%

    Soft WDT reset

    >>>stack>>>

    ctx: sys
    sp: 3fffed40 end: 3fffffb0 offset: 01b0
    3fffeef0:  40242a1c efd8a1fc 60000600 4021223d 
    3fffef00:  00000000 3ffed558 00000000 00000000 
    3fffef10:  40231530 3ffed558 3ffee510 60000600 
    ...
    3fffff90:  3fffdad0 00000000 3ffeed50 40100229 
    3fffffa0:  3fffdad0 00000000 3ffeed50 402088e5 
    <<<stack<<<

     ets Jan  8 2013,rst cause:2, boot mode:(3,7)

    load 0x4010f000, len 1392, room 16
    tail 0
    chksum 0xd0
    csum 0xd0
    v3d128e5c
    ~ld
    Starting UDP
    Local port:   123

    Time server IP:   194.146.251.100

    Sending NTP request ...

    Sending NTP request ...
    NTP response:   1585898481

    Local time: 2020-04-03 07:21:21
    Failed to read from DHT sensor!
    Failed to read from DHT sensor!
    020-04-03 07:21:21

    NTP response:   1585898486

    Local time: 2020-04-03 07:21:26
    Failed to read from DHT sensor!
    Failed to read from DHT sensor!
    020-04-03 07:21:26

    NTP response:   1585898496

    Local time: 2020-04-03 07:21:36
    Failed to read from DHT sensor!
    Failed to read from DHT sensor!
    ˙
     ets Jan  8 2013,rst cause:2, boot mode:(3,7)

    load 0x4010f000, len 1392, room 16
    tail 0
    chksum 0xd0
    csum 0xd0
    v3d128e5c
    ~ld
    Starting UDP
    Local port:   123

    Time server IP:   194.146.251.100

    Sending NTP request ...

    Sending NTP request ...
    NTP response:   1585898511

    Local time: 2020-04-03 07:21:51
    Failed to read from DHT sensor!
    Failed to read from DHT sensor!
    020-04-03 07:21:51

    NTP response:   1585898516

    Local time: 2020-04-03 07:21:56
    Failed to read from DHT sensor!
    Failed to read from DHT sensor!
    020-04-03 07:21:56

    NTP response:   1585898526

    Local time: 2020-04-03 07:22:06
    Failed to read from DHT sensor!
    Failed to read from DHT sensor!
    ˙
     ets Jan  8 2013,rst cause:2, boot mode:(3,7)
    ...

    Wygląda na to, że zadziałał Watch Dog, ale z jakiej przyczyny nie wiem. Może opóźniała się odpowiedź z serwera NTP. Nie usprawiedliwia to jednak tego, że po resecie nie można już dogadać się z czujnikiem.
  • #11
    khoam
    Level 41  
    sq9etc wrote:
    Wygląda na to, że zadziałał Watch Dog, ale z jakiej przyczyny nie wiem.

    Zwykle tak się zdarza, kiedy w programie jednocześnie używa się asynchronicznego serwera WWW wraz z inną biblioteką pracującą w trybie synchronicznym po TCP lub UDP.

    sq9etc wrote:
    Gdy połączyłem zalinkowany program z tym Network Time Protocol to miałem taki efekt.

    Dobrze byłoby, abyś pokazał jak to "połączyłeś", w szczególności w pętli loop().

    sq9etc wrote:
    Nie usprawiedliwia to jednak tego, że po resecie nie można już dogadać się z czujnikiem.

    Trochę usprawiedliwia, biorąc pod uwagę, że po Soft WDT Reset zostają "śmieci" w pamięci RAM.
  • #12
    oskar777

    Level 26  
    Ja miałem problem podobny z DHT jak dla ESP-7 wybrałem nie prawidłową ilość pamięci. Czasem jest to też problem z zasilaniem.
  • #13
    sq9etc
    Level 12  
    khoam wrote:

    Dobrze byłoby, abyś pokazał jak to "połączyłeś", w szczególności w pętli loop().

    Kod:
    main.cpp
    Code: c
    Log in, to see the code


    WiFi.h
    Code: c
    Log in, to see the code


    WiFi.cpp
    Code: c
    Log in, to see the code

    khoam wrote:
    sq9etc wrote:
    Nie usprawiedliwia to jednak tego, że po resecie nie można już dogadać się z czujnikiem.

    Trochę usprawiedliwia, biorąc pod uwagę, że po Soft WDT Reset zostają "śmieci" w pamięci RAM.

    Ja tam robię też ESP.reset().
  • #14
    khoam
    Level 41  
    Proponuję następującą modyfikację w loop():
    Code: c
    Log in, to see the code

    sq9etc wrote:
    Ja tam robię też ESP.reset().

    Lepiej użyć ESP.restart() - "czystsza" forma restartu, zamyka poprawnie połączenia sieciowe, nie pozostawia "śmieci" w rejestrach.

    Jak wyglądają statystyki zajętości pamięci RAM po kompilacji?
  • #15
    sq9etc
    Level 12  
    khoam wrote:
    Jak wyglądają statystyki zajętości pamięci RAM po kompilacji?

    36 %. Co zrobić żeby w Atomie nie zamykało się samo to okienko z komunikatami kompilacji? Trudno zobaczyć tę zajętość pamięci, bo zaraz szybko się zamyka.

    Dodano po 9 [godziny] 5 [minuty]:

    yield() nie pomogło. Zobaczę jeszcze z zamianą ESP.reset() na ESP.restart().
  • #16
    khoam
    Level 41  
    sq9etc wrote:
    yield() nie pomogło.

    Zawiesił się program i wykonał Soft WTD Reset? Czy też po wymuszeniu ESP.reset() program nie wznowił pracy poprawnie? To są dwie różne rzeczy.
  • #17
    sq9etc
    Level 12  
    khoam wrote:
    Zawiesił się program i wykonał Soft WTD Reset? Czy też po wymuszeniu ESP.reset() program nie wznowił pracy poprawnie? To są dwie różne rzeczy.

    Tego nie wiem, bo nie miałem podpiętego podsłuchu. Efekt był taki, że po jakimś czasie przestał się czytać DHT22 jak wcześniej. Mogę tylko podejrzewać, że przyczyna była ta sama, czyli Soft WDT Reset.
  • #18
    khoam
    Level 41  
    sq9etc wrote:
    Tego nie wiem, bo nie miałem podpiętego podsłuchu.

    Proponuję jednak to zrobić. W przeciwnym wypadku rozwiązywanie tego problemu, to będzie strzelanie na oślep. Może się uda ;)
  • #19
    sq9etc
    Level 12  
    Po zmianach:
    -dodanie yield() tam gdzie sugerowałeś,
    -zamiana ESP.reset() na ESP.restart(),

    jest to samo, tzn.:
    -występuje Soft WDT reset,
    -po powyższym nie można dogadać się z DHT22, ESP.restart() nie pomaga na brak komunikacji z czujnikiem.
  • #20
    khoam
    Level 41  
    sq9etc wrote:
    jest to samo, tzn.:
    -występuje Soft WDT reset,

    Czy również po tym, jak prawidłowo zostały wyświetlone ostatnie wartości temperatury i wilgotności (vide post #10)?
    Po jakim czasie wystąpił ten Soft WDT Reset?
  • #21
    sq9etc
    Level 12  
    khoam wrote:
    sq9etc wrote:
    jest to samo, tzn.:
    -występuje Soft WDT reset,

    Czy również po tym, jak prawidłowo zostały wyświetlone ostatnie wartości temperatury i wilgotności (vide post #10)?

    Dokładnie tak.
    khoam wrote:
    Po jakim czasie wystąpił ten Soft WDT Reset?

    Za pierwszym razem po 1h 18m pracy, za drugim po prawie 4-ech godzinach poprawnej pracy.
  • #22
    khoam
    Level 41  
    OK, to pozostaje do wyjaśnienia jedna kwestia. Odnoszę się do pierwszego kodu z postu #13.
    Co konkretnie chciałeś osiągnąć przez użycie zmiennych dHTReadingErrorsCount oraz prevDHTReadingErrorsCount? Od jakiego stanu tych zmiennych chciałeś uzależnić reset układu i w jakiej sytuacji?
    To co jest w kodzie, to widzę ;)
  • #23
    sq9etc
    Level 12  
    khoam wrote:
    OK, to pozostaje do wyjaśnienia jedna kwestia. Odnoszę się do pierwszego kodu z postu #13.
    Co konkretnie chciałeś osiągnąć przez użycie zmiennych dHTReadingErrorsCount oraz prevDHTReadingErrorsCount? Od jakiego stanu tych zmiennych chciałeś uzależnić reset układu i w jakiej sytuacji?
    To co jest w kodzie, to widzę ;)


    Po trzech nieudanych próbach odczytu czujnika ma być wykonany reset. Z tym, że jeżeli w jednym cyklu nie uda się odczytać temperatury i wilgotności to zaliczam to jako jeden błąd. Dlatego wprowadziłem dwie zmienne i inkrementuję dHTReadingErrorsCount przy odczycie wilgotności, tylko gdy nie zrobiłem tego przy odczycie temperatury. Stąd ten warunek:
    Code: c
    Log in, to see the code
  • #24
    krzbor
    Level 23  
    Miałem program na ESP, który czasami się restartował (kilka razy na dobę). ESP współpracowało z SIM800. Uznałem, że winą są zakłócenia z GSM. Musiałem jednak poprawić program i restarty były niemal cały czas. W końcu ustaliłem, że problem wynika ze zwracania "String" jako rezultat funkcji - powinno działać, a nie działa. Rozwiązałem problem rezygnując ze zwracania wartości "String" przez funkcję - "String" jest teraz przekazywany do funkcji przez referencję i wszystko zaczęło działać. W Twoim kodzie jest funkcja "processor", która zwraca String'a. Może też występuje ten sam problem co u mnie?
  • #25
    khoam
    Level 41  
    sq9etc wrote:
    Po trzech nieudanych próbach odczytu czujnika ma być wykonany reset.

    Niezależnie od tego w jakim długim okresie czasu nastąpiły?

    krzbor wrote:
    Rozwiązałem problem rezygnując ze zwracania wartości "String" przez funkcję - "String" jest teraz przekazywany do funkcji przez referencję i wszystko zaczęło działać.

    Faktycznie zwracanie całego obiektu String przez funkcję to nie jest dobra praktyka. Problem polega na tym, że funkcja send_P() wymaga podania callback o typie AwsTemplateProcessor:
    Code: c
    Log in, to see the code
    Typ AwsTemplateProcessor jest zdefiniowany jako:
    Code: c
    Log in, to see the code
    więc nie można "podstawić" funkcji callback innego typu niż String(const String&).

    Można uniknąć wielokrotnych alokacji pamięci dla obiektu String zwracanego przez funkcję processor() definiując zmienną globalną typu String z rezerwacją odpowiedniej długości bufora z użycie String.reserve(). Zmienna ta byłaby modyfikowana wewnątrz funkcji processor() i zwracana przez tę funkcję - nie byłaby więc każdorazowo tworzona nowa zmienna String na potrzeby wywołania funkcji send_P().

    Można też użyć send() zamiast send_P() i przekazywać wprost zmienną String modyfikowaną przez processor().
    Code: c
    Log in, to see the code
  • #26
    krzbor
    Level 23  
    Rzeczywiście, nie zauważyłem, że ta funkcja to callback. Moje doświadczenie z obiektem String było takie, że jeśli funkcja zwraca ten obiekt i jest on przypisywany do zmiennej globalnej, to jest OK (tak mam w innych projektach). Problem się pojawił, gdy rezultat funkcji zwracającej String był przechowywany w innej funkcji w zmiennej lokalnej - innymi słowy dochodziła obsługa stosu. Skoro tu mamy callback to też zachodzi ta sytuacja.
  • #27
    khoam
    Level 41  
    @krzbor Dla mnie najlepszym sposobem na używanie klasy String jest użycie klasy std::string z biblioteki standardowej C++ :) Na szczęście w wypadku ESP8266 jest ta biblioteka dostępna. Klasa String w HAL dla ESP8266 została przepisana z wersji HAL dla AVR i jest to moim zdaniem gigantyczne nieporozumienie.
  • #28
    sq9etc
    Level 12  
    khoam wrote:
    sq9etc napisał:
    Po trzech nieudanych próbach odczytu czujnika ma być wykonany reset.

    Niezależnie od tego w jakim długim okresie czasu nastąpiły?

    Trafna uwaga, choć u mnie jak czujnik przestawał się czytać, to już na amen.

    Dodano po 4 [minuty]:
    Zamieniłem Send_P na Send, ale nic się nie zmieniło, tzn. po kilkudziesięciu minutach czujnik przestawał odpowiadać.
    Zakomentowałem część kodu odpowiedzialną za pobieranie i konwertowanie czasu do tekstu. Zamiast tego wyświetlam sobie numer odczytu od uruchomienia modułu. Na obecną chwilę jest 5080 odczytów, czyli od ponad 14-tu godzin wszystko działa. Dalej mam wyświetlane trzy zmienne jak miałem. Tak, że nie wygląda mi to na jakiś problem ze stringami.
  • #29
    khoam
    Level 41  
    sq9etc wrote:
    choć u mnie jak czujnik przestawał się czytać, to już na amen.

    Może tak się zdarzać, ale uważam, że taki licznik powinien być resetowany po określonym czasie, kiedy nie występują błędy - błędne odczyty mogą też wynikać z chwilowych zakłóceń, na które nie ma się wpływu. Natomiast, kiedy faktycznie przestanie czytać czujnik, to i tak kolejne 3 błędne odczyty od razy wyjdą.

    Dobrze byłoby też sprawdzić, czy w trakcie działania nie ma jakichś wycieków pamięci. Można użyć funkcji getFreeHeap(), która zwraca (jako uint32_t) ilość dostępnej pamięci na stercie.
    Użycie funkcji:
    Code: c
    Log in, to see the code
    W loop() można co jakiś czas wysyłać informację na Serial.

    https://arduino-esp8266.readthedocs.io/en/latest/libraries.html#esp-specific-apis
  • #30
    sq9etc
    Level 12  
    Odremowałem fragment kodu konwertujący czas z zmiennej typu uint32_t na ciąg tekstowy i w tej postaci program działał przez ponad 3 doby.
    W pierwotnej wersji, skleconej na szybko z dwóch, którą prezentowałem na listingu była niefajna rzecz. Mianowicie serwer czasu był odpytywany tak samo często jak czujnik, czyli co 10 s.
    Teraz zmieniłem to w ten sposób, że synchronizacja następuje raz na dobę po północy wg czasu zimowego. Na razie działa od wieczora. Mam nadzieję, że w ten sposób będzie to już działać stabilnie przez dłuższy czas. Ciekaw jestem jaki będzie rozjazd czasu pod koniec doby. Czas inkrementuję sobie co odczyt czujnika, czyli co 10 s.