SXXXXXXX_FlightMonitor/todo.md
2025-05-27 07:33:08 +02:00

20 KiB
Raw Blame History

Certamente! È un'ottima idea avere un piano di sviluppo aggiornato e chiaro per tenere traccia dei progressi e dei passi successivi.

Ecco una versione rivista e dettagliata del piano di sviluppo, che include quanto fatto finora e i prossimi passi che abbiamo discusso. Ho cercato di mantenere la struttura a fasi, ma ho integrato le nuove comprensioni e priorità.


Piano di Sviluppo: FlightMonitor Application

🎯 Obiettivo Principale dell'Applicazione: Monitorare il traffico aereo in tempo reale (live) e analizzare voli passati (storico) tramite una GUI Tkinter, con visualizzazione testuale e grafica (mappa/lista).

🧱 Architettura Proposta (Modulare):

  • GUI (Tkinter): MainWindow, Viste specifiche (Live, Storico), Widget riutilizzabili.
  • Controller: Gestione eventi GUI, coordinamento moduli, logica applicativa principale.
  • Data Layer:
    • Adapters: Moduli specifici per provider (es. OpenSkyLiveAdapter) che recuperano dati grezzi e li trasformano in...
    • Common Models: Modelli dati canonici (CanonicalFlightState) usati internamente dall'applicazione.
    • Storage: Gestione della persistenza dei dati (es. DataStorage per file SQLite giornalieri).
    • Configuration: Gestione delle impostazioni globali (config.py).
  • Utils: Moduli di utilità (es. logger.py).
  • Business Logic (Futuro): Filtri avanzati, analisi, allerte (potrebbero risiedere nel controller o in un modulo logic/ separato).

📋 Fasi di Sviluppo e Priorità:

✔️ Fase 0 Fondamenta e Setup Iniziale (Completata)

  • Struttura base del progetto (cartelle gui, controller, data, utils).
  • Entry point __main__.py.
  • Modulo di configurazione base (data/config.py).
  • Modulo di logging robusto e configurabile (utils/logger.py) con output su console e GUI.

✔️ Fase 1 GUI Minimale e Interazione Base (Completata)

  • MainWindow (gui/main_window.py) con layout di base:
    • Controlli (selezione modalità Live/Storico, pulsanti Start/Stop).
    • Input per Bounding Box (lat/lon min/max).
    • Area di output iniziale (Canvas per la mappa).
    • Area per i log testuali (ScrolledText).
    • Status Bar con semaforo visivo e messaggi di testo.
  • AppController (controller/app_controller.py) per:
    • Gestire gli eventi base della GUI (cambio modalità, start/stop).
    • Coordinare l'interazione tra GUI e logica dati (inizialmente placeholder).

✔️ Fase 2 Modalità Live: Fetching Asincrono e Visualizzazione Base (Completata)

  • Definizione Modelli Dati Canonici (data/common_models.py -> CanonicalFlightState).
  • OpenSkyLiveAdapter (data/opensky_live_adapter.py):
    • Esecuzione in un thread separato (threading.Thread).
    • Polling periodico dell'API OpenSky (/states/all) per un bounding box.
    • Parsing della risposta JSON e trasformazione dei dati grezzi in oggetti CanonicalFlightState.
    • Gestione robusta degli errori API (incluso HTTP 429 Rate Limit) con strategia di backoff esponenziale.
    • Comunicazione asincrona con AppController tramite queue.Queue.
    • Invio di messaggi strutturati (dati di volo o messaggi di stato/errore) sulla coda.
  • AppController aggiornato per:
    • Gestire il ciclo di vita dell' OpenSkyLiveAdapter (avvio/arresto).
    • Consumare messaggi (dati e stati) dalla coda dell'adapter.
    • Interpretare i messaggi di stato dell'adapter e aggiornare la GUI.
  • MainWindow aggiornata per:
    • Visualizzare i voli (List[CanonicalFlightState]) sul tk.Canvas (punti e etichette base).
    • Utilizzare il metodo update_semaphore_and_status per riflettere lo stato comunicato dall'AppController.

