How to integrate GPIO input into django?

Hi, I want to use django on a raspberry pi to show a website, which keeps track of numbers, that are entered on a keypad, which is attached to the raspberry pi via GPIO. I have been able to set up django to serve a website and I have a python script that reads the GPIO from the raspberry and prints out the number that was typed on the console.

But I don’t know where to put the python code inside of django. I tried putting the keypad code in a view, but that failed, probably because there is a while true loop to read the GPIO input all the time. I found this: python - Raspberry Pi and Django - Background check GPIO Button - Stack Overflow but they seem more advanced and I don’t understand the answers.

Is “Celery” what I need? Or can I use “GPIO.add_event_detect” and where would I put that in my django files? Maybe someone can point me in the right direction. Sorry if this is stupid, I am new to this…

This is the keypad code I want to integrate:

import RPi.GPIO as GPIO
import time

L1 = 5
L2 = 6
L3 = 13
L4 = 19

C1 = 26
C2 = 16
C3 = 25
C4 = 21

GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM)

GPIO.setup(L1, GPIO.OUT)
GPIO.setup(L2, GPIO.OUT)
GPIO.setup(L3, GPIO.OUT)
GPIO.setup(L4, GPIO.OUT)

GPIO.setup(C1, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(C2, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(C3, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(C4, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

def readLine(line, characters):
    GPIO.output(line, GPIO.HIGH)
    if(GPIO.input(C1) == 1):
        print(characters[0])
    if(GPIO.input(C2) == 1):
        print(characters[1])
    if(GPIO.input(C3) == 1):
        print(characters[2])
    if(GPIO.input(C4) == 1):
        print(characters[3])
    GPIO.output(line, GPIO.LOW)

try:
    while True:
        readLine(L1, ["1","2","3","A"])
        readLine(L2, ["4","5","6","B"])
        readLine(L3, ["7","8","9","C"])
        readLine(L4, ["*","0","#","D"])
        time.sleep(0.3)
except KeyboardInterrupt:
    print("\nApplication stopped!")

None of the above.

You want an external process that reads the keyboard and stores the data somewhere that Django can access on-demand.

I use redis as the communications channel between external processes and Django on my Raspberry Pi projects. It works extremely well for this. You could also use memcached if you don’t need all the features of redis. You can even use a database like PostgreSQL if you’ve got a physical disk (not just the SD card or flash drive) attached to the Pi.

Thanks!

So I would have the python script running separatly from django and have it write the numbers to a database, where django can access.

I will look for some tutorials to work with redis as you suggest. But as I understand, it stores data only in the ram, so if the raspberry would crash, the data would be gone, right? And why would I need a harddrive if I use a different db that django and the python script share? Could I also just write to the “build in” SQlite of django from my python script?

Using the term “database” very loosely, yes.

Redis does back up its data store to permanent storage, but no, it’s not intended to be the final repository of information. So you are correct - you want something to write that to a more persistent storage if that’s what you need. (In my case, I’m collecting sensor readings. The Django view reads the data from redis and writes data as necessary to the database.)

SD cards and USB flash drives have very limited lifespans for writes. If you’re writing to an SD card consistently (as in frequent database commits), the life expectancy of your SD card will be measured in months. (And I have a stack of dead SD cards and USB flash drives to show for it…)

SQLite isn’t really designed for multiple, concurrent access from multiple processes. If you’re only writing to a database from one process and reading it from another, you should generally be ok. Any risk here will be based on how much your Django app is also going to rely upon writing to that database.

Thank you very much for your detailed answers! I will try to figure it out :slight_smile:

I am a bit further on this project now, but stuck again :frowning:

I have the Arduino send its values via http request and I can also process them with django, but I can’t figure out how to get them in the database. I found out how to create a web from and store data that was entered, but I can’t figure out how to skip the “web-frontend” part to directly store the data. I assume I still need to use some kind of “view”… but I am a bit lost :frowning:

Specifically, and in detail, how are you doing this?

If the Arduino is sending data in via http request, then Django is already receiving that request and dispatching the data to the view.

In general, your view can create instances of models - there’s no requirement that a form be involved.

Than you very much for your help!

I have this function in my views.py (and this is all I have so far):

@csrf_exempt
def keypad():
    if request.method == 'POST':
        amount = request.POST['amount']
        usercode = request.POST['usercode']
        return HttpResponse("received amount: " + amount + " and usercode: " + usercode)

and I know it works, because the arduino processes the response from django.

So now I would need a model in my models.py and create an instance of that model within the function of my views.py?

Correct. (And you want to make sure the table exists too - typically by using the makemigrations and migrate commands.)

Ok, so now I tried this:

urls.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', views.index, name="home"),
    path('keypad/', views.CreateKeypadPost, name='keypad'),

models.py

class KeyPad(models.Model):
    amount = models.IntegerField()
    usercode = models.CharField(max_length=50)

and views.py

class CreateKeypadPost():
    fields = ('message',)#,'group')
    model = models.KeyPad

    @csrf_exempt
    def keypad():
        if request.method == 'POST':
            amount = request.POST['amount']
            usercode = request.POST['usercode']
            transaction = KeyPad(amount=amount, usercode=usercode)
            transaction.save()
            return HttpResponse("received amount: " + amount + " and usercode: " + usercode)

but it fails with

path("keypad/",views.CreateKeypadPost.as_view(),name="create"),
AttributeError: 'function' object has no attribute 'as_view'

Is my class CreateKeypadPost () missing some argument, and what would it be? I am not even sure where to look for options what kind of classes can be used here. Or am I completely off the track…?

This is a view.

Why are you trying to convert this to a CBV?

To be honest I wasn’t aware that this would be converting something and I don’t know what other options there are. How would I use django without using a view?

Can you maybe point me in the direction which concepts I should understand? I don’t even know what to look for, since all instruction I find seem to be web-frontend-based.

You are using a view.

This:

is a view. It is a Function-Based View.

It’s actually what you start with when you work your way through the tutorial. See Writing your first Django app, part 3 | Django documentation | Django

(If you haven’t worked your way through either of the Official Django Tutorial or the Django Girls Tutorial, you should. Otherwise, you’re likely missing a number of important concepts.)

Sorry, I got confused after reading so much… for me there is just so much information… I did not know the django girls tutorial, this is really good to read, much easier than the official documentation. Thanks for the tip!

Now I figured out how to process the data from the post request and save it to the database :slight_smile:

1 Like