Du contrôle d’un afficheur à led tricolores avec un raspberry Pi

Position du problème

On désire afficher des chiffres sur un écran à LED, 16 par 32, tricolores. Ici, cet écran vient de chez HackSpark et se pilote via des librairies fournies par le vendeur. En l’occurrence, mon collègue désire en savoir un peu plus et contrôler plus précisément son affichage. Je lui propose donc mon aide.

On va donc piloter en Python, via le port série /dev/ttyUSB0 l’affichage. Le code présenté ici n’a pas vocation a être beau, il a juste vocation à être pédagogique.

Piloter l’affichage directement depuis une console clavier/écran

On se limite ici au choix de la couleur et à un affichage assez basique : allumé ou éteint. Mon collègue désire programmer lui même le reste de la logique.

Le vendeur nous informe que pour communiquer avec l’écran, il faut envoyer un premier octet dont la valeur doit être 2, puis un octet dont la valeur est 1, puis les quantités de rouge, vert, bleu, sur 3 octets pour chacune des leds, ce qui nous donne un tableau de 3x32x8+2=1538 octets. Ce tableau est initialisé avec bytearray de Python. On crée également un objet série ser=serial.Serial('/dev/ttyUSB0',baudrate=2000000) qui permettra d’écrire (lire envoyer) des données sur le port série de l’écran. Pour plus de lisibilité, j’ai séparé en deux fonctions les opérations d’allumage et d’extinction. Le code suit :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/usr/bin/python
import serial
from time import sleep 
#Creation d'un objet serie
ser=serial.Serial('/dev/ttyUSB0',baudrate=2000000) 
# Creation d'un tableau blanc
# Ce tableau d'octet contient un premier octet dont la valeur est 2 suivi d'un octet a 1.
tp=bytearray(1538)
tp[0]=chr(2)
tp[1]=chr(1) 
def allumer():
  for i in xrange(2,len(tp),3):
    tp[i]=chr(00)
    tp[i+1]=chr(60)
    tp[i+2]=chr(40)
  ser.write(tp)

def eteindre():
  for i in range(2,len(tp)):
    tp[i]=chr(0)
  ser.write(tp)

allumer()
sleep(5)
eteindre()

Pour la suite, on désire commander cela à partir d’un téléphone en Wifi, ou par le réseau. Il faut donc permettre au RaspberryPi de communiquer de cette façon. En l’occurrence, ici on choisit arbitrairement lighttpd. Dans le dossier /var/www/ on rajoute un fichier index.html :

<!doctype html>
<html>
<head>
  <meta charset="utf8">
  <title>Une page de démonstration pour le serveur web</title>
  <script src="http://blog.thetys-retz.net/post/2013/07/18/prototype.js"></script>
</head>
<body>
  <h1>Une page de démo</h1>
  <form>
    <input type="button" value="On" onclick="go('a')" style="font-size:200%;">
    </br>
    <input type="button" value="Off" onclick="go('e')" style="font-size:200%;">
  </form>
  <script type="text/javascript"> function go(qry) {
    new Ajax.Request('test.py?q='+qry,{method: 'GET'}); }
  </script>
</body>
</html>

On n’oublie pas de télécharger Prototype.js qui nous permettra de très facilement concevoir la page web ci-dessus et l’appel discret à la page qui contient le code.

On ajoute un fichier exécutable test.py qui complète le premier code en Python :

# all of our code now lives within the app() function which is called for each http request we receive
def app(environ, start_response):
  # start our http response
  start_response("200 OK", [("Content-Type", "text/html")])
  # look for inputs on the URL
  i = urlparse.parse_qs(environ["QUERY_STRING"])
  yield (' ')
  # flup expects a string to be returned from this function
  # if there's a url variable named 'q'
  if "q" in i:
    if i["q"][0] == "a":
      allumer() 
      # Turn it on
    elif i["q"][0] == "e":
      eteindre() 
      # Turn it off 
  #by default, Flup works out how to bind to the web server for us, so
  #just call it with our app() function and let it get on with it WSGIServer(app).run()

On n’oubliera pas d’enlever les 3 dernières lignes du code précédent.

copie_page_web.PNG

Pour que cette page soit pleinement fonctionnelle, on n’oublie pas de rajouter :

fastcgi.server = (
    ".py" => (
      "python-fcgi" => (
        "socket" => "/tmp/fastcgi.python.socket",
        "bin-path" => "/var/www/test.py",
        "check-local" => "disable",
        "max-procs" => 1)
      )
    ) 

et "mod_fastcgi", dans server.modules = (.

Sous Debian, et donc sous Rasbian, /dev/ttyUSB0 est gid: dialout. Le plus simple ici est de donner à l’uid: www-data la permission d’utiliser ce périphérique avec usermod -aG dialout www-data.

L’idée du serveur est très inspirée de Controlling a Raspberry Pi’s GPIO over the network de Dav’s bit o the web

Un portail très captif

La dernière étape consiste à créer un point d’accès : pour cela, on utilise hostapd et dnsmasq. Le premier sert à créer le point d’accès wifi et le second permet de distribuer une adresse réseau aux clients et de les rediriger systématiquement sur la page d’accueil.

Tagcloud
Ubuntu automontage kernel authentification orgcamp NetworkManager Internet identification PSL Science-Fiction JDLL postfix Opinions Gentoo Éducation Iptables OSM rubber sympa GNU-Linux Educ Libre PlanetUbuntuFr PlanetUbuntu nfs UbuntuFr Mathématiques auto hébergement Python compilation dovecot Mozilla Mandriva Emacs Perso eCryptfs April Drupal beamer automatisation shell DNS Voile Mutt orgmode Société LDAP Réflexions SNCF configuration Épinay redmine sqlite php CAPES Spam OpenVPN CPL dotclear ISN vélo mail installation OpenSSL GCC X.org sudo ArchLinux fail vserver IPv6 Debian Coups de gueule LaTeX Admin Sys Free Parinux RaspberryPi Vie numérique Essai sieve gpg vim fun Randonnée SPF OpenStack Informatique Coup de gueule Lectures Paris Web imap RATP Technique CLI code KDE roundcube Munin