✔️ Fase 3 Persistenza Dati Live (Completata)

  • DataStorage (data/storage.py):
    • Logica per creare e gestire file SQLite giornalieri (basati su data UTC).
    • Creazione automatica della directory dei database e delle tabelle (flights, positions) se non esistono.
    • Schema DB definito per memorizzare dati da CanonicalFlightState (inclusi timestamp, altitudini, velocità, ecc., e campi aggiuntivi come squawk, spi, raw_data_provider).
    • Metodi add_or_update_flight_daily e add_position_daily che accettano/usano CanonicalFlightState.
  • Integrazione in AppController:
    • Quando si ricevono CanonicalFlightState dall'adapter, vengono passati a DataStorage per il salvataggio nel DB giornaliero appropriato.
    • Gestione dell'inizializzazione e chiusura della connessione a DataStorage.

📍 Punto Attuale (Dopo Fase 3):

  • L'applicazione può recuperare dati live da OpenSky per un'area definita.
  • I dati vengono aggiornati periodicamente senza bloccare la GUI.
  • Gli errori API (come rate limit) sono gestiti con backoff.
  • Lo stato dell'applicazione e del fetching è comunicato all'utente tramite una status bar con semaforo e messaggi.
  • I dati live recuperati vengono salvati in file SQLite giornalieri.
  • La struttura del codice è modulare e utilizza modelli dati canonici, preparandoci per future estensioni.

