Forum: Mikrocontroller und Digitale Elektronik Bluetooth LE BLE Daten von Powermeter entschlüsseln


von Tim B. (tim_b84)


Angehängte Dateien:

Lesenswert?

Moin Leute, ich versuche gerade für dieses Gerät eine schönere App mit 
App Inventor zu kreieren, die sich via BLE mit dem Gerät verbindet. 
http://www.junteks.com/product/278218225
Ich habe bereits ein Bluetooth-Protokoll aus meinem Smartphone gezogen, 
das protokolliert, wie ich die originale App öffne und mich mit dem 
Gerät verbinde. Ich kann das Protokoll mit Wireshark öffnen, aber so 
richtig verstehe ich nicht, was da passiert. 
(btsnoop_hci_202201251007.cfa)
Außerdem habe ich die originale App dekompiliert. Da gibt es auch eine 
Datei, die wichtigen Inhalte preisgibt, aber auch hier fällt es mir 
schwer dem etwas Sinnvolles zu entnehmen. (MainActivity.java)
Außerdem habe ich mit App Inventor einen der Bluetooth Services 
abonniert und empfange damit tatsächlich eine Datenreihe aus der ich 
Laufzeit, Spannung, Strom und Leistung auslesen kann. Allerdings ist das 
so umständlich, dass ich davon ausgehe, dass es noch einen anderen Weg 
geben muss. Z.B. wird im HEX -Format die Laufzeit in Sekunden gefolgt 
vom Wert D5 angezeigt. (D5 (HEX-Wert) taucht z.B. als Dezimalzahl in der 
Java-Datei wieder auf.) Immer mal wieder ändert sich der Wert dann aber 
sprunghaft und es wird ein völlig falscher Wert für die Laufzeit gefolgt 
vom Wert D5 angezeigt. Der Wert für die Spannung hat jeweils 
unterschiedlich viele Stellen, sodass man nie so recht weiß, welche 
Stellen man jetzt verwenden muss etc.
Kann jemand von Euch jemand etwas mit dem Bluetooth-Protokoll oder mit 
der dekompilierten App anfangen und mir ggf. helfen, mit der App 
weiterzukommen?

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Hast Du mal beim Hersteller nach Dokumentation zum Protokoll gefragt? 
Ansonsten kannst Du Dir mit einem generischen GATT-Client, die Services 
und die dazugehörigen Characteristics angucken. Das sollte deutlich 
einfacher sein, als sich das mit einem Sniffer die Discovery-Prozedur 
anzugucken. Wenn dabei allerdings etwas komplexere Mechanismen, wie 
Control-Points verwendet werden, kommt man damit recht schnell an die 
Grenzen.

von Tim B. (tim_b84)


Lesenswert?

Der Hersteller antwortet leider nicht.

Ich habe mir die Bluetooth Services und GATTs mit dieser App angeschaut. 
https://play.google.com/store/apps/details?id=com.siliconlabs.bledemo&hl=de&gl=US

Ich nehme an, das ist so eine Art generischer GATT-Client, oder?

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Tim B. schrieb:

> Ich nehme an, das ist so eine Art generischer GATT-Client, oder?

Richtig :-) Damit kannst Du wahrscheinlich schon heraus bekommen, wie 
das Protokoll funktioniert.

Die Characteristic ab Handle 0x0021 scheint ja irgendwie die 
interessante zu sein. Vielleicht verwenden die diese Characteristic nur 
wie eine Art UART. 0xbb könnte dann so etwas wie eine Frame-Anfang zu 
sein und 0xee das Ende (Packet 930 bis 934 würde dann zusammen einen 
Frame ergeben).

Die Notifications, die im Sekundentakt gesendet werden, haben dann 
wahrscheinlich den Frame-Type  Opcode  whatever von 0x50 und die 
Nutzlast wäre dann z.B.:
1
  0x08 0xd5 0x88
2
  0x09 0xd5 0x89
3
  0x10 0xd5 0x96
4
  0x11 0xd5 0x97

die würde ich mal Beobachten, wenn Du die Messwerte änderst

von Tim B. (tim_b84)


Angehängte Dateien:

Lesenswert?

Puh, da komm ich nicht mehr mit Frame-Type  Opcode  whatever von 0x50. 
Da verstehe ich nur noch Bahnhof :-)

