A decibel meter themed after Fallout is a nice addition to my pedalboard for tracking room noise levels. The initial display features the vault logo and indicates the current decibels. The second screen presents system information against a Pip-Boy backdrop. The third screen offers a clock, calendar, and a cheerful thumbs-up icon. There’s also a 4th screen I use to write simple notes like uncommon tunings. I rarely use the last anymore after buying a strobestomp. It can be easily altered or removed via the code below.

I coated the enclosure with a spray on textured rubber making it difficult to identify the buttons that are on the right side. They still function normally and should add some life to them. The above image looks a little washed in this pic. Image clarity on the device is identical to what is shown below.

It’s worth downloading a mobile app to calibrate(ballpark) your specific mic. There are notable variations in these types.

Materials:

  • HiLetgo ESP32 LCD WiFi Kit ESP-32 1.14 Inch LCD Display
  • Omnidirectional Microphone Module I2S Interface INMP441 MEMS
  • (Optional) 2000mAh 103454 Lipo Rechargeable Battery Pack with Wire JST Connector

Usage:

  • Upper Button: Turns device on and resets
  • Top Button : Scrolls through multiple pages
  • Lower Button : Long press powers off the device

Place these 5 images in the root of your homeassistant / esphome dir.

esphome:
  name: decibel-monitor
  platform: esp32
  board: ttgo-t7-v13-mini32

external_components:
  - source: github://stas-sl/esphome-sound-level-meter

# Enable logging
logger:
  level: DEBUG

# Enable Home Assistant API
api:
  encryption:
    key: "your key here"

ota:


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

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Esphome-Web-90E240"
    password: "your pw here"

captive_portal:

# ---------------------------

# INMP441 I2S MEMS microphone
# VDD  3V3
# GND  GND
# SD   D26
# L/R  GND
# WS   D25
# SCK  D5

status_led:
  pin: 2

i2s:
  bck_pin: GPIO15         # SCK
  ws_pin: GPIO17         # WS
  din_pin: GPIO39        # SD
  sample_rate: 48000            # default: 48000
  bits_per_sample: 32           # default: 32

  # right shift samples.
  # for example if mic has 24 bit resolution, and i2s configured as 32 bits,
  # then audio data will be aligned left (MSB) and LSB will be padded with
  # zeros, so you might want to shift them right by 8 bits
  
  bits_shift: 8                 # default: 0

sound_level_meter:
  id: sound_level_meter1

  # update_interval specifies over which interval to aggregate audio data
  # you can specify default update_interval on top level, but you can also
  # override it further by specifying it on sensor level

  update_interval: 1s           # default: 60s

  # buffer_size is in samples (not bytes), so for float data type
  # number of bytes will be buffer_size * 4

  buffer_size: 1024             # default: 1024

  # see your mic datasheet to find sensitivity and reference SPL.
  # those are used to convert dB FS to db SPL

  mic_sensitivity: 5dB        # default: empty
  mic_sensitivity_ref: 90dB     # default: empty

  # for flexibility sensors are organized hierarchically into groups.
  # each group can have any number of filters, sensors and nested groups.
  # for examples if there is a top level group A with filter A and nested
  # group B with filter B, then for sensors inside group B filters A
  # and then B will be applied:
  # groups:
  #   # group A
  #   - filters:
  #       - filter A
  #     groups:
  #       # group B
  #       - filters:
  #           - filter B
  #         sensors:
  #           - sensor X

  groups:
    - sensors:
        - type: eq
          name: Leq_1s

# automation
# available actions:
#   - sound_level_meter.turn_on
#   - sound_level_meter.turn_off
#   - sound_level_meter.toggle


switch:
  - platform: template
    name: "ON / OFF"
    lambda: |-
      return id(sound_level_meter1).is_on();
    turn_on_action:
      then: sound_level_meter.turn_on
    turn_off_action:
      then: sound_level_meter.turn_off
    restore_mode: RESTORE_DEFAULT_ON
  
  - platform: restart
    name: "Reset"

button:
  - platform: shutdown
    name: "Shutdown"
    id: ttgo_off
  
sensor:

  - platform: internal_temperature
    name: "Temp" 
  
  - platform: homeassistant
    id: dmeter
    entity_id: sensor.Leq_1s
    internal: true
    filters:
      - filter_out: "nan"
  
  - platform: wifi_signal 
    name: "Signal dB"
    id: wifi_signal_db
    update_interval: 60s
    entity_category: "diagnostic"

  - platform: copy 
    source_id: wifi_signal_db
    name: "Signal Percent"
    filters:
      - lambda: return min(max(2 * (x + 100.0), 0.0), 100.0);
    unit_of_measurement: "%"
    entity_category: "diagnostic"
    device_class: ""
  
  - platform: adc
    pin: 33
    name: "Battery Voltage"
    attenuation: 11db
    unit_of_measurement: 'V'
    update_interval: 60s
    filters:
      - calibrate_linear:
          # Map 0.0 (from sensor) to 0.0 (true value)
          - 0.0 -> 0.0
          - 2.06 -> 1.89
      - lambda: return x * 2.0;
        
  - platform: adc
    pin: 34
    name: "Battery Charge"
    update_interval: 60s
    unit_of_measurement: '%'
    filters:
      - sliding_window_moving_average:
          window_size: 15
          send_every: 15
      - calibrate_linear:
          # Map 0.0 (from sensor) to 0.0 (true value)
          - 0.0 -> 0.0
          - 1.1 -> 100.0
        
