Programm verhällt sich beim starten in Idle und aus der Konsole unterschiedlich

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
schappenberg
User
Beiträge: 11
Registriert: Sonntag 18. Oktober 2015, 23:12

Hallo!

nachdem ich mein erstes größeres Programm wie in diesem Thread empfohlen auf ein "Datenbankprogramm" und ein Ausgabeprogramm geändert habe, musste ich gestern leider feststellen dass sich mein Datenbankprogramm beim Starten aus Idle unter Raspian und in der Konsole unterschiedlich verhält.

Starte ich das Programm in Idle passt alles, das Programm läuft stabil bis zum nächsten Stromausfall ... Um dieses Problem zu umgehen, wollte ich mein Programm automatisch über die Datei /etc/rc.local starten lassen, leider Fehlanzeige, es werden keine Datenbankausgaben mehr gemacht. Starte ich das Programm manuell über die Konsole, das gleiche, irgendwie läuft es nicht richtig durch, ich habe an diversen "neuralgischen" Stellen print-Ausgaben eingefügt um herauszufinden wo es hakt, leider hat mir das nicht wirklich geholfen. Es wird, soweit ich gekommen bin, meine while true Schleife nur einmal durchlaufen (glaube ich zumindest), was ich aber nicht rausfinden kann warum das so ist. Ich arbeite übrigens mit Python 2.7, ich verwende ein Script von Adafruit, das leider in Python 3 nicht verfügbar ist.

Kann mir jemand weiterhelfen wo das Problem liegen könnte? Den Programm-Code kann ich wenn nötig heute Abend nachreichen ...

Danke
Benutzeravatar
__blackjack__
User
Beiträge: 13064
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@schappenberg: Die Informationen reichen so nicht aus. Das kann ja an allem möglichen liegen, von Rechteproblemen bis zu Fehler im Programm. Du musst schon etwas genauer beschreiben was Du machst und was darauf hin passiert, und wie das von Deinen Erwartungen abweicht.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
schappenberg
User
Beiträge: 11
Registriert: Sonntag 18. Oktober 2015, 23:12

Sorry, werde heute Abend den Code posten, hoffentlich hilft das weiter.

Grundsätzlich starte ich das gleiche Programm, einmal aus Idle heraus, einmal mit manuellem Aufruf aus der Konsole.
Aus Idle gestartet verhält sich das Programm wie erwartet, es werden Daten zyklisch von der seriellen Schnittstelle gelesen und in eine SQLite DB geschrieben. Starte ich das Programm aber über die Konsole (LXTerminal), werden nur einmal die Daten von der seriellen Schnittstelle gelesen, aber nichts in die DB geschrieben, soweit ich gesehen habe wird auch die WHILE TRUE Schleife nur einmal durchlaufen, den Code poste ich am Abend.

An Rechteprobleme habe ich auch gedacht, aber wieder verworfen, weil wenn ich als eingeloggter Benutzer ein Programm aus Idle oder der Konsole starte sollte doch rechtemäßig das gleiche sein, oder liege ich da schon falsch.
Fehler im Programm verstehe ich auch nicht, oder macht Idle etwas anderes als wenn ich das Programm aus der Konsole heraus manuell starte? Ein paar Fehlermeldungen habe ich zwar schon beim Konsolenaufruf erhalten auf die mich Idle nicht hingewiesen habe, diese habe ich aber schon korrigiert.

Danke
Benutzeravatar
__blackjack__
User
Beiträge: 13064
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@schappenberg: Wenn eine ``while True:``-Schleife nur einmal durchlaufen wird (und da kein ``break`` drin steht um die Schleife abzubrechen) dann wird die durch eine Ausnahme verlassen oder irgendetwas in der Schleife blockiert.

Zwischen IDLE und Konsole gibt es schon ein paar Unterschiede. Man sollte Programme immer auch ohne eine IDE starten/testen, denn letztendlich verändert fast jede IDE die Ablaufumgebung irgendwie.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
schappenberg
User
Beiträge: 11
Registriert: Sonntag 18. Oktober 2015, 23:12

Hallo,

spät aber doch, der Code der mir schlaflose Nächte bereitet (bitte um Nachsicht, ist mein erstes Programm dass über einen Zweizeiler hinausgeht):

Code: Alles auswählen

#!/usr/bin/python
# -*- coding: iso-8859-15 -*-
from __future__ import division
import sys
import serial
import time
import sqlite3
from datetime import datetime, date, timedelta
from Adafruit_BMP085 import BMP085

