[PYTHON] "2/2" Ich mache eine einfache Webanwendung für den Roboterbetrieb. "Raspberry Pi 3B + und Django Channels"

Intro

Es ist s_rae. Ich lerne hart Programmieren.

Als Praxis der Anwendungsentwicklung habe ich eine Schnittstelle erstellt, die den Roboter bedienen kann. https://github.com/samanthanium/dullahan_local Sie können den Quellcode unter sehen.

Im Anschluss an den vorherigen Beitrag werde ich diesmal ein wenig über die Quelle erklären. Letztes Mal: https://qiita.com/s_rae/items/d808c3eccd8e173dc55b

Da es für Hobbyzwecke gemacht wurde, werde ich die Fehlerbehandlung weglassen.

Verwendete Frameworks und Bibliotheken

Wir verwenden diese Technologie für dieses Projekt.

Django Framework

Django bediente hauptsächlich Webseiten über HTTP, verwaltete Benutzer in Sitzungen und arbeitete an der SQLite-Datenbank.

Das Django-Projekt besteht übrigens aus mehreren Apps (Code, der für andere Projekte wiederverwendet werden kann).

Dieses Projekt --dullahan (Haupt-App des Projekts) --pages (Für Home, About, Login Webseiten) --control_system (Seite zum Senden von Befehlen und Registrieren von Geräten) --bluetooth_interface (einschließlich Consumer und Funktion des Bluetooth-Geräts)

Es besteht aus "App".

Der Grund, warum ich Django verwendet habe, ist, dass es viele Funktionen hat und schnell erstellt werden kann. Ich wollte auch Python üben.

Django Channels Django Channels ist eine Bibliothek, die für das Django-Framework erstellt wurde. Es ist möglich, dem Django-Framework Funktionen wie Websocket hinzuzufügen.

Channels ist ein Mechanismus, der die Klasse "Consumer" zum Verarbeiten von WebSocket-Nachrichten verwendet. Es kann Funktionen ausführen, die der Ansicht des Django-Frameworks ähneln.

Pybluez Pybluez ist eine Bibliothek, die erstellt wurde, um die Bluetooth-Funktionalität des Systems in Python zu nutzen. Ich werde den Pybluez-Code hier nicht erklären, aber Sie können den Code auf ähnliche Weise wie das Socket-Modul schreiben.

Codebeschreibung

Benutzer meldet sich an> Gerät hinzufügen-> Befehl an Gerät senden Ich werde den Gefühlsfluss erklären.

pages/views.py


#...
def log_in(req):
    form = AuthenticationForm()
    if req.method == 'POST':
        form = AuthenticationForm(data=req.POST)
        if form.is_valid():
            login(req, form.get_user())
            return redirect(reverse('get_home'))
        else:
            return render(req, 'login.html', {'form': form})
    return render(req, 'login.html', {'form': form})
#...
def sign_up(req):
    form = UserCreationForm()
    if req.method == 'POST':
        form = UserCreationForm(data=req.POST)
        if form.is_valid():
            form.save()
            return redirect(reverse('log_in'))
        else:
            print(form.errors)
    return render(req, 'signup.html', {'form': form})

Hier ist die Funktion für die Benutzeranmeldung. Sie können sich einfach mit der in Djangos Formularen enthaltenen Methode "form.get_user" anmelden.

Nachdem

@login_required

Sie können den aktuellen Benutzer mithilfe des Dekorators von in der Ansicht überprüfen.

Als nächstes wird der Bildschirm angezeigt, auf dem nach den umgebenden Bluetooth-Geräten gesucht und diese aufgezeichnet werden können.

control_system/views.py


from bluetooth_interface import bt_functions as bt
#...
@login_required
def device_search_ajax(req):
    try:
        if req.method == "GET":
            nearby_devices = json.dumps(bt.search())
            return JsonResponse({'nearby_devices':nearby_devices}, status=200)
        else:
            #...
    except:
        #Fehlerbehandlung
#...

Verwenden Sie bei der Suche nach Bluetooth-Geräten in Ihrer Nähe die Ajax-Anfrage.

bt.search ist eine Funktion zum Suchen nach Bluetooth-Geräten mit Pybluez.

Dieser Kawa verwendet Websocket anstelle von HTTP, um Nachrichten mit dem Roboter auszutauschen.

