Reconnaissance vocale sans paramétrages ... Retour d'expérience

Bonjour,

La reconnaissance vocale c’est sympa, mais au vu de la quantité de paramétrages nécessaires avec Google Home ou Alexa ou le système d’interaction de Jeedom …
Pour chaque action il faut ajuster les paramètres, corriger ici, modifier là … c’est décourageant !!!

Fort de cette inexpérience frustrante j’ai écris un moteur d’interaction travaillant directement sur la base de données de Jeedom et couplé, pour le moteur de reconnaissance vocale avec l’APK JPI de @dJuL (dont on ne dira jamais assez l’excellence). Il répond également aux SMS (merci encore à JPI de @dJuL), à PushBullet et à Télégram et peut être bientôt au téléphone !!!

Les contraintes :
Evidemment il est nécessaire de ‹ normer › les libellés des différents équipements et des commandes, norme légère puisque j’ai « ajusté » mes 246 équipements en moins de une heure.

Résultat :
Avec ce principe 95 % des données des équipements physiques ou virtuels sont directement accessible sans AUCUN paramétrage, le traitement est quasi instantané et peu consommateur de CPU (travail direct sur la BdD) et permet un dialogue quasi naturel avec la VR.

A titre d’exemple voici un jeu de test d’une quarantaine de commandes suivi des résultats :

"donne moi la température du salon et puis donne moi la température extérieure 
ensuite je voudrais connaître la consommation de la lampe du bureau après donne moi
 la luminosité de l`oeil de la cuisine donne moi aussi l`humidité du salon et 
pour finir monte le volet du bureau allume la lumière du séjour allume le 
booster et dis encore merci à @dJuL",
	
	"donne moi la météo",
	"quel est l'état de la lampe du séjour",
	"quelle est la puissance de la lampe du bureau",
	"donne moi la consommation de la lampe du séjour",
	"quelle est la température extérieure",
	"donne moi la Pression de l'extérieur",
	"quel est la vitesse du vent",
	"donne moi le Cap du vent de l'extérieur",
	"donne moi la direction du vent de l'extérieur",
	"donne moi la température du congélo de l'extérieur",
	"donne moi la température du frigo du salon",
	"quelle est la température de la chambre",
	"température de l'oeil de la cuisine",
	"donne moi la luminosité de l'oeil de la cuisine",
	"donne moi l'humidité du salon",
	"quel est l'état de la porte du séjour",
	 "quel est l'état du booster",
	"quel est l'état de la lampe oeuf du salon",
	"donne moi l'état de la porte d'entrée",
	"quel est la consigne de chauffage de la chambre",
	"donne moi l'état de la sirène de la maison",
	"quelle est la puissance consommée par la lampe de la cuisine",
	"donne moi la puissance du lave linge",
	"donne moi la puissance du lave Vaisselle",
	"donne moi la puissance du compresseur de la piscine",
	"met la lampe couleur du salon à 10%",
	"éteint la lampe couleur du salon",
	"allume le booster",
	"arrête le booster",
	"éteint la lampe du bureau",
	"règle la lampe du bureau a 50%",
	"allume la lampe du bureau",
	"baisse la lampe de la sam à 50%",
	"met la lampe du séjour à 50%",
	"met la lampe du séjour à 50%",

A remarquer :

  • la première demande à rallonge …
  • Les réponses du type ‹ … est déjà à … › qui évite aussi de lancer la commande

le traitement prend moins de 1/4 sec et donne comme résultat :

- la température du salon  est à 22°C
- la température extérieur  est à 19°C
- la consommation de la lampe du bureau du salon  est allumée
- la luminosité de de l`oeil de la cuisine du salon est à 241 Lux
- l`humidité du salon  est à 49%
- c`est fait,  le volet du bureau du salon  est maintenant Ouvert
- c`est fait,  la lampe du séjour du salon  est maintenant allumée 
- c`est fait,  le booster du salon  est maintenant en route
- l`etat de la lampe du séjour du salon  est à 50%
- la puissance de la lampe du bureau du salon  est allumée
- Actuellement  la température extérieure mesurée est de 19 degrés et l'humidité de 
- 56 %, (Le vent souffle du Ouest Nord Ouest à 33 kilomètres heure avec des rafales 
- à 33 kilomètres heure.) Les prévisons de Météo France pour 17 heures sont  
- Ensoleillé., UV 2, Température : 15 degrés, (Le vent souflera à 20 kilomètres 
- heure du Nord Ouest avec des rafales à 40 kilomètres heure.)
- la consommation de la lampe du séjour du salon  est à 50%
- la température extérieur  est à 19°C
- la pression de l'extérieur  est à 1023 hecto Pascal
- Votre demande est introuvable, essayer une autre formulation
- la cap du vent de l'extérieur  est à 290°
- la température du congélateur de l'extérieur  est à -21°C
- la température du réfrigérateur du salon  est à 4°C
- la température de la chambre  est à 19°C
- température de l`oeil de la cuisine du salon  est à 22°C
- la luminosité de l`oeil de la cuisine du salon  est à 241 Lux
- l'humidité du salon  est à 49%
- l`etat de la porte du séjour du salon  est ouverte
- l`etat du booster du salon  est arrété
- l`etat de la lampe oeuf du salon  est allumée
- l`etat de la porte d`entrée du salon  est fermée
- la consigne de chauffage de la chambre  est  : Economique
- l`etat de la sirène de la maison  est arrété
- la puissance par la lampe de la cuisine du salon  est éteinte
- la puissance du lave linge du Rez-de-Chaussée  est à 1W
- la puissance du lave vaisselle du salon est arrété
- la puissance du compresseur de la piscine de l`extérieur  est à 716W
- c`est fait,  la lampe couleur du salon  est maintenant à 10 %
- la lampe couleur du salon  est déja éteinte
- le booster du salon  est déja en route
- c'est fait,  le booster du salon  est maintenant arrété
- c'est fait,  la lampe du bureau du salon  est maintenant éteinte
- c'est fait,  la lampe du bureau du salon  est maintenant à 50%
- la lampe du bureau du salon  est déjà allumée
- la lampe de la Salle manger du salon  est déja à 50%
- la lampe du séjour du salon  est déjà à 50%
- la lampe du séjour du salon  est déjà à 50%

