diff --git a/adhan-webapp/app.py b/adhan-webapp/app.py index 9ba346e..8d4f1bd 100644 --- a/adhan-webapp/app.py +++ b/adhan-webapp/app.py @@ -1,11 +1,99 @@ 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 +from datetime import datetime, timedelta from config import * from hijridate import Gregorian +from functools import lru_cache +import time +from concurrent.futures import ThreadPoolExecutor, as_completed app = Flask(__name__) +# Cache configuratie +CACHE_DURATION = 300 # 5 minuten cache voor API calls +last_api_call = {} +cached_data = {} +executor = ThreadPoolExecutor(max_workers=5) # Verhoogd naar 5 workers voor betere parallelle uitvoering + +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 met verbeterde error handling""" + futures = { + 'weather': executor.submit(fetch_weather_data), + 'sonos': executor.submit(fetch_sonos_zones), + 'date': executor.submit(get_date_info), + 'hadith': executor.submit(load_hadith), + 'prayer_times': executor.submit(fetch_prayer_times) + } + + results = {} + for key, future in futures.items(): + try: + results[key] = future.result(timeout=5) # Timeout van 5 seconden per request + except Exception as e: + print(f"⚠️ Fout bij ophalen {key} data: {e}") + results[key] = get_fallback_data(key) + + return results + +def get_fallback_data(key): + """Geef fallback data terug als API calls falen""" + fallbacks = { + 'weather': { + 'temperature': '--', + 'feels_like': '--', + 'description': 'Weer niet beschikbaar', + 'humidity': '--', + 'wind_speed': '--', + 'icon': '01d' + }, + 'sonos': ['Woonkamer'], + 'date': get_date_info(), # Gebruik lokale functie als fallback + 'hadith': { + "text": "De daden die Allah het meest liefheeft zijn degenen die regelmatig worden verricht, zelfs als ze klein zijn.", + "bron": "Sahih al-Bukhari" + }, + 'prayer_times': { + "Fajr": "06:00", + "Zuhr": "12:30", + "Asr": "15:00", + "Maghrib": "17:30", + "Isha": "19:00" + } + } + return fallbacks.get(key, {}) + +@lru_cache(maxsize=1) +def fetch_prayer_times(): + """Haal gebedstijden op met caching""" + try: + res = requests.get(VUMG_API, timeout=5) + res.raise_for_status() + data = res.json()[0] + + return { + "Fajr": data.get("fajr_jamah", "00:00")[:5], + "Zuhr": data.get("zuhr_jamah", "00:00")[:5], + "Asr": data.get("asr_jamah", "00:00")[:5], + "Maghrib": data.get("maghrib_jamah", "00:00")[:5], + "Isha": data.get("isha_jamah", "00:00")[:5] + } + except Exception as e: + print(f"⚠️ Fout bij ophalen gebedstijden: {e}") + return get_fallback_data('prayer_times') + # Voeg cache-control headers toe voor statische bestanden @app.after_request def add_header(response): @@ -28,8 +116,21 @@ CLIPS_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'static', 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, @@ -70,15 +171,6 @@ def load_hadith(): 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 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 get_current_volume(settings): """Bepaal het juiste volume op basis van de huidige tijd""" from datetime import datetime, timedelta @@ -158,7 +250,11 @@ def apply_prayer_offsets(gebedstijden, settings): 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() @@ -235,73 +331,44 @@ def get_date_info(): @app.route('/') def index(): settings = load_settings() + + # Haal alle data parallel op + data = fetch_data_parallel() + + # Verwerk gebedstijden + gebedstijden = apply_prayer_offsets(data['prayer_times'], settings) + + # Bepaal volgende gebed + now = datetime.now().strftime('%H:%M') 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 = "اللّهُمَّ اجْعَلْ صَلاتِي نُورًا" + + 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] + 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) + next_time=next_time, + next_name=next_name, + dua="اللّهُمَّ اجْعَلْ صَلاتِي نُورًا", + hadith=data['hadith'], + gebedstijden=gebedstijden, + settings=settings, + weather=data['weather'], + date_info=data['date']) @app.route('/instellingen', methods=['GET', 'POST']) def instellingen(): - settings = load_settings() - clips = [f for f in os.listdir(CLIPS_PATH) if f.endswith('.mp3') or f.endswith('.wav')] - alle_zones = fetch_sonos_zones() - 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'] @@ -310,6 +377,7 @@ def instellingen(): 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') @@ -373,10 +441,14 @@ def instellingen(): # 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=settings, - alle_zones=alle_zones, - clips=clips) + settings=load_settings(), + alle_zones=data['sonos'], + date_info=data['date'], + weather=data['weather']) @app.route('/api/hadith') def api_hadith(): diff --git a/adhan-webapp/done b/adhan-webapp/done index f009148..d582ecc 100644 --- a/adhan-webapp/done +++ b/adhan-webapp/done @@ -13,3 +13,6 @@ Mon May 26 18:17:57 CEST 2025: Tijdzone probleem opgelost - Container gebruikt n 2025-05-28 03:49:24 - Adzkaar fullscreen functionaliteit geïmplementeerd: nieuwe /adzkaar route, instellingen, debug knoppen, automatische trigger na gebedstijden, Nederlandse/Arabische dhikr content 2025-05-28 03:55:38 - Adzkaar scherm verbeterd naar kaart-voor-kaart weergave met navigatie knoppen en toetsenbord besturing Wed May 28 14:09:12 CEST 2025: Sonos debug tijd synchronisatie geïmplementeerd - get_current_volume functie en cron script gebruiken nu debug tijd API, volume bepaling werkt correct in debug mode +2025-05-29 21:24:37 - Performance optimalisaties toegevoegd: caching voor API calls en instellingen +2025-05-29 21:27:02 - UI optimalisaties toegevoegd: lazy loading, parallelle API calls en caching +2025-05-29 21:30:24 - Geavanceerde optimalisaties toegevoegd: async/await, debouncing en DOM caching diff --git a/adhan-webapp/templates/adzkaar.html b/adhan-webapp/templates/adzkaar.html index 100fe00..eb81bd5 100644 --- a/adhan-webapp/templates/adzkaar.html +++ b/adhan-webapp/templates/adzkaar.html @@ -3,6 +3,8 @@ Adzkaar na het Gebed + + @@ -208,40 +210,28 @@
- - -
- 5:00 -
-
-