control_system/consumers.py


#...
class CommandConsumer(WebsocketConsumer):
    def connect(self):
        #Suchen Sie das Modell des vom Benutzer ausgewählten Geräts
        self.device_id = self.scope['url_route']['kwargs']['device_id']
        self.device_group_name = 'command_%s' % self.device_id
        device = Device.objects.get(id=self.device_id)

        #Ermöglichen Sie dem Consumer für Bluetooth die serielle Kommunikation mit dem Gerät
        async_to_sync(self.channel_layer.send)('bt-process', {
            'type': 'bt_connect',
            'group_name': self.device_group_name,
            'uuid': device.uuid,
            'device' : device.id,
            }
        )

        #Benutzer zur Gruppe hinzufügen
        async_to_sync(self.channel_layer.group_add)(
            self.device_group_name,
            self.channel_name
        )

        self.accept()

    #...

    def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']
        device_id = text_data_json['device']

        #Senden Sie Befehle an das Gerät
        async_to_sync(self.channel_layer.send)('bt-process', {
            'type': 'bt_send_serial',
            'device': device_id,
            'message': message,
            }
        )

        #...

    #Speichern und Weiterleiten von Antwortnachrichten, die von Bluetooth-Geräten empfangen wurden
    def command_message(self, event):
        message = event['message']
        device_id = event['device']
        
        #Mit Zeitstempel im Gerätemodell speichern
        device = Device.objects.get(id=device_id)
        new_history = CommandHistory(device=device, command=message )
        new_history.save()

        command_history = {}
        all_history = device.history.all()
        for command in all_history:
            command_history[command.timestamp.strftime('%H:%M:%S')] = command.command + '\n'


        #Befehlsverlauf an Benutzer senden
        self.send(text_data=json.dumps({
            'message': command_history,
            'device': device_id
        }))

Das ist etwas kompliziert, aber um es kurz zu erklären

--Connect öffnet die Websocket-Kommunikation mit dem Benutzer und ermöglicht die Kommunikation mit dem Bluetooth-Gerät. "Bt-Prozess" bezieht sich auf den Verbraucher für Bluetooth-Geräte, der derzeit im Hintergrund ausgeführt wird. Ich möchte versuchen, "bt_connect" von "bt-process" zu verwenden.

--receive sendet einen Befehl an das in der Nachricht enthaltene Gerät an den Roboter, wenn der Benutzer eine Nachricht über die Webseite sendet. Dies sendet auf die gleiche Weise wie oben auch eine Nachricht an "bt-process".

--command_message speichert die vom Roboter empfangene Antwort im Datenbankmodell des Roboters. Die Nachricht hat eine Eins-zu-Eins-Beziehung zum Robotermodell. Es ist ein Formular, das mit der ID des Roboters verbunden ist.

Als nächstes folgt die Verbraucherklasse für die Kommunikation mit dem Roboter.

bluetooth_interface/consumers.py


#...
from bluetooth_interface import bt_functions
#...
class BTConsumer(SyncConsumer):

    def bt_connect(self, message):
            #Denken Sie daran, eine Nachricht an den Benutzer senden zu können
            self.device_group_name = message['group_name']
            self.sock = {}

            #Bluetooth-Kommunikationsportnummer
            self.port_num = 1

            #Machen Sie eine Kommunikationsbuchse
            sock, msg = bt_functions.connect(message['uuid'], self.port_num)

            #Socket mit Geräte-ID aufzeichnen
            if sock != 1: 
                self.sock = {message['device']:[sock, self.port_num]}

            #Kommunikationsstatus an Benutzer senden
            async_to_sync(self.channel_layer.group_send)(
                    self.device_group_name,
                    {
                        'type': 'command_message',
                        'device': message['device'],
                        'message': msg,
                        }
                    )

    #...

    def bt_send_serial(self, event):
        
        #Nehmen Sie die vom Benutzer angeforderte Geräte-ID und Nachricht
        device_id = int(event['device'])
        message = event['message']

        #Wählen Sie einen Socket aus, um mit dem Gerät zu kommunizieren, und senden Sie eine Nachricht
        if device_id in self.sock.keys():
            result = bt_functions.send_serial(self.sock[device_id][0], message)
        #Senden Sie eine Antwortnachricht an den Benutzer
            async_to_sync(self.channel_layer.group_send)(
                    self.device_group_name,
                    {
                        'type': 'command_message',
                        'device': device_id,
                        'message': result,
                        }
                    )

    #...

