Exemplo n.º 1
0
#
# Main
#
if __name__ == "__main__":

    os.system("python " + SUCCESS_SCRIPT + " 1")

    # Create IP connection
    ipcon = IPConnection()

    # Create device object
    nr = BrickletNFCRFID(UID, ipcon)

    # Reconnect automatically
    ipcon.set_auto_reconnect(True)

    # Register logging handlers
    ipcon.register_callback(IPConnection.CALLBACK_CONNECTED, cb_connected)
    ipcon.register_callback(IPConnection.CALLBACK_DISCONNECTED,
                            cb_disconnected)

    # Connect to brickd
    ipcon.connect(HOST, PORT)

    # Register state changed callback to function cb_state_changed
    nr.register_callback(nr.CALLBACK_STATE_CHANGED,
                         lambda x, y: cb_state_changed(x, y, nr))

    # Start scan loop
    nr.request_tag_id(nr.TAG_TYPE_MIFARE_CLASSIC)
Exemplo n.º 2
0
class DeviceManager(object):
	"""
	Diese Klasse implementiert den Gerätemanager einer ORBIT-Anwendung.

	**Parameter**

	``core``
		Ein Verweis auf den Anwendungskern der ORBIT-Anwendung.
		Eine Instanz der Klasse :py:class:`Core`.

	**Beschreibung**

	Der Gerätemanager baut eine Verbindung zu einem TinkerForge-Server auf,
	ermittelt die angeschlossenen Bricks und Bricklets und stellt
	den Komponenten in den Jobs die jeweils geforderten Geräte zur Verfügung.

	Dabei behält der Gerätemanager die Kontrolle über den Gerätezugriff.
	Das bedeutet, dass der Gerätemanager die Autorität hat, einer Komponente
	ein Gerät zur Verügung zu stellen, aber auch wieder zu entziehen.

	Eine Komponente bekommt ein von ihm angefordertes Gerät i.d.R. dann zugewiesen,
	wenn die Komponente aktiv und das Gerät verfügbar ist. Wird die Verbindung
	zum TinkerForge-Server unterbrochen oder verliert der TinkerForge-Server
	die Verbindung zum Master-Brick (USB-Kabel herausgezogen), entzieht
	der Gerätemanager der Komponente automatisch das Gerät, so dass eine 
	Komponente i.d.R. keine Verbindungsprobleme behandeln muss.

	Umgesetzt wird dieses Konzept mit Hilfe der Klassen :py:class:`SingleDeviceHandle`
	und :py:class:`MultiDeviceHandle`.
	"""

	def __init__(self, core):
		self._core = core
		self._connected = False
		self._devices = {}
		self._device_handles = []
		self._device_callbacks = {}
		self._device_initializers = {}
		self._device_finalizers = {}

		# initialize IP connection
		self._conn = IPConnection()
		self._conn.set_auto_reconnect(True)
		self._conn.register_callback(IPConnection.CALLBACK_ENUMERATE, self._cb_enumerate)
		self._conn.register_callback(IPConnection.CALLBACK_CONNECTED, self._cb_connected)
		self._conn.register_callback(IPConnection.CALLBACK_DISCONNECTED, self._cb_disconnected)

	def trace(self, text):
		"""
		Schreibt eine Nachverfolgungsmeldung mit dem Ursprung ``DeviceManager``
		auf die Konsole.
		"""
		if self._core.configuration.device_tracing:
			self._core._trace_function(text, 'DeviceManager')

	@property
	def devices(self):
		"""
		Ein Dictionary mit allen zur Zeit verfügbaren Geräten.
		Die UID des Geräts ist der Schlüssel und der Wert ist eine Instanz
		der TinkerForge-Geräte-Klasse 
		(wie z.B. ``tinkerforge.bricklet_lcd_20x4.BrickletLCD20x4``).
		"""
		return self._devices

	def start(self):
		"""
		Startet den Gerätemanager und baut eine Verbindung zu einem TinkerForge-Server auf.
		Die Verbindungdaten für den Server werden der ORBIT-Konfiguration entnommen.

		Gibt ``True`` zurück, wenn die Verbindung aufgebaut werden konnte, sonst ``False``.

		Siehe auch: :py:meth:`stop`
		"""
		if self._conn.get_connection_state() == IPConnection.CONNECTION_STATE_DISCONNECTED:
			host = self._core.configuration.host
			port = self._core.configuration.port
			retry_time = self._core.configuration.connection_retry_time
			self.trace("connecting to %s:%d ..." % (host, port))
			connected = False
			while not connected:
				try:
					self._conn.connect(host, port)
					connected = True
				except KeyboardInterrupt:
					connected = False
					break
				except:
					connected = False
					self.trace("... connection failed, waiting %d, retry ..." % retry_time)
					try:
						time.sleep(retry_time)
					except KeyboardInterrupt:
						break
			if connected:
				self.trace("... connected")
			return connected

	def stop(self):
		"""
		Trennt die Verbindung zum TinkerForge-Server und beendet den Gerätemanager.

		Vor dem Trennen der Verbindung wird die Zuordnung zwischen den Geräten
		und den Komponenten aufgehoben.

		Siehe auch: :py:meth:`start`
		"""
		self._finalize_and_unbind_devices()
		if self._conn.get_connection_state() != IPConnection.CONNECTION_STATE_DISCONNECTED:
			self.trace("disconnecting")
			self._conn.disconnect()

	def _cb_enumerate(self, uid, connected_uid, position, hardware_version,
	                 firmware_version, device_identifier, enumeration_type):

		if enumeration_type == IPConnection.ENUMERATION_TYPE_AVAILABLE or \
		   enumeration_type == IPConnection.ENUMERATION_TYPE_CONNECTED:
			# initialize device configuration and bindings
			self.trace("device present '%s' [%s]" % (device_name(device_identifier), uid))
			if known_device(device_identifier):
				# bind device and notify components
				self._bind_device(device_identifier, uid)
			else:
				self.trace("could not create a device binding for device identifier " + device_identifier)
		if enumeration_type == IPConnection.ENUMERATION_TYPE_DISCONNECTED:
			# recognize absence of device
			self.trace("device absent '%s' [%s]" % (device_name(device_identifier), uid))
			# unbind device and notify components
			self._unbind_device(uid)

	def _cb_connected(self, reason):
		self._connected = True
		# recognize connection
		if reason == IPConnection.CONNECT_REASON_AUTO_RECONNECT:
			self.trace("connection established (auto reconnect)")
		else:
			self.trace("connection established")
		# enumerate devices
		self._conn.enumerate()

	def _cb_disconnected(self, reason):
		self._connected = False
		# recognize lost connection
		if reason == IPConnection.DISCONNECT_REASON_ERROR:
			self.trace("connection lost (error)")
		elif reason == IPConnection.DISCONNECT_REASON_SHUTDOWN:
			self.trace("connection lost (shutdown)")
		else:
			self.trace("connection lost")

	def _bind_device(self, device_identifier, uid):
		self.trace("binding '%s' [%s]" % 
			(device_name(device_identifier), uid))
		# create binding instance
		device = device_instance(device_identifier, uid, self._conn)
		# add passive identity attribute
		identity = device.get_identity()
		device.identity = identity
		# initialize device
		self._initialize_device(device)
		# store reference to binding instance
		self.devices[uid] = device
		# register callbacks
		if uid in self._device_callbacks:
			callbacks = self._device_callbacks[uid]
			for event in callbacks:
				self.trace("binding dispatcher to '%s' [%s] (%s)" % 
					(device_name(device_identifier), uid, event))
				mcc = callbacks[event]
				device.register_callback(event, mcc)
		# notify device handles
		for device_handle in self._device_handles:
			device_handle.on_bind_device(device)

	def _unbind_device(self, uid):
		if uid in self._devices:
			device = self._devices[uid]
			self.trace("unbinding '%s' [%s]" % 
				(device_name(device.identity[5]), uid))
			# notify device handles
			for device_handle in self._device_handles:
				device_handle.on_unbind_device(device)
			# delete reference to binding interface
			del(self._devices[uid])

			# delete reference to multicast callbacks
			if uid in self._device_callbacks:
				del(self._device_callbacks[uid])
		else:
			self.trace("attempt to unbind not bound device [%s]" % uid)

	def _finalize_and_unbind_devices(self):
		for uid in list(self._devices.keys()):
			self._finalize_device(self._devices[uid])
			self._unbind_device(uid)

	def add_device_initializer(self, device_identifier, initializer):
		"""
		Richtet eine Initialisierungsfunktion für einen Brick- oder Bricklet-Typ ein.

		**Parameter**

		``device_identifier``
			Die Geräte-ID der TinkerForge-API. 
			Z.B. ``tinkerforge.bricklet_lcd_20x4.BrickletLCD20x4.DEVICE_IDENTIFIER``
		``initializer``
			Eine Funktion, welche als Parameter eine Instanz der TinkerForge-Geräteklasse
			entgegennimmt.

		**Beschreibung**

		Sobald der Gerätemanager ein neues Gerät entdeckt, 
		zu dem er bisher keine Verbindung aufgebaut hatte, 
		ruft er alle Initialisierungsfunktionen für die entsprechende
		Geräte-ID auf.

		*Siehe auch:*
		:py:meth:`add_device_finalizer`
		"""
		if device_identifier not in self._device_initializers:
			self._device_initializers[device_identifier] = []
		self._device_initializers[device_identifier].append(initializer)
		self.trace("added initializer for '%s'" % 
			(device_name(device_identifier)))

	def _initialize_device(self, device):
		device_identifier = device.identity[5]
		if device_identifier in self._device_initializers:
			self.trace("initializing '%s' [%s]" %
				(device_name(device.identity[5]), device.identity[0]))
			for initializer in self._device_initializers[device_identifier]:
				try:
					initializer(device)
				except Error as err:
					if err.value != -8: # connection lost
						self.trace("Error during initialization of : %s" % err.description)
				except Exception as exc:
					self.trace("Exception caught during device initialization:\n%s" % exc)

	def add_device_finalizer(self, device_identifier, finalizer):
		"""
		Richtet eine Abschlussfunktion für einen Brick- oder Bricklet-Typ ein.

		**Parameter**

		``device_identifier``
			Die Geräte-ID der TinkerForge-API. 
			Z.B. ``tinkerforge.bricklet_lcd_20x4.BrickletLCD20x4.DEVICE_IDENTIFIER``
		``finalizer``
			Eine Funktion, welche als Parameter eine Instanz der TinkerForge-Geräteklasse
			entgegennimmt.

		**Beschreibung**

		Sobald der Gerätemanager die Verbindung zu einem Gerät selbstständig
		aufgibt (d.h. die Verbindung nicht durch eine Störung unterbrochen wurde),
		ruft er alle Abschlussfunktionen für die entsprechende
		Geräte-ID auf.

		*Siehe auch:*
		:py:meth:`add_device_initializer`
		"""
		if device_identifier not in self._device_finalizers:
			self._device_finalizers[device_identifier] = []
		self._device_finalizers[device_identifier].append(finalizer)
		self.trace("added finalizer for '%s'" % 
			device_name(device_identifier))

	def _finalize_device(self, device):
		device_identifier = device.identity[5]
		if device_identifier in self._device_finalizers:
			self.trace("finalizing '%s' [%s]" %
				(device_name(device.identity[5]), device.identity[0]))
			for finalizer in self._device_finalizers[device_identifier]:
				try:
					finalizer(device)
				except Error as err:
					if err.value != -8: # connection lost
						self.trace("Error during device finalization: %s" % err.description)
				except Exception as exc:
					self.trace("Exception caught during device finalization:\n%s" % exc)

	def add_handle(self, device_handle):
		"""
		Richtet eine Geräteanforderung (Geräte-Handle) ein.

		Eine Geräteanforderung ist eine Instanz einer Sub-Klasse
		von :py:class:`DeviceHandle`. Das kann entweder eine Instanz von
		:py:class:`SingleDeviceHandle` oder von :py:class:`MultiDeviceHandle` sein.

		Das übergebene Geräte-Handle wird über alle neu entdeckten Geräte
		mit einem Aufruf von :py:meth:`DeviceHandle.on_bind_device` benachrichtigt.
		Je nach Konfiguration nimmt das Handle das neue Gerät an oder ignoriert es.
		Verliert der Gerätemanager die Verbindung zu einem Gerät, wird das
		Geräte-Handle ebenfalls mit einem Aufruf von
		:py:meth:`DeviceHandle.on_unbind_device` benachrichtigt.

		*Siehe auch:*
		:py:meth:`remove_handle`
		"""
		if device_handle in self._device_handles:
			return
		self._device_handles.append(device_handle)
		device_handle.on_add_handle(self)
		for device in self._devices.values():
			device_handle.on_bind_device(device)

	def remove_handle(self, device_handle):
		"""
		Entfernt eine Geräteanforderung (Geräte-Handle).

		Eine Geräteanforderung ist eine Instanz einer Sub-Klasse
		von :py:class:`DeviceHandle`. Das kann entweder eine Instanz von
		:py:class:`SingleDeviceHandle` oder von :py:class:`MultiDeviceHandle` sein.

		*Siehe auch:*
		:py:meth:`add_handle`
		"""
		if device_handle not in self._device_handles:
			return
		for device in self._devices.values():
			device_handle.on_unbind_device(device)
		device_handle.on_remove_handle()
		self._device_handles.remove(device_handle)

	def add_device_callback(self, uid, event, callback):
		"""
		Richtet eine Callback-Funktion für ein Ereignis
		eines Bricks oder eines Bricklets ein.

		**Parameter**

		``uid``
			Die UID des Gerätes für das ein Ereignis abgefangen werden soll.
		``event``
			Die ID für das abzufangene Ereignis.
			Z.B. ``tinkerforge.bricklet_lcd_20x4.BrickletLCD20x4.CALLBACK_BUTTON_PRESSED``
		``callback``
			Eine Callback-Funktion die bei Auftreten des Ereignisses aufgerufen werden soll.

		**Beschreibung**

		Da jedes Ereignis andere Ereignisparameter besitzt,
		muss die richtige Signatur für die Callbackfunktion der TinkerForge-Dokumentation
		entnommen werden. Die Ereignisparameter werden in der API-Dokumentation
		für jeden Brick und jedes Bricklet im Abschnitt *Callbacks* beschrieben.

		.. note:: Der Gerätemanager stellt einen zentralen
			Mechanismus für die Registrierung von Callbacks
			für Geräteereignisse zur Verfügung, weil die 
			TinkerForge-Geräteklassen nur ein Callback per Ereignis
			zulassen. Der Gerätemanager hingegen unterstützt beliebig viele 
			Callbacks für ein Ereignis eines Gerätes.

		*Siehe auch:*
		:py:meth:`remove_device_callback`
		"""
		if uid not in self._device_callbacks:
			self._device_callbacks[uid] = {}
		
		callbacks = self._device_callbacks[uid]
		
		if event not in callbacks:
			self.trace("creating dispatcher for [%s] (%s)" % (uid, event))
			mcc = MulticastCallback()
			callbacks[event] = mcc
			if uid in self._devices:
				device = self._devices[uid]
				self.trace("binding dispatcher to [%s] (%s)" % (uid, event))
				device.register_callback(event, mcc)
		
		mcc = callbacks[event]
		self.trace("adding callback to dispatcher for [%s] (%s)" % (uid, event))
		mcc.add_callback(callback)

	def remove_device_callback(self, uid, event, callback):
		"""
		Entfernt eine Callback-Funktion von einem Ereignis
		eines Bricks oder eines Bricklets.

		**Parameter**

		``uid``
			Die UID des Gerätes für das ein Callback aufgehoben werden soll.
		``event``
			Die ID für das Ereignis.
			Z.B. ``tinkerforge.bricklet_lcd_20x4.BrickletLCD20x4.CALLBACK_BUTTON_PRESSED``
		``callback``
			Die registrierte Callback-Funktion die entfernt werde soll.

		**Beschreibung**

		Für die Aufhebung des Callbacks muss die gleiche Funktionsreferenz übergeben werden
		wie bei der Einrichtung des Callback.

		*Siehe auch:*
		:py:meth:`add_device_callback`
		"""
		if uid in self._device_callbacks:
			callbacks = self._device_callbacks[uid]
			if event in callbacks:
				mcc = callbacks[event]
				self.trace("removing callback from dispatcher for [%s] (%s)" % (uid, event))
				mcc.remove_callback(callback)
