PiFace Digital macht Probleme beim Ansteuern

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
raspido
User
Beiträge: 31
Registriert: Montag 10. November 2014, 19:42
Kontaktdaten:

Guten Tag Leute,

ich habe zur Zeit ein wenig Probleme mit meinem PiFace Digital. Ich möchte gerne mittels dem PiFace Digital über Relais Steckdosen schalten. Der Hardwareteil macht mir keine Probleme, bin Elektriker. Das Problem ist eher die Software.

Ich habe folgenden Code produziert:

Code: Alles auswählen

#!/usr/bin/python

# Steckdosensteuerung mit PiFace Digital
# erstellt am: 15.01.2017
# Version: 1.1

# importieren der benoetigten Bib.
from time import sleep
import sys
import pifacedigitalio as p

p.init()                # PiFace initialisiern

ort = sys.argv[1]       # Parameter 1 der Variable "ort" zuweisen
zustand = sys.argv[2]   # Parameter 2 der Variable "zustand" zuweisen

# Ort mit Relais Verknuepfen
relais = {"an" : 0, "cd" : 1, "bl" : 2, "so" : 3, "ta1" : 4, "ta2" : 5, "ta3" : 6, "wei" : 7}

# Funktion "ausgang" definieren
def ausgang(ort, zustand):
# Steckdosen einschalten
        if zustand == "1":
                # Relais Aktivieren
                p.digital_write(relais[ort],1,1)
                sys.exit
# Steckdosen ausschalten
        elif zustand == "0":
                #  Relais Deaktivieren
                p.digital_write(relais[ort],0,1)
                sys.exit()

# Funktion "ausgang" mit Parameter aufrufen
ausgang(ort, zustand)
Das "Problem" was ich habe ist der Zeile p.init() verschuldet. Soweit bin ich schonmal. Aber erstmal zu dem wie das Script ablaufen soll und was passieren soll.

1. Ich starte das Script mit der Übergabe von 2 Parameter. 1. Ort und 2. Zustand z.B. "python steckdosen.py ta1 1"
2. Das Script soll entsprechenden Befehl ausführen
3. Das Script beendet sich sobald Aufgabe erfüllt wurde.

Und nun zu meinem Problem, wenn ich z.B. erst eine Steckdose einschalten möchte und dann eine zweite setzt mir das Script jedes mal die Ausgänge zurück, beim neustarten des Scripts. Nur mir fällt außer der "aufwändige" Weg, dass ich bei jedem Start die Zustände der einzellnen Ausgänge mir speicher und bei jedem Start, diese wieder auf "Originalzunstand" neu gesetzt werden, außer die Veränderung die ich haben möchte.

Kann mir da ggf. jemand helfen wie ich das Problem in den Griff bekommen kann?

Eine Info noch, ich starte zur Zeit die Scripte per Hand. Auf Dauer soll es aber über ein Webinterface laufen. Daher fiel mir bislang keine andere Lösung ein, das Script jedes mal "neu" zu starten. Aber das Klappt ja dann nich wie geplant.



Michael
Zuletzt geändert von Anonymous am Montag 27. Februar 2017, 13:30, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
Hobby-Programmierung - Also KEIN Profi-Progger
raspido
User
Beiträge: 31
Registriert: Montag 10. November 2014, 19:42
Kontaktdaten:

Einie Idee kam mir gerade irgendwie wie ein "Geistesblitz" ob das aber schon die "Lösung" ist weiß ich nicht. Habe mit diesem bisher nicht wirklich was zu tun gehabt.

Aber wollte mal die Idee in den Raum schmeißen.

Ich könnte die Anwendung in 2 Teile teilen. 1. ein Server Socket in Python, der die eigentliche Steuerung übernimmt und 2. ein Client Script, was einfach die "Steuerbefehle" an den "Server" übergibt. Also es würden beide Scripte auf einem Raspberry Pi laufen, aber so könnte ich ggf. das Problem umgehen.

