Venv und serielle Schnittstelle

Django, Flask, Bottle, WSGI, CGI…
Antworten
erdmulch
User
Beiträge: 218
Registriert: Samstag 17. Juli 2010, 19:50

Sonntag 8. Juli 2018, 19:38

Hallo zusammen,

Ich habe eine kleine Webapplikation mit Django realisiert.
Nun würde ich gerne Daten von der seriellen Schnittstelle in die Datenbank schreiben.
Leider gibt es ein Berechtigungsproblem wenn ich das serielle Skript unter venv starte.

Hattet ihr auch schon das Problem?
Hase
User
Beiträge: 55
Registriert: Donnerstag 1. Oktober 2009, 15:17
Wohnort: Bremer Speckgürtel

Sonntag 8. Juli 2018, 20:14

Betriebssystem?
erdmulch
User
Beiträge: 218
Registriert: Samstag 17. Juli 2010, 19:50

Sonntag 8. Juli 2018, 20:16

Hab ein Raspberry Pi Zero W
__deets__
User
Beiträge: 3289
Registriert: Mittwoch 14. Oktober 2015, 14:29

Montag 9. Juli 2018, 04:06

Es kann technisch keinen Zusammenhang geben zwischen venv und den Berechtigungen einer seriellen Schnittstelle. Da läuft etwas anderes falsch. Kannst du ein minimales(!) Beispiel erstellen, das du im und ohne venv laufen lässt, und die Fehlermeldung vergleichen?
Hase
User
Beiträge: 55
Registriert: Donnerstag 1. Oktober 2009, 15:17
Wohnort: Bremer Speckgürtel

Montag 9. Juli 2018, 08:23

Kann es sein, dass du einmal als root arbeitest, das andere Mal als user?

Alle, die auf /dev/ttySx zugreifen wollen, müssen Mitglied der Gruppe "dialout" sein, das ist standardmässig meist nicht der Fall, also ggf. ergänzen.
erdmulch
User
Beiträge: 218
Registriert: Samstag 17. Juli 2010, 19:50

Montag 9. Juli 2018, 19:09

nein, ich arbeite beides mal als user. -Dachte ich zumindest bis ich hier diese Zeilen verfasst habe...-
Aber stimmt, eine Kleinigkeit ist wirklich anders.
Ich werde deshalb ein wenig ausholen...

das ganze ist wie gesagt eine Django Applikation.
Auf meinem System habe ich ein Skript am laufen, das die Daten vom Microcontroller über den UART in die Datenbank schreibt.
Da der Raspberry keinen richtigen UART besitzt sondern nur eine OTG Schnittstelle (Raspberry teilt sich die Schnittstelle mit Bluetooth und der seriellen Schnittstelle) musste ein paar Dinge angepasst werden. Dabei bin ich nach folgendem Buch vorgegangen:
https://www.rheinwerk-verlag.de/raspber ... gJDSfD_BwE
z.B musste ich in der /boot//config.txt den Wert force_turbo=1 gesetzt werden.
in der Datei cmdline.txt musste folgende Zeile ergänzt werden:
dtoverlay=pi-miniuart-bt

Nachdem ich diese Einstellungen gemacht haben, funktioniert es auch ohne größere Probleme.

"Diese Variante funktioniert leider nur, solange die CPU-Temperatur weniger als 85°C beträgt. Ab diesem Wert fährt der interne Überhitzungsschutz des SoC nämlich die Taktfrequenz auf ein Minimum zurück." Wenn die Taktfrequenz heruntergefahren wird, dann ändert sich die Baudrate, folglich können die beide Geräte nicht mehr miteinander kommunizieren.

Nachdem ich die CPU Temperatur asugelesen hatte und diese um die 50°C bei mir war, sah ich da kein Problem. Allerdings zeigen langzeit test, damit der UART irgendwann wenn auch nur kurzzeitig ausgestiegen ist. Das folgende Skript wurde abgebrochen und musste händisch wieder gestartet werden.

Code: Alles auswählen

#!/usr/bin/python3
# -*- coding: utf-8 -*-
 
