Kommunikation mit Unterprogramm

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
Stephanius II
User
Beiträge: 2
Registriert: Mittwoch 21. Juni 2017, 19:48

Hallo Zusammen

zuerst einmal, ich habe mir das alles selber beigebracht, also entschuldigt, wenn die Lösungen etwas Unkonventionell oder sowieso total unpassend oder unnötig komplex oder was auch immer sind, ich kenne leider niemanden, der Python ordentlich beherrscht und fand leider viel zu lange, dass es unnötig sei, ein Buch zu Python zu bestellen. Inzwischen ist eines unterwegs, es kommt leider nicht innert nützlicher frist an. Saudumm? richtig!

Also wenn ihr übrige Zeit habt, könnt ihr mich gerne in Formsachen korrigieren oder auf einfachere Lösungen hinweisen usw. Was auch immer ihr für Tipps habt, sie sind herzlich wilkommen!

Also, meine situation ist folgendermassen: Ich habe für ein projekt in der Schule eine Uhr mit Binäranzeige gebaut. Hierbei verwende ich ein Raspberry Pi und steuere über die GPIO pins eine LEDmatrix mit jeweils sechs LEDs für sekunden und minuten und fünf LEDs für die Anzeige der Stunden an. Die auswertung und umwandlung der Zeit sowie die Steuerung der GPIO Pins erfolgt über ein Pythonscript:

Code: Alles auswählen

import RPi.GPIO as gpio                 #importiert die Befehle zu den GPIO Pins
from time import strftime as t          #importiert die benötigten Befehle zum abfragen der Uhrzeit
from subprocess import Popen as popen   #importiert den Befehl zum öffnen anderer Skripte

gpio.setmode(gpio.BOARD) #Wählt die Nummerierun der GPIO Pins

ColumnList = [7,8,10,12,11,13]  #Liste der Benötigten Pins zur Steuerung der einzelnen Ledspalten
RowList = [15,16,18,19]         #Liste der Benötigten Pins zur Steuerung der einzelnen Ledreihen
InputList= [21,22,24]           #Liste der Benötigten Pins für die abfrage der Knöpfe

gpio.setup(RowList, gpio.OUT, initial = 1)                   #Setzt die Pins für die Steuerung der Ledreihen auf, 1=Aus
gpio.setup(ColumnList, gpio.OUT, initial = 0)                #Setzt die Pins für die Steuerung der Ledspalten auf, 1=Ein
gpio.setup(InputList, gpio.IN, pull_up_down = gpio.PUD_DOWN) #Setzt die Pins für die Abfrage der Knöpfe auf

allways = 1      #Die Standardzustände der Variablen werden eingestellt
OutputMode = 0 #OutputMode bestimmt, was ausgegeben werden soll: 24 bei drücken des Knopfs auf Pin 24 -> die Zeitanzeige ein/aus
#geplant sind noch: 34 bei langem drücken von knopf auf Pin24-> Zeit einstellen mit 21(+1), 22(nächste Zeiteinheit) 24(-1)
#32 bei Langem drücken von Knopf auf Pin22-> Wecker einstellen mit 21(+1), 22(nächste Zeiteinheit) 24(-1)
 
def button_input(InpuList):  #Hier werte ich die Inputs der drei Knöpfe aus.
    for pin in InputList
        gpio.add_event_detect(pin, gpio.RISING) 
        if gpio.event_detected(pin): #Wenn eine positive Signalflanke erkannt wird...
            if OutputMode == pin:
                output = 0
            else if OutputMode == 0:
                output = pin
            return output

