Batteriestatus der am Mac angeschlossenen Bluetooth-Geräte in Homebridge integrieren

  • Wieso, weshalb, warum?

    Wer kennt es nicht? Die Frau hat an ihrem freien Tag mal wieder gekonnt die Hinweise zum niedrigen Batteriestand der Magic Mouse ignoriert, als sie im Internet nach den schönsten Babynamen recherchiert hat. Man kommt nach Hause, möchte ein Homebridge-Plugin installieren aber die Maus ist tot.


    Das Szenario ist natürlich völlig aus der Luft gegriffen! :P


    Trotzdem wollte ich für den Fall der Fälle den Batteriestatus von Magic Mouse und Magic Keyboard in Homebridge einbinden. Nach einiger Bastelei in einer sehr kurzen Nacht habe ich es dann auch tatsächlich hinbekommen.

    Wie funktioniert das?

    • Auf dem Mac wird mittels crontab ein Bash-Script ausgeführt, das den aktuellen Batteriestand ausliest
    • Die Ausgabe wird hübsch formatiert in eine .json-Datei auf dem Raspberry Pi geschrieben
    • Auf dem Raspberry Pi läuft das Plugin homebridge-http-humidity, das die Informationen in HomeKit einfügt
    • In der Home App sieht man dann zwei Sensoren, die (natürlich nicht die Luftfeuchte, sondern) den Batteriestand anzeigen


    Achtung!

    Vorweg: das hier ist wirklich nur eine Bastelanleitung. Es gibt mit Sicherheit elegantere Wege, zum gleichen Ziel zu kommen. Für mich und meine Zwecke ist es so aber ausreichend. Lest die Anleitung bitte bis zum Ende durch. Wenn ihr euch irgendwo unsicher seid, dann lasst es lieber oder fragt einfach nach. Falls ihr Verbesserungsvorschläge habt - immer her damit!

    Vorraussetzungen

    Damit alles reibungslos funktioniert, solltet ihr wie in der Homebridge Installations-Anleitung im Abschnitt SSH-Schlüsselerstellung und -installation beschrieben über ssh (ohne die Eingabe eines Kennworts) auf euren Raspberry Pi zugreifen können. Außerdem solltet ihr natürlich einen Mac, eine Magic Mouse und ein Magic Keyboard besitzen.

    Los geht's

    1. btBattery.sh auf dem Mac erstellen


    Erstellt auf eurem Mac in einem beliebigen Verzeichnis eine Datei die ihr zum Beispiel btBattery.sh nennt.

    Bei mir liegt die Datei in einem Unterordner innerhalb meines Benutzerordners: /Users/gerrit/Bash/btBattery.sh


    Der Inhalt der Datei sollte wie folgt aussehen:

    Code
    #! /bin/bash
    
    PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
    BATTLVL=$(/usr/sbin/ioreg -r -l -n AppleHSBluetoothDevice | egrep '"BatteryPercent" = |^  \|   "Bluetooth Product Name" = '| sed 's/  |   "Bluetooth Product Name" = "Magic Mouse 2"/  \{  \"mouse\":/' | sed 's/  |   "Bluetooth Product Name" = "Magic Keyboard"/  \,  \"keyboard\":/'| sed 's/  |   |       "BatteryPercent" = / /')
    
    BATTJSON=${BATTLVL//[$'\t\r\n']}
    BATTJSON+=" }"
    
    echo $BATTJSON | ssh [email protected] "cat > /var/www/html/json/btBattery.json"

    Die Stelle, an der "Bluetooth Product Name" = "Magic Mouse 2" und "Bluetooth Product Name" = "Magic Keyboard" steht, müsst ihr entsprechend der Bezeichnung eurer Bluetooth-Geräte anpassen. Den Namen eurer verbundenen Geräte seht ihr, wenn ihr auf dem Mac oben in der Statuszeile auf das Bluetooth-Symbol klickt.


    In der letzten Zeile muss die IP über die euer Raspberry Pi erreichbar ist eingetragen werden. Außerdem wird hier das Verzeichnis und der Dateiname für die .json-Datei in der wir den Batteriestand speichern wollen angegeben. Diese Datei erstellen etwas später.


    2. apache2 auf dem Raspberry Pi installieren


    Nun kommt der Teil, mit dem ich nicht sehr zufrieden bin. Das Plugin homebridge-http-humidity verlangt als Quelle eine URL. Lokale Pfade werden nicht akzeptiert. Und ein passenderes Plugin habe ich leider nicht finden können. So kam ich zu dem Entschluss, dass es am einfachsten ist, auf dem Raspberry Pi einen Apache Webserver zu installieren. Hier der Link dazu aus der offiziellen Dokumentation.


    Führt mit sudo apt-get update ein Update der Pakete durch und installiert mit sudo apt-get apache2 -y den Apache Webserver auf dem Raspberry Pi.


    Nach der Installation wechselt ihr mit cd /var/www/html/ in das Hauptverzeichnis des Webservers. Dort erstellt ihr mit sudo nano /json/btBattery.json die Datei, die wir im btBattery.sh Script angegeben haben. Zu Testzwecken füllen wir diese Datei mit einer Zeile Inhalt:

    Code
    { "mouse": 69, "keyboard": 69 }

    Speichert die Datei und ändert den Benutzer von root auf pi sudo chown pi: /json/btBattery.json


    Wenn ihr jetzt am Mac im Browser http://192.168.178.xx/json/btBattery.json eingebt, solltet ihr die Ausgabe der Datei sehen. Natürlich müsst ihr hier die IP entsprechend anpassen. Auf dem Raspberry Pi könnt ihr die Datei auch über http://localhost/json/btBattery.json erreichen.


    Alternative mit Node Red


    Eine Alternative zum Apache Server mit Node Red hat sschuste in seinem lesenswerten Kommentar aufgezeigt.


    3. homebridge-http-humidity Plugin installieren


    Installiert das Plugin homebridge-http-humidity und fügt in eurer config.json folgende Accessories hinzu:

    Hier muss theoretisch nichts weiter angepasst werden, sei denn eure Geräte haben eine andere Bezeichnung oder ihr wollte sie anders benennen.

    Die Pseudo-Variablen ?type=mouse und ?type=keyboard musste ich hinzufügen, weil das Plugin sonst unzufrieden damit war, zweimal die gleiche URL aufrufen zu müssen.


    Startet Homebridge neu!

    Wenn alles richtig lief, habt ihr jetzt zwei neue Sensoren, die jeweils den von uns eingetragenen Fake-Wert 69 % anzeigen. Im nächsten Schritt versorgen wir sie dann mit den tatsächlichen Werten.


    4. btBattery.sh auf dem Mac regelmäßig ausführen


    Jetzt fehlt nur noch die Aktualisierung der Batteriewerte. Das Script btBattery.sh muss dazu ausführbar sein und regelmäßig aufgerufen werden.

    Ausführbar machen wir das Script über Terminal mit chmod +x /Users/gerrit/Bash/btBattery.sh - ihr gebt hier natürlich euren eigenen Pfad ein!

    Jetzt soll das Script noch regelmäßig aufgerufen werden. Dazu nutzen wir crontab. Startet crontab mit nano als Editor in einem Terminal-Fenster: env EDITOR=nano crontab -e


    Fügt die folgenden Zeilen ein und speichert die Datei.

    Code
    PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
    * * * * * /Users/gerrit/Bash/btBattery.sh

    Die erste Zeile sorgt dafür, dass crontab die korrekten Pfade benutzt.

    In der zweiten Zeile geben wir mit den Sternchen an, wie oft das Script ausgeführt werden soll und wo es zu finden ist.


    Zunächst starten wir das Script jede Minute. Auf der Seite crontab.guru könnt ihr später relativ einfach eure eigenen Werte für die Aktualisierung erstellen.


    In der Home App sollten jetzt nach ca. einer Minute die tatsächlichen Werte des Batteriestatus auftauchen.


    Wenn dem so ist könnt ihr crontab beispielsweise wie folgt anpassen:

    Code
    MAILTO=""
    PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
    */30 * * * * /Users/gerrit/Bash/btBattery.sh


    Der Status der Batterien wird dann nur alle 30 Minuten übertragen. Außerdem sorgt das MAILTO="" dafür, dass euer Terminal bei Fehlermeldungen (die es jetzt nicht mehr geben sollte) nicht zugemüllt wird.


    Fertig!

    Abschließende Worte

    Ich hoffe die Umsetzung lief für euch ohne große Probleme und ich habe beim verfassen der Anleitung nichts vergessen. Ich bin mir fast sicher, dass es noch ein Homebridge-Plugin geben muss, das besser geeignet ist und keinen Webserver benötigt. Die Anleitung werde ich dann (gerne mit eurer Hilfe) entsprechend anpassen.


    Ich bin mehr Bastler als Programmierer. Wenn hier irgendwo grober Unfug steht, freue ich mich über konstruktive Kritik.

    Einmal editiert, zuletzt von Gerrit ()

  • /usr/sbin/ioreg -r -l -n AppleHSBluetoothDevice

    ergibt bei mir schon mal überhaupt keine Ausgabe. Da werd ich wohl mal suchen müssen.

  • Brauche ich zwar nicht aber trotzdem gute Idee und schöne Anleitung :thumbup:

  • ergibt bei mir schon mal überhaupt keine Ausgabe. Da werd ich wohl mal suchen müssen.

    Wenn du den Befehl direkt im Terminal "testen" willst musst ihn anpassen. Irgendwie verhält sich das über crontab anders. Im Terminal sollte es mit diesem hier gehen:


    Code
    echo BATTLVL=$(ioreg -r -l -n AppleHSBluetoothDevice | egrep '"BatteryPercent" = |^  \|   "Bluetooth Product Name" = '| sed 's/  |   "Bluetooth Product Name" = "Magic Mouse 2"/  \|  Mouse:/' | sed 's/  |   "Bluetooth Product Name" = "Magic Keyboard"/  \|  Keyboard:/'| sed 's/  |   |       "BatteryPercent" = / /'); 
  • Naja, wenn schon ioreg -r -l -n AppleHSBluetoothDevice nichts ergibt, dann wird auch der Rest nichts hervorzaubern. Das Ergebnis ist dann auch wie erwartet:


    BATTLVL=


    Ich hab hier einen iMac 27" 5K mit einem Bluetooth-Trackpad und einer Bluetooth-Tastatur.

    Stefan

  • So, ich habs. Bei mir lautet der Befehl:

    ioreg -r -l -n BNBTrackpadDevice | grep BatteryPercent

    ioreg -r -l -n AppleBluetoothHIDKeyboard | grep BatteryPercent


    Damit bastele ich mir jetzt auch was Feines. Danke für den Hinweis darauf :thumbup:

    • Hilfreich

    Der Shell-Befehl lautet bei mir für mein externes Trackpad:

    ioreg -c BNBTrackpadDevice | grep '"BatteryPercent" =' | sed "s/[^0-9]//g"


    und für die Tastatur:

    ioreg -c AppleBluetoothHIDKeyboard | grep '"BatteryPercent" =' | sed "s/[^0-9]//g"


    und für die Maus:

    ich habe keine.


    Dabei kommt dann einfach eine Zahl heraus, die die Batteriekapazität angibt. Aber wie geht's weiter? Der Ansatz von Gerrit, einen Apache-Webserver dafür laufen zu lassen, war mir persönlich zu fett für die eine kleine Aufgabe. Ich habe erst mit dem Gedanken gespielt, mir einen eigenen Server in Javascript zu programmieren, aber habe dann Node Red verwendet.


    Node Red ist ein Tool, das sehr leicht zu installieren ist (sowohl auf einem Mac als auch auf einem Raspi) und das es einem erlaubt, auf grafische Art und Weise zu programmieren. Meine Javascript-Kenntnisse sind sehr, sehr mager, aber ich bin in der Lage, mir was zurecht zu fummeln. Und es ist sehr einfach, die eigenen Ergüsse mit anderen Node Red-Benutzern zu teilen. Es ist tatsächlich fast ein Klacks, einen Webserver in Javascript zu programmieren (ich glaube, das sind nur drei oder vier Zeilen Code, die man aus dem Internet kopiert), aber noch viel einfacher ist es, Node Red zu verwenden.


    Programmiert wird im Browser. Das einzig Ärgerliche ist, das mit der letzten Version auf einmal alles in deutscher Sprache angezeigt wird, was nicht so schlimm wäre, wenn die Übersetzung aus dem Englischen nicht so schauerlich wäre. Daher nehme ich als Browser Chrome, den ich so eingestellt habe, dass er alles in Englisch macht. Ich bin das so gewöhnt, ich kann auch keine deutsche Shell im Terminal ertragen.



    So sieht das bei mir aus, ich hab mal einen Screenshot gemacht und mit Sprechblasen kommentiert. So etwas nennt man in Node Red-Sprache einen Flow, und den kann man mit anderen teilen. Hier ist er:

    Code
    [{"id":"883badb.f65bc5","type":"exec","z":"369d80e.2abcb","command":"ssh [email protected] /usr/sbin/ioreg -c AppleBluetoothHIDKeyboard | grep '\"BatteryPercent\" =' | sed \"s/[^0-9]//g\"","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"Get keyboard battery value","x":780,"y":1640,"wires":[["bc29640b.85a9c8"],[],[]]},{"id":"b9c4c636.4773b8","type":"inject","z":"369d80e.2abcb","name":"Every hour","topic":"","payload":"","payloadType":"date","repeat":"3600","crontab":"","once":false,"onceDelay":0.1,"x":530,"y":1640,"wires":[["883badb.f65bc5"]]},{"id":"4d1763.1418e89c","type":"homekit-service","z":"369d80e.2abcb","bridge":"7524e8b8.7da908","name":"Keyboard","serviceName":"HumiditySensor","manufacturer":"Stefan Schustereit","model":"Node-Red","serialNo":"1","characteristicProperties":"{}","x":1240,"y":1640,"wires":[[]]},{"id":"bc29640b.85a9c8","type":"function","z":"369d80e.2abcb","name":"Prepare value","func":"msg.payload = { \"CurrentRelativeHumidity\": msg.payload.trim() };\nreturn msg;","outputs":1,"noerr":0,"x":1040,"y":1640,"wires":[["4d1763.1418e89c"]]},{"id":"62188cbb.f4c9d4","type":"exec","z":"369d80e.2abcb","command":"ssh [email protected] /usr/sbin/ioreg -c BNBTrackpadDevice | grep '\"BatteryPercent\" =' | sed \"s/[^0-9]//g\"","addpay":false,"append":"","useSpawn":"false","timer":"","oldrc":false,"name":"Get trackpad battery value","x":780,"y":1700,"wires":[["acb4e69d.be23f8"],[],[]]},{"id":"980f76f3.820a58","type":"inject","z":"369d80e.2abcb","name":"Every hour","topic":"","payload":"","payloadType":"date","repeat":"3600","crontab":"","once":false,"onceDelay":0.1,"x":530,"y":1700,"wires":[["62188cbb.f4c9d4"]]},{"id":"7a0e8d00.b80634","type":"homekit-service","z":"369d80e.2abcb","bridge":"7524e8b8.7da908","name":"Trackpad","serviceName":"HumiditySensor","manufacturer":"Stefan Schustereit","model":"Node-Red","serialNo":"1","characteristicProperties":"{}","x":1240,"y":1700,"wires":[[]]},{"id":"acb4e69d.be23f8","type":"function","z":"369d80e.2abcb","name":"Prepare value","func":"msg.payload = { \"CurrentRelativeHumidity\": msg.payload.trim() };\nreturn msg;","outputs":1,"noerr":0,"x":1040,"y":1700,"wires":[["7a0e8d00.b80634"]]},{"id":"7524e8b8.7da908","type":"homekit-bridge","z":"","bridgeName":"Node-RED","pinCode":"030-45-111","port":"","manufacturer":"Stefan Schustereit","model":"Node-RED","serialNo":"1.0"}]

    Sieht hässlich aus, aber egal. Das kopiert man einfach und fügt es in Node Red wieder ein, macht noch ein paar Anpassungen für das eigene Netz und das war's dann auch schon. In diesem Fall muss Node Red vorher durch HomeKit-Fähigkeiten erweitert werden, indem man über das Menü über Manage Palette - Install das Modul @plasma2450/node-red-contrib-homekit-bridged nachinstalliert. Ist so wie Homebridge-Plugins zu installieren.


    Gerrit, ich weiß genau, dass dir Node Red eine Menge Spaß machen würde. Es verbraucht auch nicht mehr Power als ein Apache Webserver, wahrscheinlich sogar weniger.


    Stefan

  • Gerrit, ich weiß genau, dass dir Node Red eine Menge Spaß machen würde. Es verbraucht auch nicht mehr Power als ein Apache Webserver, wahrscheinlich sogar weniger.

    Mit Node Red wollte ich mich schon länger mal beschäftigen. Jetzt habe ich endlich den passenden Grund dafür. Danke dir für den hilfreichen Tipp!

  • Hi, wenn ich sudo nano /json/btBattery.json im raspby eingebe kommt das die datei nicht existier und ich kann da nichts speicher. Was mache ich falsch?

  • /json/btBattery.json

    Wie kommst du zu diesem Pfad?

  • Entweder:

    sudo nano /var/www/html/json/btBattery.json oder


    cd /var/www/html/

    sudo nano json/btBattery.json

    Einmal editiert, zuletzt von sschuste ()

  • Eine seltsame Fehlermeldung. /var/www/html/ ist eigentlich immer DocumentRoot von Apache.

    Doofe Frage, aber du gibst den Befehl auf dem Raspberry Pi ein, auf dem du zuvor Apache installiert hast und nicht etwa auf dem Mac, oder?!


    Gerrit.Fries, ich weiß genau, dass dir Node Red eine Menge Spaß machen würde. Es verbraucht auch nicht mehr Power als ein Apache Webserver, wahrscheinlich sogar weniger.

    Das war also der Beitrag, mit dem du mein Interesse für Node-RED geweckt hast. Es hat zwar noch ein halbes Jahr gedauert, bis ich mich da wirklich ran getraut habe, aber jetzt bin ich dir sehr dankbar dafür! :):thumbup:

  • Eine seltsame Fehlermeldung. /var/www/html/ ist eigentlich immer DocumentRoot von Apache.

    Doofe Frage, aber du gibst den Befehl auf dem Raspberry Pi ein, auf dem du zuvor Apache installiert hast und nicht etwa auf dem Mac, oder?!

    Ja, klar auf m Raspberry


    hab es noch mal gemacht jetzt kommt "Path '/json' is not a directory"

  • Entweder ich hab gerade einen Knick in der Optik, oder sschuste hat sich vertippt.


    Müsste das:

    cd /var/www/html/json/

    sudo nano json/btBattery.json


    Nicht eigentlich so lauten:

    cd /var/www/html/json/

    sudo nano btBattery.json


    :/


    Der erste Befehl wechselt in das Verzeichnis, der zweite erstellt die Datei im Verzeichnis. Dann muss im zweiten Befehl doch nicht wieder der Unterordner (json/) angegeben werden, oder?

  • Nicht eigentlich so lauten:

    cd /var/www/html/json/

    sudo nano btBattery.json

    ja, so ist das richtig und konnte jetzt die json erstellen. Aber der will in den Port 80 starten, conbee 2 ist schon bei mir da. Kann ich irgenwie eins von den beiden den ort ändern? Weiß nicht wie das geht.


    Ok habe es gefunden. Mache morgen weiter.


    Code
    sudo nano /lib/systemd/system/deconz.service
    Ändert dort die Zeile bspw. von
    ExecStart=/usr/bin/deCONZ -platform minimal --http-port=80
    zu
    ExecStart=/usr/bin/deCONZ -platform minimal --http-port=8090
    und speichert die Datei. Im Anschluss noch den systemd Service neustarten:
    sudo systemctl daemon-reload
    sudo systemctl restart deconz
  • oder sschuste hat sich vertippt.

    Ja, hat er :D. Du hast natürlich völlig recht. Hab's gleich mal geändert.