Apprenez à utiliser l'API locale de Philips Hue et à l'utiliser dans un premier script Python

Tu préfères Ruby ? Dommage !
Apprenez à utiliser l'API locale de Philips Hue et à l'utiliser dans un premier script Python

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.

Notre dossier sur les ampoules Philips Hue :

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 :

Philips Hue Bridge API Debug

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.

Ce contenu est désormais en accès libre

Il a été produit grâce à nos abonnés, l'abonnement finance le travail de notre équipe de journalistes.

ou choisissez l'une de nos offres d'abonnement :

17 commentaires
Avatar de Larsene_IT Abonné
Avatar de Larsene_ITLarsene_IT- 29/12/18 à 10:44:36

Décidément, je sens que l'on va s'amuser sur Inpact Hardware ! :bravo:

Avatar de David_L Équipe
Avatar de David_LDavid_L- 29/12/18 à 10:47:03

(quote:38663:Larsene_IT) ...

:smack:

Avatar de Drozo Abonné
Avatar de DrozoDrozo- 29/12/18 à 11:23:07

(quote) pipi@lit:~ $ curl https://discovery.meethue.com []

Ça sent la chocolatine pas fraiche ....

Avatar de Drozo Abonné
Avatar de DrozoDrozo- 29/12/18 à 11:45:17

un reboot, un raider et ça marche ....

Avatar de palmss INpactien
Avatar de palmsspalmss- 29/12/18 à 13:31:05

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 !

Avatar de David_L Équipe
Avatar de David_LDavid_L- 29/12/18 à 14:29:57

(quote:38670:palmss) 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 !

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 :transpi:

Avatar de palmss INpactien
Avatar de palmsspalmss- 29/12/18 à 14:32:43

Effectivement j'avais une erreur dans la requête merci !

Avatar de Paul Muad'Dib Abonné
Avatar de Paul Muad'DibPaul Muad'Dib- 29/12/18 à 16:13:17

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 :yes:

Édité par Paul Muad'Dib le 29/12/2018 à 16:14
Avatar de David_L Équipe
Avatar de David_LDavid_L- 29/12/18 à 16:19:42

(quote:38675:Paul Muad'Dib) ...

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.

Avatar de bsod Abonné
Avatar de bsodbsod- 30/12/18 à 11:11:21

Peut-on avoir (et utiliser) des Philips Hue sans accès Internet ?

Il n'est plus possible de commenter cette actualité.
Page 1 / 2

Votre commentaire

Avatar de lecteur anonyme
Avatar de lecteur anonyme

2000 - 2019 INpact MediaGroup - SARL de presse, membre du SPIIL. N° de CPPAP 0321 Z 92244.

Marque déposée. Tous droits réservés. Mentions légales et contact