Zo werkt Zwaailicht.nu: van P2000-melding tot kaart in milliseconden
Elke dag verwerkt Zwaailicht.nu duizenden P2000-meldingen — van ambulanceritten en brandweeruitrukken tot politie-inzetten. Maar hoe gaat dat precies? Wat gebeurt er in de seconden tussen het moment dat een meldkamer een alarm verstuurt en het verschijnen op de kaart?
In dit artikel nemen we je mee door de technische architectuur van Zwaailicht.nu.
Het P2000-netwerk
P2000 is het digitale alarmeringsnetwerk dat Nederlandse hulpdiensten gebruiken. Meldkamers versturen via dit netwerk korte berichten naar piepers en mobilofoons van brandweer, ambulance, politie en lifeliner-teams. Een typisch bericht ziet er zo uit:
A1 AMBU 17104 Haringstraat 15 3011TJ Rotterdam CVA
Dit compacte bericht bevat verrassend veel informatie — maar het is niet direct leesbaar voor een computer. Dat is waar onze verrijkingspijplijn begint.
Stap 1: ophalen en opslaan
De P2000-berichten ontvangen we rechtstreeks uit de ether via een Raspberry Pi met een RTL-SDR module — een goedkope software-defined radio die het FLEX-protocol op 169,65 MHz kan decoderen. De Pi draait continu en stuurt ontvangen berichten door naar de backend. Benieuwd hoe dat werkt? Waterkaart.net heeft er een uitgebreide handleiding over geschreven.
Na deduplicatie worden de meldingen opgeslagen in een DuckDB database — een snelle, embedded analytische database die ideaal is voor tijdreeksdata.
Waarom DuckDB en niet PostgreSQL? De applicatie draait als enkele container op een VPS. DuckDB heeft geen aparte databaseserver nodig, start in milliseconden op, en blinkt uit in analytische queries over tijdreeksen — precies wat we nodig hebben voor statistieken en trenddetectie.
Stap 2: de verrijkingspijplijn
Het hart van Zwaailicht.nu is de enrichment pipeline: een keten van zeven gespecialiseerde modules die elk een ander aspect van het P2000-bericht analyseren.
Prioriteit
De eerste stap extraheert de prioriteitscode. A1 betekent spoed met zwaailicht en sirene, A2 is urgent maar zonder sirene, B1 is gepland vervoer. Voor brandweer geldt P1 (spoed) en P2 (geen spoed). Politie gebruikt PRIO1 tot PRIO3.
Locatie
De locatie-enricher herkent straatnamen, huisnummers, postcodes en plaatsnamen uit de vrije tekst. Dit is complexer dan het lijkt — P2000-berichten gebruiken afkortingen, schrijven postcodes soms aan elkaar, en bevatten storingsinformatie tussen de locatiegegevens door.
Uit ons voorbeeld haalt de enricher: - Straat: Haringstraat - Huisnummer: 15 - Postcode: 3011TJ - Stad: Rotterdam
Snelweg
Meldingen op snelwegen hebben een eigen formaat: A1 RE 25,4 betekent Rijksweg A1, rechterrijbaan, hectometerpaal 25,4. De snelweg-enricher herkent de rijkswegcode, rijrichting en kilometrering.
Voertuigen
P2000-berichten bevatten voertuigcodes die aangeven welke eenheden zijn ingezet. TS is een tankautospuit, AL een autoladder, HV een hulpverleningsvoertuig, MMT het Mobiel Medisch Team (traumaheli). In totaal herkennen we meer dan 50 verschillende voertuigcodes.
Medisch
Medische meldingen bevatten vaak diagnosecodes. CVA (beroerte), ACS (hartaanval), AED (hartstilstand met beschikbare defibrillator) en TIA (mini-beroerte) zijn veelvoorkomend. Deze codes bepalen mede welke specialist wordt opgeroepen.
Incidenttype
Op basis van alle voorgaande verrijkingen classificeert de incident-enricher het type melding. Een bericht met brandweercodes en termen als “woningbrand” wordt geclassificeerd als fire/house_fire. Een ambulancemelding met CVA wordt medical. Een melding op de A1 met “aanrijding” wordt traffic/car_accident.
We onderscheiden zes hoofdcategorieën: brand, medisch, verkeer, hulpverlening, water en gevaarlijke stoffen.
Geocodering
De laatste stap vertaalt het adres naar GPS-coördinaten. Met de geëxtraheerde straat, huisnummer en stad sturen we een geocoding-verzoek om de exacte locatie op de kaart te bepalen.
Stap 3: real-time naar de kaart
Zodra een melding is verrijkt, wordt deze via een WebSocket naar alle verbonden browsers gestuurd. De kaart op de homepage toont de melding direct met een marker, inclusief kleur per hulpdienst (rood voor brandweer, geel voor ambulance, blauw voor politie).
Dit alles — ophalen, verrijken, opslaan, versturen — duurt gemiddeld minder dan 100 milliseconden per melding.
Stap 4: piekdetectie
Naast het tonen van individuele meldingen, detecteert Zwaailicht.nu automatisch pieken — periodes met ongewoon hoge activiteit. Het algoritme vergelijkt het huidige aantal meldingen per stad met het historisch gemiddelde voor datzelfde tijdstip.
De formule: als het huidige aantal meer dan k standaarddeviaties boven het gemiddelde ligt, signaleren we een piek. De ernstgraad loopt op van “verhoogd” (2-3σ) via “hoog” (3-4σ) tot “extreem” (>4σ).
Bij een gedetecteerde piek worden automatisch nieuwsartikelen gezocht om context te bieden. De pieken-pagina toont alle recente uitschieters.
Stap 5: nieuwskoppeling
Zodra een piek is gedetecteerd, gaat het systeem automatisch op zoek naar gerelateerde nieuwsberichten. Via de Google News RSS-feed zoeken we op trefwoorden uit de piek — plaatsnaam, incidenttype, hulpdienst — en filteren we op artikelen die binnen het tijdvenster van de piek zijn gepubliceerd.
Gevonden artikelen worden gekoppeld aan de piek en getoond op de detailpagina. Zo kun je bij een grote brand in Rotterdam direct de bijbehorende berichten van NOS, RTVRijnmond of het AD zien. De nieuwspagina verzamelt alle gekoppelde artikelen.
Stap 6: AI-samenvattingen
Bij pieken met voldoende meldingen en gekoppelde nieuwsberichten genereert Zwaailicht.nu automatisch een samenvatting met Claude Haiku van Anthropic. Het model krijgt de P2000-meldingen, nieuwsartikelen en piekdata als context en schrijft een beknopt, feitelijk overzicht van wat er is gebeurd.
Dit levert samenvattingen op als: “In de binnenstad van Utrecht zijn donderdagavond meerdere hulpdiensten uitgerukt voor een grote brand in een winkelpand. De brandweer was met 6 eenheden ter plaatse.” — snel leesbare context zonder dat je zelf alle losse meldingen hoeft te puzzelen.
De samenvattingen verschijnen op de pieken-pagina en op stadspagina’s in het weekoverzicht.
Stap 7: stadspagina’s en statistieken
Voor elke stad in Nederland genereert Zwaailicht.nu een eigen pagina met actuele statistieken. Amsterdam, Rotterdam, Utrecht — elke stad heeft een overzicht met:
- Meldingen per 24 uur, 7 dagen en 30 dagen
- Verdeling over hulpdiensten
- Piekuren en drukste weekdag
- Trend ten opzichte van vorige week
- Ranglijst-positie ten opzichte van andere gemeenten
De ranglijst toont welke gemeenten de meeste hulpdienst activiteit hebben.
De technische stapel
Zwaailicht.nu draait op een relatief eenvoudige stack:
- FastAPI — Python web framework voor API en server-side rendering
- DuckDB — Embedded analytische database
- Leaflet — Open-source kaartbibliotheek
- Jinja2 — Template-engine voor SEO-pagina’s
- Claude Haiku — AI-samenvattingen van incidenten
- WebSocket — Real-time communicatie met de browser
Alles draait in een enkele Docker-container achter een Caddy reverse proxy voor automatische HTTPS. Geen Kubernetes, geen microservices — gewoon een efficiënte monolith die duizenden meldingen per dag verwerkt.
Wat komt er nog?
We werken continu aan verbeteringen. Op de roadmap staan onder andere:
- Historische analyses — Trends en patronen over langere periodes
- Push-notificaties — Meldingen bij pieken in jouw omgeving
- Vergelijkingen — Steden en regio’s naast elkaar zetten
Heb je vragen of suggesties? We horen het graag.