From 48aaf828993fcbcadc15a909640db8f0afd80bed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Reinhard=20X=2E=20F=C3=BCrst?= Date: Fri, 10 Jul 2026 15:45:37 +0200 Subject: [PATCH] =?UTF-8?q?chore:=20km=5Fberechnen=20Tool=20(BEO-Entfernun?= =?UTF-8?q?gen/Fahrkosten-Recherche)=20hinzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 (1M context) --- km_berechnen/.gitignore | 2 + km_berechnen/README.md | 57 ++++++++ km_berechnen/beo-entfernungen.html | 151 ++++++++++++++++++++++ km_berechnen/beo-entfernungen.pdf | Bin 0 -> 82683 bytes km_berechnen/berechne-km.mjs | 201 +++++++++++++++++++++++++++++ km_berechnen/erzeuge-pdf.mjs | 112 ++++++++++++++++ 6 files changed, 523 insertions(+) create mode 100644 km_berechnen/.gitignore create mode 100644 km_berechnen/README.md create mode 100644 km_berechnen/beo-entfernungen.html create mode 100644 km_berechnen/beo-entfernungen.pdf create mode 100644 km_berechnen/berechne-km.mjs create mode 100644 km_berechnen/erzeuge-pdf.mjs diff --git a/km_berechnen/.gitignore b/km_berechnen/.gitignore new file mode 100644 index 0000000..0e754e3 --- /dev/null +++ b/km_berechnen/.gitignore @@ -0,0 +1,2 @@ +.env +geocode-cache.json diff --git a/km_berechnen/README.md b/km_berechnen/README.md new file mode 100644 index 0000000..7e5d1f8 --- /dev/null +++ b/km_berechnen/README.md @@ -0,0 +1,57 @@ +# km_berechnen + +Berechnet die **Straßenentfernung (km)** zwischen der fixen **Sternwarte Welzheim** +und dem Wohnort jedes BEOs (Tabelle `beos`) und schreibt das Ergebnis in die +vorhandene Spalte `beos.km`. + +Der DB-Zugriff läuft über den **PHP-Proxy** `DB4js_all.php`, da die echte +Sternwarte-Datenbank nicht direkt erreichbar ist: + +- Lesen: `cmd = LB_GET_BEO_ADRESSEN` (BEOs mit Adresse + km) +- Schreiben: `cmd = LB_UPDATE_BEO_KM` `{ id, km }` + +Distanzberechnung: + +- **Geocoding:** OpenStreetMap [Nominatim](https://nominatim.openstreetmap.org) (kostenlos, ohne API-Key) +- **Routing:** öffentlicher [OSRM](https://project-osrm.org)-Server (kostenlos, ohne API-Key) + +## Einrichtung + +1. `.env` öffnen und `PHP_DB_URL` auf den DB4js-Endpunkt setzen + (lokal: `http://localhost:8080/DB4js_all.php`). Falls der Proxy Basic-Auth + verlangt, zusätzlich `API_USER` / `API_PASS` eintragen. +2. Optional den exakten Referenzpunkt der Sternwarte setzen + (`STERNWARTE_LAT` / `STERNWARTE_LON`) — sonst wird er per Nominatim ermittelt, + mit Ortsmitte Welzheim als Fallback. + +Es werden nur Node-Bordmittel verwendet (globales `fetch`) — kein +`npm install` nötig (Node ≥ 18). + +## Ausführen + +```bash +cd km_berechnen +node --env-file=.env berechne-km.mjs # berechnen und in beos.km schreiben +node --env-file=.env berechne-km.mjs --dry-run # nur berechnen/anzeigen, DB unverändert +``` + +## Hinweise + +- Geocoding-Ergebnisse werden in `geocode-cache.json` zwischengespeichert; ein + zweiter Lauf ist dadurch deutlich schneller. Zum Neu-Geocodieren die Datei löschen. +- Nominatim erlaubt max. 1 Anfrage/Sekunde — das Skript hält dies automatisch ein. +- BEOs ohne (vollständige) Adresse bzw. ohne Geocoding-/Routing-Treffer erhalten + `km = NULL` und werden am Ende aufgelistet. +- Die öffentlichen Nominatim-/OSRM-Server sind „Fair Use"; für die ~20 BEOs + unproblematisch. +- Die beiden Proxy-Kommandos (`LB_GET_BEO_ADRESSEN`, `LB_UPDATE_BEO_KM`) sind in + `DB4js_all.php` implementiert. + +## Ergebnis prüfen + +Per Proxy: + +```bash +curl -s -X POST "$PHP_DB_URL" -H 'Content-Type: application/json' \ + -d '{"cmd":"LB_GET_BEO_ADRESSEN"}' +``` diff --git a/km_berechnen/beo-entfernungen.html b/km_berechnen/beo-entfernungen.html new file mode 100644 index 0000000..3660a07 --- /dev/null +++ b/km_berechnen/beo-entfernungen.html @@ -0,0 +1,151 @@ + +BEO-Entfernungen + + +