Le tout est tiens en 800 lignes de PHP avec force recours aux requêtes SQL et/ou REGEX :slight_smile:

Salut,
La question logique qui vient c’est :
Pourquoi ne le mets-tu pas à disposition ?

:slight_smile: parceque c’est du pur php brut, rien à voir avec un plugin.

Donc mettre à dispo cela revient à proposer un moteur en pièces détachées sans SAV !!!

Mais pour les dev intéressés voici le code du scénario :

<?php

global $regexOn, $regexOff, $regexSlider, $regexInfo;

//Infos, Commandes et Equipements :
	// $PUSHBULLET, $TELEGRAM, $infVRstate

//N° des scénarios :

// Variables :

	$debug = 1;			// ***************************

// DEFINITIONS DES REGEX PRINCIPALES
$regexOn = "((\s^)on)|allume.?|Ouvre(s|ir)?|lance.?|monte.?|(maxi(mum)?)";
$regexOff = "Of(f)?|.tein(s|t|d|dre)?|(arr.te)|stoppe.?|arr.te.?|z.ro|baisse.?|ferme.?|(mini(mum)?)";
$regexSlider = "ambiance|Slider|r.gle.?|met(s|tre)?";
$regexInfo = "(.tat)|(temp.rature.?)|consommation|Puissance|intensit.|luminosit.|humidit.|vent |rafale.?|pression|(vitesse|cap|direction)|consigne|ouverture|mouvement";


//Paramètres :

/*********************************************************************************************************************/
/*********************************************************************************************************************/
/*********************************************************************************************************************/
global $PUSHBULLET, $TELEGRAM, $org, $expediteur, $index, $silencieux, $infReponse;


// ------------------------------------------------ Récupération du message -------------------------------------------
$declencheur = mg::getTag('trigger');

$org = '';
$message = '';
if(strpos($declencheur, 'Interaction') !== false) {
	$org = 'JEEDOM';
	mg::message('', "déclencheur : $declencheur");
	$message = mg::getCmd($declencheur);
}
elseif(strpos($declencheur, 'Telegram') !== false) {
	$org = 'TELEGRAM';
	$message = mg::getCmd($declencheur);
}
elseif( strpos($declencheur, 'PushBullet') !== false) {
	$org = 'PUSHBULLET';
	$message = mg::getCmd($declencheur);
}
elseif (mg::gettag('org') == 'JPI_SMS') {
  $org = 'JPI_SMS';
  $message = mg::getTag('message');
  $expediteur = mg::getTag('expediteur');
}
elseif (mg::gettag('org') == 'JPI_INTERACTION') {
  $org = 'JPI_INTERACTION';
  $message = mg::getTag('message');
}

// ************************************************** Lancement normal ************************************************
if ($declencheur != 'user') {
	mg::messageT('', ".Base($org)  ==> $message");
	if ($message == '') { return; }
		a_decoupeMessage($message);
}

// ****************************************** Modif du statut de la VR de JPI *****************************************
if ($declencheur == 'user') {
	if ($debug == 0) {
		if (mg::getCmd($infVRstate) > 0) {
			mg::messageT('', "! Mise en veille (pause) de la reconnaissance vocale");
			mg::JPI('SCENARIO', '_veilleVR');
		} else {
			mg::messageT('', "! Activation de la reconnaissance vocale");
			mg::JPI('SCENARIO', '_activeVR');
		}

	// **************************************************** DEBUG *****************************************************
	} else {
		$messages = setDebug();
		$silencieux = 1;
		$org = 'JEEDOM';
		for ($i=0; $index < count($messages); $i++) {
			$message = $messages[$i];
			if ($message == '') { return; }
			$index = $i;
		$return = a_decoupeMessage($message);
			mg::message('', ".");
			mg::message('', ".");
			if ($return < 0) { return $return; }
		}
	}
}

