# P-2000 Monitor Real-time Dutch emergency services (P-2000) channel monitor. Koa server + WebSocket + RSS polling, dark shadcn-style UI. ## Stack | Layer | Tech | |-------------|-------------------------------------------------------| | Server | Node.js 20, Koa 2, koa-static, koa-router | | WebSocket | `ws` library — attached to same HTTP server | | P-2000 data | RSS polling via axios + xml2js (30s interval) | | Process mgr | PM2 with watch mode (`pm2.config.js`) | | Frontend | Vanilla JS, TailwindCSS Play CDN, shadcn-style design | ## Port `10000` (override via `PORT` env var) ## Running ```bash # Install npm install # Dev (PM2 watch mode — auto-restart on src/ or server.js changes) npm run dev # Logs npm run logs # Stop npm run stop # Plain node (no PM2) npm start ``` ## Project layout ``` server.js # Koa HTTP + WebSocket server, P-2000 event bridge src/p2000.js # EventEmitter: RSS fetcher, XML parser, type detector public/index.html # Single-page frontend (TailwindCSS + vanilla JS) pm2.config.js # PM2 watch config logs/ # PM2 out/error logs (git-ignored) ``` ## P-2000 Feed source **Primary:** `https://112-nu.nl/hulpdiensten/rss` (all services combined, polled every 30s) Per-service feeds also available but not used (combined is sufficient): - `https://112-nu.nl/brandweer/rss` - `https://112-nu.nl/ambulance/rss` - `https://112-nu.nl/politie/rss` Change the feed URL via `COMBINED_FEED` constant in `src/p2000.js`. ## Message types Detected from `` RSS tag first, then keyword fallback: | Category code | Type | |---------------|-------------| | BRA, BRW | `fire` | | AMB, MKA | `ambulance` | | POL | `police` | | KNRM, HELI | `rescue` | Extend `CATEGORY_MAP` or `KEYWORD_MAP` in `src/p2000.js` to tune detection. ## WebSocket protocol Client connects to `ws://localhost:10000/ws` Server → Client messages: ```json { "type": "history", "messages": [ ...MessageObject ] } { "type": "message", "message": MessageObject } ``` `MessageObject`: ```json { "id": "unique-guid", "title": "P1 Melding Brand - Rotterdam", "description": "Extended alert text", "pubDate": "2024-01-15T12:34:56.000Z", "link": "https://...", "type": "fire", "region": "Zuid-Holland" } ``` ## Health check `GET /health` → `{ status, uptime, messages }`