Jump to content

borg

Administrators
  • Gesamte Inhalte

    3.592
  • Benutzer seit

  • Letzter Besuch

  • Tagessiege

    58

Alle erstellten Inhalte von borg

  1. Firmware: Temperature IR Bricklet 2.0 2.0.3 Use correct wait times during emissivity change Improved error handling in case of invalid read Download: Temperature IR Bricklet 2.0
  2. The first idea that comes to mind: The Ethernet Extension only supports a limited number of concurrently open sockets. Do you open several sockets at the same time? Or maybe, do you not close a socket and instead of reusing it open a new one? This can happen if you create new IPConnections instead of reusing/closing it.
  3. Kannst du mal einmal die Firmware im Anhang testen? Ich konnte das sporadisch reproduzieren und nach ein bisschen testen sieht es so aus als würden wir mit dem Chip der das Display steuern zu _langsam_ sprechen. Sehr eigenartig. Zumindest konnte ich mir das Problem mit einer höheren Frequenz nicht mehr reproduzieren. segment-display-4x7-bricklet-v2.0.3-beta1.bin
  4. Habe soeben Version 2.0.3 veröffentlicht. Per Default wird jetzt ein 28-Tage-Fenster für die Kalibrierung verwendet welches man per API wieder auf 4 Tage zurück stellen kann. Die API ist dann verfügbar wenn es das nächste Bindings-Release gibt. Die Ausreißer werden jetzt rausgefiltert und nicht verwendet. Ich hab mehrere Tests gemacht bezüglich des IAQ Wertes. Wenn sich die Luftqualität ändert lässt sich das am IAQ-Wert definitiv ablesen. Zum Beispiel steigt der Wert wenn wir den Laser Cutter anstellen oder jemand frischen "dampfendes" Essen reinbringt o.ä. und er sinkt sofort wieder wenn wir lüften. Wenn sich der IAQ-Wert eigentlich nicht ändern sollte (z.B. über das Wochenende wenn keiner hier ist) verhält er sich manchmal ein bisschen komisch, finde ich. Der Wert wandert dann oft leicht auf und ab ohne ersehbaren Grund. Das längere Kalibrierungs-Fenster scheint das aber über die Zeit definitiv zu verbessern. Hab es aber jetzt natürlich noch keine 28 Tage am Stück laufen lassen. Ich habe nochmal einen Test gestartet den ich jetzt für mindestens einen Monat durchlaufen lasse.
  5. Firmware: Air Quality Bricklet 2.0.3 Bosch BSEC aktualisiert auf v1.4.7.1 RemoveCalibration API hinzugefügt Set/GetBackroudCalibration API hinzugefügt Download: Air QualityBricklet
  6. Firmware: Air Quality Bricklet 2.0.3 Update Bosch BSEC to v1.4.7.1 Add RemoveCalibration API Add Set/GetBackroudCalibration API Download: Air QualityBricklet
  7. Komisch, probiere ich morgen aus ich da etwas reproduzieren kann.
  8. Bezüglich deiner dynamischen ID + Name + Klasse-Problematik: Du kannst da dynamisch wie folgt dran kommen: #!/usr/bin/env python3 # -*- coding: utf-8 -*- from tinkerforge import device_factory for device_id in device_factory.DEVICE_CLASSES: name = device_factory.get_device_display_name(device_id) cls = device_factory.get_device_class(device_id) print("Device ID: {0}, Name: {1}, Class: {2}".format(device_id, name, cls))
  9. Wenn du Callbacks nutzt und die Daten nicht direkt im Callback verarbeiten kannst, kommst du nicht darum herum entweder Queue oder vergleichbares zu nutzen oder nur den letzten Wert zu speichern. Das hat jetzt auch nichts mit asynchron vs prozedural zu tun, die Daten fallen nunmal komplett unabhängig von dem Mainloop an. Ich würde es wie folgt lösen: #!/usr/bin/env python3 # -*- coding: utf-8 -*- # HOST = "localhost" PORT = 4223 UID = "XYZ" # Change XYZ to the UID of your Air Quality Bricklet import asyncio from tinkerforge.ip_connection import IPConnection from tinkerforge.bricklet_air_quality import BrickletAirQuality _air_pressure_queue = asyncio.Queue() def cb_air_pressure(air_pressure, loop): asyncio.run_coroutine_threadsafe(_air_pressure_queue.put(air_pressure), loop) async def event_loop(loop): ipcon = IPConnection() aq = BrickletAirQuality(UID, ipcon) ipcon.connect, HOST, PORT) aq.register_callback(aq.CALLBACK_AIR_PRESSURE, lambda x: cb_air_pressure(x, loop)) aq.set_air_pressure_callback_configuration(100, False, 'x', 0, 0) while True: air_pressure = await _air_pressure_queue.get() print('Air Pressure: {0}'.format(air_pressure)) if __name__ == "__main__": loop = asyncio.get_event_loop() loop.run_until_complete(event_loop(loop)) Wenn es darum geht Daten in einer Datenbank o.ä. zu speichern bietet es sich an eine Queue für alle Daten zu nehmen und den Typ des Datums mit zu speichern, z.B.: queue.put((TYPE_AIR_PRESSURE, air_pressure)) Da kannst du dann in deiner Mainloop eine Stelle haben an der du die Daten entgegen nimmst und ja nach Typ entsprechend bearbeitest und in der Datenbank speicherst
  10. Ich glaube da hast du etwas missverstanden. Die MQTT-Bindings sind dazu da damit man Bricks/Bricklets per MQTT ansprechen kann. Die sind nicht dazu da um irgendetwas per Python zu machen. Das ist sozusagen ein Binary welches du ausführen kannst. Das wir den Code auch veröffentlichen ist nur Zugabe. Zum Beispiel kann man damit über die MQTT-Anbindung von Node-RED Bricks/Brickelts nutzen. Was du dir da anschaust ist generierter Code (genauso wie die Python-Bindings übrigens). Das ist so als würdest du dir generierten X86-Assembler anschauen und dich darüber wundern das es schlecht lesbar ist. Wenn du wissen möchtest wie die MQTT-Bindings zustande kommen musst du hier schauen: https://github.com/Tinkerforge/generators/tree/master/mqtt
  11. Hast du vielleicht vergessen neuzustarten als du das Brickelt an Port B angeschlossen hast? Die Bricklets sind nicht hotplug-fähig.
  12. Die mA-Angaben bei den Bricks und Bricklets beziehen sich auf 5V, während der Stack Current sich bei dir auf 10,7V bezieht. Die 2,5A können also unmöglich stimmen. An welchem Port ist das Segment Display 4x7 angeschlossen? Vielleicht tritt dieses Problem hier auf? https://www.tinkerforge.com/de/doc/Hardware/Bricklets/Segment_Display_4x7.html#bekannte-fehler-probleme
  13. Nichts. Hier nochmal das Beispiel wie du die Python-Bindings asynchron nutzen kannst: #!/usr/bin/env python3 # -*- coding: utf-8 -*- # HOST = "localhost" PORT = 4223 UID = "XYZ" # Change XYZ to the UID of your Air Quality Bricklet import asyncio from concurrent.futures import ThreadPoolExecutor import functools from tinkerforge.ip_connection import IPConnection from tinkerforge.bricklet_air_quality import BrickletAirQuality _executor = ThreadPoolExecutor(10) async def event_loop(loop): tf_async = functools.partial(loop.run_in_executor, _executor) ipcon = IPConnection() aq = BrickletAirQuality(UID, ipcon) await tf_async(functools.partial(ipcon.connect, HOST, PORT)) task_temperature = tf_async(aq.get_temperature) task_humidity = tf_async(aq.get_humidity) result = await asyncio.gather(task_temperature, task_humidity) print('Temperature: {0}, Humidity: {1}'.format(*result)) if __name__ == "__main__": loop = asyncio.get_event_loop() loop.run_until_complete(event_loop(loop)) Du musst dich in dem Beispiel um keine locks, notify, rendezvous oder barriers kümmern.
  14. Nur um das klar zu stellen: Die Python-Bindings sind zu 100% kompatibel zu Python 3. Piwo möchte die Python-Bindings zusammen mit der Python 3 asyncio Library nutzen und da wir diese nicht intern verwenden benötigt es mehr Boilerplate Code um die Python-Bindings mit asyncio zu nutzen.
  15. ? Ein task den du gatherest ist doch ein Future... Vielleicht hab ich meine Beispiele zu kompliziert gemacht, wie wäre es hiermit: #!/usr/bin/env python3 # -*- coding: utf-8 -*- # HOST = "localhost" PORT = 4223 UID = "XYZ" # Change XYZ to the UID of your Air Quality Bricklet import asyncio from concurrent.futures import ThreadPoolExecutor import functools from tinkerforge.ip_connection import IPConnection from tinkerforge.bricklet_air_quality import BrickletAirQuality _executor = ThreadPoolExecutor(10) async def event_loop(loop): tf_async = functools.partial(loop.run_in_executor, _executor) ipcon = IPConnection() aq = BrickletAirQuality(UID, ipcon) await tf_async(functools.partial(ipcon.connect, HOST, PORT)) task_temperature = tf_async(aq.get_temperature) task_humidity = tf_async(aq.get_humidity) result = await asyncio.gather(task_temperature, task_humidity) print('Temperature: {0}, Humidity: {1}'.format(*result)) if __name__ == "__main__": loop = asyncio.get_event_loop() loop.run_until_complete(event_loop(loop)) ipcon.connect wird asynchron mit Parameter aufgerufen und get_temperature und get_humidity werden asynchron "ge-gathered" und die Rückgabewerte ausgegeben.
  16. Die Argumente kannst du mit functools.partial umsetzen, ist auch so in der Python-Doku so dokumentiert: https://docs.python.org/3/library/asyncio-eventloop.html Rückgabewerte in Python asyncio kann man ganz allgemein mit Futures machen: https://docs.python.org/3/library/asyncio-future.html#asyncio.Future In dem Beispiel würdest du das Future (future = asyncio.Future()) mit bei dem tf_async_call übergeben und dann da wo aktuell das print ist future.set_result(value) aufrufen und an der Stelle wo du es benutzen willst kannst du dann result = await future machen. Hier gibt es ein Beispiel dafür: https://pymotw.com/3/asyncio/futures.html In dem Beispiel oben kannst du in tf_async_call aber auch einfach den Wert zurückgeben und nach dem await asyncio.wait([task1, task2]) kannst du task1.result() und task2.result() aufrufen.
  17. Das hängt davon ab wie du dein Programm gestaltest und was mit den Werten gemacht werden muss und wie oft du Daten abfragst etc. Der ThreadPoolExecutor kann natürlich von allen Bricklets genutzt werden. Wahrscheinlich reichen da auch 2-4 Worker für beliebig viele Bricklets. Statt einer Queue pro Bricklet kannst du natürlich auch eine Queue für alle verwenden und neben den Daten den Messwert-Typ mit in die Queue packen.
  18. Der aktuelle Brick Viewer nutzt immer die aktuell veröffentlichten Python-Bindings. Hier das Beispiel nochmal mit zusätzlichem Callback: #!/usr/bin/env python3 # -*- coding: utf-8 -*- HOST = "localhost" PORT = 4223 UID = "GKp" # Change XYZ to the UID of your Air Quality Bricklet import asyncio from concurrent.futures import ThreadPoolExecutor from tinkerforge.ip_connection import IPConnection from tinkerforge.bricklet_air_quality import BrickletAirQuality import time _executor = ThreadPoolExecutor(10) _air_pressure_queue = asyncio.Queue() def cb_air_pressure(air_pressure, loop): asyncio.run_coroutine_threadsafe(_air_pressure_queue.put(air_pressure), loop) async def tf_async_call(name, func): value = await asyncio.get_event_loop().run_in_executor(_executor, func) print('{0}: {1}'.format(name, value)) async def async_main(aq): task1 = asyncio.ensure_future(tf_async_call('Temperature', aq.get_temperature)) task2 = asyncio.ensure_future(tf_async_call('Humidity', aq.get_humidity)) air_pressure = await _air_pressure_queue.get() print('Air Pressure: {0}'.format(air_pressure)) # Here your async code await asyncio.wait([task1, task2]) print('Done!') if __name__ == "__main__": ipcon = IPConnection() # Create IP connection aq = BrickletAirQuality(UID, ipcon) # Create device object ipcon.connect(HOST, PORT) # Connect to brickd # Don't use device before ipcon is connected loop = asyncio.get_event_loop() aq.register_callback(aq.CALLBACK_AIR_PRESSURE, lambda x: cb_air_pressure(x, loop)) aq.set_air_pressure_callback_configuration(100, False, 'x', 0, 0) loop.run_until_complete(asyncio.ensure_future(async_main(aq))) ipcon.disconnect() Consolen-Ausgabe:
  19. Wenn du set_response_expected_all(True) aufrufst wird für alle Aufrufe (auch für Setter) eine Nachricht vom Brick/Bricklet zurück zum PC gesendet und wenn diese nicht ankommt bekommst du eine TimeoutException.
  20. Die ganzen delays sind da zu Demonstrationszwecken, damit die non-async Funktionen viel Zeit benötigen. Mit dieser Schleife hier while start + 2 > time.time(): await asyncio.sleep(0.1) print(time.time()) Zeige ich dann das ich während die Tinkerforge Getter aufgerufen werden weitere async Funktionen aufrufen kann, was ja Sinn der Sache ist. Hier eine vereinfachte Version: #!/usr/bin/env python3 # -*- coding: utf-8 -*- HOST = "localhost" PORT = 4223 UID = "GKp" # Change XYZ to the UID of your Air Quality Bricklet import asyncio from concurrent.futures import ThreadPoolExecutor from tinkerforge.ip_connection import IPConnection from tinkerforge.bricklet_air_quality import BrickletAirQuality import time _executor = ThreadPoolExecutor(10) async def tf_async_call(name, func): value = await asyncio.get_event_loop().run_in_executor(_executor, func) print('{0}: {1}'.format(name, value)) async def async_main(aq): task1 = asyncio.ensure_future(tf_async_call('Temperature', aq.get_temperature)) task2 = asyncio.ensure_future(tf_async_call('Humidity', aq.get_humidity)) # Here your async code await asyncio.wait([task1, task2]) print('Done!') if __name__ == "__main__": ipcon = IPConnection() # Create IP connection aq = BrickletAirQuality(UID, ipcon) # Create device object ipcon.connect(HOST, PORT) # Connect to brickd # Don't use device before ipcon is connected loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.ensure_future(async_main(aq))) ipcon.disconnect() Edit: Deine Idee mit den MQTT Bindings zu benutzen um damit Python asyncio zu machen hab ich leider nicht verstanden, aber was spricht dagegen den Code oben in einem asyncio-Umfeld einzusetzen?
  21. Du meinst die neuen MQTT Bindings die noch in der Beta sind? Der Code ist zu 100% generiert und in der Tat nicht zum durchlesen gedacht. Allerdings ist dort ja nun wirklich MQTT die Schnittstelle und der Python-Code im Hintergrund für den Nutzer nicht relevant. Du meinst sowas? #!/usr/bin/env python3 # -*- coding: utf-8 -*- HOST = "localhost" PORT = 4223 UID = "GKp" # Change XYZ to the UID of your Air Quality Bricklet import asyncio from concurrent.futures import ThreadPoolExecutor from tinkerforge.ip_connection import IPConnection from tinkerforge.bricklet_air_quality import BrickletAirQuality import time _executor = ThreadPoolExecutor(10) async def tf_async_call(name, func, delay): def _non_async_delayed_call(func, delay): time.sleep(delay) return func() value = await asyncio.get_event_loop().run_in_executor(_executor, lambda: _non_async_delayed_call(func, delay)) print('{0}: {1}'.format(name, value)) async def async_main(aq): call_temperature = tf_async_call('Temperature', aq.get_temperature, 2) call_humidity = tf_async_call('Humidity', aq.get_humidity, 1) task1 = asyncio.ensure_future(call_temperature) task2 = asyncio.get_event_loop().create_task(call_humidity) print('Do something useful here while humidity and temperature are gathered...') start = time.time() while start + 2 > time.time(): await asyncio.sleep(0.1) print(time.time()) await asyncio.wait([task1, task2]) print('Done!') if __name__ == "__main__": ipcon = IPConnection() # Create IP connection aq = BrickletAirQuality(UID, ipcon) # Create device object ipcon.connect(HOST, PORT) # Connect to brickd # Don't use device before ipcon is connected loop = asyncio.get_event_loop() loop.run_until_complete(asyncio.ensure_future(async_main(aq))) ipcon.disconnect() Edit: Hab das gerade nochmal ein bisschen aufgebohrt, damit man sieht das ich wirklich async calls machen kann während der getter-Aufruf läuft
  22. Eine gängige Möglichkeit Callbacks in eine Eventloop einzubinden ist im Callback die Daten in eine Queue zu packen und im Eventloop die Queue auszulesen. Im Brick Viewer nutzen wir zum Beispiel eine Queue um die Daten des Tinkerforge Systems in die Qt-Eventloop zu bekommen ohne das die GUI blockiert wird: https://github.com/Tinkerforge/brickv/blob/master/src/brickv/async_call.py
  23. @piwo: Dass die Python Bindings Threads nutzen ist ja eigentlich erstmal ein internes Implementierungsdetail. Hast du mal ein konkretes Beispiel wo du asyncio extern verwendest aber die aktuellen Python Bindings nicht nutzen kannst?
  24. Firmware: Outdoor Weather Bricklet 2.0.2 Remove Station/Sensor from list of identifiers after 12h with no data Download: Outdoor Weather Bricklet
  25. Firmware: Outdoor Weather Bricklet 2.0.2 Entferne Station/Sensor von der Identifier-Liste wenn diese für mehr als 12 Stunden am Stück keine Daten senden Download: Outdoor Weather Bricklet
×
×
  • Neu erstellen...