Jump to content

borg

Administrators
  • Gesamte Inhalte

    3.612
  • Benutzer seit

  • Letzter Besuch

  • Tagessiege

    61

Alle erstellten Inhalte von borg

  1. 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
  2. Komisch, probiere ich morgen aus ich da etwas reproduzieren kann.
  3. 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))
  4. 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
  5. 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
  6. Hast du vielleicht vergessen neuzustarten als du das Brickelt an Port B angeschlossen hast? Die Bricklets sind nicht hotplug-fähig.
  7. 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
  8. 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.
  9. 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.
  10. ? 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.
  11. 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.
  12. 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.
  13. 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:
  14. 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.
  15. 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?
  16. 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
  17. 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
  18. @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?
  19. Firmware: Outdoor Weather Bricklet 2.0.2 Remove Station/Sensor from list of identifiers after 12h with no data Download: Outdoor Weather Bricklet
  20. 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
  21. I am currently working on the Air Quality Bricklet, there is a bit more API coming too. So this is at the moment simply work in progress and the generator and air quality git are a bit out of sync.
  22. Ich hab das jetzt auf die neueste Bosch-Auswertesoftware aktualisiert und gerade einen Dauertest gestartet. Ich würde das jetzt für mindestens 4 Tage laufen lassen, damit er zumindest einmal die kompletten Daten für die Kalibrierung sammeln kann. Danach dann nochmal 1-2 Tage um zu überprüfen ob die Sensor-Daten dann vernünftig sind. Dauert also noch ca. eine Woche bis es ein neues Release gibt (falls ich nicht noch weitere Probleme finde). Es gibt übrigens auch einen Modus wo das Bricklet die letzten 28 Tage zur Kalibrierung verwendet. Was meint ihr, macht es Sinn auf den 28-Tage-Modus umzusteigen um bessere IAQ-Werte zu bekommen? Ich tendiere aktuell dazu das zu tun. Zusätzlich noch eine Funktion um die aktuelle Kalibrierung zu löschen, damit man nicht 28 Tage warten muss bis man wieder vernünftige Werte bekommt wenn man die Umgebung des Bricklets komplett verändert. Man könnte die Kalibrierungszeit auch zwischen 4/28 Tage konfigurierbar für den Nutzer machen.
  23. Da haben sich zwei Bugs miteinander verzahnt. Es gibt einen Bug im Bootloader der dazu führt das ein Bricklet in seltenen Fällen fälschlicherweise die Position 'Z' bekommt (die eigentlich für Bricklets die an Isolator Bricklets angeschlossen sind vorgesehen ist). Das ist an und für sich erstmal gar nicht so schlimm, dadurch geht nichts kaputt. Es führt aber dazu das im Brick Viewer das Bricklet ohne Parent angezeigt wird und die Auto-Update-Funktion hat dafür keine Unterstützung. Dadurch funktioniert auf einmal die Auto-Update-Funktion nicht mehr . Wird zum nächsten Brick Viewer Release gefixt.
  24. You would need to add a RS232 Bricklet and construct this sentence from the data you get from the GPS Bricklet. The GPS Bricklet does not have API that transfers the NMEA sentences to the PC.
  25. Yes, we would make a complete separate v2 version. We also would like to add .NET Core support if we do a major update of the C# bindings. For that we would have to exchange some of the internals with .NET Core compatible stuff too.
×
×
  • Neu erstellen...