Fernsteuerung mit Flask Problem

Django, Flask, Bottle, WSGI, CGI…
Antworten
ice2711
User
Beiträge: 3
Registriert: Montag 29. Mai 2017, 09:02

Montag 29. Mai 2017, 09:20

Hallo,
Ich habe mir ein Fahrzeug gebaut das ich gern über ein Smartphone steuern wollte. Im Fahrzeug ist ein Raspberry verbaut das ein WLAN-AP aufbaut damit ich mich mit dem Smartphone verbinden kann und hier eine HTML-Seite zur Steuerung aufrufen kann. Zum einen wollte ich über Schaltflächen Steuerungsbefehle manuell weitergeben, das funktioniert auch alles problemlos. Als nächstes wollte ich eine automatische Steuerung realisieren bei der das Fehrzeug über zwei Ultraschallsensoren Hinternisse erkennt und automatisch ausweicht. Die automatische Steuerung funktioniert auch soweit gut. Aber ich wollte gern über die HTML-Seite über das Smartphone die automatische Steuerung ein und ausschalten, das funktioniert leider nicht. Wahrscheinlich liegt es daran dass in main_automatik eine Schleife intergriert ist. Gibt es eine Möglichkeit diese Schleife irgendwie über die HTML-Seite zu unterbrechen? Oder hat jemand vielleicht eine andere Idee? Ich hoffe ich konnte mein Problem einigermaßen verständlich erklären. Für jede Hilfe bin ich sehr dankbar.
Hier mein Python-Skript:

Code: Alles auswählen

# Import Module
import time
import RPi.GPIO as GPIO
from flask import Flask, request, redirect, render_template
from multiprocessing import Process

# Variablen definieren
app = Flask(__name__)
global varhit

# Pins definieren
GPIOgruen = 18 # LED gruen
GPIOgelb = 23 # LED gelb
GPIOrot = 24 # LED rot
GPIOecho_re = 25 # Echo Pin am Ultraschallsensor rechts
GPIOtrig_re = 12 # Trigger Pin am Ultraschallsensor rechts
GPIOecho_li = 20 # Echo Pin am Ultraschallsensor links
GPIOtrig_li = 16 # Trigger Pin am Ultraschallsensor links
GPIOmotor1en1 = 4 # Motor 1 enable
GPIOmotor1in1 = 17 # Motor 1 input1
GPIOmotor1in2 = 27 # Motor 1 input2
GPIOmotor2en2 = 5 # Motor 2 enable
GPIOmotor2in3 = 6 # Motor 2 input3
GPIOmotor2in4 = 13 # Motor 2 input4

# GPIO Modus festlegen
GPIO.setmode(GPIO.BCM) # Modus BCM festgelegt
GPIO.setwarnings(False) # GPIO Warnungen deaktiviert

# Pins IN und OUT festlegen
GPIO.setup(GPIOgruen, GPIO.OUT)
GPIO.setup(GPIOgelb, GPIO.OUT)
GPIO.setup(GPIOrot, GPIO.OUT)
GPIO.setup(GPIOecho_re, GPIO.IN)
GPIO.setup(GPIOtrig_re, GPIO.OUT)
GPIO.setup(GPIOecho_li, GPIO.IN)
GPIO.setup(GPIOtrig_li, GPIO.OUT)
GPIO.setup(GPIOmotor1en1, GPIO.OUT)
GPIO.setup(GPIOmotor1in1, GPIO.OUT)
GPIO.setup(GPIOmotor1in2, GPIO.OUT)
GPIO.setup(GPIOmotor2en2, GPIO.OUT)
GPIO.setup(GPIOmotor2in3, GPIO.OUT)
GPIO.setup(GPIOmotor2in4, GPIO.OUT)

# Pins zuruecksetzen
GPIO.output(GPIOgruen, False)
GPIO.output(GPIOgelb, False)
GPIO.output(GPIOrot, False)
GPIO.output(GPIOtrig_re, False)
GPIO.output(GPIOtrig_li, False)
GPIO.output(GPIOmotor1en1, False)
GPIO.output(GPIOmotor1in1, False)
GPIO.output(GPIOmotor1in2, False)
GPIO.output(GPIOmotor2en2, False)
GPIO.output(GPIOmotor2in3, False)
GPIO.output(GPIOmotor2in4, False)

