Forward Forecasting logo FORWARDFORECASTING

Field Notes · IoT & Edge

A Noise Monitor That Knows the Local Law

A Raspberry Pi on a balcony measures sound the way a sound level meter does, keeps the loud nights as tamper-evident clips, and works out from its own coordinates which noise limits apply on its street, at every minute of the week.

Fernando Borbón October 2026 Live at noise-monitor.forwardforecasting.eu, demo at forwardforecasting.eu/noise-monitor
Illustration of a residential street at night seen from a balcony, with a gold level chart above the rooftops

It started with a wedding venue across the street. Summer weekends end at three in the morning with a bass line coming through closed windows, and a complaint to the town hall needs more than "it was loud again". It needs dates, times, levels, and ideally a recording, so that a municipal technician comes to measure on the right night instead of a quiet one.

So I built a measuring station instead of keeping a diary. A Raspberry Pi with a USB microphone measures the A-weighted level every second, sends it to a small web service with a public map and chart, and records five-minute clips when the level stays high. Then I added the part that turned out to be the most interesting: the station finds out which noise regulations apply where it stands and draws the legal limit, with its own day, evening and night periods, on the chart.

Measuring like a sound level meter, on a €35 computer

A noise limit in dB(A) is a precise thing, and a homemade meter is only useful if it computes the same quantity. The station follows the definitions in IEC 61672-1, the sound level meter standard:

flowchart LR
    mic["USB microphone\n48 kHz"] --> meter["A-weighting\nLAeq, LAmax per second"]
    meter --> rec["Event detector\nLAeq,10s vs trigger\n150 s pre-roll buffer"]
    rec --> spool[("SD card spool\nFLAC + SHA-256")]
    meter --> up["Uploader"]
    spool --> up
    up -->|HTTPS| api["FastAPI + SQLite"]
    api --> web["Public map and chart"]
    api -->|"behind login"| owner["Owner: clips, spectrum"]
    api -->|"position"| osm["Nominatim\ntown + region"]
    osm --> rules["regulations.json\nstrictest limit per minute"]
    rules -->|"trigger in force"| up
      
From microphone to legal limit: the server sends each station its recording trigger with every upload.

The audio itself never leaves the Pi except around an event. The agent keeps the last few minutes in a ring buffer, so a clip starts 150 seconds before the moment the level crossed the trigger: you hear the build-up, not just the peak. Each clip is lossless FLAC with a SHA-256 hash computed on the device and checked again by the server, and a cooldown of 15 minutes means a four-hour party gives about a dozen clips instead of 48 back-to-back ones. If the WiFi drops, everything waits on the SD card and is sent later.

The first event rule failed a real test

The first version started an event when every one of 10 consecutive seconds was above the trigger. It sounded reasonable and it missed the very first real test: people talking near the microphone produced 54 loud seconds in ten minutes, but never more than four in a row, because speech and music have natural pauses. The rule now uses the energy average over the last 10 seconds, LAeq,10s, which is how noise limits are actually defined. A door slam still does not start a recording; a conversation or a song does.

Which limit? Three authorities, three timetables

The first version had one number per station: "limit 55 dB(A)". That is wrong in two ways. Limits change with the time of day, and in Spain they are set by several authorities at once. For a street in Pamplona, three texts apply (a town without a noise ordinance of its own keeps the first two):

SourcePeriodsQuiet residential area, dB(A)
Real Decreto 1367/2007, annex III, table B1 (national)day 7-19, evening 19-23, night 23-755 / 55 / 45
Decreto Foral 135/1989, art. 15.1 (Navarra)day 8-22, night 22-855 / 45
Pamplona's activities ordinance, art. 9.2 (town)day 8-22, night 22-865 / 55 at the venue's property line

Each authority can only tighten what the others allow, so the station combines them minute by minute over a week and keeps the strictest value. For a quiet residential street the result is 55 dB(A) from 8:00 to 22:00 and 45 dB(A) from 22:00 to 8:00: Navarra's longer night with the national night value. For a busier residential street it is more interesting, because Navarra allows 60/50 there while the national table stays at 55/45:

