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

Last change on this file since 113209 was 113209, checked in by eric@…, 6 weeks ago

Même problème pour Wunderground. On ne peut pas passer d'une chaine à un tableau par affectation d'un index.

  • Property svn:eol-style set to native
File size: 19.5 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                'theme_local'   => 'observation',
138                'theme_weather' => 'sticker',
139        ),
140        // TODO : tout à revoir
141        'transcodage_weather' => array(
142                'chanceflurries'  => array(41, 46),
143                'chancerain'      => array(39, 45),
144                'chancesleet'     => array(39, 45),
145                'chancesnow'      => array(41, 46),
146                'chancetstorms'   => array(38, 47),
147                'clear'           => array(32, 31),
148                'cloudy'          => array(26, 26),
149                'flurries'        => array(15, 15),
150                'fog'             => array(20, 20),
151                'hazy'            => array(21, 21),
152                'mostlycloudy'    => array(28, 27),
153                'mostlysunny'     => array(34, 33),
154                'partlycloudy'    => array(30, 29),
155                'partlysunny'     => array(28, 27),
156                'sleet'           => array(5, 5),
157                'rain'            => array(11, 11),
158                'snow'            => array(16, 16),
159                'sunny'           => array(32, 31),
160                'tstorms'         => array(4, 4),
161                'thunderstorms'   => array(4, 4),
162                'unknown'         => array(4, 4),
163                'scatteredclouds' => array(30, 29),
164                'overcast'        => array(26, 26)
165        )
166);
167
168// Configuration des données fournies par le service wunderground pour le mode 'infos'.
169// -- Seules les données non calculées sont configurées.
170$GLOBALS['rainette_wunderground_config']['infos'] = array(
171        'periode_maj' => 86400,
172        'format_flux' => 'json',
173        'cle_base'    => array('location'),
174        'donnees'     => array(
175                // Lieu
176                'ville'     => array('cle' => array('city')),
177                'pays'      => array('cle' => array('country_name')),
178                'pays_iso2' => array('cle' => array('country_iso3166')),
179                'region'    => array('cle' => array('state')),
180                // Coordonnées
181                'longitude' => array('cle' => array('lon')),
182                'latitude'  => array('cle' => array('lat')),
183                // Informations complémentaires : aucune configuration car ce sont des données calculées
184        ),
185);
186
187// Configuration des données fournies par le service wwo pour le mode 'conditions'.
188// -- Seules les données non calculées sont configurées.
189$GLOBALS['rainette_wunderground_config']['conditions'] = array(
190        'periode_maj' => 1800,
191        'format_flux' => 'json',
192        'cle_base'    => array('current_observation'),
193        'donnees'     => array(
194                // Données d'observation
195                'derniere_maj'          => array('cle' => array('observation_time_rfc822')),
196                'station'               => array('cle' => array('observation_location', 'full')),
197                // Températures
198                'temperature_reelle'    => array('cle' => array('temp_'), 'suffixe_unite' => array('id_cle' => 0, 'm' => 'c', 's' => 'f')),
199                'temperature_ressentie' => array('cle' => array('feelslike_'), 'suffixe_unite' => array('id_cle' => 0, 'm' => 'c', 's' => 'f')),
200                // Données anémométriques
201                'vitesse_vent'          => array('cle' => array('wind_'), 'suffixe_unite' => array('id_cle' => 0, 'm' => 'kph', 's' => 'mph')),
202                'angle_vent'            => array('cle' => array('wind_degrees')),
203                'direction_vent'        => array('cle' => array()),
204                // Données atmosphériques : risque_uv est calculé
205                'precipitation'         => array('cle' => array('precip_today_'), 'suffixe_unite' => array('id_cle' => 0, 'm' => 'metric', 's' => 'in')),
206                'humidite'              => array('cle' => array('relative_humidity')),
207                'point_rosee'           => array('cle' => array('dewpoint_'), 'suffixe_unite' => array('id_cle' => 0, 'm' => 'c', 's' => 'f')),
208                'pression'              => array('cle' => array('pressure_'), 'suffixe_unite' => array('id_cle' => 0, 'm' => 'mb', 's' => 'in')),
209                'tendance_pression'     => array('cle' => array('pressure_trend')),
210                'visibilite'            => array('cle' => array('visibility_'), 'suffixe_unite' => array('id_cle' => 0, 'm' => 'km', 's' => 'mi')),
211                'indice_uv'             => array('cle' => array('UV')),
212                // Etats météorologiques natifs
213                'code_meteo'            => array('cle' => array('icon')),
214                'icon_meteo'            => array('cle' => array('icon_url')),
215                'desc_meteo'            => array('cle' => array('weather')),
216                'trad_meteo'            => array('cle' => array()),
217                // Etats météorologiques calculés : icone, resume, periode sont calculés
218        ),
219);
220
221// Configuration des données fournies par le service wwo pour le mode 'conditions'.
222// -- Seules les données non calculées sont configurées.
223$GLOBALS['rainette_wunderground_config']['previsions'] = array(
224        'periodicites'       => array(
225                24 => array('max_jours' => 10),
226                //              1  => array('max_jours' => 10)
227        ),
228        'periodicite_defaut' => 24,
229        'periode_maj'        => 1800,
230        'format_flux'        => 'json',
231        'cle_base'           => array('forecast', 'simpleforecast', 'forecastday'),
232        'cle_heure'          => array(),
233        'structure_heure'    => false,
234        'donnees'            => array(
235                // Données d'observation
236                'date'                 => array('cle' => array('date', 'epoch')),
237                'heure'                => array('cle' => array()),
238                // Données astronomiques
239                'lever_soleil'         => array('cle' => array()),
240                'coucher_soleil'       => array('cle' => array()),
241                // Températures
242                'temperature'          => array('cle' => array()),
243                'temperature_max'      => array('cle' => array('high', ''), 'suffixe_unite' => array('id_cle' => 1, 'm' => 'celsius', 's' => 'fahrenheit')),
244                'temperature_min'      => array('cle' => array('low', ''), 'suffixe_unite' => array('id_cle' => 1, 'm' => 'celsius', 's' => 'fahrenheit')),
245                // Données anémométriques
246                'vitesse_vent'         => array('cle' => array('avewind', ''), 'suffixe_unite' => array('id_cle' => 1, 'm' => 'kph', 's' => 'mph')),
247                'angle_vent'           => array('cle' => array('avewind', 'degrees')),
248                'direction_vent'       => array('cle' => array()),
249                // Données atmosphériques
250                'risque_precipitation' => array('cle' => array()),
251                'precipitation'        => array('cle' => array('qpf_allday', ''), 'suffixe_unite' => array('id_cle' => 1, 'm' => 'mm', 's' => 'in')),
252                'humidite'             => array('cle' => array('avehumidity')),
253                'point_rosee'          => array('cle' => array()),
254                'pression'             => array('cle' => array()),
255                'visibilite'           => array('cle' => array()),
256                'indice_uv'            => array('cle' => array()),
257                // Etats météorologiques natifs
258                'code_meteo'           => array('cle' => array('icon')),
259                'icon_meteo'           => array('cle' => array('icon_url')),
260                'desc_meteo'           => array('cle' => array('conditions')),
261                'trad_meteo'           => array('cle' => array()),
262                // Etats météorologiques calculés : icone, resume, periode sont calculés
263        ),
264);
265
266// Configuration des données fournies par le service Wunderground en cas d'erreur.
267// -- Seules les données non calculées sont configurées.
268$GLOBALS['rainette_wunderground_config']['erreurs'] = array(
269        'cle_base'    => array('response', 'error'),
270        'donnees'     => array(
271                // Erreur
272                'code'     => array('cle' => array('type')),
273                'message'  => array('cle' => array('description')),
274        ),
275);
276
277
278/**
279 * ------------------------------------------------------------------------------------------------
280 * Les fonctions qui suivent définissent l'API standard du service et sont appelées par la fonction
281 * unique de chargement des données météorologiques `meteo_charger()`.
282 * PACKAGE SPIP\RAINETTE\WUNDERGROUND\API
283 * ------------------------------------------------------------------------------------------------
284 */
285
286/**
287 * @param string $mode
288 *
289 * @return array
290 */
291function wunderground_service2configuration($mode) {
292        // On merge la configuration propre au mode et la configuration du service proprement dit
293        // composée des valeurs par défaut de la configuration utilisateur et e paramètres généraux.
294        $config = array_merge($GLOBALS['rainette_wunderground_config'][$mode], $GLOBALS['rainette_wunderground_config']['service']);
295
296        return $config;
297}
298
299
300/**
301 * Contruit l'url de la requête en fonction du lieu, du mode et de la périodicité demandés.
302 *
303 * @api
304 *
305 * @param string $lieu
306 *        Lieu pour lequel on requiert le nom du cache.
307 * @param string $mode
308 *        Type de données météorologiques. Les valeurs possibles sont `infos`, `conditions` ou `previsions`.
309 * @param int    $periodicite
310 *        La périodicité horaire des prévisions :
311 *            - `24`, ou `1`, pour le mode `previsions`
312 *            - `0`, pour les modes `conditions` et `infos`
313 * @param array  $configuration
314 *        Configuration complète du service, statique et utilisateur.
315 *
316 * @return string
317 *        Chemin complet du fichier cache.
318 */
319function wunderground_service2url($lieu, $mode, $periodicite, $configuration) {
320
321        // Determination de la demande
322        $demande = '';
323        switch ($mode) {
324                case 'infos':
325                        $demande = 'geolookup';
326                        break;
327                case 'conditions':
328                        $demande = 'conditions';
329                        break;
330                case 'previsions':
331                        $demande = ($periodicite == 24) ? 'forecast10day/astronomy' : 'hourly10day/astronomy';
332                        break;
333        }
334
335        // On normalise le lieu et on récupère son format.
336        // Le service accepte la format ville,pays, le format latitude,longitude, le format adresse IP
337        // et le format weather ID (comme FRXX0076 pour Paris).
338        include_spip('inc/rainette_normaliser');
339        $lieu_normalise = lieu_normaliser($lieu, $format_lieu);
340        if ($format_lieu == 'weather_id') {
341                $query = "locid:${lieu_normalise}";
342        } elseif ($format_lieu == 'adresse_ip') {
343                $query = "autoip.json?geo_ip=${lieu_normalise}";
344        } elseif ($format_lieu == 'latitude_longitude') {
345                $query = $lieu_normalise;
346        } else { // Format ville,pays
347                $query = $lieu_normalise;
348                $elements = explode(',', $lieu_normalise);
349                if (count($elements) == 2) {
350                        // Le pays est précisé, il faut alors le positionner avant la ville et le séparer par un slash.
351                        $query = $elements[1] . '/' . $elements[0];
352                }
353        }
354
355        // Identification de la langue du resume.
356        // Le choix de la langue n'a d'interet que si on utilise le resume natif du service. Si ce n'est pas
357        // le cas on demande à l'API de renvoyer la langue par défaut
358        $code_langue = langue_determiner($configuration);
359
360        $url = _RAINETTE_WUNDERGROUND_URL_BASE_REQUETE
361                   . '/' . $configuration['inscription']
362                   . '/' . $demande
363                   . '/lang:' . $code_langue
364                   . '/q'
365                   . '/' . $query . '.' . $configuration['format_flux'];
366
367        return $url;
368}
369
370
371/**
372 * @param array $erreur
373 *
374 * @return bool
375 */
376function wunderground_erreur_verifier($erreur) {
377
378        // Initialisation
379        $est_erreur = false;
380
381        // Une erreur est toujours décrite par un type (code) et un message.
382        if (!empty($erreur['code']) and !empty($erreur['message'])) {
383                $est_erreur = true;
384        }
385
386        return $est_erreur;
387}
388
389
390/**
391 * Complète par des données spécifiques au service le tableau des conditions issu
392 * uniquement de la lecture du flux.
393 *
394 * @api
395 *
396 * @param array $tableau
397 *        Tableau standardisé des conditions contenant uniquement les données fournies sans traitement
398 *        par le service.
399 * @param array $configuration
400 *        Configuration complète du service, statique et utilisateur.
401 *
402 * @return array
403 *        Tableau standardisé des conditions météorologiques complété par les données spécifiques
404 *        du service.
405 */
406function wunderground_complement2conditions($tableau, $configuration) {
407        // TODO : vérifier sur le site si le cas '' vers '' a un sens ou pas ?
408        static $tendances = array('0' => 'steady', '+' => 'rising', '-' => 'falling', '' => '');
409
410        if ($tableau) {
411                // Traiter le cas où l'indice uv n'est pas fourni: wunderground renvoie une valeur négative.
412                // On écrase cette valeur par la chaine vide qui indique que la donnée n'est pas disponible.
413                if (is_int($tableau['indice_uv']) and $tableau['indice_uv'] < 0) {
414                        $tableau['indice_uv'] = '';
415                }
416
417                // Convertir la valeur de tendance dans le standard du plugin.
418                // La documentation indique que les directions uniques sont fournies sous forme de texte comme North
419                // alors que les autres sont des acronymes. En outre, la valeur semble être traduite
420                // --> Le mieux est donc de convertir à partir de l'angle
421                include_spip('inc/rainette_convertir');
422                $tableau['direction_vent'] = angle2direction($tableau['angle_vent']);
423                // Correspondance des tendances de pression dans le système standard
424                $tableau['tendance_pression'] = $tendances[$tableau['tendance_pression']];
425
426                // Parfois le nom de la station se termine par une virgule et un espace : on supprime ces deux caractères.
427                $tableau['station'] = rtrim($tableau['station'], ' ,');
428
429                // Compléter le tableau standard avec les états météorologiques calculés
430                etat2resume_wunderground($tableau, $configuration);
431        }
432
433        return $tableau;
434}
435
436
437/**
438 * Complète par des données spécifiques au service le tableau des conditions issu
439 * uniquement de la lecture du flux.
440 *
441 * @api
442 *
443 * @param array $tableau
444 *        Tableau standardisé des conditions contenant uniquement les données fournies sans traitement
445 *        par le service.
446 * @param array $configuration
447 *        Configuration complète du service, statique et utilisateur.
448 * @param int   $index_periode
449 *        Index où trouver et ranger les données.
450 *
451 * @return array
452 *        Tableau standardisé des conditions météorologiques complété par les données spécifiques
453 *        du service.
454 */
455function wunderground_complement2previsions($tableau, $configuration, $index_periode) {
456
457        if ($tableau and ($index_periode > -1)) {
458                // Déterminer la direction du vent dans le standard du plugin.
459                // La documentation indique que les directions uniques sont fournies sous forme de texte comme North
460                // alors que les autres sont des acronymes. En outre, la valeur semble être traduite
461                // --> Le mieux est donc de convertir à partir de l'angle
462                include_spip('inc/rainette_convertir');
463                $tableau['direction_vent'] = angle2direction($tableau['angle_vent']);
464
465                // Compléter le tableau standard avec les états météorologiques calculés
466                etat2resume_wunderground($tableau, $configuration);
467        }
468
469        return $tableau;
470}
471
472
473/**
474 * ---------------------------------------------------------------------------------------------
475 * Les fonctions qui suivent sont des utilitaires uniquement appelées par les fonctions de l'API
476 * ---------------------------------------------------------------------------------------------
477 */
478
479/**
480 * Calcule les états en fonction des états météorologiques natifs fournis par le service.
481 *
482 * @internal
483 *
484 * @param array $tableau
485 *        Tableau standardisé des conditions contenant uniquement les données fournies sans traitement
486 *        par le service. Le tableau est mis à jour et renvoyé à l'appelant.
487 * @param array $configuration
488 *        Configuration complète du service, statique et utilisateur.
489 *
490 * @return void
491 */
492function etat2resume_wunderground(&$tableau, $configuration) {
493
494        if ($tableau['code_meteo'] and $tableau['icon_meteo']) {
495                // Determination de l'indicateur jour/nuit qui permet de choisir le bon icone
496                // Pour ce service (cas actuel) le nom du fichier icône commence par "nt_" pour la nuit.
497                $icone = basename($tableau['icon_meteo']);
498                if (strpos($icone, 'nt_') === false) {
499                        // C'est le jour
500                        $tableau['periode'] = 0;
501                } else {
502                        // C'est la nuit
503                        $tableau['periode'] = 1;
504                }
505
506                // Détermination du résumé à afficher.
507                // Depuis la 3.4.6 on affiche plus que le résumé natif de chaque service car les autres services
508                // que weather.com possèdent de nombreuses traductions qu'il convient d'utiliser.
509                // Pour éviter de modifier la structure de données, on conserve donc desc_meteo et resume même si
510                // maintenant ces deux données coincident toujours.
511                $tableau['resume'] = ucfirst($tableau['desc_meteo']);
512
513                // Determination de l'icone qui sera affiché.
514                // -- on stocke le code afin de le fournir en alt dans la balise img
515                $tableau['icone'] = array();
516                $tableau['icone']['code'] = $tableau['code_meteo'];
517                // -- on calcule le chemin complet de l'icone.
518                if ($configuration['condition'] == $configuration['alias']) {
519                        // On affiche l'icône natif fourni par le service et désigné par son url
520                        // en faisant une copie locale dans IMG/.
521                        include_spip('inc/distant');
522                        $url = _RAINETTE_WUNDERGROUND_URL_BASE_ICONE . '/' . $configuration['theme'] . '/' . $icone;
523                        $tableau['icone']['source'] = copie_locale($url);
524                } else {
525                        include_spip('inc/rainette_normaliser');
526                        if ($configuration['condition'] == "{$configuration['alias']}_local") {
527                                // On affiche un icône d'un thème local compatible avec Wunderground.
528                                $chemin = icone_local_normaliser(
529                                        "{$tableau['icon_meteo']}.png",
530                                        $configuration['alias'],
531                                        $configuration['theme_local']);
532                        } else {
533                                // On affiche l'icône correspondant au code météo transcodé dans le système weather.com.
534                                $chemin = icone_weather_normaliser(
535                                        $tableau['code_meteo'],
536                                        $configuration['theme_weather'],
537                                        $configuration['transcodage_weather'],
538                                        $tableau['periode']);
539                        }
540                        include_spip('inc/utils');
541                        $tableau['icone']['source'] = find_in_path($chemin);
542                }
543        }
544}
Note: See TracBrowser for help on using the repository browser.