Stacja pogodowa esphome - dziwne restarty

No i zostałem zmuszony do szukania pomocy…
Mam problem z wykonaną stacją pogodową opartą o ESP32. Zauważyłem, że co jakiś czas następuje jej reset: czasami co kilka minut, czasami co kilka dni… Zauważyłem zależność, że resety nasilają się podczas opadów - gdy było sucho, system działał bez problemu praktycznie przez cały czasu. Zacząłem więc od wymiany zasilacza, okablowania, potem zmiana frameworka z arduino na idf - bez rezultatu. Postanowiłem zrobić nowy czujnik w starej obudowie: nowy ESP32 S3, nowy czujnik halla (deszczomierz działa na zasadzie przejścia magnesu przed czujnikiem i wyzwolenia gpio), nowe czujniki temperatury i… nadal to samo!
Próbując “na stole” nie mam pojęcia dlaczego, ale po wzbudzeniu czujnika halla i pojawieniu się sygnału na pinie, po jakimś czasie (różnym i nie zawsze!) następuje reset z przyczyn “Reset due to task watchdog” lub “Software reset due to exception/panic”.
Przepisałem od nowa kod obliczający wielkość opadów (podejrzewałem jakieś dzielenia przez 0 lub inne pętle), dodałem filtrowanie aby ograniczyć jakieś zbędne pingi, dodałem czyszczenie przy starcie, ale nadal bez zmian.
Kod aktualnie wygląda następująco:

  name: "deszczomierz"
  friendly_name: Deszczomierz
  on_boot: 
    priority: 600.0
    then:
      - lambda: |-
          time_t nowtime = id(homeassistant_time).now().timestamp;
          id(old_time)=nowtime-15;
          id(precipitation_id).publish_state(0);
esp32:
  board: esp32-s3-devkitc-1
  framework:
    type: arduino
logger:
  baud_rate: 0
button:
  - platform: restart
    name: "Stacja pogody Restart"
api:
  encryption:
    key: "kodkodkodkod"
ota:
  platform: esphome
  password: "otaotaota"
wifi:
  networks:
    - ssid: !secret wifi_ssid
      password: !secret wifi_password
    - ssid: !secret wifi_ssid_iot
      password: !secret wifi_password_iot
  manual_ip:
    static_ip: 192.168.8.34
    gateway: 192.168.8.1
    subnet: 255.255.255.0
  reboot_timeout: 5min
  ap:
    ssid: "Deszczomierz Fallback Hotspot"
    password: "xxxx"
captive_portal:
web_server:
light:
  - platform: esp32_rmt_led_strip
    id: led
    rgb_order: GRB
    pin: GPIO48
    num_leds: 1
    rmt_channel: 0
    chipset: ws2812
    name: "Deszczomierz LED"
binary_sensor:
  - platform: status
    name: "Front Status" 
  - platform: gpio
    pin: 
      number: GPIO4
      inverted: True
      mode:
        input: true
        pullup: true
    name: "hall deszczomierz"
    filters:
      - settle: 5ms
    id: hall_d
    on_state:
      then:
        - light.turn_on: 
            id: led
            transition_length: 0s
            red: 0
            green: 50%
            blue: 100%
        - lambda: |-
              if(id(hall_d).state)
              {
                ESP_LOGD("info","Jest przeskok deszczomierza!");
                time_t current_time = id(homeassistant_time).now().timestamp;
                time_t delta_time = current_time - id(old_time);
                if(delta_time<1)
                  {
                  delta_time=10;
                  }
                if(delta_time < 3600)
                  {
                    id(precipitation_id).publish_state($one_tick * (3600 / delta_time));
                    ESP_LOGD("info","Czas < 1h");
                  }
                else
                  {
                    id(precipitation_id).publish_state(0.5);
                    ESP_LOGD("info","Czas powyżej 1h");
                  }
                id(old_time) = current_time;
              }
        - delay: 200ms
        - light.turn_off: led
