Jump to content

Ich finde einen Fehler bei der Enumeration nicht


Recommended Posts

Ich suche nun schon seit Tagen an einem Fehler jedoch komme ich einfach nicht dahinter. Wahrscheinlich habe ich einen Denkfehler oder sonnst etwas.
Ich hoffe das mal jemand darüber schauen kann und mir sagen was ich Falsch mache.

Folgendes möchte ich umsetzten. 
Ich verfolge dabei den Robusten Tinkerforge Ansatz in Python. 
Es gibt eben eine Rugged Class wobei ich mir hier zwei Instanzen erstelle in einem Programm. Jede Instanz hat einen HOST(brickdeamon) jedoch gibt es eine Master Instanz. 
Der Grund für diese Masterinstanz ist das alle anderen Instanzen neue Bricklets oder auch bestehende Bricklets in eine Liste des Masters hinzufügen. Und in der Masterinstanz werden dann verschieden Threads erzeugt welche dann wieder die Objekte Abfragen oder konfigurieren. 
Ich hoffe mich bis jetzt Verständlich ausgedrückt zu haben.
Das mache ich eigentlich egal ob Onewire Bricklet oder IO16 Bricklet immer gleich. Der Fehler besteht auch egal welches Bricklet.

Folgenden vereinfachten Code aus der Enumeration von einem Onewire Bricklet habe ich hier:

if device_identifier == BrickletOneWire.DEVICE_IDENTIFIER:
    #test = [BrickletOneWire(uid, self.ipcon)]
    self.sensors.stop_auto_reading()
    if not self.onewire:
        self.onewire.append(BrickletOneWire(uid, self.ipcon))
        self.sensors.add_onewire(self.onewire)
        return
    dead = []
    found = False
    for i in self.onewire:
        try:
            if i.get_identity().uid == uid:
                i = BrickletOneWire(uid, self.ipcon)
                found = True
        except:
            dead.append(i)
    for i in dead:
        if i in self.onewire:
            self.onewire.remove(i)
    if found is False:
        self.onewire.append(BrickletOneWire(uid, self.ipcon))
    self.sensors.add_onewire(self.onewire)

Ich möchte prüfen ob in der Liste schon ein Objekt ist wenn nicht einfach gleich eines Anhängen und beeden.

Wenn schon welche ich der Liste sind möchte ich diese neu erzeugen könnte ja sein das die Verbindung unterbrochen war. Und falls es dabei zu einem Fehler kommt muss es ein Objekt sein welches nur mehr ein Geist ist. Welches ich dann lösche. 
Und wenn es wirklich ein neues Objekt ist also nicht gefunden wurde fügen wir es der Liste hinzu und übergeben es damit es ab nun an auch abgefragt werden kann.

Dieser Code funktioniert auch solange ich keine Bricklet außer einem hinzufüge oder Reseten muss. 
Ich komme einfach nicht dahinter. 

self.sensors.stop_auto_reading() beendet einen Thread der das Auslesen von Sensoren übernimmt und blockiert auch solange bis der Thread sicher beendet ist.

Grundsätzlich habe ich da noch ein paar fragen. Mir ist aufgefallen das get_identity().uid ohne Fehler durchläuft auch wenn das Objekt nicht mehr erreichbar ist kann das sein?
Ist es sobald ein Objekt auf ein Bricklet erzeugt wurde so das, das alte Objekt nicht mehr erreichbar ist. Lässt sich also nur ein Objekt(aktiv) pro Bricklet erzeugen?

Auch ist mir aufgefallen das die Enumeration beim start immer zweimal durchläuft. Ich verstehe nicht warum das passiert. 

In der Rugged Class steht zwar am Ende vom init()

self.ipcon.enumerate()

Aber müsste nicht wenn die Enumeration durchgeführt wurde dies nicht nochmal passieren? Oder sollte dies aus der init entfernt werden?

Achso hier noch die Methoden der Sensor Klasse: (vereinfacht)

def add_onewire(self, onewireobject):  # Fügt ein Onewire Objekt hinzu das ab nun auch eingelesen wird
    self.stop_auto_reading()  # Das lesen beenden
    self.onewire = onewireobject
    self.start_auto_reading()
    return

 

