first commit

This commit is contained in:
mathieu 2025-07-14 17:56:57 +02:00
commit a233e18c0b
48 changed files with 55300 additions and 0 deletions

645
docs/DOCUMENTATION_DEMOS.md Normal file
View file

@ -0,0 +1,645 @@
# Documentation des Scripts de Démonstration
## Vue d'ensemble
Ce document présente la documentation complète des deux scripts de démonstration créés pour illustrer les fonctionnalités des classes de données du wrapper API Atmo Data. Ces scripts utilisent des données réelles de l'API pour démontrer chaque méthode et propriété disponible.
---
## 📊 Script 1 : `demo_atmo_functions.py`
### Description générale
Script de démonstration complet pour la classe `IndiceAtmo`, illustrant toutes les fonctionnalités liées aux indices de qualité de l'air ATMO.
### Configuration
- **Région testée** : Île-de-France (AASQA 11)
- **Source de données** : API Atmo Data en temps réel
- **Date** : Jour d'exécution du script
- **Format** : GeoJSON
- **Conformité** : Notice officielle du 1er avril 2025
### Sections démontrées
#### 1. Propriétés de base (héritées d'AtmoDataBase)
```python
# Informations générales
atmo.aasqa # Code AASQA
atmo.lib_zone # Nom de la zone
atmo.source # Nom de l'organisme
atmo.type_zone # 'commune' ou 'EPCI'
atmo.code_zone # Code INSEE
# Données temporelles
atmo.date_ech # Date d'échéance
atmo.date_dif # Date de diffusion
# Coordonnées
atmo.has_coordinates() # Disponibilité coordonnées
atmo.coordinates # Objet Coordinates si disponible
atmo.x_reg, atmo.y_reg # Coordonnées réglementaires
atmo.epsg_reg # Système de projection
```
#### 2. Propriétés spécifiques ATMO
```python
# Indice global
atmo.code_qual # Code qualificatif (0-7)
atmo.lib_qual # Libellé ("Bon", "Dégradé"...)
atmo.coul_qual # Couleur hexadécimale
# Codes par polluant
atmo.code_no2 # Niveau NO2
atmo.code_so2 # Niveau SO2
atmo.code_o3 # Niveau O3
atmo.code_pm10 # Niveau PM10
atmo.code_pm25 # Niveau PM2.5
# Concentrations facultatives (μg/m³)
atmo.conc_no2 # Concentration NO2
atmo.conc_so2 # Concentration SO2
atmo.conc_o3 # Concentration O3
atmo.conc_pm10 # Concentration PM10
atmo.conc_pm25 # Concentration PM2.5
```
#### 3. Méthodes helper essentielles
```python
# Qualificatif et apparence
atmo.get_qualificatif() # → "Dégradé"
atmo.get_color() # → ("#F0E641", (240, 230, 65))
atmo.get_emoji("round") # → "🟡"
atmo.get_emoji("square") # → "🟨"
# Tests de qualité
atmo.is_good_quality() # → True si niveaux 1-2
atmo.is_poor_quality() # → True si niveaux 4+
# Analyse des polluants
atmo.get_worst_pollutant() # → ("O3", 3)
atmo.get_pollutants_summary() # → Dict complet par polluant
atmo.get_concentrations() # → Dict concentrations
atmo.get_responsible_pollutants() # → ["O3"] (règle officielle)
# Conformité notice officielle
atmo.is_commune_level() # → True si type_zone='commune'
atmo.is_epci_level() # → True si type_zone='EPCI'
```
#### 4. Fonctions centralisées (base)
```python
# Émojis et couleurs par niveau
atmo.get_emoji_by_level(3, "round") # → "🟡"
atmo.get_emoji_by_level(3, "square") # → "🟨"
atmo.get_color_by_level(3) # → ("#F0E641", (240, 230, 65))
```
### Exemple de sortie
```
📍 Station sélectionnée: Tousson
🎯 ANALYSE RAPIDE:
• Qualité globale: Dégradé (niveau 3)
• Polluant problématique: ozone (niveau 3)
• Couleur d'affichage: #F0E641 🟡
📈 ANALYSE PAR POLLUANT:
• Dioxyde d'azote: 🔵 Bon (niveau 1)
• Ozone: 🟡 Dégradé (niveau 3)
• Particules PM10: 🔵 Bon (niveau 1)
```
### Usage
```bash
python demo_atmo_functions.py
```
---
## 🌸 Script 2 : `demo_pollen_functions.py`
### Description générale
Script de démonstration complet pour la classe `IndicePollen`, illustrant toutes les fonctionnalités liées aux indices pollen.
### Configuration
- **Ville testée** : Tomblaine (INSEE 54526)
- **Région** : Grand Est (AASQA 44)
- **Source de données** : API Atmo Data en temps réel
- **Date** : Jour d'exécution du script
- **Format** : GeoJSON
### Sections démonstrées
#### 1. Propriétés de base (héritées d'AtmoDataBase)
```python
# Informations générales
pollen.aasqa # Code AASQA
pollen.lib_zone # Nom de la zone
pollen.source # Nom de l'organisme
pollen.alerte # Statut d'alerte (True/False)
# Coordonnées et fonctions centralisées
pollen.has_coordinates() # Disponibilité coordonnées
pollen.get_emoji_by_level(2, "round") # → "🟢"
pollen.get_color_by_level(2) # → ("#50CCAA", (80, 204, 170))
```
#### 2. Propriétés spécifiques pollen
```python
# Codes par taxon (espèce)
pollen.code_ambr # Ambroisie (0-6)
pollen.code_arm # Armoise (0-6)
pollen.code_aul # Aulne (0-6)
pollen.code_boul # Bouleau (0-6)
pollen.code_gram # Graminées (0-6)
pollen.code_oliv # Olivier (0-6)
# Concentrations (grains/m³)
pollen.conc_ambr # Concentration ambroisie
pollen.conc_arm # Concentration armoise
pollen.conc_aul # Concentration aulne
pollen.conc_boul # Concentration bouleau
pollen.conc_gram # Concentration graminées
pollen.conc_oliv # Concentration olivier
# Taxons responsables (API)
pollen.pollen_resp # Chaîne brute de l'API
```
#### 3. Méthodes helper spécialisées
```python
# Détection d'alertes
pollen.is_alert_active() # → False
# Analyse des niveaux
pollen.get_highest_pollen() # → ("arm", 2.0)
pollen.get_highest_concentration() # → ("gram", 28.0)
pollen.get_dangerous_pollens() # → [] (niveau ≥ 4)
# Taxons responsables (parsing intelligent)
pollen.get_responsible_pollens() # → ["Armoise", "Graminées"]
# Données quantitatives
pollen.get_concentrations() # → {"gram": 28.0, "arm": 5.9, ...}
# Résumé complet avec styles d'émojis
pollen.get_pollens_summary("round") # Style rond par défaut
pollen.get_pollens_summary("square") # Style carré
```
#### 4. Structure du résumé complet
```python
summary = pollen.get_pollens_summary()
# Retourne pour chaque taxon :
{
'code': 2.0, # Niveau de pollen
'concentration': 5.9, # Grains/m³
'qualificatif': 'Faible', # Texte du niveau
'espece': 'Armoise', # Nom complet
'couleur': ('#50CCAA', (80, 204, 170)), # Hex + RGB
'emoji': '🟢', # Émoji selon style
'emoji_round': '🟢', # Émoji rond
'emoji_square': '🟩' # Émoji carré
}
```
### Exemple de sortie
```
📍 Station sélectionnée: Tomblaine
🎯 5. TAXONS RESPONSABLES DE L'INDICE (API):
• get_responsible_pollens(): ['Armoise', 'Graminées']
→ Espèces responsables selon l'API: Armoise, Graminées
🔬 3. CONCENTRATION LA PLUS ÉLEVÉE:
• get_highest_concentration(): ('gram', 28.0)
→ Espèce: Graminées
→ Concentration: 28.0 grains/m³
🎨 8. TEST DES STYLES D'ÉMOJIS:
• Comparaison des styles par défaut:
- Armoise: Rond=🟢 | Carré=🟩
- Graminées: Rond=🟢 | Carré=🟩
```
### Usage
```bash
python demo_pollen_functions.py
```
---
## 🔧 Fonctionnalités communes
### Système d'émojis unifié
Les deux scripts démontrent le système d'émojis centralisé :
```python
# Styles disponibles
"round" → 🟢 🟡 🔴 🟣 ⚫ # Formes rondes
"square" → 🟩 🟨 🟥 🟪 ⬛ # Formes carrées
# Usage dans les classes
atmo.get_emoji("round") # IndiceAtmo
pollen.get_pollens_summary("square") # IndicePollen avec style
```
### Conformité réglementaire
Les deux scripts valident la conformité avec :
- **Arrêté du 10 juillet 2020** (réglementation ATMO)
- **Notice technique du 1er avril 2025** (spécifications officielles)
- **Structure des données API** (pages 12-14 de la notice)
- **Codes couleur officiels** (tableau page 6 de la notice)
### Gestion des erreurs
```python
try:
# Connexion API
client = AtmoDataClient()
success = client.auto_login()
# Récupération données
data = client.get_indices_atmo(...)
except AtmoDataException as e:
print(f"❌ Erreur API: {e}")
except Exception as e:
print(f"❌ Erreur inattendue: {e}")
```
---
## 📋 Informations techniques
### Prérequis
- **Python 3.7+**
- **Fichier `credentials.json`** configuré
- **Connexion internet** pour l'API
- **Modules** : `atmo_data_client`, `atmo_data_models`, `constantes`
### Données utilisées
- **ATMO** : 1288+ stations Île-de-France
- **Pollen** : Données Tomblaine (Grand Est)
- **Format** : GeoJSON avec objets typés
- **Temps réel** : Date du jour d'exécution
### Structure de sortie
1. **Connexion et récupération** des données
2. **Propriétés de base** (héritées)
3. **Propriétés spécifiques** (ATMO/Pollen)
4. **Méthodes helper** (une par une)
5. **Exemples pratiques** d'utilisation
6. **Informations techniques** et conformité
### Performance
- **Temps d'exécution** : ~3-5 secondes
- **Données récupérées** : 1-1500 objets selon l'endpoint
- **Mémoire** : ~10-50 MB selon le volume
- **Connexions** : 1 session HTTP réutilisée
---
## 💡 Cas d'usage
### Pour les développeurs
- **Apprentissage** : Comprendre l'utilisation de chaque méthode
- **Tests** : Valider le bon fonctionnement des classes
- **Intégration** : Voir des exemples concrets d'usage
- **Débogage** : Identifier les problèmes potentiels
### Pour la documentation
- **Exemples vivants** : Code qui fonctionne avec vraies données
- **Référence complète** : Toutes les méthodes illustrées
- **Validation** : Preuve de conformité réglementaire
- **Formation** : Support pour apprendre l'API
### Pour les tests
- **Validation fonctionnelle** : Chaque méthode testée
- **Tests d'intégration** : API + classes + méthodes
- **Tests de régression** : Vérifier les mises à jour
- **Tests de conformité** : Respect des spécifications
---
## 🚀 Extensions possibles
### Nouvelles fonctionnalités
- **Comparaison multi-dates** : Évolution dans le temps
- **Analyse géographique** : Comparaison multi-zones
- **Export des résultats** : Sauvegarde des démonstrations
- **Mode interactif** : Choix de la zone/date par l'utilisateur
### Optimisations
- **Cache des données** : Éviter les appels répétés
- **Mode offline** : Utilisation de données pré-enregistrées
- **Parallélisation** : Récupération simultanée des données
- **Configuration** : Paramètres externalisés
---
## 📞 Support
### En cas de problème
1. **Vérifier** le fichier `credentials.json`
2. **Tester** la connexion API manuellement
3. **Contrôler** la disponibilité des données (weekend/jours fériés)
4. **Consulter** les logs d'erreurs détaillés
### Maintenance
- **Mise à jour** selon les évolutions de l'API
- **Adaptation** aux nouvelles spécifications réglementaires
- **Extension** pour de nouveaux types de données
- **Optimisation** des performances selon l'usage
---
## 📈 Script 3 : `demo_emission_functions.py`
### Description générale
Script de démonstration complet pour la classe `EmissionData`, illustrant toutes les fonctionnalités liées aux données d'émissions atmosphériques.
### Configuration
- **Zones testées** : Principales métropoles françaises (Nancy, Strasbourg, Metz, Paris, Lyon, Marseille, etc.)
- **Source de données** : Données simulées basées sur des valeurs réalistes
- **Type** : Émissions par polluant et par secteur d'activité
- **Format** : GeoJSON avec coordonnées géographiques
### Sections démonstrées
#### 1. Propriétés de base (héritées d'AtmoDataBase)
```python
# Informations générales
emission.code # Code zone (INSEE)
emission.name # Nom de la zone
emission.aasqa # Code AASQA
emission.source # Nom de l'organisme
emission.date_maj # Date de mise à jour
# Données démographiques
emission.population # Nombre d'habitants
emission.superficie # Superficie en km²
# Coordonnées géographiques
emission.has_coordinates() # Disponibilité coordonnées
emission.coordinates # Objet Coordinates
```
#### 2. Propriétés spécifiques émissions
```python
# Émissions par polluant (tonnes/an)
emission.nox # Oxydes d'azote
emission.pm10 # Particules PM10
emission.pm25 # Particules PM2.5
emission.ges # Gaz à effet de serre (CO2 eq.)
# Secteur d'activité
emission.code_pcaet # Code secteur PCAET
```
#### 3. Méthodes helper essentielles
```python
# Calculs de densité
emission.get_emission_density('nox') # → 8.36 tonnes/km²
emission.get_emission_density('pm10') # → 2.85 tonnes/km²
# Calculs par habitant
emission.get_emission_per_capita('nox') # → 0.001197 t/hab/an
emission.get_emission_per_capita('ges') # → 0.008108 t/hab/an
# Données globales
emission.get_total_emissions() # → Dict complet
emission.get_secteur_name() # → "Transport routier"
```
#### 4. Fonctions centralisées (base)
```python
# Émojis et couleurs (niveau fictif pour visualisation)
emission.get_emoji_by_level(3, "round") # → "🟡"
emission.get_color_by_level(3) # → ("#F0E641", (240, 230, 65))
```
### Exemple de sortie
```
Zone: Nancy
Population: 104,885 habitants
Superficie: 15.01 km²
Émissions totales:
- NOx: 125.5 tonnes/an
- PM10: 45.2 tonnes/an
- PM2.5: 28.7 tonnes/an
- GES: 850.3 tonnes/an
Densités d'émission par km²:
- NOx: 8.36 tonnes/km²
- PM10: 3.01 tonnes/km²
Émissions par habitant:
- NOx: 1.20 kg/hab/an
- GES: 8.11 kg/hab/an
```
### Usage
```bash
python demo_emission_functions.py
```
---
## 🚨 Script 4 : `demo_episode_functions.py`
### Description générale
Script de démonstration complet pour la classe `EpisodePollution`, illustrant toutes les fonctionnalités liées aux épisodes de pollution.
### Configuration
- **Zones testées** : Principales agglomérations françaises
- **Types d'épisodes** : Information, Recommandation, Alerte
- **Polluants** : NO2, SO2, O3, PM10, PM2.5
- **Format** : GeoJSON avec géométries variées (Point, MultiPolygon)
### Sections démonstrées
#### 1. Propriétés de base (héritées d'AtmoDataBase)
```python
# Informations générales
episode.aasqa # Code AASQA
episode.lib_zone # Zone affectée
episode.source # Nom de l'organisme
episode.date_maj # Date de mise à jour
# Informations temporelles
episode.date_dif # Date de diffusion
episode.date_ech # Date d'échéance
# Géométrie
episode.geometry # Géométrie GeoJSON
episode.has_coordinates() # Coordonnées disponibles
```
#### 2. Propriétés spécifiques épisodes
```python
# Polluant concerné
episode.code_pol # Code polluant (1-6)
episode.lib_pol # Nom polluant
episode.code_zone # Code de la zone
episode.etat # État de l'épisode
# États typiques:
# "PAS DE DEPASSEMENT"
# "PROCEDURE D'INFORMATION"
# "PROCEDURE D'INFORMATION ET DE RECOMMANDATION"
# "PROCEDURE D'ALERTE"
# "ALERTE NIVEAU 1"
```
#### 3. Méthodes helper spécialisées
```python
# Analyse des alertes
episode.is_alert_active() # → True/False
episode.get_alert_level() # → "Information"/"Alerte"/"Aucune"
# Analyse des polluants
episode.get_polluant_code() # → "PM10" (normalisé)
# Analyse géométrique
episode.is_geometry_complex() # → True si MultiPolygon
```
#### 4. Mapping des codes polluants
```python
# Codes API → Codes normalisés
'1' → 'NO2' # Dioxyde d'azote
'2' → 'SO2' # Dioxyde de soufre
'3' → 'O3' # Ozone
'5' → 'PM10' # Particules PM10
'6' → 'PM2.5' # Particules PM2.5
```
### Exemple de sortie
```
Zone affectée: Agglomération de Nancy
Polluant: PM10 (Code: 5)
Code polluant normalisé: PM10
État: PROCEDURE D'INFORMATION ET DE RECOMMANDATION
Alerte active: ✓
Niveau d'alerte: Information
Géométrie complexe: ✓
Comparaison des épisodes:
Zone Polluant Niveau Alerte État
Paris PM10 Information ✓ PROCEDURE D'INFORMATION
Lyon O3 Alerte ✓ PROCEDURE D'ALERTE
Marseille PM2.5 Alerte ✓ ALERTE NIVEAU 1
Strasbourg NO2 Aucune ✗ PAS DE DEPASSEMENT
```
### Usage
```bash
python demo_episode_functions.py
```
---
## 🔧 Fonctionnalités communes (scripts 3-4)
### Gestion des données manquantes
Les deux nouveaux scripts démontrent la robustesse face aux cas particuliers :
```python
# Cas gérés automatiquement
- Population = 0 → émission par habitant = 0
- Superficie = 0 → densité = 0
- État vide → alerte = False
- Code inconnu → valeur par défaut
- Géométrie None → coordonnées = None
```
### Calculs avancés
```python
# EmissionData
emission.get_emission_density('nox') # Densité spatiale
emission.get_emission_per_capita('ges') # Impact par habitant
emission.get_total_emissions() # Vue d'ensemble
# EpisodePollution
episode.is_alert_active() # Détection automatique
episode.get_alert_level() # Classification
episode.is_geometry_complex() # Type de zone
```
### Analyses comparatives
```python
# Comparaison inter-zones (EmissionData)
for emission in emissions:
nox_per_cap = emission.get_emission_per_capita('nox') * 1000
print(f"{emission.name}: {nox_per_cap:.1f} kg/hab/an")
# Analyse d'alertes (EpisodePollution)
alertes_actives = sum(1 for ep in episodes if ep.is_alert_active())
print(f"Alertes actives: {alertes_actives}/{len(episodes)}")
```
---
## 📋 Informations techniques mises à jour
### Couverture complète du datamodel
Les 4 scripts couvrent désormais **toutes les classes** du datamodel :
- ✅ **IndiceAtmo** : Qualité de l'air (script 1)
- ✅ **IndicePollen** : Indices pollen (script 2)
- ✅ **EmissionData** : Données d'émissions (script 3)
- ✅ **EpisodePollution** : Épisodes de pollution (script 4)
### Méthodes testées (au total)
**Classes spécialisées** : 25+ méthodes spécifiques
**Classe de base** : 8 méthodes héritées
**Propriétés** : 50+ propriétés documentées
**Cas particuliers** : 15+ scénarios de robustesse
### Types de données
- **Indices temps réel** : Qualité air + Pollen
- **Données statistiques** : Émissions par secteur
- **Alertes dynamiques** : Épisodes de pollution
- **Géométries** : Point, MultiPolygon, coordonnées
### Performance globale
- **Temps d'exécution** : 3-5 secondes par script
- **Données traitées** : 1-1500 objets selon le type
- **Mémoire** : 10-50 MB selon le volume
- **Robustesse** : Gestion complète des erreurs
---
## 💡 Cas d'usage étendus
### Analyse environnementale complète
```python
# Workflow complet avec les 4 classes
indices = get_indices_atmo(region="idf") # Qualité air actuelle
pollens = get_indices_pollen(ville="nancy") # Allergènes
emissions = get_emissions(zone="metropole") # Sources pollution
episodes = get_episodes(region="nationale") # Alertes actives
# Analyse croisée
if any(ep.is_alert_active() for ep in episodes):
# Corréler avec indices et émissions
responsible_sources = analyze_emission_sources(emissions)
current_quality = analyze_air_quality(indices)
```
### Surveillance réglementaire
```python
# Conformité notice officielle (tous scripts)
- Respect codes couleur officiels
- Validation structure données API
- Gestion coordonnées réglementaires
- Calculs selon arrêté du 10 juillet 2020
```
### Applications métier
- **Collectivités** : Surveillance qualité air + Alertes
- **Santé publique** : Pollens + Épisodes + Indices
- **Industrie** : Émissions + Conformité réglementaire
- **Recherche** : Données complètes + Analyses croisées
---
*Documentation complète pour les 4 scripts de démonstration du wrapper API Atmo Data*
*Conforme à la notice officielle du 1er avril 2025*

