filoor c212ec4987 feat(debug): debug mode tijdsynchronisatie toegevoegd
De commit introduceert een debug tijdsynchronisatie tussen de cron script, de hoofdpagina en de Flask API. Deze functies maken het mogelijk om de huidige tijd te simuleren met een instelbare offset voor testdoeleinden. Het volume en de gebedstijden passen zich nu aan op basis van deze debug tijd indien actief. Debugger gebruikers kunnen via de nieuwe '/api/debug-time' endpoint de tijd aanpassen. De wijzigingen verbeteren de testbaarheid van de applicatie en zorgen ervoor dat gebedsafroepen en volumebepaling correct functioneren onder simulatieomstandigheden.
2025-05-28 18:59:15 +02:00

595 lines
18 KiB
HTML

<!DOCTYPE html>
<html lang="nl">
<head>
<meta charset="UTF-8">
<title>Debug - Gebedstijden Tester</title>
<link rel="stylesheet" href="/static/style.css">
<link href="https://fonts.googleapis.com/css2?family=Cairo:wght@700&family=Lato:wght@400;700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<style>
body {
margin: 0;
padding: 0;
min-height: 100vh;
overflow-x: hidden;
overflow-y: auto;
}
.debug-container {
max-width: 1200px;
margin: 2rem auto;
padding: 2rem;
background: var(--panel-bg);
border-radius: 15px;
border: 1px solid var(--panel-border);
color: var(--text-color);
min-height: calc(100vh - 4rem);
}
.debug-header {
text-align: center;
margin-bottom: 2rem;
}
.debug-header h1 {
color: var(--accent);
font-family: 'Cairo', sans-serif;
font-size: 2.5rem;
margin-bottom: 0.5rem;
}
.debug-header p {
color: var(--text-secondary);
font-size: 1.1rem;
}
.debug-grid {
display: flex;
flex-direction: column;
gap: 2rem;
margin-bottom: 2rem;
}
.debug-panel {
background: var(--card-bg);
padding: 1.5rem;
border-radius: 10px;
border: 1px solid var(--border-color);
color: var(--text-color);
}
.debug-panel h3 {
color: var(--accent);
margin-bottom: 1rem;
font-family: 'Cairo', sans-serif;
font-size: 1.3rem;
}
.time-controls {
display: flex;
flex-direction: column;
gap: 1rem;
}
.time-input {
display: flex;
align-items: center;
gap: 1rem;
}
.time-input label {
color: var(--text-color);
font-weight: 600;
}
.time-input input {
padding: 0.5rem;
border: 1px solid var(--border-color);
border-radius: 5px;
background: var(--input-bg);
color: var(--text-color);
font-size: 1.1rem;
width: 120px;
}
.btn {
padding: 0.7rem 1.5rem;
border: none;
border-radius: 8px;
cursor: pointer;
font-weight: 600;
transition: all 0.3s ease;
margin: 0.2rem;
font-size: 0.9rem;
}
.btn-primary {
background: var(--accent);
color: var(--bg-color);
}
.btn-secondary {
background: var(--text-secondary);
color: var(--bg-color);
}
.btn-danger {
background: #dc3545;
color: white;
}
.btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
opacity: 0.9;
}
.prayer-times-list {
list-style: none;
padding: 0;
margin: 0;
}
.prayer-times-list li {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.7rem;
margin-bottom: 0.5rem;
background: var(--input-bg);
border-radius: 5px;
border: 1px solid var(--border-color);
color: var(--text-color);
}
.prayer-times-list li.active {
background: rgba(234, 179, 8, 0.2);
border-color: var(--accent);
}
.status-display {
background: var(--input-bg);
padding: 1rem;
border-radius: 8px;
margin-bottom: 1rem;
font-family: 'Courier New', monospace;
font-size: 0.9rem;
color: var(--text-color);
border: 1px solid var(--border-color);
}
.quick-actions {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
margin-top: 1rem;
}
.back-link {
display: inline-block;
margin-bottom: 1rem;
color: var(--accent);
text-decoration: none;
font-weight: 600;
}
.back-link:hover {
color: var(--text-color);
}
@media (max-width: 768px) {
.debug-container {
margin: 1rem;
padding: 1rem;
}
.btn {
font-size: 0.8rem;
padding: 0.5rem 1rem;
}
}
</style>
</head>
<body>
<div class="debug-container">
<a href="/" class="back-link">← Terug naar hoofdpagina</a>
<div class="debug-header">
<h1>🔧 Debug Mode</h1>
<p>Test de adhaan functionaliteit door de tijd aan te passen</p>
</div>
<div class="debug-grid">
<div class="debug-panel">
<h3>⏰ Tijd Controles</h3>
<div class="status-display" id="statusDisplay">
Huidige tijd: <span id="currentDebugTime">--:--</span><br>
Volgende gebed: <span id="nextPrayerDebug">--</span><br>
Status: <span id="debugStatus">Normaal</span>
</div>
<div class="time-controls">
<div class="time-input">
<label>Stel tijd in:</label>
<input type="time" id="manualTime" />
<button class="btn btn-primary" onclick="setManualTime()">Zet Tijd</button>
</div>
<div class="quick-actions">
<button class="btn btn-secondary" onclick="adjustTime(-60)">-1 min</button>
<button class="btn btn-secondary" onclick="adjustTime(-10)">-10 sec</button>
<button class="btn btn-secondary" onclick="adjustTime(10)">+10 sec</button>
<button class="btn btn-secondary" onclick="adjustTime(60)">+1 min</button>
</div>
<div class="quick-actions">
<button class="btn btn-primary" onclick="setTimeToNextPrayer(-1)">1 min voor gebed</button>
<button class="btn btn-primary" onclick="setTimeToNextPrayer(0)">Exact gebedstijd</button>
<button class="btn btn-danger" onclick="resetTime()">Reset naar echte tijd</button>
</div>
</div>
</div>
<div class="debug-panel">
<h3>🕌 Gebedstijden Vandaag</h3>
<ul class="prayer-times-list" id="prayerTimesList">
{% for naam, tijd in gebedstijden.items() %}
<li data-prayer="{{ naam }}" data-time="{{ tijd[:5] }}">
<span>{{ naam }}</span>
<span>{{ tijd[:5] }}</span>
<button class="btn btn-secondary" onclick="setTimeToPrayer('{{ tijd[:5] }}', -1)">-1 min</button>
<button class="btn btn-primary" onclick="setTimeToPrayer('{{ tijd[:5] }}', 0)">Nu</button>
</li>
{% endfor %}
</ul>
</div>
</div>
<div class="debug-panel">
<h3>📊 Debug Log</h3>
<div class="status-display" id="debugLog" style="height: 200px; overflow-y: auto;">
Debug log wordt hier weergegeven...<br>
</div>
<button class="btn btn-secondary" onclick="clearLog()">Wis Log</button>
</div>
<div class="debug-panel">
<h3>🔊 Sonos Status</h3>
<div class="status-display" id="sonosStatus" style="height: 150px; overflow-y: auto;">
Sonos status wordt geladen...<br>
</div>
<div class="quick-actions">
<button class="btn btn-primary" onclick="checkSonosStatus()">🔄 Ververs Status</button>
<button class="btn btn-danger" onclick="stopAllSonos()">⏹️ Stop Alle Audio</button>
</div>
</div>
<div class="debug-panel">
<h3>📿 Adzkaar Testing</h3>
<div class="status-display" id="adzkaarStatus" style="height: 100px; overflow-y: auto;">
Status: {% if settings.adzkaar_enabled %}Ingeschakeld{% else %}Uitgeschakeld{% endif %}<br>
Duur: {{ settings.adzkaar_duration or 5 }} minuten<br>
</div>
<div class="quick-actions">
<button class="btn btn-primary" onclick="testAdzkaar()">📿 Test Adzkaar Scherm</button>
<button class="btn btn-secondary" onclick="openAdzkaarDirect()">🔗 Open Adzkaar Direct</button>
</div>
</div>
</div>
<script>
let debugTimeOffset = 0; // Offset in seconden
let isDebugMode = false;
function log(message) {
const logElement = document.getElementById('debugLog');
const timestamp = new Date().toLocaleTimeString();
logElement.innerHTML += `[${timestamp}] ${message}<br>`;
logElement.scrollTop = logElement.scrollHeight;
}
function clearLog() {
document.getElementById('debugLog').innerHTML = 'Debug log gewist...<br>';
}
function getDebugTime() {
const now = new Date();
if (isDebugMode) {
now.setTime(now.getTime() + (debugTimeOffset * 1000));
}
return now;
}
function updateDebugDisplay() {
fetch('/api/debug-time')
.then(response => response.json())
.then(data => {
if (data.success) {
document.getElementById('currentDebugTime').textContent = data.current_time_display;
// Update status
const statusElement = document.getElementById('debugStatus');
statusElement.textContent = data.debug_active ? 'Debug Mode Actief' : 'Normaal';
statusElement.style.color = data.debug_active ? '#ff6b6b' : '#00ff00';
// Check voor gebedstijd
checkPrayerTime(data.current_time_display);
}
})
.catch(error => {
console.log('Fout bij ophalen debug tijd:', error);
// Fallback naar normale tijd
const now = new Date();
const timeStr = now.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
document.getElementById('currentDebugTime').textContent = timeStr;
document.getElementById('debugStatus').textContent = 'Normaal';
});
}
function checkPrayerTime(currentTime) {
const prayerTimes = {{ gebedstijden | tojson }};
let nextPrayer = null;
let isExactTime = false;
for (const [name, time] of Object.entries(prayerTimes)) {
const prayerTime = time.substring(0, 5);
if (prayerTime === currentTime) {
isExactTime = true;
log(`🕌 ADHAAN TIJD! ${name} (${prayerTime})`);
// Trigger adhaan
triggerAdhaan(name);
}
if (prayerTime > currentTime && !nextPrayer) {
nextPrayer = `${name} (${prayerTime})`;
}
}
if (!nextPrayer) {
// Volgende dag
const firstPrayer = Object.entries(prayerTimes)[0];
nextPrayer = `${firstPrayer[0]} (${firstPrayer[1].substring(0, 5)}) - morgen`;
}
document.getElementById('nextPrayerDebug').textContent = nextPrayer;
// Update active prayer in list
document.querySelectorAll('.prayer-times-list li').forEach(li => {
li.classList.remove('active');
if (li.dataset.time === currentTime) {
li.classList.add('active');
}
});
}
function triggerAdhaan(prayerName) {
// Speel adhaan af
const audio = document.getElementById('adhanAudio');
if (audio) {
audio.play().catch(e => log(`Fout bij afspelen audio: ${e.message}`));
}
// Verstuur naar Sonos (als niet gemute)
fetch('/api/debug-adhaan', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ prayer: prayerName, time: getDebugTime().toLocaleTimeString() })
})
.then(response => response.json())
.then(data => {
if (data.success) {
log(`✅ Adhaan verzonden naar Sonos voor ${prayerName}`);
} else {
log(`❌ Fout bij Sonos: ${data.error}`);
}
})
.catch(e => log(`❌ Netwerk fout: ${e.message}`));
}
function setManualTime() {
const timeInput = document.getElementById('manualTime');
if (!timeInput.value) return;
const [hours, minutes] = timeInput.value.split(':');
const now = new Date();
const targetTime = new Date();
targetTime.setHours(parseInt(hours), parseInt(minutes), 0, 0);
const offsetSeconds = Math.floor((targetTime - now) / 1000);
fetch('/api/debug-time', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'set_offset', offset: offsetSeconds })
})
.then(response => response.json())
.then(data => {
if (data.success) {
log(`${data.message}`);
updateDebugDisplay();
} else {
log(`❌ Fout: ${data.error}`);
}
})
.catch(error => log(`❌ Netwerk fout: ${error.message}`));
}
function adjustTime(seconds) {
fetch('/api/debug-time', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'adjust', seconds: seconds })
})
.then(response => response.json())
.then(data => {
if (data.success) {
log(`${data.message}`);
updateDebugDisplay();
} else {
log(`❌ Fout: ${data.error}`);
}
})
.catch(error => log(`❌ Netwerk fout: ${error.message}`));
}
function setTimeToPrayer(prayerTime, offsetMinutes) {
const [hours, minutes] = prayerTime.split(':');
const now = new Date();
const targetTime = new Date();
targetTime.setHours(parseInt(hours), parseInt(minutes), 0, 0);
targetTime.setTime(targetTime.getTime() + (offsetMinutes * 60 * 1000));
const offsetSeconds = Math.floor((targetTime - now) / 1000);
fetch('/api/debug-time', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'set_offset', offset: offsetSeconds })
})
.then(response => response.json())
.then(data => {
if (data.success) {
const offsetText = offsetMinutes === 0 ? 'exact' : `${offsetMinutes} min ervoor`;
log(`🕌 Tijd ingesteld op ${prayerTime} (${offsetText})`);
updateDebugDisplay();
} else {
log(`❌ Fout: ${data.error}`);
}
})
.catch(error => log(`❌ Netwerk fout: ${error.message}`));
}
function setTimeToNextPrayer(offsetMinutes) {
const prayerTimes = {{ gebedstijden | tojson }};
const currentTime = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
for (const [name, time] of Object.entries(prayerTimes)) {
const prayerTime = time.substring(0, 5);
if (prayerTime > currentTime) {
setTimeToPrayer(prayerTime, offsetMinutes);
return;
}
}
// Als geen gebed meer vandaag, neem eerste van morgen
const firstPrayer = Object.entries(prayerTimes)[0];
setTimeToPrayer(firstPrayer[1].substring(0, 5), offsetMinutes);
}
function resetTime() {
fetch('/api/debug-time', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ action: 'reset' })
})
.then(response => response.json())
.then(data => {
if (data.success) {
log(`🔄 ${data.message}`);
updateDebugDisplay();
} else {
log(`❌ Fout: ${data.error}`);
}
})
.catch(error => log(`❌ Netwerk fout: ${error.message}`));
}
function checkSonosStatus() {
log('🔄 Sonos status controleren...');
fetch('/api/sonos-status')
.then(response => response.json())
.then(data => {
const statusElement = document.getElementById('sonosStatus');
if (data.success) {
let statusHtml = `Sonos API: ${data.api_ip}<br><br>`;
for (const [zone, info] of Object.entries(data.zones)) {
const statusColor = info.status === 'online' ? '#00ff00' : '#ff6b6b';
statusHtml += `<span style="color: ${statusColor}">● ${zone}</span><br>`;
statusHtml += ` Status: ${info.status}<br>`;
if (info.status === 'online') {
statusHtml += ` Afspelen: ${info.playbackState}<br>`;
statusHtml += ` Track: ${info.currentTrack}<br>`;
statusHtml += ` Volume: ${info.volume}%<br>`;
} else if (info.error) {
statusHtml += ` Fout: ${info.error}<br>`;
}
statusHtml += '<br>';
}
statusElement.innerHTML = statusHtml;
log('✅ Sonos status bijgewerkt');
} else {
statusElement.innerHTML = `❌ Fout: ${data.error}`;
log(`❌ Sonos status fout: ${data.error}`);
}
})
.catch(error => {
log(`❌ Netwerk fout bij Sonos status: ${error.message}`);
document.getElementById('sonosStatus').innerHTML = `❌ Netwerk fout: ${error.message}`;
});
}
function stopAllSonos() {
log('⏹️ Alle Sonos audio stoppen...');
fetch('/api/sonos-stop', {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
})
.then(response => response.json())
.then(data => {
if (data.success) {
log(`${data.message}`);
// Ververs status na stoppen
setTimeout(checkSonosStatus, 1000);
} else {
log(`❌ Fout bij stoppen: ${data.error}`);
}
})
.catch(error => {
log(`❌ Netwerk fout bij stoppen: ${error.message}`);
});
}
function testAdzkaar() {
log('📿 Adzkaar scherm testen...');
fetch('/api/trigger-adzkaar', {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
})
.then(response => response.json())
.then(data => {
if (data.success) {
log(`${data.message}`);
// Open Adzkaar scherm in nieuw venster/tab
window.open(data.url, '_blank', 'fullscreen=yes,scrollbars=no,resizable=no');
} else {
log(`❌ Adzkaar fout: ${data.error}`);
document.getElementById('adzkaarStatus').innerHTML += `❌ Fout: ${data.error}<br>`;
}
})
.catch(error => {
log(`❌ Netwerk fout bij Adzkaar test: ${error.message}`);
});
}
function openAdzkaarDirect() {
log('🔗 Adzkaar scherm direct openen...');
window.open('/adzkaar', '_blank', 'fullscreen=yes,scrollbars=no,resizable=no');
}
// Update elke seconde
setInterval(updateDebugDisplay, 1000);
// Initiële updates
updateDebugDisplay();
checkSonosStatus();
log('🔧 Debug mode gestart');
</script>
<!-- Hidden audio element for testing -->
<audio id="adhanAudio" src="/static/clips/{{ settings['audio_clip'] }}" preload="auto"></audio>
</body>
</html>