Entfernungen der BEOs zur Sternwarte Welzheim

+

Einfache Straßenentfernung in Kilometern · Stand: 10. Juli 2026

+

+ Die folgende Tabelle listet die einfache Straßenentfernung (Auto) von deinem + Wohnort zur Sternwarte Welzheim. Die Werte wurden automatisch über + OpenStreetMap / OSRM ermittelt. Bitte prüfe deinen Wert und melde + ihn in jedem Fall zurück – auch wenn er stimmt. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
#NameWohnortkm
1Ralf BernhardStuttgart53.0
2Steffen BrücknerWeil im Schönbuch68.6
3Hans DschidaUrbach15.3
4Andrea EssRemshalden23.8
5Ulrich FörnzlerStuttgart39.3
6Reinhard FuerstStuttgart43.3
7Martin GertzWeinstadt26.8
8Hubert GräberRemshalden19.1
9Marc GüssmannBacknang22.3
10Rudolf IdlerKernen29.3
11Hans-Ulrich KellerStuttgart40.8
12Olaf Meyer-HammeWinterbach19.0
13Xeno NastosAlfdorf14.7
14Jörg NikolaizigLudwigsburg46.9
15Christoph RiedlAichwald33.7
16Eva SchneiderWelzheim8.1
17Bernd SchulerSchorndorf14.5
18Christoph WeishaarWaiblingen-Bittenfeld43.0
19Matthias ZollerSindelfingen60.6
+

19 Beobachter · Sternwarte Welzheim · automatisch erzeugt

+ \ No newline at end of file diff --git a/km_berechnen/beo-entfernungen.pdf b/km_berechnen/beo-entfernungen.pdf new file mode 100644 index 0000000000000000000000000000000000000000..bef6018dc69177428a4baa161ba5e35b86606778 GIT binary patch literal 82683 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