22:00
50 dB(A), Navarra's night begins
23:00
45 dB(A), the national night begins
07:00
50 dB(A), national night ends, Navarra's continues
08:00
55 dB(A), day

Nobody would write that timetable by hand, and it falls out of the combination automatically.

From coordinates to a town hall

When a station gets a position (from a map in the "Add new device" form, by hand, or from the WiFi access points it can see), the server asks OpenStreetMap's Nominatim for the municipality, region and country. The rules live in one JSON file, each with the place it covers, its periods, its value for each type of area (the categories the regulations themselves use: hospitals and schools, quiet residential, residential with traffic, commercial, leisure, industrial, rural) and a link to the official text. The owner picks the type of area; everything else follows from the position.

The weekly schedule then drives the whole site. It produces the stepped limit line and grey night bands on the chart, the pink shading where the level was over the limit in force at that moment, the time over the limit per period in the last 24 hours, and the classification of each recorded event against the limit when it started. A 50 dB(A) event at 23:30 is now "+5 over" while the same level at noon is "within". It also drives the device: with every upload the server returns the recording trigger, the limit in force plus an offset, so the station records more readily at night without anyone changing a setting.

The rule file also covers New South Wales (with a day that starts an hour later on Sundays) and Brazil, and falls back to the WHO guideline (55 dB(A) day, 45 at night) anywhere without a rule on file, clearly labelled as a guideline, not a law. Midtown Manhattan is over it all day.

Honest about what this is

An official assessment measures LKeq over the whole period with a certified meter, adds penalties for tonal or impulsive sound, and some ordinances measure at the property line or inside the home with the windows closed. A USB microphone is not a certified class 1 meter, and in Spain no USB microphone makes a measurement legally valid on its own. The station compares one-second readings with the limit in force, which is exactly what is needed to find the nights worth an official measurement and to show a pattern, and the page says so under the limits table.

What broke along the way

The stack, briefly

NumPy / SciPyA-weighting and decimation filters with state carried between one-second blocks.
sounddevice / soundfilePortAudio capture and lossless FLAC clips on the Pi.
FastAPI + SQLite (WAL)One container, 37 MB of RAM idle, one row per station per second.
OpenStreetMap NominatimCoordinates to municipality and region, to pick the regulations.
zoneinfoDay and night periods in the station's time zone, right across daylight-saving changes.
Leaflet + Chart.jsThe public map and the chart with the stepped limit line.
Web Audio APIA live third-octave spectrum while a clip plays: bass through the walls shows up immediately.
cloud-init + GitHub Actions"Add new device" downloads the SD card files; every push deploys through AWS SSM with OIDC.

What it costs to run

No extra cloud cost: the service is one small container on a host that already runs other services, the map tiles, reverse geocoding and WiFi location lookups are free at this volume, and there are no AI calls. Storage grows by about 1.4 GB of levels and 3 GB of clips per station per year. The hardware is about €160 per station with a measurement microphone that ships with its own calibration file, which can then be checked against an acoustic calibrator that carries an accredited certificate.

Try it

The demo has five simulated stations with synthesised sound, each following its own local time and its own rules: New York, the Amazon rainforest (on a fixed limit, since nature is not regulated), Madrid by the stadium on match nights, a concert in Sydney, and a Barcelona street next to a wedding venue. The "Add new device" form works there too: click anywhere on the map and it looks up the rules for that town.

See it live

Real IEC 61672 level definitions, real regulations with links to the official texts, and a station on a real balcony waiting for its microphone.

Open the demo → Live service →

About the cover image: a balcony view of a residential street at night, with a level trace rising above the rooftops. ImageModelstability.stable-image-core-v1:1 · AWS Bedrock (us-west-2)Prompt“Editorial illustration, a quiet residential street at night seen from a balcony, a small weatherproof microphone station on the railing, glowing gold sound waves rising from a lit building across the street, a gold stepped line chart floating above the rooftops, deep navy background, minimalist flat vector illustration style, clean geometric linework, no text, no logos”