Daher mal meine Frage an die, die sowas schon gemacht haben. Also Netzwerk Programmierung und Co, wäre das ein vernünftiger Weg oder gibt es ggf. noch einen besseren?



Michael
Hobby-Programmierung - Also KEIN Profi-Progger
BlackJack

@raspido: Server dafür klingt nach einer guten Lösung. Falls die Weboberfläche dafür nicht zu komplex wird, würde das wahrscheinlich alles zusammen mit `bottle` und dem dort integrierten Webserver lösen.
raspido
User
Beiträge: 31
Registriert: Montag 10. November 2014, 19:42
Kontaktdaten:

Ne als Weboberfläche habe ich schon etwas laufen, welches neben Funksteckdosen und so weiter auch mit Scripten arbeiten kann. Und da kann ich ja einfach den Server im Hintergrund starten, sobald der Pi startet und über die Weboberfläche starte ich dann einfach das "Client-Script", dass sendet was es zu senden hat und kann sich ja dann auch wieder beenden.

Werde es später oder die Tage mal testen, je nachdem wie ich dazu komme. Also ob meine Idee, die ich habe so klappt wie gedacht.

Aber hier mal meine Gedanken:

Server startet wie gesagt automatisch mit dem RaspberryPi. Und wartet auf Nachricht vom Client. Die Nachricht trennt er beim Trennzeichen, so kann ich Ort und Zustand in einer Nachricht versenden. Im Anschluß wandelt er den Zustand von Text in eine Zahl um. Im Anschluß holt er sich aus der Liste die "Zuordnung" von Ort und Pin-Nummer und schaltet den Ausgang entsprechend.

Und der Client sendet einfach Ort und Zustand, z.B. "ta1:1" also er schaltet ta1 einfach ein.

Muss nur gucken ob das so klappt wie gedacht und nicht, dass der Server sich so ständig erstmal beendet wenn Client sich verabschiedet.

UDP sollte für die Zwecke doch reichen oder wäre besser eine TCP Verbindung?



Michael
Hobby-Programmierung - Also KEIN Profi-Progger
BlackJack

@raspido: Bei UDP können Pakete verloren gehen. Und so direkt Socket selber programmieren würde ich persönlich auch nicht. Ich würde wahrscheinlich trotzdem `bottle` nehmen und eine kleine REST-API zur Verfügung stellen. Endweder über die URLs oder JSON, oder eine Kombination aus beidem.
raspido
User
Beiträge: 31
Registriert: Montag 10. November 2014, 19:42
Kontaktdaten:

Ja okay dann muss ich mal gucken.

Nur wie gesagt ein fertiges Webinterface gibt es schon, da wollte ich auch nur ungern dran rumfummeln. Bin froh, dass das so läuft und dort ist schon einiges mehr integriert als nur die Steckdosen die noch dazu kommen sollen.

Also Rollos laufen drüber, Temperatursensoren und sonst was. Also alles neu machen wäre sicher aufwendiger.

Ich denke ich werde es später oder die Tage einfach erstmal mit einem Socketbeispiel aus dem Netz versuchen, dies "umbauen" nach Wünschen und vielleicht tut es ja dann schon was es soll. Weil z.B. der Server muss dem Client keine Antwort geben, was bei manchen Beispielen im Netz gezeigt wird. Er muss eigentlich nur die Information empfangen, Nachicht Splitten, Verwerten und fertig.

Vor allem muss es ja auch nur einfach sein und funktionieren. Also soll ja keine Programmiermeisterstückdingsbums werden. Bin da eher einfacher gestrickt. :D Und zudem weiß ich nicht ob das Webinterface da so mit spielt, also Scripte aufrufen und so läuft tadellos.



Michael

PS: Aber danke schon erstmal für die Hilfe. Ich werd es mal testen und einfach ein Feedback geben. Den Code kann ich gern dann auch Posten, vielleicht will ja jemand anderes auch sowas noch machen.
Hobby-Programmierung - Also KEIN Profi-Progger
BlackJack