WUEstatus=bytearray([2, 1, 0xf0]) #Statusabfrage
WUEreq_weather=bytearray([2, 1, 0xf4]) #gespeicherte Wetterdaten abfragen
WUEoutput_hex=bytearray([2, 2, 0xfb, 0x0]) #Ausgabe als Hex
WUEweather_send_mode=bytearray([2, 2, 0xf2, 2]) #Wetterdaten speichern und auf Anfrage ausgeben
bmp = BMP085(0x77, 2) #Adresse vom BMP085

def init():
    global WUE
    global wetterdb
    WUE=serial.Serial(port="/dev/ttyAMA0",baudrate=4800,bytesize=8,parity=serial.PARITY_NONE,stopbits=1,timeout=1) #Serielle Schnittstelle einrichten
    time.sleep(1)
    WUE.write(WUEweather_send_mode)
    time.sleep(1)
    WUE.write(WUEoutput_hex)
    wetterdb = sqlite3.connect('wetterdb')
    wetterdb.execute("CREATE TABLE IF NOT EXISTS wetterdaten ([timestamp] timestamp primary key, temp integer, humity integer, windspeed integer, rain integer, press_at_sea integer, flash integer)")

def berechne_temp(daten_high, daten_low): #Berechnung Quelle: stackoverflow.com/questions/1604464/twos-complement-in-python
    datenint=int("0x" + str(daten_high) + str(daten_low),16)
    if datenint >= 2**16:
        raise ValueError("Value: {} out of range of {}-bit value.".format(datenint,16))
    else:
        return datenint - int((datenint <<1) & 2**16)

def berechne_regen(jetzt, zuletzt):
    if jetzt < zuletzt:
        jetzt==4095+jetzt
    return (jetzt-zuletzt)*0,295

def read_data(): #Wetterdaten von der Schnittstelle und vom BMP085 lesen
    WUE.write(WUEreq_weather) #Daten abrufen
    wetterdaten=[]
    for x in range(14): #Wetterdaten sind genau 14 byte lang
        wetterdaten.append('{:02x}'.format(ord(WUE.read())))
    pressure = bmp.readPressure() #Luftdruck vom BMP085 lesen
    altitude = 437
    psea = pressure / pow(1.0 - altitude/44330.0, 5.255)
    wetterdaten.append(psea)
    return(wetterdaten)

def write_data_in_db(wetterdaten): #uebergebene Wetterdaten in eine DB schreiben
    wetterdb.execute("INSERT INTO wetterdaten(timestamp, temp, humity, windspeed, rain, press_at_sea) values (?, ?, ?, ?, ?, ?)", (datetime.now(), berechne_temp(wetterdaten[5], wetterdaten[6]), int(str(wetterdaten[7])+str(wetterdaten[8]),16), int(str(wetterdaten[9])+str(wetterdaten[10]),16), int(str(wetterdaten[11])+str(wetterdaten[12]),16), wetterdaten[14]))
    wetterdb.commit()

if __name__ == "__main__":
    init() #FS20 WUE initialisieren
    read_data() #Wetterdaten lesen um zu schauen ob etwas da ist
    try:
        while 1:
            #print(time.strftime("%d.%m.%Y %H:%M:%S"))
            WUE.write(WUEstatus) #Staus abfragen
            for x in range(7): #alle 7 Status bytes nacheinander lesen ...
                read_byte = WUE.read()
                if x == 6: #letzes byte
                    if ord(read_byte) > 0: #wenn Wetterdaten vorhanden ...
                        write_data_in_db(read_data()) #Wetterdaten lesen und in die DB schreiben
            time.sleep(120)
    except(KeyboardInterrupt, SystemExit):
        WUE.close() #Serielle Schnittstelle wieder schließen
        wetterdb.close() #Datenbankverbindung schließen
        print("alle Verbindungen geschlossen")
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@schappenberg: vergiss gleich wieder, dass es soetwas wie `global` überhaupt gibt, alles was eine Funktion braucht, bekommt sie über ihre Argumente, also auch wetterdb und WUE, wobei WUE gegen die Konvention ist, weil komplett groß geschriebene Variablennamen eigentlich Konstanten ist, zudem ist wue ein völlig kryptischer Name.
Statt in `read_data` Bytes in ihre Hexzahlen umzuwandeln und sie dann kompliziert per int wieder in Zahlen umzuwandeln um sie dann in eine signed int16 umzuwandeln solltest Du die Bytes per struct.unpack gleich ins richtige Zahlenformat konvertieren.
In `berechne_regen` willst Du höchstwahrscheinlich nicht immer ein Tuple aus 0 und 295 zurückgeben.
Statt des `except`-Blocks benutze einen `finally`-Block.
schappenberg
User
Beiträge: 11
Registriert: Sonntag 18. Oktober 2015, 23:12

