// ────────────────────────────────────────────────
// DEBUT CONFIGURATION AUTO
// ────────────────────────────────────────────────
$parameters = parameters();
// URL complète fournie → extraction automatique du nom de la ville et du code
$url = $parameters['url'];
// CHANGE ICI le nombre de jours souhaité (1 à 14)
$nb_jours_max = $parameters['nbJoursMax'];
// à mettre sur false si on ne veut pas des infos détaillées de la journée
$detailJour = $parameters['detailJour'];
// ────────────────────────────────────────────────
// FIN CONFIGURATION MANUELLE
// ────────────────────────────────────────────────
// récupère le nom de la ville et le code meteoblue
if (preg_match('#/semaine/([^/_]+)_([^/_]+)_(\d+)#i', $url, $matches)) {
$nomVille = urldecode($matches[1]); // saint-avertin
$codeVille = $matches[2]; // 2981512
$scenario->setLog("URL analysée → ville : $nomVille | code : $codeVille");
} else {
$scenario->setLog("ERREUR : impossible d'extraire ville et code depuis l'URL fournie");
$scenario->setLog("└── Script arrêté (format URL invalide)");
return;
}
$nomVilleSansAccent = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $nomVille);
$nomVilleSansAccent = preg_replace("/[^a-zA-Z0-9 '’\-]+/", '', $nomVilleSansAccent);
$scenario->setLog('nom sans accent '. $nomVilleSansAccent);
// paramètres pour le plugin virtual
$nomVilleAffiche = ucwords(str_replace('-', ' ', $nomVilleSansAccent)); // si tiret remplace par un espace + majuscule, par exemple: saint-avertin → Saint Avertin
$nomVilleAffiche = ucwords(str_replace("'", ' ', $nomVilleAffiche));
$nomAffiche = 'météo ' . $nomVilleAffiche; // → détermine le nom du virtuel, par exemple: météo Saint Avertin
// Construction du logicalId (format compatible Jeedom : minuscules, underscores) à adapter si vous avez des caractères spéciaux dans le nom de votre ville (au cas où...)
$logicalId = 'meteo_' . str_replace('-', '_', strtolower($nomVilleSansAccent)); // → meteo_saint_avertin
// et c'est parti
if (!is_int($nb_jours_max) || $nb_jours_max < 1 || $nb_jours_max > 14) {
$nb_jours_max = 7; // valeur par défaut sécurisée
$scenario->setLog("ATTENTION : nb_jours_max invalide → forcé à 7");
}
$scenario->setLog("┌── Début script Météo $nomVille ── ($nb_jours_max jours demandés)");
$scenario->setLog("→ URL : " . $url);
$scenario->setLog("Récupération page meteoblue...");
// Récupération via cURL
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36');
$html = curl_exec($ch);
if ($html === false) {
$error = curl_error($ch);
$scenario->setLog("ERREUR cURL : " . $error);
curl_close($ch);
$scenario->setLog("└── Script arrêté (erreur réseau)");
return;
}
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$scenario->setLog("Code HTTP : " . $http_code . " | Taille HTML : " . strlen($html) . " octets");
if ($http_code != 200 || strlen($html) < 5000) {
$scenario->setLog("ERREUR : page invalide ou trop courte → abandon");
$scenario->setLog("└── Fin script (échec chargement page)");
return;
}
// Parsing DOM
$scenario->setLog("Parsing HTML...");
$dom = new DOMDocument();
libxml_use_internal_errors(true);
$dom->loadHTML('' . $html);
libxml_clear_errors();
$xpath = new DOMXPath($dom);
// Extraction jours et données
$jours_nodes = $xpath->query("//time[contains(concat(' ', normalize-space(@class), ' '), ' date ')]");
$jours_data_nodes = $xpath->query("//div[contains(concat(' ', normalize-space(@class), ' '), ' tab-content ')]");
$nb_jours_dispo = $jours_nodes->length;
$nb_data_dispo = $jours_data_nodes->length;
$nb_jours = min($nb_jours_max, $nb_jours_dispo);
$nb_data = min($nb_jours_max, $nb_data_dispo);
$scenario->setLog("Jours disponibles sur meteoblue : $nb_jours_dispo");
$scenario->setLog("Jours retenus (limite demandée) : $nb_jours");
$vent = $direction = $tmax = $tmin = $pluie = $soleil = [];
for ($i = 0; $i < $nb_data; $i++) {
$day = $jours_data_nodes->item($i);
// Vent
$vent_div_n = $xpath->query(".//div[contains(concat(' ', normalize-space(@class), ' '), ' wind ')]", $day);
if ($vent_div_n->length > 0) {
$vent_div = $vent_div_n->item(0);
$vitesse = trim(str_replace('km/h', '', $vent_div->textContent));
$span_n = $xpath->query(".//span", $vent_div);
$dir_val = ($span_n->length > 0) ? end(explode(' ', trim($span_n->item(0)->getAttribute('class')))) : 'N';
} else {
$vitesse = '0';
$dir_val = 'N';
}
$vent[] = $vitesse;
$direction[] = $dir_val;
// Autres valeurs
$node = $xpath->query(".//div[contains(@class,'tab-temp-max')]", $day)->item(0);
$tmax[] = $node ? trim($node->textContent) : '';
$node = $xpath->query(".//div[contains(@class,'tab-temp-min')]", $day)->item(0);
$tmin[] = $node ? trim($node->textContent) : '';
$node = $xpath->query(".//div[contains(@class,'tab-precip')]", $day)->item(0);
$pluie[] = $node ? trim($node->textContent) : '';
$node = $xpath->query(".//div[contains(@class,'tab-sun')]", $day)->item(0);
$soleil[] = $node ? trim($node->textContent) : '';
}
$scenario->setLog("Données extraites pour " . count($vent) . " jours");
if (count($vent) > 0) {
$scenario->setLog("Exemple jour 0 → Tmax: " . ($tmax[0] ?: '?') . " | Pluie: " . ($pluie[0] ?: '?'));
}
// ────────────────────────────────────────────────
// Fonctions utilitaires
// ────────────────────────────────────────────────
function wind_arrow($dir_val)
{
$mapping = [
"n" => 0,
"nne" => 22.5,
"ne" => 45,
"ene" => 67.5,
"e" => 90,
"ese" => 112.5,
"se" => 135,
"sse" => 157.5,
"s" => 180,
"sso" => 202.5,
"ssw" => 202.5,
"so" => 225,
"sw" => 225,
"oso" => 247.5,
"wsw" => 247.5,
"o" => 270,
"w" => 270,
"ono" => 292.5,
"wnw" => 292.5,
"no" => 315,
"nw" => 315,
"nno" => 337.5,
"nnw" => 337.5
];
$lower = strtolower(trim($dir_val));
$angle = ($mapping[$lower] ?? 0) + 180;
$angle = $angle % 360;
return " ↑ "
. " " . strtoupper($dir_val) . "";
}
function temp_color($temp)
{
preg_match_all('/\d+\.?\d*/', $temp, $m);
$nums = array_map('floatval', $m[0]);
$s = $nums ? max($nums) : 0;
if ($s <= 0) return "#3828c7";
if ($s <= 5) return "#6FA8FF";
if ($s <= 15) return "#b3e146";
if ($s <= 20) return "#3CFF3C";
if ($s <= 28) return "#FFA500";
return "#FF4040";
}
function vent_color($speed)
{
preg_match_all('/\d+\.?\d*/', $speed, $m);
$nums = array_map('floatval', $m[0]);
$s = $nums ? max($nums) : 0;
if ($s < 30) return "#3CFF3C";
if ($s <= 50) return "#FFA500";
return "#FF4040";
}
function format_vent($value)
{
preg_match_all('/\d+\.?\d*/', $value, $m);
$nums = $m[0];
if (count($nums) >= 2) {
return $nums[0] . " ↯" . end($nums) . "";
}
return $value ?: '0';
}
function pluie_bg($value)
{
preg_match_all('/\d+\.?\d*/', $value, $m);
$nums = array_map('floatval', $m[0]);
$p = $nums ? max($nums) : 0;
if ($p == 0) return "#a562a5";
if ($p <= 2) return "#FFD700";
if ($p <= 5) return "#FF8C00";
return "#FF0000";
}
function pluie_percent($value)
{
preg_match_all('/\d+\.?\d*/', $value, $m);
$nums = array_map('floatval', $m[0]);
$p = $nums ? max($nums) : 0;
if ($p == 0) return "#a562a5";
if ($p <= 20) return "#FFD700";
if ($p <= 50) return "#FF8C00";
return "#FF0000";
}
function soleil_bar($value, $max_h = 10)
{
preg_match_all('/\d+/', $value, $m);
$h = intval($m[0][0] ?? 0);
$ratio = min($h / $max_h, 1);
$width = intval($ratio * 100);
return "
"
. "{$h} h
";
}
$COLORS = [
"Tmax" => "#FF6B5A",
"Tmin" => "#6FA8FF"
];
$ICONS = [
"Vent" => "\u{1F4A8}",
"Direction" => "\u{1F9ED}",
"Tmax" => "\u{2B06}\u{FE0F}",
"Tmin" => "\u{2B07}\u{FE0F}",
"Pluie" => "\u{1F327}\u{FE0F}",
"Soleil" => "\u{2600}\u{FE0F}"
];
// ────────────────────────────────────────────────
// Construction du tableau HTML
// ────────────────────────────────────────────────
$table = "";
// Ligne des jours
$table .= "| Jours : | ";
$count_jours = 0;
foreach ($jours_nodes as $index => $j) {
if ($count_jours >= $nb_jours) {
break;
}
$short_node = $xpath->query(".//div[contains(concat(' ', normalize-space(@class), ' '), ' tab-day-short ')]", $j)->item(0);
$short_day = $short_node ? trim($short_node->textContent) : '';
$long_node = $xpath->query(".//div[contains(concat(' ', normalize-space(@class), ' '), ' tab-day-long ')]", $j)->item(0);
$long_day = $long_node ? trim($long_node->textContent) : '';
$data_meteo[$index] = [
'jour_court' => $short_day,
'jour_long' => $long_day,
'donnees' => []
];
$table .= ""
. htmlspecialchars($short_day) . " "
. "" . htmlspecialchars($long_day) . " | ";
$count_jours++;
}
$table .= "
";
// Lignes des données
$rows = [
"Vent" => $vent,
"Direction" => $direction,
"Tmax" => $tmax,
"Tmin" => $tmin,
"Pluie" => $pluie,
"Soleil" => $soleil
];
$row_index = 0;
foreach ($rows as $label => $values) {
$bg = ($row_index % 2 == 0) ? "transparent" : "rgba(255,255,255,0.04)";
$icon = $ICONS[$label] ?? '';
$table .= "| {$icon} {$label} : | ";
for ($col = 0; $col < $nb_jours; $col++) {
$v = $values[$col] ?? ''; // sécurité si tableau plus court
$data_meteo[$col]['donnees'][$label] = $v;
$cell_bg = $bg;
$text_color = "white";
$display = htmlspecialchars($v);
$size = in_array($label, ["Tmax", "Tmin"]) ? "1.1em" : "1em";
if ($label == "Vent") {
$display = format_vent($v);
$text_color = vent_color($v);
} elseif ($label == "Direction") {
$display = wind_arrow($direction[$col] ?? 'N');
$text_color = vent_color($vent[$col] ?? '0');
} elseif ($label == "Pluie") {
$display = preg_replace('/(mm)/', "$1", htmlspecialchars($v));
$cell_bg = pluie_bg($v);
$text_color = "black";
} elseif ($label == "Soleil") {
$display = soleil_bar($v);
} else {
$text_color = $COLORS[$label] ?? 'rgb(var(--txt-color))';
}
$table .= ""
. $display . " | ";
}
$table .= "
";
$row_index++;
}
$json_resultat = json_encode($data_meteo, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
$table .= "
";
$scenario->setLog("Tableau HTML généré (" . strlen($table) . " caractères)");
// ────────────────────────────────────────────────
// 2. Tableau détaillé aujourd'hui (three-hourly-view)
// ────────────────────────────────────────────────
if ($detailJour) {
$today_content = "Tableau horaire introuvable
";
$three_hourly = $xpath->query("//table[contains(@class,'picto') and contains(@class,'three-hourly-view')]");
if ($three_hourly->length > 0) {
$tbl = $three_hourly->item(0);
$time_cells = $xpath->query(".//tr[contains(@class,'times')]//td", $tbl);
$icon_cells = $xpath->query(".//tr[contains(@class,'icons')]//img", $tbl);
$temp_cells = $xpath->query(".//tr[contains(@class,'temperatures')]//td//div[contains(@class,'cell')]", $tbl);
$feel_cells = $xpath->query(".//tr[contains(@class,'windchills')]//td//div[contains(@class,'cell')]", $tbl);
$wind_cells = $xpath->query(".//tr[contains(@class,'windspeeds')]//td//div[contains(@class,'cell')]", $tbl);
$dir_cells = $xpath->query(".//tr[contains(@class,'winddirs')]//td//div[contains(@class,'winddir')]", $tbl);
$pluie_cells = $xpath->query(".//tr[contains(@class,'precipprobs')]//td//span[contains(@class,'precip-prob')]", $tbl);
$pluie_mm = $xpath->query(".//tr[contains(@class,'precips')]//td//div[contains(@class,'cell')]//span", $tbl);
$hourly_blocks = $xpath->query(".//div[contains(@class, 'precip-bar-flex')]", $tbl);
$rainspot_cells = $xpath->query(".//tr[contains(@class,'rainspots')]//td//div[contains(@class,'rainspot')]", $tbl);
$today_content = ''
. '
'
. ''
. '| Heure | '
. (($parameters['detailC2'] ?? false) ? 'Icône | ' : '')
. (($parameters['detailC3'] ?? false) ? 'Temp | ' : '')
. (($parameters['detailC4'] ?? false) ? 'Ressenti | ' : '')
. (($parameters['detailC5'] ?? false) ? 'Vent | ' : '')
. (($parameters['detailC6'] ?? false) ? 'Pluie | ' : '')
. (($parameters['detailC7'] ?? false) ? '(mm/3h) | ' : '')
. (($parameters['detailC8'] ?? false) ? 'RainSPOT | ' : '')
. (($parameters['detailC9'] ?? false) ? '(% mm/h1) | ' : '')
. (($parameters['detailC10'] ?? false) ? '(% mm/h2) | ' : '')
. (($parameters['detailC11'] ?? false) ? '(% mm/h3) | ' : '')
. '
';
$slots = min(8, $time_cells->length);
$data_meteo_detail = [];
for ($i = 0; $i < $slots; $i++) {
$heure = (int)date('G');
// 2. Calculer l'index de la tranche (0, 1, 2, 3...) pour mette flèche + couleur verte à la tranche horaire actuelle
$indexTranche = floor($heure / 3);
$h_prefix = ''; // pas de >> par défaut
$color_prefix = ''; // pas de couleur par défaut
$border_prefix = 'border-bottom:1px solid #444;'; // bordure par défaut
$h_node = $xpath->query(".//time", $time_cells->item($i))->item(0);
$h = $h_node ? trim($h_node->textContent) : '?';
if ($h === '0300') {
$h = '0-3h';
if ($indexTranche == 0) {
$h_prefix = '➡ ';
}
} elseif ($h === '0600') {
$h = '3-6h';
if ($indexTranche == 1) {
$h_prefix = '➡ ';
}
} elseif ($h === '0900') {
$h = '6-9h';
if ($indexTranche == 2) {
$h_prefix = '➡ ';
}
} elseif ($h === '1200') {
$h = '9-12h';
if ($indexTranche == 3) {
$h_prefix = '➡ ';
}
} elseif ($h === '1500') {
$h = '12-15h';
if ($indexTranche == 4) {
$h_prefix = '➡ ';
}
} elseif ($h === '1800') {
$h = '15-18h';
if ($indexTranche == 5) {
$h_prefix = '➡ ';
}
} elseif ($h === '2100') {
$h = '18-21h';
if ($indexTranche == 6) {
$h_prefix = '➡ ';
}
} elseif ($h === '2400') {
$h = '21-24h';
if ($indexTranche == 7) {
$h_prefix = '➡ ';
}
}
if ($h_prefix) {
$color_prefix = 'color:#3CFF3C;font-weight:bold;';
$border_prefix = "border: 6px solid grey; border-style: double; padding: 2px;";
}
$current_block = $hourly_blocks->item($i);
if ($current_block) {
$details = $xpath->query(".//p[@class='precip-help']//strong", $current_block);
$probability = ['0%', '0%', '0%'];
$precipitation = ['0 mm', '0 mm', '0 mm'];
$count = $details->length;
for ($j = 0; $j < min(3, $count / 2); $j++) {
$prob_node = $details->item($j * 2);
$mm_node = $details->item($j * 2 + 1);
if ($prob_node) {
$probability[$j] = trim($prob_node->textContent);
}
if ($mm_node) {
$precipitation[$j] = trim($mm_node->textContent);
}
}
}
$data_meteo_detail[$h] = [
'temp' => trim($temp_cells->item($i)->textContent ?? '-'),
'ressenti' => trim($feel_cells->item($i)->textContent ?? '-'),
'vent' => trim($wind_cells->item($i)->textContent ?? '-'),
'direction' => ($dir_cells->item($i) ? trim($dir_cells->item($i)->textContent) : '-'),
'pluie_percent' => trim($pluie_cells->item($i)->textContent ?? '0%'),
'pluie_mm' => trim($pluie_mm->item($i)->textContent ?? '0 mm'),
'probability_h1' => $probability[0] ?? '0%',
'precipitation_h1' => $precipitation[0] ?? '0 mm',
'probability_h2' => $probability[1] ?? '0%',
'precipitation_h2' => $precipitation[1] ?? '0 mm',
'probability_h3' => $probability[2] ?? '0%',
'precipitation_h3' => $precipitation[2] ?? '0 mm'
];
$icon = $icon_cells->item($i) ?? null;
if ($icon) {
$src = htmlspecialchars($icon->getAttribute('src'));
$alt = htmlspecialchars($icon->getAttribute('alt') ?? 'Icône météo');
$title = htmlspecialchars($icon->getAttribute('title') ?? $alt); // priorise title si présent, sinon alt
$icon_html = '
'; // optionnel : améliore le chargement
} else {
$icon_html = '-';
}
// ─── RainSPOT ────────────────────────────────────────
$rainspot_html = '-';
if ($i < $rainspot_cells->length) {
$rainspot_div = $rainspot_cells->item($i);
// Récupère toutes les lignes .spot-row
$rows = $xpath->query(".//div[contains(@class,'spot-row')]", $rainspot_div);
if ($rows->length === 7) { // on attend exactement 7 lignes
$grid = []; // tableau 7×7 pour stocker les classes rX
$valid = true;
for ($r = 0; $r < 7; $r++) {
$row = $rows->item($r);
$cells = $xpath->query(".//div[contains(@class,'spot-col-')]", $row);
$col = 0; // position actuelle dans la grille 7 colonnes
foreach ($cells as $cell) {
$class = $cell->getAttribute('class');
preg_match('/spot-col-(\d+)/', $class, $m_width);
preg_match('/r(\d+)/', $class, $m_r);
$width = isset($m_width[1]) ? (int)$m_width[1] : 1;
$r_val = isset($m_r[1]) ? (int)$m_r[1] : 0;
// Remplit les cases fusionnées avec la même valeur
for ($w = 0; $w < $width; $w++) {
if ($col + $w >= 7) {
$valid = false; // débordement → grille invalide
break 2;
}
$grid[$r][$col + $w] = $r_val;
}
$col += $width;
}
// Vérifie que la ligne fait bien 7 colonnes
if ($col !== 7) {
$valid = false;
break;
}
}
if ($valid && count($grid) === 7 && count($grid[0]) === 7) {
// Palette couleurs (tu peux personnaliser)
$color_map = [
0 => 'transparent',
9 => '#d0e8ff', // très faible / averses légères
1 => '#a0d0ff',
2 => '#6090ff',
3 => '#ff4500', // forte
// Ajoute d'autres si meteoblue en utilise plus (rare)
];
$rainspot_html = '';
for ($row = 0; $row < 7; $row++) {
for ($colu = 0; $colu < 7; $colu++) {
$rval = $grid[$row][$colu] ?? 0;
$bg = $color_map[$rval] ?? '#444';
// Option : mettre en évidence la cellule centrale
$extra = ($row === 3 && $colu === 3) ? 'border:1.5px solid #ffeb3b;' : '';
$rainspot_html .= "
";
}
}
$rainspot_html .= '
';
}
}
}
$temp = trim($temp_cells->item($i)->textContent ?? '-');
$ressenti = trim($feel_cells->item($i)->textContent ?? '-');
$vent = trim($wind_cells->item($i)->textContent ?? '-');
$dir_node = $dir_cells->item($i);
$dir = $dir_node ? trim($dir_node->textContent) : '-';
$pluie = trim($pluie_cells->item($i)->textContent ?? '0%');
$pluie_extract_mm = trim($pluie_mm->item($i)->textContent ?? '0 mm');
$vent_display = ($vent !== '-' && $dir !== '-')
? $vent . ' ' . wind_arrow($dir)
: ($vent !== '-' ? $vent : $dir);
$moyvent = '-';
if (preg_match('/(\d+)\s*-\s*(\d+)/', $vent, $matches)) {
$moyVent = ($matches[1] + $matches[2]) / 2;
}
$vent_color = ($moyVent !== '-') ? vent_color($moyVent) : 'rgb(var(--txt-color))';
$temp_color = ($temp !== '-') ? temp_color($temp) : 'rgb(var(--txt-color))';
$temp_color_ressenti = ($ressenti !== '-') ? temp_color($ressenti) : 'rgb(var(--txt-color))';
$pluie_color = pluie_percent($pluie);
$pluie_mm_color = pluie_bg($pluie_extract_mm);
$pluie_h1_color = pluie_percent($data_meteo_detail[$h]['probability_h1']);
$pluie_h2_color = pluie_percent($data_meteo_detail[$h]['probability_h2']);
$pluie_h3_color = pluie_percent($data_meteo_detail[$h]['probability_h3']);
if (($i == 0 && $parameters['detailL1']) ||
($i == 1 && $parameters['detailL2']) ||
($i == 2 && $parameters['detailL3']) ||
($i == 3 && $parameters['detailL4']) ||
($i == 4 && $parameters['detailL5']) ||
($i == 5 && $parameters['detailL6']) ||
($i == 6 && $parameters['detailL7']) ||
($i == 7 && $parameters['detailL8'])
) {
$today_content .= ""
. "| " . $h_prefix . htmlspecialchars($h) . ' | '
. (($parameters['detailC2'] ?? false) ? '' . $icon_html . ' | ' : '')
. (($parameters['detailC3'] ?? false) ? '' . htmlspecialchars($temp) . ' | ' : '')
. (($parameters['detailC4'] ?? false) ? '' . htmlspecialchars($ressenti) . ' | ' : '')
. (($parameters['detailC5'] ?? false) ? '' . $vent_display . ' | ' : '')
. (($parameters['detailC6'] ?? false) ? '' . htmlspecialchars($pluie) . ' | ' : '')
. (($parameters['detailC7'] ?? false) ? '' . htmlspecialchars($pluie_extract_mm) . ' | ' : '')
. (($parameters['detailC8'] ?? false) ? '' . $rainspot_html . ' | ' : '')
. (($parameters['detailC9'] ?? false) ? '' . htmlspecialchars($probability[0] ?? '0%') . ' ' . htmlspecialchars($precipitation[0] ?? '0 mm') . ' | ' : '')
. (($parameters['detailC10'] ?? false) ? '' . htmlspecialchars($probability[1] ?? '0%') . ' ' . htmlspecialchars($precipitation[1] ?? '0 mm') . ' | ' : '')
. (($parameters['detailC11'] ?? false) ? '' . htmlspecialchars($probability[2] ?? '0%') . ' ' . htmlspecialchars($precipitation[2] ?? '0 mm') . ' | ' : '')
. '
';
}
}
$today_content .= '
';
$scenario->setLog("Tableau today complet reconstruit ($slots créneaux)");
} else {
$scenario->setLog("Aucun tableau three-hourly-view trouvé");
}
}
// ────────────────────────────────────────────────
// Gestion équipement virtuel
// ────────────────────────────────────────────────
function findVirtual($name)
{
$name = strtolower(trim($name));
foreach (eqLogic::byType('virtual') as $eq) {
if (strtolower(trim($eq->getName())) === $name) {
return $eq;
}
}
return null;
}
// Principal
$virtual = findVirtual($nomAffiche);
if (!$virtual) {
$virtual = new eqLogic();
$virtual->setName($nomAffiche);
$virtual->setLogicalId($logicalId);
$virtual->setEqType_name('virtual');
$virtual->setIsEnable(1);
$virtual->setIsVisible(1);
$virtual->save();
$cmd = new cmd();
$cmd->setEqLogic_id($virtual->getId());
$cmd->setLogicalId('tableau_meteo');
$cmd->setName('Tableau Météo');
$cmd->setType('info');
$cmd->setSubType('string');
$cmd->save();
$cmdJson = new cmd();
$cmdJson->setEqLogic_id($virtual->getId());
$cmdJson->setLogicalId('data_meteo_json');
$cmdJson->setName('Données Météo JSON');
$cmdJson->setType('info');
$cmdJson->setSubType('string');
$cmdJson->setIsVisible(0);
$cmdJson->save();
} else {
$scenario->setLog("Équipement virtuel trouvé : " . $virtual->getName());
$cmdMain = $virtual->getCmd('info', 'tableau_meteo');
$cmdJson = $virtual->getCmd('info', 'data_meteo_json');
if (!$cmdMain) {
$scenario->setLog("ATTENTION : commande 'tableau_meteo' manquante → création");
$cmd = new cmd();
$cmd->setEqLogic_id($virtual->getId());
$cmd->setLogicalId('tableau_meteo');
$cmd->setName('Tableau Météo');
$cmd->setType('info');
$cmd->setSubType('string');
$cmd->save();
}
if (!$cmdJson) {
$scenario->setLog("ATTENTION : commande 'data_meteo_json' manquante → création");
$cmdJson = new cmd();
$cmdJson->setEqLogic_id($virtual->getId());
$cmdJson->setLogicalId('data_meteo_json');
$cmdJson->setName('Données Météo JSON');
$cmdJson->setType('info');
$cmdJson->setSubType('string');
$cmdJson->setIsVisible(0);
$cmdJson->save();
}
}
$cmdMain = $virtual->getCmd('info', 'tableau_meteo');
if ($cmdMain) {
$virtual->checkAndUpdateCmd('tableau_meteo', $table);
$virtual->refreshWidget();
$scenario->setLog("Principal mis à jour");
}
$cmdJson = $virtual->getCmd('info', 'data_meteo_json');
if ($cmdJson) {
$virtual->checkAndUpdateCmd('data_meteo_json', $json_resultat);
$scenario->setLog("JSON mis à jour");
}
// Today
if ($detailJour) {
$nomToday = $nomAffiche . ' - détaillé';
$logicalToday = $logicalId . '_today';
$virtualToday = findVirtual($nomToday);
if (!$virtualToday) {
$virtualToday = new eqLogic();
$virtualToday->setName($nomToday);
$virtualToday->setLogicalId($logicalToday);
$virtualToday->setEqType_name('virtual');
$virtualToday->setIsEnable(1);
$virtualToday->setIsVisible(1);
$virtualToday->save();
$cmdT = new cmd();
$cmdT->setEqLogic_id($virtualToday->getId());
$cmdT->setLogicalId('tableau_today');
$cmdT->setName('Aujourd\'hui détaillé');
$cmdT->setType('info');
$cmdT->setSubType('string');
$cmdT->save();
$cmdJsonT = new cmd();
$cmdJsonT->setEqLogic_id($virtualToday->getId());
$cmdJsonT->setLogicalId('data_meteo_json_today');
$cmdJsonT->setName('Données Météo JSON Aujourd\'hui');
$cmdJsonT->setType('info');
$cmdJsonT->setSubType('string');
$cmdJsonT->setIsVisible(0);
$cmdJsonT->save();
} else {
$scenario->setLog("Équipement virtuel pour today trouvé : " . $virtualToday->getName());
$cmdT = $virtualToday->getCmd('info', 'tableau_today');
$cmdJsonT = $virtualToday->getCmd('info', 'data_meteo_json_today');
if (!$cmdT) {
$scenario->setLog("ATTENTION : commande 'tableau_today' manquante → création");
$cmdT = new cmd();
$cmdT->setEqLogic_id($virtualToday->getId());
$cmdT->setLogicalId('tableau_today');
$cmdT->setName('Aujourd\'hui détaillé');
$cmdT->setType('info');
$cmdT->setSubType('string');
$cmdT->save();
}
if (!$cmdJsonT) {
$scenario->setLog("ATTENTION : commande 'data_meteo_json_today' manquante → création");
$cmdJsonT = new cmd();
$cmdJsonT->setEqLogic_id($virtualToday->getId());
$cmdJsonT->setLogicalId('data_meteo_json_today');
$cmdJsonT->setName('Données Météo JSON Aujourd\'hui');
$cmdJsonT->setType('info');
$cmdJsonT->setSubType('string');
$cmdJsonT->setIsVisible(0);
$cmdJsonT->save();
}
}
$cmdToday = $virtualToday->getCmd('info', 'tableau_today');
if ($cmdToday) {
$virtualToday->checkAndUpdateCmd('tableau_today', $today_content);
$virtualToday->refreshWidget();
$scenario->setLog("Today mis à jour");
}
$cmdJsonToday = $virtualToday->getCmd('info', 'data_meteo_json_today');
if ($cmdJsonToday) {
$virtualToday->checkAndUpdateCmd('data_meteo_json_today', json_encode($data_meteo_detail, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
$scenario->setLog("JSON Today mis à jour");
}
}
$scenario->setLog("└── Fin script");