@raspido: Wie gesagt, ich würde keinen Socket-Code selber basteln sondern etwas auf Bottle aufbauen. Das hat auch überhaupt nichts damit zu tun das Du schon eine Weboberfläche hast, denn darum geht es ja gar nicht, sondern nur darum eine möglichst einfache Schnittstelle für den Server zu schreiben, mit fertigem Protokoll, wofür es viele Client-Implementierungen gibt (HTTP halt) und mit einem Datenformat für die Kommunikation für das es auch schon Code zum (de)serialisieren gibt: JSON.

Socketbeispiel aus dem Netz ist so ganz allgemein nämlich schon mal eine schlechte Idee, weil die meistens fehlerhaft sind.
raspido
User
Beiträge: 31
Registriert: Montag 10. November 2014, 19:42
Kontaktdaten:

Kannst mir den ggf. helfen bei dem Einstieg?

ich habe damit so auch noch nichts gemacht. Kanns ja gern mal versuchen.

Ich wollte aber das möglichst mit den Client so machen, wie oben beschrieben, also das er startet, sendet und dann beendet. Weil ich so über das Webinterface das am einfachsten machen kann.


Michael
Hobby-Programmierung - Also KEIN Profi-Progger
BlackJack

@raspido: Ist eigentlich ziemlich simpel. Schau's Dir erst einmal an: http://bottlepy.org/docs/stable/

Wenn man ein Wörterbuch zurück gibt, dann macht Bottle da automatisch eine Antwort mit dem Content-Type 'application/json' und JSON als Inhalt. Was man beachten sollte sind die Eigenschaften die Browser oder HTTP-Clients generell von HTTP-Methoden erwarten, also GET darf keinen Zustand auf dem Server verändern. Für's schalten sollte man also POST verwenden. Nach REST eigentlich eher PUT.
raspido
User
Beiträge: 31
Registriert: Montag 10. November 2014, 19:42
Kontaktdaten:

Okay. sieht mächtig umfangreich aus.

Hab mal das "Hallo - Welt" Ding probiert und das klappte schon mal zumindest. Nur ich steige irgendwie nicht so recht dahinter, wie ich damit zu dem Ziel kommen kann, und meine Ausgänge schalten kann?

Kannst mir da ggf. noch mal ein Stück weiter "die Hand führen"? Oder gibt's evtl. auch was in Deutsch an Tutorials oder so?


Michael
Hobby-Programmierung - Also KEIN Profi-Progger
BlackJack

@raspido: Das ist ein Mikrorahmenwerk, also bestimmt nicht „mächtig umfangreich“. Das ist *eine* .py-Datei. Mächtig umfangreich wäre Django. :-)

Komplett ungetestet:

Code: Alles auswählen

#!/usr/bin/env python
from __future__ import absolute_import, division, print_function
import pifacedigitalio as piface
from bottle import route, run


NAME_TO_INDEX = {
    'an': 0, 'cd': 1, 'bl': 2, 'so': 3, 'ta1': 4, 'ta2': 5, 'ta3': 6, 'wei': 7
}


@route('/switches')
def get_switches():
    return NAME_TO_INDEX


@route('/switch/<where>/<how:int>', method='POST')
def set_switch(where, how):
    result = {'where': where, 'how': how, 'error': None}
    try:
        index = NAME_TO_INDEX[where]
    except KeyError:
        result['error'] = 'unknown `where`'
    else:
        piface.digital_write(index, how, 1)

    return result


def main():
    piface.init()
    run(host='localhost', port=8080, debug=True)


if __name__ == '__main__':
    main()
raspido
User
Beiträge: 31
Registriert: Montag 10. November 2014, 19:42
Kontaktdaten:

Okay,

danke werde ich die Tage mal auf den Pi packen und testen. Hab den Abend aber nicht ganz untätig da gesessen. Habe mal was zusammengestrickt um mal bisschen rum zu probieren und es läuft. Also es handelt sich um eine UDP Lösung.

Hier mal der Servercode:

Code: Alles auswählen

#!/usr/bin/python
# UDP Server - Script
# Dateiname: udpserv.py