Mqchz#xQ3-EO&@3p1yl1Y;3{6X4~r7 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 literal 0 HcmV?d00001 diff --git a/km_berechnen/berechne-km.mjs b/km_berechnen/berechne-km.mjs new file mode 100644 index 0000000..6433e49 --- /dev/null +++ b/km_berechnen/berechne-km.mjs @@ -0,0 +1,201 @@ +// Berechnet die Straßenentfernung (km) zwischen der fixen Sternwarte Welzheim +// und dem Wohnort jedes BEOs und schreibt das Ergebnis in die Spalte beos.km. +// +// Der DB-Zugriff läuft über den PHP-Proxy (DB4js_all.php), da die echte +// Sternwarte-Datenbank nicht direkt erreichbar ist: +// Lesen: cmd LB_GET_BEO_ADRESSEN +// Schreiben: cmd LB_UPDATE_BEO_KM { id, km } +// +// Geocoding: OpenStreetMap Nominatim | Routing: öffentlicher OSRM-Server. +// Beide kostenlos, ohne API-Key. Ausführen mit: +// node --env-file=.env berechne-km.mjs +// +// Optionen: +// --dry-run nichts in die DB schreiben, nur berechnen und anzeigen + +import { readFile, writeFile } from 'node:fs/promises'; +import { fileURLToPath } from 'node:url'; +import { dirname, join } from 'node:path'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const CACHE_FILE = join(__dirname, 'geocode-cache.json'); +const USER_AGENT = 'sternwarte-welzheim-km-berechnen/1.0 (rxf@gmx.de)'; +const DRY_RUN = process.argv.includes('--dry-run'); + +const PHP_DB_URL = process.env.PHP_DB_URL || 'http://localhost:8080/DB4js_all.php'; + +// Fallback-Referenzpunkt: Ortsmitte Welzheim (nur Näherung, per .env überschreibbar) +const DEFAULT_STERNWARTE = { lat: 48.8756, lon: 9.6377 }; + +const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); + +// ---- PHP-Proxy (DB4js) ---- + +async function callProxy(cmd, params = {}) { + const headers = { 'Content-Type': 'application/json' }; + if (process.env.API_USER && process.env.API_PASS) { + const token = Buffer.from(`${process.env.API_USER}:${process.env.API_PASS}`).toString('base64'); + headers.Authorization = `Basic ${token}`; + } + const res = await fetch(PHP_DB_URL, { + method: 'POST', + headers, + body: JSON.stringify({ cmd, ...params }), + }); + const text = await res.text(); + let json; + try { + json = JSON.parse(text); + } catch { + throw new Error(`DB4js ${cmd} HTTP ${res.status}: ${text.slice(0, 200)}`); + } + if (json && typeof json === 'object' && !Array.isArray(json) && 'error' in json) { + throw new Error(`DB4js ${cmd}: ${json.error}`); + } + if (!res.ok) throw new Error(`DB4js ${cmd} HTTP ${res.status}`); + return json; +} + +// ---- Geocode-Cache (Adresse -> {lat, lon} | null) ---- + +async function loadCache() { + try { + return JSON.parse(await readFile(CACHE_FILE, 'utf8')); + } catch { + return {}; + } +} + +async function saveCache(cache) { + await writeFile(CACHE_FILE, JSON.stringify(cache, null, 2), 'utf8'); +} + +// ---- Nominatim Geocoding (max. 1 Anfrage/Sekunde) ---- + +async function geocode(query, cache) { + if (Object.prototype.hasOwnProperty.call(cache, query)) { + return cache[query]; // Treffer (auch gecachte Fehlschläge = null) + } + const url = + 'https://nominatim.openstreetmap.org/search?format=json&limit=1&q=' + + encodeURIComponent(query); + const res = await fetch(url, { headers: { 'User-Agent': USER_AGENT } }); + if (!res.ok) throw new Error(`Nominatim HTTP ${res.status}`); + const json = await res.json(); + const hit = Array.isArray(json) && json[0] + ? { lat: parseFloat(json[0].lat), lon: parseFloat(json[0].lon) } + : null; + cache[query] = hit; + await saveCache(cache); + await sleep(1100); // Rate-Limit einhalten + return hit; +} + +// ---- OSRM Straßenrouting -> Distanz in km ---- + +async function roadKm(from, to) { + const url = + `https://router.project-osrm.org/route/v1/driving/` + + `${from.lon},${from.lat};${to.lon},${to.lat}?overview=false`; + const res = await fetch(url, { headers: { 'User-Agent': USER_AGENT } }); + if (!res.ok) throw new Error(`OSRM HTTP ${res.status}`); + const json = await res.json(); + if (json.code !== 'Ok' || !json.routes?.[0]) return null; + return Math.round((json.routes[0].distance / 1000) * 10) / 10; +} + +function buildAddress(row) { + const parts = [row.Adresse, [row.Plz, row.Ort].filter(Boolean).join(' ').trim()] + .map((s) => (s || '').trim()) + .filter(Boolean); + return parts.length ? parts.join(', ') + ', Deutschland' : ''; +} + +async function resolveSternwarte(cache) { + const envLat = parseFloat(process.env.STERNWARTE_LAT ?? ''); + const envLon = parseFloat(process.env.STERNWARTE_LON ?? ''); + if (Number.isFinite(envLat) && Number.isFinite(envLon)) { + return { lat: envLat, lon: envLon, source: '.env' }; + } + const hit = await geocode('Sternwarte, Welzheim, Deutschland', cache); + if (hit) return { ...hit, source: 'Nominatim' }; + return { ...DEFAULT_STERNWARTE, source: 'Fallback (Ortsmitte Welzheim)' }; +} + +async function main() { + const cache = await loadCache(); + + const ref = await resolveSternwarte(cache); + console.log(`Proxy: ${PHP_DB_URL}`); + console.log( + `Referenzpunkt Sternwarte Welzheim: ${ref.lat}, ${ref.lon} [${ref.source}]\n` + ); + + const rows = await callProxy('LB_GET_BEO_ADRESSEN'); + + const done = []; + const skipped = []; + + for (const row of rows) { + const address = buildAddress(row); + if (!address) { + skipped.push({ row, reason: 'keine Adresse' }); + if (!DRY_RUN) await callProxy('LB_UPDATE_BEO_KM', { id: row.ID, km: null }); + continue; + } + + let km = null; + let reason = ''; + try { + const geo = await geocode(address, cache); + if (!geo) { + reason = 'Geocoding ohne Treffer'; + } else { + km = await roadKm(ref, geo); + if (km == null) reason = 'keine Route gefunden'; + } + } catch (err) { + reason = err.message; + } + + if (!DRY_RUN) await callProxy('LB_UPDATE_BEO_KM', { id: row.ID, km }); + + if (km == null) skipped.push({ row, reason }); + else done.push({ row, km }); + } + + // ---- Zusammenfassung ---- + console.log('Berechnete Entfernungen:'); + console.log('Kürzel Name Ort km'); + console.log('─'.repeat(66)); + done + .sort((a, b) => a.km - b.km) + .forEach(({ row, km }) => { + console.log( + (row.Kuerzel || '').padEnd(7) + + ' ' + + (row.Name || '').padEnd(24) + + ' ' + + (row.Ort || '').padEnd(24) + + ' ' + + String(km).padStart(6) + ); + }); + + if (skipped.length) { + console.log('\nÜbersprungen / ohne Ergebnis (km = NULL):'); + skipped.forEach(({ row, reason }) => + console.log(` ${(row.Kuerzel || '?').padEnd(7)} ${(row.Name || '').padEnd(24)} — ${reason}`) + ); + } + + console.log( + `\nFertig. ${done.length} berechnet, ${skipped.length} übersprungen.` + + (DRY_RUN ? ' (DRY-RUN: nichts in die DB geschrieben)' : ' In Spalte beos.km gespeichert.') + ); +} + +main().catch((err) => { + console.error('Fehler:', err.message); + process.exit(1); +}); diff --git a/km_berechnen/erzeuge-pdf.mjs b/km_berechnen/erzeuge-pdf.mjs new file mode 100644 index 0000000..4fb58d3 --- /dev/null +++ b/km_berechnen/erzeuge-pdf.mjs @@ -0,0 +1,112 @@ +// Erzeugt eine PDF-Tabelle aller BEOs mit Wohnort und Straßenentfernung (km) +// zur Sternwarte Welzheim — zum Versand an die BEOs zur Verifizierung. +// +// Daten kommen über den PHP-Proxy (cmd GET_BEOS). Das HTML wird mit Headless- +// Chrome nach PDF gerendert. +// node --env-file=.env erzeuge-pdf.mjs +// +// Ergebnis: beo-entfernungen.html und beo-entfernungen.pdf + +import { writeFile } from 'node:fs/promises'; +import { execFile } from 'node:child_process'; +import { promisify } from 'node:util'; +import { fileURLToPath } from 'node:url'; +import { dirname, join } from 'node:path'; + +const execFileP = promisify(execFile); +const __dirname = dirname(fileURLToPath(import.meta.url)); +const HTML_FILE = join(__dirname, 'beo-entfernungen.html'); +const PDF_FILE = join(__dirname, 'beo-entfernungen.pdf'); + +const PHP_DB_URL = process.env.PHP_DB_URL || 'http://localhost:8080/DB4js_all.php'; +const CHROME = process.env.CHROME_PATH || + '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'; + +async function callProxy(cmd, params = {}) { + const headers = { 'Content-Type': 'application/json' }; + if (process.env.API_USER && process.env.API_PASS) { + const token = Buffer.from(`${process.env.API_USER}:${process.env.API_PASS}`).toString('base64'); + headers.Authorization = `Basic ${token}`; + } + const res = await fetch(PHP_DB_URL, { + method: 'POST', headers, body: JSON.stringify({ cmd, ...params }), + }); + const json = await res.json(); + if (json && !Array.isArray(json) && json.error) throw new Error(`DB4js ${cmd}: ${json.error}`); + return json; +} + +const esc = (s) => String(s ?? '').replace(/[&<>]/g, (c) => ({ '&': '&', '<': '<', '>': '>' }[c])); + +function fullName(r) { + return [r.vorname, r.name].map((x) => (x || '').trim()).filter(Boolean).join(' '); +} + +function buildHtml(rows) { + const stand = new Date().toLocaleDateString('de-DE', { day: '2-digit', month: 'long', year: 'numeric' }); + const body = rows.map((r, i) => ` + + ${i + 1} + ${esc(fullName(r))} + ${esc(r.ort)} + ${r.km == null || r.km === '' ? '—' : esc(r.km)} + `).join(''); + + return ` +BEO-Entfernungen + + +

