METEO : utilisez l’API de Météo France

L’interrogation de la base de données de MF permet l’accès à des paramètres que l’on ne trouve généralement pas dans les modules ou cartes proposés habituellement sur HA.
Exemple : le rayonnement et l’ensoleillement peuvent intéresser les possesseurs de panneaux photovoltaïques, la visibilité a de l’intérêt pour un pilote de planeur, la nébulosité pour les amateurs de photos de paysages, …

On accède aussi à différents types de données. Pour les données d’observation, il y a les mesures toutes les 6 minutes (cas présenté ici), ou les données horaires suffisantes pour la plupart d’entre nous.

Exemple d’affichage

Comment obtenir l’autorisation d’accès de MF

  1. créer un compte sur MeteofranceWeb
    si besoin, vous pouvez trouver de l’aide dans MeteofranceWeb
    il faut souscrire à l’API Données d’observation (validité de la souscription pour 2 ans)
    plus tard, dans votre profil, vous pourrez accéder directement à mes API

  2. choisir votre station d’observation :
    dans la rubrique Documentation, puis Description
    de là, on accède un nouveau portail Données Publiques de Météo-France - Informations sur les stations (métadonnées)
    et dans l’onglet Informations sur les stations, vous pouvez trouver l’identifiant de la station la plus proche de chez vous
    ou alors, dans Documentation, on trouve Liste des stations
    exemple : Annecy-Meythet, id station 74182001

j’ai trouvé un jour une carte interactive des stations météo…mais impossible de remettre la main dessus.

  1. générer un token
    choisir le type API Key par exemple pour une durée de 31536000 secondes (1 an)
    copier-coller le token dans le fichier secrets.yaml
# météo
mf_key: 'eyJ4NXQiOiJZV0kxTT...'

Intégration dans HA :
Personnellement j’utilise les packages qui permettent de grouper toutes les entités d’un même thème dans un seul fichier

Code du package mameteo.yaml :

# fichier mameteo.yaml

# Template ##########################################################
template:
  - sensor:
    - name: rayonnement normalisé
      # sensor.rayonnement_normalise
      state: "{{ (state_attr('mameteo.data','raw') | from_json)['ray_glo01'] }}"
      unit_of_measurement: "J/m2@6mn"