def led_start():
    GPIO.output(GPIOrot, True)
    time.sleep (1.0)
    GPIO.output(GPIOgelb, True)
    time.sleep (1.0)
    GPIO.output(GPIOgruen, True)
    time.sleep (1.0)
    GPIO.output(GPIOgelb, False)
    GPIO.output(GPIOrot, False)

def led_gruen():
    GPIO.output(GPIOrot, False)
    GPIO.output(GPIOgelb, False)
    GPIO.output(GPIOgruen, True)

def led_gelb():
    GPIO.output(GPIOrot, False)
    GPIO.output(GPIOgelb, True)
    GPIO.output(GPIOgruen, False)

def led_rot():
    GPIO.output(GPIOrot, True)
    GPIO.output(GPIOgelb, False)
    GPIO.output(GPIOgruen, False)

def measure_distance_re():
    GPIO.output(GPIOtrig_re, True) # High Signal auf Trigger geben
    time.sleep(0.00001)
    GPIO.output(GPIOtrig_re, False) # Low Signal auf Trigger geben
    start_time = time.time() # Initialisiere Zeit
    while GPIO.input(GPIOecho_re) == 0: # Solange Echo low ist
        start_time = time.time() # Zeit wird in Variable start_time geschrieben
    while GPIO.input(GPIOecho_re) == 1: # Solange Echo high ist
        stop_time = time.time() # Zeit wird in Variable stop_time geschrieben
    # Entfernung berechnen
    time_elapsed = stop_time - start_time # start_time wird von stop_time abgezogen 
    distance_re = (time_elapsed * 34300) / 2 # Berechnung der Distanz in cm
    return distance_re # Gibt das Ergebnis zurueck

def measure_distance_li():
    GPIO.output(GPIOtrig_li, True) # High Signal auf Trigger geben
    time.sleep(0.00001)
    GPIO.output(GPIOtrig_li, False) # Low Signal auf Trigger geben
    start_time = time.time() # Initialisiere Zeit
    while GPIO.input(GPIOecho_li) == 0: # Solange Echo low ist
        start_time = time.time() # Zeit wird in Variable start_time geschrieben
    while GPIO.input(GPIOecho_li) == 1: # Solange Echo high ist
        stop_time = time.time() # Zeit wird in Variable stop_time geschrieben
    # Entfernung berechnen
    time_elapsed = stop_time - start_time # start_time wird von stop_time abgezogen 
    distance_li = (time_elapsed * 34300) / 2 # Berechnung der Distanz in cm
    return distance_li # Gibt das Ergebnis zurueck

def move_stop():
    # Motor1
    GPIO.output(GPIOmotor1en1, False)
    GPIO.output(GPIOmotor1in1, False)
    GPIO.output(GPIOmotor1in2, False)
    # Motor2
    GPIO.output(GPIOmotor2en2, False)
    GPIO.output(GPIOmotor2in3, False)
    GPIO.output(GPIOmotor2in4, False)

def move_forward():
    # Motor1
    GPIO.output(GPIOmotor1en1, True)
    GPIO.output(GPIOmotor1in1, True)
    GPIO.output(GPIOmotor1in2, False)
    # Motor2
    GPIO.output(GPIOmotor2en2, True)
    GPIO.output(GPIOmotor2in3, True)
    GPIO.output(GPIOmotor2in4, False)

def move_backward():
    # Motor1
    GPIO.output(GPIOmotor1en1, True)
    GPIO.output(GPIOmotor1in1, False)
    GPIO.output(GPIOmotor1in2, True)
    # Motor2
    GPIO.output(GPIOmotor2en2, True)
    GPIO.output(GPIOmotor2in3, False)
    GPIO.output(GPIOmotor2in4, True)

def move_left():
    # Motor1
    GPIO.output(GPIOmotor1en1, True)
    GPIO.output(GPIOmotor1in1, False)
    GPIO.output(GPIOmotor1in2, True)
    # Motor2
    GPIO.output(GPIOmotor2en2, True)
    GPIO.output(GPIOmotor2in3, True)
    GPIO.output(GPIOmotor2in4, False)