Also, wenn ich die Service UUID ffe0 und die Char UUID ffe1 verwende 
bekomme ich im Sekundentakt eine Zeichenkette gesendet. Ich vermute mal, 
dass ich mit App Inventor das UART Protokoll zu sehen bekomme. Die habe 
ich mir genauer angeschaut und festgestellt, dass die Kette entweder im 
Sekundentakt die Laufzeit oder sofort eine Spannungs-, Strom- oder 
Leistungänderung mitteilt.
Im ersten Fall lautet die Zeichenkette z.B. 187 3 85 33 213 40 238. Die 
187 scheint eine Art Anfangszeichen zu sein. Die 213 gibt an, dass davor 
die Zeit steht. Die 40 weiß ich nicht, die ändert sich aber auch im 
Sekundentakt. Evt. eine Prüfsumme. Die 238 ist das Schlusslicht. Wenn 
ich die Zeichenkette zwischen 187 und 213 zusammen setze und ins 
HEX-Format umwandle, dann habe ich die Laufzeit. Leider ändert sich 
dieser Wert gelegentlich plötzlich und die Laufzeit wird falsch 
angezeigt. Warum konnte ich noch nicht herausfinden.
Bei einer Änderung von Spannung oder Strom werden die jeweiligen Werte 
gefolgt von 192, 193 angezeigt. Auch hier muss ich ins HEX-Format 
konvertieren.
Nun frage ich mich, warum das dermaßen kompliziert gemacht ist. Ich weiß 
z.B. nie, wie viele Stellen die Spannung denn jetzt hat. Klar kann ich 
was programmieren, das mir die Stellen zwischen der 187 und der 192 
ausrechnet, aber ich frage mich, ob es nicht auch einfacher geht. 
Außerdem kann ich die Werte für Spannung und Strom nicht manuel abrufen 
und bekomme sie erst, wenn es eine Änderung gibt. In der originalen App 
wird die Spannung aber gleich zu Beginn angezeigt. Wenn ich so etwas 
programmieren würde, dann würde ich doch eine Zeichenkette senden, die 
alle Infos in immer derselben Reihenfolge enthält, damit ich der Reihe 
die einfach entnehmen kann. Darum kommt mir immer wieder der Gedanke, 
dass ich hier irgendwas falsch mache...

von noreply@noreply.com (Gast)


Lesenswert?