# Automations #######################################################
automation:
  # Météo France - data 6mn
  # interrogation de l'API de Météo France : données d'observation (6'), fréquence de modif : 6 minutes
  - id: mameteo_data_6mn
    alias: MaMétéo - data 6mn
    description: 'interrogation de l''API de Météo France'
    mode: single
    trigger:
      - platform: time_pattern
        # toutes les 6 minutes
        minutes: "/6"
    condition: []
    action:
      - service: python_script.exec
        data:
          key: !secret mf_key_obs
          title: Python inline
          source: |
            from datetime import datetime
            import requests
            import urllib.parse  

            try:            
              serveur = 'https://public-api.meteofrance.fr/public/DPObs/v1'
              key = data.get("key", "")
              service = '/station/infrahoraire-6m'
              station = '74182001' # code de la station sélectionnée : Annecy Meythet
              datage = datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")     # en UTC
            
              url = serveur + service + '?id_station=' + station + '&date=' + urllib.parse.quote(datage) + '&format=json&apikey=' + urllib.parse.quote(key)
              # print('url=', url)
              r = requests.get(url)
              rstr = str(r)
              print(r)
              if '<400>' in rstr:
                hass.states.set('mameteo.data', '400: Contrôle de paramètres en erreur')
              elif '<404>' in rstr:
                hass.states.set('mameteo.data', '404: Jeu de données inexistant')
              elif '<Response [200]>' in rstr:
                print('analyse du json')
                resp = r.json()[0]
                print('resp=', resp)
                # hass.states.set( 'mameteo.data', datetime.now().strftime("%d/%m/%Y %H:%M:%S"), { 'json': 'r' } )
                datage = datetime.strftime( datetime.strptime(resp['reference_time'], '%Y-%m-%dT%H:%M:%SZ'), '%d/%m/%Y %H:%M:%S' )
                hass.states.set( 'mameteo.data', datetime.now().strftime("%d/%m/%Y %H:%M:%S"), 
                                  {
                                    'raw': str(resp).replace('\'', '\"'),       # ainsi on peut faire : (state_attr('mameteo.data','raw') | from_json)['t']
                                    'raw2': str(resp),
                                    'reference_time': datage,                   # date and time of the production of the data in UTC
                                    'temperature': resp['t']-273.15,            # air temperature at 2 meters above the ground in Kelvin degrees -> °C
                                    'humidite': resp['u'],                      # hourly relative humidity at 2 meters 
                                    'pression': resp['pres']/100,               # station pressure in Pa -> hPa 
                                    'vent_direction': resp['dd'],               # mean wind direction at 10 meters above the ground in degrees
                                    'vent_force': resp['ff']*3.6,               # mean wind speed at 10 meters above the ground in m/s -> km/h
                                    'rafale_direction': resp['dxi10'],          # 10 minutes mean wind gust direction at 10 meters above the ground in degrees 
                                    'rafale_force': resp['fxi10']*3.6,          # 10 minutes mean wind gust speed at 10 meters above the ground in m/s
                                    'precipitation': resp['rr_per'],            # all precipitation over the previous 6 minutes in mm  
                                    'puissance_solaire': resp['ray_glo01']/360, # global radiation over the previous 6 minutes in J/m² = Wh/m² pendant 6mn -> puissance solaire W/m²
                                    'ensoleillement': resp['insolh'],           # sunshine duration over the previous 1H in min
                                    'visibilite': resp['vv'],                   # horizontal visibility in meters 
                                    'origine': 'Météo France, Données Observation 6mn'
                                  })
                hass.states.set( 'mameteo.reference_time',   datage,                 { 'unit_of_measurement': 'UTC' } )
                hass.states.set( 'mameteo.temperature',      resp['t']-273.15,       { 'unit_of_measurement': '°C' } )
                hass.states.set( 'mameteo.humidite',         resp['u'],              { 'unit_of_measurement': '%' } )
                hass.states.set( 'mameteo.pression',         resp['pres']/100,       { 'unit_of_measurement': 'hPa' } )
                hass.states.set( 'mameteo.vent_direction',   resp['dd'],             { 'unit_of_measurement': '°' } )
                hass.states.set( 'mameteo.vent_force',       resp['ff']*3.6,         { 'unit_of_measurement': 'km/h' } )
                hass.states.set( 'mameteo.rafale_direction', resp['dxi10'],          { 'unit_of_measurement': '°' } )
                hass.states.set( 'mameteo.rafale_force',     resp['fxi10']*3.6,      { 'unit_of_measurement': 'km/h' } )
                hass.states.set( 'mameteo.precipitation',    resp['rr_per'],         { 'unit_of_measurement': 'mm/1h' } )
                hass.states.set( 'mameteo.puissance_solaire',resp['ray_glo01']/360,  { 'unit_of_measurement': 'W/m²' } )
                hass.states.set( 'mameteo.ensoleillement',   resp['insolh'],         { 'unit_of_measurement': 'mn' } )
                hass.states.set( 'mameteo.visibilite',       resp['vv'],             { 'unit_of_measurement': 'm' } )
              else:
                hass.states.set('mameteo.data', 'erreur non définie: ' + rstr)
            except Exception as e:
                print(f'exception: {e=}')
            print('automation.mameteo_data_6mn: terminé')

Remarque : à partir de ce code, accès à une clé de l’attribut raw
Cf remarque sur l’initialisation de l’attribut raw

template:
  - sensor:
    - name: rayonnement normalisé
      state: "{{ (state_attr('mameteo.data','raw') | from_json)['ray_glo01'] }}"
      unit_of_measurement: "J/m2@6mn"

remarque sur le rafraichissement des données :
suite à un démarrage de HA, il faut un petit moment avant d’avoir les données disponibles (6 minutes max dans cet exemple)

Il n’est pas utile de relancer HA, le rechargement des automatisations suffit

Traces de HA :

2024-03-25 16:28:46.200 INFO (MainThread) [homeassistant.components.automation] _async_add_entity platform platform_name=automation entity=MaMétéo - data 6mn
2024-03-25 16:28:46.204 INFO (MainThread) [homeassistant.components.automation.ma_meteo_data_6mn] Initialized trigger MaMétéo - data 6mn

