mardi 27 janvier 2015

Python, imprimer en PCL directement sur une HP 3015 en réseau

Introduction
Nous avons plusieurs imprimantes HP dans notre société, dont une HP 3015 en réseau.
Le bonheur avec une HP3015, c'est qu'il est possible d'ouvrir un socket sur le port 9100 et commencer à envoyer un flux texte à imprimer.
Il est également possible d'inclure des séquence d'échappement pour modifier la font, la taille, ect. C'est ce que qu'offre PCL, qui utilise des séquences de "caractères" particulier pour opérer ces changement.

L'avantage de cette approche est d'être totalement indépendante de la plateforme, du langage de programmation et de l'OS. Si vous le vouliez, vous pourriez imprimer depuis un Arduino + Ethernet, Raspberry, etc! Si cela à l'avantage de ne pas surcharger l'OS avec des composants logiciel (pilotes et soft annexés qui font parfois 100Mb+), votre code sera plus long et plus complexe (il devra injecter les séquence d'échappement dans le texte à imprimer, faire gaffe à ne pas déborder de la page, etc).

Pour ceux qui doute du bien fondé de cette approche un peu extrême, je leur propose de prendre un bon vieux soft Clipper en production (20 ans d'ages) et de le recompiler sous Win32.
C'est là que l'on apprécie les bonne vielles casseroles et le gain de temps en R&D.  Une bonne vielle poule au pot... humm que c'est bon!

HP 3015 + PCL + Python
Voulant introduire du graphique dans le documents imprimés (hé oui, PCL le supporte), je me suis dit "pourquoi ne pas faire un prototype en Python".
Simple et facile à mettre en oeuvre, c'est un langage idéal pour faire quelques tests.

Seulement voila, j'ai chié des boulons (Metric 60 les gars!). Pas a cause du l'imprimante IP, pas à cause du socket, par a cause de Python mais à cause de l'encoding!
Entre explosion pour erreur d'encodage, affichage de mes accentués à la va te faire f...., j'en ai vu de toutes les couleurs.

En suivant les recommandations sur l'article "L’encoding en Python, une bonne fois pour toute" de Sam & Max, j'ai fait très attention à mon encoding (UTF8 pour les sources), utilisé des chaines de caractère Unicode (Python 2.7) et réencoder vers le bon code page pour l'envoi des chaines de caractères vers l'imprimante (cp850, il a aussi fallut le trouver celui-là).

Par contre, il m'a fallut un temps considérable pour remarquer que les séquences d'échappement devaient être envoyéez en UTF-8 (sinon "encoding error") et le texte avec accentués en cp850!!!
J'en ai mangé mon clavier (j'en ai encore la barre d'espacement en travers de la gorge!).

Un bout de code qui marche
Voici finalement un petit bout de code simplissime en état de fonctionnement. Les séquences d'échappement modifies seulement la taille du texte. Le but étant d'avoir un résultat cohérent sur l'imprimante sans explosion Python!

#!/usr/bin/env python
# -*- coding: utf8 -*-

import socket
import sys
import encodings

PRINTER_IP = '192.168.1.206'
PRINTER_PORT = 9100
PRINTER_ENCODING = 'cp850'

s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
s.connect( (PRINTER_IP, PRINTER_PORT) )
  
s.sendall( bytes( (u"Chère Mère à la peau tanée.\r\n").encode( PRINTER_ENCODING )) )
s.sendall( bytes( (u""+chr(27)+"(s5H").encode( 'UTF-8' ) ))
s.sendall( bytes( (u"Cet énorme titre\r\n").encode( PRINTER_ENCODING ) ))
s.sendall( bytes( (u""+chr(27)+"(s11H").encode( 'UTF-8' ) ))
s.sendall( bytes( (u"a t'il attiré ton regard\r\n").encode( PRINTER_ENCODING ) ))
s.sendall( bytes( (u""+chr(27)+"(s17H").encode( 'UTF-8' ) ))
s.sendall( bytes( (u"à moins que cela ne soit impossible?").encode( PRINTER_ENCODING ) ))

s.close()


Il y a certainement moyen de rendre ce code plus lisible (le blinder ou faire en sorte qu'il soit "safe" sous Python 3) mais au moins, il fonctionne!

Quel encoding sur mon imprimante
Dans l'exemple précédent, j'utilise 'cp850' comme encoding sur l'imprimante HP.
J'ai eu beaucoup de mal a trouver le bon encodage car malheureusement, Google et le Net ne sont pas très bavard à ce propos!

Encore un fois, c'est un petit script Python qui à testé TOUTES les possibilités en imprimant une phrase contenant un 'é' et le codepage utilisé pour cette impression.
Il ne reste plus qu'a relever les lignes ou le "é" est imprimé correctement.

#!/usr/bin/env python
# -*- coding: utf8 -*-

import socket
import sys
import encodings

PRINTER_IP = '192.168.1.206'
PRINTER_PORT = 9100

s = socket.socket( socket.AF_INET, socket.SOCK_STREAM )
s.connect( (PRINTER_IP, PRINTER_PORT) )

for e in encodings.aliases.aliases.values():
  try:
    s.sendall( bytes( (u"Encode ecute é with %s\r\n" % e).encode( e ) ) )
  except:
    s.sendall( bytes( (u"Fails ecute encoding with %s\r\n" % e).encode( "UTF-8" ) ) )
    
s.sendall( bytes( (u"TIME 600\r\n").encode( "UTF-8")) )     # Pas d'accent -> pas de problème
s.sendall( bytes( (u""+chr(27)+"(s5H"+"Big Title").encode( "UTF-8" ) )) # Pas d'accent -> pas de problème

s.close()

Plusieurs options  valides
"é" est un caractère assez répandu dans les alphabets. Il y a donc plusieurs codes pages pouvant convenir.
J'ai finalement choisi 'cp850' car en Belgique, c'est le codepage 850 qui est également utilisé "sous DOS". Les imprimantes vendue dans le même pays sont forcement configuré avec un codepage similaire à celui utilisé par les OS locaux.
Python peut encore une fois vous aider à déterminer le code page de votre système d'exploitation (la console).
C:\temp\python-hp>python
Python 2.7.5 (default, May 15 2013, 22:44:16) [MSC v.1500 64 bit (AMD64)] on win
32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> print( sys.stdout.encoding )
cp850
>>>

Le mot de la fin
Je ne voudrais pas jouer mon stroumpf grognon mais...
"J'aime pas l'encoding!"

Bonne amusement

jeudi 22 janvier 2015

PostgresSql et Python avec psyco2

Nous avons une belle DB PostgreSql utilisé par notre programme de production (Clipper compilé avec Harbour Project, Mediator utiliser pour l'accès DB).

Voulant afficher les stats d'expéditions journalière le moniteur d'un portable de récup, je me suis demandé s'il était possible d'attaquer notre DB à partir d'un script Python.
Après quelques recherches sur le Net, je suis rapidement venu et revenu vers PsycoPg2.

Bibliothèque PsycoPG2 - Accéder à vos DB PostgresSql en Python.
Il vaut avouer qu'avec cette bibliothèque, cela devient un vrai jeu d'enfant.
Non seulement il est possible d'accéder facilement à une DB PostgreSql mais en plus, les données sont accessible dans le plus pure esprit Pythonien!
Il est possible:
  • D'exécuter des requêtes SQL
  • Lire un seul enregistrement (FetchOne)
  • Lire  tous les enregistrement (FetchAll)
  • Ou d'utiliser un curseur sur le serveur de base de donnée (pour ne pas charger massivement vos milliers de records en une fois).
  • Supporte les transactions (commit après plusieurs insertions).
  • etc.
Après avoir fait quelques tests (Linux Mint 17.1), je peux vous affirmer que c'est de la balle!

Installation
Sur Linux Mint (Ubuntu), l'installation se résume à:

sudo apt-get install python-Psycopg2

Il semblerait qu'il soit parfois compliqué de trouver les paquets pour certaines distribution. Sachez que la documentation officielle (crf liens ci-dessous) reprend quelques notes concernant la compilation de la bibliothèque.

Des tutoriels
Connaître une bonne bibliothèque c'est bien mais avec de la doc c'est mieux.
Voici donc quelques ressources incontournables.

vendredi 16 janvier 2015

L'encoding en Python... une bonne fois pour toute

Excellent article --incontournable-- disponible sur le blog de Sam & Max.
Unicode - un petit coup de gueule 
Tout le monde ne jure que par l'Unicode et je dois bien admettre que cela a facilité les échanges sur le net... mais a bien y penser, je ne suis pas certain que cela soit pour un mieux (globalement).
Cela à ajouté un sacré niveau de complexité sur un des éléments de base de la programmation (les chaines de caractères... et fichiers).
Dire que je me retrouve à se gratter la tête pour essayer de comprendre pourquoi je n'arrive pas à imprimer un "é" sur mon imprimante HP en la contactant par socket pour imprimer du PCL en direct.
A oui mais grâce à UNICODE je dois:
  • Penser à l'encodage de mon OS
  • Pense à l'encodage des code python avec mon éditeur de texte (afr!)
  • Et celui de tes strings (python 2.7 ou 3)... string ou unicode string?
  • etc
Bref, cela devient un usine à gaz pour les méninges et tout cela pour un simple "é".
C'est là que je trouve que nous n'avons pas gagné grand chose avec unicode... les choses simple et les fondations devraient rester "simple".

 

mardi 13 janvier 2015

PC Portables pour Linuxiens - Configuration à la demande et sans vente liée d'OS

C'est en lisant cet article sur loligrub.be que j'ai découvert le fabriquant Clevo en France (Clevo.fr).

Capable de vous concocter PC et PC Portable avec et SANS Système d'exploitation.

Il est enfin possible de se fournir des PC Portables pour nous Linuxiens sans passer par la case "Licence Microsoft"... de quoi investir la différence dans le Matos!

Livrable en Belgique et en France avec clavier Français ou Belge.
Que demander de plus !

Une référence à retenir:
  • Clevo le spécialiste du pc portable sur mesure.

Clévo propose d'ailleurs un chouette offre permettant de réaliser des micro-serveur Linux pour un prix de départ à 299Eur

dimanche 11 janvier 2015

Basic Authentication avec Python - authentification dans l'entête HTML

J'avais justement besoin de m'authentifier pour faire des requête d'API sur Spark Cloud dans le cadre du projet PyCall.

J'ai trouvé une ressource très intéressante:
Un grand merci à Michael Foord.

Quelques ressources complémentaires:

samedi 27 décembre 2014

Linux Mint: Démarrer un Script Python depuis de bureau

Cet article décrit les différentes étapes pour démarrer un script python à partir d'un lien sur le bureau de Linux Mint (dérivé d'Ubuntu).

Introduction
PrestaShop est un chouette e-commerce mais il traine malheureusement quelques lacunes parfois très handicapantes.
L'une de ses faiblesses se trouve dans le SAV... il est parfois impossible de localiser un nouveau message client lorsqu'il l'envoi sur un ancien ticket (nous avons +3000 ticket et +5000 messages. Argh!

Utiliser un script Python
Grâce à l'API PrestaShop et à Python, il est possible d'écrire un script qui lit les derniers messages reçu sur le WebShop... ce qui permet de localiser plus facilement un tel message et d'avoir les informations adéquate pour le localiser rapidement (l'ID du fil de discussion dans notre cas).

Les scripts Python et utilisateurs finaux
Si je suis à l'aise avec un terminal Linux, ce n'est pas le cas de tout le monde.
L'idéal, c'est quand même d'avoir une icon sur le Bureau qui permet de lancer le script et afficher les résultats attendu.
Même si l'affichage est en mode texte vilain et méchant, ce n'est pas un problème... par contre, le démarrage du script reste un point critique pour un utilisateur Lambda.
C'est là que les choses sont un poil plus compliquées...

Bloquer le script en fin d'exécution
C'est idiot mais il est important de bloquer le script en fin d'exécution. Dans le cas contraire, le script termine son travail... l’interpréteur Python aussi et la fenêtre disparait de l'écran.
Le but c'est de laisser à l'utilisateur le temps de lire le résultat qui s'affiche à l'écran!
Pour cela, n'oubliez pas de faire un import sys en début de script
        import sys

Puis de terminer votre script python par les lignes pour force l'utilisateur à encoder un caractère pour terminer l'exécution du script
    # read char on keyboard
    char = sys.stdin.read(1)
    return 0


Ce que nous avons fait dans notre script savtrack.py...

Créer un Shell Script
Avant toute chose, il est vivement recommandé de créer un shell script (.sh) pour démarrer le script Python.
Le but de ce dernier est:
1) mettre en place les éléments nécessaires à la bonne exécution du script python
2) lancer le script python... éventuellement dans un terminal plus convivial! 