/*********************************************************************************************************************/
/************************************* RECHERCHE ET LANCEMENT DE LA DEMANDE ******************************************/
/*********************************************************************************************************************/
function d_requete($r) {
	global $index;
	$values = array();
	$valSlider = $r['valSlider'];

	// Première Recherche commande
	$resultSql = e_requeteSQL1($r);

	// Si problème on lance la requète2
	if (count($resultSql) == 0 || count($resultSql) > 1) {
		$resultSql = f_requeteSQL2($r);
	}


	// CONTROLE UNICITE DE LA REQUETE
	if (count($resultSql) > 1) {
		g_setReponse("Votre demande à plus d'une réponse possible, veuillez être plus précis");
		mg::message('Log:/_debug', "Plus d'une réponse : " .$r['message']); // debug
		return -1;
	// CONTROLE ABOUTISSEMENT DE LA REQUETE
	} else	if (count($resultSql) == 0) {
		g_setReponse("Votre demande est introuvable, essayer une autre formulation");
		mg::message('Log:/_debug', "Introuvable : " .$r['message']); // debug
		return -1;
	}

	// COMMANDE ACTION
	if ($r['typeCmd'] == 'action') {
		$valInfo = getEtatId($resultSql[0]['eqType_name'], $resultSql[0]['eqLogic_id'], "({$r['motsResiduels']}).*({$r['localisation2']})", $subType, $unite);

		// Si rien à faire
		mg::message('', "$valInfo > 0 && $valSlider > 0 && $subType");
		if ( $valInfo == $valSlider || ($valInfo > 0 && $valSlider > 0 && $subType != 'numeric')) {
				g_setReponse($r['txtCmd']. " est dèja " . libelleEtat($r['objet'], $valInfo, $subType, $unite));

		// Sinon lancement de la commande
		} else {
			mg::setCmd('#' . $resultSql[0]['cmd_id'] . '#', '', intval($valSlider));
			g_setReponse("c'est fait, {$r['txtCmd']} est maintenant " . libelleEtat($r['objet'], $valSlider, $subType, $unite));
		}
	// COMMANDE INFO
	} else	if ($r['typeCmd'] == 'info') {
		$unite = $resultSql[0]['unite'];
		$subType = $resultSql[0]['subType'];
		$valInfo =	mg::getCmd('#' . $resultSql[0]['cmd_id'] . '#');
		g_setReponse($r['txtCmd']. " est " . libelleEtat($r['objet'], $valInfo, $subType, $unite));
	}
}

/*********************************************************************************************************************/
/******************************* MAKE ET LANCEMENT DE LA REQUETE SUR LES VIRTUELS ************************************/
/*********************************************************************************************************************/
function e_requeteSQL1($r) {
	global $index;
	// RECHERCHE DE L'EQUIPEMENT
	$values = array();

	$sql = "
SELECT
-- ******** Req1 - $index - {$r['message']} ********
--
	object.name as `localisation`,
	eqLogic.eqType_name, eqLogic.name, eqLogic.id as `eqLogic_id`, eqLogic.tags, eqLogic.isEnable, eqLogic.comment,
	cmd.id as `cmd_id`, cmd.type as `cmd_type`, cmd.name as `cmd_name`, cmd.subType, cmd.value as `id_Etat`, cmd.isHistorized, cmd.unite
FROM `eqLogic`
	LEFT JOIN `cmd` ON eqLogic.id = cmd.eqLogic_id
	LEFT JOIN `object` ON object.id = eqLogic.object_id
WHERE
	eqLogic.isEnable = 1											-- FILTRAGE isEnabled 0
	AND lower(eqLogic.eqType_name) REGEXP lower('virtual')			-- FILTRAGE PROTOCOLE 1
	AND lower(object.name) = lower('{$r['localisation']}')			-- FILTRAGE LOCALISATION
	AND lower(cmd.type) = lower('{$r['typeCmd']}')					-- FILTRAGE TYPE DE COMMANDE 3

	AND lower(eqLogic.name) REGEXP lower('{$r['equipVirtuel']}') -- FILTRAGE EQUIPEMENTS VIRTUEL 4a

	AND lower(cmd.name) REGEXP lower('({$r['objet']})') -- FILTRAGE NOM CMD COMPOSE 5a
	AND lower(cmd.name) REGEXP lower('({$r['localisation2']})') -- FILTRAGE NOM CMD COMPOSE 6a
	AND lower(cmd.name) REGEXP lower('({$r['localisation']})?') -- FILTRAGE NOM CMD COMPOSE 7a

	AND lower(cmd.name) REGEXP lower('({$r['objet']} |{$r['cmd']}$)')			  -- FILTRAGE COMMANDES 8a
--
LIMIT 5
";

	mg::messageT('', $sql);
	$resultSql = DB::Prepare($sql, $values, DB::FETCH_TYPE_ALL);
	mg::message('', "Résultats de la Req1 : " . print_r($resultSql, true));
	return $resultSql;
}

/*********************************************************************************************************************/
/************************* MAKE ET LANCEMENT DE LA REQUETE SQL SUR LES PROTOCOLES PHYSIQUE ***************************/
/*********************************************************************************************************************/
function f_requeteSQL2($r) {
	global $index;
	// RECHERCHE DE L'EQUIPEMENT
	$values = array();

	$sql = "
SELECT
-- ******** Req2 - $index - {$r['message']} ********
--
	object.name as `localisation`,
	eqLogic.eqType_name, eqLogic.name, eqLogic.id as `eqLogic_id`, eqLogic.tags, eqLogic.isEnable, eqLogic.comment,
	cmd.id as `cmd_id`, cmd.type as `cmd_type`, cmd.name as `cmd_name`, cmd.subType, cmd.value as `id_Etat`, cmd.isHistorized, cmd.unite
FROM `eqLogic`
	LEFT JOIN `cmd` ON eqLogic.id = cmd.eqLogic_id
	LEFT JOIN `object` ON object.id = eqLogic.object_id
WHERE
	eqLogic.isEnable = 1											-- FILTRAGE isEnabled 0
	AND lower(eqLogic.eqType_name) REGEXP lower('openzwave|deconz|xiaomihome|rfxcom') -- FILTRAGE PROTOCOLE 1
	AND lower(object.name) = lower('{$r['localisation']}')			-- FILTRAGE LOCALISATION
	AND lower(cmd.type) = lower('{$r['typeCmd']}')					-- FILTRAGE TYPE DE COMMANDE 3
--
	AND lower(eqLogic.name) REGEXP lower('({$r['localisation2']})') -- FILTRAGE LOCALISATION2 4b
	AND lower(eqLogic.name) REGEXP lower('({$r['objet']}).*({$r['motsResiduels']})') -- FILTRAGE OBJET 5b

	AND lower(cmd.name) REGEXP lower('^({$r['cmd']})')				-- FILTRAGE COMMANDES 6b

--
LIMIT 5
";

	mg::messageT('', $sql);
	$resultSql = DB::Prepare($sql, $values, DB::FETCH_TYPE_ALL);
	mg::message('', "Résultats de la Req2 : " . print_r($resultSql, true));
	return $resultSql;
}

