feat: add timeturner for time offsets and migrate config to YAML

Co-authored-by: aider (gemini/gemini-2.5-pro-preview-05-06) <aider@aider.chat>
This commit is contained in:
Chaos Rogers 2025-07-21 19:16:06 +01:00
parent 08577f5064
commit 777a202877
9 changed files with 245 additions and 160 deletions

View file

@ -48,9 +48,16 @@
<div class="control-group">
<label for="hw-offset">Hardware Offset (ms):</label>
<input type="number" id="hw-offset" name="hw-offset">
<button id="save-offset">Save</button>
</div>
<div class="control-group">
<label>Timeturner Offset:</label>
<input type="number" id="offset-h" placeholder="H">
<input type="number" id="offset-m" placeholder="M">
<input type="number" id="offset-s" placeholder="S">
<input type="number" id="offset-f" placeholder="F">
</div>
<div class="control-group">
<button id="save-config">Save Config</button>
<button id="manual-sync">Manual Sync</button>
<span id="sync-message"></span>
</div>

View file

@ -14,7 +14,13 @@ document.addEventListener('DOMContentLoaded', () => {
};
const hwOffsetInput = document.getElementById('hw-offset');
const saveOffsetButton = document.getElementById('save-offset');
const offsetInputs = {
h: document.getElementById('offset-h'),
m: document.getElementById('offset-m'),
s: document.getElementById('offset-s'),
f: document.getElementById('offset-f'),
};
const saveConfigButton = document.getElementById('save-config');
const manualSyncButton = document.getElementById('manual-sync');
const syncMessage = document.getElementById('sync-message');
@ -67,24 +73,32 @@ document.addEventListener('DOMContentLoaded', () => {
const response = await fetch('/api/config');
if (!response.ok) throw new Error('Failed to fetch config');
const data = await response.json();
hwOffsetInput.value = data.hardware_offset_ms;
hwOffsetInput.value = data.hardwareOffsetMs;
offsetInputs.h.value = data.timeturnerOffset.hours;
offsetInputs.m.value = data.timeturnerOffset.minutes;
offsetInputs.s.value = data.timeturnerOffset.seconds;
offsetInputs.f.value = data.timeturnerOffset.frames;
} catch (error) {
console.error('Error fetching config:', error);
}
}
async function saveConfig() {
const offset = parseInt(hwOffsetInput.value, 10);
if (isNaN(offset)) {
alert('Invalid hardware offset value.');
return;
}
const config = {
hardwareOffsetMs: parseInt(hwOffsetInput.value, 10) || 0,
timeturnerOffset: {
hours: parseInt(offsetInputs.h.value, 10) || 0,
minutes: parseInt(offsetInputs.m.value, 10) || 0,
seconds: parseInt(offsetInputs.s.value, 10) || 0,
frames: parseInt(offsetInputs.f.value, 10) || 0,
}
};
try {
const response = await fetch('/api/config', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ hardware_offset_ms: offset }),
body: JSON.stringify(config),
});
if (!response.ok) throw new Error('Failed to save config');
alert('Configuration saved.');
@ -111,7 +125,7 @@ document.addEventListener('DOMContentLoaded', () => {
setTimeout(() => { syncMessage.textContent = ''; }, 5000);
}
saveOffsetButton.addEventListener('click', saveConfig);
saveConfigButton.addEventListener('click', saveConfig);
manualSyncButton.addEventListener('click', triggerManualSync);
// Initial data load

View file

@ -85,6 +85,7 @@ button:hover {
/* Status-specific colors */
#sync-status.in-sync, #jitter-status.good { font-weight: bold; color: #28a745; }
#sync-status.clock-ahead, #sync-status.clock-behind, #jitter-status.average { font-weight: bold; color: #ffc107; }
#sync-status.timeturning { font-weight: bold; color: #17a2b8; }
#jitter-status.bad { font-weight: bold; color: #dc3545; }
#ntp-active.active { font-weight: bold; color: #28a745; }
#ntp-active.inactive { font-weight: bold; color: #dc3545; }