Traces de HA lors d’une exécution > :


2024-03-25 15:20:25.473 INFO (MainThread) [homeassistant.components.automation.ma_meteo_data_6mn] MaMétéo - data 1h: Running automation actions
2024-03-25 15:20:25.473 INFO (MainThread) [homeassistant.components.automation.ma_meteo_data_6mn] MaMétéo - data 1h: Executing step call service
<Response [200]>
analyse du json
resp= {‹ lat ›: 45.928167, ‹ lon ›: 6.094, ‹ geo_id_insee ›: ‹ 74182001 ›, ‹ reference_time ›: ‹ 2024-03-25T15:20:25Z ›, ‹ insert_time ›: ‹ 2024-03-25T05:02:12Z ›, ‹ validity_time ›: ‹ 2024-03-25T05:00:00Z ›, ‹ t ›: 272.35, ‹ td ›: 271.35, ‹ tx ›: 272.85, ‹ tn ›: 272.35, ‹ u ›: 93, ‹ ux ›: 93, ‹ un ›: 92, ‹ dd ›: 10, ‹ ff ›: 1.4, ‹ dxy ›: 60, ‹ fxy ›: 3.2, ‹ dxi ›: 70, ‹ fxi ›: 3.7, ‹ rr1 ›: 0.0, ‹ t_10 ›: 280.05, ‹ t_20 ›: 281.45, ‹ t_50 ›: 283.35, ‹ t_100 ›: 282.55, ‹ vv ›: 54570, ‹ etat_sol ›: None, ‹ sss ›: 0, ‹ n ›: None, ‹ insolh ›: None, ‹ ray_glo01 ›: None, ‹ pres ›: 95590, ‹ pmer ›: 101160}
automation.mameteo_data_6mn: terminé

6 « J'aime »

Bonjour,
Merci beaucoup pour ce partage et ces éléments !
Est-il possible d’avoir le code de tes cartes également ?
Superbe boulot en tout cas

Du beau boulot bien pratique

Bonjour,

J’ai suivi le tuto mais j’ai un souci :

j’arrive a appeler le service python_script.exec mais le sensor mameteo n’est pas crée.

Pour débugger, je suis aller dans Outils de dév / Service avec :

service: python_script.exec
data:
  title: Python inline test
  source: |
    from datetime import datetime
    import requests
    import urllib.parse  

    try:            
      serveur = 'https://public-api.meteofrance.fr/public/DPObs/v1'
...
...

Si je clique sur appeler le service, j’ai ce Réponse :

serveur: https://public-api.meteofrance.fr/public/DPObs/v1
key: >-
xxxxxxxx
service: /station/infrahoraire-6m
station: "38185012"
__warningregistry__:
  version: 71
datage: 08/04/2024 16:48:06
url: >-
  https://public-api.meteofrance.fr/public/DPObs/v1/station/infrahoraire-6m?id_station=38185012&date=2024-04-08T16%3A51%3A11Z&format=json&apikey=xxxxxxxx
rstr: <Response [200]>
resp:
  lat: 45.2115
  lon: 5.682833
  geo_id_insee: "38185012"
  reference_time: "2024-04-08T16:48:06Z"
  insert_time: "2024-04-08T16:43:58Z"
  validity_time: "2024-04-08T16:42:00Z"
  t: 301.05
  td: 274.55
  u: 18
  dd: 170
  ff: 4
  dxi10: 180
  fxi10: 11.3
  rr_per: 0
  t_10: null
  t_20: null
  t_50: null
  t_100: null
  vv: null
  etat_sol: null
  sss: 0
  insolh: null
  ray_glo01: null
  pres: null
  pmer: null

Une idée sur le souci ?

Merci d’avance

