… Oder, warum ich mein WC smart machen möchte…
Aber erstmal ein Hallo und ein Vorwort:
Ich beschreibe hier relativ knapp, wie aus einer Idee ein Modul wurde. Es sieht leicht aus, aber ich habe Tage benötigt um mich einzulesen, die Werte herauszufinden, nachher per BT zu testen um anschließend ein Modul zu erstellen. Ich versuche gerne eure Fragen zu beantworten, aber ich werde jetzt nicht alle möglichen BT Geräte in Symcon holen
Kürzlich haben wir unser Badezimmer renoviert und wir beschlossen, ein WC mit Lady/Dusche/Fön anzuschaffen. Heraus kam ein WC was neben dem gewünschten noch einiges an Zusätzen beinhaltete.
Diese sind sehr hot , zum einen hat das Teil eine Sitzheizung, ein Nachtlicht, macht Töne u.v.a.m.
Zeit dies sinnvoll in ein Smarthome reinzubekommen, wichtig waren folgende Dinge:
- Wenn wir das Haus verlassen, brauche ich keine Sitzheizung oder Licht,
- Wenn jemand zuhause ist, wär die Heizung schön, aber nur unter bestimmten bedingungen
- Der Bestätigungston sollte nachts ausgeschaltet sein.
Zudem besitzt das WC ein Ferienprogramm. Dies soll aktiviert werden, wenn wir in Urlaub fahren, ein Reinigungsprogramm und noch anderes Zeug.
Schnell wurde mir auch klar, das wenn der Hersteller kein Bock mehr auf Programmierung hat, wir doof dastehen, denn es gibt zwar eine Fernbedienung, aber die kann „nur“ die Grundfunktionen darstellen. Ferienprogramm oder die Manuelle Reinigung kann man nicht aktivieren. Alles Gründe dies ändern zu wollen.
Lets Hacking…
Voraussetzung ist ein Android Smartphone sowie die passende App fü das WC. Beides ist bereits gekoppelt und die Funktion ist gegeben.
Wir aktivieren am Handy den Developer Modus und darin das Bluetooth Sniffing, außerdem empfehle ich, möglichst alles andere zu deaktivieren, was mit BT gekoppelt ist (smartwatch bspw)
Nun öffnen wir die passende App, melden uns an und merken uns was zzt eingestellt ist. (oder screenshot machen).
Dann gehen wir nach und nach die funktionen durch, nicht zuviel, wir müssen uns ja auch merken, wann wir welche Funktion ausgeführt haben.
Wenn wir durch sind, holen wir uns vom Smartphone die Debug datei und lesen diese in Wireshark ein.
Das ganze ist nun recht unübersichtlich, daher filtern wir nach btatt.
Die Ansicht habe ich mir passend gemacht, Length und Value sind hier für mich wichtig.
Hier sieht man in etwa was passiert. Sobald wir die App öffnen, sendet die App etwas (CB97ABB2) dann wird 0100 gesendet und wir bekommen eine Bestätigung (5505032a2d).
Spätestens jetzt empfiehlt es sich, eine Tabelle anzulegen und dort aufzuschreiben was wir in welcher Reihenfolge gemacht haben und welches Ergebnis kommt
Wenn wir uns den Wert ansehen der bei „Temperatur aus“ gesendet wird, dann sehen wir ein paar infos
Der nächste Schritt ist es, sich mit dem Laptop es vor dem Klo gemütlich zu machen und zu testen
Ich habe dazu die Gatttools benutzt (bin Linuxuser) und rufen folgendes auf
gatttool -I
dann melden wir uns via
connect MACADRESSE
an und melden uns mit den gefundenen Anmeldedaten an
char-write-cmd 0x010 cb97abb2
nun können wir uns „primary“ die Daten irgendwohin notieren, das gleiche mit „characteristics“
Primary
attr handle: 0x0001, end grp handle: 0x0007 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x0008, end grp handle: 0x0008 uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x0009, end grp handle: 0xffff uuid: 00011111-0405-0607-0809-0a0b0c0d11ff
characteristics
handle: 0x0002, char properties: 0x0a, char value handle: 0x0003, uuid: 00002a00-0000-1000-8000-00805f9b34fb
handle: 0x0004, char properties: 0x02, char value handle: 0x0005, uuid: 00002a01-0000-1000-8000-00805f9b34fb
handle: 0x0006, char properties: 0x02, char value handle: 0x0007, uuid: 00002a04-0000-1000-8000-00805f9b34fb
handle: 0x000a, char properties: 0x10, char value handle: 0x000b, uuid: 00012222-0405-0607-0809-0a0b0c0d11ff
handle: 0x000d, char properties: 0x0c, char value handle: 0x000e, uuid: 00013333-0405-0607-0809-0a0b0c0d11ff
handle: 0x000f, char properties: 0x1c, char value handle: 0x0010, uuid: 00014444-0405-0607-0809-0a0b0c0d11ff
handle: 0x0012, char properties: 0x1c, char value handle: 0x0013, uuid: 00015555-0405-0607-0809-0a0b0c0d11ff
Da wir ja die Anmeldaten nutzen konnten, versuchen wir nun die ersten Tests
char-write-cmd 0x000e 550504250029
Und die Heizung wird deaktiviert. Hurra!
Nun kommt Fleißarbeit, alles notieren, testen, aufschreiben.
(Achtung, diese Screenshot stimmen nicht überein, ich habe mich recht spät entschieden, das aufzuschreiben).
Wenn man mal alles in einer Tabelle hat, fallen einem einige Dinge auf…
5505 04 2500 29
5505 steht IMMER als erstes.
dann kommet es darauf an, was wir senden oder empfangen
04 sind dinge aus dem Einstellungsmenü oder
06 sind Parameter die wir erhalten
dann kommen die Values, also die Werte die an ein Gerät gesendet werden. Im obigen Fall 2500.
Die letzten beide Werten ändern sich, je nachdem was man macht… Hierbei handelt es sich um eine Checksumme, hier 29
Super. Aber wie zur Hölle berechnet man die Checksumme? Das hat mich graue Haare gekostet, ich habe mir dazu zwei kleine Funktionen geschrieben
function CalculateChecksum(string $hex)
{
$bufLen = strlen($hex);
for ($dec=0; $dec < 200; $dec+=1)
{
$sum_dec = $dec;
for ($i=0; $i < $bufLen; $i+=2)
{
//echo substr($hex, $i, 2);
$sum_dec += hexdec(substr($hex, $i, 2));
}
$crc = strtoupper(dechex(($sum_dec % 256)));
echo "CRC: ".$crc." Polynom: ". str_pad($dec,2,"0", STR_PAD_LEFT)." Polynom Hex: ".dechex($dec)."\n";
}
}
function verifyChecksum(string $hex, int $dec)
{
$bufLen = strlen($hex);
$sum_dec = $dec;
for ($i=0; $i < $bufLen; $i+=2)
{
//echo substr($hex, $i, 2);
$sum_dec += hexdec(substr($hex, $i, 2));
}
$result = strtoupper(dechex(($sum_dec % 256)));
return str_pad($result,2,"0", STR_PAD_LEFT);
}
Nun gebe ich meinen Wert ein, aber OHNE die Checksumme. Die möchte ich schließlich herausfinden
echo CalculateChecksum("5505042500");
und erhalte eine Liste mit den möglichen CRC Ergebnis (gekürzt)
CRC: 27 Polynom: 123 Polynom Hex: 7b
CRC: 28 Polynom: 124 Polynom Hex: 7c
CRC: 29 Polynom: 125 Polynom Hex: 7d
CRC: 2A Polynom: 126 Polynom Hex: 7e
CRC: 2B Polynom: 127 Polynom Hex: 7f
CRC: 2C Polynom: 128 Polynom Hex: 80
Im obigen Fall war ja die Checksumme die 29, wir merken uns das Polynom 125 und testen das ganze:
echo verifyChecksum('5505042500',125);
Als ergebnis erhalten wir 00. Mist… Es sollte ja 29 rauskommen. Also überlegen wir weiter, es ändert sich NUR das Value, also der Wert 2500, der Rest bleibt identisch. Nochmal von vorne:
echo CalculateChecksum("2500");
CRC: 25 Polynom: 00 Polynom Hex: 0
CRC: 26 Polynom: 01 Polynom Hex: 1
CRC: 27 Polynom: 02 Polynom Hex: 2
CRC: 28 Polynom: 03 Polynom Hex: 3
CRC: 29 Polynom: 04 Polynom Hex: 4
CRC: 2A Polynom: 05 Polynom Hex: 5
Aha, das Polynom 4. Neuer Versuch
echo verifyChecksum('2500',4);
Nun ist das Ergebnis 29. Perfekt. Wir testen das durch und vergewissern uns das es klappt. (kleiner Hinweis, in dem Fall ist das Polynom 04, bei den Parametern 06, fällt euch was auf? )
Nun können wir sogar die Checksumme berechnen. Warum ist das Wichtig? Wenn wir Parameter EMPFANGEN möchten wir ja sichergehen, das die auch korrekt übertragen wurde, das wird auch wichtig, wenn die Datenpakete nicht auf einmal sondern versetzt kommen.
So… Jetzt kommt aber die nächste sache… Wie sage ich nun symcon, das der ganze kram über Bluetooth an die Toilette soll? Ich habe dazu Tasmota benutzt. ich weiss noch nicht ob ich dabei bleibe, aber es erfüllt seinen Zweck.
Wir schnappen uns also einen ESP32 (wegen Bluetooth) und flashen Tasmota-Bluetooth drauf, dann stellen wir symcon als mqtt server ein, aktivieren bluetooth und starten Tasmota einmal neu.
In Tasmota selber können wir nun in deren Console die ersten Tests machen, dummerweise benötigen wir die UUIDs zum senden, diese haben wir bereits über die gatttools bekommen.
Befehle senden wir in der Tasmota Konsole so:
bleop m:MacAddresseDesKLos s:00011111-0405-0607-0809-0a0b0c0d11ff c:00014444-0405-0607-0809-0a0b0c0d11ff w:cb97abb2 go";
Nun dröseln wir mal auf
m:MacAddresseDesKLos ist die Macadresse der Toilette
s:00011111-0405-0607-0809-0a0b0c0d11ff
haben wir bei den gatttool gefunden, nachdem wir Primary eingegeben habe. Da standen drei werte, Anhand einer Liste die man auf der bluetooth seite findet können wir rausfinden, das die ersten beiden uns nicht interessieren. Bleibt also nur die letzte Auswahl.
Bei c:00014444-0405-0607-0809-0a0b0c0d11ff
konnten wir über wireshark sehen, das bei der Anmeldung 0x0010 benutzt wird,
und aus dem gatttool characteristics konnten wir folgenden Wert finden
handle: 0x000f, char properties: 0x1c, char value handle: 0x0010, uuid: 00014444-0405-0607-0809-0a0b0c0d11ff
Bei „char value handle“ steht die 0x0010 und daneben die UUID.
w:cb97abb2 bedeutet write, wir senden das value zur anmeldung an die Toilette
go führt den befehl sofort aus, ansonsten kommt es in eine warteschlange.
Obiger Befehl ermöglicht uns also die Anmeldung. Nun können wir auch testen ob das ausschalten geht
bleop m:MacAddresseDesKLos s:00011111-0405-0607-0809-0a0b0c0d11ff c:00013333-0405-0607-0809-0a0b0c0d11ff w:550504250029 go";
Achtet dabei, das sich hier die Characteristic geändert hat. Wir haben bei Wireshark gesehen, das mit 0x000e gesendet wird und die uuid dafür ist eine andere…
Wir heisst es so schön? Der Rest ist trivial. Wir können uns nun ein Modul schreiben, der mittels obigen Befehl über Tasmota das WC steuert.
Ich hoffe ich konnte euch einen kleinen Einblick geben, wie so ein scheinbar simples Modul entsteht, welche Motivation dahintersteckt und wie steil die Lernkurve ist.
Viele Grüße