Because vinyl, tapes, and CDs don't have an API.
shazam2mqtt is a Dockerised bridge that listens to your room, recognises whatever music is playing via Shazam, and publishes the result to MQTT — including Home Assistant auto-discovery.
Streaming services expose what you're playing natively. Physical media doesn't.
If you consume music on:
- Vinyl
- Cassette tapes
- CDs
- Radio
- ...or anything else that doesn't have a Spotify API endpoint
...then Home Assistant has no idea what's spinning. shazam2mqtt fixes that by placing a microphone near your speakers, fingerprinting the audio with Shazam, and pushing the track metadata straight into HA.
Your dashboard can now show:
- What's currently playing
- The artist and track name
- Album artwork (Picture Entity card)
- A link to the song on Apple Music, Spotify, Deezer
- Lyrics, release metadata, and related videos
- Whether the room is silent or loud
- Noise-gated listening — continuously monitors ambient audio using an RMS threshold (
NOISE_GATE_DB). - Smart capture — once audio is sustained for ~3 s, it records a 10-second clip.
- Shazam identification — fingerprints the clip via
xazam+shazamio_core. - Extra track info — after a match, queries Shazam for lyrics, release metadata (album, label, date), and related YouTube videos.
- MQTT publishing — pushes the track title, artist, and metadata to MQTT topics.
- Home Assistant discovery — registers 10 entities under one "Shazam" device via the MQTT integration.
- Rich JSON attributes — the Now Playing sensor carries lyrics, genres, Spotify/Deezer links, album metadata, and related YouTube videos as attributes.
- Clone / copy this directory.
- Create a
.envfile (or export variables):
DEVICE_NAME=living_room
MQTT_HOST=192.168.1.200
MQTT_USER=mqtt
MQTT_PASS=secret
NOISE_GATE_DB=-40
LISTEN_DURATION=10
COOLDOWN_SECONDS=10
SAME_SONG_COOLDOWN_SECONDS=30
SAMPLE_RATE=44100- Run:
docker compose pull
docker compose up -dHome Assistant will auto-discover the device under Settings → Devices & Services → MQTT.
All settings are optional — sensible defaults are baked in.
| Variable | Default | Description |
|---|---|---|
DEVICE_NAME |
shazam |
Prefix for the HA entity ID (living_room_shazam_now_playing) |
MQTT_HOST |
localhost |
MQTT broker host |
MQTT_PORT |
1883 |
MQTT broker port |
MQTT_USER |
(none) | MQTT username |
MQTT_PASS |
(none) | MQTT password |
NOISE_GATE_DB |
-40 |
dBFS threshold. Audio quieter than this is considered silence. |
LISTEN_DURATION |
10 |
Seconds of audio to capture for Shazam recognition |
COOLDOWN_SECONDS |
10 |
Minimum seconds between any two recognition attempts |
SAME_SONG_COOLDOWN_SECONDS |
30 |
Cooldown used instead of the normal one when the same song is detected twice in a row. Set higher to avoid re-identifying the same long track. |
HA_DISCOVERY_PREFIX |
homeassistant |
Home Assistant MQTT discovery prefix |
HA_ENABLED |
true |
Set to false to disable HA discovery messages |
SAMPLE_RATE |
44100 |
Audio sample rate in Hz. Try 48000 if you get PortAudio invalid-sample-rate errors. |
SOUND_DEVICE |
(none) | PortAudio device index. Set if the default input device is wrong. Check container logs for the device list. |
ALSA_CARD |
(none) | ALSA card name (e.g. C615). Forces the default capture device on PipeWire/ALSA hosts without fiddling with PortAudio indices. |
NOISE_LEVEL_INTERVAL |
5.0 |
Minimum seconds between Noise Level sensor MQTT updates. |
NOISE_LEVEL_DELTA |
3.0 |
dB change required to publish a Noise Level update immediately, bypassing the interval. |
REQUIRED_NO_MATCHES |
2 |
Consecutive "no match" results from Shazam before the state flips from playing to unknown/no-match. Prevents brief drop-outs from resetting the display mid-track. |
QUIET_HYSTERESIS |
5 |
Seconds of quiet audio before the state flips to silent. |
If music is playing but the gate never triggers:
- Check the Noise Level sensor in HA. If it stays below your threshold, lower
NOISE_GATE_DB(e.g.-60). - If the value is stuck at
-75even during playback, your mic gain is too low or the wrong device is selected.
| Scenario | Suggested values |
|---|---|
| Fast switching (radio, shuffle) | COOLDOWN_SECONDS=5 SAME_SONG_COOLDOWN_SECONDS=10 |
| Normal listening | COOLDOWN_SECONDS=10 SAME_SONG_COOLDOWN_SECONDS=30 (defaults) |
| Long tracks / ambient | COOLDOWN_SECONDS=15 SAME_SONG_COOLDOWN_SECONDS=120 |
Mic ──► Noise Gate (RMS) ──► 10 s Capture ──► xazam.identify()
│
▼
get_track_info() ──► lyrics, metadata, videos
│
▼
MQTT ──► Home Assistant
- Idle loop reads 1-second audio chunks and checks RMS energy.
- Trigger requires 3 consecutive "loud" chunks (~3 s hysteresis) to avoid reacting to pops.
- State machine has three states and prevents brief drop-outs from resetting the display:
playing— Shazam matched a track.unknown/no-match— Room is loud but Shazam failed afterREQUIRED_NO_MATCHESconsecutive attempts.silence— Room has been quiet forQUIET_HYSTERESISseconds.
- Command topic
shazam2mqtt/<device_name>/commandacceptslisten_nowfor manual triggers.
| Entity | Type | Payload / Example |
|---|---|---|
| Now Playing | sensor + attrs | Nothing Else Matters — Metallica + JSON attrs |
| Status | sensor | playing / unknown / silence |
| Matched | binary_sensor | ON / OFF |
| Track | sensor | Nothing Else Matters |
| Artist | sensor | Metallica |
| Confidence | sensor | 4 (match count) |
| Apple Music URL | sensor | https://music.apple.com/... |
| Artwork URL | sensor | https://is1-ssl.mzstatic.com/... |
| Noise Level | sensor | -40.0 dBFS |
| Command | command in | listen_now |
The Now Playing sensor carries rich JSON attributes:
{
"artist": "Metallica",
"title": "Nothing Else Matters",
"confidence": 4,
"apple_music_url": "...",
"artwork_url": "...",
"spotify_url": "...",
"deezer_url": "...",
"shazam_url": "...",
"lyrics": "...",
"genres": ["Metal"],
"metadata": {"Album": "Metallica", "Released": "1991", "Label": "Elektra"},
"related_videos": ["https://youtube.com/watch?v=..."]
}- Artwork: add a Picture Entity card that uses the
Artwork URLsensor. - Now Playing details: add a Markdown card with
{{ state_attr('sensor.living_room_shazam_now_playing', 'lyrics') }}. - Quick link: add a button that opens
{{ state_attr('sensor.living_room_shazam_now_playing', 'apple_music_url') }}.
The docker-compose.yml passes /dev/snd into the container. This works on most headless Linux hosts.
If your host runs PipeWire, set the ALSA card name so the container uses the right mic:
# Find your capture card name on the host
arecord -l
# Look for: card X: NAME [Human Readable Name]
# Example: card 3: C615 [HD Webcam C615]Then in .env:
ALSA_CARD=C615This is cleaner than SOUND_DEVICE because it survives card-number reordering.
If your host uses pure PulseAudio (not PipeWire), comment out the devices: block and uncomment the volumes: / PULSE_SERVER lines in docker-compose.yml.
| Topic | Type | Payload example |
|---|---|---|
shazam2mqtt/<name>/now_playing |
state | Nothing Else Matters — Metallica |
shazam2mqtt/<name>/status |
status | playing / unknown/no-match / silence |
shazam2mqtt/<name>/matched |
binary | ON / OFF |
shazam2mqtt/<name>/track |
sensor | Nothing Else Matters |
shazam2mqtt/<name>/artist |
sensor | Metallica |
shazam2mqtt/<name>/confidence |
sensor | 4 |
shazam2mqtt/<name>/apple_music_url |
sensor | https://music.apple.com/... |
shazam2mqtt/<name>/artwork_url |
sensor | https://is1-ssl.mzstatic.com/... |
shazam2mqtt/<name>/noise_level |
sensor | -40.0 |
shazam2mqtt/<name>/command |
command in | listen_now |
Make sure the container has access to /dev/snd or the PulseAudio socket. On the host:
arecord -lIf no capture devices appear, the host itself can't see a mic.
The mic doesn't support the default 44100 Hz. Try:
SAMPLE_RATE=48000Or for cheap webcams:
SAMPLE_RATE=16000The container is reading from the wrong device or the capture volume is muted.
- Check the startup logs for the device list:
docker logs shazam2mqtt --tail 20
- If the default device looks wrong, set the correct one:
# Option A: PipeWire / ALSA card name (recommended) ALSA_CARD=C615 # Option B: PortAudio device index SOUND_DEVICE=2
- Check host ALSA capture volume:
Press
alsamixer -c 2 # replace 2 with your card numberF4for Capture view, make sure it's not muted (MM) and volume is high.
- Lower
NOISE_GATE_DB(e.g.-60) so quieter audio triggers the gate. - Move the mic closer to the speakers.
- Increase
LISTEN_DURATIONto give Shazam more audio to fingerprint.
- Check that the MQTT integration is enabled in Home Assistant.
- Verify
HA_ENABLED=true. - Check the broker credentials (
MQTT_HOST,MQTT_USER,MQTT_PASS) are correct.
pip install -e .
export DEVICE_NAME=my_room
export MQTT_HOST=192.168.1.200
python -m shazam2mqttMIT