voici la page entière :

  - theme: Backend-selected
    icon: mdi:sun-thermometer
    title: Ma Météo 6'
    badges: []
    cards:
      - square: false
        columns: 1
        type: grid
        title: données 6' de Météo France
        cards:
          - type: entities
            entities:
              - entity: mameteo.data
                type: attribute
                attribute: temperature
                name: température
                suffix: °C
                icon: mdi:temperature-celsius
              - entity: mameteo.data
                type: attribute
                attribute: humidite
                suffix: '%'
                name: humidité
                icon: mdi:air-humidifier
              - entity: mameteo.data
                type: attribute
                name: pression
                attribute: pression
                suffix: hPa
              - type: section
                label: pluie
              - entity: mameteo.data
                type: attribute
                attribute: nebulosite
                name: nébulosité
                suffix: octa (/8)
                icon: mdi:cloud-outline
              - entity: mameteo.data
                type: attribute
                attribute: precipitation
                name: précipitation 6'
                suffix: mm
              - type: section
                label: vent
              - entity: mameteo.data
                type: attribute
                attribute: vent_force
                name: vent
                suffix: km/h
                icon: mdi:wind-power-outline
              - entity: mameteo.data
                type: attribute
                name: sens du vent
                icon: mdi:windsock
                attribute: vent_direction
                suffix: °
              - entity: mameteo.data
                type: attribute
                attribute: rafale_force
                name: force rafale
                suffix: km/h
                icon: mdi:wind-power-outline
              - entity: mameteo.data
                type: attribute
                name: direction rafale
                icon: mdi:windsock
                attribute: rafale_direction
                suffix: °
              - type: divider
              - entity: mameteo.data
                type: attribute
                attribute: visibilite
                name: visibilité
                suffix: m
                icon: mdi:eye-outline
              - entity: mameteo.data
                type: attribute
                attribute: puissance_solaire
                name: puissance solaire
                suffix: W/m²
                icon: mdi:sun-wireless-outline
              - entity: sensor.rayonnement_normalise
                name: rayonnement
              - entity: mameteo.data
                type: attribute
                attribute: ensoleillement
                name: ensoleillement
                suffix: mn
              - type: divider
              - entity: mameteo.data
                type: attribute
                attribute: reference_time
                suffix: UTC
                name: date de référence
                secondary_info: last-updated
                card_mod:
                  style: >
                    {% set sc = as_timestamp(states.mameteo.data.last_updated)
                    %}

                    {% set sn = utcnow().timestamp() %}

                    {% if sc > sn -10*60 %}
                      {% set c = 'lightgreen' %}
                    {% else %}
                      {% set c = 'red' %}
                    {% endif %}

                    :host { color: {{ c }}; }
              - entity: mameteo.data
                name: date interrogation ou erreur
                card_mod:
                  style: |
                    {% set sc = states('mameteo.data') %}
                    :host {
                      {% if sc[0] != '<' %}
                        color: lightgreen;
                      {% else %}
                        color: red;
                      {% endif %}
                    }
      - type: vertical-stack
        cards:
          - type: custom:apexcharts-card
            config_templates: meteo_chart
            header:
              title: température
            yaxis:
              - min: 0
                decimals: 0
                align_to: 10
            series:
              - entity: mameteo.data
                attribute: temperature
                offset: '-1d'
                name: hier
                unit: °C
                color: lightgrey
              - entity: mameteo.data
                attribute: temperature
                name: aujourd'hui
                unit: °C
                color: red
          - type: custom:apexcharts-card
            config_templates: meteo_chart
            header:
              title: humidité
            yaxis:
              - max: 100
                min: 0
            series:
              - entity: mameteo.humidite
                offset: '-1d'
                name: hier
                unit: '%'
              - entity: mameteo.humidite
                name: aujourd'hui
                unit: '%'
          - type: custom:apexcharts-card
            config_templates: meteo_chart
            header:
              title: précipitation
            yaxis:
              - min: 0
                max: 1
                align_to: 0.2
            series:
              - entity: mameteo.precipitation
                offset: '-1d'
                name: hier
                unit: mm/6'
                group_by:
                  func: last
                  duration: 1min
              - entity: mameteo.precipitation
                name: aujourd'hui
                unit: mm/6'
                group_by:
                  func: last
                  duration: 1min
      - type: vertical-stack
        cards:
          - type: custom:apexcharts-card
            config_templates: meteo_chart
            header:
              title: pression
            series:
              - entity: mameteo.pression
                offset: '-1d'
                name: hier
                unit: hPa
              - entity: mameteo.pression
                name: aujourd'hui
                unit: hPa
          - type: custom:apexcharts-card
            config_templates: meteo_chart
            header:
              title: vent
            yaxis:
              - min: 0
                align_to: 10
                decimals: 0
            series:
              - entity: mameteo.vent_force
                offset: '-1d'
                name: hier
                unit: km/h
              - entity: mameteo.vent_force
                name: aujourd'hui
                unit: km/h
              - entity: mameteo.rafale_force
                name: rafale
                unit: km/h
                color: black
          - type: custom:apexcharts-card
            config_templates: meteo_chart
            header:
              title: visibilité
            yaxis:
              - max: 20000
                min: 0
            series:
              - entity: mameteo.visibilite
                offset: '-1d'
                name: hier
                unit: m
              - entity: mameteo.visibilite
                name: aujourd'hui
                unit: m
      - type: vertical-stack
        cards:
          - type: custom:apexcharts-card
            config_templates: meteo_chart
            header:
              title: puissance solaire
            yaxis:
              - max: 1000
                min: 0
                decimals: 0
            series:
              - entity: mameteo.puissance_solaire
                offset: '-1d'
                name: hier
                unit: W/m²
              - entity: mameteo.puissance_solaire
                name: aujourd'hui
                unit: W/m²
                color: red
          - type: custom:apexcharts-card
            config_templates: meteo_chart
            header:
              title: puissance solaire lissée - PV corrigés+lissés
            yaxis:
              - max: 1000
                min: 0
                decimals: 0
            series:
              - entity: sensor.solax_swdr7zrvpx_ac_power
                name: PV/m²
                unit: W/m²
                transform: return x/13.16/0.1995*(1-0.0);
                color: chartreuse
                statistics:
                  type: mean
                  period: hour
              - entity: mameteo.puissance_solaire
                name: puissance_solaire
                unit: W/m²
                color: magenta
                group_by:
                  func: avg
                  duration: 1h
          - type: custom:apexcharts-card
            config_templates: meteo_chart
            header:
              title: ensoleillement 6 mn
            yaxis:
              - max: 6
                min: 0
                decimals: 1
            series:
              - entity: mameteo.ensoleillement
                offset: '-1d'
                name: hier
                unit: mn
                group_by:
                  func: last
                  duration: 1min
              - entity: mameteo.ensoleillement
                name: aujourd'hui
                unit: mn
                group_by:
                  func: last
                  duration: 1min
              - entity: mameteo.ensoleillement
                name: moyenne
                unit: mn
                color: black
                group_by:
                  func: avg
                  duration: 30min