sensor:
  - platform: uptime
    name: "Uptime Deszczomierz"
    update_interval: 60s
  - platform: wifi_signal
    name: "WiFi Signal Deszczomierz"
    id: wifi_signal_db
    entity_category: "diagnostic"
  - platform: bmp280_i2c
    address: 0x77
    temperature:
      device_class: TEMPERATURE
      name: "Temperatura zewnetrzna deszczomierz BMP"
      id: temp_zewn_bmp 
    pressure:
      device_class: ATMOSPHERIC_PRESSURE
      name: "Cisnienie powietrza deszczomierz"
      id: cisnienie_bmp
      filters:
        offset: 20
  - platform: bh1750
    name: "Illuminance"
    #address: 0x23
    device_class: ILLUMINANCE
    update_interval: 30s
  - platform: template
    name: "opad"
    id: precipitation_id
    unit_of_measurement: "mm/h"
    device_class: PRECIPITATION_INTENSITY
    update_interval: never
    accuracy_decimals: 2
i2c:
  sda: GPIO8
  scl: GPIO9
  scan: true
  id: bus_a
substitutions:
  one_tick: '0.8418'
globals:
  - id: old_time
    type: time_t
    initial_value: "1"
    restore_value: yes
time:
  - platform: homeassistant
    id: homeassistant_time
    on_time:
      - seconds: 0
        minutes: /5
        then:
          - lambda: |-
              time_t current_time = id(homeassistant_time).now().timestamp;
              time_t delta_time = current_time - id(old_time);
              if(delta_time < 30)
                {
                delta_time=30;
                }
              if(delta_time > 3600)
                {
                  id(precipitation_id).publish_state(0);
                  ESP_LOGD("info","1 godzina bez opadów, zeruję aktualny opad.");
                }
              else
              {
                float opad_teoretyczny=$one_tick * (3600 / delta_time);
                if((opad_teoretyczny<id(precipitation_id).state)&&(opad_teoretyczny>0))
                {
                 id(precipitation_id).publish_state(opad_teoretyczny); 
                }
              }
switch:
  - platform: gpio
    name: 'Oświetlenie droga'
    restore_mode: RESTORE_DEFAULT_OFF
    id: oswietlenie
    pin:
      inverted: True
      number: GPIO44
      mode:
        output: True
debug:          
text_sensor:
  - platform: debug
    reset_reason:
      name: "Reset Reason"  
wpisz lub wklej tutaj kod

Całkowicie skończyły mi się już pomysły co może powodować te restarty i jak zmusić całość do współpracy…

Cześć
Użycie on_state ze względu na możliwe zakłócenia jest ryzykowne i pytanie czy na pewno potrzebne? Może lepiej użyć Interval ?
Wyrzuć też substitutions bo już nie raz się przekonałem że to generowało problemy i w sumie nie znalazłem odpowiedzi dlaczego (nadaje się chyba tylko do powtarzających się nazw). Albo od razu wpisz w lambdzie 0.8418 albo zastosuj Globals.

Też miałem podejrzenia związane z ewentualnymi zakłóceniami (które próbuję odsiać przez “settle”). Zwiększyłem obecnie filtrowanie do 10ms i jak na razie od godziny bez resetów. Substitutions wyrzuciłem, dzięki za podpowiedź, zobaczymy.
Wpadła mi teraz jeszcze jedna rzecz w związku z ewentualnymi zakłóceniami - wprawdzie przewód łączący czujnik halla i ESP nie jest jakiś przesadnie długi (~0,6m) i wymieniłem go już w ferworze walki (poprzedni był o połowę krótszy), ale czy zewnętrzny rezystor nie pomógłby ustabilizować sygnał? Może wewnętrzny pullup jest zbyt słaby?

Z pewnością nie zaszkodzi.

Zastanawia mnie jeszcze delta_time
Zamiast <1 ja bym dał <=0
Co do zewnętrznego rezystora to jest to zdecydowanie słuszna droga

Przez <1 chciałem dodatkowo wyeliminować wszelkie wzbudzenia z okresem poniżej sekundy.
Będę musiał spróbować dorzucić rezystor. Dzięki za wszelkie podpowiedzi.

Mała aktualizacja: przeanalizowałem dokładniej działanie i zauważyłem, że czasami czas synchronizował się nie przy starcie, ale dopiero po kilku minutach. Podejrzewam, że gdy kod w tym okresie porównywał upływ czasu, otrzymywał różnicę czasu “0” i mogło dochodzić do dzielenia przez zero po przeskoku. Tyle, że nie tłumaczy to resetów po jakimś czasie prawidłowego zliczania impulsów (co też się zdarzało).
Na razie czekam na deszcz aby przetestować rezultaty dotychczasowych korekt.
Mam jeszcze pytanie o zewnętrzny rezystor: ze względu na dostęp, chciałbym go założyć przy czujniku, a nie przy ESP - czy ma to jakieś istotne znaczenie? Czy rezystor 4,7k będzie odpowiedni? Do tej pory nie musiałem używać zewnętrznych rezystorów stąd moje wątpliwości…