def move_right():
    # Motor1
    GPIO.output(GPIOmotor1en1, True)
    GPIO.output(GPIOmotor1in1, True)
    GPIO.output(GPIOmotor1in2, False)
    # Motor2
    GPIO.output(GPIOmotor2en2, True)
    GPIO.output(GPIOmotor2in3, False)
    GPIO.output(GPIOmotor2in4, True)

def turn_left():
    led_rot()
    move_stop()
    time.sleep(0.5)
    move_backward()
    time.sleep(2.0)
    move_stop()
    time.sleep(0.5)
    move_left()
    time.sleep(1.2)
    move_stop()
    time.sleep(0.5)

def turn_right():
    led_rot()
    move_stop()
    time.sleep(0.5)
    move_backward()
    time.sleep(2.0)
    move_stop()
    time.sleep(0.5)
    move_right()
    time.sleep(1.2)
    move_stop()
    time.sleep(0.5)
	
def main_automatik(): # Funktion automatische Steuerung
    try:
        while True:
            distance_re = measure_distance_re() # Fuehrt die Funktion measure_distance_re aus und uebernimmt Ergebnis
            print "Entfernung rechts = %.2f cm" % distance_re
            distance_li = measure_distance_li() # Fuehrt die Funktion measure_distance_li aus und uebernimmt Ergebnis
            print "Entfernung links = %.2f cm" % distance_li
            time.sleep(0.2)
            if distance_re < 30.00 or distance_li < 30.00:
                if distance_re < 30.00:
                    turn_left()
                if distance_li < 30.00:
                    turn_right()
            elif distance_re < 40.00 or distance_li < 40.00:
                led_gelb()
            else:
                led_gruen()
                move_forward()
    except KeyboardInterrupt: # Unterbricht bei Eingabe von Strg + c
        print "Messung gestoppt"
        GPIO.cleanup()


@app.route('/')
def index():
    return render_template('index.html')

@app.route('/controlit', methods = ['POST'])
def main_manuell(): # Funktion manuelle Steuerung
    button_hit = request.form['buttonPress']
    global varhit
    varhit = button_hit
    if button_hit == 'Vorwaerts':
        print "Vorward"
        move_stop()
        time.sleep(0.5)
        move_forward()
    if button_hit == 'Zurueck':
        print "Back"
        move_stop()
        time.sleep(0.5)
        move_backward()
    if button_hit == 'Links':
        print "Left"
        move_stop()
        move_left()
        time.sleep(0.5)
        move_stop()
    if button_hit == 'Rechts':
        print "Right"
        move_stop()
        move_right()
        time.sleep(0.5)
        move_stop()
    if button_hit == 'Stop':
        print "Stop"
        move_stop()
    #if button_hit == 'Automatik':
        #main_automatik
    return redirect('/')
        
if __name__ == '__main__':
    led_start()
    app.run(host='0.0.0.0', port=5000, debug = True)
    main_manuell()
Zuletzt geändert von Anonymous am Montag 29. Mai 2017, 09:35, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Sirius3
User
Beiträge: 8115
Registriert: Sonntag 21. Oktober 2012, 17:20

Montag 29. Mai 2017, 10:57

@ice2711: kurze Antwort, du brauchst einen Thread in dem der Webserver läuft und eine Hauptschleife für die Steuerung Deines Fahrzeugs. Damit ist wichtig, dass nur in der Hauptschleife alle Pins angesteuert werden, der Webserver ist nur dazu da, bestimmte Befehle an die Hauptschleife zu senden. Das Senden findet am besten über eine Queue statt. "global" zu benutzen ist nie eine gute Idee und auf oberster Ebene sogar noch nutzlos. Die Motorensteuerung würde ich über eine passende Datenstruktur lösen und nicht durch Funktionsaufrufe. Damit bist Du dann flexibler, die einzelnen Bewegungen zusammenzuschalten. GPIO-Warnings auf False zu setzen ist immer eine schlechte Idee, weil die Warnungen Dir ja sagen, dass Du etwas falsch machst; dann solltest Du die Ursache beheben und sie nicht einfach ignorieren. Das cleanup in main_automatik ist dort an der falschen Stelle. Ein cleanup sollte immer am Ende des Programms stattfinden und nicht in einer Funktion und nicht nur, wenn man das Programm mit Ctrl+C abbricht.
BlackJack

Montag 29. Mai 2017, 11:10

