source: spip-zone/_plugins_/rainette/trunk/services/wunderground.php @ 108190

Last change on this file since 108190 was 108190, checked in by eric@…, 3 years ago

Pour Wunderground:

  • Correction du calcul de l'url de l'icone .
  • ajout d'un cas de tendance de pression pour éviter une notice. Ce cas est traité pour l'instant comme une erreur et la tendance n'est pas affichée.

Début de mise à jour du transcodage de owm vers weather.

  • Property svn:eol-style set to native
File size: 19.2 KB
Line 
1<?php
2/**
3 * Ce fichier contient l'ensemble des constantes et fonctions implémentant le service Wunderground.
4 * Ce service fournit des données au format XML ou JSON.
5 *
6 * @package SPIP\RAINETTE\SERVICES\WUNDERGROUND
7 */
8if (!defined('_ECRIRE_INC_VERSION')) {
9        return;
10}
11
12if (!defined('_RAINETTE_WUNDERGROUND_URL_BASE_REQUETE')) {
13        /**
14         * URL de base (endpoint) des requêtes au service Wunderground
15         */
16        define('_RAINETTE_WUNDERGROUND_URL_BASE_REQUETE', 'http://api.wunderground.com/api');
17}
18if (!defined('_RAINETTE_WUNDERGROUND_URL_BASE_ICONE')) {
19        /**
20         * URL de base des icônes fournis par le service Wunderground
21         */
22        define('_RAINETTE_WUNDERGROUND_URL_BASE_ICONE', 'http://icons.wxug.com/i/c');
23}
24
25
26// Configuration des valeurs par défaut des éléments de la configuration dynamique.
27// Ces valeurs sont applicables à tous les modes.
28$GLOBALS['rainette_wunderground_config']['service'] = array(
29        'alias'   => 'wunderground',
30        'nom'     => 'Weather Underground',
31        'credits' => array(
32                'titre'       => 'Weather Underground',
33                'logo'        => 'wunderground.png',
34                'lien'        => 'http://www.wunderground.com/',
35        ),
36        'termes'         => array(
37                'titre' => 'Terms and Conditions of use',
38                'lien' => 'https://www.wunderground.com/weather/api/d/terms.html'
39        ),
40        'enregistrement' => array(
41                'titre' => 'Join Weather Underground',
42                'lien' => 'https://www.wunderground.com/signup?mode=api_signup',
43                'taille_cle' => 16
44        ),
45        'offres'         => array(
46                'titre' => 'Pricing',
47                'lien' => 'https://www.wunderground.com/weather/api/d/pricing.html',
48                'limites' => array(
49                        'day'         => 500,
50                        'minute'      => 10
51                )
52        ),
53        'langues' => array(
54                'disponibles' => array(
55                        'AF' => 'af',
56                        'AR' => 'ar',
57                        'AZ' => 'az',
58                        'BY' => 'be',
59                        'BU' => 'bg',
60                        'CA' => 'ca',
61                        'HT' => 'cpf_hat',
62                        'CZ' => 'cs',
63                        'CY' => 'cy',
64                        'DK' => 'da',
65                        'DL' => 'de',
66                        'GR' => 'el',
67                        'EN' => 'en',
68                        'EO' => 'eo',
69                        'SP' => 'es',
70                        'ET' => 'et',
71                        'EU' => 'eu',
72                        'FA' => 'fa',
73                        'FI' => 'fi',
74                        'FR' => 'fr',
75                        'IR' => 'ga',
76                        'GZ' => 'gl',
77                        'GU' => 'gu',
78                        'IL' => 'he',
79                        'HI' => 'hi',
80                        'CR' => 'hr',
81                        'HU' => 'hu',
82                        'HY' => 'hy',
83                        'ID' => 'id',
84                        'IS' => 'is',
85                        'IT' => 'it',
86                        'JP' => 'ja',
87                        'JW' => 'jv',
88                        'KA' => 'ka',
89                        'KM' => 'km',
90                        'KR' => 'ko',
91                        'KU' => 'ku',
92                        'LA' => 'la',
93                        'LT' => 'lt',
94                        'LV' => 'lv',
95                        'GM' => 'man',
96                        'MI' => 'mi',
97                        'MK' => 'mk',
98                        'MN' => 'mn',
99                        'MR' => 'mr',
100                        'MT' => 'mt',
101                        'MY' => 'my',
102                        'NL' => 'nl',
103                        'NO' => 'no',
104                        'OC' => 'oc',
105                        'PA' => 'pa',
106                        'PL' => 'pl',
107                        'PS' => 'ps',
108                        'BR' => 'pt',
109                        'RO' => 'ro',
110                        'RU' => 'ru',
111                        'SK' => 'sk',
112                        'SL' => 'sl',
113                        'AL' => 'sq',
114                        'SR' => 'sr',
115                        'SW' => 'sv',
116                        'SI' => 'sw',
117                        'TH' => 'th',
118                        'TK' => 'tk',
119                        'TL' => 'tl',
120                        'TR' => 'tr',
121                        'TT' => 'tt',
122                        'UA' => 'uk',
123                        'UZ' => 'uz',
124                        'VU' => 'vi',
125                        'SN' => 'wo',
126                        'YI' => 'yi',
127                        'CN' => 'zh',
128                        'TW' => 'zh_tw',
129                ),
130                'defaut'      => 'EN'
131        ),
132        'defauts' => array(
133                'inscription' => '',
134                'unite'       => 'm',
135                'condition'   => 'wundergound',
136                'theme'       => 'a',
137        )
138);
139
140// Configuration des données fournies par le service wunderground pour le mode 'infos'.
141// -- Seules les données non calculées sont configurées.
142$GLOBALS['rainette_wunderground_config']['infos'] = array(
143        'periode_maj' => 86400,
144        'format_flux' => 'json',
145        'cle_base'    => array('location'),
146        'donnees'     => array(
147                // Lieu
148                'ville'     => array('cle' => array('city')),
149                'pays'      => array('cle' => array('country_name')),
150                'pays_iso2' => array('cle' => array('country_iso3166')),
151                'region'    => array('cle' => array('state')),
152                // Coordonnées
153                'longitude' => array('cle' => array('lon')),
154                'latitude'  => array('cle' => array('lat')),
155                // Informations complémentaires : aucune configuration car ce sont des données calculées
156        ),
157);
158
159// Configuration des données fournies par le service wwo pour le mode 'conditions'.
160// -- Seules les données non calculées sont configurées.
161$GLOBALS['rainette_wunderground_config']['conditions'] = array(
162        'periode_maj' => 1800,
163        'format_flux' => 'json',
164        'cle_base'    => array('current_observation'),
165        'donnees'     => array(
166                // Données d'observation
167                'derniere_maj'          => array('cle' => array('observation_time_rfc822')),
168                'station'               => array('cle' => array('observation_location', 'full')),
169                // Températures
170                'temperature_reelle'    => array('cle' => array('temp_'), 'suffixe_unite' => array('id_cle' => 0, 'm' => 'c', 's' => 'f')),
171                'temperature_ressentie' => array('cle' => array('feelslike_'), 'suffixe_unite' => array('id_cle' => 0, 'm' => 'c', 's' => 'f')),
172                // Données anémométriques
173                'vitesse_vent'          => array('cle' => array('wind_'), 'suffixe_unite' => array('id_cle' => 0, 'm' => 'kph', 's' => 'mph')),
174                'angle_vent'            => array('cle' => array('wind_degrees')),
175                'direction_vent'        => array('cle' => array()),
176                // Données atmosphériques : risque_uv est calculé
177                'precipitation'         => array('cle' => array('precip_today_'), 'suffixe_unite' => array('id_cle' => 0, 'm' => 'metric', 's' => 'in')),
178                'humidite'              => array('cle' => array('relative_humidity')),
179                'point_rosee'           => array('cle' => array('dewpoint_'), 'suffixe_unite' => array('id_cle' => 0, 'm' => 'c', 's' => 'f')),
180                'pression'              => array('cle' => array('pressure_'), 'suffixe_unite' => array('id_cle' => 0, 'm' => 'mb', 's' => 'in')),
181                'tendance_pression'     => array('cle' => array('pressure_trend')),
182                'visibilite'            => array('cle' => array('visibility_'), 'suffixe_unite' => array('id_cle' => 0, 'm' => 'km', 's' => 'mi')),
183                'indice_uv'             => array('cle' => array('UV')),
184                // Etats météorologiques natifs
185                'code_meteo'            => array('cle' => array('icon')),
186                'icon_meteo'            => array('cle' => array('icon_url')),
187                'desc_meteo'            => array('cle' => array('weather')),
188                'trad_meteo'            => array('cle' => array()),
189                // Etats météorologiques calculés : icone, resume, periode sont calculés
190        ),
191);
192
193// Configuration des données fournies par le service wwo pour le mode 'conditions'.
194// -- Seules les données non calculées sont configurées.
195$GLOBALS['rainette_wunderground_config']['previsions'] = array(
196        'periodicites'       => array(
197                24 => array('max_jours' => 10),
198                //              1  => array('max_jours' => 10)
199        ),
200        'periodicite_defaut' => 24,
201        'periode_maj'        => 1800,
202        'format_flux'        => 'json',
203        'cle_base'           => array('forecast', 'simpleforecast', 'forecastday'),
204        'cle_heure'          => array(),
205        'structure_heure'    => false,
206        'donnees'            => array(
207                // Données d'observation
208                'date'                 => array('cle' => array('date', 'epoch')),
209                'heure'                => array('cle' => array()),
210                // Données astronomiques
211                'lever_soleil'         => array('cle' => array()),
212                'coucher_soleil'       => array('cle' => array()),
213                // Températures
214                'temperature'          => array('cle' => array()),
215                'temperature_max'      => array('cle' => array('high', ''), 'suffixe_unite' => array('id_cle' => 1, 'm' => 'celsius', 's' => 'fahrenheit')),
216                'temperature_min'      => array('cle' => array('low', ''), 'suffixe_unite' => array('id_cle' => 1, 'm' => 'celsius', 's' => 'fahrenheit')),
217                // Données anémométriques
218                'vitesse_vent'         => array('cle' => array('avewind', ''), 'suffixe_unite' => array('id_cle' => 1, 'm' => 'kph', 's' => 'mph')),
219                'angle_vent'           => array('cle' => array('avewind', 'degrees')),
220                'direction_vent'       => array('cle' => array()),
221                // Données atmosphériques
222                'risque_precipitation' => array('cle' => array()),
223                'precipitation'        => array('cle' => array('qpf_allday', ''), 'suffixe_unite' => array('id_cle' => 1, 'm' => 'mm', 's' => 'in')),
224                'humidite'             => array('cle' => array('avehumidity')),
225                'point_rosee'          => array('cle' => array()),
226                'pression'             => array('cle' => array()),
227                'visibilite'           => array('cle' => array()),
228                'indice_uv'            => array('cle' => array()),
229                // Etats météorologiques natifs
230                'code_meteo'           => array('cle' => array('icon')),
231                'icon_meteo'           => array('cle' => array('icon_url')),
232                'desc_meteo'           => array('cle' => array('conditions')),
233                'trad_meteo'           => array('cle' => array()),
234                // Etats météorologiques calculés : icone, resume, periode sont calculés
235        ),
236);
237
238// Configuration des données fournies par le service Wunderground en cas d'erreur.
239// -- Seules les données non calculées sont configurées.
240$GLOBALS['rainette_wunderground_config']['erreurs'] = array(
241        'cle_base'    => array('response', 'error'),
242        'donnees'     => array(
243                // Erreur
244                'code'     => array('cle' => array('type')),
245                'message'  => array('cle' => array('description')),
246        ),
247);
248
249
250/**
251 * ------------------------------------------------------------------------------------------------
252 * Les fonctions qui suivent définissent l'API standard du service et sont appelées par la fonction
253 * unique de chargement des données météorologiques `meteo_charger()`.
254 * PACKAGE SPIP\RAINETTE\WUNDERGROUND\API
255 * ------------------------------------------------------------------------------------------------
256 */
257
258/**
259 * @param string $mode
260 *
261 * @return array
262 */
263function wunderground_service2configuration($mode) {
264        // On merge la configuration propre au mode et la configuration du service proprement dit
265        // composée des valeurs par défaut de la configuration utilisateur et e paramètres généraux.
266        $config = array_merge($GLOBALS['rainette_wunderground_config'][$mode], $GLOBALS['rainette_wunderground_config']['service']);
267
268        return $config;
269}
270
271
272/**
273 * Contruit l'url de la requête en fonction du lieu, du mode et de la périodicité demandés.
274 *
275 * @api
276 *
277 * @param string $lieu
278 *        Lieu pour lequel on requiert le nom du cache.
279 * @param string $mode
280 *        Type de données météorologiques. Les valeurs possibles sont `infos`, `conditions` ou `previsions`.
281 * @param int    $periodicite
282 *        La périodicité horaire des prévisions :
283 *            - `24`, ou `1`, pour le mode `previsions`
284 *            - `0`, pour les modes `conditions` et `infos`
285 * @param array  $configuration
286 *        Configuration complète du service, statique et utilisateur.
287 *
288 * @return string
289 *        Chemin complet du fichier cache.
290 */
291function wunderground_service2url($lieu, $mode, $periodicite, $configuration) {
292
293        // Determination de la demande
294        $demande = '';
295        switch ($mode) {
296                case 'infos':
297                        $demande = 'geolookup';
298                        break;
299                case 'conditions':
300                        $demande = 'conditions';
301                        break;
302                case 'previsions':
303                        $demande = ($periodicite == 24) ? 'forecast10day/astronomy' : 'hourly10day/astronomy';
304                        break;
305        }
306
307        // On normalise le lieu et on récupère son format.
308        // Le service accepte la format ville,pays, le format latitude,longitude, le format adresse IP
309        // et le format weather ID (comme FRXX0076 pour Paris).
310        include_spip('inc/rainette_normaliser');
311        $lieu_normalise = lieu_normaliser($lieu, $format_lieu);
312        if ($format_lieu == 'weather_id') {
313                $query = "locid:${lieu_normalise}";
314        } elseif ($format_lieu == 'adresse_ip') {
315                $query = "autoip.json?geo_ip=${lieu_normalise}";
316        } elseif ($format_lieu == 'latitude_longitude') {
317                $query = $lieu_normalise;
318        } else { // Format ville,pays
319                $query = $lieu_normalise;
320                $elements = explode(',', $lieu_normalise);
321                if (count($elements) == 2) {
322                        // Le pays est précisé, il faut alors le positionner avant la ville et le séparer par un slash.
323                        $query = $elements[1] . '/' . $elements[0];
324                }
325        }
326
327        // Identification de la langue du resume.
328        // Le choix de la langue n'a d'interet que si on utilise le resume natif du service. Si ce n'est pas
329        // le cas on demande à l'API de renvoyer la langue par défaut
330        $code_langue = langue_determiner($configuration);
331
332        $url = _RAINETTE_WUNDERGROUND_URL_BASE_REQUETE
333                   . '/' . $configuration['inscription']
334                   . '/' . $demande
335                   . '/lang:' . $code_langue
336                   . '/q'
337                   . '/' . $query . '.' . $configuration['format_flux'];
338
339        return $url;
340}
341
342
343/**
344 * @param array $erreur
345 *
346 * @return bool
347 */
348function wunderground_erreur_verifier($erreur) {
349
350        // Initialisation
351        $est_erreur = false;
352
353        // Une erreur est toujours décrite par un type (code) et un message.
354        if (!empty($erreur['code']) and !empty($erreur['message'])) {
355                $est_erreur = true;
356        }
357
358        return $est_erreur;
359}
360
361
362/**
363 * Complète par des données spécifiques au service le tableau des conditions issu
364 * uniquement de la lecture du flux.
365 *
366 * @api
367 *
368 * @param array $tableau
369 *        Tableau standardisé des conditions contenant uniquement les données fournies sans traitement
370 *        par le service.
371 * @param array $configuration
372 *        Configuration complète du service, statique et utilisateur.
373 *
374 * @return array
375 *        Tableau standardisé des conditions météorologiques complété par les données spécifiques
376 *        du service.
377 */
378function wunderground_complement2conditions($tableau, $configuration) {
379        // TODO : vérifier sur le site si le cas '' vers steady a un sens ou pas ?
380        static $tendances = array('0' => 'steady', '+' => 'rising', '-' => 'falling', '' => '');
381
382        if ($tableau) {
383                // Traiter le cas où l'indice uv n'est pas fourni: wunderground renvoie une valeur négative.
384                // On écrase cette valeur par la chaine vide qui indique que la donnée n'est pas disponible.
385                if (is_int($tableau['indice_uv']) and $tableau['indice_uv'] < 0) {
386                        $tableau['indice_uv'] = '';
387                }
388
389                // Convertir la valeur de tendance dans le standard du plugin.
390                // La documentation indique que les directions uniques sont fournies sous forme de texte comme North
391                // alors que les autres sont des acronymes. En outre, la valeur semble être traduite
392                // --> Le mieux est donc de convertir à partir de l'angle
393                include_spip('inc/rainette_convertir');
394                $tableau['direction_vent'] = angle2direction($tableau['angle_vent']);
395                // Correspondance des tendances de pression dans le système standard
396                $tableau['tendance_pression'] = $tendances[$tableau['tendance_pression']];
397
398                // Parfois le nom de la station se termine par une virgule et un espace : on supprime ces deux caractères.
399                $tableau['station'] = rtrim($tableau['station'], ' ,');
400
401                // Compléter le tableau standard avec les états météorologiques calculés
402                etat2resume_wunderground($tableau, $configuration);
403        }
404
405        return $tableau;
406}
407
408
409/**
410 * Complète par des données spécifiques au service le tableau des conditions issu
411 * uniquement de la lecture du flux.
412 *
413 * @api
414 *
415 * @param array $tableau
416 *        Tableau standardisé des conditions contenant uniquement les données fournies sans traitement
417 *        par le service.
418 * @param array $configuration
419 *        Configuration complète du service, statique et utilisateur.
420 * @param int   $index_periode
421 *        Index où trouver et ranger les données.
422 *
423 * @return array
424 *        Tableau standardisé des conditions météorologiques complété par les données spécifiques
425 *        du service.
426 */
427function wunderground_complement2previsions($tableau, $configuration, $index_periode) {
428
429        if ($tableau and ($index_periode > -1)) {
430                // Déterminer la direction du vent dans le standard du plugin.
431                // La documentation indique que les directions uniques sont fournies sous forme de texte comme North
432                // alors que les autres sont des acronymes. En outre, la valeur semble être traduite
433                // --> Le mieux est donc de convertir à partir de l'angle
434                include_spip('inc/rainette_convertir');
435                $tableau['direction_vent'] = angle2direction($tableau['angle_vent']);
436
437                // Compléter le tableau standard avec les états météorologiques calculés
438                etat2resume_wunderground($tableau, $configuration);
439        }
440
441        return $tableau;
442}
443
444
445/**
446 * ---------------------------------------------------------------------------------------------
447 * Les fonctions qui suivent sont des utilitaires utilisés uniquement appelées par les fonctions
448 * de l'API.
449 * PACKAGE SPIP\RAINETTE\WUNDERGROUND\OUTILS
450 * ---------------------------------------------------------------------------------------------
451 */
452
453/**
454 * Calcule les états en fonction des états météorologiques natifs fournis par le service.
455 *
456 * @internal
457 *
458 * @param array $tableau
459 *        Tableau standardisé des conditions contenant uniquement les données fournies sans traitement
460 *        par le service. Le tableau est mis à jour et renvoyé à l'appelant.
461 * @param array $configuration
462 *        Configuration complète du service, statique et utilisateur.
463 *
464 * @return void
465 */
466function etat2resume_wunderground(&$tableau, $configuration) {
467
468        if ($tableau['code_meteo'] and $tableau['icon_meteo']) {
469                // Determination de l'indicateur jour/nuit qui permet de choisir le bon icone
470                // Pour ce service (cas actuel) le nom du fichier icône commence par "nt_" pour la nuit.
471                $icone = basename($tableau['icon_meteo']);
472                if (strpos($icone, 'nt_') === false) {
473                        // C'est le jour
474                        $tableau['periode'] = 0;
475                } else {
476                        // C'est la nuit
477                        $tableau['periode'] = 1;
478                }
479
480                // Determination, suivant le mode choisi, du code, de l'icone et du resume qui seront affiches
481                if ($configuration['condition'] == $configuration['alias']) {
482                        // On affiche les conditions natives fournies par le service.
483                        // Celles-ci étant déjà traduites dans la bonne langue on stocke le texte exact retourné par l'API.
484                        $tableau['icone']['code'] = $tableau['code_meteo'];
485                        $url = _RAINETTE_WUNDERGROUND_URL_BASE_ICONE . '/' . $configuration['theme'] . '/' . $icone;
486                        $tableau['icone']['url'] = copie_locale($url);
487                        $tableau['resume'] = ucfirst($tableau['desc_meteo']);
488                } else {
489                        // On affiche les conditions traduites dans le système weather.com
490                        // Pour le resume on stocke le code et non la traduction pour éviter de générer
491                        // un cache par langue comme pour le mode natif. La traduction est faite via les fichiers de langue
492                        $meteo = meteo_wunderground2weather($tableau['code_meteo'], $tableau['periode']);
493                        $tableau['icone'] = $meteo;
494                        $tableau['resume'] = $meteo;
495                }
496        }
497}
498
499
500/**
501 * @internal
502 *
503 * @link http://plugins.trac.wordpress.org/browser/weather-and-weather-forecast-widget/trunk/gg_funx_.php
504 * Transcodage issu du plugin Wordpress weather forecast.
505 *
506 * @param string $meteo
507 * @param int    $periode
508 *
509 * @return string
510 */
511function meteo_wunderground2weather($meteo, $periode = 0) {
512        static $wunderground2weather = array(
513                'chanceflurries'  => array(41, 46),
514                'chancerain'      => array(39, 45),
515                'chancesleet'     => array(39, 45),
516//              'chancesleet'     => array(41, 46),
517                'chancesnow'      => array(41, 46),
518                'chancetstorms'   => array(38, 47),
519                'clear'           => array(32, 31),
520                'cloudy'          => array(26, 26),
521                'flurries'        => array(15, 15),
522                'fog'             => array(20, 20),
523                'hazy'            => array(21, 21),
524                'mostlycloudy'    => array(28, 27),
525                'mostlysunny'     => array(34, 33),
526                'partlycloudy'    => array(30, 29),
527                'partlysunny'     => array(28, 27),
528                'sleet'           => array(5, 5),
529                'rain'            => array(11, 11),
530                'snow'            => array(16, 16),
531                'sunny'           => array(32, 31),
532                'tstorms'         => array(4, 4),
533                'thunderstorms'   => array(4, 4),
534                'unknown'         => array(4, 4),
535                'scatteredclouds' => array(30, 29),
536                'overcast'        => array(26, 26)
537        );
538
539        $icone = 'na';
540        $meteo = strtolower($meteo);
541        if (array_key_exists($meteo, $wunderground2weather)) {
542                $icone = strval($wunderground2weather[$meteo][$periode]);
543        }
544
545        return $icone;
546}
Note: See TracBrowser for help on using the repository browser.