{ "name": "IA Mistral - QR", "isActive": "1", "group": "Technique", "mode": "provoke", "schedule": "", "trigger": [ "" ], "timeout": "0", "object_id": null, "isVisible": "0", "display": { "name": "" }, "order": "9999", "description": "", "configuration": { "timeDependency": 0, "has_return": 0, "logmode": "default", "allowMultiInstance": "0", "syncmode": "0", "timeline::enable": "0", "timeline::folder": "" }, "elements": [ { "name": null, "type": "action", "options": [], "order": "0", "subElements": [ { "name": null, "type": "action", "subtype": "action", "options": { "collapse": "0", "enable": "1" }, "order": "0", "expressions": [ { "type": "element", "subtype": null, "expression": "2259", "options": [], "order": "0", "element": { "name": null, "type": "comment", "options": [], "order": "0", "subElements": [ { "name": null, "type": "comment", "subtype": "comment", "options": { "collapse": "0" }, "order": "0", "expressions": [ { "type": "comment", "subtype": null, "expression": "1\/ mistral_api_key : clé API de Mistral\n2\/ jeedom_question : l'ID de la commande Question\n3\/ jeedom_sortie : l'ID de la commande Réponse", "options": [], "order": "0" } ] } ] } }, { "type": "action", "subtype": null, "expression": "variable", "options": { "enable": "1", "background": "0", "name": "mistral_api_key", "value": "" }, "order": "1" }, { "type": "action", "subtype": null, "expression": "variable", "options": { "enable": "1", "background": "0", "name": "jeedom_question", "value": "339805" }, "order": "2" }, { "type": "action", "subtype": null, "expression": "variable", "options": { "enable": "1", "background": "0", "name": "jeedom_sortie", "value": "339806" }, "order": "3" }, { "type": "element", "subtype": null, "expression": "2260", "options": [], "order": "4", "element": { "name": null, "type": "comment", "options": [], "order": "0", "subElements": [ { "name": null, "type": "comment", "subtype": "comment", "options": { "collapse": "0" }, "order": "0", "expressions": [ { "type": "comment", "subtype": null, "expression": "Récupération des capteurs par pièces :\nLister l'ensemble des pièces dont vous souhaitez envoyer les capteurs à l'IA séparées par des ;\nBien respecter la syntaxe. Si vous ne souhaitez pas utiliser ce mode de liste, écrire ainsi $scenario->setData(\"jeedom_piece_id\", \"\");", "options": [], "order": "0" } ] } ] } }, { "type": "element", "subtype": null, "expression": "2261", "options": [], "order": "5", "element": { "name": null, "type": "code", "options": [], "order": "0", "subElements": [ { "name": null, "type": "code", "subtype": "action", "options": { "collapse": "0", "enable": "1" }, "order": "0", "expressions": [ { "type": "code", "subtype": null, "expression": "$scenario->setData(\"jeedom_piece_id\", \"\");", "options": [], "order": "0" } ] } ] } }, { "type": "element", "subtype": null, "expression": "2262", "options": [], "order": "6", "element": { "name": null, "type": "comment", "options": [], "order": "0", "subElements": [ { "name": null, "type": "comment", "subtype": "comment", "options": { "collapse": "0" }, "order": "0", "expressions": [ { "type": "comment", "subtype": null, "expression": "Récupération des capteurs :\nLister à partir de la ligne 2 l'ensemble des capteurs que vous souhaiter envoyer à l'IA séparées par des ;\nBien respecter la syntaxe. Si vous ne souhaitez pas utiliser ce mode de liste, écrire ainsi $scenario->setData(\"jeedom_capteurs\", \"\");", "options": [], "order": "0" } ] } ] } }, { "type": "element", "subtype": null, "expression": "2263", "options": [], "order": "7", "element": { "name": null, "type": "code", "options": [], "order": "0", "subElements": [ { "name": null, "type": "code", "subtype": "action", "options": { "collapse": "0", "enable": "1" }, "order": "0", "expressions": [ { "type": "code", "subtype": null, "expression": "$scenario->setData(\"jeedom_capteurs\", \"\n#[Piscine][Piscine Plugin][Température]#;\n#[Salle de bain][Capteur][Température]#\n\");", "options": [], "order": "0" } ] } ] } }, { "type": "element", "subtype": null, "expression": "2264", "options": [], "order": "8", "element": { "name": null, "type": "comment", "options": [], "order": "0", "subElements": [ { "name": null, "type": "comment", "subtype": "comment", "options": { "collapse": "0" }, "order": "0", "expressions": [ { "type": "comment", "subtype": null, "expression": "Bloc code de gestion", "options": [], "order": "0" } ] } ] } }, { "type": "element", "subtype": null, "expression": "2265", "options": [], "order": "9", "element": { "name": null, "type": "code", "options": [], "order": "0", "subElements": [ { "name": null, "type": "code", "subtype": "action", "options": { "collapse": "0", "enable": "1" }, "order": "0", "expressions": [ { "type": "code", "subtype": null, "expression": "$scenario->setLog(\" Début du script Assistant Domotique avec Mistral AI.\");\n\n\/\/ 1. Vérification de l’environnement PHP\nerror_reporting(E_ALL);\nini_set('display_errors', 1);\n$scenario->setLog(\" Test : Environnement PHP chargé avec succès.\");\n\n\/\/ 2. Pause\nsleep(2);\n\n\/\/ 3. Récupération des variables\n$apiKeyMistral = $scenario->getData(\"mistral_api_key\");\n$pieceIds = $scenario->getData(\"jeedom_piece_id\");\n$jeedomCapteurs = $scenario->getData(\"jeedom_capteurs\");\n$jeedomQuestionID = $scenario->getData(\"jeedom_question\");\n$jeedomSortieID = $scenario->getData(\"jeedom_sortie\");\n\n\/\/ 4. Vérification des valeurs\nif (\n empty($apiKeyMistral) ||\n empty($jeedomQuestionID) ||\n empty($jeedomSortieID) ||\n (empty($jeedomCapteurs) && empty($pieceIds))\n) {\n $scenario->setLog(\" Erreur : Une ou plusieurs variables essentielles sont manquantes.\");\n exit;\n}\n$scenario->setLog(\" API Key : OK\");\n$jeedomQuestion = cmd::byString($jeedomQuestionID)->execCmd();\n$scenario->setLog(\" Question posée : \\\"$jeedomQuestion\\\"\");\n\n\/\/ 5. Récupération des capteurs\n$listeCapteurs = [];\n\n\/\/ 5a. Si capteurs manuels définis, on les ajoute\nif (!empty($jeedomCapteurs)) {\n $scenario->setLog(\"Ajout des capteurs manuels.\");\n foreach (explode(\";\", $jeedomCapteurs) as $cap) {\n $listeCapteurs[] = trim($cap);\n }\n}\n\n\/\/ 5b. Si pièces définies, on récupère leurs capteurs\nif (!empty($pieceIds)) {\n foreach (explode(\";\", $pieceIds) as $pieceId) {\n $objet = jeeObject::byId((int)trim($pieceId));\n if (is_object($objet)) {\n $scenario->setLog(\"Pièce détectée : \" . $objet->getName());\n foreach (eqLogic::byObjectId($objet->getId()) as $eq) {\n foreach ($eq->getCmd('info') as $cmd) {\n if ($eq->getName() !== \"Résumé\") {\n $prefix = '#';\n\t\t\t\t\t\t$suffix = '#';\n\t\t\t\t\t\t$cmdFormat = $prefix . '[' . $objet->getName() . '][' . $eq->getName() . '][' . $cmd->getName() . ']' . $suffix;\n $listeCapteurs[] = $cmdFormat;\n }\n }\n }\n } else {\n $scenario->setLog(\"Pièce ID $pieceId introuvable.\");\n }\n }\n}\n\n\/\/ 5c. Sauvegarde de la liste fusionnée et affichage\nif (empty($listeCapteurs)) {\n $scenario->setLog(\"Erreur : aucune source de capteurs définie.\");\n exit;\n}\n$jeedomCapteurs = implode(\";\", $listeCapteurs);\n$scenario->setData(\"jeedom_capteurs\", $jeedomCapteurs);\n\/\/$scenario->setLog(\"Liste finale des capteurs : $jeedomCapteurs\");\n$scenario->setLog(\"Liste finale :\");\n\n\/\/ 5d. Extraction des données pour chaque capteur\n$capteursData = [];\nforeach ($listeCapteurs as $cap) {\n $cmd = cmd::byString(trim($cap));\n if (is_object($cmd) && $cmd->execCmd() !== '') {\n $valeur = $cmd->execCmd();\n $unite = $cmd->getUnite();\n $id = $cmd->getId();\n $nom = $cmd->getHumanName();\n $nomAvecId = \"$nom [ID: $id]\";\n $scenario->setLog(\"Capteur récupéré : $nomAvecId → $valeur$unite\");\n $capteursData[] = [\n \"id\" => $id,\n \"nom\" => $nomAvecId,\n \"valeur\"=> $valeur,\n \"unite\" => $unite\n ];\n }\n}\n\n\/\/ 6. Construction du prompt\n$prompt = \"Tu es un assistant domotique Jeedom qui analyse les relevés des capteurs.\\n\\n\";\n$prompt .= \"Capteurs détectés :\\n\";\nforeach ($capteursData as $d) {\n $prompt .= \"- {$d['nom']} : {$d['valeur']}{$d['unite']}\\n\";\n}\n$prompt .= \"\\nSi l'utilisateur fournit un ID (ex : 339805), utilise ce tableau pour faire la correspondance.\\n\\n\";\n$prompt .= \"Question : \\\"{$jeedomQuestion}\\\"\\n\\n\";\n$prompt .= \"Réponds en une seule phrase claire et pertinente.\\n\";\n\n\/\/ 7. Préparation de la requête Mistral\n$request = [\n \"model\" => \"mistral-small-2506\", \n \/\/ mistral-medium-2505 : Modèle \"medium\" avec chat complet, support de vision, très bon équilibre performance\/prix .\n \/\/ mistral-small-2506 : Plus léger, plus rapide, idéal pour réponses simples.\n \/\/ mistral-large-2411 : Plus puissant, contexte long, mais consommateur de ressources.\n \"messages\" => [\n [\"role\"=>\"system\",\"content\"=>\"Tu es un assistant Jeedom, très clair et direct.\"],\n [\"role\"=>\"user\",\"content\"=>$prompt]\n ],\n \"temperature\"=> 0.3,\n \"max_tokens\" => 150\n];\n$jsonPayload = json_encode($request, JSON_UNESCAPED_UNICODE);\n\n\/\/ 8. Envoi à Mistral\n$ch = curl_init();\ncurl_setopt($ch, CURLOPT_URL, \"https:\/\/api.mistral.ai\/v1\/chat\/completions\");\ncurl_setopt($ch, CURLOPT_RETURNTRANSFER, true);\ncurl_setopt($ch, CURLOPT_HTTPHEADER, [\n \"Content-Type: application\/json\",\n \"Authorization: Bearer $apiKeyMistral\"\n]);\ncurl_setopt($ch, CURLOPT_POST, true);\ncurl_setopt($ch, CURLOPT_POSTFIELDS, $jsonPayload);\ncurl_setopt($ch, CURLOPT_TIMEOUT, 30);\n\n$response = curl_exec($ch);\n$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);\n$curlError = curl_error($ch);\ncurl_close($ch);\n\n\/\/ 9. Analyse de la réponse\n$assistantResponse = \"Erreur : aucune réponse générée.\";\nif ($response === false) {\n $scenario->setLog(\" Erreur CURL : $curlError\");\n $scenario->setLog(\" Code HTTP : $httpCode\");\n exit;\n}\n$scenario->setLog(\" Réponse HTTP reçue : $httpCode\");\n$data = json_decode($response, true);\nif (isset($data['choices'][0]['message']['content'])) {\n $assistantResponse = trim($data['choices'][0]['message']['content']);\n} else {\n $scenario->setLog(\" Réponse Mistral invalide : \".print_r($data, true));\n}\n\n\/\/ 10. Envoi dans Jeedom\n$cmdSortie = cmd::byId($jeedomSortieID);\nif (is_object($cmdSortie)) {\n $cmdSortie->event($assistantResponse);\n $scenario->setLog(\" Réponse envoyée : \\\"$assistantResponse\\\" à la commande $jeedomQuestion\");\n} else {\n $scenario->setLog(\" Erreur : commande ID $jeedomSortieID introuvable.\");\n}\n\n$scenario->setLog(\" Fin du script Assistant Domotique Mistral AI.\");", "options": [], "order": "0" } ] } ] } } ] } ] } ] }