def start_auto_reading(self): # Startet den Thread der nun alle Fühler einließt
    if not self.__threadonewire.is_alive():
        self.__readingalowed = True
        self.__stopevent.clear()
        self.__threadonewire = threading.Thread(target=self.__getsensordata)  # Thread anlegen für das Erfassen der Temperaturwerte
        self.__threadonewire.setDaemon(True)  # damit wird der Task sofort beendet wenn das Hauptprogramm beendet wird
        self.__threadonewire.start()

def stop_auto_reading(self): # stopt den Thread für das Lesen und wartet bis er auch gestoppt wurde!
    self.__readingalowed = False # Thread auffordern zum beenden
    help = time.time()
    while self.__threadonewire.is_alive() is True:
        help = time.time()
        self.__stopevent.wait()  # Solange warten bis das Event gesetzt wurde
    print("auf das beenden gewartet s: {}".format(time.time() - help))
    return

Sobald nun ein Sensor Resetet wird oder hinzugefügt wird bekomme ich diesen Fehler: (Also nach der Enumeration)

Traceback (most recent call last):
  File "C:\Program Files\Python39\lib\threading.py", line 888, in run
    self._target(*self._args, **self._kwargs)
  File "C:\Users\markus\PycharmProjects\HomeAtmosphereControl\hac_classes.py", line 111, in __getsensordata
    i.reset()  # Das wird überhaupt nur benötigt weil ein reset nötig ist da nach einer zeit keine Sensoren mehr gefunden werden
  File "C:\Users\markus\PycharmProjects\HomeAtmosphereControl\venv\lib\site-packages\tinkerforge\bricklet_one_wire.py", line 315, in reset
    self.check_validity()
  File "C:\Users\markus\PycharmProjects\HomeAtmosphereControl\venv\lib\site-packages\tinkerforge\ip_connection.py", line 496, in check_validity
    raise Error(Error.DEVICE_REPLACED, 'Device has been replaced')
tinkerforge.ip_connection.Error: Device has been replaced (-16)

 

Ich verstehe aber nicht Warum. Wenn ich in der Enumeration vom Onewire nur ein Objekt erzeuge also so:

test = [BrickletOneWire(uid, self.ipcon)]
self.sensors.add_onewire(

Damit läuft der Code was aber auf nur ein Onewire Bricklet limitiert. Was ich nicht möchte. 

Aktuell sind an beiden aktiven brickdeamons nur an einem ein Onewire Modul angeschlossen.

Ich würde mich wirklich sehr über einen Tip oder Hilfe freuen.
Danke.

Grüße
Markus 

Link to post
Share on other sites
17 hours ago, DoIT said:

Mir ist aufgefallen das get_identity().uid ohne Fehler durchläuft auch wenn das Objekt nicht mehr erreichbar ist kann das sein?

Nein.

17 hours ago, DoIT said:

Ist es sobald ein Objekt auf ein Bricklet erzeugt wurde so das, das alte Objekt nicht mehr erreichbar ist. Lässt sich also nur ein Objekt(aktiv) pro Bricklet erzeugen?

Ja.

17 hours ago, DoIT said:

Auch ist mir aufgefallen das die Enumeration beim start immer zweimal durchläuft. Ich verstehe nicht warum das passiert. 

Schaust du auf den enumerate_type und unterscheidest Connected und Available Enumerate Callbacks?

Zu der "Device has been replaced" Fehlermeldung: Die IPConnection hält intern eine Liste von UID auf Device Object. Wenn du für eine UID ein neues Device Object anlegst, dann wird das alte Device Object ersetzt. Wenn du dann auf dem alten Device Object Funktionen aufrufst, dann bekommst du den "Device has been replaced" Fehler.

Das ganze kommt durch die "i = BrickletOneWire(uid, self.ipcon)" Zeile. Das ersetzt nicht den Eintrag in der onewire Liste, sondern du änderst nur die lokale Variable i, ersetzt aber in er IPConnection das alte BrickletOneWire Object durch das neue, das dann aber nicht in der onewire Liste landet. Dadurch verwendest du später das alte BrickletOneWire Object wieder.

Es ist aber an der Stelle auch nicht notwendig das BrickletOneWire Object neu anzulegen. Sprich wenn du die Zeile löscht löst sich dadurch dein Problem.

Link to post
Share on other sites

Danke für deine Antwort.
Ok jetzt wird es mir klarer.

Nein auf den enumeration_type habe ich nicht geachtet jedoch habe ich den Code einfach vom Beispiel übernommen es steht also folgendes:

if enumeration_type == IPConnection.ENUMERATION_TYPE_CONNECTED or enumeration_type == IPConnection.ENUMERATION_TYPE_AVAILABLE:

Ich bin davon ausgegangen das es schon sinn machen würde sobald ein Enumeration Event ausgelöst wurde einfach die Objekte neu zu erzeugen und auch zu konfigurieren.

Ok also ich ersetzte das Objekt nicht in der Liste. Sondern nur temporär das i Objekt.

Wie würdest du das Problem lösen um aus einer Liste eventuell nicht mehr erreichbare Brickletobjekte zu löschen bzw. neu zu erzeugen?

Bzw. warum ist das neu erzeugen nicht nötig?

Danke für deine Hilfe.

Grüße
 

Link to post
Share on other sites
55 minutes ago, DoIT said:

Nein auf den enumeration_type habe ich nicht geachtet jedoch habe ich den Code einfach vom Beispiel übernommen es steht also folgendes:


if enumeration_type == IPConnection.ENUMERATION_TYPE_CONNECTED or enumeration_type == IPConnection.ENUMERATION_TYPE_AVAILABLE:

Ich bin davon ausgegangen das es schon sinn machen würde sobald ein Enumeration Event ausgelöst wurde einfach die Objekte neu zu erzeugen und auch zu konfigurieren.

Wie in der Doku beschrieben kommt ein Enumerate-Connected unaufgefordert durch Starten oder Resetten der Hardware. Ein Enumerate-Available kommt durch Anforderung über die enumerate() Funktion. Ich erwarte, dass bei den beiden Enumerate-Callbacks einer ein Connected- und einer ein Available-Callback ist. Alternativ hast du noch ein anderes Programm laufen, dass auch enumerate() aufruft. Enumerate Callback die von einem Programm ausgelöst werden kommen auch an allen Programmen an die zur gleichen Adresse verbunden sind.

55 minutes ago, DoIT said:

Wie würdest du das Problem lösen um aus einer Liste eventuell nicht mehr erreichbare Brickletobjekte zu löschen bzw. neu zu erzeugen?

Anstatt die Toten die Lebenden finden. Den Fall, dass die onewire Liste leer ist muss nicht extra behandelt werden. Wenn die Liste leer ist, dann wird die for Schleife nicht betreten, found bleibt False.

if device_identifier == BrickletOneWire.DEVICE_IDENTIFIER:
    self.sensors.stop_auto_reading()
    alive = []
    found = False
    for i in self.onewire:
        try:
            if i.get_identity().uid == uid:
                found = True
        except:
            pass # ignoring non-responding Bricklet
        else:
            alive.append(i)
    if not found:
        alive.append(BrickletOneWire(uid, self.ipcon))
    self.onewire = alive
    self.sensors.add_onewire(self.onewire)

 

55 minutes ago, DoIT said:

Bzw. warum ist das neu erzeugen nicht nötig?

Weil das Device Object keinen relevanten Zustand hält außer die Response-Expected-Einstellungen. Daher muss es nicht neu angelegt, wenn sich das Bricklet enumeriert, denn es ändert sich durch das Enumerieren aus der Sicht des Device Object nichts.

Link to post
Share on other sites

Ok jetzt verstehe ich das. Den nebenbei habe ich noch den Brickviewer geöffnet.

Ah irgendwie bin ich davon ausgegangen das es nötig sein sollte die Objekte bei einem Verbindungsverlust neu zu erstellen.

Habe den Code nun nach deinem Beispiel angepasst. Jetzt funktioniert es. Vielen Danke! 😀

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...