Milquino – Datenanalyse

Der Milquino ist ein Automat zur Zubereitung von Babyflaschen. Wahlweise gibt es dieses Gerät mit einer WLAN-Funktion und kann somit App gestützt genutzt werden.

Eine Nachfrage beim Hersteller ergab, dass es leider keine API gibt die man nutzen könnte, um den Milquino z.B. in Home-Assistant zu integrieren.

Da die Kommunikation offensichtlich über das lokale WLAN läuft und kein Cloud-Service dazwischen ist (was ich sehr begrüßenswert finde), müsste es doch möglich sein, die Kommunikation zwischen der App und dem Gerät mitzuhören, zu analysieren und entsprechend nutzen daraus zu ziehen.

Und genau darum soll es hier gehen. Wie kommuniziert die App mit dem Milquino und kann dies genutzt werden.

Disclaimer

Bevor es losgeht braucht es, so denke ich, einen kleinen Disclaimer. Soll mir ja schließlich niemand auf Idee kommen, hier würden illegale Aktivitäten durchgeführt.

Das Gerät wurde von mir weder geöffnet noch wurde die App de-kompiliert. Die gesamte Analyse basiert auf Mitschnitten in meinem eigenen Netzwerk.

Die ersten Informationen

Hat man den Milquino einmal in sein WLAN integriert wird man relativ schnell feststellen dass er eine „Webseite“ mitbringt. Ruft man die IP des Milquino auf, wird einem folgendes präsentiert:

Einmal mit Wireshark den Aufruf mitgeschnitten bekommt man die Info was verbaut wurde um einen kleinen Server im Milquino zu betreiben:

Wir wissen nun also, dass es sich um einen ESP8226 Chip auf einem NodeMCU Board handelt. Wir gehen einfach mal davon aus, dass keine Anstrengungen unternommen wurden, diese Info zu streuen obwohl ein anderes „Gerät“ genutzt wurde ;). Man mag sich nun fragen: In wie weit bringt mir diese Info nun etwas?

Nun ja, die Antwort ist so simpel wie eventuell überraschend. Sie bringt uns nichts, außer eventuell interessant zu sein.

Kommen wir nun aber zu den wirklich interessante Informationen. Schneidet man den Netzwerkverkehr zwischen App und Milquino mit, findet man heraus dass der Milquino auf Port 9990 mittels UDP angesprochen wird. Zum Glück für uns, ist der Datenverkehr nicht verschlüsselt, sondern Plaintext.

Machen wir es kurz

Das Ergebnis meiner Analyse sind, aktuell, die folgenden Funktionen.

  • Anschalten
  • Ausschalten
  • Domainname erfragen
  • Status erfragen
  • Wassermenge konfigurieren
  • Konfigurierte Wassermenge erfragen
  • Anzahl der Pulverlöffel konfigurieren
  • Konfigurierte Anzahl der Pulverlöffel erfragen
  • Pulverdosierung per Löffel konfigurieren
  • Konfigurierte Pulverdosierung per Löffel erfragen
  • Fläschchen machen

Es gibt noch weitere Funktionen in der App, wie z.B. eine Info ob der Wassertank installiert ist oder ob entkalkt werden muss. Alles habe ich noch nicht analysiert.

Da die Kommunikation per UDP im Klartext stattfindet, können die Funktionen mittels netcat ganz einfach selber getestet werden, indem man die folgenden Strings per UDP an seinen Milquino auf Port 9990 sendet.

Die Payloads, die zu senden sind, um die oben genannten Funktionen zu nutzen lauten:

Function: on

Payload: C:1:72\r\n

Der Returnwert ist

E:C11:06
S:0A:22

S:0A:22 ist der Status dafür, dass die Maschine angeschaltet ist. Wofür der erste Wert steht, habe ich nicht rausgefunden.

Function: off

Payload: C:0:73\r\n

Der Returnwert ist

E:C01:07
S:02:51

S:02:51 ist der Status der anzeigt, dass die Maschine ausgeschaltet ist. Der Sinn des ersten Wertes entzieht sich aktuell meiner Kenntnis

Function: getDomainName

Payload: A:1:70\r\n