Exemplo n.º 3
0
    # ...reenable auto reconnect mechanism, as described below...
    ipcon.set_auto_reconnect(True)

    # ...then trigger enumerate
    ipcon.enumerate()

# Print incoming enumeration
def cb_enumerate(uid, connected_uid, position, hardware_version, firmware_version,
                 device_identifier, enumeration_type):
    print("UID: " + uid + ", Enumeration Type: " + str(enumeration_type))

if __name__ == "__main__":
    # Create IPConnection
    ipcon = IPConnection()

    # Disable auto reconnect mechanism, in case we have the wrong secret.
    # If the authentication is successful, reenable it.
    ipcon.set_auto_reconnect(False)

    # Register Connected Callback
    ipcon.register_callback(IPConnection.CALLBACK_CONNECTED, cb_connected)

    # Register Enumerate Callback
    ipcon.register_callback(IPConnection.CALLBACK_ENUMERATE, cb_enumerate)

    # Connect to brickd
    ipcon.connect(HOST, PORT)

    input("Press key to exit\n") # Use raw_input() in Python 2
    ipcon.disconnect()
    # ...reenable auto reconnect mechanism, as described below...
    ipcon.set_auto_reconnect(True)

    # ...then trigger enumerate
    ipcon.enumerate()

# Print incoming enumeration
def cb_enumerate(uid, connected_uid, position, hardware_version, firmware_version,
                 device_identifier, enumeration_type):
    print("UID: " + uid + ", Enumeration Type: " + str(enumeration_type))

if __name__ == "__main__":
    # Create IPConnection
    ipcon = IPConnection()

    # Disable auto reconnect mechanism, in case we have the wrong secret.
    # If the authentication is successful, reenable it.
    ipcon.set_auto_reconnect(False)

    # Register Connected Callback
    ipcon.register_callback(IPConnection.CALLBACK_CONNECTED, cb_connected)

    # Register Enumerate Callback
    ipcon.register_callback(IPConnection.CALLBACK_ENUMERATE, cb_enumerate)

    # Connect to brickd
    ipcon.connect(HOST, PORT)

    raw_input("Press key to exit\n") # Use input() in Python 3
    ipcon.disconnect()