le warningregistry ne me parle pas

en ce qui concerne le manque de données (tous les null), je pense que tu as sélectionné une station sous-équipée ou en panne.
essaie en prenant une autre station…

j’ai aussi cette réponse :
{"lat": 45.2115, "lon": 5.682833, "geo_id_insee": "38185012", "reference_time": "2024-04-08T06:10:07Z", "insert_time": "2024-04-08T06:02:27Z", "validity_time": "2024-04-08T06:00:00Z", "t": 285.85, "td": 282.15, "tx": 286.75, "tn": 285.85, "u": 78, "ux": 78, "un": 72, "dd": 0, "ff": 0.0, "dxy": 110, "fxy": 1.1, "dxi": 130, "fxi": 2.0, "rr1": 0.0, "t_10": None, "t_20": None, "t_50": None, "t_100": None, "vv": None, "etat_sol": None, "sss": 0.01, "n": None, "insolh": None, "ray_glo01": None, "pres": None, "pmer": None}

sinon, la ‹ bonne › solution serait quelque chose comme :

                datage = datetime.strftime( datetime.strptime(resp['reference_time'], '%Y-%m-%dT%H:%M:%SZ'), '%d/%m/%Y %H:%M:%S' )
                p = resp['pres']
                if p is not None:
                  p /= 100
                rg = resp['ray_glo01']
                if rg is not None:
                  rg /= 360
                hass.states.set( 'mameteo.data', datetime.now().strftime("%d/%m/%Y %H:%M:%S"), 
                                  {
                                    'raw': str(resp).replace('\'', '\"'),       # ainsi on peut faire : (state_attr('mameteo.data','raw') | from_json)['t']
                                    'reference_time': datage,                   # date and time of the production of the data in UTC
                                    'temperature': resp['t']-273.15,            # air temperature at 2 meters above the ground in Kelvin degrees -> °C
                                    'humidite': resp['u'],                      # hourly relative humidity at 2 meters 
                                    'pression': p,                              # station pressure in Pa -> hPa 
                                    'vent_direction': resp['dd'],               # mean wind direction at 10 meters above the ground in degrees
                                    'vent_force': resp['ff']*3.6,               # mean wind speed at 10 meters above the ground in m/s -> km/h
                                    'rafale_direction': resp['dxi10'],          # 10 minutes mean wind gust direction at 10 meters above the ground in degrees 
                                    'rafale_force': resp['fxi10']*3.6,          # 10 minutes mean wind gust speed at 10 meters above the ground in m/s
                                    'precipitation': resp['rr_per'],            # all precipitation over the previous 6 minutes in mm  
                                    'puissance_solaire': rg,                    # global radiation over the previous 6 minutes in J/m² = Wh/m² pendant 6mn -> puissance solaire W/m²
                                    'ensoleillement': resp['insolh'],           # sunshine duration over the previous 1H in min
                                    'visibilite': resp['vv'],                   # horizontal visibility in meters 
                                    'origine': 'Météo France, Données Observation 6mn'
                                  })
                hass.states.set( 'mameteo.reference_time',   datage,                 { 'unit_of_measurement': 'UTC' } )
                hass.states.set( 'mameteo.temperature',      resp['t']-273.15,       { 'unit_of_measurement': '°C' } )
                hass.states.set( 'mameteo.humidite',         resp['u'],              { 'unit_of_measurement': '%' } )
                hass.states.set( 'mameteo.pression',         p,                      { 'unit_of_measurement': 'hPa' } )
                hass.states.set( 'mameteo.vent_direction',   resp['dd'],             { 'unit_of_measurement': '°' } )
                hass.states.set( 'mameteo.vent_force',       resp['ff']*3.6,         { 'unit_of_measurement': 'km/h' } )
                hass.states.set( 'mameteo.rafale_direction', resp['dxi10'],          { 'unit_of_measurement': '°' } )
                hass.states.set( 'mameteo.rafale_force',     resp['fxi10']*3.6,      { 'unit_of_measurement': 'km/h' } )
                hass.states.set( 'mameteo.precipitation',    resp['rr_per'],         { 'unit_of_measurement': 'mm/1h' } )
                hass.states.set( 'mameteo.puissance_solaire',rg,                     { 'unit_of_measurement': 'W/m²' } )
                hass.states.set( 'mameteo.ensoleillement',   resp['insolh'],         { 'unit_of_measurement': 'mn' } )
                hass.states.set( 'mameteo.visibilite',       resp['vv'],             { 'unit_of_measurement': 'm' } )