import socket
import sys
import pifacedigitalio as p

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
p.init()

# Ausgänge mit "Namen" versehen, da das einfacher ist als immer die Nummern zu merken
relais = {"an" : 0, "cd" : 1, "bl" : 2, "so" : 3, "ta1" : 4, "ta2" : 5, "ta3" : 6, "wei" : 7}

try:
    s.bind(("", 50000))
    while True:
        daten, addr = s.recvfrom(1024)
        output = daten.split(":")

        # Steckdose einschalten
        if output[1] == "1":
                # Relais Aktivieren und Steckdose einschalten
                p.digital_write(relais[output[0]],1,1)
        # Steckdosen ausschalten
        elif output[1] == "0":
                # Relais deaktivieren und Steckdose ausschalten
                p.digital_write(relais[output[0]],0,1)

finally:
    s.close()

und hier der Clientcode, aufrufbar mittels: python udpclient.py ta:1 (ta:1 bildet den Ort und Zustand)

Code: Alles auswählen

#!/usr/bin/python
# UDP - Client - Script
# Dateiname: udpclient.py

import socket
import sys
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

nachricht = sys.argv[1]

s.sendto(nachricht, ("127.0.0.1", 50000)) # Wenn Server und Client auf unterschiedlichen Pi's laufen anpassen
s.close()

Habe es auch ein wenig schon getestet und bei ersten Versuchen tat es, was es sollte.

Falls es so nicht gesehen bzw. bemerkt hast, bei dem Befehl p.digital_write(relais[output[0]],0,1) ist ein zusätzlicher Parameter mit angegeben. Hat den Grund, dass ich zur Zeit 2 PiFace digital an meinem Raspberry Pi habe und diese sind ja falls nicht bekannt "Adressierbar". Nur als Info am Rade für die es noch nicht mit bekommen haben.



Michael
Hobby-Programmierung - Also KEIN Profi-Progger
BlackJack

@raspido: Das Argument habe ich doch auch angegeben‽
raspido
User
Beiträge: 31
Registriert: Montag 10. November 2014, 19:42
Kontaktdaten:

Jap ich weiß, war aber auch an die anderen im Forum, weil es gibt ggf. auch welche die bislang maximal 1 PiFace Digital am Raspberry Pi hatten und nicht wussten, dass auch mehr geht. Wusste ich selbst bis vor kurzem noch nicht und hab mit Müh und not noch 2 weitere PiFace Digital 1 zusammen gefunden. Hab jetzt 3 Stück, wenn ich noch an eines kommen würde wäre super, aber ich denke dafür bin ich zuspät. Gibt ja schon Version 2.

@BlackJack:War keine Kritik an dir.



Michael
Hobby-Programmierung - Also KEIN Profi-Progger
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@raspido: dass UDP-Pakete beim Empfänger ankommen ist nicht garantiert. Wenn es Dir also nichts ausmacht, nicht zu wissen, ob Deine Steckdose geschaltet wurde oder nicht, ...
Für ein verlässliches Protokoll müßtest Du noch einen Rückgabe senden und auch bedenken, dass der Rückgabewert verloren gehen könnte. Alles in allem UDP sauber hinzubekommen ist aufwendig, ein fertiges funktionierendes HTTP-Framework zu verwenden dagegen einfach.
raspido
User
Beiträge: 31
Registriert: Montag 10. November 2014, 19:42
Kontaktdaten:

Klar ist das alles einfacher. Ich wollte das was "BlackJack" gepostet habe auch mal testen, ob das so funktioniert und so.

Bin aber prallel am überlegen, meine Idee erstmal parallel zu testen und mal zu gucken wie oft es passiert, dass da was verlohren geht. Bei den ersten Tests zumindest hatte eigentlich alles Tadellos geklappt. Okay hab es auch bislang nur max 20 mal hin und Her geschalten. Aber ich denke die Zeit wird es zeigen, wenn es richtig in den Altäglichen Einsatz kommt und so.



Michael
Hobby-Programmierung - Also KEIN Profi-Progger
Antworten