Messwerte von Waage per Bluetooth LE übertragen (bluepy)

  • Hallo,

    ich versuche gerade für einen Bekannten ein kleines Python-Programm zu schreiben. Er hat eine Fitdays-Waage, welche ihre Messwerte per BLE an ein Smartphone überträgt. Er würde diese Werte jetzt aber gerne auch mit seinem Pi 4B empfangen. Anscheinend gibt es mehrere alternative, herstellerunabhängige Apps für diese Art Waagen. Also sollte man davon ausgehen dürfen, dass die Übertragung nicht besonders abgesichert ist. Jetzt bin ich im Thema Low Energy nicht gerade sehr fit. Die Waage wird von hcitool lescan auf jeden Fall mal gefunden. sudo gatttool b <mac> -I funktioniert zwar, der Befehl connect scheitert aber nach einiger Zeit mit der Meldung "Connection refused". Bei weiteren Versuchen erfolgt ein Input/Output Error bis man hciconfig hci0 reset ausführt. Jetzt habe ich folgendes Script geschrieben:

    das ausführen (mittels sudo) ergibt folgendes:

    Zitat

    Gerät gefunden:a0:91:53:e2:58:db

    Adress-Typ: public

    connectable:False

    Signal:-73dB

    Und beim Wiegen das:

    Zitat

    Broadcast empfangen von a0:91:53:e2:58:db(AAA006):

    (1, 'Flags', '04')

    (3, 'Complete 16b Services', '0000ffb0-0000-1000-8000-00805f9b34fb')

    (255, 'Manufacturer', 'aca0db58e25391a0a0c9c2780db0')

    (9, 'Complete Local Name', 'AAA006')

    Da connectable=false ist, gehe ich nach einiger Recherche davon aus, dass die Waage ihre Daten nur per Advertisment überträgt. Und so wie ich das sehe und verstehe, können sie nur in den Manufacturer Data enthalten sein. Jetzt stellt sich mir nur die Frage wie das zu entschlüsseln ist. Zunächst mal bleibt die Länge der Manufacturer-Daten immer gleich (112 bit), egal ob Körpermesswerte (Wasser, Fett, Knochen) mit gemessen wurden oder nur das Gewicht. Dann ist die Mac-Adresse der Waage enthalten, so das nur noch 16 bit vor und 48 bit nach der Mac für Nutzdaten bleiben. Da die Mac-Adresse "verkehrt herum" ist vermute ich mal es handelt sich um Little Endian-Datentypen. Aber egal ob Big oder Little und ob float oder integer oder sonst was (auch nicht ASCII oder UTF-8), ich bekomme aus diesem Bit-Salat egal mit welchen offset ich das auswerten will nichts brauchbares heraus. Da ich aber auch nur viel vermute und wenig weiß hoffe ich jetzt auf einen Tipp von euch. Hat irgend etwas von dem was ich da tue Hand und Fuß? Oder muss man doch irgendwie mit dem Gerät verbinden um Services und characteristics auslesen zu können? Kann man aus den Manufacturer-Daten irgendwas heraus lesen?

    Danke schon mal für Tipps

  • Messwerte von Waage per Bluetooth LE übertragen (bluepy)? Schau mal ob du hier fündig wirst!

  • Ich bin auch nicht der große Experte für BLE, aber 6 Byte Daten sieht doch erstmal gut aus. Die Frage ist doch was passiert, wenn du da zb einen immer gleichen Eimer Wasser drauf stellst, im Wechsel mit einem anderen bekannten Gewicht. Ich kann mir auch nicht vorstellen, dass die mehr als 2 Byte für das Gewicht benötigen & würde erwarten, die beiden Bytes ändern sich dann vorhersehbar.

  • Hallo, danke für die schnellen Antworten :)

    Das hätte ich eigentlich gleich dazu sagen können: Ja der Wert ändert sich je nach Gewicht. Bisher hat er sich immer nur selbst gewogen (vermute mal er wollte nicht zu seiner Frau sagen: Wieg dich mal, ich schicke die Daten dann an einen Kumpel) aber da ja eh nie exakt das selbe Ergebnis heraus kommt gibt es schon Unterschiedliche Werte:

    aca0db58e25391a0a0c9c2780db0

    aca0db58e25391a0a0a0a0a306a9

    aca0db58e25391a0a0c9f8c00dae

    aca0db58e25391a020c892d80dbf

    Die ersten zwei Byte sind immer ac a0, unabhängig vom Gewicht und ob Körpermesswerte gemessen wurden oder nicht (in diesen Beispielen sind keine gemessen worden, möglich aber, dass dann trotzdem irgendein default-Wert übertragen wird).

    Dann folgt die Mac-Adresse. Interessant wird es dann vermutlich anschließend:

    a0c9c2780db0

    a0a0a0a306a9

    a0c9f8c00dae

    20c892d80dbf

    Das gesuchte Gewicht ist zwischen 88 und 91kg. Der Datentyp müsste ja vermutlich eine Fließkommazahl sein. Da fällt mir aber spontan nur float und double ein. Und float kenne ich nur mit 32 bit, was für den Anwendungsfall ja doch arg übertrieben wäre

    Edit: Der Wassereimertest ergab jetzt drei mal exakt den selben Wert:

    aca0db58e25391a0a0a0a0a306a9

    Wassereimer, 3,95kg

    Die Magie scheint sich irgendwo in den letzten drei Bytes abzuspielen. Ich vermute mal, ich suche nur noch den richtigen Datentyp

    2 Mal editiert, zuletzt von FlatGrass60523 (17. Juni 2020 um 10:47)

  • Das der Wert eine Fliesskommazahl sein muss ist ein Irrglaube. So wuerde ich zumindest das nicht formatieren, denn wir reden hier von einer Aufloesung die vielleicht bei maximal 100g liegt, und einem Wertebereich zwischen 10 und 200kg. Da mit 32 Bit zu hantieren ist etwas sehr uebertrieben.

    Ich habe einfach mal was geraten - und halte die Ausgaben fuer plausibel. Aber wie gesagt, es waere wichtig, da auch mal Daten zu bekommen, bei denen das Gewicht klar anders ist:

  • Er hat mir jetzt noch ein paar Messungen geschickt:

    4,85kg

    aca0db58e25391a0a0c8b1900db6

    aca0db58e25391a0a0c8a9d40db2

    aca0db58e25391a020c8b27e0da5

    aca0db58e25391a0a0c89fb60daa

    aca0db58e25391a0a0c8a0a00db5

    aca0db58e25391a0a0c8a0a00db5

    4,80kg

    aca0db58e25391a0a0c8a4640dbd

    aca0db58e25391a0a0c8b2240dab

    aca0db58e25391a020c8b2740dbb

    Der Wert wurde immer so von der Waage und der App angezeigt.

    Nach fast jedem Wert kam außerdem folgende Zeile, die auch früher schon öfter mal vorhanden war:


    aca0db58e25391a0a0a0a0a306a9

    Das könnte evtl. ein festgelegtes Signal oder ein Fehler sein.

    Bei den 4,85kg gibt dein Script folgendes aus:

    51360 25764 48397 102.72

    51360 9394 43789 102.72

    51232 29874 47885 102.464

    Bei 4,80:

    51360 37041 46605 102.72

    51360 54441 45581 102.72

    51232 32434 42253 102.464

    51360 46751 43533 102.72

    51360 41120 46349 102.72

    51360 41120 46349 102.72

    I

  • Es ist ein bisschen nervig, aber ich glaube wir brauchen leider mehr Daten. Am besten eben sagen wir mal Kiloweise anstiege. Vielleicht hat er ja Spass an Hanteln. Oder eben ein Eimer Wasser, und immer wieder einen Liter reinkippen. Denn bisher habe ich in keiner Weise ein Schema erkennen koennen. Kann sein, dass die das zB einfach mit etwas XORen. Und so Kram. Leider aergerlich. Wichtig ist auch rauszufinden, ob der exakt gleiche angezeigte Wert immer zur gleichen Ausgabe fuehrt. Oder ob die zB in einem Byte ein secret definieren, mit dem dann der Rest zu dekodieren ist.

  • Habe es mal weiter gegeben. Ich weiß mittlerweile so viel, dass die Fitday-App nicht spezifisch für diese Waage ist sondern ein vielzahl verschiedener Marken unterstützt. Scheint da vielleicht eine Art quasi-Standard zu geben. Bluetooth LE selbst kennt ja eine so genannte Characteristic für Waagen. Dafür müsste aber erst mal eine Verbindung hergestellt werden können. Ich versuche das morgen mal mit Python, in dem Moment in dem ein Advertisment kommt die Verbindung herzustellen. Wäre ja ärgerlich wenn man versucht, diese Manufacturer-Daten zu entschlüsseln wenn es das nicht mal ist. Außerdem habe ich die Fitday-App für Android durch den Decompiler gejagt und schaue mal was es da so rauszulesen gibt. Er darf in der Zwischenzeit Wiegemeister spielen ;) Im moment bin ich aber leider arbeiten

  • Er hat mir mal noch ein paar Messungen geschickt:

    Er hat die Waage auch mal auf Pfund umgestellt, was von der App direkt erkannt wurde. Also schickt die Waage wohl auch die Art der Gewichtseinheit mit.

    OpenScale unterstützt die Waage nicht, ich wühle mich gerade durch Fitdays... aber das wird was größeres.

    Aktiv eine BLE-Verbingung zur Waage aufbauen hat mit Python genau so wenig funktioniert, wie mit gatttool. Was mich etwas wundert, den wie ich im Quelltext von OpenScale sehe scheint es wohl eher gängig zu sein eine Verbindung zum Gerät aufzubauen und dann den Wert abzufragen.

    Wenn nichts gelesen werden kann, wird hier (https://github.com/oliexdev/openS…tooth-4.x-scale) beschrieben, wie man es reverse-engineeren könnte.

    Er sucht gerade nach seinem alten Android-Smartphone. Allerdings sieht es fast so aus als würde die Anleitung auch Characteristics abrufen, was eine aktive LE-Verbindung bedeuten würde.

    Die Waage ist übrigens eine Insmart

    Das ist doch alles sehr viel komplizierter als gedacht :geek:

  • Wir haben es dann endlich raus gefunden: Zunächst mal sendet die Waage nicht EIN Advertisement pro Wiegung sondern dutzende. Die 20 im ersten Byte zeigt wohl den Abschluss der Messung an. Die folgenden drei Bytes sindder Messwert, das 0d weiß kein Mensch und danach folgt eine Prüfsumme (Also nicht die, die vom Bluetooth Le-Protokoll vorgesehen ist sondern eine zusätzliche). Herausgefunden haben wir das alles indem wir so getan haben als wären wir die Waage und Daten an die App gesendet haben.

    Folgendes hat aber etwas gedauert herauszufinden:

    Nehmen wir zb. c9 c3 be. Um den korrekten Wert zu erhalten müssen das dritte und fünfte "Zeichen" Des Hex-Strings getauscht werden anhand folgenden Schemas:

    0 1 2 3 4 5 6 7 8 9 a b c d e f Normal
    a b 8 9 e f c d 2 3 0 1 6 7 4 5 Icomon

    Aus "c9 c3 be" wird so "c9 63 1e".

    c8 a0 a0 ist, wie wir mittlerweile wissen 0,00kg. Anhand der Tabelle wird das zu c8 00 00.

    Wenn ich jetzt c9 63 1e - c8 00 00 rechne komme ich auf 01 63 1e. In Dezimal: 90910. Geteilt durch 1000 sind 90,91, gerundet auf 0,05 ergibt das 90,9. Und damit genau das, was die App anzeigt. WIr haben das mit vielen Werten probiert und es funktioniert einfach immer. Ich hab keine Ahnung, ob das irgendwelches Big/Little-Endian oder MSB/LSB-Voodoo ist (man erkennt ja durchaus ein Muster in der "Verschiebung"), hauptsache das Thema ist endlich erledigt ;) Wenn doch jemand eine Erklärung dafür hat, ich lerne gerne dazu. Jedenfalls vielen Dank für alle Ratschläge, hat uns auf dem Weg zur Antwort definitiv geholfen.

  • Toll das ihr das herausgefunden habt!

    Das 0x0d ist ein new line, und ich kann mir gut vorstellen, dass das Protokoll aus einer seriellen abgeleitet ist. Auch wenn die Bytes vorher ein 0x0d Zeichen enthalten könnten, und es darum etwas sinnlos ist.

    Die “Verschlüsselung” hat nichts mit MSB oder Endianess zu tun, sondern ist XOR:

    Code
    for i in range(16):
        print(hex(i), hex(i ^ 0xa))

    Auch da kann man nur spekulieren. Kann einfach nur zur Verschleierung gedacht sein. Manchmal macht man das auch als primitive Prüfsumme, aber dann schickt man die original Daten natürlich mit.

  • Also doch XOR, wie du früher schon vermutet hast ^^.

    Na gut, es war dann nicht so schwer darauf zu kommen. Wir haben unsere Pi's und zwei Android-Phones genommen, ich hab ein Script geschrieben das ein Advertisement mit einem festen Prüfwert sendet, per adb shell screencap -p einen Screenshot aufnimmt, zuschneidet, per tesseract-ocr auswertet ob der Prüfwert angezeigt wird. Danach von c80000 aufsteigend den ersten Wert sendet, per OCR auswertet, in eine Datenbank speichert, wieder den Prüfwert sendet, dan c80001 usw. Nach mehreren Tagen 24h-Betrieb und 93.000 gespeicherten Werten hab ichs dann doch endlich gesehen. Also alles kein Problem :D

    Nur gut das so ein kleines Nebenprojekt nicht komplett eskalieren kann. Wäre ja ein Wahnsinniger Aufwand-Nutzen-Faktor :wallbash:

    Jedenfalls vielen Dank für die Erklärung, jetzt bin ich wieder ein bisschen schlauer.

    Wenn Körperwerte gesendet werden ist das erste Byte übrigens a2 und 0d ist 06. Aber erstens ändern sich die Körperwerte sobald man in der App Alter oder Größe ändert, also sendet die Waage wohl nur einen Impendanzwert. Und zweitens interessieren uns diese Daten nicht. Uns reicht zum Glück das Gewicht ^^

    Einmal editiert, zuletzt von FlatGrass60523 (21. September 2020 um 11:33)

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!