From 2d35c6b7296594441f5b3787753431f69cba3160 Mon Sep 17 00:00:00 2001 From: Eduard Wisch Date: Sat, 15 Aug 2026 17:45:52 +0200 Subject: [PATCH] WLAN-Demodaten: Kanalanalyse ohne echten Empfang ansehen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Auf Eddys Vorschlag. Der Android-Emulator hat keine WLAN-Hardware und liefert bei jedem Scan null Netze — Kanalgraph, Gruppierung, Kanalempfehlung und die Warnregeln ließen sich damit auf dem Gerät überhaupt nicht ansehen. Genau deshalb ging die erste Fassung der Diagramme unbemerkt unlesbar in den Einsatz. Schalter in den Einstellungen (Diagnose → WLAN-Demodaten). Ist er an, zeigt die Kanalanalyse eine realistische Beispielumgebung statt echter Messwerte. Die Daten decken bewusst die Grenzfälle ab: Mesh über zwei Bänder, mehrere Netze auf demselben Kanal, ein 40-MHz-Netz im 2,4-GHz-Band und ein DFS- sowie ein 160-MHz-Netz im 5-GHz-Band (lösen beide Warnregeln aus), Netze in allen drei UNII-Blöcken, ein Netz am Bandrand, ein offenes Netz ohne Standard-Angabe. Leichtes Rauschen je Scan, damit mehrere Momentaufnahmen einen Zeitverlauf mit sichtbarem Auf und Ab ergeben. Damit keine Demo je für eine echte Messung gehalten wird: - deutlich sichtbarer Hinweis im Kopf der Seite, solange der Modus an ist - Messungs-Label beginnt mit "DEMODATEN — " - result-JSON trägt demodaten:true; Dolibarr zeigt das in der Kartenansicht und im PDF als eigene Zeile (PDF besonders wichtig, das Dokument geht zum Kunden) Im Emulator durchgespielt: Schalter an -> Kanalanalyse zeigt alle Diagramme mit Netzen, 5-GHz-Band in drei lesbaren UNII-Blöcken, Fazit-Zeile und alle drei Warnhinweise korrekt. Momentaufnahme gespeichert, synchronisiert und in der Test-DB geprüft: Label und result-Flag korrekt als Demo markiert. Zweitnutzen: Vorführung beim Kunden, unabhängig davon was gerade in der Luft ist. --- src/lib/wifi/demo.ts | 131 ++++++++++++++++++ src/routes/einstellungen/+page.svelte | 37 +++++ .../protokoll/[id]/wifikanal/+page.svelte | 26 ++++ 3 files changed, 194 insertions(+) create mode 100644 src/lib/wifi/demo.ts diff --git a/src/lib/wifi/demo.ts b/src/lib/wifi/demo.ts new file mode 100644 index 0000000..1e9d10d --- /dev/null +++ b/src/lib/wifi/demo.ts @@ -0,0 +1,131 @@ +/** + * WLAN-Demodaten für Vorführung und Prüfung ohne echten Empfang. + * + * Warum das nötig ist: der Android-Emulator hat keine WLAN-Hardware und + * liefert bei jedem Scan null Netze. Kanalgraph, Gruppierung, Kanalempfehlung + * und die Warnregeln ließen sich damit auf dem Gerät überhaupt nicht ansehen — + * die erste Fassung der Diagramme ging deshalb unbemerkt unlesbar in den + * Einsatz. Mit diesem Schalter zeigt die App eine realistische Kundensituation + * und die gesamte Anzeigekette lässt sich vor Ort wie im Emulator prüfen. + * + * Zweiter Nutzen: Vorführung beim Kunden ohne Abhängigkeit davon, was gerade + * in der Luft liegt. + * + * Die Daten sind bewusst so gewählt, dass sie die Grenzfälle abdecken: + * - Mesh (dieselbe SSID auf mehreren BSSIDs und Bändern) + * - mehrere Netze auf demselben Kanal (Co-Channel) + * - ein 40-MHz-Netz im 2,4-GHz-Band (löst Warnregel 1 aus) + * - ein DFS-Kanal und ein 160-MHz-Netz im 5-GHz-Band (löst Warnregel 2 aus) + * - Netze in allen drei UNII-Blöcken, damit die 5-GHz-Aufteilung sichtbar wird + * - ein Netz am Bandrand und ein offenes Netz ohne Standard-Angabe + */ + +import { Preferences } from '@capacitor/preferences'; +import type { WifiNetwork } from '../scanner'; + +const KEY = 'netdiag_wifi_demo'; + +/** BSSID des Netzes, das im Demomodus als „verbunden" gilt */ +export const DEMO_CONNECTED_BSSID = 'AA:BB:CC:10:20:01'; + +export const DEMO_NETWORKS: WifiNetwork[] = [ + // Eigenes Netz (Mesh über 2,4 + 5 GHz) + { + ssid: 'FRITZ!Box 7590 SM', bssid: DEMO_CONNECTED_BSSID, channel: 6, frequency: 2437, + rssi: -48, band: '2.4 GHz', widthMhz: 20, standard: 'Wi-Fi 5 (802.11ac)', security: 'WPA2', ageMs: 800, + }, + { + ssid: 'FRITZ!Box 7590 SM', bssid: 'AA:BB:CC:10:20:02', channel: 44, frequency: 5220, + rssi: -55, band: '5 GHz', widthMhz: 80, centerFreq0: 5210, + standard: 'Wi-Fi 6 (802.11ax)', security: 'WPA3', ageMs: 900, + }, + // Gastnetz auf demselben Kanal wie das Hauptnetz (Co-Channel) + { + ssid: 'Sandmann-Gast', bssid: 'AA:BB:CC:10:20:03', channel: 6, frequency: 2437, + rssi: -52, band: '2.4 GHz', widthMhz: 20, standard: 'Wi-Fi 5 (802.11ac)', security: 'WPA2', ageMs: 1100, + }, + // Repeater (Mesh, zweiter Standort) — 5 GHz auf DFS-Kanal (Warnregel) + { + ssid: 'Repeater-Halle', bssid: 'AA:BB:CC:10:20:04', channel: 11, frequency: 2462, + rssi: -61, band: '2.4 GHz', widthMhz: 20, standard: 'Wi-Fi 4 (802.11n)', security: 'WPA2', ageMs: 2200, + }, + { + ssid: 'Repeater-Halle', bssid: 'AA:BB:CC:10:20:05', channel: 100, frequency: 5500, + rssi: -70, band: '5 GHz', widthMhz: 80, centerFreq0: 5530, + standard: 'Wi-Fi 5 (802.11ac)', security: 'WPA2', ageMs: 2600, + }, + // Nachbar mit 40 MHz im 2,4-GHz-Band (Warnregel) + { + ssid: 'Nachbar-WLAN-1', bssid: 'DD:EE:FF:30:40:01', channel: 1, frequency: 2412, + rssi: -74, band: '2.4 GHz', widthMhz: 40, centerFreq0: 2422, + standard: 'Wi-Fi 4 (802.11n)', security: 'WPA2', ageMs: 3400, + }, + { + ssid: 'Telekom-2AB3F', bssid: 'DD:EE:FF:30:40:02', channel: 11, frequency: 2462, + rssi: -79, band: '2.4 GHz', widthMhz: 20, standard: 'Wi-Fi 4 (802.11n)', security: 'WPA2', ageMs: 4100, + }, + // Offenes Netz am oberen Bandrand, ohne Standard-Angabe + { + ssid: 'Vodafone-Hotspot', bssid: 'DD:EE:FF:30:40:03', channel: 13, frequency: 2472, + rssi: -85, band: '2.4 GHz', widthMhz: 20, security: 'offen', ageMs: 5200, + }, + // UNII-1: schwacher Nachbar + Drucker-Direktverbindung + { + ssid: 'o2-WLAN-9912', bssid: 'DD:EE:FF:30:40:04', channel: 36, frequency: 5180, + rssi: -76, band: '5 GHz', widthMhz: 20, standard: 'Wi-Fi 5 (802.11ac)', security: 'WPA2', ageMs: 3900, + }, + { + ssid: 'DIRECT-hp-OfficeJet', bssid: 'DD:EE:FF:30:40:05', channel: 48, frequency: 5240, + rssi: -81, band: '5 GHz', widthMhz: 20, standard: 'Wi-Fi 5 (802.11ac)', security: 'WPA2', ageMs: 4400, + }, + // UNII-3: Kamera + zweiter Büro-AP mit 160 MHz (Warnregel) + { + ssid: 'Kamera-Hof-5G', bssid: 'DD:EE:FF:30:40:06', channel: 149, frequency: 5745, + rssi: -72, band: '5 GHz', widthMhz: 40, centerFreq0: 5755, + standard: 'Wi-Fi 5 (802.11ac)', security: 'WPA2', ageMs: 2900, + }, + { + ssid: 'Buero-AP-2', bssid: 'DD:EE:FF:30:40:07', channel: 157, frequency: 5785, + rssi: -68, band: '5 GHz', widthMhz: 160, centerFreq0: 5775, + standard: 'Wi-Fi 6 (802.11ax)', security: 'WPA2', ageMs: 1800, + }, +]; + +/** + * Demodaten mit leichtem Rauschen — so verändert sich das Bild zwischen zwei + * Scans wie in der Wirklichkeit, und mehrere Momentaufnahmen ergeben einen + * Zeitverlauf mit sichtbarem Auf und Ab statt völlig gerader Linien. + */ +export function demoNetworks(): WifiNetwork[] { + return DEMO_NETWORKS.map((n) => ({ + ...n, + rssi: Math.max(-92, Math.min(-30, n.rssi + Math.round((Math.random() - 0.5) * 6))), + })); +} + +/* --- Schalter (überlebt den App-Neustart) --- */ + +let aktiv = false; + +export function isDemoAktiv(): boolean { + return aktiv; +} + +export async function ladeDemoSchalter(): Promise { + try { + const { value } = await Preferences.get({ key: KEY }); + aktiv = value === '1'; + } catch { + aktiv = false; + } + return aktiv; +} + +export async function setzeDemoSchalter(an: boolean): Promise { + aktiv = an; + try { + await Preferences.set({ key: KEY, value: an ? '1' : '0' }); + } catch { + /* Schalter gilt dann nur für diese Sitzung */ + } +} diff --git a/src/routes/einstellungen/+page.svelte b/src/routes/einstellungen/+page.svelte index 065b04e..f03eb2a 100644 --- a/src/routes/einstellungen/+page.svelte +++ b/src/routes/einstellungen/+page.svelte @@ -7,11 +7,28 @@ import { sync } from '$lib/sync.svelte'; import { toast } from '$lib/toast.svelte'; import { APP_VERSION, checkForUpdate, installUpdate, type UpdateInfo } from '$lib/updater'; + import { ladeDemoSchalter, setzeDemoSchalter } from '$lib/wifi/demo'; + import { onMount } from 'svelte'; let checking = $state(false); let available = $state(null); let installing = $state(false); let percent = $state(0); + let wifiDemo = $state(false); + + onMount(async () => { + wifiDemo = await ladeDemoSchalter(); + }); + + async function toggleWifiDemo(e: Event) { + const an = (e.currentTarget as HTMLInputElement).checked; + wifiDemo = an; + await setzeDemoSchalter(an); + toast.show( + an ? 'WLAN-Demodaten an — Kanalanalyse zeigt Beispieldaten' : 'WLAN-Demodaten aus', + an ? 'info' : 'success', + ); + } // Sync-Status in Klartext const syncLabel = $derived( @@ -220,6 +237,26 @@ > Debug-Log öffnen + + + + {#if demoAktiv} +

+ Demodaten aktiv — die angezeigten Netze sind erfunden, nicht gemessen. + Eine hier gespeicherte Momentaufnahme wird als Demo gekennzeichnet. Abschalten unter + Einstellungen → WLAN-Demodaten. +

+ {/if} + {#if fazit}

{fazit}

{/if}