Open viotemp1 opened 6 months ago
Hi!
Unfortunately, PDM mics currently are not supported, there was an attempt to support them, you can read previous discussion and you can also check out branch https://github.com/stas-sl/esphome-sound-level-meter/tree/pdm_support, but seems like there are still some issues, I just can’t try it myself as I don’t have those mics.
Hello,
I tried that branch and I get sound_level: 118.52 all the time. MAybe you can find some hints in M5Stack PDM I'll check more into the source code. Thanks!
I made a fork and changed a bit fork according to the M5Stack PDM example. It's working now, not sure about the values ranges and calibration, but I do not need that.
Thanks for help!
@viotemp1 can you share your config on how you got it working? I'm trying to get an Atom Echo to work as a sound level meter too, and it also uses a pdm mic.
@viotemp1 can you share your config on how you got it working? I'm trying to get an Atom Echo to work as a sound level meter too, and it also uses a pdm mic.
This is my config for M5Stack Core2 AWS
# GPIOs
# 25 - side LEDs
# 26,36 - Groove Port B Black (DAC/ADC)
# 32, 33 - Groove Port A Red
# 21, 22 - I2CA - internal
# 18, 23, 38 - SPI
# 5, 15, 4 - TFT
## 13 14 - Groove Port C Blue (RX/TX)
# 27 - Digital RGB LED Weatherproof Strip SK6812
# (34-39) does not support output pin mode
# I2C
# Bus Internal
# 0x34 - AXP192 Power management
# 0x35 - ATECC608 HW Encryption
# 0x38 - FT6336U Touch Screen
# 0x51 - BM8563 RTC
# 0x68 - MPU6886 Accelerometer/Gyroscope
substitutions:
esp_name: "decibel-meter"
esp_name1: "decibel_meter"
ip: ...
board: m5stack-core2
mic_clk: GPIO0 # internal
mic_data: GPIO34 # internal
i2s_bclk: GPIO12 # internal for speaker
groove_port_c_rx_pin: GPIO13 # ext MIC CLK
groove_port_c_tx_pin: GPIO14 # ext MIC DATA
aws_core2_side_leds_pin: GPIO25
groove_port_a_sda_pin: GPIO32 # (IR Tx)
groove_port_a_scl_pin: GPIO33 # (IR Rx)
groove_port_b_dac_pin: GPIO26
groove_port_b_adc_pin: GPIO36
internal_i2c_sda_pin: GPIO21
internal_i2c_scl_pin: GPIO22
internal_spi_clk_pin: GPIO18
internal_spi_mosi_pin: GPIO23
internal_spi_miso_pin: GPIO38
display_cs_pin: GPIO5
display_dc_pin: GPIO15
display_reset_pin: GPIO4
count_volume_change: "2"
globals:
- id: display_switch_var
type: bool
# initial_value: 'true'
restore_value: yes
- id: touch_x
type: int
initial_value: '0'
- id: touch_y
type: int
initial_value: '0'
- id: touch_state
type: int
initial_value: '0'
esphome:
name: $esp_name
friendly_name: $esp_name
on_boot:
- priority: -100.0
then:
# - light.turn_on: ${esp_name1}_led
# - delay: 5s
# - light.turn_off: ${esp_name1}_led
# - switch.turn_on: ${esp_name1}_display_switch
# - lambda: |-
# ESP_LOGI("boot", "display_switch_var: %s", id(display_switch_var) ? "ON" : "OFF");
# if (id(display_switch_var)) {
# id(${esp_name1}_display_switch).turn_on();
# }
- logger.log:
level: INFO
format: "boot finished"
esp32:
board: $board
framework:
type: arduino
external_components:
- source: github://viotemp1/esphome-sound-level-meter
- source:
type: local
path: my_components
# Enable logging
logger:
level: !secret log_level # DEBUG
# level: DEBUG
logs:
api.connection: ERROR
component: ERROR
graph: ERROR
main: INFO
remote.pronto: INFO
uptime.sensor: INFO
# Enable Home Assistant API
api:
encryption:
key: ...
ota:
password: ...
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
use_address: $ip
domain: .local
reboot_timeout: !secret reboot_timeout
fast_connect: on
manual_ip:
static_ip: $ip
gateway: 10.0.0.1
subnet: 255.255.255.0
color:
- id: color_blue
red: 0%
green: 0%
blue: 100%
- id: color_red
red: 100%
green: 0%
blue: 0%
- id: color_green
red: 0%
green: 100%
blue: 0%
- id: color_white
red: 100%
green: 100%
blue: 100%
- id: color_black
red: 0%
green: 0%
blue: 0%
- id: color_dark_green
red: 0%
green: 50%
blue: 0%
- id: color_dark_red
red: 50%
green: 0%
blue: 0%
- id: color_dark_blue
red: 0%
green: 0%
blue: 50%
font:
- file: "gfonts://Roboto@medium"
id: font_roboto
size: 22
- file: "gfonts://Roboto@medium"
id: font_roboto_med
size: 56
- file: "gfonts://Roboto@medium"
id: font_roboto_big
size: 80
- file: "gfonts://Roboto@medium"
id: font_roboto_10
size: 10
- file: "gfonts://Roboto@medium"
id: font_roboto_20
size: 20
light:
- platform: neopixelbus
type: GRB
variant: SK6812
pin: $aws_core2_side_leds_pin
num_leds: 10
name: "${esp_name1}_LED_Light"
id: ${esp_name1}_led
restore_mode: ALWAYS_OFF
# remote_receiver:
# pin:
# number: $groove_port_a_scl_pin # GPIO33 # (IR Rx)
# inverted: true
# dump: raw # all raw
remote_transmitter:
pin: $groove_port_a_sda_pin # GPIO32 # (IR Tx)
carrier_duty_percent: 50%
button:
- platform: restart
name: ${esp_name1}_Restart
id: ${esp_name1}_restart_switch
- platform: template
name: "${esp_name1}_Sound Level Meter Toggle"
on_press:
- sound_level_meter.toggle: my_sound_level_meter
....
time:
- platform: homeassistant
id: esptime
spi:
clk_pin: $internal_spi_clk_pin
mosi_pin: $internal_spi_mosi_pin
miso_pin: $internal_spi_miso_pin
i2c:
- id: bus_internal
sda: $internal_i2c_sda_pin
scl: $internal_i2c_scl_pin
frequency: 800kHz
scan: True
switch:
- platform: template
name: "${esp_name1} Display Switch"
id: ${esp_name1}_display_switch
lambda: |-
if (id(display_switch_var)) {
return true;
} else {
return false;
}
turn_on_action:
- lambda: |-
id(display_switch_var) = true;
id(axp192_id).set_brightness(0.75);
turn_off_action:
- lambda: |-
id(display_switch_var) = false;
id(axp192_id).set_brightness(0.0);
sensor:
- platform: wifi_signal
name: "${esp_name1}_WiFi_Signal"
id: wifi_signal_sensor
update_interval: 60s
- platform: uptime
name: "${esp_name1}_Uptime"
id: ${esp_name1}_uptime_sensor
accuracy_decimals: 0
internal: true
update_interval: 1s
- platform: mpu6886
i2c_id: bus_internal
address: 0x68
temperature:
name: "${esp_name1}_Temperature"
- platform: axp192
id: axp192_id
model: M5CORE2
address: 0x34
i2c_id: bus_internal
update_interval: 30s
brightness: 75%
battery_level:
name: "${esp_name1} Battery Level"
id: "${esp_name1}_battery_level"
- platform: template
name: "${esp_name1} Vin Voltage"
id: "${esp_name1}_get_vin_voltage"
lambda: return id(axp192_id).GetVinVoltage();
update_interval: 60s
force_update: True
unit_of_measurement: "V"
- platform: template
name: "${esp_name1} Battery Voltage"
id: "${esp_name1}_get_bat_voltage"
lambda: return id(axp192_id).GetBatVoltage();
update_interval: 60s
force_update: True
unit_of_measurement: "V"
- platform: template
name: "${esp_name1} APS Voltage"
id: "${esp_name1}_get_aps_voltage"
lambda: return id(axp192_id).GetAPSVoltage();
update_interval: 60s
force_update: True
unit_of_measurement: "V"
- platform: homeassistant
name: "${esp_name1} Living Threshold"
entity_id: input_number.decibel_meter_living_threshold
id: decibel_meter_living_threshold
internal: true
- platform: template
name: "Sound Level Peak 1min"
id: ${esp_name1}_sound_level_peak_1min
# lambda: return id(${esp_name1}_sound_level_peak).state;
update_interval: 1s
unit_of_measurement: dBZ # dBA
filters:
- max:
window_size: 60
send_every: 1
send_first_at: 1
text_sensor:
- platform: wifi_info
ip_address:
name: ${esp_name1}_IP_Address
ssid:
name: ${esp_name1}_ESP_Connected_SSID
id: wifi_info_ssid_sensor
bssid:
name: ${esp_name1}_ESP_Connected_BSSID
mac_address:
name: ${esp_name1}_ESP_Mac_Wifi_Address
- platform: template
name: "display_text"
id: display_text
internal: True
# lambda: |-
# return {""};
update_interval: 60s
# on_value:
# then:
# - lambda: |-
# ESP_LOGI("display_text", "value changed %s", x.c_str());
binary_sensor:
- platform: status
name: ${esp_name}_Status
id: esp32_status
- platform: homeassistant
name: "HA Decibel Meter Living Enabled"
entity_id: input_boolean.decibel_meter_living
id: ha_decibel_meter_living_enabled
internal: True
on_press:
then:
- sound_level_meter.turn_on
on_release:
then:
- sound_level_meter.turn_off
- platform: template
name: "${esp_name}_high_sound_level"
id: ${esp_name1}_high_sound_level
lambda: |-
if (id(${esp_name1}_sound_level_peak).state > id(decibel_meter_living_threshold).state) {
if (!id(ir_volume_down_up_script).is_running()) {
id(ir_volume_down_up_script).execute();
}
return true;
} else {
return false;
}
- platform: template
name: "${esp_name}_high_sound_level_running"
lambda: |-
if (id(ir_volume_down_up_script).is_running()) {
return true;
} else {
return false;
}
i2s:
ws_pin: $groove_port_c_rx_pin #: GPIO13 # ext MIC CLK
din_pin: $groove_port_c_tx_pin #: GPIO14 # ext MIC DATA
sample_rate: 16000 # 44100 48000
bits_per_sample: 16
dma_buf_count: 2
dma_buf_len: 128
use_apll: true # true false
bits_shift: 0 # 8 0 4
# pdm: true
sound_level_meter:
id: my_sound_level_meter
# 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
# ignore audio data at startup for this long
warmup_interval: 3s # default: 500ms
# 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: 0dB # default: empty
mic_sensitivity_ref: 0dB # default: empty
offset: 29dB
multiplier: 10dB
groups:
- sensors:
- type: eq
name: Leq_1s
id: "sound_level"
internal: true
update_interval: 0.2s
- type: peak
name: "Sound Level Peak"
id: ${esp_name1}_sound_level_peak
unit_of_measurement: dBZ # dBZ
# internal: true
on_value:
then:
lambda: |-
id(decibel_meter_living_threshold).publish_state(id(decibel_meter_living_threshold).state);
id(${esp_name1}_sound_level_peak_1min).publish_state(x);
# - logger.log:
# level: INFO
# format: "sound_level_peak: %.2f"
# args: ['x']
graph:
# Show bare-minimum auto-ranged graph
- id: sound_level_graph
duration: 1min
width: 300
height: 180
traces:
- sensor: decibel_meter_living_threshold
line_type: SOLID
continuous: true
line_thickness: 2
color: color_red
- sensor: ${esp_name1}_sound_level_peak
line_type: SOLID
continuous: true
line_thickness: 2
color: color_blue
script:
- id: ir_volume_down_up_script
mode: single
then:
# - logger.log:
# format: "High sound level detected. Volume will be adjusted"
# level: INFO
...
- id: turn_on_display
mode: single
then:
- switch.turn_on: ${esp_name1}_display_switch
- delay: 60s
- switch.turn_off: ${esp_name1}_display_switch
display:
- platform: ili9xxx # ili9341
model: M5STACK # TFT 2.4R (ILI9342) / M5STACK
cs_pin: $display_cs_pin
dc_pin: $display_dc_pin
reset_pin: $display_reset_pin
# rotation: 90°
update_interval: 1s
id: core2_display
lambda: |-
int d_width = it.get_width();
int d_height = it.get_height();
int d_h_width = int(d_width/2);
int d_h_height = int(d_height/2);
// bool battery_level_state = id(${esp_name1}_battery_level).state > 80 ? true : false;
// ESP_LOGI("display dimensions", "width: %d / d_height: %d", d_width, d_height); // 320x240
it.fill(COLOR_OFF);
if (id(${esp_name1}_display_switch).state)
{
//auto touch = id(my_touchscreen)->get_touch();
//if (touch) { // or touch.has_value()
// it.filled_circle(touch.value().x, touch.value().y, 10, color_red);
//}
// No display_text
if (id(display_text).state == "") {
it.strftime(10, 0, id(font_roboto), TextAlign::TOP_LEFT, "%H:%M:%S", id(esptime).now());
it.printf(d_width-10, 0, id(font_roboto), TextAlign::TOP_RIGHT, "%.02f / %.02f", id(${esp_name1}_sound_level_peak).state, id(${esp_name1}_sound_level_peak_1min).state);
it.graph(10, 30, id(sound_level_graph));
if (id(esp32_status).state) {
it.filled_rectangle(0, d_height -25, d_h_width, 25, color_dark_green);
}
else {
it.filled_rectangle(0, d_height -25, d_h_width, 25, color_dark_red);
}
if (id(${esp_name1}_battery_level).state > 80 ) {
it.filled_rectangle(d_h_width, d_height -25, d_width, 25, color_dark_green);
}
else if (id(${esp_name1}_battery_level).state > 50 ) {
it.filled_rectangle(d_h_width, d_height -25, d_width, 25, color_dark_blue);
}
else {
it.filled_rectangle(d_h_width, d_height -25, d_width, 25, color_dark_red);
}
it.printf(d_h_width, d_height, id(font_roboto), TextAlign::BOTTOM_CENTER, "%s / %s / %.0f", id(esp32_status).state ? "ON" : "OFF", id(wifi_info_ssid_sensor).state.c_str(), id(wifi_signal_sensor).state);
it.printf(d_width, d_height, id(font_roboto), TextAlign::BOTTOM_RIGHT, "%.0f", id(${esp_name1}_battery_level).state);
}
// display_text present
else if (id(display_text).state != ""){
it.printf(d_h_width, d_h_height, id(font_roboto_med), TextAlign::CENTER_HORIZONTAL , "%s", id(display_text).state.c_str());
}
}
Hello,
I'm trying to use this component with AtomS3U - SPM1423, but this has only MIC_CLK & MIC_DATA pins. Any ideea what to do with the ws_pin? It looks like it's mandatory.
I tried also this external mic (based on the same chip) - pdm - the same, the WS pin is missing.
Regards, V