Python tool für Bluetooth BLE Scan - liegt der fehler bei mir?

therealsimmal

Cadet 1st Year
Registriert
Okt. 2024
Beiträge
10
Hallo zusammen,
ich wollte mir für ein Hygrometer das Bluetooth hat ein tool bauen um die werte mit Bluetooth Low Energy abrufen und daraus den VPD wert berechnen und ausgeben.
Ich häng immernoch am anfang weil ichs einfach nicht schaff die passenden UUID's für Temperatur und relative Luftfeuchte zu finden.
Das tool das ich für den BLE scan geschrieben habe sieht so aus:


Python:
import asyncio
import threading
import tkinter as tk
from tkinter import ttk
from bleak import BleakScanner, BleakClient

class BLEScannerApp:
    def [B]init[/B](self, root):
        self.root = root
        self.root.title("BLE-Geräte-Scanner")
        self.root.geometry("1200x800")

        self.scanner = BleakScanner()
        self.scanning = False
        self.devices = []
        self.selected_device = None
        self.selected_characteristic = None

        self.setup_ui()

    def setup_ui(self):
        self.paned_window = ttk.PanedWindow(self.root, orient=tk.HORIZONTAL)
        self.paned_window.pack(fill=tk.BOTH, expand=True)

        left_frame = ttk.Frame(self.paned_window)
        right_frame = ttk.Frame(self.paned_window)

        self.paned_window.add(left_frame, weight=1)
        self.paned_window.add(right_frame, weight=2)

        # Linke Seite
        self.device_list = tk.Listbox(left_frame, width=50, height=20)
        self.device_list.bind("<Double-Button-1>", self.select_device)
        self.device_list.pack(pady=10, padx=10, fill=tk.BOTH, expand=True)

        self.scan_button = tk.Button(left_frame, text="Scannen starten", command=self.toggle_scanning)
        self.scan_button.pack(pady=10)

        # Rechte Seite
        right_paned = ttk.PanedWindow(right_frame, orient=tk.VERTICAL)
        right_paned.pack(fill=tk.BOTH, expand=True, pady=10, padx=10)

        # Services Frame (now with tabs)
        self.services_notebook = ttk.Notebook(right_paned)
        right_paned.add(self.services_notebook, weight=1)

        # Values Frame
        values_frame = ttk.Frame(right_paned)
        right_paned.add(values_frame, weight=1)

        values_label = ttk.Label(values_frame, text="Werte")
        values_label.pack(anchor=tk.W)

        self.values_text = tk.Text(values_frame, wrap=tk.WORD)
        self.values_text.pack(fill=tk.BOTH, expand=True)

        button_frame = ttk.Frame(values_frame)
        button_frame.pack(fill=tk.X)

        self.read_button = tk.Button(button_frame, text="Wert lesen", command=self.read_characteristic_value, state=tk.DISABLED)
        self.read_button.pack(side=tk.LEFT, padx=(0, 5))

        self.write_button = tk.Button(button_frame, text="Wert schreiben", command=self.write_characteristic_value, state=tk.DISABLED)
        self.write_button.pack(side=tk.LEFT, padx=5)

        self.notify_button = tk.Button(button_frame, text="Benachrichtigungen aktivieren", command=self.toggle_notifications, state=tk.DISABLED)
        self.notify_button.pack(side=tk.LEFT, padx=5)

        self.clear_button = tk.Button(button_frame, text="Werte löschen", command=self.clear_values)
        self.clear_button.pack(side=tk.LEFT, padx=5)

    def toggle_scanning(self):
        if self.scanning:
            self.stop_scanning()
        else:
            self.start_scanning()

    def start_scanning(self):
        self.scanning = True
        self.scan_button.config(text="Scannen stoppen")
        threading.Thread(target=self.scan_loop, daemon=True).start()

    def stop_scanning(self):
        self.scanning = False
        self.scan_button.config(text="Scannen starten")

    def scan_loop(self):
        async def run_scan():
            while self.scanning:
                devices = await self.scanner.discover()
                self.root.after(0, self.update_device_list, devices)
                await asyncio.sleep(5)  # Scan every 5 seconds

        asyncio.run(run_scan())

    def update_device_list(self, devices):
        self.devices = devices
        self.device_list.delete(0, tk.END)
        for device in self.devices:
            self.device_list.insert(tk.END, f"{device.name or 'Unbekannt'} ({device.address})")

    def select_device(self, event=None):
        index = self.device_list.curselection()
        if index:
            self.selected_device = self.devices[index[0]]
            self.stop_scanning()
            threading.Thread(target=self.get_services_thread, daemon=True).start()

    def get_services_thread(self):
        asyncio.run(self.get_services())

    async def get_services(self):
        device_name = self.selected_device.name or 'Unbekannt'
        tab_name = f"{device_name} ({self.selected_device.address})"

        # Check if tab already exists
        for tab in self.services_notebook.tabs():
            if self.services_notebook.tab(tab, "text") == tab_name:
                self.services_notebook.select(tab)
                return

        # Create new tab
        tab = ttk.Frame(self.services_notebook)
        self.services_notebook.add(tab, text=tab_name)

        services_tree = ttk.Treeview(tab, columns=('uuid', 'properties'), show='tree headings')
        services_tree.heading('uuid', text='UUID')
        services_tree.heading('properties', text='Eigenschaften')
        services_tree.pack(fill=tk.BOTH, expand=True)
        services_tree.bind("<Double-1>", self.on_characteristic_double_click)

        self.root.after(0, self.update_values_text, f"Verbinde mit {self.selected_device.address}...\n")

        try:
            async with BleakClient(self.selected_device.address) as client:
                services = await client.get_services()

                for service in services:
                    service_item = services_tree.insert('', 'end', text=str(service.uuid), values=(str(service.uuid), ''))
                    for char in service.characteristics:
                        services_tree.insert(service_item, 'end', text=str(char.uuid), values=(str(char.uuid), ', '.join(char.properties)))
        except Exception as e:
            self.root.after(0, self.update_values_text, f"Error: {str(e)}\n")

    def on_characteristic_double_click(self, event):
        tree = event.widget
        item = tree.selection()[0]
        parent_item = tree.parent(item)
        if parent_item:  # It's a characteristic
            self.selected_characteristic = tree.item(item)['text']
            properties = tree.item(item)['values'][1].split(', ')

            if 'read' in properties:
                self.read_characteristic_value()

    def read_characteristic_value(self):
        if self.selected_characteristic:
            threading.Thread(target=self.read_value_thread, daemon=True).start()

    def read_value_thread(self):
        asyncio.run(self.read_value())

    async def read_value(self):
        if not self.selected_characteristic:
            return

        self.root.after(0, self.update_values_text, f"Lese Wert von {self.selected_characteristic}...\n")

        try:
            async with BleakClient(self.selected_device.address) as client:
                value = await client.read_gatt_char(self.selected_characteristic)
                self.root.after(0, self.update_values_text, f"Wert: {value.hex()}\n")
        except Exception as e:
            self.root.after(0, self.update_values_text, f"Fehler beim Lesen: {str(e)}\n")

    def write_characteristic_value(self):
        # Hier können Sie einen Dialog implementieren, um den zu schreibenden Wert einzugeben
        # Für dieses Beispiel verwenden wir einen festen Wert
        value_to_write = b'\x01\x02\x03'
        threading.Thread(target=self.write_value_thread, args=(value_to_write,), daemon=True).start()

    def write_value_thread(self, value):
        asyncio.run(self.write_value(value))

    async def write_value(self, value):
        if not self.selected_characteristic:
            return

        self.root.after(0, self.update_values_text, f"Schreibe Wert zu {self.selected_characteristic}...\n")

        try:
            async with BleakClient(self.selected_device.address) as client:
                await client.write_gatt_char(self.selected_characteristic, value)
                self.root.after(0, self.update_values_text, f"Wert erfolgreich geschrieben: {value.hex()}\n")
        except Exception as e:
            self.root.after(0, self.update_values_text, f"Fehler beim Schreiben: {str(e)}\n")

    def toggle_notifications(self):
        threading.Thread(target=self.toggle_notifications_thread, daemon=True).start()

    def toggle_notifications_thread(self):
        asyncio.run(self.toggle_notifications_async())

    async def toggle_notifications_async(self):
        if not self.selected_characteristic:
            return

        try:
            async with BleakClient(self.selected_device.address) as client:
                await client.start_notify(self.selected_characteristic, self.notification_handler)
                self.root.after(0, self.update_values_text, f"Benachrichtigungen für {self.selected_characteristic} aktiviert\n")
                # Hier könnten Sie einen Mechanismus implementieren, um die Benachrichtigungen zu stoppen
                await asyncio.sleep(30)  # Benachrichtigungen für 30 Sekunden empfangen
                await client.stop_notify(self.selected_characteristic)
                self.root.after(0, self.update_values_text, f"Benachrichtigungen für {self.selected_characteristic} deaktiviert\n")
        except Exception as e:
            self.root.after(0, self.update_values_text, f"Fehler bei Benachrichtigungen: {str(e)}\n")

    def notification_handler(self, sender, data):
        self.root.after(0, self.update_values_text, f"Benachrichtigung empfangen: {data.hex()}\n")

    def update_values_text(self, text):
        self.values_text.insert(tk.END, text)
        self.values_text.see(tk.END)

    def clear_values(self):
        self.values_text.delete('1.0', tk.END)

