Tags : Chat GPT domotique jeedom
0. Contexte
Parfois, nos textes sur nos assistants vocaux sont trop plats, et les interactions ne sont pas assez intuitives. Grâce au travail de @fwehrle sur la communauté, j’ai pu créer un scénario à trous permettant d’utiliser ChatGPT.
J’ai choisi deux types d’interactions : celle qui génère une réponse et celle qui déclenche une action.
1. Création d’un virtuel
Tout d’abord, je crée un virtuel à adapter pour les deux scénarios selon vos besoins.
L’ID de chaque commande est indiqué après la sauvegarde, à gauche du nom. Il nous servira pour les scénarios. Par exemple, l’ID de la commande « question » pour le scénario question-réponse est celui-ci.
2. Scénario question – réponse
Voici le template de ce scénario :
Créez un bloc action et ajoutez-y tout ce qui suit :
– Créez trois variables :
puis un bloc code :
scenario::setData("jeedom_capteurs", "#[Virtuel Température][Etage - Température][Température]#;#[Virtuel Température][Salon bas - Température][Température]#");
Pensez à remplacer les devices que vous souhaitez fournir à ChatGPT. Par exemple, dans mon cas : #[Virtuel Température][Etage – Température][Température]#;#[Virtuel Température][Salon bas – Température][Température]#
Un second bloc code :
$scenario->setLog("🚀 Début du script Assistant Domotique avec GPT-4o.");
// **1️⃣ Vérification de l'environnement PHP**
error_reporting(E_ALL);
ini_set('display_errors', 1);
$scenario->setLog("✅ Test : Environnement PHP chargé avec succès.");
// **2️⃣ Pause pour éviter le bug de récupération des variables Jeedom**
sleep(2);
// **3️⃣ Récupération des variables Jeedom**
$apiKeyGPT = scenario::getData("jeedom_openai_api");
$jeedomCapteurs = scenario::getData("jeedom_capteurs"); // Liste des capteurs sous forme Jeedom
$jeedomQuestion = scenario::getData("jeedom_question"); // Question de l'utilisateur
$jeedomSortieID = scenario::getData("jeedom_sortie"); // Commande où envoyer la réponse
// **4️⃣ Vérification des valeurs**
if (empty($apiKeyGPT) || empty($jeedomCapteurs) || empty($jeedomQuestion) || empty($jeedomSortieID)) {
$scenario->setLog("❌ Erreur : Une ou plusieurs variables essentielles sont manquantes.");
exit;
}
// **📌 Log des variables récupérées pour débogage**
$scenario->setLog("📌 API Key : ✅ OK");
$scenario->setLog("📌 Capteurs Jeedom : $jeedomCapteurs");
$scenario->setLog("📌 Question posée : \"$jeedomQuestion\"");
$scenario->setLog("📌 ID de la sortie : $jeedomSortieID");
// **5️⃣ Extraction des données Jeedom**
$capteursArray = explode(";", $jeedomCapteurs);
$capteursData = [];
foreach ($capteursArray as $capteur) {
$cmd = cmd::byString(trim($capteur));
if (is_object($cmd) && $cmd->execCmd() !== '') {
$valeur = $cmd->execCmd();
$scenario->setLog("✅ Capteur récupéré : {$cmd->getHumanName()} → $valeur");
$capteursData[] = ["nom" => $cmd->getHumanName(), "valeur" => $valeur];
} else {
$scenario->setLog("⚠️ Capteur introuvable ou valeur vide : $capteur");
}
}
if (empty($capteursData)) {
$scenario->setLog("❌ Erreur : Aucune donnée récupérée de Jeedom.");
exit;
}
// **6️⃣ Reformulation explicite du prompt pour OpenAI**
$prompt = "Tu es un assistant domotique Jeedom qui analyse les relevés des capteurs et répond aux questions de l'utilisateur.\n\n";
$prompt .= "**📊 Capteurs détectés et relevés actuels :**\n";
foreach ($capteursData as $data) {
$prompt .= "- **{$data['nom']}** : {$data['valeur']}°C\n";
}
$prompt .= "\n⚠️ **Attention : Certains nombres dans la question peuvent être des identifiants et ne sont pas des capteurs.**\n";
$prompt .= "Tu dois ignorer tout chiffre qui ne correspond pas à un relevé de capteur.\n\n";
$prompt .= "**💡 Question posée par l'utilisateur :** \"$jeedomQuestion\"\n\n";
$prompt .= "**Ta mission :**\n";
$prompt .= "- Compare les relevés des capteurs.\n";
$prompt .= "- Réponds en **UNE seule phrase claire et directe**.\n";
$prompt .= "- Donne **l'information essentielle** sans analyser des nombres inutiles.\n\n";
$prompt .= "**Exemple de réponse correcte :**\n";
$prompt .= "- \"Le salon est l'endroit le plus chaud avec 19.8°C.\"\n";
$prompt .= "- \"Aucun relevé ne permet de répondre précisément à cette question.\"\n";
$prompt .= "\n**Réponds maintenant :**";
$scenario->setLog("📩 Envoi du prompt à OpenAI...");
// **7️⃣ Préparation de la requête OpenAI**
$data = [
"model" => "gpt-4o",
"messages" => [
["role" => "system", "content" => "Tu es un assistant domotique qui analyse les relevés des capteurs et réponds aux questions de manière directe et pertinente."],
["role" => "user", "content" => $prompt]
],
"max_tokens" => 200,
"temperature" => 0.6
];
$jsonPayload = json_encode($data, JSON_UNESCAPED_UNICODE);
if ($jsonPayload === false) {
$scenario->setLog("❌ Erreur : JSON mal formé avant envoi à OpenAI.");
exit;
}
// **8️⃣ Envoi à OpenAI**
$openaiUrl = "https://api.openai.com/v1/chat/completions";
$options = [
"http" => [
"header" => "Content-Type: application/json\r\n" . "Authorization: Bearer " . $apiKeyGPT . "\r\n",
"method" => "POST",
"content" => $jsonPayload,
"timeout" => 10
]
];
$context = stream_context_create($options);
$response = @file_get_contents($openaiUrl, false, $context);
// **9️⃣ Gestion de la réponse OpenAI**
$chatgptResponse = "Erreur : Aucune réponse générée.";
if ($response !== FALSE) {
$responseData = json_decode($response, true);
if (isset($responseData['choices'][0]['message']['content'])) {
$chatgptResponse = trim($responseData['choices'][0]['message']['content']);
} else {
$scenario->setLog("❌ Réponse OpenAI invalide : " . print_r($responseData, true));
}
} else {
$scenario->setLog("❌ Erreur OpenAI : L'API n'a pas répondu.");
exit;
}
// **🔟 Envoi de la réponse vers Jeedom**
$cmdSortie = cmd::byId($jeedomSortieID);
if (is_object($cmdSortie)) {
$cmdSortie->event($chatgptResponse);
$scenario->setLog("✅ Réponse envoyée à l'action message ID $jeedomSortieID : $chatgptResponse");
} else {
$scenario->setLog("⚠️ Erreur : Commande ID $jeedomSortieID introuvable.");
}
// **🔚 Fin du script**
$scenario->setLog("🔚 Fin du script Assistant Domotique.");
Comment utiliser ce scénario ?
jeedom_capteurs = par exemple : #[Virtuel][Salon][Température]#;#[Divers][Meteo][Condition]#
jeedom_openai_api = ta clé API OpenAI
jeedom_question = ID de ta question
jeedom_sortie = ID du message où afficher la réponse
2.1 Exemple :
Le soir, je vérifie mon planning ainsi que celui des membres de la famille, et c’était un peu tristoune. Cela donnait :
* »Bonjour à tous, voici le programme de demain :
- Pour Loïc, le programme est B.
- Pour Élodie, le programme est [vide].
- Pour la famille, le programme est : Judo pour Marylou.
Pensez à sortir les poubelles. »*
Pas très engageant…
J’ai donc décidé d’envoyer mes plannings à ChatGPT, qui me les restitue avec une version plus naturelle et évolutive chaque jour.
Dans mon scénario, j’indique :
- jeedom_question:59090 → Contient la question :
« Annonce le programme du lendemain pour chaque membre de la famille avec fluidité et un ton léger. S’il n’y a rien dans l’agenda de Loïc ou d’Élodie, c’est que nous sommes en repos. Le mercredi, on doit sortir les poubelles. » - jeedom_capteurs : –> Agenda Google des membres de la famille :
[Protocole][Agenda Loïc][Événement demain] ; [Protocole][Agenda Élodie][Événement demain]
- jeedom_sortie = 59035 –> ce qui me génère alors :
« Salut tout le monde ! Voici ce qui vous attend demain :
Loïc a prévu travaille en B, tandis qu’Élodie profite d’une journée de repos bien méritée.
Marylou a son cours de judo, donc n’oubliez pas le kimono !
Aucun anniversaire à fêter, donc pas de gâteau en vue.
Ah, et pensez à sortir les poubelles avant que ça déborde.
Passez une excellente journée ! »
Chaque jour à 20h, ce scénario s’exécute et Alexa nous annonce le programme du lendemain.
3. Scénario question-action
Voici le template de ce scénario :
Je mets dans un Object/piece de ma maison toutes les commandes que j’autorise à chatgpt
On crée un bloc action puis on met tout ce qui suit dedans
Créer 4 variables :
puis, on crée un bloc code :
$scenario->setLog("🚀 Début du script Assistant Domotique avec GPT-4o.");
// **1️⃣ Vérification de l'environnement PHP**
error_reporting(E_ALL);
ini_set('display_errors', 1);
$scenario->setLog("✅ Test : Environnement PHP chargé avec succès.");
// **2️⃣ Récupération des variables dynamiques**
sleep(2); // Pause pour s'assurer que les variables sont bien disponibles
$openaiApiKey = scenario::getData("jeedom_openai_api");
$cmdAskId = scenario::getData("jeedom_question");
$pieceId = scenario::getData("jeedom_piece");
$cmdReponseId = scenario::getData("jeedom_sortie");
$scenario->setLog("📌 API Key récupérée : " . (empty($openaiApiKey) ? "❌ Manquante" : "✅ OK"));
$scenario->setLog("📌 Commande utilisateur ID : " . (empty($cmdAskId) ? "❌ Manquante" : $cmdAskId));
$scenario->setLog("📌 Pièce ID : " . (empty($pieceId) ? "❌ Manquante" : $pieceId));
$scenario->setLog("📌 Commande de réponse ID : " . (empty($cmdReponseId) ? "❌ Manquante" : $cmdReponseId));
// **📌 Vérification des variables obligatoires**
if (empty($openaiApiKey) || empty($cmdAskId) || empty($pieceId) || empty($cmdReponseId)) {
$scenario->setLog("❌ Erreur : Une ou plusieurs variables essentielles sont manquantes.");
exit;
}
// **3️⃣ Récupération de la commande utilisateur**
$cmdAsk = cmd::byId((int)$cmdAskId);
$questionUtilisateur = (is_object($cmdAsk) && $cmdAsk->execCmd() !== '') ? $cmdAsk->execCmd() : "";
if (empty($questionUtilisateur)) {
$scenario->setLog("⚠️ Aucune commande reçue !");
exit;
}
$scenario->setLog("📩 Commande utilisateur : $questionUtilisateur");
// **4️⃣ Récupération des équipements de la pièce**
$objet = jeeObject::byId((int)$pieceId);
if (!is_object($objet)) {
$scenario->setLog("❌ Erreur : Aucun objet trouvé pour l'ID $pieceId.");
exit;
}
$scenario->setLog("✅ Pièce détectée : " . $objet->getName());
// **5️⃣ Récupération des équipements actionnables**
$equipements = $objet->getEqLogic(true);
$equipementsActionnables = [];
foreach ($equipements as $equipement) {
if ($equipement->getIsEnable() && $equipement->getIsVisible()) {
foreach ($equipement->getCmd() as $cmd) {
if ($cmd->getIsVisible() == 1 && $cmd->getType() == "action") {
$equipementsActionnables[] = [
"nom" => $equipement->getName(),
"commande" => $cmd->getName(),
"id" => $cmd->getId()
];
$scenario->setLog("✅ Équipement actionnable détecté : " . $equipement->getName() . " - Commande : " . $cmd->getName());
}
}
}
}
if (empty($equipementsActionnables)) {
$scenario->setLog("❌ Aucun équipement actionnable détecté !");
exit;
}
// **6️⃣ Encodage JSON des équipements pour OpenAI**
$equipementsJson = json_encode($equipementsActionnables, JSON_UNESCAPED_UNICODE);
if (!$equipementsJson || $equipementsJson == "null") {
$scenario->setLog("❌ Erreur JSON : les équipements ne sont pas envoyés à GPT.");
exit;
}
$scenario->setLog("📊 Envoi des équipements détectés à GPT : " . $equipementsJson);
// **7️⃣ Envoi à GPT-4o**
$data = [
"model" => "gpt-4o",
"messages" => [
["role" => "system", "content" => "Tu es un assistant domotique Jeedom intelligent. Analyse et exécute les demandes en fonction des équipements disponibles."],
["role" => "system", "content" => "Réponds TOUJOURS sous la forme d'un JSON contenant : 'question', 'response', 'id', 'mode' (action ou info)."],
["role" => "user", "content" => "Voici les équipements disponibles dans la pièce ID $pieceId : " . $equipementsJson],
["role" => "user", "content" => "Commande utilisateur : " . $questionUtilisateur]
],
"max_tokens" => 200,
"temperature" => 0.5
];
$options = [
"http" => [
"header" => "Content-Type: application/json\r\n" . "Authorization: Bearer " . $openaiApiKey . "\r\n",
"method" => "POST",
"content" => json_encode($data),
"timeout" => 10
]
];
$context = stream_context_create($options);
$response = @file_get_contents("https://api.openai.com/v1/chat/completions", false, $context);
// **8️⃣ Vérification de la réponse GPT-4o**
if ($response === FALSE) {
$scenario->setLog("❌ Erreur OpenAI : L'API n'a pas répondu.");
exit;
}
$responseData = json_decode($response, true);
if (!isset($responseData['choices'][0]['message']['content'])) {
$scenario->setLog("❌ Réponse OpenAI invalide : " . print_r($responseData, true));
exit;
}
// **🔹 Suppression des balises `json` dans la réponse**
$chatgptResponse = trim($responseData['choices'][0]['message']['content']);
$chatgptResponse = str_replace(["```json", "```"], "", $chatgptResponse);
$chatgptResponse = trim($chatgptResponse);
$scenario->setLog("✅ Réponse GPT après nettoyage : " . $chatgptResponse);
// **9️⃣ Exécution de la commande si action détectée**
$reponseJson = json_decode($chatgptResponse, true);
if (isset($reponseJson['id']) && $reponseJson['mode'] == "action") {
$cmdIds = $reponseJson['id'];
if (is_array($cmdIds)) {
foreach ($cmdIds as $cmdId) {
$cmd = cmd::byId((int)$cmdId);
if (is_object($cmd)) {
$cmd->execCmd();
$scenario->setLog("✅ Exécution de la commande ID $cmdId : " . $cmd->getHumanName());
} else {
$scenario->setLog("❌ Échec : ID de commande inexistant ($cmdId)");
}
}
} elseif (is_numeric($cmdIds)) {
$cmd = cmd::byId((int)$cmdIds);
if (is_object($cmd)) {
$cmd->execCmd();
$scenario->setLog("✅ Exécution de la commande ID $cmdIds : " . $cmd->getHumanName());
} else {
$scenario->setLog("❌ Échec : ID de commande inexistant ($cmdIds)");
}
} else {
$scenario->setLog("⚠️ Aucun ID valide retourné par GPT.");
}
}
// **🔟 Envoi de la réponse dans Jeedom**
$cmdReponse = cmd::byId((int)$cmdReponseId);
if (is_object($cmdReponse)) {
$cmdReponse->event($reponseJson['response']);
$scenario->setLog("✅ Réponse envoyée à l'ID $cmdReponseId : " . $reponseJson['response']);
} else {
$scenario->setLog("❌ Erreur : Impossible d'envoyer la réponse (ID $cmdReponseId).");
}
// **🔚 Fin du script**
$scenario->setLog("🔚 Fin du script Assistant Domotique.");
Comment utiliser ce scénario ?
- jeedom_openai_api = Ta clé API OpenAI
- jeedom_commande = ID de la commande utilisateur (ex: question posée via un assistant vocal ou une interaction)
- jeedom_piece = ID de la pièce Jeedom contenant les équipements à contrôler
- jeedom_sortie = ID du message où afficher la réponse
trouver id de la pièce :
Choisir la pièce dans son dashboard puis on l’a dans le lien de la page :
3.1 Exemple
Il fait trop sombre, je veux que ChatGPT m’aide.
- jeedom_commande = 59100 → Contient la commande : « Il fait sombre, aide-moi. »
- jeedom_piece = 72 → Contient les équipements à contrôler. Pièce créée pour l’occasion, dans mon cas.
- jeedom_sortie = 59101 → Réponse de ChatGPT : « J’allume la lumière pour vous. »
Et paf, la magie opère !
4. Automatisation
Lorsque je publie quelque chose dans ma commande question ou question ask, je veux que le scénario s’exécute. Du coup, après chaque validation, je crée une action.
Je choisis ma question message, puis je clique sur la roue crantée.
Puis, je vais dans Configuration → Action après exécution de la commande.
Je choisis Scénario, puis je sélectionne celui que je souhaite exécuter et je le démarre.
Libre à vous d’intégrer cette zone de texte dans Telegram, Jeedom Connect, etc.
Les possibilités sont infinies !
Par exemple, je crée cela dans Jeedom Connect/
Et il l’éteint tout seul
J’espère que cet article vous sera utile.
Belle journée, et n’oubliez pas que la vie est une fête ! 🎉