In meinem Fall ist der Returnwert zum Beispiel

:MILQUINO-9335445:192.168.178.149

Hier sieht man die IP des Gerätes in meinem Netzwerk sowie den Domainnamen. Ob diese Funktion tatsächlich genutzt wird, um den Domainnamen zu erfahren, ist nur eine Vermutung von mir.

Function: getStatus

Payload: C:5:76\r\n

Der Returnwert um anzuzeigen, dass die Maschine angeschaltet ist, ist

S:0A:22

Ist die Maschine ausgeschaltet kommt der Wert

S:02:51

zurück.

Function: setAmountOfWater

Der Milquino unterstützt in 30ml Schritten die Zubereitung von 60ml bis 240ml Babymilch. Entsprechend gibt es mehrere Payloads die zu senden sind, entsprechend der gewünschten Zubereitungsmenge Wasser.

Payload (60ml):  W:2:65\r\n
Payload (90ml):  W:3:64\r\n
Payload (120ml): W:4:63\r\n
Payload (150ml): W:5:62\r\n
Payload (180ml): W:6:61\r\n
Payload (210ml): W:7:60\r\n
Payload (240ml): W:8:6F\r\n

Der Returnwert ist immer der gesendete Payload. Möchte man also 120ml Wasser einstellen, kommt als Antwort „W:4:63“ zurück.

Function: getAmountOfWater

Payload: C:3:70\r\n

Dieser Payload führt dazu, dass man die aktuell konfigurierte Wassermenge zurückbekommt. Der Rückgabewert entspricht den Payload-Werten aus der Funktion „setAmountOfWater“.

Function: setNumberOfSpoons

Der Milquino unterstützt die Zubereitung von Babymilch mit maximal 7 Pulverlöffeln. Entsprechend, wie bereits bei der Funktion „setAmountOfWater“ gibt es wieder mehrere Payloads die gesendet werden können um die Konfiguration entsprechend durchzuführen.

Payload (2 Spoons): P:1:61\r\n
Payload (3 Spoons): P:2:62\r\n
Payload (4 Spoons): P:3:63\r\n
Payload (5 Spoons): P:4:64\r\n
Payload (6 Spoons): P:5:65\r\n
Payload (7 Spoons): P:6:66\r\n

Der Returnwert ist immer der gesendete Payload. Möchte man also 5 Pulverlöffel konfigurieren, sendet man den Payload „P:4:64\r\n“ und erhält als Antwort „P:4:64“

Function: getNumberOfSpoons

C:4:77\r\n

Die Funktion liefert den aktuell eingestellten Wert für die Menge zu verwendender Pulverlöffel zurück. Die Werte entsprechen denen aus der Funktion „getNumberOfSpoons“.

Function: setDosingPerSpoon

Der Milquino unterstützt die Dosierung eines Löffels im Bereich von 3,8g Pulver bis 5,6g Pulver in 0,2g Schritten. Entsprechend gibt es die folgenden Payloads:

Payload (3,8g): G:0:77
Payload (4g):   G:1:76
Payload (4,2g): G:2:75
Payload (4,4g): G:3:74
Payload (4,6g): G:4:73
Payload (4,8g): G:5:72
Payload (5g):   G:6:71
Payload (5,2g): G:7:70
Payload (5,4g): G:8:7F
Payload (5,6g): G:9:7E

Die Rückgabe ist auch hier immer der Wert, der gesendet wurde.

Function: getDosingPerSpoon

Payload: C:7:74

Der Rückgabewert ist die aktuell eingestellte Menge Pulver pro Löffel und die Werte sind in der Funktion „getDosingPerSpoon“ aufgeführt.

Function: makeMilk

Schlussendlich die Funktion, die die Maschine dazu veranlasst, eine Flasche Babymilch zu mischen.

Payload: C:2:71\r\n

Die Rückgabewerte dieser Funktion verstehe ich aktuell noch nicht, sind für mich zum jetzigen Zeitpunkt aber auch nicht von allzu großem Interesse.

Ein Beispiel

Wie kann man all diese Informationen nun nutzen, um den Milquino auch ohne App zu steuern? Man nutzt z.B. das Kommandozeilen-Tool netcat.