//********************************************************************************************************************/
/******************************** DECOUPE LA DEMANDE EN PHRASE DE SOUS DEMANDE ***************************************/
/*********************************************************************************************************************/
function a_decoupeMessage($message) {
	global $index, $regexOn, $regexOff, $regexSlider, $regexInfo;

	// gestion des apostrophes (le remplacement inverse se fait dans 'g_setReponse' en fin de traitement)
	$message = str_ireplace(array('l\''), 'l_ ', $message);
	$message = str_ireplace(array('d\''), 'd_ ', $message);

	// Pré nettoyage
	$message = str_replace(array('quel', 'quelle', ' est ', 'donne', 'moi ',' puis ', 'depuis', 'ensuite', 'après', 'continue' , 'finalement'), ' ', $message);
	// Mots parasites à supprimer d'office
	$message = str_ireplace(array('fabienne', 'd_ accord', 'alors', 'ok', 'parfait', ' tu ', ' et '), ' ', $message);

	$n = 0;
	$regex = "/($regexOn|$regexOff|$regexSlider|$regexInfo)/ui";

	// EXTRACTION DES PHRASES
	$phrases = array();
	$mots = explode(' ', $message);
	foreach($mots as $key => $mot) {
			preg_match($regex, $mot, $found);
			if (@iconv_strlen($found[0]) > 1) {
				$n++;
				$phrases[$n] = '';
				// recherche et pose du préfixe pronom
				if (array_search($mots[$key-1], array('le', 'la', 'les', 'du', 'des', 'l_', 'd_')) !== false) {
					$phrases[$n] .= $mots[$key-1];
				}
			}
			if ($n > 0) { $phrases[$n] .= " $mot "; }
	}
	mg::message('', "\n$message\n" . print_r($phrases, true));

	// LANCEMENT DES PHRASES DECOUPEES
	foreach($phrases as $key => $phrase) {
		$phrase = str_ireplace('  ', ' ', trim($phrase));
		$nbMots = count(explode(' ', $phrase));
		if ($nbMots > 1) {
			mg::messageT('', ". Phrase $index - (" . ($key) . "/" . count($phrases) . ") - $nbMots mots ==> '" . $phrase . "'");

			$return = b_decodeMessage(trim($phrase));
		}
	}
}

/*/*******************************************************************************************************************/
/***************************************** DECODE LE TXT DE LA DEMANDE ***********************************************/
/*********************************************************************************************************************/
function b_decodeMessage($message) {
	$message = c_nettoieMessage($message);
	if (trim($message) == '') { return; }

	// Init du tableaux de synthèse
	$r = array('message'=>'', 'equipVirtuel'=>'', 'localisation'=>'', 'localisation2'=>'', 'objet'=>'', 'action'=>'', 'typeCmd'=>'', 'cmd'=>'', 'valSlider'=>'', 'motsResiduels'=>'', 'txtCmd'=>'');
	$r['message'] = $message;

	// Recherche de l'EQUIPEMENT VIRTUEL et de l'OBJET
	getEqVirtuel($r);

	// Recherche de l'OBJET
	getObjet($r);

	// Recherche de LOCALSATION et LOCALISATION2 (complémentaire)
	getLocalisations($r);

	// Recherche d'une commande ACTION
	getCmdAction($r);

	// Recherche d'une commande INFO
		if ($r['action'] != 'Action') {
			getCmdInfo($r);
		}

	// ******************************************** NOM TEXTUEL DE LA COMMANDE ********************************************
	$tabMots = explode(' ', $r['message']);
	for ($i = 0; $i < count($tabMots); $i++) {
		if (@iconv_strlen(trim($tabMots[$i])) > 1
		)
		{ $r['txtCmd'] .= "$tabMots[$i] "; }
		$r['txtCmd'] = str_replace($r['action'], '', $r['txtCmd']);
		$r['txtCmd'] = str_replace(intval($r['valSlider']), '', $r['txtCmd']);
		$r['txtCmd'] = str_replace('%', '', $r['txtCmd']);
	}
		$r['txtCmd'] = str_replace('état', '', $r['txtCmd']);
	$r['txtCmd'] = str_replace('  ', ' ', $r['txtCmd']);

	// ************************************************ MOTS RESIDUELS ************************************************
	$separateur = '.*';

	$txtCmd2 = str_replace(array('chauffage', 'nombre', 'etat', 'consommée', 'consommé', 'vent'), ' ', $r['txtCmd']);
	$txtCmd2 = str_ireplace(' ', ' ', $txtCmd2);

	$tabMots = explode(' ', $txtCmd2);
	for ($i = 0; $i < count($tabMots); $i++) {
		if (@iconv_strlen(trim($tabMots[$i])) > 3
			&& strpos($r['cmd'], $tabMots[$i]) === false
			&& strpos($r['action'], $tabMots[$i]) === false ////////////////////////////////
			&& strpos($r['localisation'], $tabMots[$i]) === false
			&& strpos($r['localisation2'], $tabMots[$i]) === false
			&& strpos($r['objet'], $tabMots[$i]) === false
		) {
			$r['motsResiduels'] .= trim("($tabMots[$i])$separateur");
		}
	}
	$r['motsResiduels'] = trim($r['motsResiduels'], $separateur);
	$r['motsResiduels'] = str_ireplace('  ', ' ', $r['motsResiduels']);

	// ******************************************************* FIN ********************************************************

	mg::message('', "Tableau du décodage de la requète :" . print_r($r, true));
	mg::message('', " .");

	// Erreur si pas de cmd
	if (!$r['cmd']) {
		g_setReponse("Veuillez reformuler votre demande en précisant l'action désirée (monter, éteindre, donne-moi, etc...)");
		mg::message('Log:/_debug', "Pas d'action : " .$r['message']); // debug
		return -1;
	}
	// Erreur pas de localisation
	if (!$r['localisation']) {
		g_setReponse("Veuillez reformuler votre demande en précisant la localisation (Salon, Etage, Rez de Chaussée, Extérieur)");
		mg::message('Log:/_debug', "Pas de localisation : " .$r['message']); // debug
		return -1;
	}

	// Lancement de la requète SQL
	return $return = d_requete($r);
}