@ice2711: Man müsste die Programmlogik von der Benutzerinteraktion trennen und die Programmlogik zum Beispiel per Thread nebenläufig ausführen. Mit all den Problemen die nebenläufige Programmierung so mit sich bringt. Also beispielsweise das Du die Interaktion der Threads thread-safe hinbekommen musst. Einfachste Variante ist Kommunikation zwischen den Threads mittels Queues.

Anmerkungen zum Quelltext:

`multiprocessing.Process` wird importiert, aber nicht verwendet. Wäre sowieso nicht die beste Wahl hier, denn man braucht ja nicht wirklich 100% parallele Ausfürhrung um meherere Kerne auszunutzen, sondern nur nebenläufige Ausführung von den verschiedenen Programmteilen, damit die sich nicht gegenseitig blockieren.

``global`` hat auf Modulebene keine Effekt, macht dort also keinen Sinn. Und in einem sauberen Programm haben globale Variablen sowieso nichts zu suchen. Weg damit. `varhit` wird zudem ja auch gar nicht wirklich benutzt.

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

Kommentare sollten dem Leser einen Mehrwert über den Code liefern und nicht einfach nur das wiederholen was dort offensichtlich schon als Code steht. Also ``# Import Module`` vor den Modulimporten ist sinnlos. Wer das ohne den Kommentar nicht versteht, dem wird auch der Kommentar nicht weiterhelfen. Faustregel: Kommentare beschreiben *warum* der Code das macht was er macht, denn *was* er macht, beschreibt der Code selbst bereits. Wenn das warum nicht klar ist, und man das im Code auch nicht besser ausdrücken kann, *dann* kann ein Kommentar hilfreich sein. Man sollte aber immer erst einmal schauen ob man den Code nicht verständlicher schreiben kann. Oft hilft eine passende Namenswahl für Werte und Funktionen weiter.

Wenn man beispielsweise Konstanten für Pins definiert, dann kann man das mit den Pins in einen Kommentar schreiben, oder man wählt die Namen so, dass man diesen Kommentar nicht braucht. Konstanten werden übrigens per Konvention KOMPLETT_IN_GROSSBUCHSTABEN geschrieben. Siehen auch den Style Guide for Python Code.

Der Aufruf von `main_manuell()` nach `app.run()` macht keinen Sinn. `app.run()` kehrt nicht zurück bis man das Programm beispielsweise mit Strg+C abbricht.

Statt die Warnungen mit `GPIO.setwarnings()` auszuschalten, sollte man die Probleme beseitigen die zu Warnungen führen. Meistens ist das sowieso nur, dass am Programmende nicht ordentlich aufgeräumt wird und deshalb beim nächsten Programmstart eine Warnung deswegen ausgegeben wird. Man will *auf jeden Fall* `GPIO.cleanup()` aufrufen. Das sollte als sehr weit oben in der Aufrufhierarchie und in einem ``finally``-Zweig stehen. Die Behandlung von Strg+C sollte auch auf oberster Ebene der Aufrufhierarchie stehen, sonst wird am Ende nicht alles abgebrochen was man damit abbrechen möchte.

Viele Funktionen enthalten nahezu den gleichen Code der sich nur durch ein paar Werte unterscheidet. Solche Codewiederholungen verletzen das DRY-Prinzip — Don't Repeat Yourself. Wenn man einen Fehler in solchen Code beheben muss, oder etwas ändern möchte, muss man das in jeder Kopie des Codes tun, und auch in jeder Kopie auf die gleiche Art und Weise. Das macht nicht nur unnötig mehr Arbeit, dabei besteht auch die Gefahr das man Fehler macht und die Kopien am Ende auseinanderlaufen.

Das Messen des Abstands ist der ”schwerste” Fall, weil hier wirklich viel Kode kopiert wurde. Da sollte man die Daten die sich bei den beiden Kopien unterscheiden heraus ziehen und beim Aufruf als Argumente übergeben.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python
# coding: utf8
from __future__ import absolute_import, division, print_function
import time
from RPi import GPIO
from flask import Flask, request, redirect, render_template

app = Flask(__name__)