Möchte man so zum Beispiel den Status der Maschine erfahren, könnte man folgenden Befehl in einer Bash-Shell ausführen:

echo -ne "C:5:76\r\n" | nc -u 192.168.178.149 9990

Dieser Befehl sendet den String „C:5:76“ mit CRLF Zeilenterminierung durch das Tool netcat mittels UDP an die IP 192.168.178.149 auf Port 9990:

Wie bekomme ich „das“ jetzt in Home-Assistant?

Abschließend möchte ich ein Beispiel geben, wie man die Informationen nun nutzen kann um eine erste Home-Assistant Integration seinen Milquino zu bauen.

Dazu nutzen wir sowohl die command_line als auch die shell_command Integration von Home-Assistant.

Möchte man sich einen Button bauen um sowohl den aktuellen Status der Maschine als auch den An/Aus-Zustand zu steuern, wäre dies mit einem Binary-Sensor z.B. so machbar:

- platform: command_line
  name: milquino_status
  command: 'echo -ne "C:5:76\r\n" | nc -u -w 2 192.168.178.149 9990'
  scan_interval: 30
  payload_on: "S:0A:22"
  payload_off: "S:02:51"
  command_timeout: 5
  device_class: running

Um sich die aktuelle Konfiguration der Wassermenge sowie Löffelanzahl und Pulvermenge anzeigen zu lassen, könnte man einen Sensoren mit entsprechendem value_template nutzen:

- platform: command_line
  name: milquino_configuredAmountOfWater
  command: 'echo -ne "C:3:70\r\n" | nc -u -w 2 192.168.178.149 9990'
  scan_interval: 30
  command_timeout: 5
  unit_of_measurement: ml
  value_template: >-
    {% if value == 'W:2:65' %} 60
    {% elif value == 'W:3:64' %} 90
    {% elif value == 'W:4:63' %} 120
    {% elif value == 'W:5:62' %} 150
    {% elif value == 'W:6:61' %} 180
    {% elif value == 'W:7:60' %} 210
    {% elif value == 'W:8:6F' %} 240
    {% else %} 0
    {% endif %}
    
- platform: command_line
  name: milquino_configuredNumberOfSpoons
  command: 'echo -ne "C:4:77\r\n" | nc -u -w 2 192.168.178.149 9990'
  scan_interval: 30
  command_timeout: 5
  unit_of_measurement: spoons
  value_template: >-
    {% if value == 'P:1:61' %} 2
    {% elif value == 'P:2:62' %} 3
    {% elif value == 'P:3:63' %} 4
    {% elif value == 'P:4:64' %} 5
    {% elif value == 'P:5:65' %} 6
    {% elif value == 'P:6:66' %} 7
    {% else %} 0
    {% endif %}
    
- platform: command_line
  name: milquino_dosingPerSpoon
  command: 'echo -ne "C:7:74\r\n" | nc -u -w 2 192.168.178.149 9990'
  scan_interval: 30
  command_timeout: 5
  unit_of_measurement: g
  value_template: >-
    {% if value == 'G:0:77' %} 3,8
    {% elif value == 'G:1:76' %} 4
    {% elif value == 'G:2:75' %} 4,2
    {% elif value == 'G:3:74' %} 4,4
    {% elif value == 'G:4:73' %} 4,6
    {% elif value == 'G:5:72' %} 4,8
    {% elif value == 'G:6:71' %} 5
    {% elif value == 'G:7:70' %} 5,2
    {% elif value == 'G:8:7F' %} 5,4
    {% elif value == 'G:9:7E' %} 5,6
    {% else %} 0
    {% endif %}

Um eine Flasche dann letztendlich zuzubereiten könnte man sich einen „Button“ basteln, der einen Service aufruft, den man sich per shell_command baut:

milquino_make_milk: 'echo -ne "C:2:71\r\n" | nc -u -w 2 192.168.178.149 9990'

Das Endergebnis könnte nun so aussehen:

Abschließende Gedanken