binary_sensor:
  - platform: status
    name: "Status"
    id: system_status  
  
  - platform: gpio
    pin:
      number: GPIO0
      inverted: true
    name: dmeter bottom push
    id: tdisplay_button_input_0
    on_click:
    - min_length: 100ms
      max_length: 350ms
      then:
        - button.press: ttgo_off


  - platform: gpio
    pin:
      number: GPIO35
      inverted: true
    id: tdisplay_button_input_1
    name: dmeter top push
    on_click:
    - min_length: 50ms
      max_length: 350ms
      then:
      - display.page.show_next: my_display
      - component.update: my_display


text_sensor:
  - platform: wifi_info
    ip_address:
      name: "IP"
      id: addy
    ssid:
      name: "SSID"
      id: base
    mac_address:
      name: "Mac"
      id: mac

color:
  - id: my_red
    red: 100%
    green: 0%
    blue: 0%

  - id: my_yellow
    hex: dfb843

  - id: my_green
    hex: 4b931b

  - id: my_blue
    red: 0%
    green: 0%
    blue: 100%

  - id: my_dblue
    red: 0%
    green: 0%
    blue: 70%

  - id: my_orange
    red: 80%
    green: 20%
    blue: 0%

  - id: my_gray
    red: 50%
    green: 50%
    blue: 50%

  - id: my_wht
    red: 75%
    green: 75%
    blue: 75%

font:
  - file: "OpenSans-Bold.ttf"
    id: helvetica_48
    size: 84
  - file: "OpenSans-Bold.ttf"
    id: helvetica_T
    size: 60
  - file: "OpenSans-Bold.ttf"
    id: helvetica_24
    size: 32
  - file: "OpenSans-Bold.ttf"
    id: helvetica_S
    size: 12
  - file: "OpenSans-Bold.ttf"
    id: helvetica_M
    size: 24

  - file: "NotoMusic-Regular.ttf"
    id: music_M
    size: 24
    glyphs: ♯♪!"%()+=,-_.:°/?0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz



# put a ttf font called Helvetica.ttf in the esphome folder

time:
  - platform: homeassistant
    id: esptime

spi:
  clk_pin: GPIO18
  mosi_pin: GPIO19

#interval:
#  - interval: 30s
#    then:
#      - display.page.show: page1
#      - component.update: my_display


image:
  - file: "wifi-on.png"
    id: wifion
    type: RGB24
  
  - file: "wifi-off.png"
    id: wifioff
    type: RGB24
  
  - file: "vaultbkg.jpg"
    id: vaultbkg
    type: RGB24
  
  - file: "pboy.jpg"
    id: pboy
    type: RGB24
  
  - file: "fobk.jpg"
    id: fobk
    type: RGB24

display:
  - platform: st7789v
    model: TTGO TDisplay 135x240
    backlight_pin: GPIO4
    update_interval: 1s
    eightbitcolor: False
    cs_pin: GPIO5
    dc_pin: GPIO16
    reset_pin: GPIO23
    rotation: 90
    id: my_display
    pages:
      - id: page1
        lambda: |-
          it.image(0, 0, id(vaultbkg));
          it.printf(169, 64, id(helvetica_48), id(my_yellow), TextAlign::CENTER_RIGHT, "%.0f", id(dmeter).state);
          it.printf(236, 120, id(helvetica_M), id(my_gray), TextAlign::CENTER_RIGHT, "dB");

            if (id(system_status).state) {
          it.image(207, 0, id(wifion));
          }
            else {
          it.image(207, 0, id(wifioff));
          }

      - id: page2
        lambda: |-
          it.image(0, 0, id(pboy));
          it.printf( 50, 70, id(helvetica_S), id(my_green),"Signal: %.0fdB", id(wifi_signal_db).state);
          it.printf( 50, 40, id(helvetica_S), id(my_green), "%s", id(addy).state.c_str());
          it.printf( 50, 55, id(helvetica_S), id(my_green), "%s", id(mac).state.c_str());
          it.printf( 50, 25, id(helvetica_S), id(my_green), "%s", id(base).state.c_str());

      - id: page3
        lambda: |-
          it.image(0, 0, id(fobk));
          it.strftime(0, 0, id(helvetica_T), id(my_wht), "%I:%M:%S", id(esptime).now());
          it.strftime(10, 68, id(helvetica_M), id(my_gray), "%m-%d-%Y", id(esptime).now());
          it.strftime(10, 98, id(helvetica_M), id(my_blue), "%A", id(esptime).now());

      - id: page4
        lambda: |-
          it.printf(10, 0, id(helvetica_M), id(my_gray), "STD C:");
          it.printf(10, 30, id(music_M), id(my_gray), "C - F - A♯ - D♯ - G - C");
SideMenu