MainActivity.java Reengineeren.
Insbesondere private void parseCommand(int n, int n2) {

von noreply@noreply.com (Gast)


Lesenswert?

Und ich würde untersuchen, ob die App das BLE-Gerät gezielt abfragt.


    public void sendData(byte[] arrby) {
        BluetoothGatt bluetoothGatt;
        if (this.able && (bluetoothGatt = this.mBluetoothGatt) != null) 
{
            BluetoothGattCharacteristic bluetoothGattCharacteristic = 
bluetoothGatt.getService(UUID.fromString((String)"0000fff0-0000-1000-800 
0-00805f9b34fb")).getCharacteristic(UUID.fromString((String)"0000fff2-00 
00-1000-8000-00805f9b34fb"));
            bluetoothGattCharacteristic.setValue(arrby);
            this.mBluetoothGatt.writeCharacteristic(bluetoothGattCharacteristic);
        }
    }

von noreply@noreply.com (Gast)


Lesenswert?

Und jetzt die wichtigen Fragen. ;-)
Reden wir über einen KG-140F, wo kann man den bestellen und was kostet 
das Gerät?

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Tim B. schrieb:
> Die habe
> ich mir genauer angeschaut und festgestellt, dass die Kette entweder im
> Sekundentakt die Laufzeit oder sofort eine Spannungs-, Strom- oder
> Leistungänderung mitteilt.
> Im ersten Fall lautet die Zeichenkette z.B. 187 3 85 33 213 40 238.

> 187 scheint eine Art Anfangszeichen zu sein...

Ja, oder eben BB in hexadezimal. In der Software-Entwicklung ist es 
recht üblich, die C-Notation für hexadezimale Zahlen (literals) zu 
verwenden: 0xBB

> Die 40 weiß ich nicht, die ändert sich aber auch im
> Sekundentakt. Evt. eine Prüfsumme.

Kann sein, wäre bei einer UART nicht unüblich. Den Typen der Daten 
kodiert man "üblicherweise" mit einem bestimmten Wert am Anfang, damit 
mit man relativ früh erkennt, wie die Daten zu Interpretieren wären. Ich 
würde dann eher darauf tippen, dass die 3 (0x03) anzeigen, dass es sich 
um die Laufzeit handelt.

> Leider ändert sich
> dieser Wert gelegentlich plötzlich und die Laufzeit wird falsch
> angezeigt.

Versuch mal nur Werte miteinander zu vergleichen, bei denen die Zahl 
hinter dem 187 (0xbb) identisch sind.

> Auch hier muss ich ins HEX-Format
> konvertieren.
> Nun frage ich mich, warum das dermaßen kompliziert gemacht ist. Ich weiß
> z.B. nie, wie viele Stellen die Spannung denn jetzt hat.

Du must dort nichts in's HEX-Format konvertieren. Das ist nur eine Art, 
Zahlen darzustellen. Was Du machen must (und das machst Du dann 
implizit, wenn Du Zahlen (Bytes) in's HEX-Format konvertierst), ist die 
einzelnen Bytes wieder zusammen zu einer größeren Zahl zusammensetzen 
(deserialisieren).

> Klar kann ich
> was programmieren, das mir die Stellen zwischen der 187 und der 192
> ausrechnet, aber ich frage mich, ob es nicht auch einfacher geht.

Das ist so ziemlich die einfachste, binäre Darstellung von Zahlen, die 
möglich ist (von dem Frame (0xbb, 0xee) und der CRC mal angesehen).

> Außerdem kann ich die Werte für Spannung und Strom nicht manuel abrufen
> und bekomme sie erst, wenn es eine Änderung gibt. In der originalen App
> wird die Spannung aber gleich zu Beginn angezeigt.

Im gezeigten Mitschnitt, sendet das Gerät direkt mit dem Subscribe auf 
die Characteristic die ersten Daten (frame 921). Vielleicht hast Du da 
noch ein Problem in Deiner App, dass die z.B. zuerst auf die 
Characteristic subscribed und dann den dazu nötigen Callback 
installiert.

> Wenn ich so etwas
> programmieren würde, dann würde ich doch eine Zeichenkette senden, die
> alle Infos in immer derselben Reihenfolge enthält, damit ich der Reihe
> die einfach entnehmen kann. Darum kommt mir immer wieder der Gedanke,
> dass ich hier irgendwas falsch mache...

Binäre Protokolle sind halt deutlich effektiver. Für Zahlen von 0-1000 
bräuchtest Du 4 Byte, ein Binärprotokoll aber nur 2 Byte.

HTH
Torsten

von Tim B. (tim_b84)


Lesenswert?

noreply@noreply.com schrieb:
> Und jetzt die wichtigen Fragen. ;-)
> Reden wir über einen KG-140F, wo kann man den bestellen und was kostet
> das Gerät?

Ich habe ein KG-110F. Gibts z.B. bei Aliexpress für ca. 30€

https://de.aliexpress.com/item/1005003414812628.html?gatewayAdapt=glo2deu&spm=a2g0o.9042311.0.0.1ae04c4diXvJgI

von Tim B. (tim_b84)


Lesenswert?

Vielen Dank für die Vielen Antworten.

>> 187 scheint eine Art Anfangszeichen zu sein...
>
> Ja, oder eben BB in hexadezimal. In der Software-Entwicklung ist es
> recht üblich, die C-Notation für hexadezimale Zahlen (literals) zu
> verwenden: 0xBB

Okay, ich hatte mich nur gewundert, weil in App Inventor erst mal 
Dezimalzahlen angezeigt werden und auch in dem dekompilierten Java-Code 
sind Dezimalzahlen angegeben... aber der Code ist ja auch 
dekompiliert:-) und App Inventor ist eben App Inventor :-)


