Commande SOMFY TAHOMA avec l’API locale

Bonjour,
J’essai désespérément de créer le Token d’authentification pour piloter ma « Tahoma Switch ». Je suis pourtant la procédure, mais je dois louper quelque chose :face_with_open_eyes_and_hand_over_mouth:

Peux-tu m’aiguiller sur la marche à suivre STP?

Merci d’avance

1 « J'aime »

Il faut procéder pas à pas en suivant la documentation officielle

  1. Login

Il faut disposer des identifiants du compte Somfy (email / mot de passe), à remplacer dans la commande ci-dessous

curl -v "https://ha101-1.overkiz.com/enduser-mobile-web/enduserAPI/login" --header "Content-Type: application/x-www-form-urlencoded" --data-urlencode "userId=xxx@domaine.fr" --data-urlencode "userPassword=xxxxx"

La réponse doit être
{"success":true,"roles":[{"name":"ENDUSER"}]}

Il faut récupérer le cookie, qui est visible dans la réponse affichée par curl avec le paramètre -v sur la ligne « Set-Cookie: JSESSIONID=XXXXXXXXX; Path=/enduser-mobile-web; Secure; HttpOnly; SameSite=None »

  1. Récupération du token

On doit disposer de l’identifiant de la box Tahoma (appelé « PIN », de la forme 1234-5678-9012) et lancer une deuxième commande curl. Remplacer les valeurs du « PIN » et du cookie (récupéré à l’étape précédente):

curl "https://ha101-1.overkiz.com/enduser-mobile-web/enduserAPI/config/1234-5678-9012/local/tokens/generate" --header "Cookie: JSESSIONID=XXXXXXXXX"

Dans la réponse JSON, on récupère la valeur du token

  1. Activation du token

Lancer une dernière commande curl pour activer le token. Remplacer l’id de la box, la valeur du token issue de l’étape précédente. Il est possible de donner un nom au nouveau token (ici, « Mon Token »)

curl "https://ha101-1.overkiz.com/enduser-mobile-web/enduserAPI/config/1234-5678-9012/local/tokens" --header "Content-Type: application/json" --header "Cookie: JSESSIONID=XXXXXXXXX" --data '{"label": "Mon Token","token": "xxxxxxxxxxxx","scope": "devmode"}'
  1. Utilisation
    Le token peut ensuite être utilisé pour lancer les commandes via l’API locale.
    C’est n’est pas 100% clair, mais il semble que le token n’expire normalement jamais, mais qu’il est parfois « invalidé » par une mise à jour de la box. Il faut alors relancer toutes les étapes précédentes pour obtenir un nouveau token.

Voici un autre exemple en PowerShell:

[System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true} 

$pin = "1234-5678-9012" # remplacer par le vrai "PIN" de la box Tahoma
$cloud = "ha101-1.overkiz.com"

Invoke-WebRequest "https://$cloud/enduser-mobile-web/enduserAPI/login" `
   -Method post -ContentType "application/x-www-form-urlencoded" `
   -Body 'userId=xxxxx@domaine.fr&userPassword=************' -SessionVariable "sess"

$r = Invoke-RestMethod "https://$cloud/enduser-mobile-web/enduserAPI/config/$pin/local/tokens/generate" `
   -Method Get -ContentType "application/json" `
   -WebSession $sess 

Write-Host "Token = $($r.token)"
  