if [B]name[/B] == "[B]main[/B]":
    root = tk.Tk()
    app = BLEScannerApp(root)
    root.mainloop()


ich bekomme nur UUID's die wenn ich sie richtig codiert werte ausgeben wie
"0000"
"Version1.0"
"TP357S (6527)"
oder der abruf bricht vorher ab oder es heißt service nicht gefunden

ich weis echt nichtmehr was ich noch probieren kann
hab den aktuellsten Bluetoothtreiber den ich installieren kann für die Intel Dual AC-7265
kann es sein das nur die eigentlich dafür vorgesehene app für android auf diese UUID zugriff hat?
kann ich das dem gerät irgendwie vorgaukeln?

danke schonmal für jede hilfe!
 

Anhänge

  • blescan.PNG
    blescan.PNG
    284,3 KB · Aufrufe: 82
Zuletzt bearbeitet:
Bitte pack zuerst den Code mal in eine Codeumgebung (natürlich ohne Leerzeichen in den eckigen Klammern). Sonst ist das ganze zu unübersichtlich.

[ CODE=PYTHON] Code goes here [ /CODE]

Alternativ auch mit dem GUI möglich (Python muss für korrektest Markup dann noch aus dem Dropdown ausgewählt werden):

1727849908418.png
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: therealsimmal und R O G E R
Zurück
Oben