>> Die 40 weiß ich nicht, die ändert sich aber auch im
>> Sekundentakt. Evt. eine Prüfsumme.
>
> Kann sein, wäre bei einer UART nicht unüblich. Den Typen der Daten
> kodiert man "üblicherweise" mit einem bestimmten Wert am Anfang, damit
> mit man relativ früh erkennt, wie die Daten zu Interpretieren wären. Ich
> würde dann eher darauf tippen, dass die 3 (0x03) anzeigen, dass es sich
> um die Laufzeit handelt.

Seltsamerweise ist es hier andersrum und die Typen der Daten werden nach 
dem Wert angegeben (liest man in China nicht von rechts nach links?). 
Tatsächlich gehört die 3 mit zur Laufzeit. Alles was zwischen 187 und 
213 steht ist die Laufzeit in Sekunden, da bin ich mir ziemlich sicher. 
Nur die 40 weiß ich noch nicht. Da die aber eben auch im Sekundentakt 
hochzählt würde es ja Sinn machen, wenn das eine Prüfsumme wäre. Da muss 
ich wohl mal ein bisschen hin und her rechnen um rauszufinden, wie die 
berechnet wird. Vielleicht die Quersumme oder so...


>> Leider ändert sich
>> dieser Wert gelegentlich plötzlich und die Laufzeit wird falsch
>> angezeigt.
>
> Versuch mal nur Werte miteinander zu vergleichen, bei denen die Zahl
> hinter dem 187 (0xbb) identisch sind.

Wie meinst Du das?

