Python
Force et direction du vent
FFVL
Liste des balises : https://data.ffvl.fr/json/balises.json
Relevés : https://data.ffvl.fr/json/relevesmeteo.json
Pioupiou
Liste des balises et relevés : https://api.pioupiou.fr/v1/live/all
Prévision pluie heure par heure
Lib :
pip install meteofrance-api
Code :
from meteofrance_api import MeteoFranceClient
import time
client = MeteoFranceClient()
rain = client.get_rain(latitude=49.276437, longitude=-0.703140)
for forecast in rain.forecast:
hour = time.strftime('%d/%m/%Y %H:%M:%S', time.localtime(forecast['dt']))
print(hour, forecast['desc'], forecast['rain'])
Sortie :
12/07/2023 13:30:00 Temps sec 1
12/07/2023 13:35:00 Temps sec 1
12/07/2023 13:40:00 Temps sec 1
12/07/2023 13:45:00 Temps sec 1
12/07/2023 13:50:00 Temps sec 1
12/07/2023 13:55:00 Temps sec 1
12/07/2023 14:05:00 Temps sec 1
12/07/2023 14:15:00 Temps sec 1
12/07/2023 14:25:00 Temps sec 1
Détermination du jour et de la nuit
pip install pyephem
import ephem
import datetime
import math
# Parameters : latitude, longitude and timestamp utc of observer
# Return : the height of the sun
def sun_height(latitude, longitude, timestamp):
observer = ephem.Observer()
observer.lat = latitude * math.pi / 180.0
observer.lon = longitude * math.pi / 180.0
observer.date = datetime.datetime.fromtimestamp(timestamp).strftime("%Y/%m/%d %H:%M:%S")
sun = ephem.Sun(observer)
return sun.alt * 180.0 / math.pi
# If the top of the sun is higher than the horizon (Diameter of sun = 0.5 degrees)
if sun_height(49.276437, -0.703140, 1689161276) > -0.25:
print('jour')
else:
print('nuit')
Téléchargement de météogramme
import requests
from lxml import etree
from io import StringIO
def download_meteogramme(url_page, fichier_telecharge):
username = "************"
password = "************"
url = "https://www.meteoblue.com/fr/user/login/index"
session = requests.Session()
response = session.get(url)
if response.status_code == 200:
parser = etree.HTMLParser()
tree = etree.parse(StringIO(response.text), parser)
csrf = tree.find("//input[@id='csrf']")
csrf_name = csrf.get('name')
csrf_value = csrf.get('value')
data = {"username": username, "password": password, csrf_name: csrf_value}
response = session.post(url, data=data)
url = url_page
response = session.get(url)
if response.status_code == 200:
html = etree.HTML(response.content)
div = html.xpath("//div[@id='blooimage']")[0]
img_url = f'https:{div.get("data-href")}'
response = requests.get(img_url)
with open(fichier_telecharge, "wb") as f:
f.write(response.content)
else:
print("Error:", response.status_code)
Historique de la batterie de la balise FFVL
Crédit : David L. – Licence : CC BY-SA 4.0
Script utilisé pour générer le graphique :
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#Auteur : David LOUISE
import os
import sys
import argparse
import requests
import pandas as pd
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
API_BASE = "https://data.ffvl.fr/api/"
DEFAULT_HOURS = 72
DEFAULT_API_KEY = os.getenv("FFVL_API_KEY", "00000000000000000000000000000000")
def fetch_balise_data(balise_id: int, hours: int = DEFAULT_HOURS, api_key: str = DEFAULT_API_KEY):
"""Récupère les données JSON pour une balise donnée."""
params = {
"base": "balises",
"r": "histo",
"hours": str(hours),
"idbalise": str(balise_id),
"mode": "json",
"key": api_key,
}
try:
resp = requests.get(API_BASE, params=params, timeout=20)
resp.raise_for_status()
except requests.RequestException as e:
print(f"Erreur HTTP en récupérant les données: {e}", file=sys.stderr)
sys.exit(1)
try:
data = resp.json()
except ValueError:
print("Réponse non JSON reçue depuis l’API.", file=sys.stderr)
sys.exit(1)
if not isinstance(data, list) or len(data) == 0:
print("Aucune donnée renvoyée par l’API pour cette balise/intervalle.", file=sys.stderr)
sys.exit(1)
return data
def build_dataframe(records):
"""Transforme la liste JSON en DataFrame propre."""
df = pd.DataFrame.from_records(records)
df["date"] = pd.to_datetime(df["date"], errors="coerce")
for col in ("u_sol", "u_bat"):
if col in df.columns:
df[col] = pd.to_numeric(df[col], errors="coerce")
else:
df[col] = pd.NA
df = df.dropna(subset=["date"])
df = df.sort_values("date").reset_index(drop=True)
return df
def plot_panneau_et_batterie(df: pd.DataFrame, balise_id: int, out_path: str):
"""Trace panneau solaire et batterie sur le même axe Y, en points non reliés, axe X formaté toutes les 4 h."""
if df["u_sol"].isna().all() and df["u_bat"].isna().all():
print("Aucune valeur exploitable pour le panneau solaire ou la batterie.", file=sys.stderr)
sys.exit(1)
fig, ax = plt.subplots(figsize=(10, 5))
# Panneau solaire (rouge)
if not df["u_sol"].isna().all():
ax.scatter(df["date"], df["u_sol"], color="red", label="Panneau solaire (mV)", s=10)
# Batterie (bleu)
if not df["u_bat"].isna().all():
ax.scatter(df["date"], df["u_bat"], color="blue", label="Batterie (mV)", s=10)
ax.set_xlabel("Date / heure")
ax.set_ylabel("Tension (mV)")
ax.legend(loc="best")
plt.title(f"Balise {balise_id} — Panneau solaire (rouge) & Batterie (bleu)")
# Axe X : un tick toutes les 4h, format jour/heure
ax.xaxis.set_major_locator(mdates.HourLocator(interval=4))
ax.xaxis.set_major_formatter(mdates.DateFormatter("%d/%m %Hh"))
fig.autofmt_xdate(rotation=45)
ax.grid(True, which='major', linestyle='-', linewidth=0.3)
plt.tight_layout()
plt.savefig(out_path, dpi=150)
plt.close(fig)
def main():
parser = argparse.ArgumentParser(description="Génère un graphique panneau solaire & batterie pour une balise FFVL (PNG).")
parser.add_argument("balise_id", type=int, help="Identifiant de la balise (ex: 97)")
parser.add_argument("--hours", type=int, default=DEFAULT_HOURS, help=f"Fenêtre historique en heures (défaut: {DEFAULT_HOURS})")
parser.add_argument("--out", type=str, default=None, help="Fichier PNG de sortie (défaut: <balise_id>.png)")
parser.add_argument("--api-key", type=str, default=DEFAULT_API_KEY, help="Clé API FFVL (optionnelle)")
args = parser.parse_args()
out_path = args.out or f"{args.balise_id}.png"
data = fetch_balise_data(args.balise_id, hours=args.hours, api_key=args.api_key)
df = build_dataframe(data)
plot_panneau_et_batterie(df, args.balise_id, out_path)
print(f"Fichier généré : {out_path}")
if __name__ == "__main__":
main()