Ich war ziemlich verwirrt darüber, wie ich es hier machen soll. Als Ergebnis

--Erstellen Sie einen Verbraucher, mit dem der Roboter jederzeit Nachrichten (Sensordaten, Antworten auf Befehle usw.) senden kann

Ich habe es möglich gemacht.

Django Channels verwendet die Channels Layer, um die Kommunikation zwischen Consumer-Klassen und -Prozessen zu ermöglichen.

Selbst wenn sich der Benutzer abmeldet oder andere Arbeiten ausführt, sind sie in einem anderen Prozess immer mit dem Roboter verbunden.

Ich habe es noch nicht erstellt, kann aber auf diese Weise immer Sensordaten von Robotern und IoT-Geräten abrufen.

Weitere Informationen finden Sie in der Dokumentation zu Django Channels. https://channels.readthedocs.io/en/latest/topics/channel_layers.html https://channels.readthedocs.io/en/latest/topics/worker.html

Schließlich

Ich denke, es wäre einfacher gewesen, ein Projekt mit Node.js zu erstellen, das mit Async einfach zu verwenden ist.

Ich habe jedoch Django- und Django-Kanäle verwendet, weil ich die vielen Funktionen von Django (Sicherheit, Benutzerverwaltung, Formulare usw.) nutzen wollte.

Es hat ungefähr 2 Wochen gedauert, bis es soweit war. Es gab viele neue Dinge, daher war es meistens Zeit, Dokumente zu lesen und zu studieren.

Vielen Dank, dass Sie diesmal auch gelesen haben.

Recommended Posts

"2/2" Ich mache eine einfache Webanwendung für den Roboterbetrieb. "Raspberry Pi 3B + und Django Channels"
"1/2" Ich mache eine einfache Webanwendung für den Roboterbetrieb. "Raspberry Pi 3B + und Django Channels"
Ich habe eine WEB-Bewerbung bei Django gemacht
[Für Anfänger] Ich habe mit Raspberry Pi einen menschlichen Sensor erstellt und LINE benachrichtigt!
Erstellen Sie eine WEB-Überwachungskamera mit Raspberry Pi und OpenCV
Ich habe versucht, Raspeye und conect + mit der Web-API zu verbinden
Ich habe einen Ressourcenmonitor für Raspberry Pi mit einer Tabelle erstellt
(Für Anfänger) Versuchen Sie, mit Django eine einfache Web-API zu erstellen
Ich habe mit Razpai einen Webserver erstellt, um Anime zu schauen
Machen Sie einen einfachen CO2-Inkubator mit Raspberry PI und CO2-Sensor (MH-Z14A)
Startete eine Webanwendung auf AWS mit Django und wechselte Jobs
Erstellen Sie eine Webanwendung mit Django
Erstellen Sie mit Raspberry Pi einen WLAN-Ethernet-Konverter und einen einfachen Router
Ich möchte eine Webanwendung mit React und Python Flask erstellen
Erklären Sie vorsichtig den Prozess der Erstellung einer einfachen Überwachungskamera ohne Server mithilfe von Raspeye, Gmail API und Line API
[Raspberry Pi] Fügen Sie ein Thermometer und ein Feuchtigkeitsmessgerät hinzu
Ich habe versucht, das Webanwendungs-Framework zu vergleichen
Quellkompilieren Sie Apache2.4 + PHP7.4 mit Raspberry Pi und erstellen Sie einen Webserver --2 PHP Einführung
Quellkompilieren Sie Apache2.4 + PHP7.4 mit Raspberry Pi und erstellen Sie einen Webserver. 1. Apache-Einführung
Ich habe versucht, Flask auf Raspberry Pi 3 Model B + mit Nginx und uWSGI auszuführen
Die Geschichte der Erstellung einer Webanwendung, die umfangreiche Lesungen mit Django aufzeichnet
Ich habe versucht, mit Raspeye + Tact Switch eine Schaltfläche für Slack zu erstellen
Versuchen Sie, eine Webanwendung mit Vue.js und Django (Mac Edition) zu erstellen - (1) Umgebungskonstruktion, Anwendungserstellung