Latest Release: v0.9.5 (2025-11-13) Tested with ESPHome: Version: 2025.10.5
CI status is reflected by the badge above; the latest run is passing.
An ESP32-based vibration sensor node that measures structure-borne noise (Körperschall) from household devices like well pumps, ventilation systems, and motors. It performs real-time FFT analysis on-board and publishes spectral data to Home Assistant via ESPHome.
This project turns an ESP32 and an IMU into a smart body-sound / vibration sensor:
- Samples acceleration at 1 kHz
- Runs a 512-point FFT on-device
- Aggregates the spectrum into configurable bands
- Sends compact JSON spectra and RMS values to Home Assistant
- Monitors CPU load so you can see how hard the ESP32 is working
Use it to detect pump/fan activity, identify devices by their vibration signature, or feed data into ML pipelines running on your Raspberry Pi / Home Assistant ecosystem.
- Real-time FFT Analysis: 512-sample FFT @ 1000 Hz on ESP32
- Multi-band Spectral Energies: 16 frequency bands for device fingerprinting
- Home Assistant Integration: Seamless integration via ESPHome
- JSON Spectrum Output: Compact spectral data for ML/analysis
- CPU Load Monitoring: Track ESP32 performance in real-time
- High-Pass Filtering: Removes DC component (gravity)
- 50% Overlap: Smooth spectral updates ~4/second
-
Prepare Hardware
- ESP32 D1 mini-style board (Wemos D1 mini32 or similar)
- MPU6050 / MPU6500 / MPU9250 IMU
- Rigid mounting to the vibrating structure (pipe, wall, housing)
-
Clone / Copy Project
- Place this repository (or at least
body_sound_sensor.yamlandcustom_components/) in your ESPHome directory, e.g.config/esphome/in Home Assistant.
- Place this repository (or at least
-
Configure Secrets
- copy or edit your
secrets.yamlor devicebody_sound_sensor.yamlto define the following keys:wifi_ssid,wifi_passwordapi_encryption_key(32-byte base64) (delete if unused)ota_password
- copy or edit your
-
Build & Upload
- Via ESPHome Dashboard, build and upload
body_sound_sensor.yaml, or use CLI:esphome upload body_sound_sensor.yaml
- Via ESPHome Dashboard, build and upload
-
Integrate with Home Assistant
- The device will appear via the ESPHome integration.
- Use the exposed sensors (
RMS,CPU load,Spectrum JSON) in automations, dashboards, or external analysis.
Basic hardware requirements are:
- MCU: ESP32 D1 mini-style board (ESP32-WROOM)
- Sensor: MPU-9250 / MPU-6500 / MPU-6050 IMU
- Connection: I²C bus (3.3 V)
🟣 Expand for detailed hardware configuration & wiring
- MCU: ESP32-WROOM D1 Mini
- Sensor: MPU6050 3-axis accelerometer
- I²C Address: 0x68 (default)
- WiFi: MOMOWLAN
- MCU: ESP32 D1 mini-style board (Wemos D1 mini32 or similar)
- Sensor: MPU-9250 / MPU-6500 / MPU-6050 IMU (3-axis accelerometer)
- Connection: I²C bus
| MPU Pin | ESP32 Pin | Description |
|---|---|---|
| VCC | 3.3V | Power supply |
| GND | GND | Ground |
| SDA | GPIO 21 | I²C Data |
| SCL | GPIO 22 | I²C Clock |
I²C Address: Typically 0x68 (or 0x69 depending on AD0 pin configuration)
- Mount sensor rigidly to the structure carrying the vibration
- Use screws + bracket OR rigid mounting glue/high-strength tape
- Mount close to vibration source (e.g., near pump pipe or supporting wall)
- Avoid: Thick, soft, foam-like adhesives (they dampen vibrations)
- Name:
Body Sound Vibration RMS - Unit:
g(gravitational acceleration) - Purpose: Overall vibration level for on/off detection and thresholds
- Name:
Body Sound FFT CPU Load - Unit:
% - Purpose: Monitor ESP32 performance (should stay < 70–80%)
- Name:
Body Sound Spectrum JSON - Format: JSON object with spectral data
🟣 Expand for JSON example and field description
Example JSON Output:
{
"fs": 1000.0,
"n": 512,
"bin_hz": 1.953,
"rms": 0.012345,
"peak_hz": 49.2,
"max_analysis_hz": 300.0,
"ts_ms": 12345678,
"win_ms": 512.0,
"hop_ms": 256.0,
"seq": 42,
"epoch_ms": 1731492345123,
"bands": [12.5, 8.3, 15.7, 22.1, 18.9, 11.2, 9.4, 7.8, 6.5, 5.2, 4.1, 3.3, 2.8, 2.1, 1.5, 1.2],
"band_center": [ 9.4, 28.1, 46.9, 65.6, 84.4,103.1,121.9,140.6,159.4,178.1,196.9,215.6,234.4,253.1,271.9,290.6],
"band_low": [ 0.0, 18.8, 37.5, 56.3, 75.0, 93.8,112.5,131.3,150.0,168.8,187.5,206.3,225.0,243.8,262.5,281.3],
"band_high": [18.8, 37.5, 56.3, 75.0, 93.8,112.5,131.3,150.0,168.8,187.5,206.3,225.0,243.8,262.5,281.3,300.0]
}JSON Fields:
fs: Sample frequency (Hz)n: FFT size (samples)bin_hz: Frequency resolution (Hz/bin)rms: Time-domain RMS vibration (g)peak_hz: Dominant frequency (Hz)bands: Array of 16 band energies (arbitrary units)max_analysis_hz: Upper bound of analyzed spectrum used to build bandsband_center: Center frequency (Hz) of each bandband_low/band_high: Low/high edges (Hz) of each bandts_ms: Monotonic timestamp (ms since boot) at window centerwin_ms: Window length in millisecondshop_ms: Hop size (advance between successive window centers) in msseq: Incrementing window index (starts at 0)epoch_ms: Wall-clock Unix time (ms) when ESPHome time sync is available; else omitted
The component publishes both monotonic and wall-clock timing for ML and historical correlation:
| Field | Source | Purpose |
|---|---|---|
ts_ms |
millis() mapped to window center |
Stable sequencing independent of NTP |
seq |
Internal counter | Detect gaps / missing windows |
win_ms |
Derived from n / fs |
Reconstruct exact analysis window length |
hop_ms |
Derived from overlap (window_shift) |
Determine update cadence & effective FPS |
epoch_ms |
SNTP time + monotonic offset | Align spectra to real-world events; only present after time sync |
If epoch_ms is still 0 or missing early after boot, rely on ts_ms + seq. Once time sync completes, epoch_ms will appear automatically with no configuration changes beyond adding a time: block in YAML.
You can expose device settings as dedicated sensors so they appear on the Home Assistant device page:
sensor:
- platform: mpu_fft_json
mpu_fft_json_id: mpu_fft
# ... existing RMS / CPU sensors ...
bin_hz:
name: "Body Sound FFT Bin Size"
entity_category: diagnostic
sample_frequency:
name: "Body Sound Sample Rate"
unit_of_measurement: "Hz"
entity_category: diagnostic
fft_samples:
name: "Body Sound FFT Size"
entity_category: diagnostic
fft_bands:
name: "Body Sound Band Count"
entity_category: diagnostic
max_analysis_hz:
name: "Body Sound Max Analysis Hz"
unit_of_measurement: "Hz"
entity_category: diagnosticThese update automatically from the firmware each time a new FFT window is processed.
The following parameters can be tuned (via YAML options; changing values requires firmware re-upload and device reboot):
| Parameter | Default | Description |
|---|---|---|
sample_frequency |
1000.0 | Sampling rate (Nyquist = fs/2) |
fft_samples |
512 | FFT window size (power of 2) |
fft_bands |
16 | Number of frequency bands |
window_shift |
0 | 0 = 50% overlap; else sample shift |
dc_alpha |
0.01 | High-pass filter coefficient |
load_window_us |
1,000,000 | CPU load averaging window (µs) |
Component options (YAML):
max_analysis_hz(default300.0): Cap the analyzed spectrum when computing band energies and frequency metadata. Omit or set to0to use the full Nyquist (fs/2). Example:
mpu_fft_json:
id: mpu_fft
address: 0x68
max_analysis_hz: 300.0
sample_frequency: 1000.0
fft_samples: 512
fft_bands: 16
window_shift: 0
dc_alpha: 0.01
load_window_us: 1000000Performance Considerations:
- Lower
SAMPLE_FREQUENCY→ Less CPU load, lower Nyquist frequency - Smaller
FFT_SAMPLES(256) → Faster FFT, coarser frequency resolution - Larger
FFT_SAMPLES(1024) → Finer resolution, more CPU/RAM usage - Fewer
FFT_BANDS→ Less data per frame, cheaper processing in Home Assistant / Node-RED
🟣 Expand for detailed use cases
- Parse JSON
bands[]as feature vector - Train classifier to identify which device is running (pump, fan, etc.)
- Use different frequency signatures as "fingerprints"
- Monitor
rmsvalue for threshold-based detection - Example: "Pump active" when RMS > 0.02g and bands[2–4] elevated
- Track changes in spectral patterns over time
- Detect mechanical wear or anomalies (e.g., bearing degradation)
- Alert on significant deviations from baseline
- Log JSON spectra with labels to database
- Train models off-device (Raspberry Pi / PC)
- Deploy models for real-time classification or anomaly detection
- Hardware: docs/HARDWARE.md
- Setup: docs/SETUP.md
- CI/CD: docs/CI_CD.md
- CI/CD FAQ: docs/CI_CD_FAQ.md
🟣 Expand for repository layout
```text . ├── body_sound_sensor.yaml # ESPHome configuration ├── custom_components/ │ └── mpu_fft_json/ │ ├── sensor.py # ESPHome codegen sensors │ ├── text_sensor.py # ESPHome codegen text sensors │ └── mpu_fft_json.h # C++ custom component (FFT processing) ├── secrets.yaml.example # Template for WiFi/API credentials ├── scripts/ │ ├── setup.ps1 # Automated setup script │ └── release.ps1 # Release helper script ├── .github/ │ └── workflows/ │ ├── esphome-ci.yml # CI/CD: validate, compile, test │ └── release.yml # Release automation ├── docs/ │ ├── SETUP.md # Detailed setup guide │ ├── HARDWARE.md # Hardware assembly instructions │ ├── CI_CD.md # CI/CD documentation │ └── CI_CD_FAQ.md # CI/CD FAQ and tips ├── examples/ │ └── python/ # Python analysis scripts └── README.md # This file ```🟣 Expand for troubleshooting tips
- Check I²C wiring (SDA/SCL)
- Verify I²C address (0x68 or 0x69)
- Run I²C scan via ESPHome logs
- Check sensor power supply (3.3V)
- Reduce
SAMPLE_FREQUENCY(e.g., 500 Hz) - Decrease
FFT_SAMPLES(e.g., 256) - Reduce
FFT_BANDS(e.g., 8) - Increase
WINDOW_SHIFT(less overlap)
- Check mechanical mounting (ensure rigid)
- Increase
DC_ALPHAfor stronger high-pass filtering - Add averaging filter in Home Assistant
- Verify sensor is not picking up ESP32 self-vibration
- Check ESPHome logs for errors
- Verify
spectrum_textsensor is registered - Ensure FFT processing is completing (CPU not overloaded)
🟣 Expand for contributing and release workflow
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
To create a release, use the helper script:
# Patch release (bug fixes)
.\scripts
elease.ps1 -VersionBump patch
# Minor release (new features)
.\scripts
elease.ps1 -VersionBump minor
# Major release (breaking changes)
.\scripts
elease.ps1 -VersionBump majorOr simply ask GitHub Copilot: "Push and release a patch version"
See CI/CD Documentation for details.
This project is licensed under the MIT License – see the LICENSE file for details.
- ESPHome – Home automation framework
- ESP-DSP – Optimized DSP library for ESP32
- Specification document contributors
- Issues: GitHub Issues
- Discussions: GitHub Discussions
Note: This is a hobbyist project for structure-borne noise analysis. For critical industrial monitoring applications, please consult professional vibration analysis equipment and expertise.