Wie aus zwei unbekannten ESP-Clients im Netz ein lokaler, cloudfreier Füllstandssensor für Home Assistant wird.
Worum geht es?
OilFox ist ein batteriebetriebener Ultraschallsensor, der einmal am Tag den Füllstand im Öltank misst und an die Hersteller-Cloud (FoxInsights) schickt.
Lange Zeit lief dieses Setup ohne Probleme bei mir über die HACS (Marketplace) Integration „HA Oilfox„
Der Ausgangspunkt
In meinen Netzwerk-Protokollierungen sind immer wieder, für kurze Zeit zwei Unbekannte ESP Geräte aufgetaucht.
Lange habe ich mir darüber keine Gedanken gemacht, da die Geräte eigentlich immer Offline waren, wenn ich danach geschaut hatte – und mit Sicherheit mit meinen vielen ESP-Basteleien zu tun gehabt haben – war zumindest meine Annahme.
Mit der Zeit stellte sich allerdings heraus, dass die Geräte doch einmal am Tag für wenige Minuten Online waren – und Überraschung – mit keinem meiner bestehenden ESP-Projekten übereinstimmten.
Eine genauere Protokollierung zeigte dann, dass das Verbindungsverhalten mit den Messdaten der Oilfox Integration zusammenhängt – die beiden Geräte waren also meine Oilfox Sensoren – jedes mal, wenn sie eine neue Messung übertragen haben.
Damit war klar, Oilfox arbeitet mit einem ESP… den könnte man doch sicherlich irgendwie „lokal“ bekommen.
Die erste Idee war der große Umbau: Gerät öffnen, Platine analysieren, eigene Firmware aufspielen. Das haben wir auch angefangen (dazu in Teil 2 mehr), aber unterwegs kam die bessere, viel einfachere Lösung.
Ein kurzer Blick in die Hardware
Beim Öffnen (das Gehäuse ist nicht verklebt, nur gesteckt) zeigt sich der Aufbau:
- AI-Thinker ESP-12 (ESP8266) – das WLAN-Modul
- Raytac MDBT40 (Nordic nRF51822) – ein Bluetooth-Controller
- PCF85063A – eine Echtzeituhr mit Alarm
- LM75A – ein Temperatursensor
- PCF8574A – ein I/O-Expander
- TPS63001 – ein Spannungswandler, der aus der CR123A stabile 3,3 V macht
- dazu der Ultraschall-Teil mit abgleichbarem Übertrager
Die spannende Erkenntnis beim Durchmessen: Der nRF ist das Gehirn, der ESP ist nur ein WLAN-Modem. Echtzeituhr, Temperatursensor und I/O-Expander hängen an einem gemeinsamen I²C-Bus, und die Weckleitung (Taster und Uhr) läuft zum nRF. Der nRF wacht auf, misst, rechnet – und schaltet den ESP nur zum Senden kurz ein.
Der entscheidende Moment: der Netzwerk-Mitschnitt
Bevor man irgendetwas am Gerät verändert, lohnt sich die einfachste Frage überhaupt: Wie genau spricht der OilFox mit seiner Cloud?
Denn wenn eine lokale Lösung für möglichst viele Personen nutzbar sein soll, dann muss diese am besten ohne komplexe Hardware-Eingriffe nutzbar sein.
Das Ziel bleibt also erst einmal, lediglich die Gerätekommunikation aus der Cloud zu lösen.
Eventuelle Anpassungen an der Hardware – und ggf. der Firmware für spätere, eigene Projekte sind dann ein separater Schritt und haben mit dem reinen, lokalen Betrieb nichts mehr zu tun.
Der naheliegende Schritt war daher, erst einmal den Netzwerkverkehr zwischen dem Oilfox Sensor und der Cloud mit zu schneiden.
Dabei sind direkt zwei Dinge ins Auge gesprungen:
- Reines HTTP auf Port 80 – kein TLS.
Der gesamte Datenverkehr findet unverschlüsselt und in Klartext statt. - Der Download pro Sitzung ist winzig (~1,15 KB) – viel zu klein für eine TLS-Zertifikatskette. Schon das war der Hinweis, dass hier nichts verschlüsselt ist.
Der Messwert-Upload im Klartext (Werte anonymisiert):
POST /v1/meter
{
"token": "00000000-0000-0000-0000-000000000000",
"hwid": "XX:XX:XX:XX:XX:XX",
"value": 142.7197,
"battery": 728,
"version": "176.OF_PROD",
"temperature": 14.25,
"serialNumber": "OF709000xxxx",
"measurements": [[-1,-1,-1,142.72, ... ,281.80], ...]
}Code-Sprache: JSON / JSON mit Kommentaren (json)
Antwort der Cloud:
{"measurementInterval":1440}Code-Sprache: JSON / JSON mit Kommentaren (json)
Damit war der Plan klar. Das Feld value ist der rohe Abstand zur Öloberfläche, temperature kommt vom LM75A, und der Server gibt nur das Messintervall (1440 Minuten = täglich) zurück. Die Umrechnung in Liter und Prozent passiert in der Cloud.
Die Lösung: die Cloud lokal ersetzen
Wenn das Gerät unverschlüsselt an einen Hostnamen sendet, dann biegt man genau diesen Hostnamen auf einen eigenen Server um. Kein Öffnen, kein Löten, kein Flashen.
Dazu braucht es nur ein paar wenige Bausteine:
1. Ein lokaler „Cloud“-Server. Ein kleiner HTTP-Server (reine Python-Standardbibliothek), der POST /v1/meter annimmt, die Messung als JSON-Lines protokolliert und mit {"measurementInterval":1440} antwortet. Die Firmware-Abfrage beantwortet er mit der gleichen Version – es wird also kein Update ausgelöst. Optional leitet er die Anfrage zusätzlich an die echte Cloud weiter, sodass App und die bestehende Integration während der Umstellung weiterlaufen.
2. Ein DNS-Rewrite. metering.prod.oilfox.io zeigt im lokalen Netz auf den eigenen Server. Beim UniFi-Gateway geht das direkt: Policy Engine → DNS → Host (A). Da der OilFox unverschlüsselt über Port 80 spricht, genügt das – kein Zertifikat, keine Tricks.
3. Eine Home-Assistant-Integration. Sie pollt den lokalen Server und legt pro Gerät Sensoren an: Abstand, Temperatur, Batterie-Rohwert, letzter Empfang und – über ein Kalibrierprofil – Füllstand in Prozent und Liter. Vom Datenmodell her angelehnt an chises/ha-oilfox, aber als local_polling gegen den eigenen Server.
Für wen es ganz ohne eigene LXC sein soll: Der Server liegt auch als Home-Assistant-Add-on bei, und die Integration lässt sich über HACS als Custom Repository einbinden.
Funktioniert es? Der direkte Vergleich
Nach dem DNS-Eintrag kam prompt die erste echte Messung beim lokalen Server an – der OilFox lieferte bei der eigenen LXC ab statt bei AWS. Der Vergleich lokal gegen Cloud für dasselbe Gerät:
| Wert | Lokal | Cloud |
| Füllmenge | 138,0 L | 138 L |
| Füllstand | 13,5 % | 14 % |
| Temperatur | 14,4 °C | — |
| Abstand | 143 cm | — |
Die Liter sind deckungsgleich, die kleine Prozentabweichung ist reine Rundung. Lokal, ohne Cloud, ohne Eingriff am Gerät – und die Werte stimmen.
Nachbauen: Installation
Der lokale Server läuft überall, wo Python oder Docker läuft.
Variante 1 – Docker
git clone https://github.com/ChristophCaina/Oilfox_local.git
cd Oilfox_local/cloud-app
docker compose up -d --buildCode-Sprache: Shell Session (shell)
Die Konfiguration steckt in docker-compose.yml (Weiterleitung an/aus, optional feste Messzeit, Zeitzone).
Variante 2 – LXC / Host via systemd
git clone https://github.com/ChristophCaina/Oilfox_local.git
cp Oilfox_local/cloud-app/deploy/oilfox-cloud.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now oilfox-cloudCode-Sprache: Shell Session (shell)
Pfade in der Unit ggf. an den Klon-Ort anpassen.
Variante 3 – Home Assistant Addon / App
Das Addon in den Einstellungen über „Repositories“ hinzufügen und die Konfiguration entsprechend anpassen.
Der DNS-Rewrite
Egal welche Variante – der entscheidende Schritt ist, metering.prod.oilfox.io auf den Server zu zeigen. Beim UniFi-Gateway: Policy Engine → DNS → Host (A), Name metering.prod.oilfox.io, IP des Servers. Mit AdGuard/Pi-hole analog unter „DNS Rewrites“.
Die Integration
In HACS als Custom Repository dieselbe URL hinzufügen (Kategorie Integration), OilFox Local installieren, Home Assistant neu starten und die Integration mit der Server-URL (http://<server>:80) einrichten. Für Prozent und Liter unter Konfigurieren die Kalibrier-Tabelle eintragen.
Zwei Stellschrauben als Bonus
Weil wir die Server-Antwort kontrollieren, lassen sich zwei Dinge rein serverseitig steuern – ohne das Gerät anzufassen:
- Messhäufigkeit (
interval/OILFOX_INTERVAL): Der Server gibt dem Gerät ein anderesmeasurementIntervalzurück. Vorsicht: öfter messen = kürzere Batterielaufzeit. - Feste Messzeit (
target_time/OILFOX_TARGET_TIME): Das Intervall ist relativ, daher driftet die Messzeit täglich. Gibt man stattdessen „Minuten bis zur nächsten Wunschuhrzeit“ zurück, verankert sich die Messung selbst auf z. B. 09:00.