Le contrôle vocal est, vous le savez, un vieux rêve qui nous taraude depuis que l’on regarde des films de filles soumises science-fiction.
Heureusement pour nous, le concept et les logiciels ont bien évolués depuis ses dernières années et nous sommes bien loin désormais de nos lointains souvenirs où nous passions des heures avec notre microphone a réciter des pages et des pages de phrases abjectes pour obtenir un résultat… désespérant (si toi aussi tu vois de quoi je parle et que tu souris en y repensant, tu ne me contrediras sûrement pas 😀 )
J’avais depuis longtemps mis de côté l’idée d’utiliser ma voix pour contrôler quoi que ce soit (et encore moins ma femme, cela marche un peu mieux avec les enfants), jusqu’a ses derniers jours après une lecture intéressante sur un site web dont je vous reparlerais plus tard dans ce billet.
Le but de cet article est de vous décrire comment, avec mon téléphone Android, je contrôle par la voix l’extinction ou l’allumage de mes lumières ou la fermeture de la porte du garage. Potentiellement, tout est contrôlable désormais, il faut juste prendre le temps de coder les règles.
Mais n’anticipons pas, tout d’abord de quoi avons nous besoin.
- Un Webservice pour notre serveur Domotique
Si vous disposez d’une box domotique, vous avez sûrement le moyen de contrôler par une requête http vos prises ou interrupteurs (je vous laisse à la documentation de la dite box), mais si comme moi, vous contrôler tout par des scripts, xPL et j’en passe et des meilleurs, il va pouvoir devenir intéressant de disposer d’une API permettant par une URL de commander vos équipements.
Python (encore lui), est le candidat idéal pour créer ce WebService.
L’exemple de code que je vais vous donner n’est peut-être pas utilisable pour vous dans l’immédiat car il est fortement intégré à mon environnement domotique (xPL), mais il vous donnera sûrement des pistes pour réaliser vous même votre API.
Vous trouverez les classes que j’utilise dans mon projet xPL-PyHAL (xPLmessage par exemple ou Daemon). Donc si vous utilisez mon centralisateur xPL, il y a donc de fortes chances que cela marche tout de suite 😉 (pub pub pub)
#!/usr/bin/env python
import web
import re,socket,sys,os
from xPLmessage import xPLmessage
import threading
from Daemon import Daemon
motdepasse = "1234"
#exemple d appel http :
#lynx "http://localhost:8080/x10?cle=1234&module=a1&command=on"
web.config.debug = False
urls = (
'/', 'index',
'/x10', 'x10',
'/ipx800', 'ipx800'
)
render = web.template.render('templates/', globals={'re':re})
app = web.application(urls, globals())
class index:
def GET(self):
return web.HTTPError(403)
def POST(self):
return web.HTTPError(403)
class x10:
def GET(self):
sendmsg = xPLmessage()
key = web.input(cle='')
adress = web.input(module='')
command = web.input(command='')
if not key.cle:
raise web.HTTPError(403)
if not adress.module:
raise web.HTTPError(404)
if not command.command:
raise web.HTTPError(404)
if key.cle != motdepasse:
return 'access denied'
else :
commandx10 = command.command
devicex10 = adress.module
sendmsg.xplmsgcmndx10(commandx10,devicex10)
return 'accept'
class ipx800:
def GET(self):
sendmsg = xPLmessage()
key = web.input(cle='')
adress = web.input(module='')
command = web.input(command='')
if not key.cle:
raise web.HTTPError(403)
if not adress.module:
raise web.HTTPError(404)
if not command.command:
raise web.HTTPError(404)
if key.cle != motdepasse:
return 'access denied'
else :
commandipx800 = command.command
relayipx800 = adress.module
sendmsg.xplmsgcmndipx800(commandipx800,relayipx800)
return 'accept'
class MyDaemon(Daemon):
def run(self):
app.run()
if __name__ == "__main__":
service = MyDaemon('/tmp/daemon.pid')
if len(sys.argv) == 2:
if 'start' == sys.argv[1]:
sys.argv[1] = '8080'
service.start()
elif 'stop' == sys.argv[1]:
service.stop()
elif 'restart' == sys.argv[1]:
service.restart()
elif 'console' == sys.argv[1]:
sys.argv[1] = '8080'
service.console()
else:
print "Unknown command"
sys.exit(2)
sys.exit(0)
else:
print "usage: %s start|stop|restart|console" % sys.argv[0]
sys.exit(2) |
#!/usr/bin/env python
import web
import re,socket,sys,os
from xPLmessage import xPLmessage
import threading
from Daemon import Daemon
motdepasse = "1234"
#exemple d appel http :
#lynx "http://localhost:8080/x10?cle=1234&module=a1&command=on"
web.config.debug = False
urls = (
'/', 'index',
'/x10', 'x10',
'/ipx800', 'ipx800'
)
render = web.template.render('templates/', globals={'re':re})
app = web.application(urls, globals())
class index:
def GET(self):
return web.HTTPError(403)
def POST(self):
return web.HTTPError(403)
class x10:
def GET(self):
sendmsg = xPLmessage()
key = web.input(cle='')
adress = web.input(module='')
command = web.input(command='')
if not key.cle:
raise web.HTTPError(403)
if not adress.module:
raise web.HTTPError(404)
if not command.command:
raise web.HTTPError(404)
if key.cle != motdepasse:
return 'access denied'
else :
commandx10 = command.command
devicex10 = adress.module
sendmsg.xplmsgcmndx10(commandx10,devicex10)
return 'accept'
class ipx800:
def GET(self):
sendmsg = xPLmessage()
key = web.input(cle='')
adress = web.input(module='')
command = web.input(command='')
if not key.cle:
raise web.HTTPError(403)
if not adress.module:
raise web.HTTPError(404)
if not command.command:
raise web.HTTPError(404)
if key.cle != motdepasse:
return 'access denied'
else :
commandipx800 = command.command
relayipx800 = adress.module
sendmsg.xplmsgcmndipx800(commandipx800,relayipx800)
return 'accept'
class MyDaemon(Daemon):
def run(self):
app.run()
if __name__ == "__main__":
service = MyDaemon('/tmp/daemon.pid')
if len(sys.argv) == 2:
if 'start' == sys.argv[1]:
sys.argv[1] = '8080'
service.start()
elif 'stop' == sys.argv[1]:
service.stop()
elif 'restart' == sys.argv[1]:
service.restart()
elif 'console' == sys.argv[1]:
sys.argv[1] = '8080'
service.console()
else:
print "Unknown command"
sys.exit(2)
sys.exit(0)
else:
print "usage: %s start|stop|restart|console" % sys.argv[0]
sys.exit(2)
Comment ca marche ?
Je le dis tout de suite, ce n’est pas « restful compliant » (je réagis sur des GET http et pas des POST) mais pour l’usage personnel que j’en fais, c’est largement suffisant (et je n’ai pas vocation à en faire un produit commercial).
En appelant par votre navigateur (ou par curl ou par lynx (qui est pour moi le nec plus ultra du navigateur web (barbu inside))) l’URL : « http://monserveurdomotique:8080/x10?cle=1234&module=a1&command=on » vous allez demander au module A1 de s’allumer.
Je prend l’exemple X10 uniquement pour la simplicité de compréhension, cela pourrai être IPX800 dans mon code ou n’importe quelle techno domotique du moment qu’elle est « appelable » par le webservice (xPL est encore et toujours votre ami pour centraliser tout cela).
La « clé » est le mot de passe pour executer une requète sur votre serveur domotique, alors évidemment la sécurité est très minimaliste dans cet exemple, mais je vous laisse peaufiner a coup d’https, de certificats, d’iptables et j’en passe.
Le code est suffisamment simple pour que vous en compreniez le fonctionnement et que vous l’adaptiez à vos besoins (les tutos sur les webservice python sont nombreux sur le nain ternet).
Maintenant que nous commes capable de donner des ordres a notre système domotique par de simples requêtes http, il nous reste à pouvoir le faire de vive voix.
- Tasker, le « must have » d’un téléphone Android
Tasker est sûrement l’un des meilleurs logiciels sous Android existant.
Il vous permet de créer toutes sortes de scénarios ou d’évènements sur votre téléphone (si je met des écouteurs alors joue une musique, si je me trouve à moins de 100m de chez moi, alors ouvre la porte du garage, etc..)
Si sa complexité rebute un peu au premier abord, on en prend vite la main et rapidement, on en arrive à coder des centaines de tâches ou de contextes qui nous facilite la vie au quotidien.
Le prix est dérisoire en comparaison de ses capacités et je ne peux que vous inviter chaudement à l’acheter.
Cerise sur le gâteau (Note inintéressante de l’auteur : Je vous fait grâce des expressions que j’ai voulu écrire ici et qui laisserait sûrement planer la honte sur ma famille durant des décennies), depuis quelques semaines, Tasker inclus désormais la possibilité d’exporter vos « scénarios » en tant qu’application autonome Android !!! C’est pas le top du summum de la geekerie ultime ça ??? (Note inintéréssante de l’auteur (encore) : Là vraiment, vous avez échappé à des expressions qui limite me vaudrait quelques années de prisons …)
Exemple, vous créez un petit scénario qui fait que quand votre téléphone est en charge, vous activez le wifi, si vous le retournez, il coupe tout, et se met en mode silence, s’il détecte votre oreillette bluetooth, il informe votre serveur domotique que vous êtes en mode privé et que les messages d’alerte de votre installation peuvent être envoyé via Notifry en Audio (qui depuis une petite discussion avec Daniel, le développeur de Notifry, a gentiment accepté d’intégrer le choix de la sortie audio des messages Notifry 🙂 Merci à lui pour répondre rapidement à mes demandes d’évolutions, un développeur aussi proche de ses utilisateurs est assez rare pour le souligner.
Et d’un clic, vous exportez votre propre application apk autonome.
Il n’y a quasiment pas de limite à Tasker, a part votre propre imagination.
Et dans toute ses imaginations possibles, je suis tombé sur un fou furieux de Tasker (dans le bon côté du terme :p, ce type fait quand même tourner 474 taches Tasker par jour oOO), Andreas Ødegård.
(alors vu que c’est un norvégien, vous comprendrez les caractères ésotériques dans son nom 😀 ), qui est ausi un des rédacteur associé pour l’excellent site Pocketables.
Ce geek comme je les aime, outre la qualité de ses billets, nous donne souvent des trucs et astuces pour Tasker et dans son lot de bidouilles, il a décider de créer son propre assistant vocal sous Android avec Tasker.
A la lecture de son billet, j’ai tout de suite accroché sur l’idée et bien sur, je me suis empressé de le mettre en oeuvre pour mon propre usage et en hommage a l’excellent travail d’Andréas, j’ai décidé de garder le même nom pour mon assistante vocale, Nelly (pour la petite histoire du pourquoi du comment ce prénom, je vous invite a lire son billet, a moins que vous ne soyez déjà un lecteur assidu de Mike Shepherd ).
Pour réaliser cet exploit, nous allons tout simplement utiliser la fonction « Obtenir depuis depuis la voix » de Tasker. Cette fonction se base sur le moteur de reconnaissance vocale de Google (une connexion au nain ternet est donc nécessaire)
La phrase analysée est contenue dans la variable %VOICE de Tasker, il ne reste plus qu’a réaliser une tâche s’executant si la variable %VOICE contient tels mots.
Pour appeler notre Webservice Python, nous allons utiliser la fonction « Get HTTP » en spécifiant les paramètres suivants :
Et pour l’analyse des mots sur lesquels réagir :
L’étoile étant bien sur un caractère joker, ce que l’on dit « autour » n’est pas pris en compte (ça vous permet de laisser libre cours a votre imagination devant votre entourage : « Nelly, mon petit, dans ta grande manséutude, si tu éteins le salon que je puisse dragouiller la demoiselle que j’ai invité chez moi pour un soi-disant repas en toute amitié, je t’en serais reconnaissant. »)
Attention quand même, par défaut vous n’avez que 30 secondes… (euh pour donner l’ordre vocal hein, pas pour la demoiselle…)
Pour vous montrer de visu de quoi Tasker est capable avec « Nelly », je vous propose une petite vidéo faite a l’arrache (je l’avoue) mais qui vous donnera les capacités du système.
Démonstration de contrôle vocal avec Tasker par Guiguiabloc
Avouez tout de même que cela en jette pas mal (en plus d’être diaboliquement génial 🙂 )
Merci donc à Andréas pour son idée, à Lee Wilmot pour son excellente application Tasker et à Olivier Sannier pour la traduction en français de Tasker 😉
Amusez vous bien 😀