Gestion d’une Cave à vins avec Tasker et Python

winecellar

Je suis un grand amateur de vin et après m’être essayé au livre de cave papier (rébarbatif il va s’en dire) pour gérer le stocks de bouteilles de ma cave à vin, j’ai cherché et essayé nombre d’application (sous Linux il va s’en dire).
Malheureusement, je n’ai jamais trouvé mon bonheur, même si OpenCellar était quand même ce que j’avais trouvé de mieux.
J’ai donc profité de mon week-end pour mettre en place une gestion de cave à vins qui convient à mes besoins (et aux vôtres aussi peut être :))

J’attendais plusieurs choses d’une « application » de gestion de cave à vins et je suis surpris de ne rien trouver d’adéquat (ou alors j’ai mal cherché et je suis ouvert à vos suggestions :))

– une application légère (donc en mode web)
– fonctionnant sous Linux (donc le prérequis précédent convient)
– fonctionnant en local (pas de cloud machin truc)
– permettant l’ajout et le retrait de bouteille avec son smartphone (car se rendre dans la cave à vin, choisir la bouteille, puis aller sur son pc ou son portable, ouvrir le site web, retirer la bouteille, c’est un peu lourd, alors que le smartphone, on l’a souvent avec soi)

N’étant pas un grand développeur web dans l’âme (ni avec mes doigts d’ailleurs), j’ai d’abord cherché une base de site sur laquelle commencer car je n’avais pas vraiment envie de passer plusieurs heures a faire du css, du div et toute la joie inhérente à ce genre d’application.

