Bonjour,
DĂ©solĂ© jâai complĂštement mis en pause le sujet pour dâautres prioritĂ©s⊠![]()
Si quelquâun reprend, je peux fournir au besoin ce que jâai dĂ©jĂ dĂ©boguĂ©.
Pour les plus patients, je me remettrai surement un jour dessus.
Bonne continuation.
Jon
Bonjour,
Je vais me mettre en premier sur la liste des plus patients alors ! ![]()
Bonne journée
Patrice
Salut les gars
Bon jâai enfin rĂ©ussi a obtenir quelque chose de stable avec un token Netatmo qui se raffraichit. Merci ChatgGPT.
Sur le serveur Web de mon NAS jâai mis 3 fichiers : Le scrpit PHP, un fichier tokens.json et un fichier NetatmoFic.json
Pour le premier lancement de la routine je récupÚre le token sur le site de Netatmo et je le colle dans le fichier tokens.json, avec le refresh token. Ensuite cela se met à jour tout seul.
tokens.json :
{"scope":["read_station"],"access_token":"63bdc885d0e552e0e60995a0|d8bf432010ae1f06630e174cc00cc979","refresh_token":"63bdc885d0e552e0e60995a0|339c3a04a7d61f82259d695c34e349bb","expires_in":10800,"expire_in":10800}
NetatmoFic.json
{"body":{"modules":[{"_id":"02:00:00:a2:39:38","main_device":"70:ee:50:9c:db:40","type":"NAModule1","data_type":["Temperature","Humidity"],"module_name":"Ext\u00e9rieur","firmware":53,"last_message":1719767900,"last_seen":1719767887,"rf_status":71,"battery_vp":5310,"dashboard_data":{"time_utc":1719767887,"Temperature":24.7,"Humidity":66,"min_temp":20.5,"max_temp":24.9,"date_max_temp":1719763324,"date_min_temp":1719725897,"temp_trend":"stable"},"date_setup":{"sec":1674312392,"usec":0}},{"_id":"03:00:00:0d:06:92","main_device":"70:ee:50:9c:db:40","type":"NAModule4","data_type":["Temperature","CO2","Humidity"],"module_name":"Bas","firmware":53,"last_message":1719767900,"last_seen":1719767900,"rf_status":49,"battery_vp":5976,"dashboard_data":{"time_utc":1719767848,"Temperature":26.1,"CO2":658,"Humidity":66,"min_temp":20.9,"max_temp":26.4,"date_max_temp":1719759390,"date_min_temp":1719715042,"temp_trend":"stable"},"date_setup":{"sec":1674315041,"usec":0}},{"_id":"06:00:00:06:8e:70","main_device":"70:ee:50:9c:db:40","type":"NAModule2","data_type":["Wind"],"module_name":"An\u00e9mom\u00e8tre","firmware":27,"last_message":1719767900,"last_seen":1719767900,"rf_status":72,"battery_vp":5636,"dashboard_data":{"time_utc":1719767893,"WindStrength":4,"WindAngle":261,"GustStrength":15,"GustAngle":238,"max_wind_str":19,"max_wind_angle":308,"date_max_wind_str":1719746661},"date_setup":{"sec":1674390316,"usec":0}},{"_id":"05:00:00:0a:5f:86","main_device":"70:ee:50:9c:db:40","type":"NAModule3","data_type":["Rain"],"module_name":"Pluviom\u00e8tre","firmware":14,"last_message":1719767900,"last_seen":1719767893,"rf_status":75,"battery_vp":5312,"dashboard_data":{"time_utc":1719767893,"Rain":0,"sum_rain_1":0,"sum_rain_24":0},"date_setup":{"sec":1674394512,"usec":0}},{"_id":"03:00:00:0e:7c:c8","main_device":"70:ee:50:9c:db:40","type":"NAModule4","data_type":["Temperature","CO2","Humidity"],"module_name":"Cellier","firmware":53,"last_message":1719765689,"last_seen":1719765682,"rf_status":95,"battery_vp":5512,"date_setup":{"sec":1705504846,"usec":0}},{"_id":"03:00:00:0e:74:a2","main_device":"70:ee:50:9c:db:40","type":"NAModule4","data_type":["Temperature","CO2","Humidity"],"module_name":"Serre","firmware":53,"last_message":1719767900,"last_seen":1719767900,"rf_status":72,"battery_vp":5603,"dashboard_data":{"time_utc":1719767848,"Temperature":34.1,"CO2":623,"Humidity":40,"min_temp":19.4,"max_temp":37.4,"date_max_temp":1719755391,"date_min_temp":1719724987,"temp_trend":"down"},"date_setup":{"sec":1705590549,"usec":0}}],"devices":[{"_id":"70:ee:50:9c:db:40","type":"NAMain","co2_calibrating":false,"date_setup":{"sec":1674312390,"usec":0},"firmware":204,"last_status_store":1719767901,"module_name":"Etage","station_name":"Les Colibris (Etage)","place":{"altitude":104,"city":"Salon de Provence","country":"FR","timezone":"Europe\/Paris","location":[5.129619,43.63725]},"wifi_status":43,"data_type":["Temperature","CO2","Humidity","Noise","Pressure"],"dashboard_data":{"time_utc":1719767899,"Temperature":29.5,"CO2":553,"Humidity":54,"Noise":37,"Pressure":1012.9,"AbsolutePressure":1000.5,"min_temp":23.3,"max_temp":29.6,"date_max_temp":1719763358,"date_min_temp":1719715076,"temp_trend":"stable","pressure_trend":"stable"},"modules":["02:00:00:a2:39:38","03:00:00:0d:06:92","06:00:00:06:8e:70","05:00:00:0a:5f:86","03:00:00:0e:7c:c8","03:00:00:0e:74:a2"]}]},"status":"ok","time_exec":0.09278488159179688,"time_server":1719768002}
Et le sript PHP avec gestion des erreurs :
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
$CLIENT_ID = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
$CLIENT_SECRET = "yyyyyyyyyyyyyyyyyyyyyyyyyy";
$IP_IPX800 = "192.168.1.250";
$API_key = "apikey";
$TOKENS_FILE = '/volume1/web/Netatmo/tokens.json';
$OUTPUT_FILE = '/volume1/web/Netatmo/NetatmoFic.json';
// Fonction pour lire les tokens depuis le fichier
function read_tokens($file) {
if (!file_exists($file)) {
die("Fichier des tokens non trouvé.");
}
$tokensJson = file_get_contents($file);
$tokens = json_decode($tokensJson, true);
if ($tokens === null) {
die("Erreur lors de la lecture du fichier des tokens.");
}
return $tokens;
}
// Fonction pour écrire les tokens dans le fichier
function write_tokens($file, $tokens) {
file_put_contents($file, json_encode($tokens));
}
// Fonction pour rafraĂźchir les tokens
function refresh_tokens($refresh_token, $client_id, $client_secret) {
$refreshApiUrl = "https://api.netatmo.com/oauth2/token";
$refreshData = [
'grant_type' => 'refresh_token',
'refresh_token' => $refresh_token,
'client_id' => $client_id,
'client_secret' => $client_secret,
];
$options = [
'http' => [
'method' => 'POST',
'header' => 'Content-Type: application/x-www-form-urlencoded',
'content' => http_build_query($refreshData),
],
];
$context = stream_context_create($options);
$refreshResponse = file_get_contents($refreshApiUrl, false, $context);
if ($refreshResponse === false) {
$error = error_get_last();
die("Erreur lors du rafraĂźchissement du token d'accĂšs: " . $error['message']);
}
$newTokens = json_decode($refreshResponse, true);
if (!isset($newTokens['access_token']) || !isset($newTokens['refresh_token'])) {
die("Réponse invalide lors du rafraßchissement du token d'accÚs.");
}
return $newTokens;
}
// Fonction pour récupérer la liste des périphériques
function fetch_device_list($access_token) {
$url = "https://api.netatmo.net/api/devicelist?access_token=$access_token";
$response = file_get_contents($url);
if ($response === false) {
$error = error_get_last();
die("Erreur lors de la récupération de la liste des périphériques: " . $error['message']);
}
return json_decode($response, true);
}
// Lire les tokens
$tokens = read_tokens($TOKENS_FILE);
$ACCESS_TOKEN = $tokens['access_token'];
$REFRESH_TOKEN = $tokens['refresh_token'];
// Récupérer la liste des périphériques
$json_devices = fetch_device_list($ACCESS_TOKEN);
if ($json_devices === false || !isset($json_devices['body'])) {
// Si la récupération échoue, rafraßchir les tokens et réessayer
$tokens = refresh_tokens($REFRESH_TOKEN, $CLIENT_ID, $CLIENT_SECRET);
write_tokens($TOKENS_FILE, $tokens);
$ACCESS_TOKEN = $tokens['access_token'];
// Réessayer de récupérer la liste des périphériques
$json_devices = fetch_device_list($ACCESS_TOKEN);
if ($json_devices === false || !isset($json_devices['body'])) {
die("Ăchec de la rĂ©cupĂ©ration de la liste des pĂ©riphĂ©riques aprĂšs le rafraĂźchissement du token.");
}
}
// Enregistrer la liste des périphériques dans un fichier
if (file_put_contents($OUTPUT_FILE, json_encode($json_devices)) === false) {
die("Erreur lors de l'écriture du fichier $OUTPUT_FILE.");
}
echo "C'est gagné\n";
// Fonction pour calculer le niveau de batterie
function Batterie1($valeur) {
$T1 = [0, 10, 25, 50, 75, 100];
$valeur = intval(0.002 * $valeur - 6);
return ($valeur >= 5) ? 5 : (($valeur < 1) ? 1 : $valeur);
}
function Batterie2($valeur) {
$T2 = [0, 10, 25, 50, 75, 100];
$valeur = intval(0.0024 * $valeur - 8.6341);
return ($valeur >= 5) ? 5 : (($valeur < 1) ? 1 : $valeur);
}
// Extraire et préparer les données pour le push
$ext_temp = floatval($json_devices["body"]["modules"][0]["dashboard_data"]["Temperature"]) * 10 + 1000;
$ext_temp_min = floatval($json_devices["body"]["modules"][0]["dashboard_data"]["min_temp"]) * 10 + 1000;
$ext_temp_max = floatval($json_devices["body"]["modules"][0]["dashboard_data"]["max_temp"]) * 10 + 1000;
$ext_humidite = floatval($json_devices["body"]["modules"][0]["dashboard_data"]["Humidity"]) * 10 + 1000;
$ext_battery = Batterie1(floatval($json_devices["body"]["modules"][0]["battery_vp"]));
$M1_temp = floatval($json_devices["body"]["modules"][1]["dashboard_data"]["Temperature"]) * 10;
$M1_temp_min = floatval($json_devices["body"]["modules"][1]["dashboard_data"]["min_temp"]) * 10;
$M1_temp_max = floatval($json_devices["body"]["modules"][1]["dashboard_data"]["max_temp"]) * 10;
$M1_humidite = floatval($json_devices["body"]["modules"][1]["dashboard_data"]["Humidity"]) * 10;
$M1_battery = Batterie2(floatval($json_devices["body"]["modules"][1]["battery_vp"]));
$M1_CO2 = floatval($json_devices["body"]["modules"][1]["dashboard_data"]["CO2"]);
$M3_Rain = floatval($json_devices["body"]["modules"][3]["dashboard_data"]["Rain"]) * 1000;
$M3_Rain_24 = floatval($json_devices["body"]["modules"][3]["dashboard_data"]["sum_rain_24"]) * 1000;
$M3_Rain_1 = floatval($json_devices["body"]["modules"][3]["dashboard_data"]["sum_rain_1"]) * 1000;
$M3_battery = Batterie1(floatval($json_devices["body"]["modules"][3]["battery_vp"]));
$M5_Wind = floatval($json_devices["body"]["modules"][2]["dashboard_data"]["WindStrength"]);
$M5_Wind_A = floatval($json_devices["body"]["modules"][2]["dashboard_data"]["WindAngle"]);
$M5_Gust = floatval($json_devices["body"]["modules"][2]["dashboard_data"]["GustStrength"]);
$M5_Gust_A = floatval($json_devices["body"]["modules"][2]["dashboard_data"]["GustAngle"]);
$M5_Wind_Max = floatval($json_devices["body"]["modules"][2]["dashboard_data"]["max_wind_str"]);
$M5_Wind_Max_A = floatval($json_devices["body"]["modules"][2]["dashboard_data"]["max_wind_angle"]);
$M5_battery = Batterie2(floatval($json_devices["body"]["modules"][2]["battery_vp"]));
if ($M5_Wind < 0) $M5_Wind = 0;
if ($M5_Wind_A < 0) $M5_Wind_A = 0;
$MS_temp = floatval($json_devices["body"]["devices"][0]["dashboard_data"]["Temperature"]) * 10;
$MS_temp_min = floatval($json_devices["body"]["devices"][0]["dashboard_data"]["min_temp"]) * 10;
$MS_temp_max = floatval($json_devices["body"]["devices"][0]["dashboard_data"]["max_temp"]) * 10;
$MS_humidite = floatval($json_devices["body"]["devices"][0]["dashboard_data"]["Humidity"]) * 10;
$MS_CO2 = floatval($json_devices["body"]["devices"][0]["dashboard_data"]["CO2"]);
$MS_Pressure = floatval($json_devices["body"]["devices"][0]["dashboard_data"]["Pressure"]) * 10;
$MS_Noise = floatval($json_devices["body"]["devices"][0]["dashboard_data"]["Noise"]) * 10;
$URL_Push = "http://$IP_IPX800/api/xdevices.json?key=$API_key"
. "&SetVA01=$ext_temp&SetVA02=$ext_temp_min&SetVA03=$ext_temp_max"
. "&SetVA04=$ext_humidite&SetVA05=$ext_battery&SetVA06=$M1_temp"
. "&SetVA07=$M1_temp_min&SetVA08=$M1_temp_max&SetVA09=$M1_humidite"
. "&SetVA10=$M1_battery&SetVA11=$M1_CO2&SetVA18=$M3_Rain"
. "&SetVA19=$M3_Rain_24&SetVA20=$M3_Rain_1&SetVA21=$M3_battery"
. "&SetVA22=$MS_temp&SetVA23=$MS_temp_min&SetVA24=$MS_temp_max"
. "&SetVA25=$MS_humidite&SetVA26=$MS_CO2&SetVA27=$MS_Pressure"
. "&SetVA28=$MS_Noise&SetVA29=$M5_Wind&SetVA30=$M5_Wind_A"
. "&SetVA31=$M5_Gust&SetVA32=$M5_battery";
// Affichage de l'URL générée
echo $URL_Push . "<br>";
// Envoi des données à l'API
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $URL_Push);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$data = curl_exec($ch);
curl_close($ch);
// Fonction pour enregistrer des logs
function write_log($message) {
$log_file = '/volume1/web/Netatmo/Netatmo.log';
$date = date('Y-m-d H:i:s');
file_put_contents($log_file, "[$date] $message\n", FILE_APPEND);
}
// Exemple d'utilisation des logs
write_log("Début du script");
// Lire les tokens
$tokens = read_tokens($TOKENS_FILE);
$ACCESS_TOKEN = $tokens['access_token'];
$REFRESH_TOKEN = $tokens['refresh_token'];
write_log("Tokens lus avec succĂšs");
// Récupérer la liste des périphériques
$json_devices = fetch_device_list($ACCESS_TOKEN);
write_log("Liste des périphériques récupérée");
// Enregistrer la liste des périphériques dans un fichier
if (file_put_contents($OUTPUT_FILE, json_encode($json_devices)) === false) {
write_log("Erreur lors de l'écriture du fichier $OUTPUT_FILE.");
die("Erreur lors de l'écriture du fichier $OUTPUT_FILE.");
}
write_log("Liste des périphériques enregistrée dans $OUTPUT_FILE");
// ... (le reste du script)
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $URL_Push);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
$data = curl_exec($ch);
curl_close($ch);
write_log("Données envoyées à l'API IPX800: " . $URL_Push);
write_log("Fin du script");
?>
La derniÚre partie du scrip enregistre les logs dans un fichier « Netatmo.log »
[2024-07-01 11:50:02] Début du script
[2024-07-01 11:50:02] Tokens lus avec succĂšs
[2024-07-01 11:50:02] Liste des périphériques récupérée
[2024-07-01 11:50:02] Liste des périphériques enregistrée dans /volume1/web/Netatmo/NetatmoFic.json
[2024-07-01 11:50:02] Données envoyées à l'API IPX800: http://192.168.1.250/api/xdevices.json?key=apikey&SetVA01=1232&SetVA02=1207&SetVA03=1232&SetVA04=1650&SetVA05=4&SetVA06=238&SetVA07=223&SetVA08=238&SetVA09=650&SetVA10=5&SetVA11=671&SetVA18=0&SetVA19=0&SetVA20=0&SetVA21=4&SetVA22=256&SetVA23=244&SetVA24=256&SetVA25=560&SetVA26=491&SetVA27=10124&SetVA28=440&SetVA29=4&SetVA30=315&SetVA31=12&SetVA32=4
[2024-07-01 11:50:02] Fin du script
Avec le Refresh Token automatique et lâĂ©criture des logs :
$CLIENT_ID = "xxxxxxxxxxxxxxxxxxxxxxxxxx";
$CLIENT_SECRET = "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy";
$IP_IPX800 = "192.168.1.250";
$API_key = "apikey";
$TOKENS_FILE = '/volume1/web/Netatmo/tokens.json';
$LOG_FILE = '/volume1/web/Netatmo/script.log';
// Fonction pour écrire des logs
function log_message($message) {
global $LOG_FILE;
error_log(date('[Y-m-d H:i:s] ') . $message . PHP_EOL, 3, $LOG_FILE);
}
// Lire les tokens depuis le fichier
function read_tokens($file) {
log_message("Lecture des tokens depuis le fichier $file.");
$tokensJson = file_get_contents($file);
return json_decode($tokensJson, true);
}
// Ăcrire les tokens dans le fichier
function write_tokens($file, $tokens) {
log_message("Ăcriture des tokens dans le fichier $file.");
file_put_contents($file, json_encode($tokens));
}
// RafraĂźchir le token d'accĂšs
function refresh_access_token($refresh_token, $client_id, $client_secret) {
log_message("RafraĂźchissement du token d'accĂšs.");
$refreshApiUrl = "https://api.netatmo.com/oauth2/token";
$refreshData = [
'grant_type' => 'refresh_token',
'refresh_token' => $refresh_token,
'client_id' => $client_id,
'client_secret' => $client_secret,
];
$options = [
'http' => [
'method' => 'POST',
'header' => 'Content-Type: application/x-www-form-urlencoded',
'content' => http_build_query($refreshData),
],
];
$context = stream_context_create($options);
$refreshResponse = file_get_contents($refreshApiUrl, false, $context);
if ($refreshResponse === false) {
log_message("Erreur lors du rafraĂźchissement du token d'accĂšs.");
die("Erreur lors du rafraĂźchissement du token d'accĂšs.");
}
$newTokens = json_decode($refreshResponse, true);
log_message("Token d'accĂšs rafraĂźchi avec succĂšs.");
return $newTokens;
}
// Vérifier l'expiration du token et rafraßchir si nécessaire
function get_valid_access_token($tokens, $client_id, $client_secret) {
$expires_in = $tokens['expires_in'];
$last_refreshed = $tokens['last_refreshed'];
$current_time = time();
// Vérifier si le token d'accÚs a expiré
if ($current_time > $last_refreshed + $expires_in) {
log_message("Token d'accÚs expiré, rafraßchissement nécessaire.");
$tokens = refresh_access_token($tokens['refresh_token'], $client_id, $client_secret);
$tokens['last_refreshed'] = time();
write_tokens($GLOBALS['TOKENS_FILE'], $tokens);
}
return $tokens['access_token'];
}
// Initialisation
log_message("Début de l'exécution du script.");
$tokens = read_tokens($TOKENS_FILE);
$tokens['last_refreshed'] = $tokens['last_refreshed'] ?? time();
$ACCESS_TOKEN = get_valid_access_token($tokens, $CLIENT_ID, $CLIENT_SECRET);
// Appel de l'API Netatmo pour récupérer la liste des périphériques
$response = file_get_contents("https://api.netatmo.net/api/devicelist?access_token=$ACCESS_TOKEN");
// Vérifier si la réponse contient "body"
if (strpos($response, 'body') !== false) {
file_put_contents('/volume1/web/Netatmo/NetatmoFic.json', $response);
log_message("Récupération de la liste des périphériques réussie.");
echo "C'est gagné\n";
} else {
log_message("Erreur lors de la récupération de la liste des périphériques.");
die("Erreur lors de la récupération de la liste des périphériques.");
}
// Tentative de PUSH sur IPX800V4
$json_devices = json_decode($response, true);
// Ajouter des logs pour chaque module et périphérique traité
function Batterie1($valeur) {
log_message("Calcul de la batterie pour Batterie1 avec valeur $valeur.");
$T1 = array(0, 10, 25, 50, 75, 100);
$valeur = intval(0.002 * $valeur - 6);
if ($valeur >= 5) {
$valeur = 5;
} else if ($valeur < 1) {
$valeur = 1;
}
return $T1[$valeur];
}
function Batterie2($valeur) {
log_message("Calcul de la batterie pour Batterie2 avec valeur $valeur.");
$T2 = array(0, 10, 25, 50, 75, 100);
$valeur = intval(0.0024 * $valeur - 8.6341);
if ($valeur >= 5) {
$valeur = 5;
} else if ($valeur < 1) {
$valeur = 1;
}
return $T2[$valeur];
}
// Module 0 (Terrasse)
log_message("Traitement du module 0 (Terrasse).");
$ext_temp = floatval($json_devices["body"]["modules"][0]["dashboard_data"]["Temperature"]) * 10 + 1000;
$ext_temp_min = floatval($json_devices["body"]["modules"][0]["dashboard_data"]["min_temp"]) * 10 + 1000;
$ext_temp_max = floatval($json_devices["body"]["modules"][0]["dashboard_data"]["max_temp"]) * 10 + 1000;
$ext_humidite = floatval($json_devices["body"]["modules"][0]["dashboard_data"]["Humidity"]) * 10 + 1000;
$ext_battery = Batterie1(floatval($json_devices["body"]["modules"][0]["battery_vp"]));
// Module 1 (Intérieur Bas)
log_message("Traitement du module 1 (Intérieur Bas).");
$M1_temp = floatval($json_devices["body"]["modules"][1]["dashboard_data"]["Temperature"]) * 10;
$M1_temp_min = floatval($json_devices["body"]["modules"][1]["dashboard_data"]["min_temp"]) * 10;
$M1_temp_max = floatval($json_devices["body"]["modules"][1]["dashboard_data"]["max_temp"]) * 10;
$M1_humidite = floatval($json_devices["body"]["modules"][1]["dashboard_data"]["Humidity"]) * 10;
$M1_battery = Batterie2(floatval($json_devices["body"]["modules"][1]["battery_vp"]));
$M1_CO2 = floatval($json_devices["body"]["modules"][1]["dashboard_data"]["CO2"]);
// Module 3 : Pluie
log_message("Traitement du module 3 (Pluie).");
$M3_Rain = floatval($json_devices["body"]["modules"][3]["dashboard_data"]["Rain"]) * 1000;
$M3_Rain_24 = floatval($json_devices["body"]["modules"][3]["dashboard_data"]["sum_rain_24"]) * 1000;
$M3_Rain_1 = floatval($json_devices["body"]["modules"][3]["dashboard_data"]["sum_rain_1"]) * 1000;
$M3_battery = Batterie1(floatval($json_devices["body"]["modules"][3]["battery_vp"]));
// Module 2 : Vent
log_message("Traitement du module 2 (Vent).");
$M5_Wind = floatval($json_devices["body"]["modules"][2]["dashboard_data"]["WindStrength"]); // vitesse du vent
$M5_Wind_A = floatval($json_devices["body"]["modules"][2]["dashboard_data"]["WindAngle"]); // angle du vent
$M5_Gust = floatval($json_devices["body"]["modules"][2]["dashboard_data"]["GustStrength"]); // vitesse rafale
$M5_Gust_A = floatval($json_devices["body"]["modules"][2]["dashboard_data"]["GustAngle"]); // angle rafale
$M5_Wind_Max = floatval($json_devices["body"]["modules"][2]["dashboard_data"]["max_wind_str"]); // vitesse max
$M5_Wind_Max_A = floatval($json_devices["body"]["modules"][2]["dashboard_data"]["max_wind_angle"]); // angle max
$M5_battery = Batterie2(floatval($json_devices["body"]["modules"][2]["battery_vp"]));
if ($M5_Wind < 0) { $M5_Wind = 0; }
if ($M5_Wind_A < 0) { $M5_Wind_A = 0; }
// Device 0 Station Etage
log_message("Traitement du device 0 (Station Etage).");
$MS_temp = floatval($json_devices["body"]["devices"][0]["dashboard_data"]["Temperature"]) * 10;
$MS_temp_min = floatval($json_devices["body"]["devices"][0]["dashboard_data"]["min_temp"]) * 10;
$MS_temp_max = floatval($json_devices["body"]["devices"][0]["dashboard_data"]["max_temp"]) * 10;
$MS_humidite = floatval($json_devices["body"]["devices"][0]["dashboard_data"]["Humidity"]) * 10;
$MS_CO2 = floatval($json_devices["body"]["devices"][0]["dashboard_data"]["CO2"]);
$MS_Pressure = floatval($json_devices["body"]["devices"][0]["dashboard_data"]["Pressure"]) * 10;
$MS_Noise = floatval($json_devices["body"]["devices"][0]["dashboard_data"]["Noise"]) * 10;
// PUSH IPX800V4
log_message("Envoi des données à l'IPX800V4.");
$URL_Push = "http://" . $IP_IPX800 . "/api/xdevices.json?key=" . $API_key . "&SetVA01=" . $ext_temp . "&SetVA02=" . $ext_temp_min .
"&SetVA03=" . $ext_temp_max . "&SetVA04=" . $ext_humidite . "&SetVA05=" . $ext_battery . "&SetVA06=" . $M1_temp .
"&SetVA07=" . $M1_temp_min . "&SetVA08=" . $M1_temp_max . "&SetVA09=" . $M1_humidite . "&SetVA10=" . $M1_battery .
"&SetVA11=" . $M1_CO2 . "&SetVA18=" . $M3_Rain . "&SetVA19=" . $M3_Rain_24 . "&SetVA20=" . $M3_Rain_1 . "&SetVA21=" . $M3_battery .
"&SetVA22=" . $M5_Wind . "&SetVA23=" . $M5_Wind_A . "&SetVA24=" . $M5_Gust . "&SetVA25=" . $M5_Gust_A . "&SetVA26=" . $M5_Wind_Max .
"&SetVA27=" . $M5_Wind_Max_A . "&SetVA28=" . $M5_battery . "&SetVA29=" . $MS_temp . "&SetVA30=" . $MS_temp_min .
"&SetVA31=" . $MS_temp_max . "&SetVA32=" . $MS_humidite . "&SetVA33=" . $MS_CO2 . "&SetVA34=" . $MS_Pressure . "&SetVA35=" . $MS_Noise;
$output = shell_exec('curl "' . $URL_Push . '"');
log_message("Données envoyées à l'IPX800V4 avec succÚs.");
echo "C'est gagné\n";
// Fin du script
log_message("Fin de l'exécution du script.");
?>
Merci @AlexFisho pour le partage !
Le dernier script php apporte quelles modifs ?
jâai un petit soucis sur lâhumiditĂ© du module extĂ©rieur qui affiche 155% au lieu de 55%, alors que câest OK pour le module principal.
Au niveau de lâIPX, la jauge de la batterie ne sâaffiche pas, as tu modifiĂ© le code par rapport au tuto de @fgtoul ?
Hello
Le dernier script vĂ©rifie la validitĂ© du token afin de prendre le refresh Ă temps. DâaprĂšs ce que jâai compris des explications de ChatGPT. Jâai laissĂ© ChatGPT modifier le code avec des demandes de prĂ©cisions jusquâĂ obtenir un script fonctionnel. Pour lâhumiditĂ© jâai cette conversion en JS sur mon Dashboard : let H0=(datasources[« STATUS »][« response »][« analogV3 »]-1000)/10;
//MODULE EXTERIEUR
let T0=(datasources["STATUS"]["response"]["analogV0"]-1000)/10;
let Tmin0=(datasources["STATUS"]["response"]["analogV1"]-1000)/10;
let Tmax0=(datasources["STATUS"]["response"]["analogV2"]-1000)/10;
let H0=(datasources["STATUS"]["response"]["analogV3"]-1000)/10;
let B0=datasources["STATUS"]["response"]["analogV4"];
let NB0=B0;
if (B0==100){NB0='full'};
return `
<br>
<span style="float:left;margin-left:20px;font-weight: bold; font-size: 2.5em;">${T0}°</span>
<span style="float:right;margin-right:10px;font-weight: bold; font-size: 2em;">${H0}%</span>
<br><br><br>
<span style="float:left; margin-left:10px;">⇩</span><span style="font-weight: bold;">${Tmin0}°</span> <span>⇧</span><span style="font-weight: bold;">${Tmax0}°</span>
<br><br>
<span style="float:left; margin-left:15px;" class="glyphicons glyphicons-battery-${NB0}"></span>
`;