GREEN_LED_PIN = 18
YELLOW_LED_PIN = 23
RED_LED_PIN = 24
RIGHT_ECHO_PIN = 25
RIGHT_TRIGGER_PIN = 12
LEFT_ECHO_PIN = 20
LEFT_TRIGGER_PIN = 16
MOTOR_A_ENABLE_PIN = 4
MOTOR_A_INPUT_1_PIN = 17
MOTOR_A_INPUT_2_PIN = 27
MOTOR_B_ENABLE_PIN = 5
MOTOR_B_INPUT_1_PIN = 6
MOTOR_B_INPUT_2_PIN = 13


def led_start():
    GPIO.output(RED_LED_PIN, True)
    time.sleep(1.0)
    GPIO.output(YELLOW_LED_PIN, True)
    time.sleep(1.0)
    GPIO.output(GREEN_LED_PIN, True)
    time.sleep(1.0)
    GPIO.output(YELLOW_LED_PIN, False)
    GPIO.output(RED_LED_PIN, False)


def led_gruen():
    GPIO.output(RED_LED_PIN, False)
    GPIO.output(YELLOW_LED_PIN, False)
    GPIO.output(GREEN_LED_PIN, True)


def led_gelb():
    GPIO.output(RED_LED_PIN, False)
    GPIO.output(YELLOW_LED_PIN, True)
    GPIO.output(GREEN_LED_PIN, False)


def led_rot():
    GPIO.output(RED_LED_PIN, True)
    GPIO.output(YELLOW_LED_PIN, False)
    GPIO.output(GREEN_LED_PIN, False)


def measure_distance(trigger_pin, echo_pin):
    GPIO.output(trigger_pin, True)
    time.sleep(0.00001)
    GPIO.output(trigger_pin, False)
    start_time = time.time()
    while not GPIO.input(echo_pin):
        start_time = time.time()
    while GPIO.input(echo_pin):
        stop_time = time.time()
    elapsed_time = stop_time - start_time
    return (elapsed_time * 34300) / 2  # Berechnung der Distanz in cm


def move_stop():
    GPIO.output(MOTOR_A_ENABLE_PIN, False)
    GPIO.output(MOTOR_A_INPUT_1_PIN, False)
    GPIO.output(MOTOR_A_INPUT_2_PIN, False)

    GPIO.output(MOTOR_B_ENABLE_PIN, False)
    GPIO.output(MOTOR_B_INPUT_1_PIN, False)
    GPIO.output(MOTOR_B_INPUT_2_PIN, False)


def move_forward():
    GPIO.output(MOTOR_A_ENABLE_PIN, True)
    GPIO.output(MOTOR_A_INPUT_1_PIN, True)
    GPIO.output(MOTOR_A_INPUT_2_PIN, False)

    GPIO.output(MOTOR_B_ENABLE_PIN, True)
    GPIO.output(MOTOR_B_INPUT_1_PIN, True)
    GPIO.output(MOTOR_B_INPUT_2_PIN, False)


def move_backward():
    GPIO.output(MOTOR_A_ENABLE_PIN, True)
    GPIO.output(MOTOR_A_INPUT_1_PIN, False)
    GPIO.output(MOTOR_A_INPUT_2_PIN, True)

    GPIO.output(MOTOR_B_ENABLE_PIN, True)
    GPIO.output(MOTOR_B_INPUT_1_PIN, False)
    GPIO.output(MOTOR_B_INPUT_2_PIN, True)


def move_left():
    GPIO.output(MOTOR_A_ENABLE_PIN, True)
    GPIO.output(MOTOR_A_INPUT_1_PIN, False)
    GPIO.output(MOTOR_A_INPUT_2_PIN, True)

    GPIO.output(MOTOR_B_ENABLE_PIN, True)
    GPIO.output(MOTOR_B_INPUT_1_PIN, True)
    GPIO.output(MOTOR_B_INPUT_2_PIN, False)


def move_right():
    GPIO.output(MOTOR_A_ENABLE_PIN, True)
    GPIO.output(MOTOR_A_INPUT_1_PIN, True)
    GPIO.output(MOTOR_A_INPUT_2_PIN, False)

    GPIO.output(MOTOR_B_ENABLE_PIN, True)
    GPIO.output(MOTOR_B_INPUT_1_PIN, False)
    GPIO.output(MOTOR_B_INPUT_2_PIN, True)


def turn_left():
    led_rot()
    move_stop()
    time.sleep(0.5)
    move_backward()
    time.sleep(2.0)
    move_stop()
    time.sleep(0.5)
    move_left()
    time.sleep(1.2)
    move_stop()
    time.sleep(0.5)