Invoke-WebRequest "https://$cloud/enduser-mobile-web/enduserAPI/config/$pin/local/tokens" `
   -Method Post -ContentType "application/json" `
   -WebSession $sess `
   -Body "{""label"":""Mon token"", ""token"":""$($r.token)"", ""scope"":""devmode""}"

K.

Merci pour ta réponse!
Je suis désolé, je n’avais pas donné suffisamment d’infos au départ.

Je suis en train de coder en PHP une fonction qui permettra de se « Loguer » ou « ReLoguer » Automatiquement, par une simple action.

Je vous partagerai si vous le souhaitez le code, une fois fini :wink:

En attendant, j’ai pu avancer un peu car ton code m’a ouvert l’esprit avec l’option -v (Verbose).

:pray:t2:

Pas de souci, ça servira à d’autres :slight_smile:

Le point important, c’est de récupérer le cookie JSESSIONID après l’authentification et de le réutiliser pour les appels suivants.

Il ne semble pas y avoir de méthode pour « ré-activer » un token expiré, on ne peut qu’en créer un nouveau. C’est cohérent avec l’information non confirmée que le token n’expire jamais.

Il est possible de lister les tokens actifs:

curl "https://ha101-1.overkiz.com/enduser-mobile-web/enduserAPI/config/1234-5678-9012/local/tokens/devmode" --header "Cookie: JSESSIONID=XXXXXXXXXXXXXXXX"

Et de supprimer un token: remplacer UUIDTOKEN par l’id tu token renvoyé par la commande précédente:

curl -X DELETE "https://ha101-1.overkiz.com/enduser-mobile-web/enduserAPI/config/1234-5678-9012/local/tokens/UUIDTOKEN" --header "Cookie: JSESSIONID=XXXXXXXXXXXXXXXX"

K.

Je Pêche … Pas moins de Valider le token :hot_face:

Voici le morceau de code, si quelqu’un à une idée:

	$url = "https://ha101-1.overkiz.com/enduser-mobile-web/enduserAPI/config/" . $Pin_code . "/local/tokens";
	
	$data = array("label" => "Jeedom_Token","token" => $Token_session,"scope" => "devmode");
	$postData = json_encode($data);
	
	$ch = curl_init();

	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($ch, CURLOPT_HEADER, true);
//	curl_setopt($ch, CURLOPT_VERBOSE, true);
	curl_setopt($ch, CURLOPT_POST, 1);
	curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
	curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));

	$output = curl_exec($ch);
	$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

	curl_close($ch);

Sachant que:
$Pin_code = Le Pin code (ex:1234-5678-9012)
$Token_session = Le Token reçu lors de la Generation

L’erreur affichée: {« errorCode »:« RESOURCE_ACCESS_DENIED »,« error »:« Not authenticated »}

Merci d’avance pour vos lumières :bulb:

L’erreur indique que l’API pense que tu n’es pas authentifié.

Sauf si ton code est incomplet ici, je ne vois pas où tu passes le cookie JSESSIONID (via CURLOPT_COOKIE, ou CURLOPT_COOKIEFILE) lors de ton POST sur /local/tokens

Le cookie est obligatoire pour tous les appels suivants /login.

Exemple (pour lister les tokens existants via un GET sur /local/tokens)

        // Login
        $url = "https://ha101-1.overkiz.com/enduser-mobile-web/enduserAPI/login";
        $data = array("userId" => "monlogin@domaine.fr", "userPassword" => "M0nPassw0rd!");

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
        curl_setopt($ch, CURLOPT_COOKIEFILE, "");
        $output = curl_exec($ch);
        $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        // On recupere les cookies renvoyes par l'API de login
        preg_match_all('|Set-Cookie: (.*);|U', $output, $matches);
        $cookies = implode('; ', $matches[1]);

        // Liste les tokens deja enregistres
        $url = "https://ha101-1.overkiz.com/enduser-mobile-web/enduserAPI/config/1234-5678-9012/local/tokens/devmode";
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_COOKIE, $cookies); // On passe les cookies d'authentification
        $output = curl_exec($ch);
        $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        print($output);

Resultat:

[{"label":"Mon Token","gatewayId":"1234-5678-9012,"gatewayCreationTime":1680083286000,"uuid":"00000000-0000-0000-0000-000000000000","scope":"devmode"}]

K.

Merci pour ton aide, c’était bien le Cookie qui manquait :blush: :wink:

Voici donc la V1 de mon code si ça peut aider quelqu’un…
Je créerai un nouveau sujet quand je serais en V2 car on est un peu hors sujet ici :face_with_open_eyes_and_hand_over_mouth: :wink:

Merci encore, au plaisir.

<?php
$userId = "votre ID";
$userPassword = "Votre Mot de Passe";
$Pin_code = "1234-5678-9100";

//LOGIN
tahoma_Logon($userId, $userPassword);
////print_r( $JSESSIONID_cookies ); /**CHECK Cookie ID Return**/

//TOKEN GENERATOR
get_tahoma_token($Pin_code);
////echo "token_session::" . $Token_session; /**CHECK Token Return**/

//TOKEN VALIDATION
validat_tahoma_token($Pin_code);

//GET AVAILABLE TOKENS LIST
//get_tahoma_token_LIST($Pin_code);

//DELETE TOKEN
//Delete_tahoma_token($Pin_code,"Votre uuid");

//************************************************************************************************************//

//LOGIN
function tahoma_Logon($userId, $userPassword) {
	
	global $JSESSIONID_cookies;
	
//	log::add('tahoma', 'debug', "logon with " . $userId);

	$url = "https://ha101-1.overkiz.com/enduser-mobile-web/enduserAPI/login";

	$postData = sprintf(
		"userId=%s&userPassword=%s",
		urlencode($userId),
		urlencode($userPassword)
	);
	
	$ch = curl_init();

	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($ch, CURLOPT_HEADER, true);
//	curl_setopt($ch, CURLOPT_VERBOSE, true);

	curl_setopt($ch, CURLOPT_POST, true);
	curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
	curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));

	$output = curl_exec($ch);
	$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

	curl_close($ch);

	if (($output == "") || ($httpcode == 401)) {
//		log::add('tahoma', 'debug', "new cookie - logon: ko: " . $httpcode);
//		log::add('tahoma', 'debug', "return: " . print_r($output, true));
		echo "new cookie - logon: ko: " . $httpcode . "<br>"; /**DEBUG**/
		echo "return: " . print_r($output, true) . "<br>"; /**DEBUG**/
		
		return false;
	}

	
//	echo "Output tahoma_Logon: ".$output."<br>"; /**DEBUG**/
	
	//EXTRACT COOKIE VALUE
	preg_match_all('/^Set-Cookie:\s*([^;]*)/mi',$output,  $match_found);
	parse_str($match_found[1][0],  $extract_JSESSIONID);
	$JSESSIONID_cookies = $extract_JSESSIONID['JSESSIONID'];

	
//	log::add('tahoma', 'debug', "new cookie:" .$JSESSIONID_cookies. " - logon: OK: " . $httpcode);
	echo "new cookie:" .$JSESSIONID_cookies. " - logon: OK: " . $httpcode . "<br>"; /**DEBUG**/

	return true;
	
}


//TOKEN GENERATOR
function get_tahoma_token($Pin_code) {

	global $JSESSIONID_cookies;
	global $Token_session;

//	echo "JSESSIONID_cookies: " . $JSESSIONID_cookies . "<br>"; /**DEBUG**/
	
//	log::add('tahoma', 'debug', "logon with " . $userId . " and cookie " . $JSESSIONID_cookies);

	$url = "https://ha101-1.overkiz.com/enduser-mobile-web/enduserAPI/config/" . $Pin_code . "/local/tokens/generate";

	$ch = curl_init();

	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json','Cookie: JSESSIONID='.$JSESSIONID_cookies));

	$output = curl_exec($ch);
	$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

	curl_close($ch);

//echo "Output get_tahoma_token: ".$output . "<br>"; /**DEBUG**/
	
	if (($output == "") || ($httpcode == 401)) {
//		log::add('tahoma', 'debug', "new Token - logon: ko: " . $httpcode . "(" . $retour . ")");
//		log::add('tahoma', 'debug', "return: " . print_r($output, true));
		return false;
	}

	$token = json_decode($output);
	$Token_session = $token->{'token'};
	
//	log::add('tahoma', 'debug', "new Token:" . $Token_session . " - logon: ok: " . $httpcode);
	echo "new Token:" . $Token_session . " - logon: OK: " . $httpcode . "<br>"; /**DEBUG**/

	return true;	
	
}

//TOKEN VALIDATION
function validat_tahoma_token($Pin_code) {

	global $JSESSIONID_cookies;
	global $Token_session;

//	echo "JSESSIONID_cookies: " . $JSESSIONID_cookies . "<br>"; /**DEBUG**/
//	echo "Token_session: " . $Token_session . "<br>"; /**DEBUG**/

	
//	log::add('tahoma', 'debug', "logon with " . $userId . " and cookie " . $JSESSIONID_cookies . " and Token " . $Token_session);
	
	$url = "https://ha101-1.overkiz.com/enduser-mobile-web/enduserAPI/config/" . $Pin_code . "/local/tokens";
	
	$data = array("label" => "Jeedom_Token","token" => $Token_session,"scope" => "devmode");
	$postData = json_encode($data);
		
	$ch = curl_init();

	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($ch, CURLOPT_HEADER, true);
//	curl_setopt($ch, CURLOPT_VERBOSE, true);
	curl_setopt($ch, CURLOPT_POST, 1);
	curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
	curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json','Cookie: JSESSIONID='.$JSESSIONID_cookies));

	$output = curl_exec($ch);
	$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

	curl_close($ch);

//echo "Output validat_tahoma_token: ".$output . "<br>"; /**DEBUG**/
	
	if (($output == "") || ($httpcode == 401)) {
//		log::add('tahoma', 'debug', "new Validat Tahoma Token - logon: ko: " . $httpcode . "(" . $retour . ")");
//		log::add('tahoma', 'debug', "return: " . print_r($output, true));
		return false;
	}
	
//	log::add('tahoma', 'debug', "new Token - logon: ok: " . $httpcode);
//	echo "new Token:" . $Token_session . " - logon: OK: " . $httpcode . "<br>"; /**DEBUG**/

	return true;	
	
}

//GET AVAILABLE TOKENS LIST
function get_tahoma_token_LIST($Pin_code) {

	global $JSESSIONID_cookies;
	global $Token_session;

//	echo "JSESSIONID_cookies: " . $JSESSIONID_cookies . "<br>"; /**DEBUG**/
//	echo "Token_session: " . $Token_session . "<br>"; /**DEBUG**/

	
//	log::add('tahoma', 'debug', "logon with " . $userId . " and cookie " . $JSESSIONID_cookies . " and Token " . $Token_session);
	
	$url = "https://ha101-1.overkiz.com/enduser-mobile-web/enduserAPI/config/" . $Pin_code . "/local/tokens/devmode";
			
	$ch = curl_init();

	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//	curl_setopt($ch, CURLOPT_HEADER, true);
//	curl_setopt($ch, CURLOPT_VERBOSE, true);
	curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json','Cookie: JSESSIONID='.$JSESSIONID_cookies));

	$output = curl_exec($ch);
	$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

	curl_close($ch);

//echo "Output get_tahoma_token: ".$output . "<br>"; /**DEBUG**/
	
	if (($output == "") || ($httpcode == 401)) {
//		log::add('tahoma', 'debug', "new Token - logon: ko: " . $httpcode . "(" . $retour . ")");
//		log::add('tahoma', 'debug', "return: " . print_r($output, true));
		return $output;
	}
	
	$data = json_decode($output);
	

	print "<pre>";	/**DEBUG**/
	print_r($data);	/**DEBUG**/
	print "</pre>";	/**DEBUG**/
	
	
//	log::add('tahoma', 'debug', "new Token - logon: ok: " . $httpcode);
//	echo "new Token:" . $Token_session . " - logon: OK: " . $httpcode . "<br>"; /**DEBUG**/

	return $data;	
	
}



//DELETE TOKEN
function Delete_tahoma_token($Pin_code,$uuid) {

	global $JSESSIONID_cookies;
	global $Token_session;

//	echo "JSESSIONID_cookies: " . $JSESSIONID_cookies . "<br>"; /**DEBUG**/
//	echo "Token_session: " . $Token_session . "<br>"; /**DEBUG**/

	
//	log::add('tahoma', 'debug', "logon with " . $userId . " and cookie " . $JSESSIONID_cookies . " and Token " . $Token_session);
	
	$url = "https://ha101-1.overkiz.com/enduser-mobile-web/enduserAPI/config/" . $Pin_code . "/local/tokens/".$uuid;
			
	$ch = curl_init();

	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");

	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//	curl_setopt($ch, CURLOPT_HEADER, true);
//	curl_setopt($ch, CURLOPT_VERBOSE, true);
	curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json','Cookie: JSESSIONID='.$JSESSIONID_cookies));

	$output = curl_exec($ch);
	$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

	curl_close($ch);

//echo "Output get_tahoma_token: ".$output . "<br>"; /**DEBUG**/
	
	if (($output == "") || ($httpcode == 401)) {
//		log::add('tahoma', 'debug', "new Token - logon: ko: " . $httpcode . "(" . $retour . ")");
//		log::add('tahoma', 'debug', "return: " . print_r($output, true));
		return $output;
	}
		
	
//	log::add('tahoma', 'debug', "Delete Token:" . $uuid . " - logon: ok: " . $httpcode);
	echo "Delete Token:" . $uuid . " - logon: OK: " . $httpcode . "<br>"; /**DEBUG**/

	return true;	
	
}
?>

Hello,

j’ai moi aussi testé l’API locale.
Globalement ca fonctionne.

Par contre, le soucis est qu’il semble ajourd’hui manquer des fonctionnalités disponible via l’ancienne API « Cloud », par exemple les scénario, l’accès aux commandes reliées à la Tahoma, etc… ce qui empecherait de basculer totalement dessus.

1 « J'aime »

Hello World,

Bon maintenant que le Login est fait, je suis en mode « Codage des fonctions Local » et je pêche sur la base…

Pour test, Juste une fonction simple d’appel de la Version de l’API me retourne ça, avec le code ci dessous:
Could not resolve host: gateway-2034-2257-8930.local
Output Info_Command:
Output httpcode: 0

Il doit manquer quelque chose mais je ne trouve pas quoi :scream: :hot_face:

Une idée? :pray:

function Info_Command($Pin_code,$ID_Command) {

	global $Token_session;
	$url = "https://gateway-2034-2257-8930.local:8443/enduser-mobile-web/1/enduserAPI/apiVersion";
  
	$ch = curl_init();

	curl_setopt($ch, CURLOPT_URL, $url);
	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($ch, CURLOPT_HEADER, true);
	curl_setopt($ch, CURLOPT_VERBOSE, true);
	curl_setopt($ch, CURLOPT_HTTPGET, true);
	curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));	
	
	$output = curl_exec($ch);
	print curl_error($ch) . "<br>";

	$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

	curl_close($ch);

echo "Output Info_Command: ".$output . "<br>"; /**DEBUG**/
echo "Output httpcode: ".$httpcode; /**DEBUG**/
	
	if (($output == "") || ($httpcode == 401)) {
		return false;
	}

	return true;	
	
}

Il y a souvent des problèmes pour la résolution mDns. Ca fait l’objet de pas mal de questions sur le github.
Tente de pinger l’URL depuis la machine où tu executes le php pour voir si la résolution fonctionne (ping gateway-1234-1234.local). Si ca ne répond pas, c’est que la résolution mDNS sur ta machine ne fonctionne pas. Si tu arrives à pinger en utilisant l’IP, c’est ca le problème.

Il semble que certains arrivent à contacter en enlevant le .local, ou autre… mais sinon le plus simple c’est d’utiliser l’IP de ta Tahoma plutot que le nom mDNS.

Personnellement, ping gateway-xxx.local sur mon PC windows marche, mais sur mon NAS Synology non ( Name or service not known). Du coup, plutot que https://gateway-xx-.local:8443, j’ai directement l’IP https://192.168.1.x:8443/enduser

Merci beaucoup pour ta réponse, effectivement pour le moment je code sur le NAS.

La grand question, c’est comment tu envoies le numéro PIN de la TAHOMA en passant directement par l’adresse IP?

:pray:t2::pray:t2::pray:t2:

Je ne comprends pas la question.
Tu as besoin du pin pour récupérer le token auprès du serveur d’autorisation central, comme tu l’as fait.
Après le pin peut servir d’URL pour joindre la tahoma sur ton réseau local. La tahoma utilise mdns pour s’annoncer comme « je m’appelle gateway-pin ». Cependant, ce mdns comme tout dns c’est juste associer un « nom » dns a une ip. Donc tu peux remplacer le nom (gateway-pin.local) par l’ ip.

Donc si tu connais l’ip de ta tahoma sur ton réseau local t’as pas besoin d’utiliser l’adresse en gateway

2 « J'aime »

Je n’ai malheureusement pas eu le temps de te remercier @johann.r:pray: :pray: :pray:
Je cherchais des complications là où il n’y en avait pas :laughing:

QUID du moment:
Je n’ai aucun retour d’info de la position du portail que j’utilise pour test, quand les demandes d’ouvertures sont réalisés avec la télécommande IO en direct.
Par contre le retour est correct en cas d’action depuis l’API (Via " /setup/devices/{deviceURL}/states " ou " /events/{listenerId}/fetch " !

Est-ce normal? Pour moi non… Le IO devant faire un retour d’info!

Y-a t’il une action non documenté a réaliser pour demander une MAJ ou une technique?

En sachant que sur l’APP SOMFY, l’info de position est également exact et immédiate.

:pray: Merci d’avance pour votre aide :pray:

Tu peux préciser :

  • Tu ouvres un listener via /events/register
  • Tu appuies sur la télécommande
  • Tu appelles /events/{listenerId}/fetch plusieurs fois, et tu n’obtiens jamais aucune info en retour c’est ca ?

Tu as bien ouvert ton listener avant d’actionner sur la télécommande ?
Si c’est ca, c’est vrai que ca ne me parait pas très logique mais peut être que le event listener ne donne des infos que sur les commandes qui sont déclenchées par la tahoma. Peut etre une question à poser sur le github si c’est ca. Faudrait que je teste chez moi.

Sinon, en contournement, je suppose que si tu rappelles /setup tu vas obtenir les info à jour telles que la tahoma les connait. Mais bon, c’est pas une très bonne pratique puisqu’ils disent explicitement de ne pas appeler /setup trop souvent… faut pas boucler dessus.

1 « J'aime »

Re, Merci pour ta réponse rapide.

Pour être plus précis:

C’est déjà fait :wink:

C’est exactement ça, avec un Refresh toutes les minutes, 5min ou 10min, aucune info!

Par contre si je fais:

  • Application SOMFY Fermée
  • Ouverture du portail avec la télécommande
  • Ouverture de l’application SOMFY
  • Appel de /events/{listenerId}/fetch
    → Retour d’info correct
  • Quitter l’application SOMFY
  • Fermeture du portail
  • Ouverture de l’application SOMFY
  • Appel de /events/{listenerId}/fetch
    → Retour d’info correct

Voici mon code:

//REGISTER LISTENER
function Register_Listener() {

	global $Token_session;
	global $Tahoma_ip_address;
	global $Register_Listener_ID;
	
	log::add('script', 'debug', "Register_Listener - logon with Token " . $Token_session);

  	$url = "https://" .$Tahoma_ip_address. "/enduser-mobile-web/1/enduserAPI/events/register";

    $ch = curl_init();

	curl_setopt($ch, CURLOPT_URL, $url);

	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json','Authorization: Bearer '.$Token_session,'Content-Length: 0'));
	curl_setopt($ch, CURLOPT_POST, 1);
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
	
	
	$output = curl_exec($ch);
	$output_error = curl_error($ch);

	if (stristr($output_error, 'SSL: no alternative certificate subject name')) {
		log::add('script', 'ERROR', "ERREUR SSL: " . $output_error);
		print curl_error($ch);
	}	
	
	$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);


	curl_close($ch);
	
	if (($output == "") || (	($httpcode != 200) && ($httpcode != 100)	)) {
		log::add('script', 'ERROR', "Register_Listener - ASK INFO ko: " . $httpcode . "(" . $output . ")");
		log::add('script', 'ERROR', "Register_Listener - return: " . print_r($output_error, true));
		return false;
	}
	
	
	$data = json_decode($output);
	$Register_Listener_ID = $data->{'id'};
		
	log::add('script', 'debug', "Register_Listener - Request ID:" . $Register_Listener_ID . " - logon: ok: " . $httpcode);


	Get_Last_Info_Event();	
	
}

//GET LAST INFO EVENT
function Get_Last_Info_Event() {

	global $Token_session;
	global $Tahoma_ip_address;
	global $Register_Listener_ID;
	global $Nbr_Tentative;
	
	log::add('script', 'debug', "Get_Last_Info_Event - logon with Token " . $Token_session . " ASK INFO with Register_Listener_ID: " . $Register_Listener_ID);

  	$url = "https://" .$Tahoma_ip_address. "/enduser-mobile-web/1/enduserAPI/events/" . $Register_Listener_ID ."/fetch";

	$ch = curl_init();

	curl_setopt($ch, CURLOPT_URL, $url);

	curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
	curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json','Authorization: Bearer '.$Token_session,'Content-Length: 0'));
	curl_setopt($ch, CURLOPT_POST, 1);
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
	
	
	$output = curl_exec($ch);
	$output_error = curl_error($ch);

	if (stristr($output_error, 'SSL: no alternative certificate subject name')) {
		log::add('script', 'ERROR', "ERREUR SSL: " . $output_error);
		//print curl_error($ch);
	}	
	
	$httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE);


	curl_close($ch);
	
	if (($output == "") || (	($httpcode != 200) && ($httpcode != 100)	)) {
		log::add('script', 'ERROR', "Get_Last_Info_Event: ko: " . $httpcode . "(" . $output . ")");
	}
	
	$Nbr_Tentative = $Nbr_Tentative + 1;
	
	$data = json_decode($output,TRUE);
	$ERROR_Get_Last_Info_Event = $data["error"];
  	
	if(	(	stristr($ERROR_Get_Last_Info_Event,"Unknown object")	|| stristr($output,"No registered event listener")	) and $Nbr_Tentative < 5	) {
		
		log::add('script', 'debug', "Get_Last_Info_Event - Tentative " . $Nbr_Tentative . " ASK INFO with Register_Listener_ID:" . $Register_Listener_ID);
		
		
		Register_Listener();
		
	}else if((	stristr($ERROR_Get_Last_Info_Event,"Unknown object")	|| stristr($output,"No registered event listener")	) and $Nbr_Tentative >= 5) {
		log::add('script', 'ERROR', "Get_Last_Info_Event: " . $Nbr_Tentative . "Tentatives / ko: " . $httpcode . "(" . $output_error . ")");
		log::add('script', 'ERROR', "Get_Last_Info_Event - return: " . print_r($output, true));
		
		return false;
	}else{
      
      log::add('script', 'debug', "Get_Last_Info_Event OK / ASK INFO with Register_Listener_ID:" . $Register_Listener_ID);
      
      if (empty($data)) {
        log::add('script', 'debug', "Get_Last_Info_Event OK / No Data Found to Update with Register_Listener_ID:" . $Register_Listener_ID);
      }

      foreach ($data as &$data_IO_URL) {
        $IO_Device_URL = $data_IO_URL["deviceURL"];
        $IO_Device = substr($IO_Device_URL, strrpos($IO_Device_URL, "/") + 1); //Recherche la valeur après le dernier dernier slash
        
        if ($data_IO_URL["deviceStates"][0]["name"] == "core:ManufacturerSettingsState") {
                    
          switch ($data_IO_URL["deviceStates"][0]["value"]["current_position"]) {
            case 51200:
              $current_position = 100;
              break;
            case 55303:
              $current_position = 75;
              break;
            case 54272:
              $current_position = 50;
              break;
            case 0:
              $current_position = 0;
              break;
          }
                      
            $Device_Data = Jeedom_Device_Data();
          
          foreach ($Device_Data as $row) {
            if ($row["Somfy_IO_ID"] == $IO_Device) { //Action si le numéro IO est dans la liste des périphériques demandés en parametre $ID_Commands
              Update_Jeedom_Device_state($IO_Device,$row["Chemin_Etat"],$current_position);
              break;
            }
          }        
        }else{
          log::add('script', 'debug', "Get_Last_Info_Event OK / No Data Found to Update with 'IO_Device':" . $IO_Device);

        }
      }

	}
  
	return true;		
}


//Récupère les Infos Jeedom correspondants aux $ID_Commands demandés en paramètre
function Jeedom_Device_Data() {
  global $ID_Commands;
  
  $ID_Commands_List = explode ("," , $ID_Commands); //Liste les ID des commandes dans un Array
  
  
  $Device_Data = array();
  
  foreach ($ID_Commands_List as &$ID_Command) { //Pour chaque valeur, Récupérer le Numéro IO stocké et le chemin de la commande Etat
    
    log::add('script', 'debug', "Jeedom_Device_Data - Try to get Data with 'ID_Command':" . $ID_Command);    
    
    $cmd = cmd::byId($ID_Command);
    
    if (	!empty($cmd)	) { //Vérifie si le numéro de la commande existe
      
      $HumanNameCommand_IO = $cmd->getHumanName(); //Récupére le Chemin de la Commande correspondant au Numéro $ID_Command
      $Somfy_IO_ID = $cmd->execCmd(); //Récupére le Numéro IO stocké

      $HumanNameCommand_Etat = str_replace("[I0_ID_Command]", "[Etat]", "#" . $HumanNameCommand_IO . "#"); //Transforme le Chemin de la Commande correspondant au Numéro $ID_Command en Chemin pour la commande "Etat"
      
      $Device_Data[] = array("ID_Command" => $ID_Command, "Somfy_IO_ID" => $Somfy_IO_ID, "Chemin_Etat" => $HumanNameCommand_Etat); //Création du tableau
    
      log::add('script', 'debug', "Jeedom_Device_Data - 'ID_Command':" . $ID_Command . " / 'Somfy_IO_ID':" . $Somfy_IO_ID . " / 'Chemin_Etat':" . $HumanNameCommand_Etat);
      
    }else{
      log::add('script', 'ERROR', "Jeedom_Device_Data - 'ID_Command':" . $ID_Command . " NOT FOUND");
    }

  }
  
  return $Device_Data;
}

//Mettre à jour Valeur Etat du périphérique demandé
function Update_Jeedom_Device_state($Somfy_IO_ID,$Chemin_Etat,$current_position) {
  
  cmd::byString($Chemin_Etat)->event($current_position);
  
  log::add('script', 'debug', "Update_Jeedom_Device_state - Update Command Data 'Etat': " . $Chemin_Etat . " of 'IO': " . $Somfy_IO_ID . " To: ".$current_position);
  
  return true;
}

:pray:

Si j’y pense je tenterai de tester chez moi si j’observe le meme comportement.
Mais je pense que là, il sera très difficile de répondre à notre niveau, seuls les gens de Somfy pourraient répondre.
A première vue, j’ai envie de dire que d’après ton test, la Tahoma ne récupère pas / mets pas à jour les infos automatiquement lorsqu’on agit sur un équipement avec la télécommande. Mais qu’elle doit faire cette mise à jour ou forcer d’une manière ou d’une autre lorsque tu lances l’appli, et du coup, les renvoyer dans le listener.
Par contre, pourquoi et comment… les possibilités sont nombreuses. Et ce que certains équipements n’émettent jamais d’info vers la Tahoma, ou n’en renvoient pas lorsqu’ils sont commandés par la télécommande ? Et que c’est elle qui doit les interroger, ce qu’elle fait lorsque tu ouvres l’appli ? De manière régulière, mais pas assez régulière et forcée lorsque tu ouvres l’appli ? Est ce que seulement certains équipements IO émettent vraiment d’eux meme lorsqu’ils sont activés, ou qu’il faut forcément les « pooler » régulièrement pour connaitre leur position par exemple ?
Est ce que la Tahoma recoit bien les infos, mais ne les mets pas à jour tant que l’appli n’est pas activée ? S’agit t’il d’un bug, ou d’une contrainte technique du protocole ?
Aucune idée … :frowning:

1 « J'aime »

Salut.
Voici le test que j’ai fait aujourd’hui. J’ai ouvert un listener puis regardé ce que je récupère comme Events en agissant via l’API, via l’app Tahoma, ou via une commande murale.
J’ai des velux natif IO et des micromodule izymo IO shutter.

Via l’API, j’obtiens en plus des ExecutionStateChangedEvent/CommandExecutionStateChangedEvent. Je ne les obtiens pas quand je fais la commande via l’App Tahoma. Ceci me parait logique ceci dit : ces event viennent t’informer sur la commande que tu as lancée. Si tu n’as pas lancé la commande via l’API, logique que tu ne sois pas informé de son exécution (début / fin / echec).

Je recois bien des DeviceStateChangedEvent en revanche, qui m’indiquent notamment le statut (OpenClosedState) et le %age de fermeture (ClosureState), que le lance via l’API ou via l’app tahoma.

Maintenant, en agissant en commande murale, je fais, je pense, les memes constatations que toi : je ne recois pas de mise à jour de statut sur l’API dans l’immédiat
Mais : je constate que l’App Tahoma ne se mets pas à jour en temps réel non plus ! Il faut un certain temps avant que le statut soit mis à jour sur l’app tahoma. Et, surtout, quand le statut est mis à jour sur l’app Tahoma, alors je récupère l’info également dans mon listener !
Enfin, si je lance une commande API (stop par exemple) sur un volet dont le statut a changé via une commande murale, je recois le nouveau statut avec les infos d’exécution de ma commande stop.

En gros, là où une commande via la tahoma (que ce soit via l’app, ou via l’API) va entrainer une mise à jour très rapide du statut, et la mise à dispo des infos via le listener, lorsqu’on agit avec une commande murale, c’est bien plus long, ce qui fait qu’on a pas de retour d’état immédiat.

Une différence cependant par rapport à toi : si je ferme l’app Tahoma, et que je lance un volet VELUX par commande murale, je finis quand meme, après un certain temps, par avoir le retour d’info sur le listener. Mais ca n’est pas le cas sur le micromodule shutter !! Pour le micromodule, il faut effectivement que je lance l’app pour que la mise à jour se fasse.

J’en viens à penser que :

  • quand la Tahoma a connaissance d’un nouvel état, elle le mets bien à dispo sur le listenier
  • MAIS qu’elle n’a pas forcément l’info rapidement quand ce changement d’état se fait via commande murale
  • ET EN PLUS, la mise à dispo de cette info semble dépendre de l’équipement piloté…

Ca pourrait sembler indiquer (mais là ca devient très hypothétique :)) que certains équipements « annoncent » leur changement d’état d’eux meme, alors que d’autres non s’ils sont piloté par commande murale. Et que l’app, elle, a un moyen de forcer la mise à jour de tous les statuts, ce qui les rend ensuite disponible sur l’API.

1 « J'aime »

Sujet très intéressant, a suivre.
A savoir que le mode dev est aussi dispo sur connexxon.
Bientôt la fin du mode cloud avec Somfy ? Je l’espère !

Bonjour à tous,

Ce sujet m’intéresse également.
@kimagure , @johann.r savez vous où cela en est ?

Est-il question d’un plugin jeedom pour l’accès à la tahoma via api locale dans les semaines à venir ?

Je pense que ce plugin est attendu par beaucoup de personnes (même en version payante).

Par avance, merci.

1 « J'aime »

Je n’ai pas vraiment prévu de faire un plugin malheureusement, je n’aurai pas la bande passante pour le maintenir.

D’autant plus que je n’ai actuellement qu’un seul volet Somfy IO (et un store Somfy RTS), donc pas vraiment la capacité à pouvoir tester tous les équipements supportés.

Par contre, je vois dans le market un plugin « Connexoon » en beta qui visiblement utilise lui aussi l’API locale. Je t’invite à y jeter un oeil (je vais aussi regarder de mon côté !)

K.

1 « J'aime »