Can't get sound level sensor to work to save my life (ICS 43434 with Sparkfun ESP32 C6)

I run a woodshop and I’m trying to create a sensor that both monitors particulate matter in the air, as well as noise levels in decibels. I’ve got the particulate monitor working, but I can’t get the microphone to work. The sensors show up listed in Home Assistant for “Average Loudness” and “Peak Loudness”, but both report “Unknown.” This is my first ESPHome project and I’m sure I’m missing something. Here’s the kit I’m using:

Here’s my yaml in Home Assistant:

esphome:
  name: air-sensor
  friendly_name: Air Sensor

esp32:
  board: esp32-c6-devkitc-1
  framework:
    type: esp-idf

# Enable logging
logger:
  level: DEBUG

# Enable Home Assistant API
api:
  encryption:
    key: "yadda yadda yadda"

ota:
  - platform: esphome
    password: "yadda yadda yadda"

# i2c for air sensor
i2c:
  sda: 6
  scl: 7
  scan: true

#i2s for microphone
i2s_audio:
  i2s_lrclk_pin: GPIO1
  i2s_bclk_pin: GPIO2

sensor:
  - platform: pmsa003i
    pm_1_0:
      name: "PM1.0"
    pm_2_5:
      name: "PM2.5"
    pm_10_0:
     name: "PM10.0"
    pmc_0_3:
      name: "PMC >0.3µm"
    pmc_0_5:
      name: "PMC >0.5µm"
    pmc_1_0:
      name: "PMC >1µm"
    pmc_2_5:
      name: "PMC >2.5µm"
    pmc_5_0:
      name: "PMC >5µm"
    pmc_10_0:
      name: "PMC >10µm"
    update_interval: 5s
    
  - platform: sound_level
    id: sound_level_meter
    microphone: mic_breakout
    measurement_duration: 1000ms
    passive: True
    peak:
      name: "Peak Loudness"
    rms:
      name: "Average Loudness"

microphone:
  - platform: i2s_audio
    id: mic_breakout
    i2s_din_pin: GPIO3
    adc_type: external
    pdm: false
    sample_rate: 48000
    bits_per_sample: 32bit
    channel: left
    use_apll: true

# Button to soft restart, which fixes a problem where the air sensor doesn't initialize properly
button:
  - platform: restart
    name: "Air Sensor Restart"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password
  manual_ip:
    static_ip: 192.168.1.105
    gateway: 192.168.1.1
    subnet: 255.255.255.0

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Air-Sensor Fallback Hotspot"
    password: "yada yada yada"

captive_portal:
    

Here’s the log file I get:

INFO ESPHome 2025.10.1
INFO Reading configuration /config/esphome/air-sensor.yaml...
INFO Starting log output from 192.168.1.105 using esphome API
INFO Successfully resolved air-sensor @ 192.168.1.105 in 0.000s
INFO Successfully connected to air-sensor @ 192.168.1.105 in 0.089s
INFO Successful handshake with air-sensor @ 192.168.1.105 in 0.080s
[18:04:38.775][I][app:185]: ESPHome version 2025.10.1 compiled on Oct 17 2025, 17:42:37
[18:04:38.775][C][wifi:679]: WiFi:
[18:04:38.776][C][wifi:458]:   Local MAC: yadda yadda yadda
[18:04:38.776][C][wifi:465]:   IP Address: 192.168.1.105
[18:04:38.781][C][wifi:469]:   SSID: yadda yadda yadda
[18:04:38.781][C][wifi:469]:   BSSID: yadda yadda yadda
[18:04:38.781][C][wifi:469]:   Hostname: 'air-sensor'
[18:04:38.781][C][wifi:469]:   Signal strength: -48 dB ▂▄▆█
[18:04:38.781][C][wifi:469]:   Channel: 11
[18:04:38.781][C][wifi:469]:   Subnet: 255.255.255.0
[18:04:38.781][C][wifi:469]:   Gateway: 192.168.1.1
[18:04:38.781][C][wifi:469]:   DNS1: 0.0.0.0
[18:04:38.781][C][wifi:469]:   DNS2: 0.0.0.0
[18:04:38.781][C][logger:261]: Logger:
[18:04:38.781][C][logger:261]:   Max Level: DEBUG
[18:04:38.781][C][logger:261]:   Initial Level: DEBUG
[18:04:38.787][C][logger:267]:   Log Baud Rate: 115200
[18:04:38.787][C][logger:267]:   Hardware UART: USB_SERIAL_JTAG
[18:04:38.788][C][logger:274]:   Task Log Buffer Size: 768
[18:04:38.788][C][logger:280]:   Level for 'i2s': DEBUG
[18:04:38.790][C][logger:280]:   Level for 'microphone': DEBUG
[18:04:38.790][C][logger:280]:   Level for 'sound_level_meter': DEBUG
[18:04:38.804][C][i2c.idf:081]: I2C Bus:
[18:04:38.804][C][i2c.idf:082]:   SDA Pin: GPIO6
[18:04:38.804][C][i2c.idf:082]:   SCL Pin: GPIO7
[18:04:38.804][C][i2c.idf:082]:   Frequency: 50000 Hz
[18:04:38.806][C][i2c.idf:092]:   Recovery: bus successfully recovered
[18:04:38.806][C][i2c.idf:102]: Results from bus scan:
[18:04:38.806][C][i2c.idf:108]: Found device at address 0x12
[18:04:38.806][C][i2c.idf:108]: Found device at address 0x36
[18:04:38.824][C][i2s_audio.microphone:079]: Microphone:
[18:04:38.824][C][i2s_audio.microphone:079]:   Pin: 3
[18:04:38.824][C][i2s_audio.microphone:079]:   PDM: NO
[18:04:38.824][C][i2s_audio.microphone:079]:   DC offset correction: NO
[18:04:38.838][C][pmsa003i:041]: PMSA003I:
[18:04:38.842][C][pmsa003i:042]:   Address: 0x12
[18:04:38.844][C][restart.button:015]: Restart Button 'Air Sensor Restart'
[18:04:38.844][C][restart.button:018]:   Icon: 'mdi:restart'
[18:04:38.860][C][captive_portal:116]: Captive Portal:
[18:04:38.879][C][esphome.ota:093]: Over-The-Air updates:
[18:04:38.879][C][esphome.ota:093]:   Address: 192.168.1.105:3232
[18:04:38.879][C][esphome.ota:093]:   Version: 2
[18:04:38.879][C][esphome.ota:100]:   Password configured
[18:04:38.879][C][safe_mode:018]: Safe Mode:
[18:04:38.879][C][safe_mode:018]:   Successful after: 60s
[18:04:38.879][C][safe_mode:018]:   Invoke after: 10 attempts
[18:04:38.879][C][safe_mode:018]:   Duration: 300s
[18:04:38.893][C][web_server.ota:241]: Web Server OTA
[18:04:38.895][C][api:222]: Server:
[18:04:38.895][C][api:222]:   Address: 192.168.1.105:6053
[18:04:38.895][C][api:222]:   Listen backlog: 4
[18:04:38.895][C][api:222]:   Max connections: 8
[18:04:38.898][C][api:229]:   Noise encryption: YES
[18:04:38.911][C][mdns:179]: mDNS:
[18:04:38.911][C][mdns:179]:   Hostname: air-sensor
[18:04:38.915][C][sound_level:022]: Sound Level Component:
[18:04:38.915][C][sound_level:022]:   Measurement Duration: 100 ms
[18:04:38.916][C][sound_level:015]:   Peak: 'Peak Loudness'
[18:04:38.916][C][sound_level:015]:     State Class: 'measurement'
[18:04:38.916][C][sound_level:015]:     Unit of Measurement: 'dB'
[18:04:38.916][C][sound_level:015]:     Accuracy Decimals: 1
[18:04:38.920][C][sound_level:025]:     Device Class: 'sound_pressure'
[18:04:38.920][C][sound_level:015]:   RMS: 'Average Loudness'
[18:04:38.920][C][sound_level:015]:     State Class: 'measurement'
[18:04:38.920][C][sound_level:015]:     Unit of Measurement: 'dB'
[18:04:38.920][C][sound_level:015]:     Accuracy Decimals: 1
[18:04:38.922][C][sound_level:025]:     Device Class: 'sound_pressure'
[18:04:40.706][D][sensor:131]: 'PM1.0': Sending state 0.00000 µg/m³ with 2 decimals of accuracy
[18:04:40.707][D][sensor:131]: 'PM2.5': Sending state 1.00000 µg/m³ with 2 decimals of accuracy
[18:04:40.707][D][sensor:131]: 'PM10.0': Sending state 1.00000 µg/m³ with 2 decimals of accuracy
[18:04:40.712][D][sensor:131]: 'PMC >0.3µm': Sending state 195.00000 #/0.1L with 0 decimals of accuracy
[18:04:40.713][D][sensor:131]: 'PMC >0.5µm': Sending state 162.00000 #/0.1L with 0 decimals of accuracy
[18:04:40.713][D][sensor:131]: 'PMC >1µm': Sending state 0.00000 #/0.1L with 0 decimals of accuracy
[18:04:40.713][D][sensor:131]: 'PMC >2.5µm': Sending state 0.00000 #/0.1L with 0 decimals of accuracy
[18:04:40.727][D][sensor:131]: 'PMC >5µm': Sending state 0.00000 #/0.1L with 0 decimals of accuracy
[18:04:40.727][D][sensor:131]: 'PMC >10µm': Sending state 0.00000 #/0.1L with 0 decimals of accuracy

I can’t get the log file to produce anything regarding the microphone on i2s. I’ve got everything connected using a breadboard and I’ve tested continuity between posts and that seems good to my novice eyes.

Again, this is my first ESPHome and ESP32 project, so I’m probably missing something simple, but I just want to have a graph on Home Assistant that shows decibel levels over time.

Thanks in advance for any help you all can provide.

I have no experience using i2s mics, but a quick read of the doc seems to imply that you need to turn the mic on first.

In passive mode, it looks like you do that with a microphone.capture action, I assume you can put this in an on_boot: block at a high enough priority that everything has started.

Relevant doc links - capture action:

The bit about when the sensor is active if passive is true:

And a link to on_boot: if you haven’t used it before:

Put together it would look something like:

esphome:
  name: air-sensor
  friendly_name: Air Sensor
  on_boot:
    - priority: -100
      then:
        - microphone.capture   # defaults to the single mic if only one defined, otherwise id is required.

YES! That was it! I tried looking through the docs but somehow I missed that. Thanks a ton for the detailed assistance. I just added that on_boot statement to the beginning and everything lit right up. Thanks again.