1433
docs/JOURNAL.md Normal file

File diff suppressed because it is too large Load diff

157
docs/QUICKSTART.md Normal file
View file

@ -0,0 +1,157 @@
# Guide de démarrage rapide
## 1. Configuration initiale
### Installer le package
```bash
# Installation depuis le repository local
pip install -e .
# Ou installation des dépendances seulement
pip install requests>=2.25.0
```
### Configurer vos credentials
```bash
# Option 1: Script automatique
python examples/setup_credentials.py
# Option 2: Manuelle
cp credentials.json.example credentials.json
# Puis éditer credentials.json avec vos identifiants
```
## 2. Test de connexion
```bash
python tests/test_real_connection.py
```
## 3. Premier script
```python
from atmo_data_wrapper import AtmoDataClient
# Connexion automatique
client = AtmoDataClient()
client.auto_login()
# Récupérer les indices ATMO d'Île-de-France
indices = client.get_indices_atmo(aasqa="11")
# Afficher les résultats
print(f"Récupéré {len(indices)} indices")
for indice in indices:
print(f"{indice.lib_zone}: {indice.get_qualificatif()}")
# Afficher la source des données (obligatoire)
from atmo_data_wrapper import get_atmo_licence
print(f"\nSource: {get_atmo_licence('courte')}")
```
## 4. Exemples disponibles
### Scripts d'introduction
- `examples/example_usage.py` - Tous les endpoints avec données brutes
- `examples/example_data_models.py` - Objets typés et méthodes helper
- `examples/example_save_files.py` - Sauvegarde en différents formats
- `examples/example_aasqa_utilities.py` - Fonctions utilitaires AASQA
- `examples/demo_licence_atmo.py` - Mentions légales et licence
### Scripts de démonstration complète
- `demos/demo_atmo_functions.py` - **Toutes les fonctionnalités IndiceAtmo**
- `demos/demo_pollen_functions.py` - **Toutes les fonctionnalités IndicePollen**
- `demos/demo_emission_functions.py` - **Toutes les fonctionnalités EmissionData**
- `demos/demo_episode_functions.py` - **Toutes les fonctionnalités EpisodePollution**
**Recommandé** : Commencer par les scripts de démonstration pour voir toutes les possibilités !
## 5. Structure des données
### Objets typés disponibles
- **IndiceAtmo** : Qualité de l'air avec helpers (couleurs, qualificatifs, émojis)
- **EpisodePollution** : Épisodes avec niveaux d'alerte et géométries
- **EmissionData** : Émissions avec calculs par habitant/km² et secteurs
- **IndicePollen** : Pollens avec détection des risques et taxons responsables
### Méthodes utiles
```python
# Qualité de l'air
indice.get_qualificatif() # "Bon", "Moyen", etc.
indice.get_color() # Couleur hex et RGB
indice.get_emoji("round") # Émojis ronds 🟢
indice.get_emoji("square") # Émojis carrés 🟩
indice.is_poor_quality() # Bool
# Pollens
pollen.get_responsible_pollens() # ["Armoise", "Graminées"]
pollen.get_pollens_summary() # Détail avec émojis
# Émissions et épisodes
emission.get_emission_per_capita('nox') # kg/hab/an
episode.get_alert_level() # "Information"/"Alerte"
# Collections
indices.get_statistics() # Stats globales
indices.filter_by_aasqa("11") # Filtrage par région
indices.filter_by_coordinates(...) # Filtrage géographique
```
## 6. Formats de sortie
- **GeoJSON** (défaut) → Objets typés avec méthodes helper
- **CSV** → Dictionnaires Python bruts
## 7. Sauvegarde
```python
# Sauvegarder les résultats
client.save_to_file(indices, "data/indices", "json")
client.save_to_file(indices, "data/indices", "csv")
client.save_to_file(indices, "data/indices", "geojson")
```
## 8. Codes utiles
### Régions (AASQA)
```python
from atmo_data_wrapper import get_aasqa_by_department, get_aasqa_info
# Trouver l'AASQA d'un département
aasqa = get_aasqa_by_department("54") # Nancy -> "44" (Grand Est)
# Infos complètes
info = get_aasqa_info("44")
print(info['organisme']) # "ATMO Grand-Est"
print(info['site_web']) # URL officielle
```
Codes principaux :
- `11` : Île-de-France (Airparif)
- `44` : Grand Est (ATMO Grand-Est)
- `93` : PACA (AtmoSud)
- `84` : Auvergne-Rhône-Alpes
### Polluants
- `NO2`, `SO2`, `O3`, `PM10`, `PM2.5`
## 9. Dépannage
```bash
# Vérifier la configuration
python tests/test_credentials_system.py
# Test complet
python tests/test_real_connection.py
# Debug d'un endpoint spécifique
python -c "
from atmo_data_wrapper import AtmoDataClient
client = AtmoDataClient()
client.auto_login()
print(client.get_indices_atmo())
"
# Exécution des tests
python -m pytest tests/
```

