Jump to content

Python: CALLBACK CONNECTED und WiFi Extension 2.0


Recommended Posts

Servus,

 

in einem unserer Projekte (Python) nutzen wir einen Master Brick mit WiFi Extension 2.0 und einen mit WiFi Extension (alte Version). Für beide wird ein CALLBACK_CONNECTED registriert. Das funktioniert auch bei dem Master Brick mit dem alten WiFi-Modul hervorragend: Die als CALLBACK gesetzte Funktion wird immer augerufen, wenn die WLAN-Verbindung neu augebaut wird - egal, ob zum ersten Mal per .connect() Befehl oder nach einem Abrruch der Verbindung, z.B. weil das Brick Stromausfall hatte.

Anders bei dem Brick mit WiFi Extension 2.0: Beim ersten Verbindungsaufbau per .connect() Befehl wird der Callback korrekt ausgelöst, wenn dann aber die WiFi-Verbindung unterbrochen wird und wieder aufgebaut ist, wird der Callback NICHT ausgelöst. Kennt jemand dieses Verhalten, ist das bekannt oder ein Bug? Machen wir etwas falsch? Code im Anhang.

LG Johannes

#!/usr/bin/python3
#---------------- Library --------------------------
from tinkerforge.ip_connection import IPConnection
from tinkerforge.bricklet_sound_pressure_level import BrickletSoundPressureLevel
from tinkerforge.bricklet_oled_64x48 import BrickletOLED64x48
from tinkerforge.bricklet_dual_relay import BrickletDualRelay
import time
import datetime


# -------------- Implementation ---------------------
class rugged:
    HOST1 = "brickie"
    HOST2 = "brickie2"
    PORT = 4223
    
    def __init__(self):
        self.oled1 = None
        self.dr1 = None
        self.spl1 = None
        self.oled2 = None
        self.dr2 = None
        self.spl2 = None
        
        self.ipcon1 = IPConnection()
        self.ipcon2 = IPConnection()
        
        self.ipcon1.register_callback(IPConnection.CALLBACK_ENUMERATE,self.cb_enumerate1)
        self.ipcon1.register_callback(IPConnection.CALLBACK_CONNECTED,self.cb_connected1)
        
        self.ipcon2.register_callback(IPConnection.CALLBACK_ENUMERATE,self.cb_enumerate2)
        self.ipcon2.register_callback(IPConnection.CALLBACK_CONNECTED,self.cb_connected2)
        isConnected1 = False
        isConnected2 = False
        while not (isConnected1 and isConnected2):
            if not isConnected1:
                try:
                    print('Connecting to Brick 1...')
                    self.ipcon1.connect(rugged.HOST1, rugged.PORT)
                    isConnected1 = True
                    print('Connected to Brick 1!')
                except OSError:
                    print('Could not connect to Brick1. Will retry in 5 seconds...')
                    time.sleep(5)
            if not isConnected2:
                try:
                    print('Connecting to Brick 2...')
                    self.ipcon2.connect(rugged.HOST2, rugged.PORT)
                    isConnected2 = True
                    print('Connected to Brick 2!')
                except OSError:
                    print('Could not connect to Brick2. Will retry in 5 seconds...')
                    time.sleep(5)
            
        self.ipcon1.enumerate()
        self.ipcon2.enumerate()
    
    
    def cb_dB1(self, decibel):
	#This part should not matter
            
    def cb_enumerate1(self, uid, connected_uid, position, hardware_version, firmware_version, device_identifier, enumeration_type):
        if enumeration_type == IPConnection.ENUMERATION_TYPE_CONNECTED or \
           enumeration_type == IPConnection.ENUMERATION_TYPE_AVAILABLE:
            
            if device_identifier == BrickletSoundPressureLevel.DEVICE_IDENTIFIER:
                self.spl1 = BrickletSoundPressureLevel(uid, self.ipcon1)
                self.spl1.set_decibel_callback_configuration(100,False,"x",0,0)
                self.spl1.register_callback(self.spl1.CALLBACK_DECIBEL,self.cb_dB1)
            
            if device_identifier == BrickletOLED64x48.DEVICE_IDENTIFIER:
                self.oled1 = BrickletOLED64x48(uid, self.ipcon1)
                self.oled1.clear_display()
                
            if device_identifier == BrickletDualRelay.DEVICE_IDENTIFIER:
                self.dr1 = BrickletDualRelay(uid, self.ipcon1)
                
    def cb_connected1(self, connected_reason):
        self.ipcon1.enumerate()
        
    def cb_dB2(self, decibel):
	#This part should not matter

    def cb_enumerate2(self, uid, connected_uid, position, hardware_version, firmware_version, device_identifier, enumeration_type):
        if enumeration_type == IPConnection.ENUMERATION_TYPE_CONNECTED or \
           enumeration_type == IPConnection.ENUMERATION_TYPE_AVAILABLE:
            
            if device_identifier == BrickletSoundPressureLevel.DEVICE_IDENTIFIER:
                self.spl2 = BrickletSoundPressureLevel(uid, self.ipcon2)
                self.spl2.set_decibel_callback_configuration(100,False,"x",0,0)
                self.spl2.register_callback(self.spl2.CALLBACK_DECIBEL,self.cb_dB2)
            
            if device_identifier == BrickletOLED64x48.DEVICE_IDENTIFIER:
                self.oled2 = BrickletOLED64x48(uid, self.ipcon2)
                self.oled2.clear_display()
                
            if device_identifier == BrickletDualRelay.DEVICE_IDENTIFIER:
                self.dr2 = BrickletDualRelay(uid, self.ipcon2)
                
    def cb_connected2(self, connected_reason):
        self.ipcon2.enumerate()
        
        
