Note de ce sujet :
  • Moyenne : 0 (0 vote(s))
  • 1
  • 2
  • 3
  • 4
  • 5
Prévision ensoleillement - Routeur F1ATB-S3
#1
Actuellement en phase de développement d'un nouveau routeur avec un ESP32-S3, je souhaite intégrer la prévision d'ensoleillement pour la journée à venir afin de forcer des actions comme le chauffage de l'eau sanitaire la nuit si les prévisions sont mauvaises. Utile pour la douche du soir.

Certains d'entre vous ont implanté ce type de fonction dans des systèmes de domotique. Quel prestataire utilisez-vous ? Est-il fiable et gratuit ? Complexité de l'API ? 

Vos suggestions svp

André / F1ATB
Répondre

#2
(Hier, 09:11 AM)F1ATB a écrit : Actuellement en phase de développement d'un nouveau routeur avec un ESP32-S3, je souhaite intégrer la prévision d'ensoleillement pour la journée à venir afin de forcer des actions comme le chauffage de l'eau sanitaire la nuit si les prévisions sont mauvaises. Utile pour la douche du soir.

Certains d'entre vous ont implanté ce type de fonction dans des systèmes de domotique. Quel prestataire utilisez-vous ? Est-il fiable et gratuit ? Complexité de l'API ? 

Vos suggestions svp

André / F1ATB

Bonjour,

Sur home assistant, j'utilise une integration solar forecast, basé sur open météo
https://github.com/rany2/ha-open-meteo-solar-forecast

https://open-meteo.com/en/docs

une bonne source d'inspiration, prevision à 8 jrs relativement fiable en terme de prevision, de disponibilité et gratuit
n etant pas développeur pas d'avis sur la complexité de l'api

merci pour votre routeur et votre partage !!
Répondre

#3
Hello,
j'utilise également Solar forecast en extension dans Home assistant mais aussi open météo en direct via un autre plugin .
petite préférence pour Solar Forecast plus précis me semble-t-il.
La prévision à 8 jours est parfois erronée , par contre la prévision à 24 heures reste fiable à 90% d'après mes estimations
Intéressant la prévision dans l'heure aussi
tel qu'utilisé dans home assistant , l'usage est entièrement gratuit sans contraintes.
Config : 3 routeurs F1ATB en V17.15 - 2 routeurs fixes en mode Triacs + 1 routeur mobile polyvalent en mode : Triac+SSR + 1 afficheur distant ESP32-S3
PV : (8*425W + Onduleur SunGrow 3KW) + (2 *500w + MO Hoymiles HMS-1000W-2T)
Supervision & Domotique : F1atb + Home Assistant / Shelly & MQTT
Répondre

#4
J'utilise l'intégration solcast forecast qui est fiable sur les 24/48h à venir .

C'est gratuit et assez simple de mise en place finalement
Répondre

#5
j'exploite actuellement ces infos de prévision sur mon ESP32-S3 monté en afficheur Solaire ( via esphome sous HA)
sur le scan joint, on trouve en orange, la prévision de la journée, la prévision de la prochaine heure et la prévision du lendemain


Pièces jointes Miniature(s)
   
Config : 3 routeurs F1ATB en V17.15 - 2 routeurs fixes en mode Triacs + 1 routeur mobile polyvalent en mode : Triac+SSR + 1 afficheur distant ESP32-S3
PV : (8*425W + Onduleur SunGrow 3KW) + (2 *500w + MO Hoymiles HMS-1000W-2T)
Supervision & Domotique : F1atb + Home Assistant / Shelly & MQTT
Répondre

#6
de mon coté j ai deja integré directement dans mon routeur, en terme de prevision je regarde la prevision du GTI qui est l image la plus fidele du rayonnemnt solaire.
Je n ai pas mis plein de paramètres our calculer le vrai GTI en fonction de l expo de mes panneaux, je l'utilise en relatif avec des seuils empiriques, l avantage par rapport une prevision meteo le GTI est representatif été comme hiver. Donc à minuit je prend en compte la prevision GTI moyenne du lendemain, empiriquement avec mon instalmation de PV je sais que j aurais assez de soleil pour chauffer completement mon CE avec une prévision  GTI>450 
L api  api.open-meteo.com semble etre perenne, elle donne des resultats fiables, une api très bien documentée et simple

Le principe à retenir:

Une seule requête HTTP GET vers Open-Meteo, avec global_tilted_irradiance demandé dans hourly. Pas de clé API, pas d'authentification.
L'API renvoie deux tableaux parallèles (time[] et global_tilted_irradiance[]) qu'on lit par index — l'index i de l'un correspond à l'index i de l'autre.
Deux exploitations distinctes : une valeur instantanée (moyenne autour de l'heure courante) et une prévision (moyenne des heures de jour de demain).
Pour le callcul de la moyenne du lendemain je fais la moyenne entre la première  et la derniere valeur GTI non nulle ca permet de determier le "vrai" lever et coucher de sommeil . La durée du jour n'a donc plus d influence sur ma moyenne
Je ne cherche pas à calculer des wh par integration car la valeur depend de trop de paramètres qu'ils faudraient renseigner ( Peut etre faire une integration , avec un parametre d'etalonnage basé sur le relevé des wh produit et du GTI annoncé ? bof)

( J'ai modfifié volonatirement mes coordonnées de localisation)


Code :
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>

// =========================================================
//  RÉCUPÉRATION DE L'ENSOLEILLEMENT (GTI) VIA OPEN-METEO
//  Exemple pédagogique — ESP32
// =========================================================

// --- 1. L'URL DE L'API ---------------------------------------------------
// On interroge Open-Meteo (gratuit, sans clé). Le paramètre clé est
// "global_tilted_irradiance" placé dans le bloc "hourly" : c'est lui qui
// renvoie l'ensoleillement (W/m²) heure par heure, pour un panneau incliné.
// forecast_days=2 => on récupère aujourd'hui ET demain.
const char* METEO_URL =
  "http://api.open-meteo.com/v1/forecast"
  "?latitude=46.7667&longitude=4.2667"
  "&current_weather=true"
  "&hourly=global_tilted_irradiance"
  "&timezone=Europe%2FParis"
  "&forecast_days=2";

void recupererEnsoleillement() {
    if (WiFi.status() != WL_CONNECTED) return;

    // --- 2. REQUÊTE HTTP -------------------------------------------------
    HTTPClient http;
    http.begin(METEO_URL);
    int httpCode = http.GET();
    if (httpCode != HTTP_CODE_OK) {          // 200 attendu
        http.end();
        return;
    }
    String payload = http.getString();       // le JSON renvoyé par l'API
    http.end();

    // --- 3. PARSING DU JSON ----------------------------------------------
    // Le buffer doit être assez grand pour 48h de données (2 jours).
    DynamicJsonDocument doc(3072);
    if (deserializeJson(doc, payload)) return;   // échec => on sort

    // L'API renvoie deux tableaux parallèles dans "hourly" :
    //   "time" : ["2026-06-23T00:00", "2026-06-23T01:00", ...]
    //   "global_tilted_irradiance" : [0, 0, ..., 850, 920, ...]
    JsonArray hourlyTime = doc["hourly"]["time"];
    JsonArray hourlyGti  = doc["hourly"]["global_tilted_irradiance"];

    // --- 4. TROUVER L'HEURE COURANTE DANS LE TABLEAU ---------------------
    // On lit l'heure actuelle fournie par l'API, puis on cherche l'index
    // correspondant dans le tableau horaire.
    String currentTimeStr = doc["current_weather"]["time"].as<String>();
    int currentHour = currentTimeStr.substring(11, 13).toInt();   // "14" -> 14

    int currentHourIndex = 0;
    for (int i = 0; i < hourlyTime.size(); i++) {
        int hour = hourlyTime[i].as<String>().substring(11, 13).toInt();
        if (hour == currentHour) { currentHourIndex = i; break; }
    }

    // --- 5. GTI "ACTUEL" : moyenne glissante h-1 / h / h+1 ---------------
    // On lisse la valeur instantanée sur 3 heures (zéros inclus).
    float gtiActuel = 0.0; int n = 0;
    for (int offset = -1; offset <= 1; offset++) {
        int idx = currentHourIndex + offset;
        if (idx >= 0 && idx < hourlyGti.size()) {
            gtiActuel += hourlyGti[idx].as<float>();
            n++;
        }
    }
    if (n > 0) gtiActuel /= n;

    // --- 6. PRÉVISION J+1 : moyenne des heures ensoleillées de demain ----
    // On repère le 1er créneau horaire de demain via sa date "YYYY-MM-DD",
    // puis on moyenne les 24 valeurs en ignorant les heures de nuit (GTI = 0).
    String demain = doc["daily"]["time"][1].as<String>();   // <-- voir note
    // (Avec cette URL simplifiée il faut aussi demander &daily=...; sinon
    //  on peut déduire la date de demain à partir de hourlyTime.)

    float gtiPrevuD1 = 0.0; int countJour = 0;
    int startDemain = -1;
    for (int i = 0; i < hourlyTime.size(); i++) {
        if (hourlyTime[i].as<String>().startsWith(demain.substring(0, 10))) {
            startDemain = i; break;
        }
    }
    if (startDemain != -1) {
        for (int i = 0; i < 24; i++) {
            int idx = startDemain + i;
            if (idx < (int)hourlyGti.size()) {
                float g = hourlyGti[idx].as<float>();
                if (g > 0.0) { gtiPrevuD1 += g; countJour++; }   // nuit ignorée
            }
        }
        if (countJour > 0) gtiPrevuD1 /= countJour;
    }

    // --- 7. RÉSULTAT -----------------------------------------------------
    Serial.printf("GTI actuel    : %.0f W/m2\n", gtiActuel);
    Serial.printf("GTI moyen J+1 : %.0f W/m2\n", gtiPrevuD1);
}
Répondre

#7
Merci pour vos retours détaillés qui vont me permettre d'implanter cette fonction dans le routeur-S3
Répondre

#8
j utilise aussi https://api.open-meteo.com/

voici un petit code html  qui peux aider.
Code :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Prévision production solaire (Open-Meteo)</title>

<style>
body {
    font-family: Arial, sans-serif;
    background: #f4f6f8;
    padding: 20px;
}
h1 {
    text-align: center;
}
table {
    border-collapse: collapse;
    width: 100%;
    background: #fff;
}
th, td {
    border: 1px solid #ccc;
    padding: 6px;
    text-align: center;
    font-size: 14px;
}
th {
    background: #eee;
}
.good { background: #c8f7c5; }
.medium { background: #fff3b0; }
.bad { background: #f7c5c5; }
</style>
</head>

<body>

<h1>☀️ Prévision de production solaire (5 jours)</h1>

<table id="table">
<thead>
<tr id="header">
    <th>Date</th>
    <th>? Lever</th>
    <th>? Coucher</th>
    <th>Énergie jour (Wh)</th>
</tr>
</thead>
<tbody></tbody>
</table>

<script>
// ===== PARAMÈTRES =====
const latitude = 50.66;
const longitude = 3.22;
const surfacePV = 10;     // m²
const rendement = 0.285;  // 18 %
// ======================

const url =
`https://api.open-meteo.com/v1/forecast?
latitude=${latitude}&longitude=${longitude}
&hourly=shortwave_radiation
&daily=sunrise,sunset
&forecast_days=5
&timezone=Europe/Paris`;

fetch(url)
.then(r => r.json())
.then(data => {

    const times = data.hourly.time;
    const rad   = data.hourly.shortwave_radiation;

    const sunrises = data.daily.sunrise;
    const sunsets  = data.daily.sunset;
    const datesDaily = data.daily.time;

    const jours = {};
    const heuresGlobales = new Set();

    times.forEach((t, i) => {
        if (rad[i] <= 0) return;

        const d = new Date(t);
        const h = d.getHours();
        const date = d.toISOString().slice(0,10);

        heuresGlobales.add(h);

        if (!jours[date]) jours[date] = {};
        jours[date][h] = rad[i];
    });

    const heures = [...heuresGlobales].sort((a,b)=>a-b);

    // Construction entête heures
    const header = document.getElementById("header");
    heures.forEach(h => {
        const th = document.createElement("th");
        th.textContent = h + "h";
        header.insertBefore(th, header.lastElementChild);
    });

    const tbody = document.querySelector("#table tbody");

    Object.keys(jours).forEach((date, index) => {
        let tr = document.createElement("tr");
        let energieJour = 0;

        const lever  = sunrises[index]?.slice(11,16) || "--:--";
        const coucher = sunsets[index]?.slice(11,16) || "--:--";

        tr.innerHTML = `
            <td><b>${date}</b></td>
            <td>${lever}</td>
            <td>${coucher}</td>
        `;

        heures.forEach(h => {
            const r = jours[date][h] || 0;
            const prodW = r * surfacePV * rendement;
            energieJour += prodW;

            let cls = "bad";
            if (r > 400) cls = "good";
            else if (r > 150) cls = "medium";

            tr.innerHTML += `
                <td class="${cls}">
                    ${Math.round(prodW)} Wh<br>
                </td>`;
        });

        tr.innerHTML += `<td><b>${Math.round(energieJour)} Wh</b></td>`;
        tbody.appendChild(tr);
    });
})
.catch(err => {
    alert("❌ Erreur Open-Meteo");
    console.error(err);
});
</script>

</body>
</html>
Répondre



Atteindre :


Utilisateur(s) parcourant ce sujet :
4 visiteur(s)

Moteur MyBB, © 2002-2026 Melroy van den Berg.