while allways == 1:

    OutputMode = button_input(InputList)
    
    if OutputMode == 24: #Wenn die Zeit angezeigt werden soll
        inverted_bhr = format(63 - int(t("%H")), "06b") #Fragt die aktuelle Systemzeit ab und wandelt sie
        inverted_bmin = format(63 - int(t("%M")), "06b") #in die nötige form
        inverted_bsec = format(63 - int(t("%S")), "06b") #h = Stunden, m = Minuten, s = Sekunden

        #Da die Ausgänge für die richtige ausgabe nicht auf eins, sondern auf null gestellt werden müssen,
        #werden die binären Einsen und Nullen invertiert
        #bsp: s = 51 = 110011:  63 - 51 = 12 = 001100

        #format() wandelt die Zahl in eine binäre zahl mit 6 stellen um
        #Pro stelle eine LED
        
        Row13 = '000' + inverted_bhr[1]   #Teilt die zahlen in zwei 4-stellige Teile -> je zwei Ledlinien für Studen, Minuten, und Sekunden
        Row11 = inverted_bhr[2:6]         
        Row12 = '00' + inverted_bmin[0:2]
        Row10 = inverted_bmin[2:6]
        Row8  = '00' + inverted_bsec[0:2]
        Row7  = inverted_bsec[2:6]

    for Column in ColumnList:       #Jede Splate wird nun nacheinander abgearbeitet
        gpio.output(Column, 1)      
        StrColumn = str(Column)     
        zRow = 'Row' + StrColumn    #Sorgt dafür, dass der momentanen Spalte die richtige Reihe zugeordnet wird
        rRow = eval(zRow)
        
        gpio.output(15, eval(rRow[0]))  #gibt die Outputs für die LEDreihen aus
        gpio.output(16, eval(rRow[1]))  #Da ich eine Ledmatrix verwende, kann immer nur eine Ledspalte engesteuert werden.
        gpio.output(18, eval(rRow[2]))
        gpio.output(19, eval(rRow[3]))
        gpio.output(RowList, 1)         #Schaltet alle Outputs wieder zurück
        gpio.output(ColumnList, 0)

    if OutputMode == 0:         #Sobald der Taster aus ist, wird die Schleife beendet und die Outputs zurückgesetzt
        gpio.output(RowList, 1)
        gpio.output(ColumnList, 0)

Soweit funktioniert das Script.
Nun zum Problem: Die Outputs werden zu langsam ausgegeben, das heisst, die Anzeige Flackert. würde es helfen, wenn ich diesen Programmteil

Code: Alles auswählen

        gpio.output(15, eval(rRow[0]))  #gibt die Outputs für die LEDreihen aus
        gpio.output(16, eval(rRow[1]))
        gpio.output(18, eval(rRow[2]))
        gpio.output(19, eval(rRow[3]))
        gpio.output(RowList, 1)         #Schaltet alle Outputs wieder zurück
        gpio.output(ColumnList, 0)
in ein seperates Script schreiben würde, welches ich mit subprocess.popen öffnen würde? und wie kann ich einen andauernden Variablenaustauch ermöglichen, ohne dass bei jedem durchlauf ein neues script geöffnet wird?

Ein Weiteres Problem ist, dass ich gerne zwischen einem Langen und einem Kurzen drücken der Taster unterscheiden würde, ohne dass das Programm für eine kurze zeit unterbrochen wird. Wie könnte man das Bewerkstellingen?
__deets__
User
Beiträge: 14480
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wieso sollte denn ein zweites Skript das ebenfalls in Python geschrieben ist irgendetwas verschnellern? Wenn dir dazu ein Trick einfällt, dann kannst du das ja gleich in dein eines Skript schreiben. Wie kommst du darauf, dass ein extra Prozess das magisch beschleunigt?

Ich sitze hier am iPad, darum ist es etwas schwer Kritik an deinem Code zu üben. Was aber klar ist: vergiss SOFORT das es eval gibt. In meinen >20 Jahren als Python Entwickler habe ich das noch nie gebraucht, und du benutzt es scheinbar statt vernünftiger Datenstrukturen. Vielleicht dazu später mehr.

Und was das eigentliche Problem angeht: RPI.GPIO ist eh Mist. Und das deutlich bessere pigpio kennt das hier: http://abyz.co.uk/rpi/pigpio/python.html#set_bank_1

Damit setzt du alle pins in einem Rutsch. Das sollte das flackern beseitigen.

Für die zweite frage: dafür gibt es Event callbacks die du registrieren kannst um darüber informiert zu werden, dass ein Pin seinen Zustand geändert hat. Aber Achtung: dabei betrittst du das verminte Gelände der nebenläufigen Programmierung!
BlackJack

@Stephanius II: Das ist nicht der Code den Du laufen lässt, denn der hier hat zwei Syntaxfehler‽

Zum Flackern: Kann es sein das Du da selbst für verantwortlich bist, weil du die Bits/Leds setzt, aber in Zeile 63 danach *sofort* wieder ausschaltest‽

Die `button_input()`-Funktion verwendet ihr Argument gar nicht weil da ein Tippfehler beim Namen ist und zufällig die richtigen Werte global auch unter dem Namen existieren der eigentlich das Argument sein sollte. Zudem bedient sich die Funktion auch am globalen `OutputMode`, was sie nicht sollte. Alles was eine Funktion oder Methode an Werten verwendet, und was keine Konstante ist, sollte als Argument in die Funktion hinein kommen. Und nicht auf magische Weise irgendwie in der Umgebung existieren. Das macht nämlich denn Sinn von Funktionen zunichte, das man eine in sich geschlossene Einheit hat, die man isoliert betrachten und testen kann.