Wyłącz restarty związane z brakiem połączenia API oraz później testowo te związane z brakiem połączenia WiFi (UWAGA będziesz musiał wtedy debugować po porcie szeregowym, bo brak restartu przy zerwaniu WiFi = brak komunikacji WiFi do czasu ręcznego zrestartowania sprzętu!)

to tak odnośnie tego - deszcz pogarsza propagację w 2.4GHz

oczywiście przyczyna może być inna - po prostu wilgotność w szczególnych warunkach jak np. w trakcie deszczu może być na tyle duża, że wystąpi skroplenie rosy.
W szczególności na jakichś czujnikach - to może prowadzić do zakłócenia komunikacji na danej szynie = restartów, a nawet do rdzewienia połączeń i wszelkich niechronionych elementów metalowych, bo MCU zazwyczaj jest ciepłe, chyba że używasz uśpienia to skrapla się też na płytce MCU - impregnowałeś elektronikę całościowo? (tj. pozostawiając nieimpregnowane tylko wloty czujników)

BMP280 jest szczególnie podatny na wilgoć lepiej stosować starszy BMP180

BH1750 powinieneś zaimpregnować za wyjątkiem szybki,
a czujniki temperatur ciśnienia itd. skutecznie zaklejając im sensowną taśmą samoprzylepną wlot przed impregnacją (jeśli lutowałeś podzespoły samodzielnie, a nie z gotowych płytek, to zazwyczaj fabrycznie są dostarczane z zabezpieczeniem wlotu na czas trwania procesu technologicznego montażu, to zabezpeczenie należy zdjąć dopiero po końcowej impregnacji).

Nie bardzo mi pasuje teoria korozji i zawilgocenia, bo restarty następowały również gdy zmontowałem drugi zestaw w 100% z nowych elementów (pozostała jedynie wydrukowana obudowa “wiaderka” czujnika deszczu i przekaźnik włączający oświetlenie) i gdy testowałem ten nowy zestaw w domu, na stole jakieś 3m od routera - stąd bardziej obstawiałem jakiś “babol” w moim kodzie.
Co do impregnacji to rzeczywiście o tym nie pomyślałem, aczkolwiek stary zestaw po ponad roku na zewnątrz wyglądał całkiem nieźle (poza owymi restartami “due to exception/panic”) - starałem się aby obudowa była w miarę uszczelniona z dodatkowymi uszczelkami z TPU gdzie się da (aczkolwiek BMP z oczywistych przyczyn pozostał w części wystawionej na otoczenie).

Z tym nie będę dyskutował, bo jeśli coś nie działa w warunkach idealnych to nie będzie też w ekstremalnych.

Mam za sobą kilkanaście lat praktyki z DIY (a może raczej prób używania) pracującym w ekstremalnych warunkach (czytaj: na zewnątrz pomieszczeń mieszkalnych).

I… wszystko zależy…
głównie zależy od warunków atmosferycznych, a konkretnie specyficznego mikroklimatu miejsca montażu (zupełnie inaczej jest na wysięgniku zaokiennym w blokowisku, a inaczej na środku łąki z wysoką trawą nawet jeśli montujesz na 2m słupku).
No, ale nie tylko mikroklimat - znaczenie ma też topoklimat - trwałość nieimpregnowanego sprzętu w słonecznym Wrocławiu jest w ogóle zaskakująco wysoka, za to przykładowo na Pojezierzu Drawskim fabryczna elektronika przystosowana do pracy na zewnątrz często gnije zwykle już po pierwszym sezonie.

Da się wykonać całkowicie hermetyczną obudowę, która jest odporna nawet na wybrane owady, ale moim zdaniem popartym praktyką nic nie zastępuje solidnej impregnacji (i upraszcza to konstrukcję mechaniczną).

Nie pamiętam czy gdzieś wrzucałem, to poszukam zdjęć i wrzucę tu.