if __name__ == "__main__":
    temp=rugged()
    input('Program is running. Press enter to exit.')
    temp.ipcon1.disconnect()
    temp.ipcon2.disconnect()

 

Link to comment
Share on other sites

Grundsätzlich kann sich die WIFI Extension (1 oder 2) nach einem neustart nicht selbst wieder mit dem Programm verbinden. Der Verbindungsaufbau findet immer durch die IPConnection auf PC-Seite statt.

 

Wenn die Verbindung zur WIFI Extension abbricht, sorgt das auto-reconnect Feature der IPConnection dafür das die Verbindung wieder hergestellt wird. Dadurch wird dann auch ein neuer CALLBACK_CONNECTED erzeugt.

 

Das funktioniert mit beiden Extensions, hab ich getestet. Das Problem hier ist die Erkennung des Abbruchs der TCP/IP Verbindung. Wann eine TCP/IP Verbindung als abgebrochen erkannt wird hängt von der Implementierung des TCP/IP Stacks, des Betriebssystems, den Einstellungen im Betriebssystem etc ab. Da haben wir im Zweifelsfall keinen Einfluss drauf.

 

Warum sich das jetzt bei euch zwischen WIFI Extension V1 und V2 unterscheidet weiß ich nicht.

 

Als Workaround könntet ihr folgendes probieren:

 

Oben bei den Imports:

import struct

import socket

 

Nach dem self.ipconX.connect:

sec = 15

usec = 0

timeval = struct.pack('ll', sec, usec)

self.ipconX.socket.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)

 

Mit dieser Socket Option wird die Verbindung nach 15 Sekunden ohne Datenaustausch geschlossen und das auto-reconnect greift auf jeden Fall. Nur wird die Verbindung damit natürlich auch geschlossen und wieder hergestellt wenn für 15 Sekunden einfach keine Daten übertragen wurden.

 

Am besten wäre es wenn das Tinkerforge Protokoll eine Art Alive-Ping-Pong-Message hätte die zwischen Brick Daemon und Bindings hin und hergeschickt wird. Auf diese Nachricht könnte man dann einen Timeout haben der automatisch das auto-reconnect startet, auch wenn die TCP/IP-Verbindung noch offen ist. Das steht auch schon auf der TODO-Liste, gibt es allerdings im Moment noch nicht im Protokoll.

Link to comment
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.

 Share

×
×
  • Create New...