Dieses „Wert magisch aus der Umgebung nehmen“ kann gar nicht erst passieren wenn alles was nicht Definition von Konstanten, Funktionen, und Klassen ist, in Funktionen stecken würde. Üblicherweise steht das Hauptprogramm in einer Funktion die `main()` heisst.

Die `button_input()`-Funktion gibt übrigens entweder eine Pinnummer oder 0 oder `None` als ”spezielle” Werte zurück. Das `None` sollte man explizit machen, damit sich der Leser nicht fragt ob das ein Programmfehler oder Absicht ist. Wobei es tatsächlich nach eine Programmfehler aussieht, denn der Code kann eigentlich nur zwischen 0 und einer Pinnummer wechseln, sowie da `None` ins Spiel kommt, durchbricht das diesen Kreis.

Deine Kommentierungen erschweren das lesen sehr. Du sprengst damit die Grenze von 80 Zeichen pro Zeile, was in einigen Ausgaben, zum Beispiel in einer Konsole, in E-Mails, hier im Forum, …, entweder dazu führt, dass nicht alles auf einmal sichtbar ist, oder das nach 80 Zeichen umgebrochen wird und die Kommentare für einen ”Kammeffekt” sorgen, der es schwerer macht die Struktur des Programms, die durch die Einrückung ja eigentlich schön sichtbar sein sollte, zu erfassen. In Python ist es üblich längere Kommentare vor den Code zu setzen, der damit kommentiert wird.

So einiges an Kommentaren könnte und sollte man sich auch sparen. Kommentare sollten einen Mehrwert über den Code liefern, und zwar für Leute die die Programmiersprache können und die Dokumentation von Modulen lesen können. Es macht beispielsweise keinen Sinn eine Schleife ``for Column in ColumnList:`` damit zu kommentieren das hier die Spalten nacheinander abgearbeitet werden. Das sagt der Code bereits *sehr* deutlich. Faustregel: Kommentare sollten nicht beschreiben *was* der Code macht, denn das kann man bereits am Code sehen, sondern *warum* er dass macht, was er macht. Sofern das nicht aus dem Code bereits offensichtlich ist.Sinnvoll kommentiert ist beispielsweise die Berechnung der `inverted_*`-Variablen, denn das ist vielleicht nicht so ganz offensichtlich warum das da so gemacht wird.

Was soll diese Umbenennungsorgie bei den importen? Bei `GPIO` und `Popen` verwirrt das Leute die diese Module gewohnt sind, und damit auch gewohnt sind genau diese Namen im Quelltext zu lesen. Und `time.strftime()` in `t()` umzubenennen geht gar nicht. Einbuchstabige Namen gehen bis auf wenige Ausnahmen gar nicht. Ein Name soll dem Leser vermitteln was der Wert im Kontext des Programms bedeuten soll. `t()` tut das nicht. Nicht das `strftime()` ein guter Name wäre, im Gegenteil der ist total kryptisch. Deswegen sollte man auch keine Abkürzungen oder kryptische Namenszusätze in Namen verwenden (`zRow`, `rRow`). `strftime()` könne man sinnvoll beispielsweise in `format_time()` umbenennen.

Konstantennamen werden per Konvention komplett in Grossbuchstaben geschrieben. Und mit Grossbuchstaben anfangen tun nur Konstanten- und Klassennamen. Ansonsten wird `klein_mit_unterstrichen` benannt. Siehe den Style Guide for Python Code.

Konkrete Grunddatentypen haben nichts in Namen verloren. Im Laufe der Programmentwicklung ändert man durchaus öfter mal den Typ in einen passenderen, oder man implementiert einen eigenen, und dann hat man entweder falsche und irreführende Namen im Programm, oder muss die überall ändern. Sequenztypen wie Listen benennt man üblicherweise in der Mehrzahl dessen was für ein einzelnes Element ein passender Name wäre. `ColumnList` würde zum Beispiel besser `COLUMN_PINS` heissen. Wenn man die beiden anderen `*List`-Namen für Pins entsprechend umändert, dann werden dort auch die Kommentare überflüssig, denn die Information steckt bereits im Namen. Und ist damit auch gleich überall dort verfügbar wo diese Namen verwendet werden. Man muss also nicht erst den Kommentar zum Namen suchen.