def turn_right():
    led_rot()
    move_stop()
    time.sleep(0.5)
    move_backward()
    time.sleep(2.0)
    move_stop()
    time.sleep(0.5)
    move_right()
    time.sleep(1.2)
    move_stop()
    time.sleep(0.5)


def main_automatik():
    while True:
        right_distance = measure_distance(RIGHT_TRIGGER_PIN, RIGHT_ECHO_PIN)
        print('Entfernung rechts = {0:.2f} cm'.format(right_distance))
        left_distance = measure_distance(LEFT_TRIGGER_PIN, LEFT_ECHO_PIN)
        print('Entfernung links = {0:.2f} cm'.format(left_distance))
        time.sleep(0.2)
        if right_distance < 30.00 or left_distance < 30.00:
            if right_distance < 30.00:
                turn_left()
            if left_distance < 30.00:
                turn_right()
        elif right_distance < 40.00 or left_distance < 40.00:
            led_gelb()
        else:
            led_gruen()
            move_forward()


@app.route('/')
def index():
    return render_template('index.html')


@app.route('/controlit', methods=['POST'])
def main_manuell():
    button_hit = request.form['buttonPress']
    if button_hit == 'Vorwaerts':
        print('Forward')
        move_stop()
        time.sleep(0.5)
        move_forward()
    if button_hit == 'Zurueck':
        print('Back')
        move_stop()
        time.sleep(0.5)
        move_backward()
    if button_hit == 'Links':
        print('Left')
        move_stop()
        move_left()
        time.sleep(0.5)
        move_stop()
    if button_hit == 'Rechts':
        print('Right')
        move_stop()
        move_right()
        time.sleep(0.5)
        move_stop()
    if button_hit == 'Stop':
        print('Stop')
        move_stop()
    return redirect('/')


def main():
    try:
        GPIO.setmode(GPIO.BCM)

        GPIO.setup(
            [GREEN_LED_PIN, YELLOW_LED_PIN, RED_LED_PIN],
            GPIO.OUT,
            initial=False,
        )
        GPIO.setup(RIGHT_ECHO_PIN, GPIO.IN)
        GPIO.setup(RIGHT_TRIGGER_PIN, GPIO.OUT, initial=False)
        GPIO.setup(LEFT_ECHO_PIN, GPIO.IN)
        GPIO.setup(LEFT_TRIGGER_PIN, GPIO.OUT, initial=False)
        GPIO.setup(
            [
                MOTOR_A_ENABLE_PIN,
                MOTOR_A_INPUT_1_PIN,
                MOTOR_A_INPUT_2_PIN,
                MOTOR_B_ENABLE_PIN,
                MOTOR_B_INPUT_1_PIN,
                MOTOR_B_INPUT_2_PIN,
            ],
            GPIO.OUT,
            initial=False,
        )

        led_start()
        app.run(host='0.0.0.0', port=5000, debug=True)
    except KeyboardInterrupt:  # Behandelt die Eingabe von Strg+C
        print('Programm gestoppt')
    finally:
        GPIO.cleanup()


if __name__ == '__main__':
    main()
Du solltest auch anfangen Dich mit Verbunddatentypen (`collections.namedtuple()` und Klassen) auseinander zu setzen und zum Beispiel Pins die zusammengehören in solchen Objekten zusammenfassen. Das macht das Programm leichter nachvollziehbar.
ice2711
User
Beiträge: 3
Registriert: Montag 29. Mai 2017, 09:02

Montag 29. Mai 2017, 13:42

Wow, erstmal vielen Dank an Sirius3 und BlackJack für die schnellen und ausführlichen Antworten. Wobei ich ehrlich gesagt nicht alles 100%ig verstanden habe. Werde da erstmal ein paar Dinge nachlesen müssen. Die unnötigen Überbleibsel im Code kann ich damit erklären dass ich verschiedene Dinge schon versucht aber dann nicht alles wieder restlos zurück genommen habe.
ice2711
User
Beiträge: 3
Registriert: Montag 29. Mai 2017, 09:02

Montag 19. Juni 2017, 22:03

Nochmal Danke für eure Hilfe. Ich konnte das Problem jetzt lösen. :D
Antworten