/*********************************************************************************************************************/
/**************************************************** NETTOIE MESSAGE ************************************************/
/*********************************************************************************************************************/
function c_nettoieMessage($message) {

	// Nettoie les pronoms de fin de phrase
//	$message = preg_replace('/((la)|(le)|(l_))$/ui', '', $message);
	$message = preg_replace('/\s\D{0,3}$/ui', '', $message);
	$message = trim(strtolower($message));

	// ------------------------------------- GESTION DES ABBREVIATIONS -----------------------------------------
	$message = str_ireplace(array('etg'), ' Etage ', $message);
	$message = str_ireplace(array('rdc'), ' Rez-de-Chaussée ', $message);
	$message = str_ireplace(array('sam'), ' Salle à manger ', $message);
	$message = str_ireplace(array('sdb'), ' Salle de Bain ', $message);

	// ------------------------------------- GESTION DES SYNONYME -----------------------------------------
	$message = str_ireplace(array('general'), 'général', $message);
	$message = str_ireplace(array('état'), 'etat', $message);
	$message = str_ireplace(array('Salle de Bain'), 'Salle de Bain du Rez-de-Chaussée', $message);

	$message = str_ireplace(array('rez de chaussee', 'Rez de Chaussée'), ' Rez-de-Chaussée ', $message);
	$message = str_ireplace(array('exterieur','extérieure'), 'extérieur', $message);
	$message = str_ireplace(array('entree'), 'entrée', $message);
	$message = str_ireplace(array('degré ','temperature'), 'température', $message);
	$message = str_ireplace(array('lumière','lumiere','éclairage','eclairage', 'lampes'), 'lampe', $message);
	$message = str_ireplace(array('rideau','store'), 'volet', $message);
	$message = str_ireplace(array('fenetre'), 'fenêtre', $message);
	$message = str_ireplace(array('frigo', 'frigidaire'), 'réfrigérateur', $message);
	$message = str_ireplace(array('congelo', 'congélo', 'congelateur'), 'congélateur', $message);
	$message = str_ireplace(array('puissance consommée', 'puissance consommee'), 'puissance', $message);
	$message = str_ireplace(array('diana'), 'yanna', $message);
	$message = str_ireplace(array('direction'), 'cap', $message);
	$message = str_ireplace(array('œil'), 'oeil', $message);

	// ------------------------- GESTION DES OBJETS AFFECTES D'OFFICE A LA LOCALISATION 'Salon' -----------------------
	if (strpos($message, 'salon') === false) {
		str_ireplace(array('entrée', 'entree', 'bureau', 'Salle à Manger', 'séjour', 'cuisine', 'couloir', 'booster', 'lave vaisselle', 'plaque induction', 'micro onde', 'informatique', 'retroprojecteur', 'réfrigérateur'), '', $message, $count);
		if ($count > 0) {
			$message = "$message du salon";
		}
	}

	// ------------------------- GESTION DES OBJETS AFFECTES D'OFFICE A LA LOCALISATION 'Rez-de-Chaussée' -----------------------
	if (strpos($message, 'Rez-de-Chaussée') === false) {
		str_ireplace(array('lave linge'), '', $message, $count);
		if ($count > 0) {
			$message = "$message du Rez-de-Chaussée";
		}
	}
	// ------------------------- GESTION DES OBJETS AFFECTES D'OFFICE A LA LOCALISATION 'Extérieur' -----------------------
	if (strpos($message, 'extérieur') === false) {
		str_ireplace(array('compresseur', 'piscine', 'vent', 'rafale', 'pression'), '', $message, $count);
		if ($count > 0) {
			$message = "$message de l_ extérieur";
		}
	}

	// ------------------------- GESTION DES OBJETS AFFECTES D'OFFICE A LA LOCALISATION 'Maison' -----------------------
	if (strpos($message, 'Maison') === false) {
		str_ireplace(array('alarme'), '', $message, $count);
		if ($count > 0) {
			$message = "$message de la Maison";
		}
	}

	mg::messageT('', "! Message nettoyé : '$message'");
	return $message;
}

