ESPhome Decibel Meter - HW-484/KY-037/KY-038

In case anyone still needs info on how to make this work with an ESP32, here’s what I changed:

-I changed the pin used for the analog input from the mic from A0 to GPIO36 and connected the wire there.
-Everywhere 1024 appears in the code, I changed it to 4096. This is because the ADC in the ESP32 uses 12 bits (4096) instead of 10 (1024). There should be 5 occurrences of this. One setting an initial value, one in a loop, and 3 in a couple of “map” functions.

With these two changes, a sensor using the ESP32 behaves the same as one using the 8266 (D1 Mini). I have both processors so I was able to confirm this.

I developped my own volume meter prototype based on a pre-calibrated volume meter + a raspberry pi to run my python scripts. I reached out to you by email but didn’t get an answert (yet?) @Reubertt as I’d like to figure out ways to manufacture way cheaper volume meters. (my own pre-calibrated device costs approx 100$ per device including a rpi02W)

here is what gets monitored on my end :

a Link to the live dashboard :

https://nb-be-mont-1.noisebuster.ovh/public-dashboards/3f841065ea804f11847a85ebd5e0c0d5?orgId=1&refresh=5s

I also added MQTT to Noisebuster, which results in this (but to be honest, I did not take the time to dig the HA dashboard capabilities) :

2024-08-07_09-00-11 (1)

If anyone here wants to work to make a viable product out of this, reducing the production costs, and improving the openCV capabilites to count the vehicles, I’m all ears !

there is a discord server you can join by the way : NoiseBusters

2 Likes

I just copied both (or rather, all three) bits of code together:

(... the usual stuff ...)
captive_portal:

globals:

  - id: esphome_sensitivity
    type: float
    initial_value: '36.5'
    restore_value: yes

  - id: esphome_volume
    type: int

sensor:
  - platform: adc
    pin: GPIO32
    id: esphome_db
    device_class: signal_strength
    name: "Db SoundEsp"
    icon: "mdi:volume-vibrate"
    unit_of_measurement: "db"
    update_interval: 5s
    raw: true
    filters:
      - lambda: |-
          unsigned int sample;
          unsigned long startMillis= millis(); 
          float peakToPeak = 0; 
          unsigned int signalMax = 0;
          unsigned int signalMin = 4096;
          while (millis() - startMillis < 500) {
            sample = analogRead(A0);
            if (sample < 4096){
                if (sample > signalMax){
                    signalMax = sample;
                }
                else if (sample < signalMin){
                    signalMin = sample;
                }
              }
          }
          peakToPeak = map((signalMax - signalMin),1,4096,1.5,4096);
          id(esphome_volume) = peakToPeak;
          float state = id(esphome_sensitivity)*log10(peakToPeak)+15;  
          return(state);

  - platform: template
    name: "Volume SoundEsp"
    icon: "mdi:volume-high"
    unit_of_measurement: "%"
    update_interval: 5s
    lambda: return(map((id(esphome_db).state),15,150,0,100));

  - platform: template
    name: "RAW SoundEsp"
    icon: "mdi:volume-source"
    unit_of_measurement: "%"
    update_interval: 5s
    lambda: return(map(id(esphome_volume),1,4096,0,100));

  - platform: copy
    source_id: esphome_db
    name: "Db SoundEsp Average"
    filters:
      - sliding_window_moving_average:
          window_size: 15
          send_every: 5

number:
  - platform: template
    id: sensitivity_slider
    name: "Sensitivity SoundEsp"
    icon: "mdi:knob"
    update_interval: 5s
    initial_value: "36.5"
    step: 0.1
    min_value: 20
    max_value: 40
    mode: slider
    set_action:
      then:
        - lambda:  id(esphome_sensitivity) = x;

binary_sensor:
  - platform: analog_threshold
    name: ATS alarm triggered
    sensor_id: volume_soundesp
    threshold:
      upper: 110.0
      lower: 80.0
    device_class: smoke

This returned the following errors:

PS C:\PortbleApps\ESPHome> esphome run esp32-tuinhuis.yaml
INFO ESPHome 2024.7.2
INFO Reading configuration esp32-tuinhuis.yaml...
Failed config

binary_sensor.analog_threshold: [source esp32-tuinhuis.yaml:173]
  platform: analog_threshold
  name: ATS alarm triggered

  Couldn't find ID 'volume_soundesp'. Please check you have defined an ID with that name in your configuration.
  sensor_id: volume_soundesp
  threshold:
    upper: 110.0
    lower: 80.0
  device_class: smoke
  disabled_by_default: False

Should that be esphome_db from the first post?

…? :slight_smile:

FYI, I’m running ESPHome in HA on a raspberry pi. I’m not sure if your setup differs from mine such that it will affect whether or not this YAML code works.
Anyways, here’s the entire hunk of YAML that worked for me.
Note that I got rid of the encryption keys. Yours will be different anyways.
The way I created this was to add a new device, specify ESP32, but didn’t install it. I edited the YAML and added everything from web_server and below. The stuff above this was created when I initially added the device.

