AirportInfos

 Contexte

Sur le réseau IVAO, il arrive souvent d'avoir la responsabilité de grandes zônes une fois un certain niveau obtenu. Il devient alors difficile de connaitre l'ensemble des informations concernant un aéroport : pistes disponibles, longueur des pistes, types d'approches, etc... C'est pourquoi j'ai eu l'idée de créer un petit outil AirportInfos, qui permet de récupérer rapidement les informations concernant un aéroport.

Fonctionnement

Général

Les données utilisées dans ce logiciel ne sont par fournies. En effet, c'est l'utilisateur qui doit acheter les données VasFMC sur un service très connu dans le milieu de la simulation aéronautique : les AIRAC Navigraph. Ces données sont mises à jour tous les mois avec les données réelles du domaine aéronautique.

Une fois les données récupérées, l'utilisateur doit simplement indiquer le chemin du répertoire NavData. Il lui reste ensuite à cliquer sur Valider puis de lancer le chargement en appuyant sur l'icône de synchronisation. Pour avoir accès aux données d'un aéroport l'utilisateur doit entrer son code dans le champ puis appuyer sur Entrée. Une fois fais, les différentes pistes de l'aéroport seront chargées et les données les concernant également. Chaque fois que l'utilisateur sélectionne une piste dans la liste déroulante, les onglets des données sont rechargées.

J'ai également décidé d'intégrer la possibilité de générer une clairance de départ rapidement (donné à chaque appareil afin qu'il sache ses informations de départ). Pour se faire, l'utilisateur doit double-cliquer sur la SID qui l'intéresse, remplir les données puis appuyer sur Entrée, cela mettera la clairance dans son presse-papier. La clairance sera formatée en fonction du template renseignée dans les paramètres, par exemple :

AMOL5B DEPARTURE, RWY 32L, INI CLB 080, SQ 2431

Un screen de la fenêtre de clairance est disponible en annexe 2. Dans cette première version il est également possible d'avoir accès à la météo de l'aéroport séléctionné, celle-ci est automatiquement chargée lorsque l'utilisateur valide la séléctione d'un aéroport avec la touche Entrée.

Technique

Récupérer les informations d'un aéroport

Le fonctionnement d'un point de vu technique est plutôt simple vu qu'il s'agit de lecture de fichiers. Lors de la synchronisation, une première fonction CheckFolderConfiguration permet de vérifier si le dossier indiqué dans les paramètres de l'application contient bien les sous-dossiers attendus :

public bool CheckFolderConfiguration()
{
    base_path = Properties.Settings.Default.path;
    if(Directory.Exists(base_path + "/SID") && Directory.Exists(base_path + "/STAR") && 
       File.Exists(base_path + "/cycle_info.txt") && File.Exists(base_path + "/Airports.txt"))
    {
        return true;
    }
    else
    {
        return false;
    }
}

L'application va ensuite récupérer la liste des aéroports disponibles avec la fonction GetAllAiports (annexe 1). Quand l'utilisateur entre un aéroport, on vérifie dans un premier temps que l'aéroport existe puis on récupère ses informations avec la fonction GetAirportInfos (annexe 3) notamment les différentes pistes qui sont automatiquement ajoutées dans la liste déroulante :

<ComboBox Name="cb_rwy_in_use" HorizontalAlignment="Left" ItemsSource="{Binding Path=listRunways}" DisplayMemberPath="rwyName" SelectedValuePath="rwyName" SelectionChanged="cb_rwy_in_use_SelectionChanged"/>

Il ne reste plus qu'à récupérer les SID/STAR quand l'utilisateur séléctionne une piste (Annexe 4).

Récupérer la météo

En aéronautique, la météo est donnée via une chaine de caractère appelée METAR mise à jour régulièrement, un exemple ci-dessous de la météo de Nantes :

LFRS 051030Z AUTO 17014KT CAVOK 18/07 Q1013 BECMG 18015G25KT

J'ai mis un peu de temps afin de voir comment je pouvais récupérer ces informations sans avoir à utiliser une API. J'ai ensuite trouvé plusieurs URL permetant de récupérer directement le METAR en donnant le code OACI de l'aéroport, par exemple : https://tgftp.nws.noaa.gov/data/observations/metar/stations/LFRS.TXT me donne le METAR en cours de l'aéroport de Nantes.

J'ai dans un premier temps essayé de charger la météo de façon synchrone une fois l'aéroport séléctionné mais je trouvais que ce n'était pas optimal car l'application devait attendre le METAR avant d'affichier les informations de l'aéroport. J'ai donc décidé de charger ces informations de façon asynchrone en utilisant la fonction DownloadStringAsync de WebClient :

public static void updateMetarUiWithIcaoAsync(string icao, TextBlock text_box)
{
    MetarManager.lastIcao = icao;
    MetarManager.text_box = text_box;
    WebClient wc = new WebClient();
    string formattedNoaaUrl = string.Format(URL_NOAA, icao.ToUpper());
    Uri metarUrl = new Uri(formattedNoaaUrl);
    wc.DownloadStringCompleted += Wc_DownloadNoaaStringCompleted;
    wc.DownloadStringAsync(metarUrl);
}

Une fois la page chargée, c'est la fonction Wc_DownloadNoaaStringCompleted qui prend le relai pour afficher le METAR.

Annexes

Annexe 1 : Fonction GetAllAirports

// Ceci est une partie de la fonction
List<string> listAirports = new List<string>();
string icao;
foreach (string line in File.ReadLines(base_path + "/Airports.txt"))
{
    if (!string.IsNullOrEmpty(line))
    {
        if (line[0].Equals('A'))
        {
            icao = line.Split('|')[1].ToUpper();
            listAirports.Add(icao);
        }
    }
}
return listAirports;

Annexe 2 : Fenêtre de clairance

Annexe 3 : Fonction GetAirportInfos

// ...
if (lines[i][0].Equals('A'))
{
    string[] splitedArptLine = lines[i].Split('|');
    //On rentre dans la section de l'aéroport desiré
    if (splitedArptLine[1].Equals(ICAO))
    {
        Airport airport = new Airport(ICAO, splitedArptLine[2], splitedArptLine[5]);
        List<Runway> listRunways = new List<Runway>();
        for (int j = i + 1; j < lines.Length; j++)
        {
            if (string.IsNullOrEmpty(lines[j]))
            {
                airport.listRunways = listRunways;
                return airport;
            }
            else
            {
                if (lines[j][0].Equals('R'))
                {
                    string[] splitedRwyLine = lines[j].Split('|');
                    if (splitedRwyLine[4].Equals("1"))
                    {
                        listRunways.Add(new Runway(splitedRwyLine[3], splitedRwyLine[9], splitedRwyLine[1], splitedRwyLine[2],"yes"));
                    }
                    else
                    {
                        listRunways.Add(new Runway(splitedRwyLine[3], splitedRwyLine[9], splitedRwyLine[1], splitedRwyLine[2]));
                    }

                }
            }
        }
    }
}

Annexe 4 : Récupération des informations de piste

if (list_str.Contains(icao))
{
    Dictionary<string, List<string>> dic = fileManager.getSidStarWithAirportAndRunway(icao, rwy);
    if (dic != null)
    {
        foreach (KeyValuePair<string, List<string>> entry in dic)
        {
            if (entry.Key.Equals("SID"))
            {
                lb_sid.ItemsSource = entry.Value;
            }
            else
            {
                lb_star.ItemsSource = entry.Value;
            }
        }
    }
}