From ea9381f4638f8b5f064226b1f40e99d0f7b9963a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Sun, 12 Apr 2026 11:55:31 +0200 Subject: [PATCH] Jupitersystem GRF verbessert --- config/jupiter_grs.json | 34 +++++++++++++-- public/jupitersystem.php | 90 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 119 insertions(+), 5 deletions(-) diff --git a/config/jupiter_grs.json b/config/jupiter_grs.json index e1c8ff3..a9f2f7a 100644 --- a/config/jupiter_grs.json +++ b/config/jupiter_grs.json @@ -1,6 +1,32 @@ { - "refDate": "2026-04-13T00:31:40.897Z", - "refAngle": 312227.6287687423, - "calibratedAt": "2026-04-12T09:26:52+00:00", - "calibratedBy": "Eskimue" + "refDate": "2026-04-13T04:07:00.000Z", + "refAngle": 312229.88248732366, + "calibratedAt": "2026-04-12T09:35:41+00:00", + "calibratedBy": "Eskimue", + "history": [ + { + "refDate": "2025-04-12T01:08:00.000Z", + "refAngle": 306668.75732167566, + "calibratedAt": "2026-04-12T09:33:58+00:00", + "calibratedBy": "Eskimue" + }, + { + "refDate": "2026-01-01T09:49:00.000Z", + "refAngle": 310684.2913082397, + "calibratedAt": "2026-04-12T09:38:07+00:00", + "calibratedBy": "Eskimue" + }, + { + "refDate": "2026-04-12T08:15:00.000Z", + "refAngle": 312217.3093069398, + "calibratedAt": "2026-04-12T09:32:29+00:00", + "calibratedBy": "Eskimue" + }, + { + "refDate": "2026-04-13T04:07:00.000Z", + "refAngle": 312229.88248732366, + "calibratedAt": "2026-04-12T09:35:41+00:00", + "calibratedBy": "Eskimue" + } + ] } \ No newline at end of file diff --git a/public/jupitersystem.php b/public/jupitersystem.php index 34369e8..9a667b5 100644 --- a/public/jupitersystem.php +++ b/public/jupitersystem.php @@ -24,12 +24,26 @@ if (isset($_GET['grs_api'])) { if (!$isAdmin) { http_response_code(403); echo json_encode(['error' => 'Nicht autorisiert']); exit; } $body = json_decode(file_get_contents('php://input'), true); if (!$body || !isset($body['refDate'], $body['refAngle'])) { http_response_code(400); echo json_encode(['error' => 'Ungültige Daten']); exit; } - $data = [ + $existing = []; + if (file_exists($dataFile)) { + $existing = json_decode(file_get_contents($dataFile), true) ?? []; + } + $history = $existing['history'] ?? []; + $history[] = [ 'refDate' => (string) $body['refDate'], 'refAngle' => (float) $body['refAngle'], 'calibratedAt' => date('c'), 'calibratedBy' => $_SESSION['username'] ?? 'admin', ]; + usort($history, fn($a, $b) => strcmp((string) $a['refDate'], (string) $b['refDate'])); + $latest = end($history); + $data = [ + 'refDate' => $latest['refDate'], + 'refAngle' => $latest['refAngle'], + 'calibratedAt' => $latest['calibratedAt'], + 'calibratedBy' => $latest['calibratedBy'], + 'history' => $history, + ]; $written = file_put_contents($dataFile, json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)); echo $written !== false ? json_encode(['ok' => true]) : json_encode(['error' => 'Schreibfehler – Dateiberechtigung prüfen']); exit; @@ -140,6 +154,15 @@ $bodyClass = 'solarsystem-page jupitersystem-page';
+ + @@ -779,6 +802,60 @@ function parseGrsTransitInput(str) { return isNaN(d.getTime()) ? null : d; } +function renderGrsDrift(history) { + const section = document.getElementById('grsDriftSection'); + const table = document.getElementById('grsDriftTable'); + const avgEl = document.getElementById('grsDriftAvg'); + if (!section || !table || !avgEl || !Array.isArray(history) || history.length < 2) { + if (section) section.style.display = 'none'; + return; + } + + const RAD_TO_DEG = 180 / Math.PI; + + let rows = ''; + const driftRates = []; + + for (let i = 1; i < history.length; i++) { + const prev = history[i - 1]; + const curr = history[i]; + const t1 = new Date(prev.refDate).getTime(); + const t2 = new Date(curr.refDate).getTime(); + const elapsedDays = (t2 - t1) / 86400000; + if (elapsedDays <= 0) continue; + + const expectedDeg = (elapsedDays / GRS_SYSTEM_II_PERIOD_DAYS) * 360; + const actualDeg = (curr.refAngle - prev.refAngle) * RAD_TO_DEG; + // Drift auf den Bereich [-180, 180] normieren + let drift = ((actualDeg - expectedDeg) % 360 + 540) % 360 - 180; + const driftPerDay = drift / elapsedDays; + driftRates.push(driftPerDay); + + const sign = driftPerDay >= 0 ? '+' : ''; + const color = Math.abs(driftPerDay) < 0.05 ? 'var(--text-dim)' : (driftPerDay > 0 ? 'var(--gold-pale)' : 'var(--cyan)'); + const dateStr = new Date(curr.refDate).toLocaleString('de-DE', { timeZone: 'UTC', dateStyle: 'short', timeStyle: 'short' }); + + rows += ` + ${dateStr} UT + ${elapsedDays.toFixed(1)} d + ${sign}${drift.toFixed(2)}° + ${sign}${driftPerDay.toFixed(3)}°/d + `; + } + + table.innerHTML = ` + AbgleichAbstandDrift ges.Drift/Tag + ${rows}`; + + if (driftRates.length > 0) { + const avg = driftRates.reduce((s, v) => s + v, 0) / driftRates.length; + const sign = avg >= 0 ? '+' : ''; + avgEl.textContent = `Ø Drift: ${sign}${avg.toFixed(3)}°/Tag`; + } + + section.style.display = ''; +} + function formatGrsStatus(data) { if (!data.calibratedAt) return 'Noch keine Kalibrierung gespeichert.'; const at = new Date(data.calibratedAt).toLocaleString('de-DE', { timeZone: 'UTC', dateStyle: 'short', timeStyle: 'short' }); @@ -797,6 +874,7 @@ async function loadGrsCalibration() { } const statusEl = document.getElementById('grsCalibStatus'); if (statusEl) statusEl.textContent = formatGrsStatus(data); + renderGrsDrift(data.history); } catch (e) {} } @@ -948,6 +1026,12 @@ function attachAdminHandlers() { grsBtnRot5R.addEventListener('click', () => shiftGrsRotation(5)); grsBtnSave.addEventListener('click', async () => { + if (grsTransitInput.value.trim() === '') { + grsParseError.textContent = 'Bitte zuerst einen GRS-Transitzeitpunkt eingeben und auf „Auf diese Zeit setzen" klicken.'; + grsParseError.classList.remove('is-hidden'); + return; + } + const elapsedDays = (simDate - grsRefDate) / 86400000; grsRefAngle = grsRefAngle + (elapsedDays / GRS_SYSTEM_II_PERIOD_DAYS) * Math.PI * 2; grsRefDate = new Date(simDate); @@ -956,6 +1040,10 @@ function attachAdminHandlers() { grsCalibStatus.textContent = ok === true ? `Gespeichert: ${simDate.toISOString().slice(0, 16).replace('T', ' ')} UT\nFür alle Nutzer aktiv.` : `Fehler: ${ok}`; + if (ok === true) { + const res = await fetch('jupitersystem.php?grs_api').catch(() => null); + if (res && res.ok) { const d = await res.json(); renderGrsDrift(d.history); } + } }); }