1

I am working on an IoT project which is like smart attendance and cashless payment system for schools and colleges. I am using Raspberry Pi 3 as my client machine and DigitalOcean to host PostgreSQL and core Django project. In addition to Raspberry Pi, I am using EM-18 RFID reader and R305 fingerprint reader. Now, as of now, I have built a CLI utility to use project but it's not really convenient for a person who is not that familiar with either Linux or shell in general.

Now my problem lies in my current code logic. For instance, If I want to add a student information along with their RFID/Fingerprint information to the database, I first scan for RFID tag assigned to them. Check if that tag is already in the database or not, if not then ask for their information. After this step, I again ask them to tap the same card again to enroll their fingerprint. All of these processes work without any issues on CLI. I am not able to figure out how to let the operator know which step to execute now. Although I have built a web interface in Django and it's neither user-friendly nor interactive. I think I have to use JSON/AJAX to do that, but I have no idea on how to do it.

Dhaval Savalia
  • 495
  • 5
  • 17

2 Answers2

4

Please read this not as an answer but more like a longer comment ;)

So first read into the MVC concept (for example: https://djangobook.com/model-view-controller-design-pattern/) to understand how web interfaces interact with the rest of the code.

The classical django way would be to

  1. create a form (in forms.py) based on your model.
  2. you would write some html to display the form on a website
  3. validate the form input in views.py
  4. send back an the results and display them (again html)

when you would like to do that with AJAX its a little extra work but the result will be worth it. (for example: How to POST a django form with AJAX & jQuery)

you will call a specific url which you first initialise in your urls.py file (path('checkForm', views.checkForm, name='checkForm'), in django 2.0)

the url points to a function defined in views.py with the name checkForm (same as the url path in this example but you can call it whatever you want). Inside this function you can write your python code or call the functions from there to execute your db quires, validations etc. Send back a response with the results of your code.

success: function(data, status) { $('#whatever').html(data); alert("whatever"); }

"data" is here the response from the server. I hope I gave you a hint in the right direction. Please ask if you get stuck somewhere.

p.s. I have no idea how to send the fingerprint data via http, check if there is some library.

x=data.read(12).decode("utf-8")
tag_id_in = x

this is bad code, please get rid of x. first x is a bad variable name and second its completely redundant. you also want to convert your print statements into logs or whatever but printing won't get you far.

hansTheFranz
  • 2,511
  • 4
  • 19
  • 35
  • This was really helpful and I have updated my code as you suggested. see my views.py [here](http://pasted.co/d9e1d73f). Now I get the RFID tag data and it also gets committed to the database but my problem is that I do not get `HttpResponse("Form submitted")`. It just starts reading tags all over again. I want it to be one-time process only. Also, suggest better code practice to eliminate 'try except block'. After submitting the form I don't know why I have to scan my tag to get data committed and show HttpResponse. – Dhaval Savalia Apr 15 '18 at 11:50
1

I finally figured it out. I have divided process into multiple parts. I then make AJAX call to access it.

My urls.py file:

from django.conf.urls import url
from .views import tag, check_tagid, scan_tag

urlpatterns = [
    url(r'^tag/', tag, name="tag"),
    url(r'^check_tagid/', check_tagid, name="check_tagid"),
    url(r'^scan_tag/', scan_tag, name="scan_tag"),
]

My views.py file:

from django.shortcuts import render
from django.http import HttpResponse, JsonResponse
from .models import Student
import serial

def check_tagid(request):
    """Check if scanned tag id is already associated or not"""
    tagid = request.GET.get('tagid', None)
    if Student.objects.filter(tag_id__iexact=tagid).exists():
        data = {
            'is_taken': Student.objects.filter(tag_id__iexact=tagid).exists(),
            'student': Student.objects.get(tag_id=tagid).name
        }
    else:
        data = {
            'is_taken': Student.objects.filter(tag_id__iexact=tagid).exists(),
        }
    return JsonResponse(data)


def scan_tag(request):
    """Function to check if tag is scanned or not"""
    if request.is_ajax():
        ## Init RFID reader
        data = serial.Serial(
                            port='/dev/ttyUSB1',
                            baudrate = 9600,
                            parity=serial.PARITY_NONE,
                            stopbits=serial.STOPBITS_ONE,
                            bytesize=serial.EIGHTBITS
                            )

        context = {'tagid': data.read(12).decode("utf-8")}
        return JsonResponse(context) 
    else:
        return HttpResponse("This route only handles AJAX requests")


def tag(request):
    return render(request, 'students/tag.html', {})

my tag.html file:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
</head>
<body>
    <center><h1><div id="tag_id">Scanning for tag</div></h1></center>
    <div id="if_exists"></div>


  <script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>

<script type="text/javascript">
$(document).ready(function() {
    $.get("/scan_tag/", function(data) {
        console.log(data.tagid);
        var x = document.createElement("INPUT");
        x.setAttribute("id", "tag_id_in");
        x.setAttribute("type", "hidden");
        x.setAttribute("value", data.tagid);
        document.body.appendChild(x);
        // check tag
        tagid = $("#tag_id_in").val();
        console.log(tagid);
        $.ajax({
            type: "GET",
            url: "{% url 'check_tagid' %}",
            data: {
                'tagid': tagid
            },
            success: function(data) {
                if (data.is_taken) {
                    document.getElementById('tag_id').innerHTML = "Welcome "+data.student;
                } else {
                    document.getElementById('tag_id').innerHTML = "No student with this tag id found";
                }
            }
        });
    });
});
</script>


</body>
</html>

All of this is now working as expected.

So, /tag/ is the main entry point. Now in tag.html I use jQuery get method on /scan_tag/. It will return RFID tag number. Then I call AJAX on /check_tagid/ and it will true/false depending on whether the student is in the database or not.

Dhaval Savalia
  • 495
  • 5
  • 17
  • 1
    sorry I forgot totally about the issue, glad you could solve it on your own. and good job with the "filter.exsist()" rather than "get()" to avoid "try/expect". If you are looking for further improvments: "data = serial.Serial(..." seems wrong since you initialise it each time the function is called. this should be global IMO. You could also convert your jQuery ajax calls to nativ XMLRequest to get rid of the jQuery overhead. – hansTheFranz Apr 17 '18 at 12:34
  • @hansTheFranz Thank you so much for replying! I tried to set "data = serial.Serial(..." as global but did not seem to scan RFID tags. Also, making it non-global will save power I guess as it takes 12V. I don't know anything about native XMLRequest. Can you please suggest me a good reference for that? I have found [this](https://www.w3schools.com/xml/xml_http.asp) And thank you again for suggestions! – Dhaval Savalia Apr 17 '18 at 14:58