ESP32-H2 Low Power Füllstandssensor

Servus zusammen,
ich bin grade daran einen low Power Thread Sensor zu basteln. Dank Forum bin ich nun so weit das Thread funktioniert und der Sensor in Deepsleep geht und auch wieder aufwacht.

Jetzt will ich die Spannung der Batterie messen. Wenn ich das über einen Spannungsteiler mache ist das ja recht Sinnfrei da selbst bei 330k schon 10µA fließen.
H

Der ESP hat doch ADC-Pins, mit denen man Spannungen bis 3,3V messen kann. Mit einen Vorwiderstand und Kalibrierung geht auch 5V. Copliot sagt, dass die Interne Schaltung bei richtiger Konfiguration nur den Deep-Sleep-Strom zieht und keinen zusätzlichen Messtrom. Das müsste man mal nachmessen…

Servus,

mein PC war abgeschmiert und ich dachte der Thread wurde noch nicht veröffentlicht… ich hab nun mal das DB gewälzt. Also ein Spannungsteiler ist schwierig da Eingangsschutzdioden im ESP verbaut sind. Somit hab ich nun einen P-Mos an die Batterie geschaltet und dann den Spannungsteiler. Nun kann ich mit einem IO Pin gepuffert über einen NPN Transistor kurz den Spannungsteiler bestromen und messen.
Nun müsste ich mal ein Messkoppler für kleine Ströme basteln. Was nutzt ihr da so? Ich dachte an den µCurrent von dem nervösen Australier. Den gibt es aber aktuell nicht zu kaufen. Den CurrentRanger von Low Power Lab ist mir zu teuer. Kennt ihr den INA296? Wäre der etwas? Oder der LTC6102 (Appnote DN423). Gute/genaue Shunts hab ich hier liegen.
Ich zeichne demnächst mal einen Schaltplan von meinem Aufbau.
jetzt muss ich mir erstmal noch gedanken um die Kapazitätsmessung machen.
Ich rechne mit etwa 10-200pF oder sowas an den Fühlern. Dazu muss ich die Tage mal einen Testaufbau machen.

Hier noch ein paar Messungen bisher: 40mA mit LED ein, Prozessor ein und Strommessung ein.
26,3mA wenn die LED ausgeschaltet wird. 26mA wenn die Spannungsmessung abgeschaltet wird. 0,7mA dann im DeepSleep - soweit ich da meinem VC840 trauen darf.
Mein Spannungsteiler hat f(x) = 0,56 x -0,05 bei einem R² von 1 :slight_smile:
Wir reden von einem SU2323DS als PFet mit einem BC847BLT1G zum Puffern und 82k zu 100k Spannungsteiler. der NPN wird mit 1k angesteuert und der SU2323 wird mit 820k auf High gezogen.

Aktuell hänge ich an den Impulsen. In der Sektion Switch → Starte Füllstandsmessung wird nur ein impuls erzeugt der 360us lang ist.
Bekomme ich ESP Home etwas “echtzeitfähiger”?
Oder ist eine Frequenz messen einfacher als eine genaue Zeit einzuhalten? dann müsste ich einen C zu f wandler bauen (NE555 oder so).

esphome:
  name: lechuzathread2
  friendly_name: LechuzaThread2
  min_version: 2025.9.0
  name_add_mac_suffix: false

esp32:
  variant: ESP32H2
  framework:
    type: esp-idf

# Enable logging
logger:


ota:
  - platform: esphome

# Light (WS2812) via RMT
light:
  - platform: esp32_rmt_led_strip
    id: ws2812
    name: "ESP32H2 WS2812"
    chipset: WS2812
    pin: GPIO8
    num_leds: 1
    rgb_order: RGB
    restore_mode: ALWAYS_ON
    effects:
      - random:
      - strobe:
      - flicker:

# Deep Sleep configuration (Debug: 30s)
deep_sleep:
  id: deep_sleep_1
  run_duration: 120s
  sleep_duration: 900s

network:
  enable_ipv6: true

openthread:
  device_type: MTD 
  tlv: !secret thread_tlv
    
