sync: auto-sync from HOWARD-HOME at 2026-06-16 00:24:18
Author: Howard Enos Machine: HOWARD-HOME Timestamp: 2026-06-16 00:24:18
This commit is contained in:
@@ -117,15 +117,20 @@ bash .../apply-radio.sh <site> <ng|na|6e> power low|medium|high|auto|<dBm> [-
|
||||
bash .../apply-radio.sh <site> <ng|na|6e> width 20|40|80|160 [--zone Z] [--apply]
|
||||
bash .../apply-radio.sh <site> <ng|na|6e> channel <number>|auto [--zone Z] [--apply]
|
||||
bash .../apply-radio.sh <site> <ng|na|6e> minrssi off|on|-<NN> [--zone Z] [--apply]
|
||||
bash .../apply-radio.sh <site> <ng|na|6e> disable # radio OFF (tx_power_mode=disabled) [--ap NAME] [--apply]
|
||||
bash .../apply-radio.sh <site> <ng|na|6e> enable # radio ON (tx_power_mode=auto) [--ap NAME] [--apply]
|
||||
```
|
||||
`--ap "<name>"` targets a single AP (the right scope for disables — execute optimize-radios' disable
|
||||
list one AP at a time: `optimize-radios ... ` -> for each, `apply-radio <site> ng disable --ap <name> --apply`).
|
||||
Dry-run (default) prints per-AP before->after + rollback values + the REST payload. **Writes are GATED
|
||||
OFF** until (1) `infrastructure/uos-server-network-api-rw` is vaulted (the root SSH key is the data
|
||||
plane, NOT an API write session) and (2) `--apply` is passed. Even then: rollback is auto-saved to
|
||||
`.claude/tmp/apply-rollback-*.json`, go **one `--zone` at a time**, validate live with `watch-ap.sh`
|
||||
**before and after**, and never auto channel-optimize in ultra-dense sites. WRITE PATH VALIDATED
|
||||
2026-06-16 (apply->verify->revert on 0-client 6 GHz radios). **`disable` a radio is NOT implemented**
|
||||
— there is no `radio_table` enable field; the mechanism is unconfirmed (see references/ROADMAP.md A).
|
||||
**min-data-rate / band-steering** live in `wlanconf` (not radio_table) — separate future apply path.
|
||||
2026-06-16 (apply->verify->revert + full disable/enable cycle on 0-client 6 GHz radios). **Radio
|
||||
disable IS implemented** = `tx_power_mode:"disabled"` (confirmed via UI-toggle + device-JSON diff);
|
||||
`enable` sets it back to `auto`. **min-data-rate / band-steering** live in `wlanconf` (not radio_table)
|
||||
— separate future apply path (see references/ROADMAP.md).
|
||||
Get explicit go before any write. Full roadmap: **references/ROADMAP.md**.
|
||||
|
||||
## Roadmap
|
||||
|
||||
@@ -22,10 +22,10 @@ side, multi-client enablement, and non-WiFi scope. Build/validate new apply acti
|
||||
- [x] apply-radio: width (ht 20/40/80/160)
|
||||
- [x] apply-radio: channel (manual channel assignment)
|
||||
- [x] apply-radio: min-RSSI (min_rssi_enabled + min_rssi)
|
||||
- [ ] **apply-radio: disable a radio** — NO `enabled` field in `radio_table`; the disable mechanism is
|
||||
unconfirmed (likely an AP-level/`vap` setting or a field that only appears once set). Discover by
|
||||
toggling a radio in the UI and diffing the device JSON before/after, then implement. Highest-risk
|
||||
action (coverage holes) — keep gated + per-zone + on-site validation.
|
||||
- [x] **apply-radio: disable/enable a radio** — DONE. Disable = `tx_power_mode:"disabled"` (confirmed
|
||||
2026-06-16 via UI-toggle + device-JSON diff); enable = `auto`. Validated full cycle on a 0-client
|
||||
6 GHz radio. Use `--ap <name>` to target one AP (the right scope for disables). Still highest-risk
|
||||
(coverage holes) — gate + validate per AP with watch-ap; pair with optimize-radios' disable list.
|
||||
- [ ] **min data rates** (kill 1–11 Mbps; 2.4 floor 12/24) and **band-steering / 6 GHz steer** — these
|
||||
live in **`wlanconf`** (WLAN object), NOT `radio_table`; they affect every AP on the WLAN. Separate
|
||||
apply path (`apply-wlan.sh`), more blast radius — design carefully.
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
# width 20|40|80|160 -> ht (channel width)
|
||||
# channel <number>|auto -> channel
|
||||
# minrssi off|on|-<NN> -> min_rssi_enabled (+ min_rssi if a dBm number)
|
||||
# (disable a radio is NOT here — no radio_table enable field; see references/ROADMAP.md)
|
||||
# disable -> tx_power_mode=disabled (turn the radio OFF)
|
||||
# enable -> tx_power_mode=auto (turn it back ON)
|
||||
# (radio disable == tx_power_mode "disabled"; confirmed 2026-06-16 by UI-toggle + device-JSON diff)
|
||||
# Examples:
|
||||
# apply-radio.sh cascades na width 40 # preview: 5GHz -> 40MHz everywhere
|
||||
# apply-radio.sh cascades na width 40 --zone "Floor 4" --apply
|
||||
@@ -24,10 +26,13 @@
|
||||
set -euo 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-radio.sh <site> <band> <action> <value> [--zone Z] [--apply]}"
|
||||
BAND="${2:?band ng|na|6e}"; ACT="${3:?action: power|width|channel|minrssi}"; VAL="${4:?value}"
|
||||
ZONE=""; APPLY=0; shift 4 || true
|
||||
while [ $# -gt 0 ]; do case "$1" in --zone) ZONE="$2"; shift 2;; --apply) APPLY=1; shift;; *) shift;; esac; done
|
||||
SITEARG="${1:?usage: apply-radio.sh <site> <band> <action> [value] [--zone Z] [--ap NAME] [--apply]}"
|
||||
BAND="${2:?band ng|na|6e}"; ACT="${3:?action: power|width|channel|minrssi|disable|enable}"
|
||||
shift 3
|
||||
VAL="" # disable/enable take no value; the others consume the next positional as the value
|
||||
case "$ACT" in power|width|channel|minrssi) VAL="${1:-}"; shift || true;; esac
|
||||
ZONE=""; APN=""; APPLY=0
|
||||
while [ $# -gt 0 ]; do case "$1" in --zone) ZONE="$2"; shift 2;; --ap) APN="$2"; shift 2;; --apply) APPLY=1; shift;; *) shift;; esac; done
|
||||
case "$BAND" in ng|na|6e) ;; *) echo "band must be ng|na|6e"; exit 1;; esac
|
||||
|
||||
# action+value -> the radio_table fields to set (compact JSON, used by both the preview JS and apply python)
|
||||
@@ -42,13 +47,15 @@ case "$ACT" in
|
||||
on) FIELDS="{\"min_rssi_enabled\":true}";;
|
||||
-[0-9]*) FIELDS="{\"min_rssi_enabled\":true,\"min_rssi\":$VAL}";;
|
||||
*) echo "minrssi: off|on|-<NN>"; exit 1;; esac ;;
|
||||
*) echo "action must be power|width|channel|minrssi"; exit 1;;
|
||||
disable) FIELDS="{\"tx_power_mode\":\"disabled\"}";; # turn the radio OFF (confirmed via UI diff 2026-06-16)
|
||||
enable) FIELDS="{\"tx_power_mode\":\"auto\"}";; # turn it back ON (auto power)
|
||||
*) echo "action must be power|width|channel|minrssi|disable|enable"; exit 1;;
|
||||
esac
|
||||
|
||||
if [[ "$SITEARG" =~ ^[0-9a-f]{24}$ ]]; then SITE="$SITEARG"; else
|
||||
SITE="$(bash "$UOS" --sites 2>/dev/null | grep -vi 'pq.html' | grep -i "$SITEARG" | awk '{print $1}' | head -1)"; fi
|
||||
[ -n "$SITE" ] || { echo "[ERROR] site not found"; exit 1; }
|
||||
echo "[INFO] site=$SITE band=$BAND set $FIELDS${ZONE:+ zone='$ZONE'} mode=$([ $APPLY = 1 ] && echo APPLY || echo DRY-RUN)"
|
||||
echo "[INFO] site=$SITE band=$BAND set $FIELDS${ZONE:+ zone='$ZONE'}${APN:+ ap='$APN'} mode=$([ $APPLY = 1 ] && echo APPLY || echo DRY-RUN)"
|
||||
|
||||
# ---- DRY-RUN preview: compare target fields vs current radio_table (Mongo) ----
|
||||
cat <<JS | bash "$UOS" 2>&1 | grep -viE 'pq.html|post-quantum|store now|server may need'
|
||||
@@ -57,6 +64,7 @@ function zoneOf(n){var fz=String(n||'').match(/(\d)(?:st|nd|rd|th)\s*floor/i),rm
|
||||
var n=0,skip=0;
|
||||
db.device.find({site_id:SITE,type:'uap'},{name:1,radio_table:1}).forEach(function(a){
|
||||
if('$ZONE' && zoneOf(a.name)!=='$ZONE') return;
|
||||
if('$APN' && (a.name||'')!=='$APN') return;
|
||||
(a.radio_table||[]).forEach(function(r){ if(r.radio!==BAND) return;
|
||||
var change=false,roll={};
|
||||
for(var f in FIELDS){ roll[f]=(r[f]!==undefined?r[f]:null); if(String(r[f])!==String(FIELDS[f])) change=true; }
|
||||
@@ -88,7 +96,7 @@ EOF
|
||||
exit 2
|
||||
fi
|
||||
|
||||
export AR_SITE="$SITE" AR_BAND="$BAND" AR_FIELDS="$FIELDS" AR_ZONE="$ZONE" REPO
|
||||
export AR_SITE="$SITE" AR_BAND="$BAND" AR_FIELDS="$FIELDS" AR_ZONE="$ZONE" AR_AP="$APN" REPO
|
||||
python - <<'PY'
|
||||
import os,sys,json,ssl,urllib.request,http.cookiejar
|
||||
H="172.16.3.29";PORT=11443;base=f"https://{H}:{PORT}"
|
||||
@@ -106,7 +114,7 @@ csrf=hd.get('X-CSRF-Token') or hd.get('X-Updated-Csrf-Token')
|
||||
sites=json.loads(call('GET','/proxy/network/api/self/sites')).get('data',[])
|
||||
short=next((s['name'] for s in sites if s.get('_id')==os.environ['AR_SITE']),None)
|
||||
if not short:print("[ERROR] site resolve failed");sys.exit(1)
|
||||
band=os.environ['AR_BAND'];zone=os.environ['AR_ZONE'];fields=json.loads(os.environ['AR_FIELDS'])
|
||||
band=os.environ['AR_BAND'];zone=os.environ['AR_ZONE'];apn=os.environ.get('AR_AP','');fields=json.loads(os.environ['AR_FIELDS'])
|
||||
def zof(n):
|
||||
import re;n=n or ''
|
||||
m=re.search(r'(\d)(?:st|nd|rd|th)\s*floor',n,re.I) or re.search(r'\b(\d)\d{2}\b',n)
|
||||
@@ -116,6 +124,7 @@ roll=[];done=0;fail=0
|
||||
for d in devs:
|
||||
if d.get('type')!='uap':continue
|
||||
if zone and zof(d.get('name'))!=zone:continue
|
||||
if apn and d.get('name')!=apn:continue
|
||||
rt=d.get('radio_table') or [];changed=False;old=[]
|
||||
for r in rt:
|
||||
if r.get('radio')!=band:continue
|
||||
|
||||
@@ -361,3 +361,20 @@ UI-toggle + device-JSON diff). min-data-rate/band-steering are wlanconf-level ->
|
||||
|
||||
SKILL.md apply section updated with all 4 actions + the validated-write-path note. Coord: 6aac1298.
|
||||
Next per roadmap: A (disable mechanism, wlanconf knobs, channel-plan apply) then B (per-client creds/VPN).
|
||||
|
||||
---
|
||||
|
||||
## Update: 2026-06-16 00:24 PT — radio DISABLE mechanism found; apply-radio disable/enable + --ap (validated)
|
||||
|
||||
Howard toggled 6GHz off on AP 622 in the UI; diffed the device-JSON before/after. **Disable mechanism:
|
||||
`radio_table[].tx_power_mode = "disabled"`** (radio stays in table, channel/ht untouched). Re-enable =
|
||||
`tx_power_mode "auto"`. Same field as power. (Other diffs were timestamps/cfgversion + JSON int/str noise.)
|
||||
|
||||
apply-radio.sh now supports actions: power | width | channel | minrssi | **disable | enable**, plus a
|
||||
new **--ap "<name>"** single-AP filter (correct scope for disables). Arg parsing reworked so
|
||||
disable/enable take no value. VALIDATED full enable->disable->enable cycle on 622's 0-client 6GHz via
|
||||
--apply; 622 restored to ON (auto). Workflow: optimize-radios (NEIGHBOR_JSON) disable list ->
|
||||
`apply-radio <site> <band> disable --ap <name> --apply` one AP at a time, watch-ap validated.
|
||||
|
||||
SKILL.md + ROADMAP.md updated (disable now done). apply-side now covers all radio_table knobs;
|
||||
only wlanconf-level (min-data-rate, band-steering) remains -> future apply-wlan.sh. Coord: 6aac1298-> this: msg sent.
|
||||
|
||||
Reference in New Issue
Block a user