Die Terrasse ist repariert -- und das Netz ist besser als seine Redundanz
Erster Lauf mit beiden Ping-Strecken (23:30-23:41, per Stopp-Knopf beendet). TERRASSE, die Frage des Aufbaus: 2026-08-21, ap2 tief: 43 % Verlust, laengste Luecke 20,4 s, -72 dBm 2026-08-22, ap2 auf 2,5 m: 9 % Verlust, laengste Luecke 1,0 s, -69,0 dBm Gleiches Geraet, gleiche Rolle. 1,0 s liegt unter der Hoerbarkeitsschwelle im Videocall. Der Dead Spot, der TP25 seit dem 08-20 getragen hat, ist weg. STRUKTURBEFUND: die Referenz hat in 17 von 21 Raumabschnitten 0 % Verlust -- die Alltagsabdeckung ist ueberall in Ordnung. Der Gegen-AP traegt dagegen fast nirgends: Schlafzimmer -84,6/38 %, Bad -82,3/24 %, Kueche -82,0/23 %, Terrasse -78,7/19 %. Faellt ein AP aus, ist die halbe Wohnung "verbunden, aber tot". Ein dritter AP kaufte damit REDUNDANZ, keine Abdeckung -- nach Christophs eigener Randbedingung derzeit nicht begruendet. KORREKTUR zum 22:43-Lauf: "die Kueche ist ein Loch fuer beide APs" gilt nur fuer die aeusserste Ecke. Hier hat die Referenz in der Kueche 1 % Verlust bei -71 dBm. Der Unterschied ist der Weg -- der Vorlauf ging ausdruecklich allen Waenden entlang in die totesten Winkel. Beide Aussagen gelten, sie messen verschiedene Orte. Fund E weiter abgestuft: der Sticky-Client vom 08-20 reproduzierte sich nicht (Treppe: sauberer Wechsel ap2/5G -> ap1/5G, 0 % ueber 57 s). Nicht umsetzen, bevor ein Sticky-Fall erneut gemessen ist. Ein Lauf widerlegt Fund B nicht, er zeigt nur, dass es nicht der Normalfall ist. WERKZEUG: die Auswertung wies die groesste Sonden-Luecke auf der Treppe als "⚠️ eher Ruhezustand" aus (4,6 s). Das war unser eigener Eingriff -- um 23:35:10 wechselte der Pin, das S22 war 23:35:12-16 abgemeldet. Ein Artefakt als "Geraet war erreichbar, wollte nur nicht" zu beschriften ist doppelt falsch. Pin-Wechsel werden jetzt erkannt und als solche benannt. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -136,16 +136,25 @@ def geraete(run_dir):
|
||||
("Sonde (Gegen-AP)", sonde_ping, sonde_funk)]
|
||||
|
||||
|
||||
def auswerten(ping, funk, start, stop):
|
||||
def auswerten(ping, funk, start, stop, pin_zeiten=()):
|
||||
"""Verlust, laengste Luecke, Signal und APs eines Geraets in einem Zeitfenster."""
|
||||
p = [x for x in ping if start <= x[0] < stop]
|
||||
f = [x for x in funk if start <= x[0] < stop]
|
||||
luecke, verloren = 0.0, 0
|
||||
luecke, verloren, luecke_ab = 0.0, 0, None
|
||||
for i in range(1, len(p)):
|
||||
miss = p[i][1] - p[i - 1][1] - 1
|
||||
if miss > 0:
|
||||
verloren += miss
|
||||
luecke = max(luecke, miss * 0.2)
|
||||
if miss * 0.2 > luecke:
|
||||
luecke, luecke_ab = miss * 0.2, p[i - 1][0]
|
||||
# 🔴 Die groesste Luecke der Sonde ist oft KEIN Funkbefund, sondern unser eigener
|
||||
# Eingriff: beim Umschalten des Gegen-AP wird das Geraet per Deauth geworfen und
|
||||
# braucht ein paar Sekunden zurueck. Am 2026-08-22 stand deshalb auf der Treppe
|
||||
# "4,6 s ⚠️ eher Ruhezustand" -- das Geraet war von 23:35:12 bis 23:35:16 schlicht
|
||||
# abgemeldet, weil um 23:35:10 der Pin von ap1 auf ap2 wechselte. Ein Messartefakt
|
||||
# als "Geraet war erreichbar, wollte nur nicht" zu beschriften ist doppelt falsch.
|
||||
pin_luecke = luecke_ab is not None and any(
|
||||
luecke_ab - 3 <= t <= luecke_ab + luecke + 3 for t in pin_zeiten)
|
||||
gesamt = (p[-1][1] - p[0][1] + 1) if len(p) > 1 else 0
|
||||
sig = [x[2] for x in f]
|
||||
raten = [x[3] for x in f if x[3]]
|
||||
@@ -164,6 +173,7 @@ def auswerten(ping, funk, start, stop):
|
||||
"sig": sig, "luecke": luecke, "verloren": verloren, "gesamt": gesamt,
|
||||
"ifaces": sorted({AP.get(x[1], x[1]) for x in f if x[1]}),
|
||||
"schlaefrig": schlaefrig, "verdacht": verdacht, "stumm": stumm, "gut": gut,
|
||||
"pin_luecke": pin_luecke,
|
||||
"leer": not p and not f,
|
||||
}
|
||||
|
||||
@@ -187,6 +197,9 @@ def main():
|
||||
mk = urllib.parse.unquote(m["marker"])
|
||||
if mk.upper().startswith("RAUM="):
|
||||
rooms.append((sec(m["ts_local"]), mk[5:].title()))
|
||||
pin_zeiten = [sec(m["ts_local"])
|
||||
for m in csv.DictReader(open(os.path.join(a.dir, "markers.csv")))
|
||||
if urllib.parse.unquote(m["marker"]).upper().startswith("PIN=")]
|
||||
if not rooms:
|
||||
raise SystemExit("Keine RAUM=-Marken in markers.csv — nichts zuzuordnen.")
|
||||
|
||||
@@ -204,7 +217,9 @@ def main():
|
||||
print("-" * 100)
|
||||
|
||||
for start_s, stop_s, name in fenster:
|
||||
werte = [(rolle, auswerten(ping, funk, start_s, stop_s)) for rolle, ping, funk in gs]
|
||||
werte = [(rolle, auswerten(ping, funk, start_s, stop_s,
|
||||
pin_zeiten if "Sonde" in rolle else ()))
|
||||
for rolle, ping, funk in gs]
|
||||
if all(w["leer"] for _, w in werte):
|
||||
continue
|
||||
erste = True
|
||||
@@ -214,6 +229,8 @@ def main():
|
||||
sig, luecke = w["sig"], w["luecke"]
|
||||
if w["stumm"]:
|
||||
lz = "⚠️ Display gesperrt?" if w["gut"] else "⚠️ keine Antwort"
|
||||
elif luecke and w["pin_luecke"]:
|
||||
lz = "%.1f s ⚠️ Pin-Wechsel" % luecke
|
||||
elif luecke and w["schlaefrig"]:
|
||||
lz = "%.1f s ⚠️ eher Ruhezustand" % luecke
|
||||
elif luecke and w["verdacht"]:
|
||||
@@ -237,6 +254,8 @@ def main():
|
||||
print(" erreichbar und hat nur nicht geantwortet (iOS mit gesperrtem Display).")
|
||||
print("⚠️ evtl. Ruhezustand = dasselbe Muster, aber ohne PHY-Rate zum Gegenprüfen")
|
||||
print(" (die Referenz liefert nur AP und Signal). Verdacht, kein Befund.")
|
||||
print("⚠️ Pin-Wechsel = die Lücke fällt mit dem Umschalten des Gegen-AP zusammen. Das ist")
|
||||
print(" unser eigener Eingriff (Deauth + Neuanmeldung), kein Funkbefund. Nur die Sonde.")
|
||||
print("⚠️ Display gesperrt? = Funkverbindung stand mit gutem Signal, aber KEINE einzige")
|
||||
print(" Ping-Antwort. Das ist kein Funkloch und keine Datenlücke — bei iOS beantwortet")
|
||||
print(" ein gesperrtes Display kein ICMP. Beim nächsten Lauf Display anlassen.")
|
||||
|
||||
Reference in New Issue
Block a user