import serial
import sqlite3
import sys
import time

id = None
timestamp = time.strftime("%Y-%m-%d %H:%M:%S") 
name = "Sensor1"
value1 = ""
def insert_into_database(id, timestamp, name ,value1):

    con = sqlite3.connect("/home/pi/sensor/db.sqlite3")
    cur = con.cursor()
    value = (id, timestamp, name ,value1)
    sql = "INSERT INTO sensor VALUES (?, ?, ?, ?)"
    cur.execute (sql, value)
    con.commit()
    con.rollback()
    con.close()

ser = serial.Serial("/dev/ttyAMA0")
ser.baudrate = 9600
daten = ser.readline()
ser.close
values = daten.decode('utf8')    
if (values.count(";")) == 4:
    print(daten.decode('utf8'))
    value1 = values.split(";")[0]
    value2 = values.split(";")[1]
    value3 = values.split(";")[2]
    value4 = values.split(";")[3]
    insert_into_database(id, timestamp, name ,value1)

Aussteigen ist OK. händisch starten geht leider nicht, deshalb habe ich mich für folgendende zwar unschöne aber doch funktioierende Variante entscheiden:

#!/bin/bash
while true
do
sudo python3 listener.py
sleep 1
done

zwar starte ich dieses Skript mit keiner besonderen Berechtigung.
Wie in dem Skript zu erkennen ist, wird das folgende Python Skript listener.py mit Sudo ausgeführt.

Ok, jetzt habe ich die Erklärung, warum es im "normalen" Modus funktioniert, nicht aber im venv Modus.

Das Skript muss ich mithilfe des Datenbank wrappers von Django machen. ansosnten blockiert mir das Skript ständig die Datenbank und die Webapplikation läuft dadurch sehr schleppend.

hat jemand eine Idee, wie ich das Problem lösen könnte?

vielen Dank im voraus
Sirius3
User
Beiträge: 8254
Registriert: Sonntag 21. Oktober 2012, 17:20

Montag 9. Juli 2018, 19:44

Du öffnest die Serielle Schnittstelle ständig und schließt sie sofort wieder? Sieht ziemlich umständlich aus und wundert mich, dass das überhaupt zuverlässig funktioniert. value1 wird am Anfang initialisiert, aber nicht benutzt.
Ein rollback nach einem commit ist ziemlich unsinnig.
close sollte man auch aufrufen. Vier mal split aufzurufen um jeweils nur einen Wert auszulesen, ist ziemliche Verschwendung.

Code: Alles auswählen

#!/usr/bin/python3
import serial
import sqlite3
import logging
from datetime import datetime as DateTime

ID = None
NAME = "Sensor1"

def process(db_connection)
    db_connection = sqlite3.connect("/home/pi/sensor/db.sqlite3")
    ser = serial.Serial("/dev/ttyAMA0", baudrate=9600)
    for line in ser:
        values = line.decode('utf8').split(";")
        if len(values) == 5:
            cur = db_connection.cursor()
            cur.execute ("INSERT INTO sensor VALUES (?, ?, ?, ?)", (
                ID, DateTime.now(), NAME, values[0]
            ))
            db_connection.commit()

def main():
    while True:
        try:
            process()
        except KeyboardInterrupt:
            break
        except Exception:
            # restart on any serial error
            logging.exception("reading sensor")

if __name__ == '__main__':
    main()
Benutzeravatar
noisefloor
User
Beiträge: 2456
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: Görgeshausen
Kontaktdaten:

Dienstag 10. Juli 2018, 12:22

Hallo,

ich würde das ganz anders machen und zwar so, dass die Django-App eine REST-ähnliche Schnittstelle bereit stellt, an das du dann per POST-Request die Daten sendest, die in die DB geschrieben werden soll.

Das hat IMHO den Vorteil, dass a) das Django-ORM die Operationen in der DB macht und die nicht parallel manuell was machen musst (und so Fehler entstehen können) und b) dass das einfacher und flexibler zu skalieren ist, wenn mal mehr Sensordaten dazu kommen.

Gruß, noisefloor
Antworten