/*/*******************************************************************************************************************/
/******************************************** TRANSPO TXT DES UNITES *************************************************/
/*********************************************************************************************************************/
function transpoUnite($unite) {
	$unite = trim($unite);
	if ($unite == '°C') { return '° Celsius';}
	else if ($unite == 'Lux') { return 'Luxe';}
	else if ($unite == 'A') { return 'Ampère';}
	else if ($unite == 'W') { return 'Watt';}
	else if ($unite == 'kWh') { return 'KiloWatt Heure';}
	else if ($unite == 'V') { return 'Volt';}
	else if ($unite == '°') { return 'Degré';}
	else if ($unite == 'Km/h') { return 'Kilomètre heure';}
	else if ($unite == 'hP') { return 'hecto pascal';}
	else { return $unite;}
}

/*********************************************************************************************************************/
/*************************************************** ENVOI DES REPONSES **********************************************/
/*********************************************************************************************************************/
function g_setReponse($message) {
global $PUSHBULLET, $TELEGRAM, $org, $expediteur, $index, $silencieux, $infReponse;

	// Repose des remplacements du nettoyage
	$message = str_replace('l_ ', 'l\'', $message);
	$message = str_replace('d_ ', 'd\'', $message);
	$message = str_replace('.', ',', $message);

	mg::setVar('interactReponse', $message);

	// PUSHBULLET
	if ($org == 'PUSHBULLET') {
		mg::setCmd($PUSHBULLET, '', $message);

	// TELEGRAM
	} elseif ($org == 'TELEGRAM') {
		mg::setCmd($TELEGRAM, '', $message);

	// GOOGLECAST ???????????????????
	} elseif ($org == 'GOOGLECAST') {
		mg::GOOGLECAST('TTS', $message);

	// JPI_VOCAL
	} elseif ($org == 'JPI_INTERACTION' || ($org == 'JEEDOM'&& !$silencieux)) {
		// correction de prononciation
//		$message = str_replace('est', 'é', $message);
		 mg::JPI('TTS', $message , -1);

	// JPI_SMS
	} elseif ($org == 'JPI_SMS') {
		mg::JPI('SMS', $message, $expediteur);
	}

	mg::messageT('', "! Envoi à $org de '$index - $message'");
}

/*********************************************************************************************************************/
/*************************************************** TRANSPO LIBELLE ETAT ********************************************/
/*********************************************************************************************************************/
function libelleEtat($objet, $etat, $subType, $unite) {
	global $regexInfo;

	 mg::message('', "_libEtat => objet : '$objet', etat : '$etat', subType : '$subType', unité: '$unite'");

	$ret = "à " . intval($etat) . ($unite ? " $unite" : " %");

	if (strpos($objet, 'lampe') !== false) {
		if ( $etat == 99) { $ret = 'allumée'; } elseif ( $etat == 0) { $ret = 'éteinte'; }

	} elseif (strpos($objet, 'porte') !== false || strpos($objet, 'fenêtre') !== false) {
		if ( $etat > 0) { $ret = 'ouverte'; } elseif ( $etat == 0) { $ret = 'fermée'; }

	} elseif (strpos($objet, 'volet') !== false) {
		if ( $etat == 99) { $ret = 'Ouvert'; } elseif ( $etat == 0) { $ret = 'Fermé'; }

	} else if ($subType == 'numeric') {
		if ( $etat == 99) { $ret = 'en route'; } elseif ( $etat == 0) { $ret = 'arrété'; }

	} else if ($subType == 'binary' || $subType == 'other') {
		if ( $etat > 0) { $ret = 'en route'; } elseif ( $etat == 0) { $ret = 'arrété'; }

	} else if ($subType == 'string') {
		if (strpos($etat, 'HG') !== false) { $ret = ' : Hors Gel'; }
		if (strpos($etat, 'Eco') !== false) { $ret = ' : Economique'; }
		if (strpos($etat, 'Confort') !== false) { $ret = ' : Confort'; }
	}
	else {
		preg_match("/($regexInfo)/ui", $objet, $found);
		if (@iconv_strlen($found[0]) > 1) {
			$ret = "de $etat " . transpoUnite($unite);
		}
	}
	return $ret;
}

/*********************************************************************************************************************/
/****************************************** RECHERCHE L'ETAT D'UN COMMANDE ACTION ************************************/
/*********************************************************************************************************************/
function getEtatId($typeCmd, $cmdID, $nomCmd, &$subType, &$unite) {
	$values = array();
	// Equipement virtuel
	if ($typeCmd == 'virtual') {
		$sql =	"SELECT id, subType, unite FROM `cmd`
				WHERE `eqLogic_id` = '$cmdID' AND lower(name) REGEXP lower('$nomCmd.*Etat')";
	// Equipement physique
	} else {
		$sql =	"SELECT id, subType, unite FROM `cmd`
				WHERE `eqLogic_id` = '$cmdID' AND lower(name) REGEXP lower('Etat')";
	}

	$resultSql = DB::Prepare($sql, $values, DB::FETCH_TYPE_ALL);
	$valInfo = mg::getCmd($resultSql[0]['id']);
	$etatID = $resultSql[0]['id'];
	$subType = $resultSql[0]['subType'];
	$unite = $resultSql[0]['unite'];

	mg::message('', "$sql");
	mg::message('', print_r($resultSql, true));
	mg::message('', "getEtatId => cmdID : $cmdID - subType : $subType - etatID : $etatID - valInfo : $valInfo - unite - $unite");

	return $valInfo;
}