Ok pour la formule sur lâhumiditĂ©, jâavais une erreur, par contre toujours pas de symbole batterie.
jâai lâimpression que le nouveau script ne fonctionne pas, jâai plus rien dans les log ?
Bonjour @AlexFisho , ton script est toujours fonctionnel ?
Bonjour
Avec les tokens que je rĂ©cupĂšre manuellement tous les matins et que je colle dans le fichier tokens.json ça fonctionne, lais je nâarrive toujours pas Ă avoir un Refresh token pour continuer, donc tous les matins je me connecte sur Netatmo et je regĂ©nĂšre un token.
OK, je comprends. Bonne journée.
Bonjour la communauté,
Je rĂ©pond Ă ce poste pour vous donner une solution Ă votre problĂšme⊠si toutefois vous ne lâavez toujours pas trouvĂ©e !
Il faut crĂ©er dans le volume « web » dâun NAS un dossier (que jâai nommĂ© « Netatmo »).
Dans ce dossier il faut créer un fichier JSON qui ce nommera « tokens.json » et dans le quel vous inscrirez vos tokens (acces token et refresh token) de la façon suivante :
{"access_token":"xxxxxxxxxx","refresh_token":"yyyyyyyyyyyy","expires_in":10800,"expire_in":10800,"scope":["read_station"]}
Ensuite lancer le script qui suit toutes les 10 minutes depuis le NAS :
<?php
$CLIENT_ID = "aaaaaaaaaaaaaaaa";
$CLIENT_SECRET = "bbbbbbbbbbbbbbbbb";
// Récupérer les jetons depuis le fichier tokens.json
$tokensJson = file_get_contents('file:///Volumes/web/Netatmo/tokens.json');
$tokens = json_decode($tokensJson, true);
$ACCESS_TOKEN = $tokens['access_token'];
$REFRESH_TOKEN = $tokens['refresh_token'];
// Appeler l'API Netatmo pour récupérer la liste des périphériques (Scopes "read_station")
$response = file_get_contents("https://api.netatmo.net/api/devicelist?access_token=$ACCESS_TOKEN");
// Vérifier si la réponse contient "body" (si le fichier est valide)
if (strpos($response, 'body') !== false) {
file_put_contents('/Volumes/web/Netatmo/NetatmoFic.json', json_encode($response));
echo "C'est gagné";
} else {
// sinon il faut générer un nouveau token d'accÚs en utilisant le token de rafraichissement
$refreshApiUrl = "https://api.netatmo.com/oauth2/token";
$refreshData = [
'grant_type' => 'refresh_token',
'refresh_token' => $REFRESH_TOKEN,
'client_id' => $CLIENT_ID,
'client_secret' => $CLIENT_SECRET,
];
$options = [
'http' => [
'method' => 'POST',
'header' => 'Content-Type: application/x-www-form-urlencoded',
'content' => http_build_query($refreshData),
],
];
$context = stream_context_create($options);
$refreshResponse = file_get_contents($refreshApiUrl, false, $context);
// Mettre Ă jour les tokens dans le fichier tokens.json
$newTokens = json_decode($refreshResponse, true);
file_put_contents('/Volumes/web/Netatmo/tokens.json', json_encode($newTokens));
// Mettre Ă jour le token d'accĂšs
$ACCESS_TOKEN = $newTokens['access_token'];
// Appeler Ă nouveau l'API Netatmo
$response = file_get_contents("https://api.netatmo.net/api/devicelist?access_token=$ACCESS_TOKEN");
file_put_contents('/Volumes/web/Netatmo/NetatmoFic.json', json_encode($response));
echo "C'est re-gagné";
}
?>
Ce script créera un fichier JSON (NetatmoFic.json) dans lequel vous trouverez toutes les infos de vos capteurs Netatmo !
En principe vous nâaurez plus Ă intervenir manuellement pour rĂ©cupĂ©rer les jetons !
Essayez cette solution et dites moi si cela fonctionne !
Bien amicalement Ă tous.
Bonjour @jppouma , merci pour ton aide. je viens dâessayer et ça ne fonctionne pas chez moi.
je te mets le dĂ©but du log de lâexĂ©cution du script.
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
100 2244 0 2244 0 0 4006 0 --:--:-- --:--:-- --:--:-- 4007
100 2244 0 2244 0 0 3999 0 --:--:-- --:--:-- --:--:-- 4000
Warning: file_get_contents(file:///Volumes/web/Netatmo/tokens.json): failed to open stream: No such file or directory in /volume1/web/Netatmo/Script_Netatmo.php on line 7
Call Stack:
0.0016 129144 1. {main}() /volume1/web/Netatmo/Script_Netatmo.php:0
0.0016 129368 2. file_get_contents() /volume1/web/Netatmo/Script_Netatmo.php:7
Warning: file_get_contents(https://api.netatmo.net/api/devicelist?access_token=): failed to open stream: HTTP request failed! HTTP/1.1 400 Missing token argument
in /volume1/web/Netatmo/Script_Netatmo.php on line 13
Bonjour @pat49700
problĂšme de chemin peut-ĂȘtre
/Volumes /web/Netatmo/Script_Netatmo.php
/volume1 /web/Netatmo/Script_Netatmo.php
$tokensJson = file_get_contents('file:///Volumes/web/Netatmo/tokens.json');
devrait peut-ĂȘtre ĂȘtre :
$tokensJson = file_get_contents('file:///volume1/web/Netatmo/tokens.json');
puisque le script est exécuté depuis ce chemin
modifie aussi
file_put_contents('/Volumes/web/Netatmo/tokens.json', json_encode($newTokens));
â
file_put_contents('/volume1/web/Netatmo/tokens.json', json_encode($newTokens));
et modifie
file_put_contents('/Volumes/web/Netatmo/NetatmoFic.json', json_encode($response));
â
file_put_contents('/volume1/web/Netatmo/NetatmoFic.json', json_encode($response));
Merci @cce66
Je viens de remplacer les 4 lignes et jâai toujours le mĂȘme log !
peut ĂȘtre vĂ©rifier les droits fichier et rĂ©pertoire ??
chmod 644 /volume1/web/Netatmo/tokens.json
chmod 755 /volume1/web/Netatmo/
sinon tente avec des chemin relatifs
<?php
$CLIENT_ID = "aaaaaaaaaaaaaaaa";
$CLIENT_SECRET = "bbbbbbbbbbbbbbbbb";
// Chemin relatif pour tokens.json
$TOKENS_FILE = __DIR__ . '/tokens.json';
// Récupérer les jetons depuis le fichier tokens.json
$tokensJson = file_get_contents($TOKENS_FILE);
$tokens = json_decode($tokensJson, true);
$ACCESS_TOKEN = $tokens['access_token'];
$REFRESH_TOKEN = $tokens['refresh_token'];
// Chemin relatif pour le fichier de sortie
$OUTPUT_FILE = __DIR__ . '/NetatmoFic.json';
// Appeler l'API Netatmo pour récupérer la liste des périphériques
$response = file_get_contents("https://api.netatmo.net/api/devicelist?access_token=$ACCESS_TOKEN");
// Vérifier si la réponse contient "body"
if (strpos($response, 'body') !== false) {
file_put_contents($OUTPUT_FILE, json_encode($response));
echo "C'est gagné";
} else {
// sinon il faut générer un nouveau token d'accÚs
$refreshApiUrl = "https://api.netatmo.com/oauth2/token";
$refreshData = [
'grant_type' => 'refresh_token',
'refresh_token' => $REFRESH_TOKEN,
'client_id' => $CLIENT_ID,
'client_secret' => $CLIENT_SECRET,
];
$options = [
'http' => [
'method' => 'POST',
'header' => 'Content-Type: application/x-www-form-urlencoded',
'content' => http_build_query($refreshData),
],
];
$context = stream_context_create($options);
$refreshResponse = file_get_contents($refreshApiUrl, false, $context);
// Mettre Ă jour les tokens dans le fichier tokens.json
$newTokens = json_decode($refreshResponse, true);
file_put_contents($TOKENS_FILE, json_encode($newTokens));
// Mettre Ă jour le token d'accĂšs
$ACCESS_TOKEN = $newTokens['access_token'];
// Appeler Ă nouveau l'API Netatmo
$response = file_get_contents("https://api.netatmo.net/api/devicelist?access_token=$ACCESS_TOKEN");
file_put_contents($OUTPUT_FILE, json_encode($response));
echo "C'est re-gagné";
}
?>
amélioré par Grok ca donnes (à tester) :
<?php
$CLIENT_ID = "aaaaaaaaaaaaaaaa";
$CLIENT_SECRET = "bbbbbbbbbbbbbbbbb";
$TOKENS_FILE = __DIR__ . '/tokens.json'; // Chemin relatif au script
$OUTPUT_FILE = __DIR__ . '/NetatmoFic.json'; // Chemin relatif au script
// Vérifier si le fichier tokens.json existe
if (!file_exists($TOKENS_FILE)) {
die("Erreur: Le fichier tokens.json n'existe pas Ă l'emplacement: $TOKENS_FILE");
}
// Récupérer les jetons depuis le fichier tokens.json
$tokensJson = file_get_contents($TOKENS_FILE);
if ($tokensJson === false) {
die("Erreur: Impossible de lire le fichier tokens.json");
}
$tokens = json_decode($tokensJson, true);
if (json_last_error() !== JSON_ERROR_NONE) {
die("Erreur: Fichier tokens.json invalide - " . json_last_error_msg());
}
if (!isset($tokens['access_token']) || !isset($tokens['refresh_token'])) {
die("Erreur: Tokens manquants dans le fichier JSON");
}
$ACCESS_TOKEN = $tokens['access_token'];
$REFRESH_TOKEN = $tokens['refresh_token'];
// Fonction pour appeler l'API Netatmo avec gestion des erreurs
function callNetatmoAPI($accessToken) {
$url = "https://api.netatmo.net/api/devicelist?access_token=" . urlencode($accessToken);
$context = stream_context_create([
'http' => [
'ignore_errors' => true // Pour lire les rĂ©ponses mĂȘme en cas d'erreur HTTP
]
]);
$response = @file_get_contents($url, false, $context);
if ($response === false) {
$error = error_get_last();
die("Erreur API: " . ($error['message'] ?? 'Erreur inconnue'));
}
return $response;
}
// Premier essai avec le token actuel
$response = callNetatmoAPI($ACCESS_TOKEN);
$decoded = json_decode($response, true);
if (isset($decoded['body'])) {
file_put_contents($OUTPUT_FILE, $response);
echo "C'est gagné";
exit;
}
// Si on arrive ici, c'est que le token a probablement expiré
// RafraĂźchir le token
$refreshApiUrl = "https://api.netatmo.com/oauth2/token";
$refreshData = [
'grant_type' => 'refresh_token',
'refresh_token' => $REFRESH_TOKEN,
'client_id' => $CLIENT_ID,
'client_secret' => $CLIENT_SECRET,
];
$options = [
'http' => [
'method' => 'POST',
'header' => 'Content-Type: application/x-www-form-urlencoded',
'content' => http_build_query($refreshData),
],
];
$context = stream_context_create($options);
$refreshResponse = @file_get_contents($refreshApiUrl, false, $context);
if ($refreshResponse === false) {
die("Erreur lors du rafraĂźchissement du token");
}
$newTokens = json_decode($refreshResponse, true);
if (json_last_error() !== JSON_ERROR_NONE) {
die("Erreur: Réponse de rafraßchissement invalide - " . json_last_error_msg());
}
// Sauvegarder les nouveaux tokens
if (file_put_contents($TOKENS_FILE, json_encode($newTokens)) === false) {
die("Erreur: Impossible d'écrire dans le fichier tokens.json");
}
// Réessayer avec le nouveau token
$response = callNetatmoAPI($newTokens['access_token']);
if (file_put_contents($OUTPUT_FILE, $response) === false) {
die("Erreur: Impossible d'écrire dans le fichier de sortie");
}
echo "C'est re-gagné";
?>