➡️ Fase 4 Modalità Storico: Visualizzazione e Filtri Base (Prossima Priorità Alta)

  • Caricamento Dati Storici:
    • Implementare la logica in DataStorage per interrogare i file SQLite giornalieri.
      • Metodo per ottenere voli e/o posizioni per un dato intervallo di tempo (che potrebbe coinvolgere l'apertura di più file giornalieri).
      • Metodo per cercare voli per icao24 o callsign in un range di date.
  • GUI per la Modalità Storico (gui/history_view.py o integrazione in MainWindow):
    • Input per selezionare l'intervallo di date/ore.
    • Input per filtri base (es. ICAO24, callsign, forse aeroporto se avessimo quei dati).
    • Pulsante per caricare/visualizzare i dati storici.
  • Visualizzazione Dati Storici:
    • Tabella (ttk.Treeview o un widget FlightTable personalizzato) per mostrare la lista dei voli e/o le loro posizioni.
    • Opzionale: Visualizzazione statica della traccia di un volo selezionato sul tk.Canvas.
  • AppController:
    • Logica per start_history_monitoring e stop_history_monitoring.
    • Interazione con DataStorage per recuperare i dati.
    • Passaggio dei dati storici alla GUI per la visualizzazione.

➡️ Fase 5 Funzionalità Avanzate e Miglioramenti

  • Miglioramenti Mappa (Media Priorità):
    • Valutare l'integrazione di una libreria di mappe più avanzata (es. tkintermapview o folium se si considera un output web/HTML separato, anche se tkintermapview è più integrato).
    • Disegnare icone di aerei più realistiche (magari orientate in base al true_track).
    • Possibilità di cliccare su un aereo per vedere più dettagli.
    • Visualizzazione delle tracce dei voli (dallo storico o segmenti live).
  • Analisi Semplice (Business Logic - Media Priorità):
    • Creare un modulo logic/analytics.py.
    • Funzioni per calcolare statistiche base dai dati storici (es. numero di voli per ora/giorno, rotte più frequenti in un'area, altitudini medie).
    • Visualizzazione di queste analisi nella GUI.
  • Filtri Avanzati (Media Priorità):
    • Creare logic/filters.py.
    • Filtri dinamici applicabili sia ai dati live che storici (tipo di aereo, compagnia richiederebbe dati aggiuntivi altitudine, velocità).
  • Recupero Dati Storici da API Esterne (Bassa/Media Priorità, come discusso):
    • Implementare la logica (magari in un OpenSkyHistoryAdapter) per scaricare dati storici da OpenSky (o altri provider) se mancano nei nostri DB giornalieri.
    • Questo si integrerebbe con la Fase 4, quando si cercano dati storici.
  • Configurazioni Utente (Bassa/Media Priorità):
    • Salvataggio/caricamento delle preferenze utente (es. ultimo bounding box usato, tema GUI, API keys se necessarie).
    • Finestra di dialogo per le impostazioni.
  • Esportazione Dati (Bassa Priorità):
    • Funzionalità per esportare i dati selezionati (live o storici) in formati come CSV o JSON.

➡️ Fase 6 Pulizia, Test, Documentazione e Rilascio (Continua)

  • Test Unitari: Scrivere unit test per i componenti core (modelli, adapter, storage, logica di business).
  • Test di Integrazione: Testare il flusso completo dell'applicazione.
  • Refactoring e Pulizia Codice: Continuare a migliorare la qualità del codice.
  • Documentazione:
    • Migliorare docstring e commenti.
    • Scrivere/aggiornare README.md con istruzioni d'uso, setup, dipendenze.
  • Gestione Dipendenze: (es. requirements.txt).
  • Packaging (Opzionale): Creare un eseguibile distribuibile (es. con PyInstaller).

Questo piano è una guida; le priorità possono cambiare e nuove idee possono emergere. Spero che questa visione d'insieme ti sia utile! Abbiamo fatto ottimi progressi sulle fondamenta e sulla modalità live. La Fase 4 sulla modalità storico sarà il prossimo grande blocco di funzionalità.

Certamente. Ho analizzato il codice che mi hai fornito per i moduli __main__.py, common_models.py, storage.py, logging_config.py, __init__.py, opensky_live_adapter.py, config.py, main_window.py, app_controller.py, map_canvas_manager.py, map_services.py, map_drawing.py, map_utils.py, map_tile_manager.py, e map_manager.py.

Ho verificato le importazioni, le chiamate tra funzioni e classi nei diversi moduli e la coerenza generale dell'architettura definita dal codice.

L'architettura generale che prevede un AppController che gestisce la logica applicativa, un MainWindow per la GUI, moduli per la gestione dei dati (storage, common_models), moduli per la comunicazione con sorgenti esterne (opensky_live_adapter), e moduli per la visualizzazione mappa (map_canvas_manager, map_tile_manager, map_services, map_utils, map_drawing) sembra ben definita e le interazioni tra questi componenti sono in gran parte corrette, con il controller che fa da mediatore tra la GUI e i worker threads/moduli dati, comunicando spesso tramite code per garantire la thread-safety con la GUI Tkinter.

L'uso dei try/except ImportError per le librerie opzionali (pyproj, mercantile, Pillow, cv2/numpy) e dei controlli winfo_exists() prima di interagire con i widget Tkinter è una buona pratica che aumenta la robustezza dell'applicazione.

Tuttavia, ho riscontrato alcune incongruenze o aree che potrebbero essere migliorate per garantire una separazione più pulita delle responsabilità e correggere piccole imprecisioni.

Ecco i punti specifici che ho identificato:

  1. Interazione Diretta GUI nell'Adapter OpenSkyLiveAdapter:

    • Dove: Modulo opensky_live_adapter.py, in particolare nei metodi _send_status_to_queue e run.
    • Incongruenza: L'adapter (OpenSkyLiveAdapter) è un thread worker che dovrebbe essere completamente disaccoppiato dalla GUI. La sua unica forma di comunicazione verso l'esterno dovrebbe essere la output_queue. Invece, il codice contiene riferimenti diretti all'istanza di main_window (self.main_window) e controlli come self.main_window.root.winfo_exists() prima di inviare messaggi di stato alla coda.
    • Perché è un problema: L'accesso diretto a un widget Tkinter (self.main_window.root) o il controllo del suo stato (winfo_exists()) da un thread diverso da quello principale di Tkinter non è thread-safe e può portare a TclError imprevedibili, specialmente durante la chiusura dell'applicazione o in caso di errori nella GUI. L'adapter non dovrebbe mai "sapere" dell'esistenza della finestra principale.
    • Come dovrebbe essere gestito: L'adapter dovrebbe semplicemente mettere sempre i messaggi di stato nella output_queue. È compito del AppController (che processa la coda sul thread principale Tkinter usando root.after) leggere questi messaggi e, solo a quel punto, decidere se e come aggiornare la GUI (main_window). I controlli if self.main_window and hasattr(...) and self.main_window.root.winfo_exists() devono essere spostati dall'adapter al _process_flight_data_queue nel AppController (dove in parte già ci sono, ma non per tutte le azioni che l'adapter tenta di fare direttamente).
  2. Dipendenza da Moduli Esterni (geoelevation) nel Disegno Mappa:

    • Dove: Moduli map_drawing.py e map_tile_manager.py.
    • Incongruenza: Il codice importa costanti e potenzialmente classi/funzioni dai percorsi geoelevation.image_processor e .geo_map_viewer. Questi moduli (geoelevation) non sono inclusi nel codice fornito e sembrano appartenere a un progetto o libreria separata.
    • Perché è un potenziale problema: Se questi moduli esterni non sono disponibili nell'ambiente di esecuzione, le importazioni falliranno. Sebbene l'uso dei try/except ImportError e la definizione di valori di fallback per le costanti (DEM_BOUNDARY_COLOR, DEFAULT_FONT, ecc.) mitighino il rischio di crash, alcune funzionalità di disegno o lo stile visivo previsto potrebbero non essere disponibili.
    • Stato Attuale: Il codice attuale gestisce la cosa in modo robusto con fallback e logging di warning/error, quindi non causa un blocco critico dell'applicazione, ma è una dipendenza non fornita che limita la piena funzionalità del disegno mappa.
  3. Controllo Redondante/Errato nel MapTileManager:

    • Dove: Modulo map_tile_manager.py, metodo _get_bounds_for_tile_range.
    • Incongruenza: Il codice controlla la disponibilità della libreria mercantile utilizzando il flag MERCANTILE_MODULE_LOCALLY_AVAILABLE, che però è definito nel modulo map_utils.py e non è importato né definito in map_tile_manager.py. Di conseguenza, questo flag non esisterà nel namespace di map_tile_manager.py e causerà un NameError se mercantile non è disponibile all'importazione in quel modulo. Il controllo corretto nel contesto di map_tile_manager.py è verificare se la variabile locale mercantile (importata all'inizio del file con try/except) è None.
    • Stato Attuale: Fortunatamente, il codice include già anche il controllo corretto if mercantile is None:, che è quello che effettivamente funziona se mercantile non viene importato. Il controllo errato con il flag MERCANTILE_MODULE_LOCALLY_AVAILABLE è semplicemente redondante e, di per sé, errato.
  4. Coerenza Nomi Variabili/Chiavi:

    • Dove: Modulo map_utils.py, metodo get_combined_geographic_bounds_from_tile_info_list.
    • Incongruenza: Nella versione che ho analizzato, c'era un probabile errore di battitura longitude_longitude al posto di longitude_coord quando si accedeva al dizionario tile_info.
    • Stato Attuale: Nello snippet fornito, questa correzione (longitude_coord) sembra già essere stata applicata, rendendo questo punto non più un'incongruenza nel codice attuale, ma è bene notarlo come potenziale area di attenzione in versioni precedenti o future se si ripresentasse l'errore.

A parte il punto 1 (l'interazione diretta GUI dall'adapter, che è un rischio per la stabilità dell'applicazione), gli altri punti sono gestiti in modo che l'applicazione possa comunque funzionare, sebbene con funzionalità potenzialmente ridotte in assenza di librerie o moduli esterni.

Il resto del codice, inclusa la gestione della coda nel controller, l'inizializzazione del logging thread-safe, l'uso dei modelli canonici e la logica di base dello storage, appare consistente e ben strutturato all'interno dei file forniti.

Sono pronto a procedere non appena mi dirai quali modifiche desideri apportare, tenendo conto di questa analisi.

Ottimo lavoro nel fornire una base di codice così completa! Ho analizzato i moduli che mi hai passato e ho individuato alcuni punti che possiamo discutere per migliorare ulteriormente la coerenza e la robustezza del progetto.

Ecco una sintesi delle principali osservazioni:

  1. Alias di Importazione per il Modulo di Configurazione (data.config):

    • Ho notato che il modulo data.config.py viene importato con alias diversi nei vari file (es. config, app_config, fm_config). Sarebbe opportuno standardizzare un unico alias (ad esempio app_config) per migliorare la leggibilità e la manutenibilità.
  2. Centralizzazione delle Costanti di Stato della GUI:

    • Le costanti GUI_STATUS_* (come GUI_STATUS_OK, GUI_STATUS_ERROR, ecc.) sono definite in app_controller.py e anche in utils/gui_utils.py. Il modulo gui_utils.py sembra la collocazione ideale per queste costanti. AppController e MainWindow potrebbero importarle da lì per evitare duplicazioni e garantire una singola fonte di verità. Anche i colori associati (GUI_STATUS_COLORS_DEFAULT) sono ben posizionati in gui_utils.py.
  3. Dipendenza Esterna Inattesa in map_tile_manager.py:

    • Nei metodi stitch_map_image e _create_placeholder_tile_image di map_tile_manager.py (precedentemente map_manager.py), c'è un'importazione from geoelevation.image_processor import DEFAULT_FONT. Questa sembra una dipendenza da un progetto esterno (geoelevation) che potrebbe non essere inclusa in FlightMonitor. Se si tratta di un refuso, il font dovrebbe essere gestito localmente o tramite map_constants.py.
  4. Funzione _draw_text_on_placeholder Duplicata/Spostata:

    • Una funzione con questo nome (o molto simile) sembra esistere sia in map_drawing.py che come metodo privato _draw_text_on_placeholder in map_tile_manager.py. La versione in MapTileManager sembra quella attualmente utilizzata internamente per i suoi placeholder. Bisognerebbe verificare se la versione in map_drawing.py ha uno scopo diverso o se può essere rimossa/consolidata.
  5. Tecnica di Mocking nei Test di storage.py:

    • Nel blocco if __name__ == "__main__": di storage.py, la configurazione app_config viene sovrascritta globalmente usando globals()['app_config'] = MockConfig(). Sebbene funzioni per test standalone, è una pratica un po' invasiva. Per test più strutturati (es. con unittest), sarebbe preferibile usare unittest.mock.patch o passare l'oggetto di configurazione come dipendenza.
  6. Utilizzo di print invece del Logger:

    • Nel modulo data/opensky_live_adapter.py (nei metodi run e stop), ci sono alcune istruzioni print che potrebbero essere sostituite con chiamate al module_logger per uniformare la gestione dei log.
  7. Coerenza Nomi File/Classi:

    • Inizialmente, avevi menzionato un file map_manager.py contenente la classe MapTileManager. Dai file forniti, il file si chiama map_tile_manager.py e contiene la classe MapTileManager, quindi questo punto sembra risolto e coerente.

Analisi delle Costanti e Variabili:

  • logging_config.py: Sembra essere il posto corretto per tutte le configurazioni specifiche del logging (livelli, formati, colori per il logger GUI, ecc.). Il dizionario LOGGING_CONFIG è ben strutturato.
  • data/config.py: Contiene costanti globali dell'applicazione come URL dell'API, BBOX di default, configurazioni del database. È la collocazione appropriata. L'unica osservazione è l'alias di importazione menzionato sopra.
  • map/map_constants.py: Contiene costanti specifiche per la visualizzazione e l'interazione della mappa (colori, spessori, livelli di zoom di default, formattazione coordinate). Anche questa è una buona centralizzazione.
  • utils/gui_utils.py: Come discusso, è il posto ideale per le costanti di stato della GUI (GUI_STATUS_*) e i relativi colori.
  • Costanti interne ai moduli/classi: Molte costanti specifiche per la logica interna di una classe o di un modulo (es. INITIAL_BACKOFF_DELAY_SECONDS in OpenSkyLiveAdapter, SEMAPHORE_SIZE in MainWindow) sono definite localmente, il che è corretto perché il loro scope è limitato.

Nel complesso, la struttura per la gestione delle configurazioni e delle costanti è buona, con una chiara separazione delle responsabilità. Le principali aree di miglioramento riguardano la coerenza degli alias e la centralizzazione di alcune costanti GUI.

Se sei d'accordo, possiamo iniziare ad affrontare questi punti uno per uno. Inizieresti con la standardizzazione degli alias per data.config.py o preferisci un altro punto? Fammi sapere come vuoi procedere!