Code fonctionnel sauf dans le shell

Bonjour,

Quelque chose doit m’échapper donc je fais appel à votre génie =D

Mon contexte:
Je veux actuellement faire fonctionner un bouton poussoir pour éteindre mon RPi3b+ sous Twister.
J’avais codé une boucle infinie, fonctionnelle mais je ne voulais pas d’une telle solution.

En cherchant je suis tombé sur la détection de front, que je ne connaissais pas.
Je suis tombé sur un morceau de code qui avait pas mal de points communs avec mon projet et je m’en suis inspiré.

J’ai donc deux fichiers, un module avec ma fonction et un main que je voudrais exécuter en autostart.

Mon problème :
Quand je test l’ensemble dans mon IDE, cela fonctionne.
Par contre quand je lance le .py dans mon shell, nada :thinking: enfin si la led du bouton s’allume.

Je vous joins tout ça :

import RPi.GPIO as GPIO
import time
import os

GPIO.setmode(GPIO.BCM)
GPIO.setup(14, GPIO.OUT)
GPIO.setup(3, GPIO.IN)


def my_callback(channel):

    if GPIO.input(3):
        GPIO.output(14, GPIO.LOW)

    else:

        for i in range(5):
            GPIO.output(14,False)
            time.sleep(0.1)
            GPIO.output(14,True)
            time.sleep(0.1)

        GPIO.output(14, GPIO.HIGH)
        time.sleep(2)
        #print("shutdown now")
        os.system("shutdown now")
        GPIO.cleanup()

Et :

import RPi.GPIO as GPIO
import time
import os
import fonctions_bouton

GPIO.setmode(GPIO.BCM)
GPIO.setup(14, GPIO.OUT)
GPIO.setup(3, GPIO.IN)

GPIO.output(14,True)

#GPIO.cleanup()

GPIO.add_event_detect(3, GPIO.BOTH, callback = fonctions_bouton.my_callback)

Merci de m’avoir lu et (j’espère) de votre aide :grin: :+1:

Bonjour,

Il est possible que import fonctions_bouton ne soit pas reconnu.
Je ne vois pas trop l’intérêt d’avoir 2 programmes. Essaye de tout mettre dans le même.

A+

Bonjour,

Merci de ta réponse. A vrai dire j’ai continué de chercher de mon côté et une de mes hypothèses s’est avéré être ce que tu viens de me dire donc j’ai essayé et cela n’a rien donné de plus.

Cela fonctionne très bien dans l’IDE mais pas que je lance mon script.

Pour l’intérêt d’avoir 2 programmes, il est nul actuellement mais j’avais comme idée de créer d’autres fonctions par la suite et j’ai pris l’habitude de séparé mes modules de fonctions et mes programmes.

Encore merci de ton retour en tout cas :+1:

Comment est lancé le script ?
Est-ce avec la même version de Python que l’IDE (car il peut y avoir plusieurs version sur la même machine ?

A+

Oui j’y ai pensé aussi et j’ai donc tenté avec python et python3, le résultat étant exactement le même.
Pour info, les droits d’exécution sont bien mis sur les .py aussi.

Pour le script, je tente d’abord manuellement avec un simple sudo python(ou python3) /le_chemin/script.py
J’ai aussi tenté de le lancer en fond en rajoutant & à la suite, toujours rien de plus.

Merci à toi

Bonjour,

Soit le programme Python est lancé par lui même dans ce cas, il doit être exécutable et contenir le sheebang #!/usr/bin/python dans sa première ligne.
Pour le lancer $ /chemin/fichier.py

Soit le programme est lancé par l’appel de python, dans ce cas le sheebang n’est pas nécessaire et il n’a pas nom plus besoin d’être executable
Pour le lancer $ python /chemin/fichier.py

Dans les 2 cas, le programme doit envoyer de messages d’erreur en cas de problème.
Si rien ne se passe, ajouter des commandes print (voir syntaxe en fonction de la version de Python) pour visualiser/debugger.

Edit: le sudo ne sert que lorsque c’est obligatoirement root qui doit exécuter le programme sinon c’est inutile
A+

Bonjour
en fait pour inclure fonctions_bouton en import
Il faut créer un répertoire ou tu places tes scripts de librairie et inclure le chemin du repertoire
j’ai un script pylib3.py dans le répertoire /home/$USER/py/Lib
et dans mes script qui l’utilisent j’ai
chemin = os.path.dirname(os.path.realpath(file))
if chemin not in sys.path:
sys.path.append(chemin)
try:
import Lib
except ImportError:
print (« Erreur: %s/pylib3.py absent » % (chemin))
sys.exit(1)
from Lib import pylib3

Le programme sera lancé par un script bash, donc je n’ai pas ajouter de shebang dans le programme.

Ainsi dans mes test, comme marqué plus haut, j’utilise bien l’appel de python.
Je ne sais pas pourquoi je n’ai pas pensé à utiliser de print, je vais voir si je peux avoir plus d’infos.

Merci à toi de prendre autant de temps.

Pour le sudo c’est juste une mauvaise habitude de ma part :grimacing:

Dans le cas où mon programme et mon script de librairie sont dans le même répertoire, je n’ai pas besoin d’inclure le chemin du répertoire, non ?

Dans mon cas, fonctions_bouton.py et monprogramme.py sont dans le même répertoire.
Donc je n’ai pas précisé le chemin pour mon import. Je me goure ?

Comme dit précédemment, j’ai aussi testé un programme incluant l’ensemble, donc sans import.
Le soucis vient donc d’ailleurs, enfin c’est ce que j’en déduis.

Merci de ta réponse :grinning: :+1:

Quand tu fais un import il faut obligatoirement qu’il soit dans le path système.
import ce n’est pas un simple include, fonctions_bouton.py a beau être dans le même répertoire que ton script il n’est pas dans la liste des librairies.
Même quand le script python est appelé par un bash ou par crontab, la bonne pratique est de mettre le shebang, et dans le bash tu as juste à mettre /chemin/programme .py

Bonjour @Mik91390

J’étais entièrement d’accord avec toi jusqu’à je fasse ce test sur un poste de travail:

Fichier /tmp/truc/a.py

#!/usr/bin/python3
import b
b.pw()

Fichier /tmp/truc/b.py

print ("Hello")
def pw ():
    print ("World")

Dans une console

$ chmod +x /tmp/truc/a.py
$ /tmp/truc/a.py
Hello
World

Je remarque que:

  • a.py doit être executable
  • a.py doit avoir le shebang
  • a.py et b.py doivent être dans le même repertoire
  • b.py n’a pas besoin d’être dans un répertoire connu du PATH !
  • b.py n’a pas besoin d’être exécutable
  • b.py n’a pas besoin du shebang

Je ne sais pas si ce fonctionnement est propre à mon environnement ou à Python3, ou que Python devient de plus en plus tolérant. Je suis persuadé qu’il y a quelques temps sur un ancien OS avec une version Python2.x cela ne fonctionnait pas si ‹ facilement ›.

A+

Je te remercie de l’éclaircissement. Je suis donc loin du best practice.

Ceci dit, ce n’est pas ça qui créer mon problème.
Pour avoir tester mon code actuel avec une fonction test servant à faire un simple calcul de tva (par exemple), cela fonctionne.
Je peux en déduire que monprogramme.py arrive bel et bien à importer fonctions_bouton.py et à utiliser une des fonctions présente.

Cela sans être dans le path system, sans shebang ect.
As-tu une idée ?

Merci à vous, vous êtes top

Je viens d’apporter les modifications et je n’ai pas plus de résultats.

J’en viens à me demander si la détection de front est bien fonctionnel depuis le shell.
J’ai l’impression que le programme se lance et s’arrête et donc il n’y a pas de surveillance des GPIO.

Cela me dépasse, pourquoi cela fonctionne t-il dans l’IDE ?

Je vais devoir me rabattre sur une boucle infinie, je ne suis pas fan de l’idée mais après avoir fait un test cela n’est pas gourmand en ressources.

Je reste à l’écoute bien sur.

Regarder du coté de la syntaxe du callback ?

sinon migrer vers la librairie gpiozero qui semble plus simple d’utilisation ?

https://www.raspberrypi.org/forums/viewtopic.php?t=201747

A+

Je suis déjà tombé sur l’alternative avec lambda x:, je viens de la retester et idem.
Fonctionne dans l’IDE et c’est tout.

Je vais jeter un oeil à gpiozero et je ferais un retour.
Merci :+1:

Bon alors bilan ! :grin:

La librairie gpiozero fonctionne très bien et elle m’a aussi permet de savoir comment faire fonctionner mon code avec RPi.GPIO.

J’ai effectué plusieurs test, je me permets donc (puis si ça peut intéresser quelqu’un un jour):

  1. Le programme avec la librairie rpi.gpio c’est que ça fonctionnait bien dans l’IDE mais pas via le shell. Pour une raison que j’ignore, le programme se lançait et devait sûrement s’arrêter malgré que le processus qui était quand même existant.

  2. Avec gpiozero, une fois lancé (IDE ou Shell), le processus reste bien actif en fond et écoute bien les inputs des gpio.

  3. J’ai compris que cela fonctionnait grâce à la fonction pause() et bien sûr mon code avec la lib rpi.gpio fonctionne aussi très bien si j’importe cette fonction et que j’y fait appel.

J’ai juste une question, mon tout premier code (qui fonctionne grâce à une boucle infinie) est beaucoup moins gourmant qu’en utilisant une des deux lib.

Que me conseillez-vous d’utiliser plus du coup ? boucle infinie or not ?

Encore merci à vous @jelopo et @Mik91390 pour votre aide.

Je vous laisse le programme test avec la lib gpiozero :

#!/usr/bin/python3

from gpiozero import Button, LED
from signal import pause
from subprocess import check_call

def reboot():
    check_call(['sudo', 'reboot'])
    
def poweroff():
    check_call(['sudo', 'poweroff'])
 
def led_blink():
    led.blink(on_time=0.2, off_time=0.2, n=8)
 
 
bouton = Button(3, hold_time=3)
led = LED(14)

led.on()

bouton.when_pressed = led_blink
bouton.when_released = poweroff
bouton.when_held = reboot

pause()

hello,

il me semblais que lorsque l’on utilisais Rpi.GPIO on devais initialiser les pin en entrée à 0 avec :

GPIO.setup(channel, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

ou a 1 avec

GPIO.PUD_UP

l’utilisation de

GPIO.add_event_detect(channel, GPIO.BOTH, callback = my_callback)

permet de se passer de cette forme d’initialisation ?

Je n’ai pas souvenir d’avoir vu une telle obligation et pendant ma phase de test j’ai pu remarqué que l’état initial était d’office à 0.

Dans mon cas, je cherchais à détecter un changement d’état, peu importe celui-ci.

Je ne suis pas expert non plus hein :sweat_smile:

Bonjour @bof,

Désolé je n’en sais pas plus. Toutes mes connaissances sur ce sujet proviennent des moteurs de recherches… :sweat_smile:

A+

hello jelopo,

de toutes façon l’init à zéro avec cette commande doit pas peser bien lourd et apparemment ça empêche le signal de « flotter » ( comme l’ajout d’une résistance entre le pin et le bouton)
Si GPIO.BOTH prends en compte ce flottement le résultat pourrait être aléatoire.

sur ce site : https://deusyss.developpez.com/tutoriels/RaspberryPi/PythonEtLeGpio/ ( lol mon cerveau aussi tire une grande partie de sa « mémoire » du web :wink: ) il rajoute aussi un timer pour supprimer l’effet « rebond »

GPIO.add_event_detect(channel, GPIO.BOTH, callback=my_callback, bouncetime=75)