Dans le cas de notre script savtrack.py, nous devons absolument nous trouver dans le sous répertoire PrestaConsole du répertoire utilisateur (le fameux ~/PrestaConsole).
Notre script python à besoin de lire les fichiers cachefile.pkl et config.ini... faut mieux se trouver dans le bon répertoire avant de démarrer le script!

allons y, créons notre script shell "savtrack.sh"... c'est lui qui sera démarré depuis notre bureau Linux.

#!/bin/bash

echo ==========================================
echo       listing SAV
echo ==========================================

cd /home/domeu/PrestaConsole
mate-terminal -e "/usr/bin/python /home/domeu/PrestaConsole/savtrack.py"

Comme vous pouvez le noter, nous faisons un cd (change directory) dans le bon répertoire avant de lancer le script python à l'aide de:
/usr/bin/python /home/domeu/PrestaConsole/savtrack.py

C'est quoi ce mate-terminal???
En fait, en lançant le script "savtrack.sh" depuis le bureau (voir plus loin), Linux Mint va utiliser le terminal xterm par défaut, terminal efficace mais très rudimentaire et peu convivial de prime abord.

Mon script crache un listing assez long (plus qu'un écran) et il est donc important d'avoir un terminal qui dispose d'une scrollbar permettant de naviguer dans le lonnngggg texte produit par notre script savtrack.py.
C'est pour cela que mate-terminal est utilisé pour démarrer le script python.
Résultat affiché dans mate-terminal
Rendre le script shell exécutable
Ce n'est pas tout d'avoir, un script savtrack.sh pour mettre la machine en branle, il faudrait également que ce dernier soit exécutable. Voici la commande qui rendra cela possible.

chmod +x savtrack.sh

n'hésitez pas a tester directement votre script shell depuis le terminal. Il suffit de taper la commande

./savtrack.sh

(le préfix ./ sert à informer le terminal, sans ambiguité possible, que nous voulons bien exécuter le script).

Installer xterm
Comme précisé, l'icone sur le bureau lancera savtrack.sh dans le terminal xterm (par défaut).
Pour une raison que j'ignore, xterm n'était pas installé sur mon système?!?! Pour y remédier, saisissez la commande suivante dans un terminal.

sudo apt-get install xterm

Création du lien (lanceur) sur le bureau

Faite un clique droit sur votre bureau... puis sélectionnez l'option "Créer un lanceur..." dans le menu contextuel.

Cela affiche une boite de dialogue suivante
Création d'un lanceur
La première chose à faire est de sélectionner le type de lanceur... "application dans un terminal"... c'est cette option qui permet de lancer un script shell. Le terminal utilisé sera xterm (par défaut).

Reste à compléter le restant des information... attention a bien sélectionner le script shell dans la commande (savtrack.sh dans notre cas).

Pressez OK et le raccourci est créé sur le bureau :-)
Voila!