Wenn man die GPIOs verwendet, sollte man am Programmende auch aufräumen, also garantieren das die `GPIO.cleanup()`-Funktion aufgerufen wird.

`allways` ändert nie den Wert und damit ändert sich das Ergebnis der ``while``-Bedingung niemals, also kann man da auch gleich das Ergebnis (`True`) verwenden und sich `allways` sparen.

Die ”magischen” Zahlen für die Buttons machen das Programm unverständlich. Zudem hängen sie von den konkreten Pins ab an denen die Buttons angeschlossen sind. Man sollte daraus mindestens Konstanten machen. Also statt 24 im Programm zu schreiben, besser DISPLAY_TIME_BUTTON, dann braucht man auch wieder weniger Kommentare die erklären was die 24 eigentlich bedeuten soll. Oder wenn die Buttons kontextabhängige Funktion haben, dann doch mindestens BUTTON_A_PRESSED und BUTTON_A_LONG_PRESSED, und so weiter.

Bei der Ermittlung der Zeit hast Du einen Programmfehler: Du musst den aktuellen Zeitpunkt mit *einem* Aufruf ermitteln, sonst kann es beim Übergang einer Minute auf die Nächste oder einer Stunde auf die nächste, oder einem Tag auf den Nächsten passieren, dass die drei Einzelwerte nicht zusammen passen. Die Aufrufe brauchen Zeit und während dieser Zeit läuft die Systemuhr weiter. Wenn es also 12:59:59 ist wenn Du die Stunden abfragst, kann es schon 13:00:00 sein wenn Du Minuten und Sekunden abfragst. Die angezeigte Uhrzeit wäre dann 12:00:00 — um 13:00:00.

Die Uhrzeit in Zeichenketten zu formatieren um die dann in Zahlen umzuwandeln, und die dann wieder in Zeichenketten zu wandeln, die dann später wieder… ist extrem umständlich und unübersichtlich. Als Einstieg solltest Du `datetime.datetime.now()` verwenden um alle drei Zeitwerte *auf einmal* zu bekommen und dann auch gleich als *Zahlen*. Das Invertieren von Bits geht mit einer bitweisen XOR-Verknüpfung oder einem biweisem NOT verständlicher als durch abziehen von einer magischen 63. Die in diesem Fall als literaler Binärwert verständlicher gewesen wäre. Auch das Operieren auf Zeichenketten mit Binärdarstellungen ist unschön — dafür gibt es verschiedene Bitoperationen.

Zum `eval()` was gar nicht geht: Vergiss das es die Funktion überhaupt gibt! Zudem wird das auch nicht als `int()`-Ersatz verwendet, ist in dem Code also an vier Stellen gar nicht nötig! Und das einzige wirklich ”gebrauchte” `eval()` ist nötig weil Du Variablennamen mit angehängten Pinnummern dynamisch abfragen willst. Das könnte man mit einem Wörterbuch das Pinnummern auf die Werte abbildet ohne `eval()` umsetzen. Da die Werte aber in der Reihenfolge der Pinnummern für die Zeilen abgerufen werden, kann man die auch einfach in dieser Reihenfolge in einer Liste speichern und ist damit an dieser Stelle unabhängig von den konkreten Pinnummern, die sich ja vielleicht auch mal ändern könnten, was die Programmanpassung unnötig schwer macht. Insbesondere wenn man nach Namen mit Pinnummern suchen muss. Die Pinnummern sind Daten und Daten gehören nicht in Namen.

Da fällt mir gerade ein weiterer Programmfehler auf: Wenn der Button nicht gedrückt wurde, sind die `Row*`-Namen undefiniert, werden aber trotzdem versucht ab Zeile 56 per `eval()` auszuwerten. Hast Du das überhaupt mal laufen lassen?

Die Zeilen-Pins stehen nacheinander in den `GPIO.output()` aufrufen statt das in einer Schleife zu lösen. Auch hier ist es wieder umständlich und fehleranfällig wenn man an den Werten etwas ändern will oder muss.

Warum stellst Du am Ende der Schleife an deren Anfang genau *ein* Zeilenpin auf 1 gesetzt wurde, am Ende *alle* wieder auf 0, statt nur den einen?

Der Kommentar in Zeile 66 ist falsch. Oder der Code ist falsch. Eines von beidem sollte dringend korrigiert werden.

Ich lande dann als Zwischenschritt (völlig ungetestet) ungefähr hier:

