filoor 21a79147b2 feat(parallel-fetch): voeg parallelle API-oproepen toe voor verbeterde prestaties
Introduceer een ThreadPoolExecutor om gelijktijdige API-oproepen mogelijk te maken. Deze wijziging verbetert de efficiëntie door weersinformatie, Sonos-zones en datumgegevens parallel op te halen. In de instellingenroute is logica toegevoegd om data parallel te laden, wat resulteert in snellere paginaprocessen. Daarnaast zijn er optimalisaties aan de UI gedaan om FOUC te voorkomen door het toepassen van een visibiliteitsstijl totdat de pagina volledig is geladen.
2025-05-29 21:29:25 +02:00

848 lines
32 KiB
Python

from flask import Flask, render_template, request, redirect, send_from_directory, jsonify, request as flask_request
import requests, json, os, random, subprocess
from datetime import datetime, timedelta
from config import *
from hijridate import Gregorian
from functools import lru_cache
import time
from concurrent.futures import ThreadPoolExecutor
app = Flask(__name__)
# Cache configuratie
CACHE_DURATION = 300 # 5 minuten cache voor API calls
last_api_call = {}
cached_data = {}
executor = ThreadPoolExecutor(max_workers=3) # Voor parallelle API calls
def get_cached_data(key, fetch_func, duration=CACHE_DURATION):
"""Haal data uit cache of voer fetch_func uit als cache verlopen is"""
current_time = time.time()
if key in cached_data and key in last_api_call:
if current_time - last_api_call[key] < duration:
return cached_data[key]
data = fetch_func()
cached_data[key] = data
last_api_call[key] = current_time
return data
def fetch_data_parallel():
"""Haal alle data parallel op"""
futures = {
'weather': executor.submit(fetch_weather_data),
'sonos': executor.submit(fetch_sonos_zones),
'date': executor.submit(get_date_info)
}
return {key: future.result() for key, future in futures.items()}
# Voeg cache-control headers toe voor statische bestanden
@app.after_request
def add_header(response):
if 'Cache-Control' not in response.headers:
response.headers['Cache-Control'] = 'no-store, no-cache, must-revalidate, max-age=0'
return response
# Specifieke route voor statische bestanden met cache-control
@app.route('/static/<path:filename>')
def serve_static(filename):
return send_from_directory('static', filename, cache_timeout=0)
SETTINGS_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'settings.json')
HADITHS_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static', 'hadiths.json')
VUMG_API = 'https://www.vumg.nl/?rest_route=/dpt/v1/prayertime&filter=today'
CLIPS_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static', 'clips')
# SONOS_API_IP wordt nu geïmporteerd uit config.py
# Globale variabelen
debug_time_offset = 0 # Offset in seconden voor debug mode
debug_mode_active = False
@lru_cache(maxsize=1)
def load_settings():
try:
if os.path.exists(SETTINGS_PATH) and os.path.getsize(SETTINGS_PATH) > 0:
with open(SETTINGS_PATH) as f:
return json.load(f)
except Exception as e:
print(f"⚠️ Fout bij laden van settings: {e}")
return {"volume": 30, "zones": ["Woonkamer"], "audio_clip": "adhan1.mp3"}
def fetch_weather_data():
"""Haalt weersinformatie op voor de geconfigureerde locatie"""
return get_cached_data('weather', lambda: _fetch_weather_data_impl())
def _fetch_weather_data_impl():
try:
params = {
'q': WEATHER_LOCATION,
'appid': OPENWEATHER_API_KEY,
'units': 'metric',
'lang': 'nl'
}
response = requests.get('https://api.openweathermap.org/data/2.5/weather', params=params, timeout=5)
response.raise_for_status()
data = response.json()
weather_info = {
'temperature': round(data['main']['temp']),
'feels_like': round(data['main']['feels_like']),
'description': data['weather'][0]['description'].capitalize(),
'humidity': data['main']['humidity'],
'wind_speed': round(data['wind']['speed'] * 3.6), # m/s naar km/h
'icon': data['weather'][0]['icon']
}
return weather_info
except Exception as e:
print(f"⚠️ Fout bij ophalen weerdata: {e}")
return {
'temperature': '--',
'feels_like': '--',
'description': 'Weer niet beschikbaar',
'humidity': '--',
'wind_speed': '--',
'icon': '01d'
}
def load_hadith():
try:
with open(HADITHS_PATH) as f:
hadiths = json.load(f)['hadiths']
return random.choice(hadiths)
except Exception as e:
print(f"⚠️ Fout bij laden van hadith: {e}")
return {"text": "De daden die Allah het meest liefheeft zijn degenen die regelmatig worden verricht, zelfs als ze klein zijn.", "bron": "Sahih al-Bukhari"}
def get_current_volume(settings):
"""Bepaal het juiste volume op basis van de huidige tijd"""
from datetime import datetime, timedelta
# Fallback naar oude volume als nieuwe instellingen niet bestaan
if 'volume_day' not in settings or 'volume_night' not in settings:
return settings.get('volume', 30)
# Gebruik debug tijd als actief
global debug_mode_active, debug_time_offset
if debug_mode_active:
current_time = (datetime.now() + timedelta(seconds=debug_time_offset)).strftime('%H:%M')
print(f"🔧 Volume bepaling gebruikt debug tijd: {current_time}")
else:
current_time = datetime.now().strftime('%H:%M')
night_start = settings.get('night_start', '20:00')
day_start = settings.get('day_start', '07:00')
# Converteer tijden naar vergelijkbare format
current_minutes = int(current_time[:2]) * 60 + int(current_time[3:5])
night_minutes = int(night_start[:2]) * 60 + int(night_start[3:5])
day_minutes = int(day_start[:2]) * 60 + int(day_start[3:5])
# Bepaal of het avond is
if night_minutes > day_minutes: # Normale dag/nacht cyclus (bijv. dag 07:00-20:00)
is_night = current_minutes >= night_minutes or current_minutes < day_minutes
else: # Avond gaat over middernacht (bijv. avond 20:00-07:00)
is_night = current_minutes >= night_minutes and current_minutes < day_minutes
if is_night:
volume = settings.get('volume_night', settings.get('volume', 30) // 2)
print(f"🌙 Avond volume gebruikt: {volume} (tijd: {current_time})")
return volume
else:
volume = settings.get('volume_day', settings.get('volume', 30))
print(f"☀️ Dag volume gebruikt: {volume} (tijd: {current_time})")
return volume
def apply_prayer_offsets(gebedstijden, settings):
"""Pas offsets toe op gebedstijden"""
from datetime import datetime, timedelta
offsets = {
'Fajr': settings.get('fajr_offset', 0),
'Zuhr': settings.get('zuhr_offset', 0),
'Asr': settings.get('asr_offset', 0),
'Maghrib': settings.get('maghrib_offset', 0),
'Isha': settings.get('isha_offset', 0)
}
adjusted_times = {}
for prayer, original_time in gebedstijden.items():
offset_minutes = offsets.get(prayer, 0)
if offset_minutes == 0:
adjusted_times[prayer] = original_time
continue
try:
# Parse de originele tijd
time_obj = datetime.strptime(original_time, '%H:%M')
# Voeg offset toe
adjusted_time = time_obj + timedelta(minutes=offset_minutes)
# Converteer terug naar string
adjusted_times[prayer] = adjusted_time.strftime('%H:%M')
if offset_minutes != 0:
print(f"📅 {prayer}: {original_time}{adjusted_times[prayer]} ({offset_minutes:+d} min)")
except Exception as e:
print(f"⚠️ Fout bij aanpassen {prayer} tijd: {e}")
adjusted_times[prayer] = original_time
return adjusted_times
@lru_cache(maxsize=1)
def fetch_sonos_zones():
return get_cached_data('sonos_zones', lambda: _fetch_sonos_zones_impl())
def _fetch_sonos_zones_impl():
try:
res = requests.get(f'http://{SONOS_API_IP}:5005/zones', timeout=5)
res.raise_for_status()
data = res.json()
zones = []
for group in data:
for player in group['members']:
zones.append(player['roomName'])
return sorted(set(zones))
except Exception as e:
print(f'Fout bij ophalen Sonos-zones: {e}')
return ['Woonkamer', 'Slaapkamer', 'Keuken']
def get_date_info():
"""Genereert zowel Gregoriaanse als Hijri datum informatie"""
now = datetime.now()
# Gregoriaanse datum
gregorian_date = now.strftime('%A %d %B %Y')
gregorian_short = now.strftime('%d-%m-%Y')
# Nederlandse maandnamen
dutch_months = {
'January': 'januari', 'February': 'februari', 'March': 'maart',
'April': 'april', 'May': 'mei', 'June': 'juni',
'July': 'juli', 'August': 'augustus', 'September': 'september',
'October': 'oktober', 'November': 'november', 'December': 'december'
}
# Nederlandse dagnamen
dutch_days = {
'Monday': 'maandag', 'Tuesday': 'dinsdag', 'Wednesday': 'woensdag',
'Thursday': 'donderdag', 'Friday': 'vrijdag', 'Saturday': 'zaterdag', 'Sunday': 'zondag'
}
# Vervang Engelse namen door Nederlandse
for eng, nl in dutch_months.items():
gregorian_date = gregorian_date.replace(eng, nl)
for eng, nl in dutch_days.items():
gregorian_date = gregorian_date.replace(eng, nl)
try:
# Converteer naar Hijri datum
hijri_date = Gregorian(now.year, now.month, now.day).to_hijri()
# Arabische maandnamen
hijri_months = [
'محرم', 'صفر', 'ربيع الأول', 'ربيع الثاني', 'جمادى الأولى', 'جمادى الثانية',
'رجب', 'شعبان', 'رمضان', 'شوال', 'ذو القعدة', 'ذو الحجة'
]
# Nederlandse maandnamen voor Hijri
hijri_months_nl = [
'Muharram', 'Safar', 'Rabi al-Awwal', 'Rabi al-Thani', 'Jumada al-Awwal', 'Jumada al-Thani',
'Rajab', 'Sha\'ban', 'Ramadan', 'Shawwal', 'Dhu al-Qi\'dah', 'Dhu al-Hijjah'
]
hijri_arabic = f"{hijri_date.day} {hijri_months[hijri_date.month - 1]} {hijri_date.year} هـ"
hijri_dutch = f"{hijri_date.day} {hijri_months_nl[hijri_date.month - 1]} {hijri_date.year} AH"
except Exception as e:
print(f"⚠️ Fout bij Hijri conversie: {e}")
hijri_arabic = "التاريخ الهجري غير متاح"
hijri_dutch = "Hijri datum niet beschikbaar"
return {
'gregorian_full': gregorian_date,
'gregorian_short': gregorian_short,
'hijri_arabic': hijri_arabic,
'hijri_dutch': hijri_dutch,
'current_time': now.strftime('%H:%M')
}
@app.route('/')
def index():
settings = load_settings()
next_time = "Onbekend"
next_name = "Onbekend"
debug_data = {}
gebedstijden = {}
hadith = load_hadith()
weather = fetch_weather_data()
date_info = get_date_info()
try:
res = requests.get(VUMG_API)
res.raise_for_status()
data = res.json()[0]
gebedstijden = {
"Fajr": data.get("fajr_jamah", "00:00")[:5], # Haal seconden weg
"Zuhr": data.get("zuhr_jamah", "00:00")[:5], # Haal seconden weg
"Asr": data.get("asr_jamah", "00:00")[:5], # Haal seconden weg
"Maghrib": data.get("maghrib_jamah", "00:00")[:5], # Haal seconden weg
"Isha": data.get("isha_jamah", "00:00")[:5] # Haal seconden weg
}
# Pas offsets toe op gebedstijden
gebedstijden = apply_prayer_offsets(gebedstijden, settings)
now = datetime.now().strftime('%H:%M')
for naam, tijd in gebedstijden.items():
if tijd > now:
next_time = tijd
next_name = naam
break
else:
next_time = list(gebedstijden.values())[0]
next_name = list(gebedstijden.keys())[0]
debug_data = {
"api_response": data,
"gebedstijden": gebedstijden,
"now": now,
"next_time": next_time,
"next_name": next_name
}
except Exception as e:
print("❌ Fout bij ophalen/verwerken van gebedstijden:", e)
dua = "اللّهُمَّ اجْعَلْ صَلاتِي نُورًا"
return render_template('index.html',
next_time=next_time,
next_name=next_name,
dua=dua,
hadith=hadith,
gebedstijden=gebedstijden,
debug=debug_data,
settings=settings,
weather=weather,
date_info=date_info)
@app.route('/instellingen', methods=['GET', 'POST'])
def instellingen():
if request.method == 'POST':
try:
# Nieuwe volume instellingen
if 'volume_day' in request.form and 'volume_night' in request.form:
settings = load_settings()
settings['volume_day'] = int(request.form['volume_day'])
settings['volume_night'] = int(request.form['volume_night'])
settings['night_start'] = request.form['night_start']
settings['day_start'] = request.form['day_start']
# Update oude volume voor backward compatibility
settings['volume'] = settings['volume_day']
else:
# Fallback: gebruik default waarden als velden ontbreken
settings = load_settings()
settings['volume_day'] = settings.get('volume_day', 15)
settings['volume_night'] = settings.get('volume_night', 8)
settings['night_start'] = settings.get('night_start', '20:00')
settings['day_start'] = settings.get('day_start', '07:00')
settings['volume'] = settings['volume_day']
# Gebedstijd offsets
settings['fajr_offset'] = int(request.form.get('fajr_offset', 0))
settings['zuhr_offset'] = int(request.form.get('zuhr_offset', 0))
settings['asr_offset'] = int(request.form.get('asr_offset', 0))
settings['maghrib_offset'] = int(request.form.get('maghrib_offset', 0))
settings['isha_offset'] = int(request.form.get('isha_offset', 0))
# Adzkaar instellingen
settings['adzkaar_enabled'] = 'adzkaar_enabled' in request.form
settings['adzkaar_duration'] = int(request.form.get('adzkaar_duration', 5))
# Hadith instellingen
settings['hadith_interval_seconds'] = int(request.form.get('hadith_interval_seconds', 30))
# Pi HDMI volume instelling
if 'pi_hdmi_volume' in request.form:
pi_volume = int(request.form.get('pi_hdmi_volume', 70))
settings['pi_hdmi_volume'] = pi_volume
# Probeer Pi volume in te stellen via amixer (alleen als we niet in Docker draaien)
try:
# Check of we in een Docker container draaien
if os.path.exists('/.dockerenv'):
print(f"🔊 Pi HDMI volume opgeslagen: {pi_volume}% (Docker container - amixer niet beschikbaar)")
else:
subprocess.run(['amixer', 'set', 'PCM', f'{pi_volume}%'],
check=True, capture_output=True, text=True)
print(f"🔊 Pi HDMI volume ingesteld op {pi_volume}%")
except (subprocess.CalledProcessError, FileNotFoundError) as e:
print(f"⚠️ Kon Pi volume niet direct instellen: {e} (volume wel opgeslagen)")
except Exception as e:
print(f"❌ Onverwachte fout bij volume instelling: {e}")
settings['zones'] = request.form.getlist('zones')
settings['audio_clip'] = request.form['audio_clip']
with open(SETTINGS_PATH, 'w') as f:
json.dump(settings, f, indent=2)
if 'test_clip' in request.form:
# Gebruik het juiste volume voor de test
test_volume = get_current_volume(settings)
for zone in settings['zones']:
url = f"http://{SONOS_API_IP}:5005/{zone}/clip/{settings['audio_clip']}/{test_volume}"
try:
r = requests.get(url, timeout=3)
print(f"🎵 Test clip verzonden naar {zone}, status: {r.status_code}")
except Exception as e:
print(f"❌ Fout bij afspelen op zone {zone}: {e}")
return redirect('/instellingen')
except Exception as e:
print(f"❌ Fout bij opslaan instellingen: {e}")
# Probeer alsnog door te gaan zonder de Pi volume instelling
return redirect('/instellingen')
# Haal alle data parallel op
data = fetch_data_parallel()
return render_template('settings.html',
settings=load_settings(),
alle_zones=data['sonos'],
date_info=data['date'],
weather=data['weather'])
@app.route('/api/hadith')
def api_hadith():
hadith = load_hadith()
return jsonify(hadith)
@app.route('/api/mute', methods=['POST'])
def toggle_mute():
try:
data = flask_request.get_json()
mute = data.get('mute', False)
with open(SETTINGS_PATH, 'r+') as f:
settings = json.load(f)
settings['mute'] = mute
f.seek(0)
json.dump(settings, f, indent=2)
f.truncate()
return jsonify({'success': True, 'mute': mute})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/weather')
def api_weather():
"""API endpoint voor het ophalen van actuele weerdata"""
weather = fetch_weather_data()
return jsonify(weather)
@app.route('/api/date-info')
def api_date_info():
"""API endpoint voor het ophalen van actuele datum informatie"""
date_info = get_date_info()
return jsonify(date_info)
@app.route('/api/test-audio', methods=['POST'])
def test_audio():
"""Test een audio bestand lokaal in de browser"""
try:
data = flask_request.get_json()
audio_file = data.get('audio_file', 'adhan1.mp3')
# Controleer of het bestand bestaat
audio_path = os.path.join(CLIPS_PATH, audio_file)
if not os.path.exists(audio_path):
return jsonify({'success': False, 'error': 'Audio bestand niet gevonden'}), 404
return jsonify({
'success': True,
'message': f'Audio bestand {audio_file} is beschikbaar',
'url': f'/static/clips/{audio_file}'
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/debug')
def debug():
"""Debug pagina voor het testen van adhaan functionaliteit"""
settings = load_settings()
# Check of debug mode is ingeschakeld
if not settings.get('debug_mode', False):
return redirect('/')
gebedstijden = {}
try:
res = requests.get(VUMG_API)
res.raise_for_status()
data = res.json()[0]
gebedstijden = {
"Fajr": data.get("fajr_jamah", "00:00")[:5], # Haal seconden weg
"Zuhr": data.get("zuhr_jamah", "00:00")[:5], # Haal seconden weg
"Asr": data.get("asr_jamah", "00:00")[:5], # Haal seconden weg
"Maghrib": data.get("maghrib_jamah", "00:00")[:5], # Haal seconden weg
"Isha": data.get("isha_jamah", "00:00")[:5] # Haal seconden weg
}
# Pas offsets toe op gebedstijden
gebedstijden = apply_prayer_offsets(gebedstijden, settings)
except Exception as e:
print("❌ Fout bij ophalen gebedstijden voor debug:", e)
# Fallback tijden voor testing
gebedstijden = {
"Fajr": "06:00",
"Zuhr": "12:30",
"Asr": "15:00",
"Maghrib": "17:30",
"Isha": "19:00"
}
# Pas ook offsets toe op fallback tijden
gebedstijden = apply_prayer_offsets(gebedstijden, settings)
return render_template('debug.html',
gebedstijden=gebedstijden,
settings=settings)
@app.route('/api/debug-adhaan', methods=['POST'])
def debug_adhaan():
"""API endpoint voor debug adhaan testing"""
import time
# Check of debug mode is ingeschakeld
settings = load_settings()
if not settings.get('debug_mode', False):
return jsonify({'success': False, 'error': 'Debug mode is niet ingeschakeld'}), 403
try:
data = flask_request.get_json()
prayer_name = data.get('prayer', 'Test')
test_time = data.get('time', 'Onbekend')
# Check mute status
if settings.get('mute', False):
return jsonify({
'success': False,
'error': 'Adhaan niet afgespeeld: mute staat aan',
'muted': True
})
# Verbeterde Sonos afspeling
success_count = 0
error_messages = []
zones = settings.get('zones', ['Woonkamer'])
audio_clip = settings.get('audio_clip', 'adhan1.mp3')
volume = get_current_volume(settings)
for zone in zones:
try:
# Stop eerst alle audio op deze zone
stop_url = f"http://{SONOS_API_IP}:5005/{zone}/pause"
requests.get(stop_url, timeout=2)
time.sleep(0.5) # Korte pauze
# Speel de clip af
clip_url = f"http://{SONOS_API_IP}:5005/{zone}/clip/{audio_clip}/{volume}"
response = requests.get(clip_url, timeout=10)
if response.status_code == 200:
success_count += 1
print(f"🔧 DEBUG: Adhaan afgespeeld op {zone} voor {prayer_name} om {test_time}")
else:
error_messages.append(f"{zone}: HTTP {response.status_code}")
except requests.exceptions.Timeout:
error_messages.append(f"{zone}: Timeout")
except Exception as e:
error_messages.append(f"{zone}: {str(e)}")
# Pauze tussen zones
if len(zones) > 1:
time.sleep(1)
if success_count > 0:
return jsonify({
'success': True,
'message': f'Adhaan afgespeeld op {success_count}/{len(zones)} zone(s)',
'errors': error_messages if error_messages else None
})
else:
return jsonify({
'success': False,
'error': f'Geen zones bereikbaar: {", ".join(error_messages)}'
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/sonos-status')
def sonos_status():
"""API endpoint voor Sonos status controle"""
try:
settings = load_settings()
zones = settings.get('zones', ['Woonkamer'])
status_info = {}
for zone in zones:
try:
# Haal zone status op
status_url = f"http://{SONOS_API_IP}:5005/{zone}/state"
response = requests.get(status_url, timeout=3)
if response.status_code == 200:
zone_data = response.json()
status_info[zone] = {
'status': 'online',
'playbackState': zone_data.get('playbackState', 'unknown'),
'currentTrack': zone_data.get('currentTrack', {}).get('title', 'Geen track'),
'volume': zone_data.get('volume', 0)
}
else:
status_info[zone] = {'status': 'error', 'error': f'HTTP {response.status_code}'}
except Exception as e:
status_info[zone] = {'status': 'offline', 'error': str(e)}
return jsonify({
'success': True,
'zones': status_info,
'api_ip': SONOS_API_IP
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/sonos-stop', methods=['POST'])
def sonos_stop():
"""API endpoint om alle Sonos zones te stoppen"""
try:
settings = load_settings()
zones = settings.get('zones', ['Woonkamer'])
stopped_zones = []
for zone in zones:
try:
stop_url = f"http://{SONOS_API_IP}:5005/{zone}/pause"
response = requests.get(stop_url, timeout=3)
if response.status_code == 200:
stopped_zones.append(zone)
except Exception as e:
print(f"Fout bij stoppen {zone}: {e}")
return jsonify({
'success': True,
'message': f'Audio gestopt op {len(stopped_zones)} zone(s)',
'stopped_zones': stopped_zones
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/quran')
def quran():
"""Quran speler pagina"""
settings = load_settings()
gebedstijden = {}
try:
res = requests.get(VUMG_API)
res.raise_for_status()
data = res.json()[0]
gebedstijden = {
"Fajr": data.get("fajr_jamah", "00:00")[:5], # Haal seconden weg
"Zuhr": data.get("zuhr_jamah", "00:00")[:5], # Haal seconden weg
"Asr": data.get("asr_jamah", "00:00")[:5], # Haal seconden weg
"Maghrib": data.get("maghrib_jamah", "00:00")[:5], # Haal seconden weg
"Isha": data.get("isha_jamah", "00:00")[:5] # Haal seconden weg
}
# Pas offsets toe op gebedstijden
gebedstijden = apply_prayer_offsets(gebedstijden, settings)
except Exception as e:
print("❌ Fout bij ophalen gebedstijden voor quran pagina:", e)
# Fallback tijden
gebedstijden = {
"Fajr": "06:00",
"Zuhr": "12:30",
"Asr": "15:00",
"Maghrib": "17:30",
"Isha": "19:00"
}
# Pas ook offsets toe op fallback tijden
gebedstijden = apply_prayer_offsets(gebedstijden, settings)
return render_template('quran.html',
gebedstijden=gebedstijden,
settings=settings)
@app.route('/adzkaar')
def adzkaar():
"""Adzkaar pagina na gebed"""
settings = load_settings()
duration_minutes = settings.get('adzkaar_duration', 5) # Default 5 minuten
return render_template('adzkaar.html',
duration_minutes=duration_minutes,
settings=settings)
@app.route('/api/trigger-adzkaar', methods=['POST'])
def trigger_adzkaar():
"""API endpoint om Adzkaar scherm te triggeren (voor debug)"""
try:
settings = load_settings()
# Check of Adzkaar is ingeschakeld
if not settings.get('adzkaar_enabled', True):
return jsonify({
'success': False,
'error': 'Adzkaar is uitgeschakeld in instellingen'
})
duration = settings.get('adzkaar_duration', 5)
return jsonify({
'success': True,
'message': f'Adzkaar scherm wordt getoond voor {duration} minuten',
'duration': duration,
'url': '/adzkaar'
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/debug-time', methods=['GET', 'POST'])
def debug_time():
"""API endpoint voor debug tijd beheer"""
global debug_time_offset, debug_mode_active
if flask_request.method == 'POST':
# Check of debug mode is ingeschakeld voor POST requests
settings = load_settings()
if not settings.get('debug_mode', False):
return jsonify({'success': False, 'error': 'Debug mode is niet ingeschakeld'}), 403
try:
data = flask_request.get_json()
action = data.get('action')
if action == 'set_offset':
debug_time_offset = data.get('offset', 0)
debug_mode_active = True
return jsonify({
'success': True,
'message': f'Debug tijd offset ingesteld op {debug_time_offset} seconden',
'offset': debug_time_offset,
'debug_active': debug_mode_active
})
elif action == 'reset':
debug_time_offset = 0
debug_mode_active = False
return jsonify({
'success': True,
'message': 'Debug tijd gereset naar echte tijd',
'offset': debug_time_offset,
'debug_active': debug_mode_active
})
elif action == 'adjust':
adjustment = data.get('seconds', 0)
debug_time_offset += adjustment
debug_mode_active = True
return jsonify({
'success': True,
'message': f'Debug tijd aangepast met {adjustment} seconden',
'offset': debug_time_offset,
'debug_active': debug_mode_active
})
else:
return jsonify({'success': False, 'error': 'Onbekende actie'}), 400
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
else: # GET request - altijd beschikbaar voor cron script
from datetime import datetime, timedelta
current_time = datetime.now()
if debug_mode_active:
current_time += timedelta(seconds=debug_time_offset)
return jsonify({
'success': True,
'current_time': current_time.strftime('%H:%M:%S'),
'current_time_display': current_time.strftime('%H:%M'),
'offset': debug_time_offset,
'debug_active': debug_mode_active,
'real_time': datetime.now().strftime('%H:%M:%S')
})
@app.route('/api/set-pi-volume', methods=['POST'])
def set_pi_volume():
"""API endpoint om Pi HDMI volume in te stellen"""
try:
data = flask_request.get_json()
volume = data.get('volume', 70)
# Valideer volume (0-100)
if not isinstance(volume, int) or volume < 0 or volume > 100:
return jsonify({'success': False, 'error': 'Volume moet tussen 0 en 100 zijn'}), 400
# Sla volume op in settings voor persistentie
settings = load_settings()
settings['pi_hdmi_volume'] = volume
with open(SETTINGS_PATH, 'w') as f:
json.dump(settings, f, indent=2)
# Check of we in een Docker container draaien
if os.path.exists('/.dockerenv'):
print(f"🔊 Pi HDMI volume opgeslagen: {volume}% (Docker container)")
return jsonify({
'success': True,
'message': f'Pi HDMI volume opgeslagen op {volume}%. Volume wordt toegepast bij browser herstart.',
'volume': volume,
'info': 'Docker container - volume opgeslagen voor browser audio'
})
else:
# Direct op Pi - probeer amixer
try:
subprocess.run(['amixer', 'set', 'PCM', f'{volume}%'],
check=True, capture_output=True, text=True)
print(f"🔊 Pi HDMI volume direct ingesteld op {volume}%")
return jsonify({
'success': True,
'message': f'Pi HDMI volume ingesteld op {volume}%',
'volume': volume
})
except (subprocess.CalledProcessError, FileNotFoundError) as e:
print(f"⚠️ Amixer fout: {e}")
return jsonify({
'success': True,
'message': f'Volume opgeslagen op {volume}%. Amixer niet beschikbaar.',
'volume': volume,
'warning': str(e)
})
except Exception as e:
print(f"❌ Volume API fout: {e}")
return jsonify({'success': False, 'error': str(e)}), 500
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80)