switch:
  - platform: template
    name: "Prevent Deep Sleep"
    id: prevent_sleep_switch
    icon: "mdi:power"
    optimistic: true
    restore_mode: RESTORE_DEFAULT_OFF
    turn_on_action:
      - logger.log: "Deep sleep prevented"
      - deep_sleep.prevent: deep_sleep_1
    turn_off_action:
      - logger.log: "Deep sleep allowed"
      - deep_sleep.allow: deep_sleep_1
  - platform: gpio
    name: "Battery Meassure"
    id: battery_meas
    pin: GPIO22
    restore_mode: RESTORE_DEFAULT_OFF
  - platform: template
    name: "Start Batteriemessung"
    id: start_measurement
    optimistic: true
    turn_on_action:
      - logger.log: "Messung gestartet"
      - switch.turn_on: battery_meas
      - delay: 2000ms  # Warte 2 Sekunden
      - lambda: |-
          std::vector<float> readings;
          for (int i = 0; i < 5; i++) {
            readings.push_back(id(battery_adc).state);
            delay(100);
          }
          float sum = 0;
          for (const auto &value : readings) {
            sum += value;
          }
          float average = sum / readings.size();
          id(battery_adc).publish_state(average);
      - switch.turn_off: battery_meas
  - platform: template
    name: "Start Füllstandsmessung"
    id: start_fuel_measurement
    optimistic: true
    turn_on_action:
      - logger.log: "Trigger Button pressed"
      - lambda: |-
          // GPIO 12 auf OUTPUT setzen
          pinMode(12, OUTPUT);
          // Impuls erzeugen
          gpio_set_level(GPIO_NUM_12, 1);
          delayMicroseconds(20);   // 20 µs
          gpio_set_level(GPIO_NUM_12, 0);
          // Pin wieder hochohmig
          pinMode(12, INPUT);

# GPIO 12 als Schalter definieren
output:
  - platform: gpio
    pin: GPIO12
    id: gpio12_output  

globals:
  - id: global_keep_awake
    type: bool
    initial_value: 'false'
  - id: global_led_on
    type: bool
    initial_value: 'false'

sensor:
  # Internal temperature sensor (simulates external temperature sensor)
  - platform: internal_temperature
    name: "CPU Temperature"
    id: cpu_temp
    update_interval: 120s
  - platform: adc
    name: "Battery voltage"
    pin: GPIO1
    id: battery_adc
    accuracy_decimals: 2
    update_interval: 120s
    attenuation: 12db
    filters:
      - multiply: 1.7857  # The voltage divider requires us to multiply by 2
      - quantile:
          window_size: 7
          send_every: 4
          send_first_at: 3
          quantile: .9 
  - platform: adc
    name: "Fuel voltage"
    pin: GPIO2
    id: fuel_adc
    accuracy_decimals: 2
    update_interval: 5s
    attenuation: 12db
    filters:
      - multiply: 1.0  # The voltage divider requires us to multiply by 2
      - quantile:
          window_size: 7
          send_every: 4
          send_first_at: 3
          quantile: .9 



text_sensor:
  - platform: openthread_info
    ip_address:
      name: "Off-mesh routable IP Address"
    channel:
      name: "Channel"
    role:
      name: "Device Role"
    #rloc16:
    #  name: "RLOC16"
    #ext_addr:
    #  name: "Extended Address"
    #eui64:
    #  name: "EUI64 Interface ID"
    #network_name:
    #  name: "Network Name"
    #network_key:
    #  name: "Network Key"
    #pan_id:
    #  name: "PAN ID"
    #ext_pan_id:
    #  name: "Extended PAN ID"

binary_sensor:
  - platform: status
    name: "LechuzaStatus"
    on_state:
      then:
        - script.execute: on_boot_sequence


script:
  - id: on_boot_sequence
    then:
      - logger.log: "on_boot_sequence start"
      - delay: 2s
      - lambda: |-
          if (id(global_keep_awake)) {
            ESP_LOGD("boot", "Keep-awake active -> disable deep sleep");
          }
      - if:
          condition:
            lambda: 'return id(global_led_on);'
          then:
            - light.turn_on:
                id: ws2812
                red: 100%
                green: 0%
                blue: 0%
                brightness: 100%
          else:
            - light.turn_off: ws2812
      - logger.log: "Blink red to indicate wake"
      - repeat:
          count: 3
          then:
            - light.turn_on:
                id: ws2812
                red: 100%
                green: 0%
                blue: 0%
                brightness: 100%
            - delay: 300ms
            - light.turn_off: ws2812
            - delay: 300ms
      - logger.log: "on_boot_sequence end"

api:
  services:
    - service: set_keep_awake
      variables:
        keep: bool
      then:
        - lambda: |-
            if (keep) {
              id(global_keep_awake) = true;
              ESP_LOGD("api", "set_keep_awake: true -> disabled deep sleep");
            } else {
              id(global_keep_awake) = false;
              ESP_LOGD("api", "set_keep_awake: false -> enabled deep sleep 30s/30s");
            }
    - service: set_led_state
      variables:
        led_on: bool
      then:
        - lambda: |-
            id(global_led_on) = led_on;
        - if:
            condition:
              lambda: 'return led_on;'
            then:
              - light.turn_on:
                  id: ws2812
                  red: 100%
                  green: 0%
                  blue: 0%
                  brightness: 100%
            else:
              - light.turn_off: ws2812