Code: Alles auswählen

# coding: utf8
from datetime import datetime as DateTime
from RPi import GPIO

COLUMN_PINS = [7, 8, 10, 12, 11, 13]
ROW_PINS = [15, 16, 18, 19]
BUTTON_PINS = _, _, DISPLAY_TIME_BUTTON = [21, 22, 24]


def button_input(button_pins, previous_pin):
    """Werte die gegebenen Buttons aus."""
    for pin in button_pins:
        GPIO.add_event_detect(pin, GPIO.RISING)
        if gpio.event_detected(pin):
            if previous_pin == pin:
                output = 0
            elif previous_pin == 0:
                output = pin
            return output
    return previous_pin


def main():
    GPIO.setmode(GPIO.BOARD)
    try:
        # Die Pins für die Reihensteuerung sind „low active“!
        GPIO.setup(ROW_PINS, GPIO.OUT, initial=1)
        GPIO.setup(COLUMN_PINS, GPIO.OUT, initial=0)
        GPIO.setup(BUTTON_PINS, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

        output_mode = 0
        column_values = [0] * len(COLUMN_PINS)
        while True:
            output_mode = button_input(BUTTON_PINS, output_mode)

            if output_mode == DISPLAY_TIME_BUTTON:
                now = DateTime.now()
                # 
                # Bitweises Invertieren der Werte wegen der „low active“-Logik
                # der Pins.
                # 
                hour, minute, second = ~now.hour, ~now.minute, ~now.second
                # 
                # Teilt die zahlen in zwei 4-stellige Teile -> je zwei Ledzeilen
                # für Stunden, Minuten, und Sekunden.
                # 
                column_values = [
                    second & 0b1111,
                    (second >> 4) & 0b1111,
                    minute & 0b0011,
                    (minute >> 4) & 0b1111,
                    hour & 0b1111,
                    (hour >> 4) & 0b1111,
                ]

        for column_pin, value in zip(COLUMN_PINS, column_values):
            GPIO.output(column_pin, 1)
            mask = 0b1000
            for row_pin in ROW_PINS:
                GPIO.output(row_pin, (value & mask) != 0)
                mask >>= 1
            # 
            # XXX Warum‽ Flackert das dann nicht wie Sau?
            # 
            GPIO.output(ROW_PINS, 1)  # Schaltet alle Outputs wieder zurück
            GPIO.output(column_pin, 0)

        if output_mode == 0:
            # 
            # FIXME Dieser Kommentar ist falsch, denn hier wird keine Schleife
            #       beendet.  Sollte vielleicht eine Schleife beendet werden?
            #       Welche?
            # 
            # Sobald der Taster aus ist, wird die Schleife beendet und die
            # Outputs zurückgesetzt
            GPIO.output(ROW_PINS, 1)
            GPIO.output(COLUMN_PINS, 0)
    finally:
        GPIO.cleanup()


if __name__ == '__main__':
    main()
Stephanius II
User
Beiträge: 2
Registriert: Mittwoch 21. Juni 2017, 19:48

Danke für die Hinweise. Mir ist aufgefallen, das dies tatsächlich nicht der richtige Code ist, den richtigen habe ich nur auf dem Raspberry, tut mir leid. Ich werde ihn, wenn ich daran denke, noch nachliefern.
Zu den Kommentaren: da es sich um eine Projektarbeit in der Schule handelt und weder meine Mitschüler noch meine Lehrer irgendwelche Hochsprachen beherrschen, sind diese Kommentare glaube ich gerechtfertigt, nur eher nicht an euch gerichtet. Tut mir leid. Und das mit den 80 Zeichen werde ich in Zukunft beachten.

Das mit dem direkten wieder ausschalten det Leds mache ich, da ich aufgrund des Aufbaus einer Ledmatrix (oder jedenfalls meiner) nur eine Ledspalte auf einmal ansteuern kann. In der neusten version des Scriptes hatte ich es glaube ich auch etwas anders. Aber es ist definitiv noch nicht ausgereift. Ich verwende eine Ledmatrix, da dies die einzige möglichkeit ist, die Leds einigermassen hell leuchten zu lassen ohne das Raspberry abzufackeln.

Vielen Dank für die Mühe, die ihr euch da allgemein in diesem Forum macht! Ich finde das wirklich genial! Allerdings komme ich dadurch nur zur Erkenntnis, dass ich wohl lieber dieses Projekt erstmal ruhen lasse und mich erstmal damit zufrieden geben muss, dass es überhaupt funktioniert. Danach werde ich erst einmal einen vernünftigen Kurs machen... Sonst gewöhne ich mir nur einen unsauberen Programmierstil an und werde die Sprache sowieso nie wirklich beherrschen.
BlackJack

@Stephanius II: Wenn Du es mit Kommentaren ”übertreiben” möchtest, dann könntest Du es mit „literate programming“ versuchen. Man könnte sagen statt den Code mit Kommentaren zu dokumentieren, schreibt man die Dokumentation und bettet dort den Code ein. Ich hatte da mal vor einger Zeit (ach Du meine Güte: 10 Jahre) hier mal ein Beispiel für das Forum mit Python und pylit.py geschrieben.

Das ist der Quelltext mit den Kommentaren: http://marc.rintsch.de/simpledb/simpledb.py

Zwischen dem Python-Quelltext mit den Kommentaren und einem reStructuredText-Quelltext mit dem Python-Quelltext in der Dokumentation kann man mittels pylit.py in beide Richtungen konvertieren. So sieht der Quelltext als Textdokument aus:
http://marc.rintsch.de/simpledb/simpledb.py.txt

Und das kann man dann mittels Docutils in andere Formate umwandeln. Zum Beispiel HTML: http://marc.rintsch.de/simpledb/simpledb.html

Oder auch PDF (via LaTeX) wenn man etwas druckbares braucht: http://marc.rintsch.de/simpledb/simpledb.pdf

Man kann auf diese Weise wirklich jede Funktion im Text ausführlich erklären und auch Beispielaufrufe in einer Python-Shell einbinden. Letztere kann man mit dem `doctest` auch automatisiert überprüfen.

Das Alter sieht man dem Beispiel teilweise an. Docutils kann mittlerweile auch Code-Blöcke mit Syntaxhervorhebung und im Python-Code standen Funktionen wie `any()` oder `all()` noch nicht zur Verfügung.

Die URL für pylit.py aus dem Beispiel stimmt nicht mehr, aber das Programm ist im Python Package Index gelistet: https://pypi.python.org/pypi/pylit

Bei den LEDs dachte ich das da noch ein bisschen Hardware dran hängt die die Zustände für eine Spalte hält. Ich denke wenn man das nicht hat, dann ist eine Sprache wie Python nicht wirklich gut geeignet das anzutreiben. Nicht mal weil es zu langsam sein könnte, sondern eher weil der Code wahrscheinlich nicht gleichmässig schnell läuft. Wie die Hardware aufgebaut ist, könnte man auch gut beim „literate programming“-Ansatz beschreiben.
Melewo
User
Beiträge: 320
Registriert: Mittwoch 3. Mai 2017, 16:30

@BlackJack: Das sieht interessant aus mit der Dokumentation, werde ich mir mal merken und gegebenenfalls näher anschauen.

Aber dass dieser Link auf der rintsch.de im Nirgendwo landet, ich gehe davon aus, dass Du das weißt?

[codebox=html4strict file=Unbenannt.html]<p>Zur Homepage von <a href="http://www.marc.rintsch.de/"[/code]
Würde bei der Zielseite eine von den beiden Varianten in der .htaccess verwenden.

Code: Alles auswählen

RewriteEngine on

# Entweder:

RewriteCond %{HTTP_HOST} !^marc\.rintsch\.de$
RewriteRule ^(.*)$ http://marc.rintsch.de/$1 [L,R=301]

# Oder:

RewriteCond %{HTTP_HOST} ^www\.marc\.rintsch\.de$
RewriteRule ^(.*)$ http://marc.rintsch.de/$1 [L,R=301]
BlackJack

@Melewo: Danke für den Hinweis. ”Früher” hat mein Webspace-Anbieter automatisch auch alle Domains nochmal mit einem www davor auf die gleiche Seite wie ohne das www eingerichtet. Keine Ahnung wie lange das schon nicht mehr der Fall ist. :-) Ich habe einfach eine www-Unterdomain eingerichtet. Sollte also wieder gehen sobald der DNS-Eintrag überall angekommen ist. Bei mir hier noch nicht, aber über Uberspace kann ich die Seite schon wieder erreichen.

Ich hatte gerade letzte Woche gemerkt das eine andere, eher ”historische” Webseite die ich betreue (eher schlecht offensichtlich) auch seit was weiss ich wie lange nicht mehr richtig konfiguriert war. Man sollte so etwas wohl regelmässig(er) kontrollieren. :-)
Antworten