537
docs/README.md Normal file
View file

@ -0,0 +1,537 @@
# Wrapper Python pour l'API Atmo Data
Ce projet fournit un wrapper Python pour l'API Atmo Data ([https://admindata.atmo-france.org](https://admindata.atmo-france.org)), permettant d'accéder facilement aux données de qualité de l'air et de pollution des Associations agréées de surveillance de la qualité de lair (AASQA) françaises.
Atmo Data est un agrégateur national des données produites par les AASQA en accès libre et sous licence ODbL, géré par Atmo France ([https://www.atmo-france.org](https://www.atmo-france.org)), la Fédération des Associations agréées de surveillance de la qualité de l'air.
Elle met à disposition 6 flux agrégés sur les 4 thèmes suivants :
- [indice ATMO de la qualité de l'air](https://www.atmo-france.org/article/lindice-atmo)
- [les épisodes de pollution](https://www.atmo-france.org/article/les-episodes-de-pollution)
- les émissions à l'échelle de la région et de l'établissement public de coopération intercommunale (EPCI)
- [l'indice pollen](https://www.atmo-france.org/article/indice-pollen)
Chacun peut donc bénéficier gratuitement de ces données mises en open data sous licence ODbL, en indiquant la source "Atmo France et les Associations agréées de surveillance de la qualité de lair" ou "Atmo France / AASQA" dans sa version courte.
La documentation de l'API est disponible en ligne à l'adresse : [https://admindata.atmo-france.org/api/doc/v2](https://admindata.atmo-france.org/api/doc/v2).
La Notice technique et dinformation des données open data sur la qualité de lair disponibles sur Atmo Data (Version 1er avril 2025) est disponible en ligne à l'adresse : [https://www.atmo-france.org/sites/federation/files/medias/documents/2025-04/notice_Atmo_Data_1eravril2025.pdf](https://www.atmo-france.org/sites/federation/files/medias/documents/2025-04/notice_Atmo_Data_1eravril2025.pdf).
## Structure du projet
```
atmo-data-wrapper/
├── atmo_data_wrapper/ # Package principal
│ ├── __init__.py # Exports principaux du package
│ └── core/ # Module central
│ ├── __init__.py # Exports du module core
│ ├── client.py # Client principal pour l'API
│ ├── models.py # Classes pour les données typées
│ ├── constants.py # Constantes et configurations
│ ├── utils.py # Fonctions utilitaires
│ └── exceptions.py # Exceptions personnalisées
├── archives/ # Anciens scripts (historique)
├── examples/ # Scripts d'exemples
│ ├── __init__.py
│ ├── example_usage.py # Exemples d'utilisation des endpoints
│ ├── example_save_files.py # Exemples de sauvegarde
│ ├── example_data_models.py # Exemples avec objets typés
│ ├── example_aasqa_utilities.py # Exemples fonctions utilitaires AASQA
│ ├── example_aasqa_advanced.py # Analyses avancées AASQA
│ ├── example_synthese_nancy.py # Exemple synthèse complète
│ └── setup_credentials.py # Configuration des credentials
├── demos/ # Scripts de démonstration complète
│ ├── __init__.py
│ ├── demo_atmo_functions.py # Démonstration complète IndiceAtmo
│ ├── demo_pollen_functions.py # Démonstration complète IndicePollen
│ ├── demo_emission_functions.py # Démonstration complète EmissionData
│ ├── demo_licence_atmo.py # Démonstration licence Atmo France
│ └── demo_episode_functions.py # Démonstration complète EpisodePollution
├── tests/ # Tests unitaires
│ ├── __init__.py
│ ├── test_validations.py # Tests de validation
│ ├── test_save_functionality.py # Tests de sauvegarde
│ ├── test_typed_client.py # Tests d'intégration modèles
│ ├── test_real_connection.py # Test de connexion réelle à l'API
│ └── test_credentials_system.py # Tests du système de credentials
├── docs/ # Documentation
│ ├── README.md # Documentation principale
│ ├── QUICKSTART.md # Guide de démarrage rapide
│ ├── DOCUMENTATION_DEMOS.md # Documentation des scripts de démonstration
│ ├── JOURNAL.md # Journal de développement
│ ├── notice_Atmo_Data_1eravril2025.md # Notice officielle API
│ └── swagger.json # Spécification API
├── credentials.json.example # Modèle de fichier credentials
├── credentials.json # Vos identifiants (à créer, ignoré par git)
├── setup.py # Configuration du package
├── pyproject.toml # Configuration moderne du package
├── requirements.txt # Dépendances de production
├── requirements-dev.txt # Dépendances de développement
├── MANIFEST.in # Fichiers à inclure dans le package
├── LICENSE # Licence MIT
└── .gitignore # Fichiers à ignorer par git
```
## Installation
### Installation depuis le repository local
```bash
# Cloner ou télécharger le project
git clone https://github.com/atmo-france/atmo-data-wrapper.git
cd atmo-data-wrapper
# Installation en mode développement
pip install -e .
# Ou installation normale
pip install .
```
### Dépendances
Le package nécessite Python 3.7+ et les dépendances suivantes :
```bash
pip install requests>=2.25.0
```
### Installation des dépendances de développement
```bash
pip install -r requirements-dev.txt
```
## Configuration des credentials
### 0. Pré requis : Demander l'autorisation
L'accès aux données requiert l'autorisation d'un d'administrateur de l'application API Atmo Data. Vous pouvez réaliser une demande de création de compte à cette adresse : https://admindata.atmo-france.org/inscription-api.
Pour vous connecter à l'API Atmo Data, vous devez créer un fichier de configuration avec vos identifiants.
### 1. Créer le fichier credentials.json
```bash
# Copier le fichier exemple
cp credentials.json.example credentials.json
# Éditer avec vos identifiants
nano credentials.json
```
### 2. Format du fichier credentials.json
```json
{
"username": "votre_nom_utilisateur",
"password": "votre_mot_de_passe",
"api_url": "https://api.atmo-data.org"
}
```
**Important** :
- Le fichier `credentials.json` est ajouté au `.gitignore` pour éviter de commiter vos identifiants
- Remplacez les valeurs par vos vrais identifiants fournis par Atmo Data
- L'URL de l'API peut être modifiée si nécessaire
## Utilisation
### Authentification
#### Méthode recommandée : Fichier credentials.json
```python
from atmo_data_wrapper import AtmoDataClient, AASQA_CODES, POLLUANTS
# Connexion automatique avec credentials.json
client = AtmoDataClient()
client.auto_login() # Utilise automatiquement credentials.json
```
## Fonctions utilitaires AASQA
Le wrapper fournit des fonctions utilitaires pour faciliter la manipulation des codes AASQA et la recherche d'organismes :
```python
from atmo_data_wrapper import (
get_aasqa_by_department,
get_aasqa_info,
search_aasqa_by_name,
get_departments_count,
validate_department_coverage,
get_aasqa_statistics
)
# Trouver l'AASQA d'un département
aasqa_code = get_aasqa_by_department("54") # Nancy
print(f"Département 54 -> AASQA {aasqa_code}") # "44" (Grand Est)
# Informations complètes d'une AASQA
info = get_aasqa_info("44")
print(f"Organisme: {info['organisme']}") # "ATMO Grand-Est"
print(f"Site web: {info['site_web']}") # URL officielle
print(f"Départements: {info['departements']}") # Liste des départements
# Recherche par nom
resultats = search_aasqa_by_name("Atmo")
for r in resultats:
print(f"{r['organisme']} - {r['region']}")
# Statistiques
stats = get_aasqa_statistics()
print(f"Nombre total d'AASQA: {stats['total_aasqa']}")
print(f"Couverture moyenne: {stats['average_coverage']:.1f} départements/AASQA")
```
## Licence et mentions légales
Conformément aux exigences d'Atmo France, le wrapper fournit des fonctions pour afficher les mentions légales requises :
```python
from atmo_data_wrapper import get_atmo_licence, print_atmo_licence
# Version courte (recommandée)
print(get_atmo_licence("courte"))
# "Atmo France / AASQA"
# Version longue (officielle)
print(get_atmo_licence("longue"))
# "Atmo France et les Associations agréées de surveillance de la qualité de l'air"
# Version complète avec licence ODbL
print_atmo_licence("complete")
# Affiche les détails complets de la licence
# Utilisation dans un script
data = client.get_indices_atmo()
print(f"Source: {get_atmo_licence('courte')}")
```
#### Méthode alternative : Identifiants directs
```python
# Connexion avec identifiants fournis directement
client = AtmoDataClient()
client.login("votre_username", "votre_password")
# Ou mélange des deux (override du fichier)
client.login(username="autre_user") # password vient du fichier
```
### Récupération des indices ATMO
```python
# Indices d'aujourd'hui
indices = client.get_indices_atmo()
# Indices d'une date spécifique
indices = client.get_indices_atmo(date="2024-06-08")
# Indices pour une région spécifique (utilisation des constantes)
indices = client.get_indices_atmo(aasqa="11") # AASQA_CODES['11'] = Île-de-France
```
### Épisodes de pollution
```python
# Épisodes en cours (3 jours)
episodes = client.get_episodes_3jours()
# Épisodes historiques
episodes = client.get_episodes_historique(date="2024-06-08")
# Filtre par polluant (utilisation des constantes)
episodes = client.get_episodes_3jours(polluant=POLLUANTS[2]) # PM10
```
### Données d'émissions
```python
# Émissions par région
emissions = client.get_emissions(echelle="region")
# Émissions par EPCI
emissions = client.get_emissions(echelle="epci", aasqa="11")
```
### Indices pollen
```python
# Indices pollen actuels
pollens = client.get_indices_pollens()
# Avec alertes uniquement
pollens = client.get_indices_pollens(alerte=True)
```
## Objets typés et modèles de données
Le wrapper utilise des objets typés pour faciliter l'exploitation des données. Chaque type de données retourné par l'API est représenté par une classe spécialisée avec des méthodes helper.
### Types de données disponibles
- **IndiceAtmo** : Indices de qualité de l'air ATMO (0-7)
- **EpisodePollution** : Épisodes de pollution atmosphérique
- **EmissionData** : Données d'inventaires des émissions
- **IndicePollen** : Indices polliniques (0-6)
- **AtmoDataCollection** : Collection gérant plusieurs objets
### Utilisation avec objets typés
```python
from atmo_data_wrapper import AtmoDataClient, Coordinates
client = AtmoDataClient()
client.auto_login() # Connexion avec credentials.json
# Les données GeoJSON retournent des objets typés
indices = client.get_indices_atmo(aasqa="11") # Retourne AtmoDataCollection
# Parcourir les données avec méthodes helper
for indice in indices:
print(f"Zone: {indice.lib_zone}")
print(f"Qualité: {indice.get_qualificatif()}")
print(f"Couleur: {indice.get_color()[0]}") # Couleur hex
if indice.is_poor_quality():
worst_pol, code = indice.get_worst_pollutant()
print(f"Attention: {worst_pol} élevé ({code})")
# Statistiques sur la collection
stats = indices.get_statistics()
print(f"Qualité moyenne: {stats['quality_stats']['moyenne']:.1f}")
# Filtrage géographique
paris = Coordinates(2.3522, 48.8566)
nearby = indices.filter_by_coordinates(paris, radius_km=20)
```
### Classes et méthodes disponibles
#### IndiceAtmo
- `get_qualificatif()` : Qualificatif textuel (Bon, Moyen, etc.)
- `get_color()` : Couleur hex et RGB associée
- `is_good_quality()` / `is_poor_quality()` : Tests de qualité
- `get_worst_pollutant()` : Polluant le plus problématique
- `get_pollutants_summary()` : Résumé de tous les polluants
#### EpisodePollution
- `is_alert_active()` : Vérifie si une alerte est en cours
- `get_alert_level()` : Niveau d'alerte (Information/Alerte/Aucune)
- `get_polluant_code()` : Code du polluant principal
#### EmissionData
- `get_emission_density(polluant)` : Densité d'émission par km²
- `get_emission_per_capita(polluant)` : Émission par habitant
- `get_total_emissions()` : Toutes les émissions
- `get_secteur_name()` : Nom du secteur d'émission
#### IndicePollen
- `is_alert_active()` : Alerte pollen active
- `get_highest_pollen()` : Espèce avec l'indice le plus élevé
- `get_dangerous_pollens()` : Liste des pollens à risque élevé
- `get_pollens_summary()` : Détail par espèce avec émojis
- `get_responsible_pollens()` : Taxons responsables selon l'API
#### AtmoDataCollection
- `filter_by_aasqa(code)` : Filtrage par région
- `filter_by_coordinates(center, radius)` : Filtrage géographique
- `get_statistics()` : Statistiques de la collection
- `to_summary()` : Résumé textuel
## API Endpoints
- `get_indices_atmo()` - Indices de qualité de l'air ATMO
- `get_episodes_3jours()` - Épisodes de pollution sur 3 jours
- `get_episodes_historique()` - Épisodes de pollution historiques
- `get_emissions()` - Inventaires des émissions
- `get_indices_pollens()` - Indices pollen
## Codes AASQA
Le wrapper fournit des constantes enrichies avec sites web et départements couverts :
- 01: Guadeloupe (Gwad'Air) - Département 971
- 02: Martinique (Madininair) - Département 972
- 03: Guyane (Atmo Guyane) - Département 973
- 04: La Réunion (Atmo Réunion) - Département 974
- 06: Mayotte (Hawa Mayotte) - Département 976
- 11: Île-de-France (Airparif) - Départements 75, 77, 78, 91, 92, 93, 94, 95
- 24: Centre-Val de Loire (Lig'Air) - Départements 18, 28, 36, 37, 41, 45
- 27: Bourgogne-Franche-Comté (Atmo BFC) - Départements 21, 25, 39, 58, 70, 71, 89, 90
- 28: Normandie (Atmo Normandie) - Départements 14, 27, 50, 61, 76
- 32: Hauts-de-France (Atmo HDF) - Départements 02, 59, 60, 62, 80
- 44: Grand Est (ATMO Grand-Est) - Départements 08, 10, 51, 52, 54, 55, 57, 67, 68, 88
- 52: Pays de la Loire (Air Pays de la Loire) - Départements 44, 49, 53, 72, 85
- 53: Bretagne (Air Breizh) - Départements 22, 29, 35, 56
- 75: Nouvelle-Aquitaine (Atmo NA) - Départements 16, 17, 19, 23, 24, 33, 40, 47, 64, 79, 86, 87
- 76: Occitanie (Atmo Occitanie) - Départements 09, 11, 12, 30, 31, 32, 34, 46, 48, 65, 66, 81, 82
- 84: Auvergne-Rhône-Alpes (Atmo AURA) - Départements 01, 03, 07, 15, 26, 38, 42, 43, 63, 69, 73, 74
- 93: Provence-Alpes-Côte d'Azur (AtmoSud) - Départements 04, 05, 06, 13, 83, 84
- 94: Corse (Qualitair) - Départements 2A, 2B
Accès programmatique :
```python
from atmo_data_wrapper import AASQA_CODES
info = AASQA_CODES['44']
print(f"Site web: {info['site_web']}")
print(f"Départements: {info['departements']}")
```
## Gestion des erreurs
Le wrapper utilise des exceptions personnalisées pour gérer différents types d'erreurs :
```python
from atmo_data_wrapper import AtmoDataClient, AtmoDataException
try:
client = AtmoDataClient()
client.auto_login()
indices = client.get_indices_atmo()
except ValueError as e:
print(f"Erreur de validation: {e}")
except AtmoDataException as e:
print(f"Erreur API: {e}")
except Exception as e:
print(f"Erreur inattendue: {e}")
```
### Types d'exceptions disponibles
- `AtmoDataException` : Exception de base
- `AuthenticationError` : Erreur d'authentification
- `ValidationError` : Erreur de validation des paramètres
- `APIError` : Erreur de l'API Atmo Data
- `NetworkError` : Erreur de réseau
- `DataError` : Erreur dans le traitement des données
## Validation des paramètres
Le wrapper valide automatiquement tous les paramètres avant d'envoyer les requêtes :
- **Formats** : Seuls `geojson` et `csv` sont acceptés
- **Codes AASQA** : Validation contre la liste des codes valides (01-94)
- **Polluants** : Validation contre la liste des polluants supportés
- **Dates** : Validation du format YYYY-MM-DD et de l'existence de la date
- **Indices** : Validation des codes qualificatifs ATMO (0-7) et pollen (0-6)
- **Bounding box** : Validation du format et de la cohérence des coordonnées
Exemple d'erreur de validation :
```python
try:
client.get_indices_atmo(format="xml") # Format invalide
except ValueError as e:
print(e) # "Format invalide: xml. Formats valides: ['geojson', 'csv']"
```
## Sauvegarde des données
Le wrapper permet de sauvegarder facilement les résultats de l'API dans différents formats :
```python
# Récupérer des données
indices = client.get_indices_atmo(aasqa="11")
# Sauvegarder en JSON
json_file = client.save_to_file(indices, "data/indices_atmo", "json")
# Sauvegarder en CSV
csv_file = client.save_to_file(indices, "data/indices_atmo", "csv")
# Sauvegarder en GeoJSON
geojson_file = client.save_to_file(indices, "data/indices_atmo", "geojson")
```
### Formats supportés pour la sauvegarde :
- `json` - Format JSON standard
- `csv` - Format CSV avec extraction automatique des propriétés
- `geojson` - Format GeoJSON (données géographiques)
### Fonctionnalités :
- **Création automatique de répertoires** : Les dossiers parents sont créés si nécessaire
- **Extensions automatiques** : Les extensions (.json, .csv, .geojson) sont ajoutées automatiquement
- **Extraction CSV intelligente** : Conversion automatique des données GeoJSON vers CSV avec coordonnées
- **Validation des formats** : Vérification de la compatibilité des données avec le format choisi
## Formats de sortie API
L'API supporte deux formats :
- `geojson` (par défaut)
- `csv`
## Tests et Exemples
### Scripts d'exemples
- `example_usage.py` - Exemples d'utilisation des endpoints (données brutes)
- `example_save_files.py` - Exemples de sauvegarde de données
- `example_data_models.py` - Exemples avec objets typés et méthodes helper
- `example_aasqa_utilities.py` - Exemples des fonctions utilitaires AASQA
- `example_aasqa_advanced.py` - Analyses avancées et statistiques AASQA
- `demo_licence_atmo.py` - Démonstration des fonctions de licence
- `example_synthese_tomblaine.py` - Exemple de synthèse complète (Atmo + Pollen)
### Scripts de démonstration complète
- `demo_atmo_functions.py` - **Démonstration complète de la classe IndiceAtmo**
- `demo_pollen_functions.py` - **Démonstration complète de la classe IndicePollen**
- `demo_emission_functions.py` - **Démonstration complète de la classe EmissionData**
- `demo_episode_functions.py` - **Démonstration complète de la classe EpisodePollution**
Ces scripts illustrent **toutes les fonctionnalités** de chaque classe avec des données réelles de l'API. Voir `DOCUMENTATION_DEMOS.md` pour une documentation détaillée.
### Scripts de test
- `test_validations.py` - Tests de validation des paramètres
- `test_save_functionality.py` - Tests de sauvegarde de fichiers
- `test_typed_client.py` - Tests d'intégration des modèles typés
- `test_real_connection.py` - Test de connexion réelle à l'API
### Test de votre configuration
```bash
# Vérifier la configuration et tester la connexion
python tests/test_real_connection.py
```
Ce script vérifie :
- La présence et validité du fichier `credentials.json`
- La connexion à l'API
- Le bon fonctionnement des différents endpoints
- Les objets typés et leurs méthodes
### Exécution des scripts
```bash
# Scripts d'exemples
python examples/example_usage.py
python examples/example_data_models.py
python examples/example_aasqa_utilities.py
python examples/demo_licence_atmo.py
# Scripts de démonstration
python demos/demo_atmo_functions.py
python demos/demo_pollen_functions.py
# Tests
python -m pytest tests/
```
## Nouvelles fonctionnalités
### Architecture améliorée
- **Séparation des constantes et utilitaires** : Les constantes sont dans `constants.py`, les fonctions utilitaires dans `utils.py`
- **Constantes enrichies** : Les codes AASQA incluent maintenant sites web et départements
- **Mapping des codes** : Constantes séparées pour les épisodes de pollution et les taxons de pollens
### Fonctions utilitaires AASQA
- Recherche par département ou nom d'organisme
- Statistiques de couverture territoriale
- Validation de l'intégrité des données
- Analyses comparatives entre organismes
### Conformité légale
- Fonctions dédiées pour les mentions légales Atmo France
- Respect de la licence ODbL
- Intégration facilitée dans rapports et applications
### Organisation du projet
- Dossier `archives/` pour l'historique des anciens scripts
- Structure claire et maintenable
- Documentation complète et à jour

View file

@ -0,0 +1,379 @@
# Notice Technique - Indice ATMO
**Guide de calcul en application de l'arrêté du 10 juillet 2020**
---
## Informations générales
- **Version** : 14 décembre 2020
- **Organisme** : Atmo France
- **Contact** : contact@atmo-france.org
- **Site web** : http://www.atmo-france.org
- **Adresse** : 7 rue Crillon
- **Téléphone** : 09 72 62 73 95
---
## Table des matières
1. [Préambule](#préambule)
2. [Historique mise en place](#1-historique--mise-en-place)
3. [Définitions](#2-définitions)
4. [Objectifs de l'indice ATMO](#3-objectifs-de-lindice-atmo)
5. [Règles de calcul de l'indice ATMO](#4-règles-de-calcul-de-lindice-atmo)
6. [Limites de l'indice](#5-limites-de-lindice)
7. [Annexes](#annexes)
---
## Préambule
L'indice ATMO est un indicateur journalier qualificatif de la qualité de l'air. Il se décline en six qualificatifs définis selon différentes classes pour cinq polluants : « bon », « moyen », « dégradé », « mauvais », « très mauvais », « extrêmement mauvais ».
Il intègre les polluants réglementés que l'on rencontre au quotidien :
- Les particules en suspension (PM₁₀ et PM₂.₅)
- Le dioxyde d'azote (NO₂)
- L'ozone (O₃)
- Le dioxyde de soufre (SO₂)
### Caractéristiques principales
- **Calcul obligatoire** sur l'ensemble du territoire français (France métropolitaine et outre-mer)
- **Périmètre géographique** ne pouvant dépasser celui de l'établissement public de coopération intercommunale (EPCI)
- **Zone plus fine** à l'échelle de la commune possible
- **Représentation simplifiée** de la qualité de l'air quotidienne en situation « de fond »
- **Calcul par les AASQA** à partir de données de modélisation, météorologiques, d'inventaire des émissions et d'observation
### Base réglementaire
Les modalités de calcul de cet indice sont précisées dans l'arrêté du 10 juillet 2020 relatif à l'indice de la qualité de l'air ambiant.
---
## 1) Historique mise en place
### Création et évolution
L'indice ATMO réglementaire a été créé en **1994** à l'initiative du ministère chargé de l'Environnement et de plusieurs Associations agréées de surveillance de la qualité de l'air (AASQA).
### Base légale
- **Article R 221-5** du code de l'environnement : prévoit la mise à disposition de l'indice de la qualité de l'air
- **Arrêté du 10 janvier 2000** : rend obligatoire le calcul de l'indice Atmo sur tout le territoire national
- **Arrêté du 22 juillet 2004** : remplace l'arrêté de 2000, modifié par l'arrêté du 21 décembre 2011
- **Arrêté du 10 juillet 2020** : abroge l'arrêté du 22 juillet 2004 et constitue la base actuelle
### Processus de révision
La révision de l'indice ATMO a été alimentée par une réflexion menée au sein d'un groupe de travail mandaté par le ministère en charge de l'Environnement en février 2018, piloté par Atmo France, et rassemblant :
- L'ensemble des AASQA
- Le Bureau de la qualité de l'air (BQA)
- Le Service de la donnée et des études statistiques (SDES) de la DGEC
### Alignement européen
Ce nouvel indice ATMO a été conçu comme une déclinaison de l'indice horaire de l'Agence européenne pour l'environnement, avec :
- Un mode de calcul différent pour fournir un indice journalier
- Une information sur l'ensemble du territoire (pas uniquement à la station)
- Une méthode d'agrégation spatiale grâce à la modélisation
---
## 2) Définitions
### Termes techniques
**Modèle méso-échelle** : Modèle fonctionnant sur un domaine de plusieurs centaines de kilomètres et dont la résolution de l'ordre de quelques kilomètres permet d'évaluer la qualité de l'air en situation de fond.
**Modèle fine échelle** : Modèle caractérisé par une résolution de l'ordre de quelques dizaines de mètres permettant l'évaluation de la qualité de l'air en proximité des sources (ex: trafic routier).
### Échéances temporelles
Les modèles de dispersion atmosphérique effectuent des calculs pour plusieurs échéances :
- **j-1** : la veille
- **j0** : le jour-même
- **j+1** : le lendemain
- **j+2** : le surlendemain
### Types de données
**Donnée assimilée** : Résulte de la combinaison des résultats de simulation et des observations pour limiter l'incertitude.
**Prévision statistique** : Révision issue de la correction statistique des simulations pour corriger les biais systématiques identifiés. Ce post-traitement utilise notamment les dernières mesures disponibles.
---
## 3) Objectifs de l'indice ATMO
Les objectifs de cet indice sont les suivants :
1. **Outil de communication** permettant de fournir une information synthétique sous une forme simple (couleur + qualificatif)
2. **Facilement compréhensible** par le grand public
3. **Qualifier la qualité de l'air** en situation de fond (pollution à laquelle personne n'échappe)
4. **Prévision** pour les journées J et J+1 a minima
5. **Couverture complète** de la zone de compétence de l'AASQA pour chacune de ses communes ou EPCI
---
## 4) Règles de calcul de l'indice ATMO
L'indice est calculé chaque jour. Il caractérise l'état de la qualité de l'air à l'échelle spatiale que l'AASQA aura jugée représentative. L'indice ATMO est diffusé soit à la commune, soit à l'EPCI, en fonction de ce que chaque AASQA considère pertinent sur son territoire.
### 4.1) Règle n°1 : Polluants concernés
Cinq polluants sont utilisés pour construire cet indice :
- **PM₂.₅** : Particules fines < 2.5 microns
- **PM₁₀** : Particules fines < 10 microns
- **O₃** : Ozone
- **NO₂** : Dioxyde d'azote
- **SO₂** : Dioxyde de soufre
### 4.2) Règle n°2 : Période prise en compte
- L'indice ATMO caractérise un état global de la qualité de l'air prévu sur **une journée**
- Calculé pour **24h** avec heure de départ à **0h TU**
- Diffusion quotidienne au plus tard à **12h (heure locale)** avec tolérance à 14h en cas de difficulté
### 4.3) Règle n°3 : Échelles des sous-indices
Un qualificatif est attribué à chaque polluant selon sa concentration. L'indice ATMO de la zone correspond au **qualificatif le plus dégradé**.
#### Tableau des seuils et qualificatifs
| Qualificatif | PM₂.₅ (μg/m³) | PM₁₀ (μg/m³) | NO₂ (μg/m³) | O₃ (μg/m³) | SO₂ (μg/m³) |
|--------------|---------------|--------------|-------------|------------|-------------|
| **Bon** | 0-10 | 0-20 | 0-40 | 0-50 | 0-100 |
| **Moyen** | 11-20 | 21-40 | 41-90 | 51-100 | 101-200 |
| **Dégradé** | 21-25 | 41-50 | 91-120 | 101-130 | 201-350 |
| **Mauvais** | 26-50 | 51-100 | 121-230 | 131-240 | 351-500 |
| **Très mauvais** | 51-75 | 101-150 | 231-340 | 241-380 | 501-750 |
| **Extrêmement mauvais** | >75 | >150 | >340 | >380 | >750 |
#### Codes couleur des qualificatifs
| Qualificatif | R | G | B | Hexadécimal |
|--------------|---|---|---|-------------|
| **Bon** | 80 | 240 | 230 | #50F0E6 |
| **Moyen** | 80 | 204 | 170 | #50CCAA |
| **Dégradé** | 240 | 230 | 65 | #F0E641 |
| **Mauvais** | 255 | 80 | 80 | #FF5050 |
| **Très mauvais** | 150 | 0 | 50 | #960032 |
| **Extrêmement mauvais** | 135 | 33 | 129 | #872181 |
#### Codes supplémentaires
| Qualificatif | R | G | B | Hexadécimal | Usage |
|--------------|---|---|---|-------------|-------|
| **Indisponible** | 221 | 221 | 221 | #DDDDDD | Absence de données |
| **Événement** | 136 | 136 | 136 | #888888 | Incident/accident |
### 4.4) Règle n°4 : Calcul de l'indice ATMO
#### Méthodologie préférentielle
Le calcul est réalisé **préférentiellement par modélisation** pour permettre une couverture complète du territoire pour J0 et J+1. À défaut, la mesure de fond peut être utilisée si elle est représentative.
#### Modèles méso-échelles (recommandés)
**Étapes de calcul** :
1. **En chaque point du modèle** : détermination du qualificatif et du/des polluant(s) responsable(s)
2. **Sélection des points** intersectant chaque commune
3. **Sélection du qualificatif le plus dégradé** parmi ceux calculés sur la commune
**Pour les communes sans point modèle** :
- Utiliser la valeur du point modèle le plus proche
- Sur-échantillonner le maillage sans interpolation
- Toute autre méthode garantissant la représentativité de fond
#### Calcul à l'EPCI
L'indice EPCI correspond à **l'indice communal le plus élevé** de l'EPCI.
### 4.5) Règle n°5 : Représentativité de la zone géographique
La représentativité spatiale de référence est donnée par les **stations de mesure de fond**. Selon la réglementation, les points de prélèvement sont représentatifs de plusieurs kilomètres carrés.
L'assimilation des données de ces stations et les prévisions statistiques associées doivent garantir la représentativité des résultats des modèles méso-échelles.
### 4.6) Règle n°6 : EPCI répartie entre deux régions
Les AASQA concernées par des EPCI à cheval entre deux régions se concertent pour une **communication cohérente**.
### 4.7) Règle n°7 : Calcul pour la veille
En cas de calcul d'un indice pour la veille (J-1), les données doivent s'appuyer sur des **données modélisées assimilées** (données brutes post-traitées pour intégrer les observations aux stations).
### 4.8) Règle n°8 : Diffusion et historique
#### Obligations de diffusion
Chaque AASQA doit publier les indices ATMO quotidiennement :
- **Flux WMS ou CSV** sur sa plateforme open data
- **Site internet** de l'AASQA
- **Informations obligatoires** : qualificatif, couleur, polluant(s) majoritaire(s)
#### Historique
En cas de calcul d'indice pour la veille, un **historique d'un an** de données en plus de l'année en cours est mis à disposition.
### 4.9) Règle n°9 : Événements spécifiques
En cas d'incident ou d'accident engendrant des émissions atmosphériques spécifiques rendant l'indice non représentatif, l'AASQA :
- **Informe** que l'indice n'est pas représentatif
- **Intègre** cette information dans le flux open data avec couleur et qualificatif spécifique (code "événement")
### 4.10) Règle n°10 : Cas particulier du SO₂
Lorsque l'AASQA mesure des niveaux importants de SO₂, notamment en cas d'incident industriel, elle peut :
- **Appliquer la règle n°9** (code événement)
- **Expertiser la situation** avec tous les outils disponibles et faire évoluer le sous-indice SO₂ en conséquence
---
## 5) Limites de l'indice
### Objectif et portée
L'indice ATMO permet de fournir une **information synthétique** sur la qualité globale de l'air de fond d'un territoire, dans l'état actuel des connaissances et de la réglementation.
### Ce que l'indice ne fait PAS
- **Ne caractérise pas** la qualité de l'air à proximité immédiate de sources fixes ou mobiles de pollution
- **Ne remplace pas** l'information spécifique lors des dépassements de seuils réglementaires
- **N'est pas adapté** pour les études épidémiologiques ou statistiques (utiliser les concentrations d'origine)
- **Ne rend pas compte** de la pollution cumulée sur de longues périodes (basé sur les seuils d'effet à court terme)
---
## Annexes
### Description du jeu de données - Indice ATMO 2021
#### Métadonnées générales
- **Jeu de données** : Indice Atmo de la qualité de l'air
- **Version** : 2021
- **Thème Inspire** : Zone de pollution potentielle
- **Résolution temporelle** : Jour
- **Résolution spatiale** : Commune ou EPCI
- **Fréquence de mise à jour** : Quotidienne à 14H locales
- **Profondeur des données** : Année N-1 complète + année en cours jusqu'à J+1 (voire J+2)
- **Licence** : ODbL 1.0 - Open Database Licence
#### Structure des flux de données
##### Flux WFS (obligatoire)
- **Type** : 1 seul WFS, 1 seule couche
- **Granularité** : Par commune ou EPCI sur la région
- **Polluants** : Tous dans la même couche
- **Profondeur** : N-1 et N jusqu'à J+1
- **Nom recommandé** : `ind_<région>` (ex: `ind_bretagne`)
##### Flux CSV (de secours)
- **Type** : 1 seul CSV, 1 seule table
- **Usage** : Obligatoire seulement si problème technique pour le WFS
- **Structure** : Identique au WFS
#### Champs obligatoires
| Nom du champ | Type | Description | Exemple |
|--------------|------|-------------|---------|
| **date_ech** | Date ISO 8601 | Date de valeur de l'indice (TU) | 2021-12-31T00:00:00Z |
| **code_qual** | Int | Classe de l'indice (1-6, 0 si absent, 7 si événement) | 1 |
| **lib_qual** | Varchar | Qualificatif textuel | Bon |
| **coul_qual** | Varchar | Couleur hexadécimale | #50F0E6 |
| **date_dif** | Date ISO 8601 | Date de diffusion (TU) | 2021-12-31T00:00:00Z |
| **source** | Varchar | Nom public de l'AASQA | Atmo Auvergne-Rhône-Alpes |
| **type_zone** | Varchar | Type de zone [commune, EPCI] | commune |
| **code_zone** | Varchar | Code commune INSEE ou code EPCI INSEE | 59350 |
| **lib_zone** | Varchar | Libellé commune ou EPCI | Marseille |
#### Codes par polluant
| Nom du champ | Type | Description | Exemple |
|--------------|------|-------------|---------|
| **code_no2** | Int | Classe sous-indice NO₂ (1-6, 0 si absent, 7 si événement) | 1 |
| **code_so2** | Int | Classe sous-indice SO₂ (1-6, 0 si absent, 7 si événement) | 2 |
| **code_o3** | Int | Classe sous-indice O₃ (1-6, 0 si absent, 7 si événement) | 3 |
| **code_pm10** | Int | Classe sous-indice PM₁₀ (1-6, 0 si absent, 7 si événement) | 4 |
| **code_pm25** | Int | Classe sous-indice PM₂.₅ (1-6, 0 si absent, 7 si événement) | 5 |
#### Coordonnées
| Nom du champ | Type | Description | Exemple |
|--------------|------|-------------|---------|
| **x_wgs84** | Float | Coordonnées en WGS84 EPSG:4326 | 3.0 |
| **y_wgs84** | Float | Coordonnées en WGS84 EPSG:4326 | 50.0 |
| **x_reg** | Float | Coordonnées réglementaires | 760889 |
| **y_reg** | Float | Coordonnées réglementaires | 6999650 |
| **epsg_reg** | Varchar | Système de projection réglementaire | 2154 |
| **geom** | Géométrie | Géométrie ponctuelle WKB | - |
#### Champs facultatifs - Concentrations
| Nom du champ | Type | Description |
|--------------|------|-------------|
| **conc_no2** | Int | Concentration de NO₂ en μg/m³ |
| **conc_so2** | Int | Concentration de SO₂ en μg/m³ |
| **conc_o3** | Int | Concentration d'O₃ en μg/m³ |
| **conc_pm10** | Int | Concentration de PM₁₀ en μg/m³ |
| **conc_pm25** | Int | Concentration de PM₂.₅ en μg/m³ |
#### Clé primaire
`date_ech` + `code_zone`
#### Exemple de gestion des versions
```
Je publie l'indice du 07-08-2020 en J+1 :
date_ech = 07-08-2020, date_diff = 06-08-2020
Je publie l'indice du 07-08-2020 en J+0 :
date_ech = 07-08-2020, date_diff = 07-08-2020
(remplace les valeurs précédentes)
Je publie l'indice du 07-08-2020 en J-1 (observé) :
date_ech = 07-08-2020, date_diff = 08-08-2020
(remplace les valeurs précédentes)
```
### Proposition méthodologique pour la représentativité
Pour analyser et garantir la représentativité spatiale des indices, il est proposé de comparer sur une année complète de données J-1 assimilées :
#### Méthodologie 1 (règle officielle)
**Indice du point modèle maximum** : Sélection de l'indice le plus dégradé parmi l'ensemble des points du modèle intersectant la commune.
#### Méthodologie 2 (validation)
**Comptage des points** : L'indice ayant le plus grand nombre de points du modèle intersectant la commune devient l'indice de la commune.
#### Méthodologie 3 (validation)
**Superficie pondérée** : Calcul par indice de la superficie cumulée intersectée entre les mailles du modèle et la commune. L'indice présentant la superficie la plus grande devient l'indice de la commune.
L'obtention de **résultats proches** entre ces méthodologies permet de valider l'échelle de diffusion retenue.
---
## Rédacteurs et validation
### Rédacteurs
- Yann Channac Mongredien (AtmoSud)
- Carole Flambard (Lig'Air)
- Delphine Guillaume (Atmo France)
- Jérôme Le Paih (ATMO Grand Est)
- Nathalie Pujol-Söhne (Atmo Hauts-de-France)
- Jérôme Rangognio (Lig'Air)
- Marine Tondelier (Atmo France)
- Romain Vidaud (Atmo Auvergne-Rhône-Alpes)
- Abderrazak Yahyaoui (Lig'Air)
### Relecteurs
- Cédric Messier, Julien Rude et Pascale Vizy (Bureau de la qualité de l'air / Ministère de la Transition écologique)
- Laurence Rouil (Ineris)
### Validation
**Validé en Comité de pilotage de surveillance le 15 décembre 2020**
---
*Document officiel - Atmo France - Version du 14 décembre 2020*

Binary file not shown.

1
docs/swagger.json Normal file

File diff suppressed because one or more lines are too long