J’ai trouvé les projets de Christophe Coenraets sur Github qui à écrit plusieurs articles et applications pour gérer sa cave à vin (je vous invite d’ailleurs à lire ses billets à ce sujet (http://coenraets.org/blog/2011/12/restful-services-with-jquery-php-and-the-slim-framework/ , http://coenraets.org/blog/2011/12/restful-services-with-jquery-and-java-using-jax-rs-and-jersey/ , http://coenraets.org/blog/2012/01/using-backbone-js-with-a-restful-java-back-end/).
Mon choix s’est porté sur sa version PHP, plus léger pour moi à mettre en œuvre.
Le plus de son application, c’est la présence d’une API permettant d’ajouter, mettre à jour ou lister le contenu de sa cave (oh voui j’adore ça lister mes vins avec un curl -i -X GET http://localhost/cellar/api/wines 😀 )

Je ne vous ferais pas l’affront de la mise en place du dépôt sous votre serveur web fétiche (penser à activer les méthodes PUT,DELETE et POST), cela coule de source.

On peuple la base et voila le premier résultat (a peu près, la c’est ma version modifiée)

screenwine1

Car oui j’ai d’abord modifié quelques fonctions.
Pour gérer les bouteilles avec mon smartphone, j’ai d’abord pensé à des étiquettes RFID, mais avec le nombre de précieux flacons, j’allais exploser mon budget « loisir« .
Donc mon choix s’est plutôt tourné vers un élément que l’on retrouve « presque » sur toutes les bouteilles, le code barre (ou EAN 13 pour les puristes).
Dans l’ensemble, j’ai très peu de bouteilles sans, principalement des achats direct au producteur, donc ne saisir qu’une infime quantité de stock à la mimine m’allait parfaitement (au pire, je pourrais faire du RFID avec elles).

NB: Dans ma folie habituelle, je vous avouerais être d’abord parti sur de la reconnaissance de l’étiquette avec OpenCV et de l’OCR mais vu l’ampleur du projet, je me suis vite raisonné 😀

Mes premières modifications apportées sur le code : ajout du champ EAN, traduction des champs, modification de la recherche sur la région en plus du nom et ajout d’un champ quantité.

Mes premiers tests de l’API était sympa mais il m’en fallait plus.
Etant plus à l’aise avec Python que PHP ou JavaScript, j’ai rapidement codé ma propre API.

Celle ci permet plusieurs choses :
– POSTer le code EAN d’une bouteille et la créer si besoin (en mettant la quantité à 1 par défaut et en lui affectant l’image ‘codeEAN’.png), si le code existe, ajouter +1 à la quantité. Possibilité également de faire -1 sur la quantité.

class addean:
def POST(self,uri):
try :
ID = web.data()
except:
return web.badrequest()
con = MySQLdb.connect(host=mysqlhost, user=mysqluser, passwd=mysqlpasswd, db=mysqldb);
cur = con.cursor()
print ID
cur.execute("""SELECT * from wine where EAN=%s""", (ID,))
result = cur.fetchone()
if result is None:
print "no bottle"
print ID
data = {'EAN': ID, 'picture': ID+'.png'}
data = json.dumps(data)
req = urllib2.Request(url, data, {'Content-Type': 'application/json'})
f = urllib2.urlopen(req)
response = f.read()
f.close()
else:
cur.execute("""UPDATE wine SET nombre=(nombre+1) where EAN=%s""", (ID,))
con.commit()
print "Number of rows updated: %d" % cur.rowcount
con.close()
 
class removeean:
def POST(self,uri):
try :
ID = web.data()
except:
return web.badrequest()
con = MySQLdb.connect(host=mysqlhost, user=mysqluser, passwd=mysqlpasswd, db=mysqldb);
cur = con.cursor()
print ID
cur.execute("""SELECT * from wine where EAN=%s""", (ID,))
result = cur.fetchone()
if result is None:
print "new bottle"
print ID
data = {'EAN': ID, 'picture': ID+'.png'}
data = json.dumps(data)
req = urllib2.Request(url, data, {'Content-Type': 'application/json'})
f = urllib2.urlopen(req)
response = f.read()
f.close()
else:
cur.execute("""UPDATE wine SET nombre=(nombre-1) where EAN=%s""", (ID,))
con.commit()
print "Number of rows updated: %d" % cur.rowcount
con.close()

– POSTer la photo de l’étiquette et l’inclure dans la fiche.

class index:
def POST(self,uri):
try:
web.cookies().filename
filenamereceived = web.cookies().filename
except:
filenamereceived == "generic"
try :
data = web.data()
except:
return web.badrequest()
if data == "":
return web.badrequest()
print filenamereceived
b64response = base64.b64encode(data)
fh = open(winepics+filenamereceived+".png", "wb")
fh.write(b64response.decode('base64'))
fh.close()
return "200 STORED"

Maintenant que mon API était prête, il fallait pouvoir utiliser le smartphone.

La meilleure application d’automatisation sous android est pour moi Tasker. De plus, de nombreux plugins existent et l’un des maîtres du plugin Tasker est sûrement João Dias alias joaomgcd.
J’utilise quasiment tout ses plugins (qui ne coûte pas grand chose pour une efficacité redoutable, dont le fameux AutoRemote) et en cherchant un plugin « barcode » (code barre) pour Tasker, et bien il existe AutoBarcode ! Magique, ce type est un génie 😀

Un peu de « codage » Tasker pour réaliser ce que je veux :

Lancer un scan de code barre,

Screenshot_20161030-212503

une fois effectué, lancer une « scène » Tasker me demandant si je veux ajouter ou retirer cette bouteille :

Screenshot_20161030-212537

– je retire, je fais -1 sur la quantité
– j’ajoute, je fais +1 si le code EAN existe, sinon j’appelle l’API du site pour créer la bouteille avec son code EAN. Je continue en demandant si je veux ajouter une photo, si non, je sors, si oui, je lance l’appareil photo qui me permet de photographier l’étiquette et de la POSTer en la nommant ‘codeEAN’.png.

Screenshot_20161030-212547
Bien sur la création de la bouteille lie automatiquement l’image à l’url ../pics/’codeEAN’.png.

Il ne me reste alors qu’a me rendre sur le site web pour compléter la fiche de la bouteille.

screenwine2
En quelques heures, j’ai enfin pu me créer un site de gestion de ma cave à vin efficace et qui répond à mes besoins.
L’ajout ou le retrait d’une bouteille se fait avec le smartphone en premier lieu (on peut le faire sur le site aussi).

Si vous voulez vous aussi déployer ce genre d’application chez vous, j’ai bien évidemment tout mis sur mon Github en forkant le projet de Christophe et en y ajoutant les éléments nécessaires 😀

Amusez vous bien 🙂

Ce billet a été posté dans geekerie et taggé , . Bookmark ce permalink.

7 commentaires sur “Gestion d’une Cave à vins avec Tasker et Python

  1. C’est tout un plaisir de te lire, même si je n’ai pas de cave à vin 🙂

  2. Bonsoir,

    merci pour l’article. C’est vraiment super.
    J’ai essayé de démarré l’API python.
    J’ai ce message d’erreur :
    File « ./ApiCellar.py », line 53
    try :
    ^

  3. effectivement, un espace qui manque. J’ai corrigé sur github (ou editer le fichier et ajouter un espace devant le try ligne 53)

  4. Bonjour,

    Merci pour ce tuto, cela fait un moment que je cherche une solution telle que celle ci.
    Cependant, loin d’être du niveau de ce tuto ,je rencontre des difficultés à le mettre en place.
    J’utilise donc phpmyadmin sur mon syno en guise de base.
    En ce qui concerne « activer les méthodes PUT,DELETE et POST » je pense que depuis le temps c’est le cas, mais j’en suis pas sur, je ne serai pas offensé d’en savoir plus ;-). Aussi lorsque depuis l’interface WEB je tente de rentrer un nouveau vin : J’ai ce message dans la console:
    addWine
    jquery-1.7.1.min.js:4 POST http://xxx.xxx.xxx.xxx/cave/api/wines 500 (Internal Server Error)
    Plus un pop-up d’erreur.
    Merci pour l’aide,

    Djo.

  5. Bonjour,
    Super, moi qui commence en domotique à faire des choses, même si cen’est pas le plus urgent je vais enfin pouvoir gérer mes bonnes bouteilles.
    Tiens ça me donne envie de retourner en Alsace pour préparer la cave avant de commencer, on en a un peu écluser ces 2 dernières années 🙂
    Merci et bonne continuation.