Note pour les puristes:
Il est bien entendu possible de modifier le terminal à utiliser par le lanceur.
Il serait donc possible de remplacer directement xterm par mate-terminal.
Par contre, cela nous impose de se souvenir de la modification si nous voulons installer notre script sur un autre ordinateur....
A contrario, les choses sont "écrites" noir sur blanc dans notre shell script.

dimanche 7 décembre 2014

F3: tester des périphériques de stockage (SD ou USB) sous Linux

Lumière sur le projet F3 (oss.digirati.com.br/f3), ce dernier permet de tester des cartes SD/USB stick.
Le programme est relativement simple et se compose de deux utilitaires f3write (pour écrire des fichiers de tests) et f3read pour effectuer les tests de lecture.

Petite présentation par l'auteur

F3 - une alternative à h2testw
Ce projet à commencé lorsque Michel Machado de F3 à acheté une carte de 32GB microSDHC pour son Android (c'était en 2010). Il a remarqué que la carte présentait toujours des défaillances lorsqu'elle était remplie. En faisant quelques recherches sur Google, il est arrivé sur les blogs Fight Flash Fraud et SOSFakeFlash qui recommande tout deux l'usage du logiciel H2testw (voir ici ou ici) pour tester les mémoires flashs.
Michel à téléchargé H2testw et à été immédiatement confronté a deux problèmes:
  1. H2testw est logiciel Windows uniquement
  2. H2testw n'est pas un logiciel open-source.
Cependant, Harald Bögeholz (l'auteur de H2testw), est assez sympa pour inclure un fichier texte décrivant comment fonctionne son programme (ainsi que le générateur de nombre aléatoire).

Ainsi naquis F3 et sa page oss.digirati.com.br/f3 qui est l'implémentation GPLv3 de H2testw réalisé par Michel Machado. Version qui fonctionne sous Linux, Macs, Windows/Cygwin et FreeBSD.
Cette implémentation s'appelle F3, qui est le raccourci de "Fight Flash Fraud" ou "Fight Fake Flash".

Comment installer F3 sous Linux
Si vous diposez d'Ubuntu ou un de ses dérivé (ex: Linux Mint), un simple apt-get fera l'affaire :-)

sudo apt-get install f3

Utiliser f3
F3 se compose de deux programme f3write et f3read.
F3write est destiné à remplir votre périphérique avec des fichiers de données (attention, il rempli l'espace disponible). f3write remplit le système de fichier avec des fichiers de 1GB nommés N.h2w, où N est un numér.
F3read relit les fichiers et fait une validation du contenu, c'est ainsi que l'on détecte les corruptions.

Voici un exemple pratique (par l'auteur)
$ ./f3write /media/5EBD-5C80/
Free space: 28.83 GB
Creating file 1.h2w ... OK!
Creating file 2.h2w ... OK!
Creating file 3.h2w ... OK!
Creating file 4.h2w ... OK!
Creating file 5.h2w ... OK!
Creating file 6.h2w ... OK!
Creating file 7.h2w ... OK!
Creating file 8.h2w ... OK!
Creating file 9.h2w ... OK!
Creating file 10.h2w ... OK!
Creating file 11.h2w ... OK!
Creating file 12.h2w ... OK!
Creating file 13.h2w ... OK!
Creating file 14.h2w ... OK!
Creating file 15.h2w ... OK!
Creating file 16.h2w ... OK!
Creating file 17.h2w ... OK!
Creating file 18.h2w ... OK!
Creating file 19.h2w ... OK!
Creating file 20.h2w ... OK!
Creating file 21.h2w ... OK!
Creating file 22.h2w ... OK!
Creating file 23.h2w ... OK!
Creating file 24.h2w ... OK!
Creating file 25.h2w ... OK!
Creating file 26.h2w ... OK!
Creating file 27.h2w ... OK!
Creating file 28.h2w ... OK!
Creating file 29.h2w ... OK!
Free space: 0.00 Byte
Average Writing speed: 2.60 MB/s

$ ./f3read /media/5EBD-5C80/
                  SECTORS      ok/corrupted/changed/overwritten
Validating file 1.h2w ...       0/  2097152/      0/      0
Validating file 2.h2w ...       0/  2097152/      0/      0
Validating file 3.h2w ...       0/  2097152/      0/      0
Validating file 4.h2w ...       0/  2097152/      0/      0
Validating file 5.h2w ...       0/  2097152/      0/      0
Validating file 6.h2w ...       0/  2097152/      0/      0
Validating file 7.h2w ...       0/  2097152/      0/      0
Validating file 8.h2w ...       0/  2097152/      0/      0
Validating file 9.h2w ...       0/  2097152/      0/      0
Validating file 10.h2w ...       0/  2097152/      0/      0
Validating file 11.h2w ...       0/  2097152/      0/      0
Validating file 12.h2w ...       0/  2097152/      0/      0
Validating file 13.h2w ...       0/  2097152/      0/      0
Validating file 14.h2w ...       0/  2097152/      0/      0
Validating file 15.h2w ...       0/  2097152/      0/      0
Validating file 16.h2w ...       0/  2097152/      0/      0
Validating file 17.h2w ...       0/  2097152/      0/      0
Validating file 18.h2w ...       0/  2097152/      0/      0
Validating file 19.h2w ...       0/  2097152/      0/      0
Validating file 20.h2w ...       0/  2097152/      0/      0
Validating file 21.h2w ...       0/  2097152/      0/      0
Validating file 22.h2w ...       0/  2097152/      0/      0
Validating file 23.h2w ...       0/  2097152/      0/      0
Validating file 24.h2w ... 1916384/   180768/      0/      0
Validating file 25.h2w ...  186816/  1910336/      0/      0
Validating file 26.h2w ...       0/  2097152/      0/      0
Validating file 27.h2w ...       0/  2097152/      0/      0
Validating file 28.h2w ...       0/  2097152/      0/      0
Validating file 29.h2w ...   28224/  1705280/      0/      0

  Data OK: 1.02 GB (2131424 sectors)
Data LOST: 27.81 GB (58322336 sectors)
        Corrupted: 27.81 GB (58322336 sectors)
 Slightly changed: 0.00 Byte (0 sectors)
      Overwritten: 0.00 Byte (0 sectors)
Average Reading speed: 9.54 MB/s

L'exemple ci-dessus indique que la carte Flash est sacrément corrompue. Plus de 27Go de données sont corrompu.

Localiser le /media
Comme vous pouvez le constater dans l'exemple, la carte SD est montée dans le répertoire /media. Le périphérique est directement accessible via /media/5EBD-5C80/
La valeur 5EBD-5C80 change d'un périphérique Flash à l'autre....

Chez MCHobby, nous sommes plutôt accros à Linux Mint. Dans ce cas, la carte SD n'est pas montée dans /media/5EBD-5C80 mais dans /media/votre_login_utilisateur/5EBD-5C80