Entfernungen der BEOs zur Sternwarte Welzheim

+

Einfache Straßenentfernung in Kilometern · Stand: ${stand}

+

+ Die folgende Tabelle listet die einfache Straßenentfernung (Auto) von deinem + Wohnort zur Sternwarte Welzheim. Die Werte wurden automatisch über + OpenStreetMap / OSRM ermittelt. Bitte prüfe deinen Wert und melde + ihn in jedem Fall zurück – auch wenn er stimmt. +

+ + + + + ${body} + +
#NameWohnortkm
+

${rows.length} Beobachter · Sternwarte Welzheim · automatisch erzeugt

+`; +} + +async function main() { + const rows = await callProxy('GET_BEOS', { what: 'id,vorname,name,ort,km' }); + rows.sort((a, b) => (a.name || '').localeCompare(b.name || '', 'de')); + + const html = buildHtml(rows); + await writeFile(HTML_FILE, html, 'utf8'); + + await execFileP(CHROME, [ + '--headless=new', + '--disable-gpu', + '--no-pdf-header-footer', + `--print-to-pdf=${PDF_FILE}`, + HTML_FILE, + ]); + + console.log(`PDF erzeugt: ${PDF_FILE} (${rows.length} BEOs)`); +} + +main().catch((err) => { console.error('Fehler:', err.message); process.exit(1); });