à faire aussi pour t, ff et fxi10
enfin, tous ceux sur lesquels il y a des calculs…

Je voulais tester le sujet mais je m’aperçois que je n’ai pas le service python_script.exec
C’est étrange ça !

J’ai bien le service déclaré dans ma configuration !

########################################################
###                   Service Python                 ###
########################################################
python_script:

Il faut impérativement mettre ce dépôt ?

Si oui du coup, il y a incompatibilité avec le script jour férié que j’avais par exemple

Arf python j’aime pas ça :slight_smile:

il faut aussi installer Python sur la machine qui fait tourner HA
est-ce la bonne réponse ?
l’avantage, c’est que quand ça marche, on peut ‹ tout › faire avec des choses comme

shell_command:
  bdd_exportation: /usr/bin/python3 /home/pi/.homeassistant/include/python_scripts/BDDexport.py

Salut,

par rapport a ton dashboard, il manque la description de config_templates: meteo_chart

tu peut le rajouter, stp ?

voici

apexcharts_card_templates:
  meteo_chart:
    apex_config:
      chart:
        height: 180px
      legend:
        show: false
    graph_span: 24h
    header:
      show: true
      show_states: true
      colorize_states: true
    color_list:
      - lightblue
      - red
    all_series_config:
      stroke_width: 2
      fill_raw: 'null'
1 « J'aime »