Apprenez à utiliser l’API locale de Philips Hue et à l’utiliser dans un premier script Python
Tu préfères Ruby ? Dommage !
Notre dossier sur les ampoules Philips Hue :
Le 29 décembre 2018 à 10h00
10 min
next
Utiliser un produit, c'est bien. Apprendre à le contrôler, c'est mieux. Les Philips Hue sont un bon cas d'école, avec une API facilement accessible et demandant peu de compétences techniques pour en tirer parti.
Après être revenus sur la gamme de produits Hue de Signify (maison mère des luminaires Philips), sa constitution et les possibilités qu'elle offre, passons aux choses sérieuses : comment récupérer des informations sur votre installation et vos ampoules, puis les utiliser à distance en communicant avec le pont.
La société a mis en place une interface RESTful locale, qui permet d'effectuer des requêtes sans avoir à passer par une application spécifique. Un navigateur ou un simple terminal suffisent.
- Retour sur la gamme Hue de Philips et quelques applications créées par la communauté
- Apprenez à utiliser l'API locale Philips Hue et à l'utiliser dans un premier script Python
- Utilisez Python et WSGI pour monter un serveur web local et gérer vos ampoules Hue (à venir)
Trouver l'IP du pont, utiliser l'API
Commençons par la gestion la plus manuelle et directe du pont. Une fois connecté à votre réseau local, la première étape est de trouver son adresse IP. Pour cela, une ligne de commande via cURL suffit, grâce à une URL spécifique.
Pour rappel, cet outil est intégré nativement à de nombreuses distributions Linux, et les versions récentes de Windows 10. Vous pouvez également le télécharger et l'installer :
curl https://discovery.meethue.com
Si vous vous rendez sur l'URL avec un navigateur, le résultat sera également affiché. Il se présente toujours cette forme :
[{"id":"ID_du_pont","internalipaddress":"IP_du_pont"}]
Si plusieurs ponts sont sur le même réseau, ils seront tous listés. Vous devrez donc identifier celui correspondant aux produits que vous voulez contrôler. Les ponts peuvent également être découverts via d'autres biais, comme les protocoles SSDP ou mDNS.
Une fois l'IP trouvée, vous pouvez accéder à l'interface web permettant d'effectuer des requêtes, l'API Debug Tool :
http://IP_du_pont/debug/clip.html
Il se compose de quatre sections : l'URL à utiliser pour la requête, la commande à envoyer, le contenu du message, le contenu de la réponse récupérée. On peut l'utiliser pour une première requête, affichant les informations relatives au pont. Pour cela, il suffit d'envoyer une requête via la commande GET sur l'URL /api/config
:
On récupère ainsi, au format JSON, le nom du pont, son adresse MAC, son ID, son modèle, les versions de l'API utilisée et du logiciel installé, un indicateur sur le fait qu'il soit neuf ou non, etc.
Notez que l'on aurait pu obtenir le même résultat en utilisant cURL via la ligne de commande suivante :
curl IP_du_pont/api/config
Récupérer et supprimer un jeton utilisateur
Passons maintenant au niveau supérieur. Car pour effectuer des requêtes, il faut être autorisé à le faire. Que ce soit pour gérer des ampoules ou obtenir des informations précises.
On utilise donc un jeton d'authentification (token) attribué par le pont après une phase d'appairage : l'username
. Une fois créé, il est ajouté à une liste blanche. Utilisé au sein d'une requête, il permet au pont de savoir qu'il peut répondre en toute sécurité. Bien entendu, il est possible de le révoquer en le retirant de la liste blanche si vous le jugez nécessaire.
Pour l'obtenir, il faut effectuer une requête POST sur l'URL /api
, en précisant le nom de l'appareil à enregistrer dans le message envoyé. Cela passe par un objet JSON assez simple, qui peut être par exemple :
{"devicetype":"my_hue_app#nom_de_l_appareil"}
Si vous voulez effectuer cette requête via curl, il faut utiliser commande suivante. Notez que sous Windows, des caractères d'échappement sont nécessaires (première ligne), mais pas sous Linux (deuxième ligne) :
curl -X POST -d {\"devicetype\":\"my_hue_app#davtest\"} IP_du_pont/api
curl -X POST -d '{"devicetype":"my_hue_app#davtest"}' IP_du_pont/api
Normalement, vous obtiendrez une erreur sous cette forme :
[{"error":{"type":101,"address":"","description":"link button not pressed"}}]
Le pont vous répond ainsi qu'il n'était pas en mode appairage, et qu'il faut tout d'abord presser son bouton. Une fois que cela est fait, envoyez à nouveau votre requête, vous obtiendrez alors votre jeton (username):
[{"success":{"username":"votre_jeton"}}]
Mettez cette information de côté (si possible dans un espace sécurisé pour éviter qu'un tiers puisse s'en servir). Créez ensuite un second jeton avec le nom d'appareil toDelete
après avoir à nouveau appuyé sur le bouton d'appairage :
{"devicetype":"my_hue_app#toDelete"}
Cela permet d'obtenir un second utilisateur que nous pourrons ensuite supprimer. Avant cela, nous allons afficher le contenu de la liste blanche, accessible dans la configuration du pont :
URL : /api/votre_jeton/config
Commande : GET
curl -X GET IP_du_pont/api/votre_jeton/config/
Comme vous êtes identifié, vous obtiendrez bien plus d'informations que précédemment, et notamment l'élément nommé whitelist
contenant tous les jetons créés, appareils associés, dates de création et de dernier usage.
Pour supprimer un jeton, là encore une requête suffit :
URL /api/votre_jeton/config/whitelist/jeton_a_supprimer
Commande : DELETE
curl -X DELETE IP_du_pont/api/votre_jeton/config/whitelist/jeton_a_supprimer
Si tout s'est bien passé, vous obtenez une réponse sous la forme :
[{"success":"/config/whitelist/jeton_a_supprimer deleted"}]
Lister et gérer vos ampoules
Maintenant que nous disposons d'un jeton, utilisons-le pour allumer et éteindre une ampoule. Tout d'abord, nous devons récupérer les informations les concernant, chacune étant identifiée par un nombre :
URL : /api/votre_jeton/lights
Commande : GET
curl -X GET IP_du_pont/api/votre_jeton/lights
Pour chaque ampoule vous obtenez différents éléments : name
, type
, state
, capabilities
, etc. Pour le moment, le seul élément qui compte est le nombre qui définit celle sur laquelle vous voulez effectuer votre test, la 6 dans notre cas.
Si l'on souhaite l'allumer, il faut exécuter la requête suivante :
URL : /api/votre_jeton/lights/ID/state
Commande : GET
Message : {"on":true}
curl -X PUT -d '{\"on\":true}' IP_du_pont/api/votre_jeton/lights/ID_de_la_lampe/state
Puis pour l'éteindre :
URL : /api/votre_jeton/lights/ID/state
Commande : PUT
Message : {"on":false}
curl -X PUT -d '{\"on\":false}' IP_du_pont/api/votre_jeton/lights/ID_de_la_lampe/state
Si tout se passe bien, le pont répond avec un message identique à ceux-ci :
[{"success":{"/lights/6/state/on":true}}]
[{"success":{"/lights/6/state/on":false}}]
Un premier script Python pour allumer/éteindre une lumière
Tâchons maintenant de rendre tout cela facilement exploitable avec un petit programme. Nous l'écrirons en Python pour le rendre utilisable sous Linux, macOS et Windows. S'il n'est pas installé sur votre système, vous pourrez trouver les fichiers nécessaires par ici :
Sous Windows, pensez à cocher la case Add Python.exe to Path dans la liste des éléments proposés. Il nous faut ensuite installer le module requests servant à exécuter des requêtes. Cela passe par une ligne de code que l'on peut taper dans un terminal une fois Python installé sur le système (pour certaines distributions Linux, le paquet python-pip sera à installer) :
pip install requests
Créez ensuite un fichier hue_manager.py
que vous ouvrirez avec votre éditeur préféré : Atom, Notepad++, Visual Studio Code, etc. Pour rappel, Python est un langage interprété, souvent utilisé pour des scripts, notamment parce qu'il dispose d'un écosystème complet et de nombreuses bibliothèques clé en main (comme requests dans notre exemple).
Il en existe d'ailleurs pour les Philips Hue, comme phue ou qhue. Pour ce petit programme, nous nous en passerons. Nous partons aussi du principe que vous avez déjà identifié l'IP de votre pont, le nombre de l'ampoule à utiliser et obtenu un jeton.
Nous allons tout d'abord réaliser un petit script permettant d'afficher l'URL pour la requête sur l'ensemble des lampes, puis celle pour la lampe que vous voulez gérer en particulier. Placez le code suivant dans hue_manager.py :
import requests
import json
bridge_ip ="IP_du_pont"
username ="votre_jeton"
light_number ="ID_de_la_lampe"
lights_url ="http://{}/api/{}/lights".format(bridge_ip, username)
light_state_url ="{}/{}/state".format(lights_url, light_number)
print lights_url
print light_state_url
On indique tout d'abord que l'on va utiliser les modules json
et requests
, puis on définit les variables utiles au bon fonctionnement de notre script sous forme de textes (ou string, d'où les guillemets). Pensez bien à les adapter selon votre configuration (IP, jeton, nombre de l'ampoule). Ensuite, nous composons les deux URL nécessaires avec la méthode str.format()
.
Celle-ci nous permet d'indiquer comment est composée l'URL puis de lister les variables à utiliser. Une fois ceci fait, nous affichons le résultat avec l'instruction print.
Pour exécuter le programme, tapez la commande suivante :
python hue_manager.py
Affichons maintenant le statut de nos différentes ampoules en ajoutant les lignes de code suivantes à notre script :
r = requests.get(lights_url)
for light in r.json():
light_current_status ="{}-{} : {}".format(light,
r.json()[light]["name"].encode("utf-8"),
r.json()[light]["state"]["on"])
print light_current_status
La première ligne exécute une requête simple sur l'URL permettant d'obtenir les informations sur les lumières. Nous récupérons ensuite le résultat au format JSON (r.json()
) pour l'utiliser dans une boucle. Le contenu de la boucle est décalé par rapport au reste du code, c'est la manière de faire de Python.
Pour chaque ampoule, nous affichons trois éléments : son nombre, son nom (.encode("utf-8")
permettant d'éviter les soucis avec les accents et caractères spéciaux), puis son statut (allumée ou non).
Enfin, si la lampe désignée est éteinte, nous l'allumons, ou inversement :
new_state = not r.json()[light_number]["state"]["on"]
message = json.dumps({"on": new_state})
action = requests.put(light_state_url, data=message)
print action.content
On récupère l'état inverse à celui de l'ampoule désignée au départ, puis on prépare le message pour la requête à envoyer. Celui-ci soit être converti de simple texte à un élément JSON (via json.dumps()
). La requête est ensuite envoyée. Nous affichons enfin son résultat.
Notez que Signify indique dans sa documentation que la phase de transition par défaut de ses ampoules est de 400 ms (elle peut être réduite à 0 ms ou allongée), et que la latence peut aller de 40 à 125 ms. Il faut donc veiller à ne pas trop envoyer de commandes. Au cas où vous auriez eu envie de jouer à « nuit... jour... nuit... jour... nuit... ».
Mais maintenant que vous avez accès à l'API et à sa documentation, la seule limite est votre imagination. Tentez donc de faire mieux (et publiez-en les sources). Celle de l'exercice du jour sont disponibles par ici.
Apprenez à utiliser l’API locale de Philips Hue et à l’utiliser dans un premier script Python
-
Trouver l'IP du pont, utiliser l'API
-
Récupérer et supprimer un jeton utilisateur
-
Lister et gérer vos ampoules
-
Un premier script Python pour allumer/éteindre une lumière
Commentaires (17)
Vous devez être abonné pour pouvoir commenter.
Déjà abonné ? Se connecter
Abonnez-vousLe 29/12/2018 à 10h44
Décidément, je sens que l’on va s’amuser sur Inpact Hardware !
Le 29/12/2018 à 10h47
Le 29/12/2018 à 11h23
Ça sent la chocolatine pas fraiche ….
Le 29/12/2018 à 11h45
un reboot, un raider et ça marche ….
Le 29/12/2018 à 13h31
Bonjour,
Merci pour ce dossier, je tombe sur une erreur de type 1 “unauthorized user” quand je fais la demande de jeton, une idée d’où peut venir le problème merci !
Le 29/12/2018 à 14h29
Y’a forcément une erreur dans la requête puisque /api ne nécessite pas d’autorisation particulière en POST, donc la seule réponse c’est le jeton ou l’erreur 101 lorsque le bouton n’est pas pressé.
L’erreur 1 est renvoyée lorsque l’username est manquant, donc pas logique pour une requête où l’on cherche justement à obtenir l’username
Le 29/12/2018 à 14h32
Effectivement j’avais une erreur dans la requête merci !
Le 29/12/2018 à 16h13
Bonjour,
Question peut-être bête mais que signifie les {} dans les lignes de code suivantes :
lights_url = “http://{}/api/{}/lights”.format(bridge_ip, username) ;
light_state_url = “{}/{}/state”.format(lights_url, light_number) ;
light_current_status = “{} - {} : {}”.format(light,
Merci par avance et bravo pour le retour d’INpact Hardware, plein de choses intéressantes en perspective
Le 29/12/2018 à 16h19
Comme expliqué on utilise la méthode str.format() qui permet de définir un texte avec des emplacements (les {}), puis la liste des variables à y placer.
Le 30/12/2018 à 11h11
Peut-on avoir (et utiliser) des Philips Hue sans accès Internet ?
Le 30/12/2018 à 11h56
Le 30/12/2018 à 13h02
Depuis, a été développé une écriture plus pythonique (via les f-strings), permettant une meilleure lisibilité du code (pour light_state_url = “{}/{}/state”.format(lights_url, light_number)) :
light_state_url = f"{lights_url}/{light_number}/state"
Le 30/12/2018 à 13h14
Python 3 uniquement, ça m’évite d’avoir à gérer le cas de ceux qui utilisent la 2.x ;)
Le 30/12/2018 à 14h33
Ooops merci … Je vais réviser mes RSS je crois que j’ai raté un truc :)
Le 31/12/2018 à 12h54
Je rêve d’une api “universelle” et de relier tout ça à ce type de hardware… Dans un jeu il commence à faire nuit et hop ta lumière baisse ! Tu est low life et ta lumière clignote en rouge, ect !
Le 31/12/2018 à 16h03
Une API ne sera jamais universelle, ne serait-ce que pour la nature assez différentes des produits que l’on peut trouver sur le marché et des protocoles qu’ils utilisent. Après tu as des systèmes domotiques qui permettent de gérer différents types de composants.
Pour le reste, c’est un peu le but de la synchronisation et de l’entertainement API de Hue, mais il faut que les développeurs l’utilisent, ça peut parfois prendre du temps
Le 02/01/2019 à 16h39
- Pourquoi Python ?
- Parce que c’est bon !*
Inpact>Hardware champion du monde ;-)
* Comprend qui veut…