Bonjour,
Je viens déposer ma petite contribution sur l’acquisition des couleurs tempo.
De ce que j’ai pu lire en parcourant (rapidement, trop de pages) ce sujet, beaucoup utilisent les services d’api-couleur-tempo.fr. Bien que je ne mette pas en doute la fiabilité de ce service, le passé nous a plusieurs fois démontré que rien n’est acquis puisque les services tiers auxquels on s’est adressé ont disparus.
http://domogeek.entropialux.com/tempoedf, et plus récemment
https://particulier.edf.fr/services/res ... TempoStore, qui a cessé de fonctionner fin 2024. Rien ne prouve qu’api-couleur-tempo.fr ne subisse pas le même sort.
C'est pourquoi j'ai jugé préférable de demander les données directement à RTE, plutôt que d'utiliser un service tiers susceptible de disparaître du jour au lendemain.
Voici la méthode que j'ai mise en place pour mes propres besoins et que je partage ici.
En pratique, j'ai utilisé les deux sources pour récupérer les informations du jour et du lendemain, et j'ai comparé les résultats afin de vérifier leur bon fonctionnement et leur cohérence. J'ai privilégié la récupération des données auprès de RTE et, si celles-ci sont indisponibles, je les récupère auprès d'api-couleur-tempo.fr.
Notez que je ne suis pas expert en programmation et que j'ai donc largement utilisé ChatGPT, que j’ai laissé tombé au profit de Claude.ai, pour écrire ce script. Il est probablement possible de l'améliorer, et je suis ouvert à toute suggestion.
Commençons par RTE.
1. Rendez-vous sur le site web
https://data.rte-france.com/web/guest# pour vous inscrire.
2. Cliquez sur « Créer mon compte ». Saisissez les informations requises et validez. Vous devez attendre l'e-mail de confirmation avant de continuer. Cette première étape n'a pas été simple, car je n'ai jamais reçu l'e-mail qui m'aurait permis d'accéder à mon compte. Sans lui, il m'était impossible de poursuivre. J'ai dû contacter l'assistance téléphonique (
rte-hotline@rte-france.com) pour qu'ils débloquent mon adresse e-mail et activent mon compte.
3. Une fois connecté à votre compte, recherchez l'API « Tempo Like Supply Contract », puis cliquez sur « Découvrir l’API » et « S'abonner à l’API » pour créer une application.
4. Donnez un nom à votre application ; vous pourrez l'utiliser ultérieurement pour d'autres API. Sélectionnez « Web/Serveur » comme type, saisissez une description et enregistrez.
5. Une fois votre application créée, rendez-vous dans l'onglet « Mes applications » où vous trouverez l'application que vous venez de créer. Cliquez dessus pour l'ouvrir. En bas, vous devriez voir l'API « Tempo Like Supply Contract » associée.
6. Votre application devrait afficher votre « ID client » et votre « ID secret ». Bien que ces valeurs soient importantes, nous avons besoin de leur version encodée en Base64. Cliquez sur le bouton « Copier en Base64 » et enregistrez cette copie pour l'utiliser dans le script. Ces informations vous permettront d'obtenir le jeton d'accès à l'API.
En effet, la récupération d'informations depuis le site web RTE se déroule en deux étapes :
1. Obtenir le jeton OAuth2 à l'aide des identifiants encodés en Base64 de votre application. Ce jeton est valable une heure.
2. Interroger l'API pour récupérer les données JSON correspondant à votre requête à l'aide du jeton d'authentification.
Pour sécuriser votre « ID client » et votre « ID secret », créez un fichier nommé « rte_api.key » où vous stockez votre ID client et votre ID secret en Base64. Je les ai enregistrés dans /home/pi/domoticz/scripts/. Vous devrez indiquer au script où vous les avez enregistrés.
Passons maintenant à Domoticz.
Nous allons d'abord créer deux sélecteurs virtuels nommés « Tempo Aujourd'hui » et « Tempo Demain ». Pour chacun d'eux, nous définissons trois niveaux : Bleu = 10, Blanc = 20 et Rouge = 30. Vous pouvez désactiver le niveau 0 (Arrêt) pour le premier sélecteur si nécessaire. Il ne reste plus qu'à installer le script dzVents ci-dessous dans la section Événements, à remplacer les Idx des deux commutateurs de sélection par ceux de votre Domoticz et à indiquer le chemin d'accès à votre fichier rte_api.key dans la section « Récupération RTE » :
Code : Tout sélectionner
-- Script de récupération des informations Tempo J et J+1
-- À partir de l'API RTE en priorité (https://data.rte-france.com)
-- et les données du site www.api-couleur-tempo.fr en secours
return {
active = true,
on = { timer = { 'at 06:15', 'at 11:15' } },
execute = function(dz)
---------------------------------------
-- Configuration des devices (IDX)
---------------------------------------
local TEMPO_AUJOURDHUI_IDX = 999 -- À REMPLACER par votre IDX
local TEMPO_DEMAIN_IDX = 999 -- À REMPLACER par votre IDX
dz.log("⏳ Récupération des couleurs Tempo via RTE (priorité) + fallback Tiers...", dz.LOG_INFO)
---------------------------------------
-- Fonctions utilitaires
---------------------------------------
-- Détection automatique du fuseau horaire (heure d'été/hiver)
local function getFrenchTimezone()
-- Méthode simple : comparer l'heure locale et UTC
-- En hiver : UTC+1, en été : UTC+2
local now = os.time()
local utcDate = os.date("!*t", now) -- Date UTC
local localDate = os.date("*t", now) -- Date locale
-- Calculer la différence en heures
local utcTime = utcDate.hour * 3600 + utcDate.min * 60 + utcDate.sec
local localTime = localDate.hour * 3600 + localDate.min * 60 + localDate.sec
local diff = (localTime - utcTime) / 3600
-- Gérer le passage de minuit
if diff < -12 then diff = diff + 24 end
if diff > 12 then diff = diff - 24 end
-- En France : +1 en hiver, +2 en été
local offset = math.floor(diff + 0.5)
-- RTE utilise l'heure française : UTC+2 en été, UTC+1 en hiver
return string.format("+%02d:00", offset)
end
local function codeToLevelRTE(val)
if val == "BLUE" then return 10, "BLEU"
elseif val == "WHITE" then return 20, "BLANC"
elseif val == "RED" then return 30, "ROUGE"
else return 0, "Pas d'info"
end
end
local function codeToLevelTiers(code)
code = tonumber(code)
if code == 1 then return 10, "BLEU"
elseif code == 2 then return 20, "BLANC"
elseif code == 3 then return 30, "ROUGE"
else return 0, "Pas d'info"
end
end
-- Lecture de la clé API depuis un fichier
local function loadAPIKey(path)
local f, err = io.open(path, "r")
if not f then
return nil, "❌ Impossible de charger la clé API RTE : " .. (err or "")
end
local raw = f:read("*a")
f:close()
if not raw or raw == "" then
return nil, "❌ Clé API RTE vide après lecture"
end
-- Nettoyage espaces / retours chariot éventuels
local key = raw:gsub("^%s+", ""):gsub("%s+$", "")
return key
end
local function getToken(apiKey)
local maxRetries = 2
local retryDelay = 3
for attempt = 1, maxRetries do
local handle = io.popen(
"curl -s -X POST 'https://digital.iservices.rte-france.com/token/oauth/' " ..
"-H 'Content-Type: application/x-www-form-urlencoded' " ..
"-H 'Authorization: Basic " .. apiKey .. "' " ..
"-d 'grant_type=client_credentials'"
)
local result = handle:read("*a")
handle:close()
local data = dz.utils.fromJSON(result)
if data and data.access_token then
if attempt > 1 then
dz.log("✅ Token RTE obtenu après " .. attempt .. " tentative(s)", dz.LOG_INFO)
end
return data.access_token
end
if attempt < maxRetries then
dz.log("⚠️ Échec obtention token RTE (tentative " .. attempt .. "/" .. maxRetries .. "), réessai dans " .. retryDelay .. "s", dz.LOG_WARNING)
os.execute("sleep " .. retryDelay)
end
end
dz.log("❌ Impossible d'obtenir un token RTE après " .. maxRetries .. " tentatives", dz.LOG_ERROR)
return nil
end
local function getRTEData(token, start_date, end_date)
local url = "https://digital.iservices.rte-france.com/open_api/tempo_like_supply_contract/v1/tempo_like_calendars" ..
"?start_date=" .. start_date ..
"&end_date=" .. end_date ..
"&fallback_status=true"
local cmd = "curl -s -X GET '" .. url .. "' " ..
"-H 'Accept: application/json' " ..
"-H 'Authorization: Bearer " .. token .. "'"
local handle = io.popen(cmd)
local result = handle:read("*a")
handle:close()
return dz.utils.fromJSON(result)
end
local function getTiersData()
local urls = {
["Tempo Aujourd'hui"] = "https://www.api-couleur-tempo.fr/api/jourTempo/today",
["Tempo Demain"] = "https://www.api-couleur-tempo.fr/api/jourTempo/tomorrow"
}
local out = {}
for name, url in pairs(urls) do
local handle = io.popen("curl -s '" .. url .. "'")
local result = handle:read("*a")
handle:close()
local data = dz.utils.fromJSON(result)
if data and data.codeJour then
local lvl, couleur = codeToLevelTiers(data.codeJour)
out[name] = { level = lvl, couleur = couleur }
else
dz.log("⚠️ Donnée Tiers manquante pour " .. name, dz.LOG_WARNING)
end
end
return out
end
---------------------------------------
-- Récupération RTE
---------------------------------------
local apiKey, err = loadAPIKey("/chemin/vers/votre/rte_api.key") -- À MODIFIER
if not apiKey then
dz.log(err, dz.LOG_ERROR)
end
local token = getToken(apiKey)
local dataRTE = {}
if token then
-- Détection automatique du timezone français
local timezone = getFrenchTimezone()
local today = os.date("%Y-%m-%dT00:00:00") .. timezone
local afterTomorrow = os.date("%Y-%m-%dT00:00:00", os.time() + 2*24*3600) .. timezone
dz.log("🔍 Plage demandée à RTE: " .. today .. " → " .. afterTomorrow, dz.LOG_INFO)
local json = getRTEData(token, today, afterTomorrow)
if json and json.tempo_like_calendars and json.tempo_like_calendars.values then
dz.log("🔍 Données RTE reçues : " .. #json.tempo_like_calendars.values .. " entrée(s)", dz.LOG_INFO)
for _, entry in ipairs(json.tempo_like_calendars.values) do
local lvl, couleur = codeToLevelRTE(entry.value)
local startDate = entry.start_date:sub(1,10)
local todayDate = os.date("%Y-%m-%d")
local tomorrowDate = os.date("%Y-%m-%d", os.time() + 24*3600)
if startDate == todayDate then
dataRTE["Tempo Aujourd'hui"] = { level = lvl, couleur = couleur }
elseif startDate == tomorrowDate then
dataRTE["Tempo Demain"] = { level = lvl, couleur = couleur }
end
end
-- Log récapitulatif de ce qui a été trouvé dans RTE
if dataRTE["Tempo Aujourd'hui"] then
dz.log("✅ RTE fournit Tempo Aujourd'hui: " .. dataRTE["Tempo Aujourd'hui"].couleur, dz.LOG_INFO)
else
dz.log("⚠️ RTE ne fournit PAS Tempo Aujourd'hui", dz.LOG_WARNING)
end
if dataRTE["Tempo Demain"] then
dz.log("✅ RTE fournit Tempo Demain: " .. dataRTE["Tempo Demain"].couleur, dz.LOG_INFO)
else
dz.log("⚠️ RTE ne fournit PAS Tempo Demain", dz.LOG_WARNING)
end
else
dz.log("⚠️ Réponse RTE invalide ou vide", dz.LOG_WARNING)
end
end
---------------------------------------
-- Récupération Tiers (fallback)
---------------------------------------
local dataTiers = getTiersData()
---------------------------------------
-- Choix final et mise à jour (RTE prioritaire, puis Tiers)
---------------------------------------
local finalVals = {}
local sourcesUsed = {}
-- Table de correspondance nom logique -> IDX
local devices = {
["Tempo Aujourd'hui"] = TEMPO_AUJOURDHUI_IDX,
["Tempo Demain"] = TEMPO_DEMAIN_IDX
}
for _, deviceName in ipairs({ "Tempo Aujourd'hui", "Tempo Demain" }) do
local src = nil
local couleur = nil
local level = 0
-- Priorité RTE, fallback Tiers
if dataRTE[deviceName] then
src = "RTE"
level = dataRTE[deviceName].level
couleur = dataRTE[deviceName].couleur
elseif dataTiers[deviceName] then
src = "Tiers (fallback)"
level = dataTiers[deviceName].level
couleur = dataTiers[deviceName].couleur
end
-- Appliquer / logger
if src then
dz.log("🎯 " .. deviceName .. " : " .. (couleur or "inconnu") .. " (source = " .. src .. ")", dz.LOG_INFO)
-- Mise à jour du device par son IDX (plus fiable que par nom)
local deviceIdx = devices[deviceName]
dz.devices(deviceIdx).switchSelector(level)
else
dz.log("❌ Aucune donnée disponible pour " .. deviceName, dz.LOG_ERROR)
end
finalVals[deviceName] = { src = src, couleur = couleur, level = level }
if src then
table.insert(sourcesUsed, src)
end
-- Comparaison si les deux sources sont présentes pour ce device
if dataRTE[deviceName] and dataTiers[deviceName] then
if dataRTE[deviceName].couleur ~= dataTiers[deviceName].couleur then
dz.log("⚠️ DIVERGENCE : RTE = " .. dataRTE[deviceName].couleur ..
" / Tiers = " .. dataTiers[deviceName].couleur, dz.LOG_ERROR)
else
dz.log("✅ Cohérence confirmée pour " .. deviceName, dz.LOG_INFO)
end
end
end -- fin for
-- Log récapitulatif des sources utilisées
if #sourcesUsed > 0 then
local uniqueSources = {}
for _, s in ipairs(sourcesUsed) do
uniqueSources[s] = true
end
local sourcesList = {}
for s in pairs(uniqueSources) do
table.insert(sourcesList, s)
end
dz.log("📊 Sources utilisées : " .. table.concat(sourcesList, ", "), dz.LOG_INFO)
end
dz.log("------ Fin récupération Tempo", dz.LOG_INFO)
end
}
Les données des jours « J » et « J+1 » sont normalement disponibles respectivement à 6h00 et 11h00. Le script est exécuté deux fois, avec un retard de 15 minutes afin de garantir la disponibilité des données sur les deux sites web. En réalité, les données sont déjà disponibles chez RTE à partir de 20h la veille au soir. Aussi, les couleurs « J » et « J+1 » sont récupérées dès la première demande. J’ai appliqué un retard de 15 minutes car cela me convient pour l’exécution d’autres scripts qui dépendent des données tempo mais vous pouvez très bien changer l’heure ou la méthode de collecte des infos.
Vous noterez que la requête tient compte du décalage horaire été/hiver (été 2h GMT, hiver 1h GMT). En effet, si la correction n’est pas faite, le json retourné est incomplet et notamment la donnée pour « J+1 ».
Ce script est réduit par rapport à celui que j’utilise pour mon application. J’y ai rajouté entre autres choses un dernier passage à 20h15 et des envois de sms en cas de non récupération des données Tempo.
Vous pouvez bien sûr le modifier selon vos besoins, par exemple pour récupérer des données plus complètes sur le site web de RTE (données disponibles depuis 2014, jusqu'à un maximum de 366 jours par requête). Pour plus d'informations sur les méthodes de récupération des données Tempo auprès de RTE, vous pouvez consulter et télécharger la documentation disponible directement via l'API.
Alors certains vont me dire que les données récupérées sur le site d’api-couleur-tempo.fr sont directement issues de RTE, qu’il est inutile de le faire à la fois chez RTE et api-couleur-tempo.fr puisque la source est la même. Certes, mais la donnée du lendemain n’est pas dispo à 6h comme chez RTE (qui je le rappelle donne cette info la veille dès 20h). Mais comme il peut arriver que le site de RTE ne soit pas dispo, le fallback d’api-couleur-tempo.fr permet de récupérer tout de même l’info. Et ça m’est arrivé, la preuve par le log :
2025-12-24 06:15:01 - Tempo Demain (IDX:161) = BLEU (source: RTE)
2025-12-24 06:15:01 - DIVERGENCE Tempo Demain : RTE=BLEU vs Tiers=Pas d'info
2025-12-24 11:15:01 - Tempo Aujourd'hui (IDX:160) = BLEU (source: RTE)
2025-12-24 11:15:01 - Tempo Demain (IDX:161) = BLEU (source: RTE)
2025-12-25 06:15:01 - Tempo Aujourd'hui (IDX:160) = BLEU (source: Tiers (fallback))
2025-12-25 06:15:01 - Tempo Demain (IDX:161) = Pas d'info (source: Tiers (fallback))
2025-12-25 11:15:01 - Tempo Aujourd'hui (IDX:160) = BLEU (source: RTE)
2025-12-25 11:15:01 - Tempo Demain (IDX:161) = BLANC (source: RTE)