diff --git a/.claude/skills/unifi-wifi/SKILL.md b/.claude/skills/unifi-wifi/SKILL.md index 1b924df..feb2469 100644 --- a/.claude/skills/unifi-wifi/SKILL.md +++ b/.claude/skills/unifi-wifi/SKILL.md @@ -146,8 +146,13 @@ Get explicit go before any write. Full roadmap: **references/ROADMAP.md**. — target with `--wlan`). Same gated REST path (`rest/wlanconf`), dry-run default, rollback saved: ```bash bash .../apply-wlan.sh minrate ng|na auto|off| [--wlan NAME] [--apply] # kill 1-11Mbps: minrate ng 12 -bash .../apply-wlan.sh steer on|off [--wlan NAME] [--apply] # 5GHz roaming-assistant +bash .../apply-wlan.sh bandsteer on|off [--wlan NAME] [--apply] # no2ghz_oui: steer 5GHz-capable off 2.4 +bash .../apply-wlan.sh bands both|5g|5g6e|6e|all [--wlan NAME] [--apply] # wlan_bands: force SSID onto bands +bash .../apply-wlan.sh steer on|off [--wlan NAME] [--apply] # roaming_assistant_na (sticky-client kick) +bash .../apply-wlan.sh bsstm on|off [--wlan NAME] [--apply] # bss_transition (802.11v) ``` +Band steering: modern UniFi has NO classic `bandsteering_mode`; its replacements are `no2ghz_oui` +(`bandsteer`) + `wlan_bands` (`bands` — 5g/5g6e forces clients up) + 802.11v `bss_transition` (`bsstm`). GOTCHA (handled): a manual min rate is only honored when `minrate_setting_preference=manual` — the script sets it; `minrate ... auto` hands rate management back to the controller. Write path validated 2026-06-16 on a 0-client WLAN (Green Valley Computer Club) — apply->verify->restore. diff --git a/.claude/skills/unifi-wifi/references/ROADMAP.md b/.claude/skills/unifi-wifi/references/ROADMAP.md index e31cc13..4b7e812 100644 --- a/.claude/skills/unifi-wifi/references/ROADMAP.md +++ b/.claude/skills/unifi-wifi/references/ROADMAP.md @@ -28,8 +28,10 @@ side, multi-client enablement, and non-WiFi scope. Build/validate new apply acti (coverage holes) — gate + validate per AP with watch-ap; pair with optimize-radios' disable list. - [x] **min data rates** (kill 1–11 Mbps; 2.4 floor 12/24) — DONE in `apply-wlan.sh` (`minrate ng|na auto|off|`). Requires `minrate_setting_preference=manual` (handled). Validated - on a 0-client WLAN. **band-steering / 6 GHz steer**: partial — `steer on|off` toggles the 5 GHz - `roaming_assistant`; classic prefer-5G band-steering field not yet located (per-AP-group?) — TODO. + on a 0-client WLAN. **band-steering: DONE** — modern UniFi has no `bandsteering_mode`; located its + replacements (2026-06-16) and wired all into apply-wlan: `bandsteer` (no2ghz_oui), `bands` + (wlan_bands — 5g/5g6e forces clients up), `steer` (roaming_assistant_na), `bsstm` (bss_transition, + 802.11v). Validated on a 0-client WLAN. (`fast_roaming_enabled`/802.11r left out — risky for IoT.) - [ ] **channel-plan apply** — feed `survey-collect` cleanest-channel output into a per-AP channel set. ## B. Multi-client enablement (use on any client we manage) diff --git a/.claude/skills/unifi-wifi/scripts/apply-wlan.sh b/.claude/skills/unifi-wifi/scripts/apply-wlan.sh index 17109ef..6c494be 100644 --- a/.claude/skills/unifi-wifi/scripts/apply-wlan.sh +++ b/.claude/skills/unifi-wifi/scripts/apply-wlan.sh @@ -7,9 +7,13 @@ # REST write path as apply-radio (login -> GET/modify/PUT rest/wlanconf/), rollback auto-saved. # # Actions: -# minrate off| -> minrate__enabled (+ minrate__data_rate_kbps) +# minrate auto|off| -> minrate_setting_preference + minrate__enabled/_data_rate_kbps # kill 1-11Mbps legacy basic rates: set 2.4 floor to 12 or 24. e.g. minrate ng 12 -# steer -> roaming_assistant_na_enabled (5GHz client steering / "roaming assistant") +# bandsteer -> no2ghz_oui (keep 5GHz-capable client OUIs off 2.4 = band steering) +# bands -> wlan_bands (force the SSID onto specific bands; 5g = strongest steer) +# steer -> roaming_assistant_na_enabled (5GHz sticky-client kicker) +# bsstm -> bss_transition (802.11v; assists band/AP steering + roaming) +# (modern UniFi has no classic 'bandsteering_mode' field; the above are its replacements, confirmed 2026-06-16) # # Usage: # bash .../apply-wlan.sh minrate ng 12 [--wlan "CSCNet"] [--apply] @@ -18,7 +22,7 @@ set -uo pipefail REPO="$(git rev-parse --show-toplevel 2>/dev/null || echo .)" UOS="$REPO/.claude/scripts/uos-mongo.sh"; VAULT="$REPO/.claude/scripts/vault.sh" SITEARG="${1:?usage: apply-wlan.sh ... [--wlan NAME] [--apply]}" -ACT="${2:?action: minrate|steer}"; shift 2 +ACT="${2:?action: minrate|steer|bandsteer|bands|bsstm}"; shift 2 WLAN=""; APPLY=0 # action-specific positional args case "$ACT" in @@ -30,9 +34,21 @@ case "$ACT" in elif [ "$RVAL" = off ]; then FIELDS="{\"minrate_setting_preference\":\"manual\",\"minrate_${RBAND}_enabled\":false}"; elif [[ "$RVAL" =~ ^[0-9]+$ ]]; then FIELDS="{\"minrate_setting_preference\":\"manual\",\"minrate_${RBAND}_enabled\":true,\"minrate_${RBAND}_data_rate_kbps\":$((RVAL*1000))}"; else echo "minrate value: auto|off|"; exit 1; fi ;; - steer) SVAL="${1:?steer }"; shift + steer) SVAL="${1:?steer }"; shift # 5GHz sticky-client kicker (roaming assistant) case "$SVAL" in on) FIELDS="{\"roaming_assistant_na_enabled\":true}";; off) FIELDS="{\"roaming_assistant_na_enabled\":false}";; *) echo "steer: on|off"; exit 1;; esac ;; - *) echo "action must be minrate|steer"; exit 1;; + bandsteer) SVAL="${1:?bandsteer }"; shift # keep 5GHz-capable client OUIs OFF 2.4 (the band-steering toggle) + case "$SVAL" in on) FIELDS="{\"no2ghz_oui\":true}";; off) FIELDS="{\"no2ghz_oui\":false}";; *) echo "bandsteer: on|off"; exit 1;; esac ;; + bands) SVAL="${1:?bands }"; shift # per-WLAN band membership (force SSID onto bands) + case "$SVAL" in + both) FIELDS="{\"wlan_bands\":[\"2g\",\"5g\"]}";; + 5g) FIELDS="{\"wlan_bands\":[\"5g\"]}";; + 5g6e) FIELDS="{\"wlan_bands\":[\"5g\",\"6e\"]}";; + 6e) FIELDS="{\"wlan_bands\":[\"6e\"]}";; + all) FIELDS="{\"wlan_bands\":[\"2g\",\"5g\",\"6e\"]}";; + *) echo "bands: both|5g|5g6e|6e|all"; exit 1;; esac ;; + bsstm) SVAL="${1:?bsstm }"; shift # 802.11v BSS Transition Management (assists steering/roaming) + case "$SVAL" in on) FIELDS="{\"bss_transition\":true}";; off) FIELDS="{\"bss_transition\":false}";; *) echo "bsstm: on|off"; exit 1;; esac ;; + *) echo "action must be minrate|steer|bandsteer|bands|bsstm"; exit 1;; esac while [ $# -gt 0 ]; do case "$1" in --wlan) WLAN="$2"; shift 2;; --apply) APPLY=1; shift;; *) shift;; esac; done diff --git a/clients/cascades-tucson/session-logs/2026-06/2026-06-15-howard-cascades-wifi-rf-audit.md b/clients/cascades-tucson/session-logs/2026-06/2026-06-15-howard-cascades-wifi-rf-audit.md index cb5be25..bf5a6fa 100644 --- a/clients/cascades-tucson/session-logs/2026-06/2026-06-15-howard-cascades-wifi-rf-audit.md +++ b/clients/cascades-tucson/session-logs/2026-06/2026-06-15-howard-cascades-wifi-rf-audit.md @@ -401,3 +401,26 @@ apply-radio (radio_table: power all-states/width/channel/minrssi/disable/enable apply-wlan (wlanconf: minrate/steer) now cover the WiFi apply surface, all gated + rollback + validated on 0-client sandboxes. ROADMAP updated. Coord: this msg. Remaining: classic band-steering field, per-client creds/VPN, switches/gateway collectors (C). + +--- + +## Update: 2026-06-16 00:58 PT — band-steering field FOUND + wired into apply-wlan (validated) + +Modern UniFi (Network 8.x) has NO classic 'bandsteering_mode'. Located its replacements by inspecting +wlanconf + the setting collection (no UI toggle needed this time): + no2ghz_oui -> the band-steering toggle (keep 5GHz-capable OUIs off 2.4) + wlan_bands (["2g","5g"]) -> per-WLAN band membership (set ["5g"]/["5g","6e"] to force clients up) + bss_transition -> 802.11v BSS-TM + roaming_assistant_na_* -> 5GHz sticky-client kicker + fast_roaming_enabled -> 802.11r (left out — risky for IoT/medical) + +Wired into apply-wlan.sh as actions: bandsteer (no2ghz_oui) | bands (wlan_bands) | steer +(roaming_assistant) | bsstm (bss_transition), alongside minrate. Validated on the 0-client Green Valley +WLAN: bandsteer on->verify->off, bsstm toggle, bands 5g dry-run; restored to original (bss_transition=true). + +Also surfaced setting.radio_ai (Channel AI: channels_na includes DFS, ht_modes_na=20/40, enabled=false) ++ setting.connectivity — possible future apply targets (pin the channel plan). + +WiFi APPLY SURFACE NOW COMPLETE: apply-radio (power all-states/width/channel/minrssi/disable/enable, +--zone/--ap) + apply-wlan (minrate/bandsteer/bands/steer/bsstm, --wlan), all gated + rollback + +validated on 0-client sandboxes. Coord: this msg. Remaining (ROADMAP C): switch/PoE + gateway collectors.