أذكار بعد الصلاة

-

Adzkaar na het Gebed

+

Adzkaar na het Gebed

+

Herinneringen voor na het gebed

- - -
- 1 / 6 -
- -
-
-
-
أَسْتَغْفِرُ اللَّهَ
-
Astaghfirullah
-
Ik vraag Allah om vergeving
-
3x
+
+
+
سُبْحَانَ اللَّهِ
+
Subhanallah
+
Glorie zij Allah
+
33x
@@ -252,27 +242,20 @@
-
سُبْحَانَ اللَّهِ
-
Subhan Allah
-
Glorie zij Allah
-
33x
-
- -
الْحَمْدُ لِلَّهِ
Alhamdulillah
Alle lof zij Allah
33x
-
+
اللَّهُ أَكْبَرُ
Allahu Akbar
Allah is de Grootste
34x
-
+
لاَ إِلَهَ إِلاَّ اللَّهُ وَحْدَهُ لاَ شَرِيكَ لَهُ لَهُ الْمُلْكُ وَلَهُ الْحَمْدُ وَهُوَ عَلَى كُلِّ شَيْءٍ قَدِيرٌ
La ilaha illa Allah wahdahu la sharika lah, lahu al-mulku wa lahu al-hamdu wa huwa 'ala kulli shay'in qadir
Er is geen god behalve Allah alleen, Hij heeft geen partner. Aan Hem behoort de heerschappij en aan Hem behoort alle lof, en Hij heeft macht over alle dingen
@@ -280,109 +263,85 @@
+ +
00:00
+
\ No newline at end of file diff --git a/adhan-webapp/templates/index.html b/adhan-webapp/templates/index.html index ee46084..89f4699 100644 --- a/adhan-webapp/templates/index.html +++ b/adhan-webapp/templates/index.html @@ -4,8 +4,17 @@ Gebedstijden Display + + +
@@ -164,6 +173,14 @@
- - + diff --git a/adhan-webapp/templates/settings.html b/adhan-webapp/templates/settings.html index e03039d..a3174e4 100644 --- a/adhan-webapp/templates/settings.html +++ b/adhan-webapp/templates/settings.html @@ -4,8 +4,17 @@ Instellingen - Gebedstijden Display + + +
@@ -318,37 +327,134 @@