Station name as "brand, street, city", grey box on all editable fields
The "grey box around the icons" report turned out not to be a defect: the box on "10.000 km"/"1 Jahr"/"15" is the wanted pattern, and every value the user can change should carry it. All .feld inputs and selects now get the grey iOS fill; inputs with their own visual language (checkbox/radio/range/file) keep the transparent base rule, so the switches are unaffected. Fuel stations are now displayed as "Shell, Pascalstr. 8, Ingolstadt" instead of the bare operator name. New _marke()/_ist_strasse()/_tankstelle() helpers are shared by both parser paths so Shell and non-Shell receipts format the same. The brand is only matched against the receipt header - searching the whole text would let "Total" hit a totals line. Missing parts are dropped instead of leaving empty comma slots, and without a known brand the operator name takes its place. station_address still carries the full street and postcode. test_bekannte_stationen updated to the new format; suite stays green. installationspaket/ is versioned from now on (user request). It contains no real vehicle data - only the example profile with empty FIN/plate placeholders. Keep it in sync whenever pyscript/ or www/ changes. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
"""Automatische Tankerkennung über den Füllstandssensor (Erweiterung zu §7.7/§5.5,
|
||||
nach dem ursprünglichen Bau nachträglich verlangt).
|
||||
|
||||
Beobachtung des Nutzers: der Füllstand (TANK_SENSOR, in Prozent) springt beim
|
||||
Fahren nie nach oben, er sinkt nur - jeder Anstieg ist also ein Tankvorgang.
|
||||
Schwelle nach Nutzervorgabe: ab +5 Liter ODER +9 Prozentpunkten Anstieg gilt
|
||||
als nachgetankt. Die 5-Liter-Vorgabe wird über fahrzeug.tankvolumen_liter aus
|
||||
dem Fahrzeugprofil in Prozentpunkte umgerechnet, damit beide Angaben auf
|
||||
derselben Einheit (Prozent) verglichen werden können; es gilt jeweils die
|
||||
empfindlichere (kleinere) der beiden Schwellen.
|
||||
|
||||
Tiefststand-Tracking statt einfachem Vorher/Nachher-Vergleich: die
|
||||
Integration liefert einen Tankvorgang oft in mehreren kleinen Schritten
|
||||
(z. B. 40% -> 45% -> 60%), von denen keiner allein die Schwelle
|
||||
überschreiten muss. Deshalb wird der zuletzt bekannte Tiefststand
|
||||
gespeichert und der Anstieg dagegen gemessen, nicht gegen den unmittelbar
|
||||
vorherigen Wert. Nach Anlage eines Tankvorgangs wird der Tiefststand auf den
|
||||
aktuellen Wert zurückgesetzt, damit derselbe Vorgang nicht mehrfach neue
|
||||
Datensätze erzeugt, wenn der Sensor währenddessen weiter ansteigt.
|
||||
|
||||
Der so angelegte Tankvorgang ist bewusst ein unvollständiger Platzhalter
|
||||
(status "unvollständig", ohne Liter/Kosten/Station) - siehe §10 Punkt 5 der
|
||||
letzten Rückmeldung: die Erwartung ist ein automatisch erkannter Tankvorgang
|
||||
mit Zeitstempel, Kilometerstand und gefahrener Distanz, den der Nutzer später
|
||||
per Beleg-Nachtrag (audi_dashboard_beleg_hochladen mit tank_id, siehe
|
||||
belegverarbeitung.py) vervollständigt.
|
||||
|
||||
EINSCHRÄNKUNG: der Tiefststand (_tiefststand_pct) lebt nur im Arbeitsspeicher
|
||||
dieses Skripts, analog zur bekannten Einschränkung in fahrterkennung.py
|
||||
(_fahrt_start_ts). Ein HA-Neustart während oder kurz vor einem Tankvorgang
|
||||
verliert den bisherigen Tiefststand - der nächste Anstieg wird dann gegen den
|
||||
ersten nach dem Neustart gemeldeten Wert gemessen. Bewusst nicht gehärtet,
|
||||
aus demselben Grund wie dort.
|
||||
|
||||
Entity-IDs stehen zentral in pyscript/modules/einstellungen.py.
|
||||
"""
|
||||
|
||||
import datetime
|
||||
|
||||
import einstellungen
|
||||
import frontend_veroeffentlichung
|
||||
import profil
|
||||
|
||||
LITER_SCHWELLE = 5
|
||||
PROZENT_SCHWELLE = 9
|
||||
STANDARD_TANKVOLUMEN_LITER = 58 # Fallback, falls im Profil nicht hinterlegt
|
||||
|
||||
_tiefststand_pct = None
|
||||
|
||||
|
||||
def _als_zahl(wert):
|
||||
try:
|
||||
return float(wert)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
|
||||
|
||||
def _schwelle_prozent():
|
||||
p = profil.profil_lesen()
|
||||
if p is None:
|
||||
tankvolumen = STANDARD_TANKVOLUMEN_LITER
|
||||
else:
|
||||
tankvolumen = p.get("fahrzeug", {}).get("tankvolumen_liter") or STANDARD_TANKVOLUMEN_LITER
|
||||
liter_als_prozent = (LITER_SCHWELLE / tankvolumen) * 100
|
||||
return min(liter_als_prozent, PROZENT_SCHWELLE)
|
||||
|
||||
|
||||
@time_trigger("startup")
|
||||
def beim_start():
|
||||
profil.ordner_sicherstellen()
|
||||
|
||||
|
||||
# Ohne konfigurierten Tankfüllstand-Sensor keinen Trigger registrieren -
|
||||
# eine leere Entity-ID als @state_trigger-Ausdruck ist ungetestetes
|
||||
# Verhalten, siehe gleiches Muster in fahrterkennung.py.
|
||||
if einstellungen.TANK_SENSOR:
|
||||
@state_trigger(f"{einstellungen.TANK_SENSOR}")
|
||||
def tankfuellstand_geaendert(value=None, old_value=None):
|
||||
global _tiefststand_pct
|
||||
|
||||
aktuell = _als_zahl(value)
|
||||
if aktuell is None:
|
||||
return
|
||||
|
||||
if _tiefststand_pct is None:
|
||||
_tiefststand_pct = aktuell
|
||||
return
|
||||
|
||||
if aktuell <= _tiefststand_pct:
|
||||
_tiefststand_pct = aktuell
|
||||
return
|
||||
|
||||
anstieg = aktuell - _tiefststand_pct
|
||||
if anstieg >= _schwelle_prozent():
|
||||
_tankvorgang_automatisch_anlegen(anstieg)
|
||||
_tiefststand_pct = aktuell
|
||||
|
||||
|
||||
def _tankvorgang_automatisch_anlegen(anstieg_pct):
|
||||
odometer_km = frontend_veroeffentlichung.zustand_oder_none(einstellungen.KM_SENSOR)
|
||||
tankvorgang = {
|
||||
"tank_id": profil.neue_id("f"),
|
||||
"receipt_key": None,
|
||||
"ts": datetime.datetime.now(datetime.timezone.utc).isoformat(),
|
||||
"liters": None,
|
||||
"fuel_total_eur": None,
|
||||
"price_per_l": None,
|
||||
"discount": None,
|
||||
"station_name": None,
|
||||
"odometer_km": odometer_km,
|
||||
"distance_km": profil.distanz_seit_letzter_tankung(odometer_km),
|
||||
"fuel_type": None,
|
||||
"source": "auto",
|
||||
"status": "unvollständig",
|
||||
"receipt_file": None,
|
||||
"edited_fields": [],
|
||||
}
|
||||
profil.tankvorgang_anhaengen(tankvorgang)
|
||||
frontend_veroeffentlichung.tankvorgaenge_veroeffentlichen()
|
||||
log.info(
|
||||
f"audi_dashboard: Tankvorgang {tankvorgang['tank_id']} automatisch erkannt "
|
||||
f"(Füllstandsanstieg {round(anstieg_pct, 1)} Prozentpunkte)"
|
||||
)
|
||||
Reference in New Issue
Block a user