@Sirius3: danke für die Anmerkungen, werde diese soweit ich es schaffe in mein Programm einarbeiten und schauen ob sich etwas ändert.
schappenberg
User
Beiträge: 11
Registriert: Sonntag 18. Oktober 2015, 23:12

@Sirius3: habe deine Vorschläge so weit wie mir bisher möglich in die Tat umgesetzt (bis auf struct.unpack, das hab ich noch nicht so ganz verstanden was das macht) und plötzlich läuft es! Und außerdem habe ich dabei auch noch den Fehler gefunden warum keine Daten in meine DB geschrieben werden: ich habe bei der Definition der wetterdb schlicht und ergreifend übersehen dass ich den Pfad relativ angegeben habe, ich habe das Programm im Terminal aber immer von ~ gestartet -> die DB die ich beobachtet habe wurde nicht beschrieben sonder eine neue unter ~ angelegt.
Außerdem habe ich mein Autostart Problem gelöst, mit /etc/rc.local hat es nicht funktioniert (warum auch immer), mit einem @reboot crontab Eintrag startet das Programm jetzt bei jedem Raspi Neustart aber automatisch.

Danke vielmals für eure Hilfe, schön langsam wirds ja ;-)
nezzcarth
User
Beiträge: 1633
Registriert: Samstag 16. April 2011, 12:47

schappenberg hat geschrieben: Freitag 29. März 2019, 22:13 Außerdem habe ich mein Autostart Problem gelöst, mit /etc/rc.local hat es nicht funktioniert (warum auch immer), mit einem @reboot crontab Eintrag startet das Programm jetzt bei jedem Raspi Neustart aber automatisch.
Wenn's geht, sollte man unter modernen Linux-Systemen nach Möglichkeit eine systemd Service-Unit dafür schreiben. Die beiden anderen Varianten, die du nennst, sind veraltet bzw. suboptimal, halten sich aber leider hartnäckig in der Raspi-Community.

Siehe zum Einstieg z.B. hier: https://wiki.ubuntuusers.de/Howto/syste ... _Beispiel/
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

nezzcarth hat geschrieben: Freitag 29. März 2019, 22:21Die beiden anderen Varianten, die du nennst, sind veraltet bzw. suboptimal, halten sich aber leider hartnäckig in der Raspi-Community.
Nicht nur die. So. Viel. Schlechter. Code. Und andere Vorgehensweisen. SCNR.
schappenberg
User
Beiträge: 11
Registriert: Sonntag 18. Oktober 2015, 23:12

Ich habe auf meinem Raspi immer noch Wheezy am laufen, da unter Stretch mein Programm auch nicht mehr funktioniert hat, ist allerdings schon ein paar Monate her dass ich das Update gewagt habe. Aber soweit ich mich erinnern kann konnte ich das Adafruit Script für den BMP085 abruf nicht mehr starten, also bin ich wieder zurück zu Wheezy gewechselt.
nezzcarth
User
Beiträge: 1633
Registriert: Samstag 16. April 2011, 12:47

schappenberg hat geschrieben: Sonntag 31. März 2019, 18:55 Ich habe auf meinem Raspi immer noch Wheezy am laufen, da unter Stretch mein Programm auch nicht mehr funktioniert hat, ist allerdings schon ein paar Monate her dass ich das Update gewagt habe.
Verstehe. Aber das solltest du m.M.n. wirklich in Angriff nehmen, denn ein OS zu verwenden, das komplett aus dem Support raus ist, ist in der Regel keine gute Idee. Selbst wenn das nur im lokalen Netz laufen sollte, ist es ein Sicherheitsrisiko
Sirius3
User
Beiträge: 17737
Registriert: Sonntag 21. Oktober 2012, 17:20

@schappenberg: na, da wäre es gut zu wissen, was genau nicht funktioniert hat. Wenn Du irgendwo nicht weiter kommst, wäre auch Dein aktueller Code ganz nützlich.
Antworten