/*********************************************************************************************************************/
/************************************* RECHERCHE DE L'EQUIPEMENT VIRTUEL D'UNE ACTION ********************************/
/*********************************************************************************************************************/
function getEqVirtuel(&$r) {

	// ECLAIRAGE
	if ($r['equipVirtuel'] == '') {
		$regex = "(Lampe|(é|e)clairage|ambiance|lumi(è|e)?|luminosité)(\s|$)";
		preg_match("/$regex/ui", $r['message'], $found);
		if (@iconv_strlen($found[0]) > 1) {
			$r['equipVirtuel'] = 'Eclairages';
			$r['objet'] = trim($found[0]);
		}
	}
	// OUVERTURES
	if ($r['equipVirtuel'] == '') {
		$regex = "(porte(s)?|volet(s)?|fenêtre|rideau(x)?|store(s)?)(\s|$)";
		preg_match("/$regex/ui", $r['message'], $found);
		if (@iconv_strlen($found[0]) > 1) {
			$r['equipVirtuel'] = 'Ouvertures';
			$r['objet'] = trim($found[0]);
		}
	}
	// MOUVEMENTS
	if ($r['equipVirtuel'] == '') {
		$regex = "(Mouvement(s)?)(\s|$)";
		preg_match("/$regex/ui", $r['message'], $found);
		if (@iconv_strlen($found[0]) > 1) {
			$r['equipVirtuel'] = 'Mouvements';
			$r['objet'] = trim($found[0]);
		}
	}
	// TEMPERATURES
	if ($r['equipVirtuel'] == '') {
		$regex = "(Chauffage(s)?|consigne|température|vent|rafales|pression|cap)(\s|$)";
		preg_match("/$regex/ui", $r['message'], $found);
		if (@iconv_strlen($found[0]) > 1) {
			$r['equipVirtuel'] = 'Températures';
			$r['objet'] = trim($found[0]);
		}
	}
	if ($r['equipVirtuel'] == '') {
		$regex = "(alarme|sirène|alerte|périmétrique|(lave linge)|(DD cinéma)|(Ecran cinéma))(\s|$)";
		preg_match("/$regex/ui", $r['message'], $found);
		if (@iconv_strlen($found[0]) > 1) {
			$r['equipVirtuel'] = 'Alarme';
			$r['objet'] = trim($found[0]);
		}
	}
	// RESUME
	if ($r['equipVirtuel'] == '' && $r['objet'] == '') {
		$regex = "(Mouvement|Température(s)?|Humidité|lumière(s)?|luminosité|mouvement|porte)(\s|$)";
		preg_match("/$regex/ui", $r['message'], $found);
		if (@iconv_strlen($found[0]) > 1)
		{
			$r['equipVirtuel'] = 'Résumé';
			$r['objet'] = trim($found[0]);
		}
	}
}

/*********************************************************************************************************************/
/*************************************** RECHERCHE DE LA COMMANDE ACTION DANS L'ACTION *******************************/
/*********************************************************************************************************************/
function getCmdAction(&$r) {
	global $regexOn, $regexOff, $regexSlider;

	if (!$r['cmd']) {
			// Recherche mots clefs indéterminé du slider
		$regexSlider0 = "(ambiance|Slider|r(è|e)gle(s|r)?|met(s|tre)?)(\s|$)";
		preg_match("/$regexSlider0/ui", $r['message'], $found);
		if (@iconv_strlen($found[0]) > 1) {
			$r['typeCmd'] = 'action';
			$r['cmd'] = 'Slider';
			$r['action'] = trim($found[0]);
		}
			// Recherche mots clefs montant
		$regexOn0 = "(monte(r|s)?|ouvre?)(\s|$)";
		preg_match("/$regexOn0/ui", $r['message'], $found);
		if (@iconv_strlen($found[0]) > 1) {
			$r['typeCmd'] = 'action';
			$r['cmd'] = 'Slider|on';
			$r['valSlider'] = '99';
			$r['action'] = trim($found[0]);
		}
			// Recherche mots clefs descendant
		$regexOff0 = "(descend(re)?|ferme(r|s)?|baisse(r)?)(\s|$)";
		preg_match("/$regexOff0/ui", $r['message'], $found);
		if (@iconv_strlen($found[0]) > 1) {
			$r['typeCmd'] = 'action';
			$r['cmd'] = 'Slider|off';
			$r['valSlider'] = '0';
			$r['action'] = trim($found[0]);
		}
		// Lecture de la valeur du slider
		$regex = "([0-9]{1,3}).{1,}";
		preg_match('/'.$regex.'/ui', $r['message'], $found);
		if (@iconv_strlen($found[0]) >= 1) {
			$r['valSlider']	= trim($found[0]);
			$r['typeCmd'] = 'action';
			$r['cmd'] = 'Slider';
		}
	}
	// ON
	if (!$r['cmd']) {
		preg_match("/($regexOn)/ui", $r['message'], $found);
		if (@iconv_strlen($found[0]) > 1) {
			$r['typeCmd'] = 'action';
			$r['cmd'] = 'On';
			$r['action'] = trim($found[0]);
			$r['valSlider'] = 99;
		}
	}
	// OFF
	if (!$r['cmd']) {
		preg_match("/($regexOff)/ui", $r['message'], $found);
		if (@iconv_strlen($found[0]) > 1) {
			$r['typeCmd'] = 'action';
			$r['cmd'] = 'Off';
			$r['action'] = trim($found[0]);
			$r['valSlider'] = 0;
		}
	}
}