>
>> Auch hier muss ich ins HEX-Format
>> konvertieren.
>> Nun frage ich mich, warum das dermaßen kompliziert gemacht ist. Ich weiß
>> z.B. nie, wie viele Stellen die Spannung denn jetzt hat.
>
> Du must dort nichts in's HEX-Format konvertieren. Das ist nur eine Art,
> Zahlen darzustellen. Was Du machen must (und das machst Du dann
> implizit, wenn Du Zahlen (Bytes) in's HEX-Format konvertierst), ist die
> einzelnen Bytes wieder zusammen zu einer größeren Zahl zusammensetzen
> (deserialisieren).
>
>> Klar kann ich
>> was programmieren, das mir die Stellen zwischen der 187 und der 192
>> ausrechnet, aber ich frage mich, ob es nicht auch einfacher geht.
>
> Das ist so ziemlich die einfachste, binäre Darstellung von Zahlen, die
> möglich ist (von dem Frame (0xbb, 0xee) und der CRC mal angesehen).

Schon, aber es wäre doch kein Problem gewesen, z.B. eine Null voran zu 
stellen, damit die Zahlenfolge immer gleich lang ist z.B. 01000 für 10 
Volt. Oder immer Spannung, Strom und Leistung zusammen zu übertragen und 
nicht mal das eine und mal das andere. Wahrscheinlich hat der 
Programmierer versucht immer so wenig Daten wie möglich zu übertragen. 
So würde das Sinn ergeben. Aber das wieder auseinander zu pflücken ist 
echt aufwendig.

>> Außerdem kann ich die Werte für Spannung und Strom nicht manuel abrufen
>> und bekomme sie erst, wenn es eine Änderung gibt. In der originalen App
>> wird die Spannung aber gleich zu Beginn angezeigt.
>
> Im gezeigten Mitschnitt, sendet das Gerät direkt mit dem Subscribe auf
> die Characteristic die ersten Daten (frame 921). Vielleicht hast Du da
> noch ein Problem in Deiner App, dass die z.B. zuerst auf die
> Characteristic subscribed und dann den dazu nötigen Callback
> installiert.

Danke, das hilft mir sehr weiter. Dann weiß ich jetzt, wo ich nach dem 
Fehler suchen muss.


>
>> Wenn ich so etwas
>> programmieren würde, dann würde ich doch eine Zeichenkette senden, die
>> alle Infos in immer derselben Reihenfolge enthält, damit ich der Reihe
>> die einfach entnehmen kann. Darum kommt mir immer wieder der Gedanke,
>> dass ich hier irgendwas falsch mache...
>
> Binäre Protokolle sind halt deutlich effektiver. Für Zahlen von 0-1000
> bräuchtest Du 4 Byte, ein Binärprotokoll aber nur 2 Byte.
>
> HTH
> Torsten

von Tim B. (tim_b84)


Lesenswert?

noreply@noreply.com schrieb:
> Und ich würde untersuchen, ob die App das BLE-Gerät gezielt abfragt.
>
>
>     public void sendData(byte[] arrby) {
>         BluetoothGatt bluetoothGatt;
>         if (this.able && (bluetoothGatt = this.mBluetoothGatt) != null)
> {
>             BluetoothGattCharacteristic bluetoothGattCharacteristic =
> bluetoothGatt.getService(UUID.fromString((String)"0000fff0-0000-1000-800 
0-00805f9b34fb")).getCharacteristic(UUID.fromString((String)"0000fff2-00 
00-1000-8000-00805f9b34fb"));
>             bluetoothGattCharacteristic.setValue(arrby);
> 
this.mBluetoothGatt.writeCharacteristic(bluetoothGattCharacteristic);
>         }
>     }

Ja, das könnte z.B. auch das Zurücksetzen des Stromzählers sein. Leider 
verstehe ich kein Wort javajanisch. Ich glaube, der wichtige Satz wäre 
hier bluetoothGattCharacteristic.setValue(arrby); Den Rest kann ich in 
etwa nachvollziehen. aber was ist mit arrby gemeint?

von Tim B. (tim_b84)


Lesenswert?

noreply@noreply.com schrieb:
> MainActivity.java Reengineeren.
> Insbesondere private void parseCommand(int n, int n2) {

Ja eben dabei hatte ich mir Hilfe erhofft, weil ich eben kein Java kann. 
Die besagte Stelle habe ich auch schon entdeckt. Z.B. wird eben mit der 
192 die Spannung abgefragt. Die taucht ja auch in der Zeichenfolge, die 
ich empfange, auf.
Was ich verstehe ist, dass er erst mal ausschließt, dass 182, 183, 224 
und 225 in der Zeichenfolge auftauchen. Die ganzen switch und default 
kann ich nicht verstehen und auch nicht, was direkt darunter bei der 217 
steht. Was anschließend kommt kann ich mir wieder in etwa zusammen 
reimen, weil ich ja z.B. auch schon herausgefunden habe, dass vor der 
192 (bzw. C0) die Spannung steht. Aber was dann weiter unten bei Main 
Activity steht kann ich auch wieder nicht nachvollziehen.

von Jim M. (turboj)


Lesenswert?

Die UUIDs sehen aus wie beim HM-17, das ist ein beliebtes UART-auf-BTLE 
Wandler Modul.

Wenn man da gelegentlich Fehler findet könnte das am Modul liegen, denn 
das verliert bei schneller UART Übertragung öfter mal Daten.

Die App ignoriert das Problem, denn im Code findet am Anfang von 
processCommand() eine simple Summenprüfung statt - bei der fehlerhafte 
Daten rausfliegen.

Normalwerweise hat man schon gewonnen wenn man die Werte aus der Anzeige 
hexadezimal im Datenstrom auffindet.

von noreply@noreply.com (Gast)


Lesenswert?

Tim B. schrieb:
> Ich glaube, der wichtige Satz wäre
> hier bluetoothGattCharacteristic.setValue(arrby);

Bitte die Bibliothek nochmal des wegen befragen. Ich gehe aber von 
nachfolgenden verhaltens aus.

arrby ist ein array of bytes, das gesendet werden soll.

mit nachfolgenden Kommando wird dann das array of bytes dann gesendet.
this.mBluetoothGatt.writeCharacteristic(bluetoothGattCharacteristic);

von noreply@noreply.com (Gast)


Lesenswert?

Tim B. schrieb:
> Was ich verstehe ist, dass er erst mal ausschließt, dass 182, 183, 224
> und 225 in der Zeichenfolge auftauchen.

Die Werte scheinen dominant zu sein. Das ganze if/switchkonstrukt 
scheint laufzeitoptimiert zu sein. Habe ich aber so noch nie gesehen.

n = Kommando
n2 = Wert

Da wird das Endgerät nach Konfigurationsparametern abgefragt und in 
parseCommand Attributen der Benutzergui zugeordnet.

z.B. in den tieferen Schichten.
wenn n=199, dann wird n2 den Attribut OCP über eine Setterroutine 
zugeordnet

 case 199: {
                                                ((SettingFragment)((Object)this.this$0.fragmentList.get(1))).setOCP(this 
.val$num);
                                                return;
                                            }

Das hier ist noch schwieriger zu verstehen. Bei n=192 wird ein Attribut 
Vol gesetzt. Könnte Voltage sein.

case 192:
                                        }
                                        ((MainFragment)((Object)this.this$0.fragmentList.get(0))).setSettingVol( 
this.val$num);
                                        return;

von noreply@noreply.com (Gast)


Lesenswert?

Die nachfolgenden Klassen wäre wichtig zu verstehen, wenn man eigene 
Kommandos aufbauen möchte. Die sind noch dekompiliert.

import com.juntek.celiangvat.util.BCDCode;
import com.juntek.celiangvat.util.BCDUtil;
import com.juntek.celiangvat.util.Command;

von noreply@noreply.com (Gast)


Lesenswert?

+ nicht dekompiliert

von Tim B. (tim_b84)


Angehängte Dateien:

Lesenswert?

noreply@noreply.com schrieb:
> Die nachfolgenden Klassen wäre wichtig zu verstehen, wenn man eigene
> Kommandos aufbauen möchte. Die sind noch dekompiliert.
>
> import com.juntek.celiangvat.util.BCDCode;
> import com.juntek.celiangvat.util.BCDUtil;
> import com.juntek.celiangvat.util.Command;

Die sind alle in einem Ordner namens Util. Ich habe auch gleich mal den 
ganzen Ordner mit den dekompilierten Files angehängt.
BCD Code sieht mir nach Umwandlung von dezimal nach hexadezimal aus. 
TimeFormat ist auch klar.

Insgesamt kann ich oft schon erkennen, was da so ungefähr gemacht 
wird...aber eben nur sehr ungefähr :-) und das hilft mir beim App 
schreiben nicht so recht weiter...

von Tim B. (tim_b84)


Angehängte Dateien:

Lesenswert?

noreply@noreply.com schrieb:
> Tim B. schrieb:
>> Was ich verstehe ist, dass er erst mal ausschließt, dass 182, 183, 224
>> und 225 in der Zeichenfolge auftauchen.
>
> Die Werte scheinen dominant zu sein. Das ganze if/switchkonstrukt
> scheint laufzeitoptimiert zu sein. Habe ich aber so noch nie gesehen.
>
> n = Kommando
> n2 = Wert
>
> Da wird das Endgerät nach Konfigurationsparametern abgefragt und in
> parseCommand Attributen der Benutzergui zugeordnet.
>
> z.B. in den tieferen Schichten.
> wenn n=199, dann wird n2 den Attribut OCP über eine Setterroutine
> zugeordnet
>
>  case 199: {
> 
((SettingFragment)((Object)this.this$0.fragmentList.get(1))).setOCP(this 
.val$num);
>                                                 return;
>                                             }
>
> Das hier ist noch schwieriger zu verstehen. Bei n=192 wird ein Attribut
> Vol gesetzt. Könnte Voltage sein.
>
> case 192:
>                                         }
> 
((MainFragment)((Object)this.this$0.fragmentList.get(0))).setSettingVol( 
this.val$num);
>                                         return;

Okay, das macht schon beides Sinn. OCP ist Overvoltageprotection. Die 
kann man bei dem Gerät einstellen und setSettingVol in Verbindung mit 
der 192 konnte ich ja sogar schon darstellen.

Grundsätzlich gehe ich erst mal davon aus, dass diese Werte nach einer 
Änderung über die Zeichenfolge gesendet werden, die ich hier sowieso 
schon empfangen kann. Irgendwie muss es aber auch möglich sein, etwas an 
das Gerät zu senden. Z. B. um den Zähler zurückzusetzen. Da wäre es 
schon noch sehr wichtig herauszufinden, wie das gehen kann.
Bisher verwende ich Service 0xfff0 Char 0xfff1 oder Service 0xffe1 Char 
ffe1. Da kommen dann im Sekundentakt Infos, die man entsprechend 
auswerten kann. Daten zu senden habe ich noch gar nicht ausprobiert.

von Tim B. (tim_b84)


Angehängte Dateien:

Lesenswert?

Ich habe jetzt noch einmal ziemlich lange am Datenempfang rumgebastelt. 
Im Grunde funktioniert es jetzt ganz gut, aber es bleibt das Problem, 
dass ich nicht weiß, wie viele Stellen ein Wert hat. Da jedes Mal 
unterschiedliche Werte gesendet werden ist es auch nicht wirklich 
möglich die Werte zwischen zwei Bezeichnungen zu verwenden. Ein 
Beispiel:

Ich bekomme die Zahlenfolge
187 18 20 192 54 193  4 55 216 137 238
bzw.
bb 12 14 c0 36 c1 4 37 d8 89 ee

Nun weiß ich, dass die Spannung 12,44V, der Strom 0,36A und die Leistung 
4,37W beträgt.

Nun kann es aber sein, dass sich dazwischen plötzlich ein anderer Wert 
mogelt. Z.B.

187 18 20 192 54 193 1 17 17 215 4 55 216 137 238
bzw.
bb 12 14 c0 36 c1 1 11 d7 4 37 d8 89 ee

Nun denkt meine Software natürlich, dass alles zwischen c1 und d8 die 
Leistung wäre und verwendet folglich 111d7437 für die Leistung.

Bisher bin ich dem Problem begegnet, indem ich immer weiter alles 
ausgeschlossen habe, was störend sein könnte, aber da immer wieder 
irgendein Wert auftaucht, mit dem die Software nicht rechnet, ist das 
keine sichere Methode.

von noreply@noreply.com (Gast)


Lesenswert?

Tim B. schrieb:
> Bisher bin ich dem Problem begegnet, indem ich immer weiter alles
> ausgeschlossen habe, was störend sein könnte, aber da immer wieder
> irgendein Wert auftaucht, mit dem die Software nicht rechnet, ist das
> keine sichere Methode.

Bilde einfach die Softwarestruktur in MainActivity.java nach:

private void process() {
- Liest aus einen Puffer, solange das Objekt 238 vorhanden ist.
- Schreibt Bytes nach einer Liste von Integer
- Unterbricht, wenn Objekt 238 gefunden wurde und gibt weiter an 
processCommand()
- Liest danach weiter wenn weitere 238 vorhanden sind.

private void processCommand(List<Integer> list) {
- Schaut auf den ersten Blick nach Integritätschecks in der Liste von 
Integer(bytearray) aus.
- macht etwas besonderes, wenn 170 in der Liste von Integer(bytearray) 
auftritt.
- Ansonsten geht es weiter nach parsecommand(n, n2) mit zwei Werten aus 
der Liste von Integer(bytearray)

private void parseCommand(int n, int n2) {
- Analysiert die Kombinationen (n,n2)
- wenn n bekannt, geht n2 ins Datenmodell
- wenn n unbekannt, wird n2 implizit aus den Bytestrom entfernt.

von Chris K. (kathe)


Lesenswert?


von Tim B. (tim_b84)


Lesenswert?

Chris K. schrieb:
> Ist das protokoll nicht im manual beschrieben ?
> http://www.junteks.com/newsitem/278597309
> http://68.168.132.244/KG-F_EN_manual.pdf

Das habe ich auch gehofft, aber das Protokoll ist nur für den RS485 Bus.
Ich habe sogar schon überlegt, ob ich das interne Bluetooth Modul kappe 
und stattdessen ein HM-10 Modul an den seriellen Port anschließe. Das 
Protokoll wäre auf jeden Fall sehr viel einfacher...

von my2ct (Gast)


Lesenswert?

Wenn die Daten wirklich verschlüsselt wären, wie es der Titel des 
Threads suggeriert, hätte man keine Chance, ohne den Schlüssel oder 
größeren Aufwand irgendwelche sinnvollen Dinge in den Daten zu erkennen.
Bisher sieht das alles eher nach einer Kodierung nach einem einfachen 
Protokoll aus.

von Tim B. (tim_b84)


Lesenswert?

Ich glaube, jetzt läuft es:

Ich suche in der Zeichenkette nach der Angabe für einen bestimmten Wert 
z.B. C0 für Spannung und verwende dann alle Zeichen davor bis zum 
nächsten nicht nummerischen Wert.

Ich habe also z.B. die Zeichenkette

187 18 17 192 85 193 6 102 216 22 238
BB 12 11 C0 55 C1 6 66 D8 16 EE

Dann suche C0 und starte dann eine Routine, die die Stellen davor 
übernimmt. Wenn er einen nicht nummerischen Wert (hier: BB) findet, dann 
wird die Routine unterbrochen. Ergebnis: 1211 (mV)

Dann suche ich nach C1 für den Strom und mache dasselbe etc.

Ob das so im Sinne des Programmierers war, weiß ich natürlich nicht...

Jetzt bleiben noch die anderen Problemchen z.B:
- Abrufen der Spannung nach dem Start. Hier ist die App offensichtlich 
nicht schnell genug um die ersten Werte die ankommen auswerten zu 
können.

- Die Prüfsumme. Die steht vor dem EE, aber ich konnte noch nicht 
herausfinden, wie sie berechnet wird. Gibt es hier neben der Quersumme 
noch andere übliche Methoden?

von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

Tim B. schrieb:
> Dann suche C0 und starte dann eine Routine, die die Stellen davor
> übernimmt. Wenn er einen nicht nummerischen Wert (hier: BB) findet, dann
> wird die Routine unterbrochen. Ergebnis: 1211 (mV)

Spannend, dass würde bedeuten, dass die Daten als BCD kodiert sind. 
Jeweils 4 bit ergeben dann eine dezimal-Ziffer. (hat mir mein Großvater 
mal von erzählt)

> - Die Prüfsumme. Die steht vor dem EE, aber ich konnte noch nicht
> herausfinden, wie sie berechnet wird. Gibt es hier neben der Quersumme
> noch andere übliche Methoden?

Ich vermute mal, dass die Kollegen da ein bestehendes, serielles 
Protokoll auf BLE umgebogen haben. BLE hat eine 24 bit CRC in der 
Übertragung. Wenn Daten bei Dir ankommen, dann sind die in der Regel 
korrekt übertragen worden. Eine zusätzlich CRC in den Nutzdaten ist 
eigentlich überflüssig. Ich würde die einfach ignorieren.

von Jim M. (turboj)


Lesenswert?

Torsten R. schrieb:
> BLE hat eine 24 bit CRC in der
> Übertragung.

Die nützt nix, wenn auf der UART Seite schon Daten verloren gehen.

Und das passiert ganz schnell mal, z.B. wenn das Modul wegen einer 
Funkstörung kurz nix los wird.

Diese fertig entwickelten Protokolle behät man dann bei, wenn man von µC 
+ BTLE Modul auf eine Single-Chip Lösung wechselt.

von Tim B. (tim_b84)


Angehängte Dateien:

Lesenswert?

Inzwischen funktioniert meine App relativ gut. Nur weiß ich noch immer 
nicht, wie diese vermaledeite Prüfsumme berechnet wird. Ich habe 
inzwischen mal Docklite installiert und damit auf die gewöhnlichen 
Prüfsummenverfahren geprüft - leider ohne Erfolg. Außerdem habe ich 
ziemlich viel hin- und hergerechnet, aber ich komme einfach nicht drauf. 
Hat dazu vielleicht noch jemand eine Idee?

von Tim B. (tim_b84)


Lesenswert?

Nochmal ein Update für die Nachwelt:

Nach langem Rumgeeier habe ich mittels Bluefruit LE Sniffer (für 
Bluetooth LE), Python und Wireshark die Bluetooth-Verbindung 
ausspioniert. Ich habe einen Vormittag gebraucht, um mich einzuarbeiten. 
Das war also sehr viel einfacher, als ich gedacht hätte. Dadurch konnte 
ich sowohl herausfinden, dass ein write Befehl an eine bestimmte UUID 
erfolgen muss, um zu Beginn alle Daten einmal über die abonnierte UUID 
zu erhalten. Außerdem konnte ich den write Befehl zum Zurücksetzen des 
Zählers herausfinden.
Ich kann im Fazit also nur empfehlen, das mit dem Sniffen zu probieren. 
Das ist zwar zeitaufwendig, weil man unglaublich viele Datenpakete 
anschauen muss, aber schlussendlich eine relativ einfache Methode, den 
Datenverkehr nachzubauen. Die Anleitung von Bluefruit sind dafür 
wirklich gut und die frei erhältliche Wireshark Software ist 
unbezahlbar.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.