Borne indicative de pollution
L’idée initiale est assez simple: Récupérer l’indice de pollution sur Airparif et piloter une led RGB Neopixel afin de lui donner une couleur correspondant à l indice récupéré…
La diode RGB Neopixel:
Cette diode distribuée par Adafruit contient en fait 3 diodes (une rouge, une verte et une bleue) ainsi qu’un petit composant électronique (ws2811) permettant de commander, en utilisant un seul fil, les niveaux de ces 3 diodes et d’obtenir ainsi n’importe quelle couleur résultant du mélange des 3 couleurs primaires.
Le brochage de la Diode est le suivant:
La commande de la diode se fait via la broche « Data In ». La broche « Data out » permet de chainer plusieurs diodes
Pilotage de la diode RGB Neopixel avec le Raspberry Pi:
Ce pilotage se fait en utilisant la broche 12 du Raspberry Pi (GPIO 18). D après ce que j ai pu trouver sur le Net, c’est actuellement l’unique GPIO permettant en Python de fonctionner en PWM de façon hardware (utilisation du contrôleur DMA du Raspberry Pi – le BCM2825 si j ai bien compris).
Je m’explique, il est possible de faire varier le niveau de sortie de toutes les broche GPIO de façon « logiciel », en faisant une boucle dans un programme tournant sur le Raspberry Pi, mais étant donné la vitesse du processeur se trouvant sur le Raspberry Pi, la fréquence du signal de sortie n’est pas assez élevée pour piloter correctement la diode. Cette diode Neopixel nécessite en effet un signal de fréquence 800 Khz
Compilation et installation de la librairie (rpi_ws281x) permettant le pilotage de la diode Neopixel
Ouvrir un terminal sur le Raspberry Pi et taper les commandes ci-dessous:
sudo apt-get update
sudo apt-get install build-essential python-dev git scons swig
git clone https://github.com/jgarff/rpi_ws281x.git
cd rpi_ws281x
scons
cd python
sudo python setup.py install
L’installation pour Python 2 s’est bien passée, par-contre, l’installation pour python 3 a planté (erreur gcc à investiguer plus tard)
Le code python
[pastacode lang= »python » message= »Pollution RVB » highlight= » » provider= »manual » manual= »import%20time%0Afrom%20neopixel%20import%20*%0Aimport%20urllib2%0Aimport%20re%0A%0A%23%20pour%20envoyer%20les%20infos%20de%20debug%20sur%20la%20sortie%20standard%0A%23%20Commenter%20pour%20suppression%20des%20messages%0ADEBUG%20%3D%20True%0A%0A%23%20Configuration%3A%20du%20%22ruban%22%20de%20LED%0A%23%20Dans%20le%20cas%20pr%C3%A9sent%2C%20je%20n%20utilise%20qu%20une%20LED%0A%0ALED_NB%20%20%20%20%20%20%20%20%20%3D%201%20%20%20%20%20%20%20%23%20Nombre%20de%20LED%20neopixel.%0ALED_PIN%20%20%20%20%20%20%20%20%3D%2018%20%20%20%20%20%20%23%20GPIO%20pin%20connectee%20au%20pixels%20et%20qui%20supporte%20le%20PWM%20hardware%0ALED_FREQ_HZ%20%20%20%20%3D%20800000%20%20%23%20LED%20signal%20frequency%20in%20hertz%20(800khz)%0ALED_DMA%20%20%20%20%20%20%20%20%3D%205%20%20%20%20%20%20%20%23%20Cannal%20DMA%20a%20utiliser%20pour%20generer%20le%20signal%20PWM%20%20%0ALED_LUMINOSITE%20%3D%20255%20%20%20%20%20%23%200%20-%3E%20sombre%20%20255%20forte%20luminositee%0ALED_INVERT%20%20%20%20%20%3D%20False%20%20%20%23%20True%20pour%20invertir%20le%20signal%20%0A%0A%23%20Definition%20des%20couleurs%20%0Arouge%20%20%20%3D%20%20%20%20%20%20%20%5B0%2C0%2C255%5D%0Aorange%20%20%3D%20%20%20%20%20%20%20%5B0%2C64%2C200%5D%0Ajaune%20%20%20%3D%20%20%20%20%20%20%20%5B0%2C128%2C200%5D%0Avert%20%20%20%20%3D%20%20%20%20%20%20%20%5B0%2C128%2C0%5D%0Ableue_vert%20%3D%20%20%20%20%5B255%2C128%2C0%5D%0Ableu%20%20%20%20%3D%20%20%20%20%20%20%20%5B255%2C0%2C0%5D%0Aviolet%20%20%3D%20%20%20%20%20%20%20%5B255%2C0%2C200%5D%0Arose%20%20%20%20%3D%20%20%20%20%20%20%20%5B%5D%0A%0A%23%20Definition%20d%20un%20tableau%20de%20cl%C3%A9%20et%20valeur%20(dictionnaire)%0A%23%20pour%20contenir%20les%20indices%20de%20pollution%20pour%20differentes%20periodes%20(jour%2C%20demain%2C%20…)%0Aindice_polution%20%3D%20%7B%7D%0A%0Ajour%20%3D%20None%0A%0A%0A%23%20Donne%20la%20couleur%20%22couleur%22%20(tableau%20a%203%20elements%2C%20la%20valeur%20du%20bleu%2C%20la%20valeur%20du%20vert%2C%20la%20valeur%20du%20rouge)%0A%23%20a%20la%20led%20se%20trouvant%20a%20la%20position%20%22led_num%22%20dans%20le%20ruban%20de%20leds%20%0Adef%20led_couleur(led_num%2Ccouleur)%3A%0A%20%20%20%20ruban.setPixelColorRGB(led_num%2Ccouleur%5B0%5D%2Ccouleur%5B1%5D%2Ccouleur%5B2%5D)%0A%20%20%20%20ruban.show()%0A%0A%0A%23%20fait%20clignoter%20la%20led%20se%20trouvant%20a%20la%20position%20%22led_num%22%20avec%20la%20couleur%20%22couleur%22%0Adef%20led_clignotte(led_num%2Ccouleur)%3A%0A%20%20%20%20for%20i%20in%20range(10)%3A%0A%20%20%20%20%20%20%20%20led_couleur(led_num%2Ccouleur)%0A%20%20%20%20%20%20%20%20time.sleep(0.5)%0A%20%20%20%20%20%20%20%20led_couleur(led_num%2C%5B0%2C0%2C0%5D)%0A%20%20%20%20%20%20%20%20time.sleep(0.5)%0A%0A%23%20Donne%20a%20la%20led%20se%20trouvant%20a%20la%20position%20%22led_num%22%20la%20couleur%20correspondant%20a%20%22niveau_in%22%0A%23%20%20%20%20%20%20%20%20vert%20%3C%2040%0A%23%20%2040%20%3C%20jaune%20%3C%2060%0A%23%20%2060%20%3C%20orange%20%3C%2080%0A%23%20%2080%20%3C%20rouge%20%3C%20100%0A%23%20%20100%20%3C%20rouge%20clignotant%0Adef%20led_niveau(led_num%2Cniveau_in)%3A%0A%20%20%20%20niveau%20%3D%20int(niveau_in)%0A%20%20%20%20if%20niveau%20%3C%2040%3A%0A%20%20%20%20%20%20%20%20if%20DEBUG%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20print(‘vert’)%0A%20%20%20%20%20%20%20%20led_couleur(led_num%2C%20vert)%0A%20%20%20%20elif%20niveau%20%3C%2060%3A%0A%20%20%20%20%20%20%20%20if%20DEBUG%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20print(‘jaune’)%0A%20%20%20%20%20%20%20%20led_couleur(led_num%2C%20jaune)%0A%20%20%20%20elif%20niveau%20%3C%2080%3A%0A%20%20%20%20%20%20%20%20if%20DEBUG%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20print(‘orange’)%0A%20%20%20%20%20%20%20%20led_couleur(led_num%2C%20orange)%0A%20%20%20%20elif%20niveau%20%3C%20100%3A%0A%20%20%20%20%20%20%20%20if%20DEBUG%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20print(‘rouge’)%0A%20%20%20%20%20%20%20%20led_couleur(led_num%2C%20rouge)%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20if%20DEBUG%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20print(‘clignotant’)%0A%20%20%20%20%20%20%20%20led_clignotte(led_num%2C%20rouge)%0A%0A%0A%23%20Recupere%20l’indide%20de%20polution%20a%20Paris%20sur%20http%3A%2F%2Fwww.airparif.asso.fr%0A%23%20Met%20a%20jour%20de%20la%20variable%20globale%20de%20type%20dictionnaire%20%22indice_polution%22%0Adef%20get_indice_polution()%3A%0A%20%20%20%20global%20jour%2C%20indice_polution%0A%20%20%20%20%0A%20%20%20%20try%3A%20page%20%3D%20urllib2.urlopen(%22http%3A%2F%2Fwww.airparif.asso.fr%2Findices%2Fresultats-jour-citeair%23jour%22)%0A%20%20%20%20except%20IOError%2C%20e%3A%0A%20%20%20%20%20%20%20%20print(e.reason)%0A%20%20%20%20%20%20%20%20return%0A%20%20%20%20for%20ligne%20in%20page%3A%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20if%20%22%3C!–%20jour–%3E%22%20in%20ligne%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20jour%20%3D%20%22aujourdhui%22%0A%20%20%20%20%20%20%20%20if%20%22%3C!–%20demain–%3E%22%20in%20ligne%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20jour%20%3D%20%22demain%22%0A%20%20%20%20%20%20%20%20if%20jour%20and%20%22Indice%20de%20l%22%20in%20ligne%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20result%20%3D%20re.search(%22(%3F%3C%3D%3B)%5B0-9%5D%2B%22%2Cligne)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20DEBUG%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print%20(result)%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20result%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20indice_polution%5Bjour%5D%20%3D%20result.group(0)%0A%20%20%20%20%20%20%20%20%20%20%20%20jour%20%3D%20None%0A%20%20%20%20if%20DEBUG%3A%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20for%20j%20in%20%5B’aujourdhui’%2C%20’demain’%5D%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20j%20in%20indice_polution.keys()%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print(%22indice%20de%20polution%20%22%20%2B%20j%20%2B%20%22%3A%20%22%20%2B%20indice_polution%5Bj%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print(%22Pas%20d%20indice%20trouve%20pour%20%22%20%2B%20j)%0A%20%20%20%20%20%20%20%20%0A%0A%23%20Programme%20principal%20%0Aif%20__name__%20%3D%3D%20’__main__’%3A%0A%20%20%20%20try%3A%0A%20%20%20%20%20%20%20%20%23%20Creation%20de%20l%20objet%20NeoPixel%0A%20%20%20%20%20%20%20%20ruban%20%3D%20Adafruit_NeoPixel(LED_NB%2C%20LED_PIN%2C%20LED_FREQ_HZ%2C%20LED_DMA%2C%20LED_INVERT%2C%20LED_LUMINOSITE)%0A%20%20%20%20%20%20%20%20%23%20Intialisation%20de%20la%20librairie%20%20%0A%20%20%20%20%20%20%20%20ruban.begin()%0A%20%20%20%20%20%20%20%20led_num%3D0%0A%20%20%20%20%20%20%20%20while%20True%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20DEBUG%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20print(ruban.getPixelColor(0))%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20get_indice_polution()%0A%20%20%20%20%20%20%20%20%20%20%20%20led_niveau(0%2Cindice_polution%5B’aujourdhui’%5D)%0A%20%20%20%20%20%20%20%20%20%20%20%20time.sleep(10)%0A%20%20%20%20finally%3A%0A%20%20%20%20%20%20%20%20led_couleur(0%2C%5B0%2C0%2C0%5D)%0A%20%20%20%20%20%20%20%20%0A »/]
Impression 3D du boitier Raspberry Pi et de la borne
Le proto en photo :
Projets de développement:
- « Dashboard » mutli LED
- Récupération et monitoring d autres type de donnés sur internet ( Web Services and Co)
- Risque de pluie ds l’heure
- Niveaux Allergènes
- Popularité d un Hashtag twitter
- …
super : je cherchais quelque chose de clair pour faire fonctionner ma bande de led et j’ai tout compris avec votre tuto.
Il me semble en plus qu’il faille arrêter la sortie son qui utilise PWM pour ne pas avoir d’interférences et d’arrêt de l’application.
.
.