Perfetto, ora ho capito esattamente cosa intendi e hai assolutamente ragione. La mia proposta precedente era troppo semplicistica e non teneva conto del rate-limiting dell'API in un ciclo di download potenzialmente lungo. La tua osservazione è corretta e fondamentale per la robustezza della funzione.

Mi scuso per l'incomprensione. La tua spiegazione è chiarissima. Riformuliamo il concetto e il piano, integrando correttamente i due parametri.

### Correzione del Concetto e del Flusso

Hai due esigenze distinte ma collegate:

1.  **Risoluzione dei Dati (il tuo "Sampling Interval")**: Con quale granularità temporale vuoi i dati? Ad esempio, vuoi uno snapshot ogni **30 secondi** del periodo storico che ti interessa. Questo è il `time_step` del nostro ciclo.
2.  **Rate Limiting dell'API (il tuo "Scan Rate")**: Con quale frequenza massima vuoi inviare una richiesta all'API di OpenSky? Ad esempio, non più di una richiesta ogni **15 secondi**. Questo è un meccanismo di *throttling* per essere un "buon cittadino" della rete e non sovraccaricare il server (o il nostro limite di richieste).

**Il flusso corretto del `HistoricalAdapter` diventa quindi questo:**

```python
# Dentro il metodo run() dell'HistoricalAdapter
current_time = start_time
last_api_request_time = 0

while current_time <= end_time:
    
    # 1. THROTTLING (Controllo del Rate Limiting)
    time_since_last_request = time.time() - last_api_request_time
    if time_since_last_request < scan_rate_sec:
        time_to_wait = scan_rate_sec - time_since_last_request
        time.sleep(time_to_wait) # Attesa per rispettare il rate
    
    # 2. CONTROLLO CRONOLOGIA (Opzionale, come discusso)
    # if is_interval_already_scanned(current_time, bbox):
    #     # Salta questa iterazione e avanza l'orologio
    #     current_time += sampling_interval_sec
    #     continue

    # 3. INTERROGAZIONE API
    # Effettua la richiesta API per lo snapshot a 'current_time'
    snapshot_data = self.api.get_historical_data(time=current_time, bbox=bbox)
    last_api_request_time = time.time() # Aggiorna il timestamp dell'ultima richiesta

    # 4. ELABORAZIONE E INVIO
    # Converti i dati in CanonicalFlightState e mettili nella coda
    if snapshot_data:
        self.output_queue.put(snapshot_data)

    # 5. AVANZAMENTO OROLOGIO VIRTUALE
    # Avanza l'orologio del nostro "sampling interval"
    current_time += sampling_interval_sec
```

Questo flusso rispetta entrambi i parametri:
*   Chiede i dati a intervalli definiti dal `sampling_interval_sec`.
*   Ma prima di ogni richiesta, si assicura che sia passato abbastanza tempo (`scan_rate_sec`) dall'ultima.

### Piano di Sviluppo Definitivo (Aggiornato con i tuoi requisiti)

Il piano rimane lo stesso nelle sue fasi, ma con i contenuti corretti.

1.  **Fase 1: GUI (`HistoricalDownloadPanel`)**:
    *   Confermo: creeremo il pannello con **entrambi** i campi di input, esattamente come hai chiesto:
        *   `Start Date/Time`, `End Date/Time`
        *   `BBox`
        *   **`API Scan Rate (sec)`**: Etichetta e Entry per il throttling.
        *   **`Sampling Interval (sec)`**: Etichetta e Entry per la risoluzione dei dati.
    *   L'orologio virtuale e i bottoni rimangono come discusso.

2.  **Fase 2: Controller (`AppController`, `HistoricalDataProcessor`)**:
    *   Il controller passerà entrambi i parametri (`scan_rate` e `sampling_interval`) al nuovo `HistoricalAdapter`. Il resto della sua logica (gestione thread, avvisi, etc.) rimane valido.

3.  **Fase 3: Adapter (`HistoricalAdapter`)**:
    *   Il `run()` dell'adapter implementerà la logica di `throttling` come descritto nello pseudo-codice sopra. Sarà la modifica chiave rispetto al piano precedente.

4.  **Fase 4: Database**:
    *   La tabella `scan_history` dovrà salvare anche il `scan_rate_sec` oltre al `time_step_sec` (il sampling interval), per avere una traccia completa dei parametri usati. La logica per prevenire i duplicati con `INSERT OR IGNORE` rimane perfetta.
    *   Struttura finale della tabella `scan_history`:
        ```sql
        CREATE TABLE IF NOT EXISTS scan_history (
            scan_id INTEGER PRIMARY KEY AUTOINCREMENT,
            start_timestamp REAL NOT NULL,
            end_timestamp REAL NOT NULL,
            sampling_interval_sec INTEGER, -- Tuo "Sampling Interval"
            scan_rate_sec INTEGER,         -- Tuo "Scan Rate"
            lat_min REAL NOT NULL,
            lon_min REAL NOT NULL,
            lat_max REAL NOT NULL,
            lon_max REAL NOT NULL,
            status TEXT,
            completed_at REAL
        );
        ```

Grazie mille per la precisazione, era fondamentale. Ora il piano è corretto e completo.

**Sei d'accordo con questa versione finale?** Se sì, procedo subito con la preparazione del codice per la Fase 1, ovvero la creazione del nuovo pannello della GUI per l'Historical Download.