So richtig zufriedenstellend, zumindest für mich, ist die Kommunikation mittels UDP an dieser Stelle nicht. Der Server im Milquino ist oft nicht so wirklich responsive. So kommt es mir persönlich einfach viel zu häufig vor, dass Abfragen an das Gerät gehen, die einfach nicht beantwortet werden. Das führt im Home-Assistant natürlich dazu, dass oft einfach keine Werte angezeigt werden.

Hätte man diesen Datenverlust eventuell vermeiden können indem man statt UDP auf TCP setzt? Vermutlich. Ändert aber nichts daran, dass aktuell einfach Datenpakete „verloren“ gehen. UDP ist nun mal Zustandslos und der Client wird es per Protokoll nicht erfahren ob das Paket ankam oder nicht.

Eventuell könnte man sich, um diese Problematik ein wenig zu mitgieren, einen eigenen Service in Home-Assistant programmieren oder eine komplette Proxy-Komponente bauen die dann auch direkt per REST angesprochen werden könnte.

Mal sehen was die Zeit noch so hergibt. Für einen ersten Start, könnte es ja jedoch reichen. Ein „Alexa – Schalte Milquino an“ ist so zumindest mal ohne große Probleme möglich. Nachts um 3 Uhr, wenn der/die kleine Hunger hat, eine Wohltat, ohne viel Aufwand an eine frische Flasche zu kommen 😉

Home Assistant: Shelly Overheat Automation

Die kleinen, aber feinen, WLAN-Devices der Firma Allterco Robotics LTD, wir nennen sie im weiteren einfach Shelly’s, sind sehr kostengünstige und kleine Automaten um das ein oder andere in einem Haus oder einer Wohnung nachträglich ein wenig „Smarter“ zu machen.

Ich habe aktuell in Summe 6 Shelly-1PM Devices verbaut. Diese nutze ich zur Schaltung von Steckdosen als auch zum Monitoring des Stromverbrauches. Ich habe hinter den folgenden Steckdosen Shelly’s versteckt:

  • Waschmaschine
  • Trockner
  • Gefrierschrank
  • TV im Elternschlafzimmer
  • PC & Monitor im Büro
  • NAS, Drucker, PI’s und weiteren „Kleinkram“ im Büro

Für jedes dieser Geräte habe ich durch die Shelly’s die Möglichkeit, diese Stromlos zu schalten und den Verbrauch zu sehen. Ein weiteres schickes Goodie ist, dass sich die Shelly Geräte nahtlos in das Home-Assistant Energy Dashboard integrieren lassen.

Jedes Shelly-1PM-Gerät bringt eine Temperaturüberwachung mit sich. Sprich: Wenn das Gerät eine Überhitzung meldet, kann man sich in Home-Assistant einen entsprechenden Trigger dafür zu nutze machen. Und über genau das handelt dieser Beitrag. Das Ziel ist es, eine Automation zu entwickeln, die per Push-Nachricht über eine Überhitzung informiert und das entsprechende Gerät auch direkt abschaltet.

Die Automationsregel sieht im gesamten so aus:

- id: '1641376749153'
  alias: Shelly Overheat Alarm
  description: 'Wenn der Überhitzungssensor eines Shelly anschlägt (Meldeschwelle:
    30 sek) muss eine Nachricht verschickt und das entsprechende Gerät abgeschaltet
    werden'
  trigger:
  - type: problem
    platform: device
    device_id: 9fb6134cbd51000b05ab19672d330ec8
    entity_id: binary_sensor.shelly1pm_f2fe43_overheating
    domain: binary_sensor
    for:
      hours: 0
      minutes: 0
      seconds: 30
  - type: problem
    platform: device
    device_id: cb1a31d8e19a6425abf4fc08b97b27ca
    entity_id: binary_sensor.shelly1pm_f272fa_overheating
    domain: binary_sensor
    for:
      hours: 0
      minutes: 0
      seconds: 30
  - type: problem
    platform: device
    device_id: beac86fe6012511f081d8cd42283af78
    entity_id: binary_sensor.shelly1pm_f26bcb_overheating
    domain: binary_sensor
    for:
      hours: 0
      minutes: 0
      seconds: 30
  - type: problem
    platform: device
    device_id: 3d2a8d2005ff8e88551177d1ba04ed62
    entity_id: binary_sensor.shelly1pm_f2fe84_overheating
    domain: binary_sensor
    for:
      hours: 0
      minutes: 0
      seconds: 30
  - type: problem
    platform: device
    device_id: 6d44a4f9186de512cd5b9c6260c2a034
    entity_id: binary_sensor.shelly1pm_3c6105e545de_overheating
    domain: binary_sensor
    for:
      hours: 0
      minutes: 0
      seconds: 30
  - type: problem
    platform: device
    device_id: d8bcbec4f58943700d49e6eb54f22c86
    entity_id: binary_sensor.shelly1pm_e629bf_overheating
    domain: binary_sensor
    for:
      hours: 0
      minutes: 0
      seconds: 30
  condition: []
  action:
  - service: notify.all_house_members
    data_template:
      message: '{{ trigger.to_state.attributes.friendly_name }} reports high temperature:  {{
        states(trigger.entity_id | replace(''binary_sensor'', ''sensor'', 1) | replace(''_overheating'',
        ''_device_temperature'')) }}°C. Turning device off!'
      title: Shelly overheat alarm
      data:
        ttl: 0
        priority: high
  - service: switch.turn_off
    data_template:
      entity_id: '{{ trigger.entity_id | replace(''binary_sensor'', ''switch'', 1)
        | replace(''_overheating'','''') }}'
  mode: single

Was hier passiert ist folgendes:

Jedes mal wenn bei einer Shelly der Überhitzungsschutz triggert, wird mir auf mein Handy eine Nachricht ge-pushed. Diese Nachricht enthält sowohl das auslösende Gerät als auch die gemessene Temperatur des Gerätes. Als letzte Aktion wird das, an der Shelly „hängende“, Gerät zur Sicherheit abgeschaltet.

Der einzige Trick besteht hier darin, sich die Namensgebung der Shelly-Geräte zu nutze zu machen. In Home-Assistant hat jedes Gerät und jeder Sensor, also jede Entität, immer eine ID, eine Entity-ID. So hat der Binärsensor des Shelly-Gerätes das vor dem TV im Schlafzimmer hängt die Entity-ID:

binary_sensor.shelly1pm_f2fe43_overheating

Da die Trigger der Automationsregel diese Binärsensoren sind, ist es nicht so ohne weiteres Möglich an die Temperatur zu kommen. Das trigger-Objekt in einer Home-Assistant Automation ist immer das Objekt das getriggert hat. Hier eben eins aus der Klasse der Binärsensoren und diese geben keine Temperatur aus. Zum Glück hat der Entwickler der Shelly-Integration nach einem Namesschema gearbeitet:

[entity_klasse].[entity_id]_[fähigkeit]

Fähigkeit soll hier den Bezeichner darstellen der klarmacht um was für eine Entität es sich handelt. So bringt eine Shelly-1PM zwei Binärsensoren mit

  • Overheat-Sensor
  • Overpower-Sensor

Die [entity_klasse] ist jeweils binary_sensor. Die [fähigkeit] für den Overheat-Sensor ist overheating und die für den Overpower-Sensor ist overpowering.

So sehen zum Beispiel bei mir alle Entitäten des Schlafzimmer-TV-Shelly’s aus:

Die für mich interessanten Entitäten habe ich mir etwas freundlicheren Namen ausgestattet. Dieses Namensschema gilt für alle Entitäten, außer für den eigentlichen Switch. Dieser wird immer mit switch.[entitd_id] belegt.

Um beim Beispiel mit der Shelly vor dem Schlafzimmer-TV zu bleiben haben wir im trigger nun die folgende Entität zu Verfügung:

binary_sensor.shelly1pm_f2fe43_overheating

Da ich aber auch die aktuelle Temperatur haben möchte, muss ich dies über eine anderen Entität lösen. Die Temperatur steht in der Entität mit der Entity-ID:

sensor.shelly1pm_f2fe43_device_temperature

Um nun aus der Entity-ID des Binärsensors, die des Temperatursensors zu machen nutzen wir die Jinja2-Replace-Funktion:

{{ states(trigger.entity_id | replace(''binary_sensor'', ''sensor'', 1) | replace(''_overheating'', ''_device_temperature'')) }}°C

Wir ersetzen den String binary_sensor durch sensor und den String _overheating durch _device_temperature.

Das gleiche Prinzip wenden wir bei der Aktion zur Abschaltung des Gerätes an. Hier benötigen wir die Entität, die den Switch repräsentiert:

switch.shelly1pm_f2fe43

Auch hier wenden wir die Replace()-Funktion an:

{{ trigger.entity_id | replace(''binary_sensor'', ''switch'', 1) | replace(''_overheating'','''') }}

Home-Assistant: Ladestand von Batterie-Devices prüfen

Ich habe in meinem Haus recht viele batteriebetriebene Sensoren von Xiaomi verbaut:

  • Fenster- und Türsensoren
  • Luftfeuchtigkeitssensoren
  • Bewegungsmelder

Eine Problematik, die alle batteriebetriebenen Geräte gemein haben ist, irgendwann sind sie eben leer. Damit mir nun nicht die Batterie des Bewegungssensor an der Eingangstüre genau dann leer geht, wenn keiner zuhause ist und jemand einbricht, habe ich eine Automation erstellt die jede Nacht um 0 Uhr den Zustand aller batteriebetriebenen Geräte in meiner Home-Assistant Installation prüft.

Dazu pflege ich eine Gruppe eben all dieser Devices:

battery_entities:
  entities:
    - sensor.battery_xiaomi_attic
    - sensor.battery_xiaomi_bathroom
    - sensor.battery_xiaomi_bedroom
    - sensor.battery_xiaomi_hwr
    - sensor.battery_xiaomi_kitchen
    - sensor.battery_xiaomi_living
    - sensor.battery_xiaomi_maindoor
    - sensor.battery_xiaomi_office
    - sensor.battery_xiaomi_toilet
    - sensor.battery_xiaomi_fitness
    - sensor.battery_xiaomi_storage
    - sensor.battery_xiaomi_window_living_big
    - sensor.battery_xiaomi_window_living_small
    - sensor.battery_xiaomi_window_dining
    - sensor.battery_xiaomi_window_kitchen_side
    - sensor.battery_xiaomi_window_kitchen_front
    - sensor.battery_xiaomi_window_guest
    - sensor.battery_xiaomi_window_hwr
    - sensor.battery_xiaomi_window_bathroom_side
    - sensor.battery_xiaomi_window_bedroom_side
    - sensor.battery_xiaomi_window_bedroom_garden
    - sensor.battery_xiaomi_window_office_garden
    - sensor.battery_xiaomi_glasbs_living_big_right
    - sensor.battery_xiaomi_changing
    - sensor.battery_xiaomi_motion_bathroom

Zum Zugriff auf die Batterie-Informationen, benötigt es jedoch die Konfiguration eines Template-Sensors im Home-Assistant:

sensor:
  - platform: template
    sensors:
      battery_xiaomi_attic:
        friendly_name: 'Xiaomi Feuchtigkeitssensor - Spitzboden'
        value_template: "{{ states.sensor.humidity_158d0002fb487a.attributes.battery_level|default(-1)|int if states.sensor.humidity_158d0002fb487a is not none }}"
        unit_of_measurement: '%'

Ich bastel mir also für jedes Batterie-Device einen Sensor, packe den in die Gruppe und die Gruppe nutze ich wiederum zur Iteration in der Automatisierung.

Die Grundidee meiner Regel ist dabei die folgende:

Prüfe jede Nacht um 0 Uhr ob irgendein Gerät aus der Gruppe „battery_entities“, einen Ladestand von unter 10% hat. Sollte dieser der Fall sein, wird die Regel ausgeführt und ich suche mir in der „Action“ alle Geräte zusammen auf die diese „Condition“ zutrifft und packe diese in eine Mail an mich.

Die „Condition“ die ich dafür nutze sieht so aus:

condition: template
value_template: >-
  {{ states | selectattr('entity_id', 'in', state_attr('group.battery_entities', 'entity_id')) | map(attribute='state') | map('int') | select("lessthan", 10) | list }}

Die „Action“, so:

data_template:
  message: >
    The following devices reporting a low battery status: {% for item in
    expand('group.battery_entities') %}
      {%- if item.state | int < 10 %}
        {{ item.name }} ({{item.state}}%)
      {% endif %}
    {%- endfor %} Regards - Your Homie
  title: Homie - Report of battery devices with low energy
service: notify.homiemail

Alles zusammen gebracht, sieht dann so aus:

- id: CheckBatteryFromDevices
  alias: Check battery level of battery devices
  trigger:
  - platform: time
    at: 00:00:00
  condition:
  - condition: template
    value_template: '{{ states | selectattr('entity_id', 'in', state_attr('group.battery_entities', 'entity_id')) | map(attribute='state') | map('int') | select("lessthan", 10) | list }}'
  action:
  - data_template:
      title: Homie - Report of battery devices with low energy
      message: "The following devices reporting a low battery status: {% for item\
        \ in expand('group.battery_entities') %}\n  {%- if item.state | int < 10 %}\n\
        \    {{ item.name }} ({{item.state}}%)\n  {% endif %}\n{%- endfor %} Regards\
        \ - Your Homie\n"
    service: notify.homiemail

DIY: ZigBee Glasbruchsensor

Als stolzer Eigenheimbesitzer mit KNX, ich nenne es mal, Grundverkabelung (Licht, Heizung und Rollos) kamen relativ schnell, nach Fertigstellung des Bau’s, weitere „Dinge“ auf, die man gut Smart machen kann.

Ich selber, bin ein großer Fan von Home-Assistant. Hier kann man allerlei Technologien an einem Ort integrieren.

So habe ich diverse Steckdosen mit WLAN-Aktoren von Shelly versehen, oder Bewegungsmelder und Luftfeuchtigkeitssensoren von Xiaomi „verbaut“.

Für meine Partnerin ist einer der großen Vorteile eines Smart-Home, die Sicherheit die man erhöhen kann. So ist im Eingangsflur eine ONVIF-Kamera aufgestellt. Die Eingangstüre ist mit einem Bewegungssensor versehen und alle Fenster haben Öffnungssensoren. Alles ist zusammen verbunden und diverse Automations-Regeln feuern bei diversen Zuständen und alarmieren im Falle eines Einbruchs oder spielen Musik ab, schalten das Licht an oder fahren die Rollos runter.

Was mir hier jedoch noch fehlte, waren Glasbruchsensoren. Die Automatisierung erkennt, wenn wir nicht zuhause sind und jemand z.B. die Terassentüre aufmacht. Was aber nicht erkannt wird ist, wenn jemand die Scheibe einschlägt und durch die Scheibe in den Innenraum tritt.

Abhilfe schafft hier nur ein Glasbruchsensor. Da ich nichts gefunden habe was mir passt, dachte ich mir, kann man doch bestimmt auch selber bauen.

Meine Lösung, ist eine selbstgebaute Verbindung zwischen einem ABUS Glasbruchsensor passiv (GMB7300) und einem Xiaomi Aqara Fenstersensor.

Der Xiaomi Fenstersensor kommuniziert mittels ZigBee mit seiner Zentrale und diese Zentrale kann im Home-Assistant sehr einfach eingerichtet werden.

Der Sensor, im original, schaltet mittels Magnetschalter. Diesen Magnetschalter habe ich einfach mit einer Zange „abgeknipst“ und den Glasbruchsensor angelötet.

Ab jetzt schaltet der Glasbruchsensor die Kontakte und der Xiaomi Sensor meldet entsprechend weiter. Testen kann man das ganze indem man den Glasbruchsensor anbringt und mit einer Münze gegen die Scheibe „flitscht“ (einfach mal googeln).

Der ABUS Sensor hat knappe 15 EUR gekostet und der Aqara Sensor knappe 10. Somit hat man für 25 EUR einen funktionalen Glasbruchsensor der ohne große Probleme in die Home-Assistant Automatisierung eingebunden werden kann.

Disclaimer: Ich bin kein Elektriker oder Fensterbauer. Jeder ist für sein Handeln selber verantwortlich und natürlich kann diese Lösung keine Garantie auf Funktion geben, für mich selber passt es. Es muss eben nur jeder für sich selber entscheiden.