/*********************************************************************************************************************/
/*************************************** RECHERCHE D'UNE COMMANDE INFO DANS L'ACTION *********************************/
/*********************************************************************************************************************/
function getCmdInfo(&$r) {
	global $regexInfo;

	if (!$r['cmd']) {
		$regex = "(quel(le)?(s)\s?(est|sont)?)|((dis|donne)\s?(moi)?)";
		preg_match("/($regex)/ui", $r['message'], $found);
		if (@iconv_strlen($found[0]) > 1) {
			$r['typeCmd'] = 'info';
			$r['action'] = trim($found[0]);
		}

		preg_match("/($regexInfo)/ui", $r['message'], $found);
		if (@iconv_strlen($found[0]) > 1) {
			$r['typeCmd'] = 'info';
			$r['cmd'] = trim($found[0]);
		} else { $r['cmd'] = 'Etat'; }

		// exceptions de libellé pour l'état d'une commande
		if ($r['objet'] == 'porte') { $r['cmd'] = 'ouverture'; }
		if ($r['objet'] == 'fenêtre') { $r['cmd'] = 'ouverture'; }
	}
}

/*********************************************************************************************************************/
/***************************************** RECHERCHE DES LOCALISATIONS DANS L'ACTION *********************************/
/*********************************************************************************************************************/
function getLocalisations(&$r) {
	$values = array();
	// Génération automatique du regex sur la liste des 'Objets Parent' des équipements
	$regex = '';
	$sql = "SELECT name, isVisible FROM `object` where name NOT REGEXP 'Sys'";
	$result = DB::Prepare($sql, (array)$values, DB::FETCH_TYPE_ALL);
	for($i=0; $i<count($result); $i++) {
		if ($result[$i]['isVisible'] ==1) { $regex .= $result[$i]['name'] .	 '|'; }
	}
	$regex = '(' . trim($regex, '|') . ')';

	// Recherche localisation
	$regex = "(Salon|chambre|rez-de-chaussée|Etage|Extérieur|Maison)";
	preg_match("/$regex/ui", $r['message'], $found);
	if (@iconv_strlen($found[0]) > 1) {
		$r['localisation'] = trim($found[0]);
	}

	// Recherche localisation complémentaire
	$regex = "(séjour|cuisine|salle à manger|bureau|couloir|entrée|sud|ouest)(\s|$)";
	preg_match("/$regex/ui", $r['message'], $found);
	if (@iconv_strlen($found[0]) > 1) {
		$r['localisation2'] = trim($found[0]);
	}
}

/*********************************************************************************************************************/
/***************************************** RECHERCHE DE L'OBJET DANS L'ACTION ****************************************/
/*********************************************************************************************************************/
function getObjet(&$r) {
	$regex = "(lampe générale|oeil|thermomètre|booster|lave vaisselle|plaque induction|micro onde|informatique|retroprojecteur|réfrigérateur|congélateur)(\s|$)";
	preg_match("/$regex/ui", $r['message'], $found);
	if (@iconv_strlen($found[0]) > 1) {
		$r['objet'] = trim($found[0]);
	}
}

/*********************************************************************************************************************/
/******************************************** SET DE DONNEES POUR LE DEBUG *******************************************/
/*********************************************************************************************************************/
function setDebug() {
	$messages = array(
	"donne moi la température du salon et puis donne moi la température extérieure ensuite quel est la consommation de la lampe du bureau après donne moi la luminosité de de l'oeil de la cuisine et finalement donne moi l'humidité du salon monte le volet du bureau allume la lumière du séjour allume le booster",

	"quel est l'état de la lampe du séjour",
	"quelle est la puissance de la lampe du bureau",
	"donne moi la consommation de la lampe du séjour",
	 );
	return $messages;
}

?>

Merci, je vais essayer ça.

Bonjour

Merci pour le partage, ca m’intéresse aussi

dans le scenario, tu mets juste le message en déclencheur ?

mon jeedom n’a pas la class « mg »

Salut,
Tu es toujours en V3?

salut, oui, le script ne fonctionne qu’en v4 ?

Je ne sais pas dire, je n’ai pas eu encore le temps de tester.
C’est juste une piste que j’évoquais.

  • La class ‹ mg › est une classe perso, mais j’y fait peu appel dans ce script et le nom des fonctions est assez transparent pour que chacun puisse la transposer dans son propre environnement (getVar, setCmd, message on voit tout de suite ce que c’est :slight_smile:

  • Pour les déclencheurs il y en a autant que de cause, donc JPI, telegram, sms, pushbullet, … sevront utiliser un déclencheur

  • C’est développé sur la V4, mais de toutes manière ce moteur n’est pas lié à la version de Jeedom dans la mesure à le dessin de la BdD ne change pas

PS : je travaille actuellement à la génération des regex en automatique pour faciliter l’usage de ce script … j’y travaille :slight_smile:

la classe « mg » est quand même appelée 47 fois dans le script :slight_smile:

oui :slight_smile: pour 4 commandes getTag, getCmd, setCmd, Message … pas très compliqué à transposé au vu du reste, non ?

Comme je l’ai déjà dit, ce n’est pas un plugin, donc réservé aux fervents pratiquants du PHP !!!

Je n’ai mis le code ici que à la demande de @mich0111