esphome:
  name: esp32-test
  friendly_name: ESP32 Test

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

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

ota:
  - platform: esphome
    password: "xxx"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Esp32-Test Fallback Hotspot"
    password: "xxx"

captive_portal:
web_server:
  port: 80

globals:

  - id: esphome_sensitivity
    type: float
    initial_value: '36.5'
    restore_value: yes

  - id: esphome_volume
    type: int

sensor:
  - platform: adc
    pin: GPIO36
    id: esphome_db
    device_class: signal_strength
    name: "Db SoundEsp"
    icon: "mdi:volume-vibrate"
    unit_of_measurement: "db"
    update_interval: 2s
    raw: true
    filters:
      - lambda: |-
          unsigned int sample;
          unsigned long startMillis= millis(); 
          float peakToPeak = 0; 
          unsigned int signalMax = 0;
          unsigned int signalMin = 4096;
          while (millis() - startMillis < 500) {
            sample = analogRead(A0);
            if (sample < 4096){
                if (sample > signalMax){
                    signalMax = sample;
                }
                else if (sample < signalMin){
                    signalMin = sample;
                }
              }
          }
          peakToPeak = map((signalMax - signalMin),1,4096,1.5,4096);
          id(esphome_volume) = peakToPeak;
          float state = id(esphome_sensitivity)*log10(peakToPeak)+15;  
          return(state);
  - platform: template
    name: "Volume SoundEsp"
    icon: "mdi:volume-high"
    unit_of_measurement: "%"
    update_interval: 2s
    lambda: return(map((id(esphome_db).state),15,150,0,100));

  - platform: template
    name: "RAW SoundEsp"
    icon: "mdi:volume-source"
    unit_of_measurement: "%"
    update_interval: 2s
    lambda: return(map(id(esphome_volume),1,4096,0,100));

number:
  - platform: template
    id: sensitivity_slider
    name: "Sensitivity SoundEsp"
    icon: "mdi:knob"
    update_interval: 5s
    initial_value: "36.5"
    step: 0.1
    min_value: 20
    max_value: 40
    mode: slider
    set_action:
      then:
        - lambda:  id(esphome_sensitivity) = x;
2 Likes

Thanks for adding the slider, it is really useful to find a good initial value.
However, the sensor doesn’t seem to work for me.
I adjusted the initial value to 5.6 (using the slider) to get a reading of 29.0 db, which matches the db of my silent room (measured with a calibrated reference decibel meter).
When I make some noise, the reading only goes up to 30 db, while my reference db-meter goes above 60-70 (talking or clapping hands).
Moreover, when I try to adjust the sensitivity via the slider, the measured db also goes up, which shouldn’t be the case.
Turning the potentiometer on the KY037 had almost no effect either.

Are you sure you are using analog output of the mic unit?
I have tinkered on this code with the help of Chatgpt and i learned a lot, especially the problem on the code/esp8266 wemos d1.

This code takes 500ms of sample with 2 seconds intervals which means the sensor doesn’t read 4/3 of the time. if you manage to get your clap detected feel lucky. I understood it made this was because a0 of 8266 also used to read wifi signal strength for device to work at all. So if try to get full sampling (1s read with 1s intervals) the Device doesn’t connect to wifi at all (code works flawless, you can read from serial usb) The best i managed was 1s analog read with 2s intervals.

I advise all who want to make this project to get a esp32.

1 Like

I want to get the reading off the digital pin as well. I connected the digital pin on the ky-037 to d1 minis D4, GPIO2.

I figured out that to use “D4” I should change the board to d1_mini

in the yaml, i added below code.

Even if the second led if off (as far as the circuitry is concerned, it is off),

I get the reading in Home assistant but it is always “detected”
I see “state=ON” on the d1’s web server.

Any ideas?

binary_sensor:

platform: gpio
pin: D4
name: “digitalPin”
device_class: sound # optional, to label it as sound sensor

Any suggestions?
Best,

After struggling with it for a couple of days, i think i figured this (erratic values that done make sense) out.
there are two leds on the module. one should be on, to indicate power…
the other should be off (when environment is silent).

In my case the second led was always on and i thought “I am not using digital output anyway, so who cares?” This was the mistake. If the second led is on even when its totally quiet, then we turn counter-clock wise until it turns off. Now when you make sound, the second led should come on. And then, the readings of the analog pin becomes much more logical and reasonable.

I couldnt get anything to make sense, until i observed that the calibration (potentiometer setting) matters.

1 Like

deleted, just found it

Hi, this worked for me thanks (code above), tweaked for pin A0 on the d1_mini
I also wound out the screw until the led went off (in quiet room).
Performing much better now

1 Like