Strange Issue with RPi.GPIO module & Django virtual env

Hi experts! Hoping you can help me figure this out.

Using RPi.GPIO v0.7.0 (apparently the latest), python 3.7.3, pip 18.1, Django 3.1.5 - all installed on a Raspberry Pi 4.

As one of my initial tests, I created a python script to simply turn on/off a couple of pumps through the Raspberry Pi GPIO pins. That works just fine. My next step was to incorporate that logic in a view that I could invoke though an HTML page - my application… The logic is a forever loop with a keyboard interrupt to stop the program.

My application is a set of models that contain information that I use to control how much water flows through a pump. The goal is to use information in tables to drive the behavior of these pumps.

I created a virtualenv for my Django application, constructed a models.py, views.py, static HTML/CSS, urls.py, and updated settings.py.

Using django, I am able to successfully perform CRUD ops on my database tables, so from that perspective everything is working how I want it to.

I added an addition definition in my views.py file to use RPi.GPIO to control a couple of pumps. From my HTML page, I can select a link that causes that view to be invoked. The actual code to drive the GPIO pins is the same as the one I used in my earlier tests (that way I can ensure no odd logic errors creeped in); ultimately of course the goal is to use tables that contain information on how to drive these pumps.

In my view, I used a for loop to drive the pumps through several iterations. Note this is not what will happen in the finished app, but baby steps…

Now here’s the issue. I can hear/feel the first of two pumps click once like it’s trying to start, but that’s it. I added a few print() statements in the view and I can see the output in my runserver console output, so I am confident that the code is being properly exercised. But I am befuddled why the pump motors won’t work for the duration I programmed.

Now the really puzzling part…

The same logic outside the virtual env workss I expect, i.e., the pump motors start and stop at the prescribed intervals.

It seems to me that there is some weird discrepancy in how the RPi.GPIO module behaves in a virtual env versus outside, but I am not clear how I can figure out what is going on.

I did a “pip freeze” in the venv and outside it. I saw that there are a significant number of modules in the installation outside the venv compared to that inside the venv. I guess that’s something I need to explore further and see if there are additional modules that need to be installed inside the venv.

In the meantime, any diagnostic tips that you could share with me will be gratefully appreciated.

This is my first time using this forum, so my apologies if I did something against the rules.!!

inside_venv

UPDATE: Googling indicates that RPi.GPIO must be run as root, therefore I will try running the server using:

sudo python manage.py runserver

and see what happens.

SOLVED!! Thanks to YouTuber @HackedExistence for tips I could use.

  1. Create an external module (not in a Django project virtual env).

    #!/usr/bin/python
    import sys
    from time import sleep
    import RPi.GPIO as GPIO

    unique to the motor driver I am using

    PWMA = 12 # GPIO18
    AIN1 = 16 # GPIO23
    AIN2 = 18 # GPIO24
    STNDBY = 22 # GPIO25

    GPIO.setmode(GPIO.BOARD)

    pwmFreq = 200

    GPIO.setup(PWMA, GPIO.OUT) # PWMA
    GPIO.setup(AIN2, GPIO.OUT) # AIN2
    GPIO.setup(AIN1, GPIO.OUT) # AIN1
    GPIO.setup(STNDBY, GPIO.OUT) # STDBY

    pwma = GPIO.PWM(PWMA, pwmFreq)
    pwma.start(100)

    def motorStart():
    GPIO.output(STNDBY, GPIO.HIGH)

    def motorStop():
    GPIO.output(STNDBY, GPIO.LOW)

    def main(argv):
    pump = sys.argv[1]
    motorStart()
    for i in range(0,2,1):
    sleep(4)
    GPIO.output(AIN1, GPIO.LOW) # AIN1 low
    GPIO.output(AIN2, GPIO.HIGH) # AIN2 high
    sleep(2)
    GPIO.output(AIN1, GPIO.LOW)
    GPIO.output(AIN2, GPIO.LOW)
    motorStop()
    GPIO.cleanup()
    print(pump) # info sent back to the Django view
    exit()

    if name == “main”:
    main(sys.argv[1:])

  2. Create a function in views.py. This will be invoked through a button press in a template motor_list.html. As you might imagine, motor_list.html renders contents of a Motor table defined in models.py

    from . import runMotor
    from .models import Motor
    def motor_process(request, id):
    motor = Motor.objects.get(id=id)
    runMotor.process_motor(request, id)
    return redirect(“motor_list”)

  3. Create a django module runMotor.py

    import subprocess
    from .models import Motor

    def process_motor(request, id):
    motor= Motor.objects.get(id=id)
    motorID = str(motor.motor)

     output = subprocess.check_output(['sudo', '/home/pi/Projects/MotorControl/motor.py', motorID])
     print( output) # whatever the motor.py returns
     return True
    
  4. Finally in motor_list.html, I have an entry to hook into motor_process()

run motor

Things to improve upon:

  • use subprocess.Popen() so I can see any intermediate output from the motor.py script in my server console log (But I haven’t figured out exactly how to use that).

I’ve had to do something like this in the past. In my case, the external controlling code is persistent - starts at boot and runs as long as the Pi is running. I use Redis to manage communication between the two. I use two Redis lists to communicate, each process writes to one list and listens to the other.

Guess I need to do some more learning. Not sure what Redis is. In my case, the motor runs only when desired. My main goal was to get all the plumbing done, and now I can refine what the app does. In any event, managing the Pi with Python/Django has been quite interesting, and actually quite simple to do once I got through the basics.

The “pip freeze” differences inside and outside a virtual env are still interesting to me, and I haven’t got a clear understanding of why that is so. I should have kept better track of what I installed inside and outside the virtual env!

Yeah and I got the Popen to work as I expected. Not complicated at all. Building the cmd line was the only thing I needed to pay attention to.

Could you please share your complete solution with Popen?