Skip to content

Commit 159eb3d

Browse files
committed
WINTEM, TEMSI FRANCE and TEMSI EUROC support
1 parent 8989ccd commit 159eb3d

File tree

5 files changed

+220
-111
lines changed

5 files changed

+220
-111
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
releases/
22
csv/
3+
pdf/
34

45
config-dev.ini

METAR_TAF_logger.py

-104
This file was deleted.

README.md

+57-6
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
# Weather Logger
22

33
## About
4-
Simple Python script to log [METAR](https://en.wikipedia.org/wiki/METAR) and [TAF](https://en.wikipedia.org/wiki/Terminal_aerodrome_forecast) weather reports from [aviation.meteo.fr](https://aviation.meteo.fr) XML API to CSV files.
4+
Simple Python script to log [METAR](https://en.wikipedia.org/wiki/METAR) and [TAF](https://en.wikipedia.org/wiki/Terminal_aerodrome_forecast) weather reports from [aviation.meteo.fr](https://aviation.meteo.fr) XML API to CSV files.
5+
Since v2.0, can also download WINTEM, TEMSI FRANCE and TEMSI EUROC maps to PDF files. Enjoy.
56

67
## Usage
7-
Run `METAR_TAF_logger.py` with a `config.ini` file path as `-c` command line argument, for example from a [cron](https://en.wikipedia.org/wiki/Cron) job.
8+
Run `weather_logger.py` with a `config.ini` file path as `-c` command line argument, for example from a [cron](https://en.wikipedia.org/wiki/Cron) job.
89

910
Crontab every 10 minutes ? There you go :
1011
```
11-
*/10 * * * * cd /SCRIPT_PATH/ && /usr/bin/python3 /SCRIPT_PATH/METAR_TAF_logger.py -c /CONFIG_PATH/config.ini
12+
*/10 * * * * cd /SCRIPT_PATH/ && /usr/bin/python3 /SCRIPT_PATH/weather_logger.py -c /CONFIG_PATH/config.ini
1213
```
1314
:warning: The `cd /SCRIPT_PATH/` command from the example above is **MANDATORY** in a cron job if you want to use relative paths in your `config.ini` configuration file. You are welcome.
1415

1516
## Output
16-
CSV file(s) containing METAR / TAF reports in the following format : `YYYY-MM-DD HH:mm METAR_OR_TAF_REPORT`
17+
1. CSV file(s) containing METAR / TAF reports in the following format : `YYYY-MM-DD HH:mm METAR_OR_TAF_REPORT`
1718

1819
For `LFPG` [ICAO](https://en.wikipedia.org/wiki/ICAO_airport_code) airport code, for example :
1920
- `METAR_LFPG.csv` :
@@ -27,6 +28,13 @@ For `LFPG` [ICAO](https://en.wikipedia.org/wiki/ICAO_airport_code) airport code,
2728
2018-02-22 16:00 TAF AMD LFPG 220719Z 2207/2312 03010G20KT 5000 BR NSC TEMPO 2207/2210 3000 BR TEMPO 2210/2218 4500 HZ TX04/2215Z TNM03/2306Z=
2829
```
2930

31+
2. PDF file(s) for WINTEM, TEMSI FRANCE and TEMSI EUROC maps :
32+
33+
- `EUROC_0.pdf`
34+
- `EUROC_1.pdf`
35+
- `TEMSI_0.pdf`
36+
- `WINTEM_0.pdf`
37+
3038
## Requirements
3139
- [Python 3](https://www.python.org/)
3240
- [lxml](http://lxml.de/)
@@ -40,18 +48,26 @@ Edit the provided `config.ini` configuration file to set up the script. Everythi
4048
TAF_logging = True
4149
; Should I save METAR reports to CSV? If True, yes. If False, nope
4250
METAR_logging = True
51+
; Should I save WINTEM maps to PDF? If True, yes. If False, nope
52+
WINTEM_logging = True
53+
; Should I save TEMSI maps to PDF? If True, yes. If False, nope
54+
TEMSI_logging = True
55+
; Should I save EUROC maps to PDF? If True, yes. If False, nope
56+
EUROC_logging = True
4357
; List of ICAO airport codes, comma separated
4458
ICAO_airport_codes = LFPG,LFPO,PHTO,EGLL
4559
; Your 10 digits aeronautical code
4660
user_code = XXXXXXXXXX
4761

4862
[Directory]
4963
; CSV files will be saved to this directory path
50-
output_directory = ./csv/
64+
csv_directory = ./csv/
65+
; PDF files will be saved to this directory path
66+
pdf_directory = ./pdf/
5167
```
5268

5369
## XML API overview
54-
For `LFPG` and `LFPO` [ICAO](https://en.wikipedia.org/wiki/ICAO_airport_code) airport codes for example, [aviation.meteo.fr](https://aviation.meteo.fr) XML API will output the following document :
70+
- For `LFPG` and `LFPO` [ICAO](https://en.wikipedia.org/wiki/ICAO_airport_code) airport codes for example, [aviation.meteo.fr](https://aviation.meteo.fr) XML API will output the following document :
5571

5672
```xml
5773
<?xml version="1.0" encoding="ISO-8859-1"?>
@@ -105,6 +121,41 @@ For `LFPG` and `LFPO` [ICAO](https://en.wikipedia.org/wiki/ICAO_airport_code) ai
105121
</groupe>
106122
```
107123

124+
- For `WINTEM`, `TEMSI FRANCE` and `TEMSI EUROC`, [aviation.meteo.fr](https://aviation.meteo.fr) XML API will output the following document structure :
125+
126+
```xml
127+
<?xml version="1.0" encoding="ISO-8859-1"?>
128+
<cartes>
129+
<bloc_zone idz="EUROC" nom="EUROC">
130+
<carte>
131+
<type>TEMSI</type>
132+
<niveau>FL20-450</niveau>
133+
<zone_carte>EUROC</zone_carte>
134+
<date_run>12 04 2018 15:00</date_run>
135+
<date_echeance>12 04 2018 15:00</date_echeance>
136+
<echeance>15 UTC</echeance>
137+
<lien>
138+
<![CDATA[/FR/aviation/affiche_image.php?login=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&layer=sigwx/fr/teuroc&echeance=20180412150000]]>
139+
</lien>
140+
</carte>
141+
<carte>
142+
<type>TEMSI</type>
143+
<niveau>FL20-450</niveau>
144+
<zone_carte>EUROC</zone_carte>
145+
<date_run>12 04 2018 18:00</date_run>
146+
<date_echeance>12 04 2018 18:00</date_echeance>
147+
<echeance>18 UTC</echeance>
148+
<lien>
149+
<![CDATA[/FR/aviation/affiche_image.php?login=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&layer=sigwx/fr/teuroc&echeance=20180412180000]]>
150+
</lien>
151+
</carte>
152+
</bloc_zone>
153+
</cartes>
154+
```
155+
156+
## Contributors
157+
- [Alfourbe](https://github.com/Alfourbe) : WINTEM, TEMSI FRANCE and TEMSI EUROC maps
158+
108159
## Todo
109160
- Debug logging
110161
- Error handling

config.ini

+9-1
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,19 @@
3636
TAF_logging = True
3737
; Should I save METAR reports to CSV? If True, yes. If False, nope
3838
METAR_logging = True
39+
; Should I save WINTEM maps to PDF? If True, yes. If False, nope
40+
WINTEM_logging = True
41+
; Should I save TEMSI maps to PDF? If True, yes. If False, nope
42+
TEMSI_logging = True
43+
; Should I save EUROC maps to PDF? If True, yes. If False, nope
44+
EUROC_logging = True
3945
; List of ICAO airport codes, comma separated
4046
ICAO_airport_codes = LFPG,LFPO,PHTO,EGLL
4147
; Your 10 digits aeronautical code
4248
user_code = XXXXXXXXXX
4349

4450
[Directory]
4551
; CSV files will be saved to this directory path
46-
output_directory = ./csv/
52+
csv_directory = ./csv/
53+
; PDF files will be saved to this directory path
54+
pdf_directory = ./pdf/

weather_logger.py

+153
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
# ##### BEGIN GPL LICENSE BLOCK #####
5+
#
6+
# This program is free software; you can redistribute it and/or
7+
# modify it under the terms of the GNU General Public License
8+
# as published by the Free Software Foundation; either version 2
9+
# of the License, or (at your option) any later version.
10+
#
11+
# This program is distributed in the hope that it will be useful,
12+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
# GNU General Public License for more details.
15+
#
16+
# You should have received a copy of the GNU General Public License
17+
# along with this program; if not, write to the Free Software Foundation,
18+
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19+
#
20+
# ##### END GPL LICENSE BLOCK #####
21+
22+
# Name :
23+
# Weather Logger
24+
# Author :
25+
# ▄▄▄▄▄▄▄ ▄ ▄▄ ▄▄▄▄▄▄▄
26+
# █ ▄▄▄ █ ██ ▀▄ █ ▄▄▄ █
27+
# █ ███ █ ▄▀ ▀▄ █ ███ █
28+
# █▄▄▄▄▄█ █ ▄▀█ █▄▄▄▄▄█
29+
# ▄▄ ▄ ▄▄▀██▀▀ ▄▄▄ ▄▄
30+
# ▀█▄█▄▄▄█▀▀ ▄▄▀█ █▄▀█
31+
# █ █▀▄▄▄▀██▀▄ █▄▄█ ▀█
32+
# ▄▄▄▄▄▄▄ █▄█▀ ▄ ██ ▄█
33+
# █ ▄▄▄ █ █▀█▀ ▄▀▀ ▄▀
34+
# █ ███ █ ▀▄ ▄▀▀▄▄▀█▀█
35+
# █▄▄▄▄▄█ ███▀▄▀ ▀██ ▄
36+
37+
# DEPENDENCIES
38+
39+
import sys
40+
import os.path
41+
import argparse
42+
import datetime
43+
import configparser
44+
import urllib.request
45+
from lxml import etree
46+
47+
# CONFIGURATION
48+
49+
PROGRAM_NAME = "Weather Logger"
50+
PROGRAM_VERSION = "2.0"
51+
52+
argParser = argparse.ArgumentParser(description=PROGRAM_NAME + " " + PROGRAM_VERSION)
53+
argParser.add_argument('-c', '--config', metavar='PATH', help='"config.ini" configuration file path', required=True)
54+
args = vars(argParser.parse_args())
55+
sConfigFilePath = args['config']
56+
57+
if not os.path.isfile(sConfigFilePath):
58+
print("Invalid INI configuration file path")
59+
sys.exit(1)
60+
try:
61+
configObj = configparser.RawConfigParser()
62+
configObj.read(sConfigFilePath)
63+
except:
64+
print("Badly written INI configuration file")
65+
sys.exit(1)
66+
67+
sWebsite = "http://aviation.meteo.fr"
68+
sBaseUrl = sWebsite + "/FR/aviation/serveur_donnees.jsp?ID=" + configObj.get('General', 'user_code') + "&TYPE_DONNEES="
69+
70+
sLocationCodes = configObj.get('General', 'ICAO_airport_codes').replace(" ", "").split(",")
71+
72+
# METAR and TAF
73+
74+
if configObj.getboolean('General', 'METAR_logging') or configObj.getboolean('General', 'TAF_logging'):
75+
76+
# URL OPENING
77+
78+
sWeatherDataUrl = sBaseUrl + "OPMET&LIEUID=" + "%7C".join(sLocationCodes) + "&METAR=oui&TAF=Deux"
79+
oFile = urllib.request.urlopen(sWeatherDataUrl)
80+
sFileContent = oFile.read()
81+
82+
# XML PARSING
83+
84+
rootXML = etree.fromstring(sFileContent)
85+
if not rootXML.find('code') is None:
86+
print("Invalid 10-digits aeronautical code")
87+
sys.exit(1)
88+
89+
for sLocationCode in sLocationCodes:
90+
91+
# DATA EXTRACTION
92+
93+
sDataMETAR = rootXML.xpath("///messages[attribute::oaci='" + sLocationCode + "']/message[attribute::type='METAR']/texte")[0].text.replace('\n', '') + '\n'
94+
sDataTAF = rootXML.xpath("///messages[attribute::oaci='" + sLocationCode + "']/message[attribute::type='TAFL']/texte")[0].text.replace('\n', '') + '\n'
95+
96+
# CSV FILES
97+
98+
sOutputPath = configObj.get('Directory', 'csv_directory')
99+
if not os.path.exists(sOutputPath):
100+
os.makedirs(sOutputPath)
101+
sDateTime = datetime.datetime.now().strftime('%Y-%m-%d %H:%M ')
102+
103+
if configObj.getboolean('General', 'METAR_logging'):
104+
csvFileMETAR = open(os.path.join(sOutputPath, "METAR_" + sLocationCode + ".csv"), 'a')
105+
csvFileMETAR.write(sDateTime + sDataMETAR)
106+
csvFileMETAR.close()
107+
108+
if configObj.getboolean('General', 'TAF_logging'):
109+
csvFileTAF = open(os.path.join(sOutputPath, "TAF_" + sLocationCode + ".csv"), 'a')
110+
csvFileTAF.write(sDateTime + sDataTAF)
111+
csvFileTAF.close()
112+
113+
# WINTEM, TEMSI FRANCE and EUROC
114+
115+
if configObj.getboolean('General', 'WINTEM_logging') or configObj.getboolean('General', 'TEMSI_logging') or configObj.getboolean('General', 'EUROC_logging'):
116+
117+
dicUrl = {}
118+
119+
sOutputPath = configObj.get('Directory', 'pdf_directory')
120+
if not os.path.exists(sOutputPath):
121+
os.makedirs(sOutputPath)
122+
123+
# WINTEM
124+
if configObj.getboolean('General', 'WINTEM_logging'):
125+
sWeatherDataUrl = sBaseUrl + "CARTES&BASE_COMPLETE=non&VUE_CARTE=AERO_WINTEM&ALTITUDE=020"
126+
dicUrl['WINTEM'] = sWeatherDataUrl
127+
# TEMSI FRANCE
128+
if configObj.getboolean('General', 'TEMSI_logging'):
129+
sWeatherDataUrl = sBaseUrl + "CARTES&BASE_COMPLETE=non&VUE_CARTE=AERO_TEMSI"
130+
dicUrl['TEMSI'] = sWeatherDataUrl
131+
# TEMSI EUROC
132+
if configObj.getboolean('General', 'EUROC_logging'):
133+
sWeatherDataUrl = sBaseUrl + "CARTES&BASE_COMPLETE=non&VUE_CARTE=AERO_TEMSI&ZONE=AERO_EUROC"
134+
dicUrl['EUROC'] = sWeatherDataUrl
135+
136+
for key in dicUrl:
137+
138+
# URL OPENING
139+
140+
oFile = urllib.request.urlopen(dicUrl[key])
141+
sFileContent = oFile.read()
142+
143+
# XML PARSING
144+
145+
rootXML = etree.fromstring(sFileContent)
146+
if not rootXML.find('code') is None:
147+
print("Invalid 10-digits aeronautical code")
148+
sys.exit(1)
149+
150+
# PDF FILES
151+
152+
for i in range(0, len(rootXML.xpath("///carte/lien"))):
153+
oFile = urllib.request.urlretrieve(sWebsite + rootXML.xpath("///carte/lien")[i].text, os.path.join(configObj.get('Directory', 'pdf_directory'), key + "_" + str(i) + ".pdf"))

0 commit comments

Comments
 (0)