# Wi‑Fi Neighborhood Counters Script

**URL:** <https://community.netbeez.net/t/wi-fi-neighborhood-counters-script/302>\
**Category:** Custom Commands\
**Tags:** custom-command\
**Created:** [August 13, 2025, 10:43pm UTC](https://community.netbeez.net/t/wi-fi-neighborhood-counters-script/302 "2025-08-13T22:43:16Z")\
**Posts on this page:** 1\
**Showing post:** 1

<div class="post-metadata">

**Author:** ![panickos](https://yyz1.discourse-cdn.com/flex031/user_avatar/community.netbeez.net/panickos/32/8_2.png) [@panickos](https://community.netbeez.net/u/panickos)\
**Post date:** [August 13, 2025, 10:43pm UTC](https://community.netbeez.net/t/wi-fi-neighborhood-counters-script/302/1 "2025-08-13T22:43:17Z")

</div>

## 1. Introduction

When diagnosing Wi‑Fi congestion or planning coverage, a quick snapshot of nearby networks by band (2.4/5/6 GHz) is invaluable.  
This script scans the air and reports **visible BSSIDs total** , a breakdown per **2.4 GHz / 5 GHz / 6 GHz** , and the count of **unique channels observed**.

**Example Use Cases:**

- Detect neighborhood density before picking channels
- Track Wi‑Fi “noisiness” over time per band
- Validate 6 GHz availability/visibility on upgraded sites

* * *

## 2. Overview of the Script

This Bash script:

1. Attempts an `iw` scan with multiple fallbacks (best‑practice order):

2. Parses the scan results with portable `awk` to:

3. Emits zeroes if scanning isn’t possible (no interface/permissions/driver support)

**Environment/Overrides:**

- `IF` (default `wlan0`) – Wi‑Fi interface
- `IW` (default `/sbin/iw`) – path to `iw`
- `SUDO` (default `sudo`) – privilege escalation (can set to empty if not needed)

**Prerequisites:**

- Linux-based NetBeez agent with a Wi‑Fi NIC
- `iw` installed and permission to scan (may require `sudo`)
- Bash + `awk`; locale forced to `C` for stable parsing

**Expected Output:**

- Five key metrics in `key=value` lines:

* * *

## 3. Script Code

```bash
#!/usr/bin/env bash
# Wi‑Fi neighborhood counters (POSIX sh, BusyBox-friendly)
# Emits:
# scan_visible_bssids_total=
# scan_visible_bssids_24g=
# scan_visible_bssids_5g=
# scan_visible_bssids_6g=
# scan_visible_channels_total=

IF="${IF:-wlan0}"
IW="${IW:-/sbin/iw}"
SUDO="${SUDO:-sudo}"
export LC_ALL=C

run_scan() {
  # Try correct ordering first, then fallbacks. Return scan text or empty.
  # 1) ap-force passive (correct order)
  out="$($SUDO "$IW" dev "$IF" scan ap-force passive 2>/dev/null)"; rc=$?
  case "$rc:$out" in
    0:*Usage*) rc=1;; # usage banner means bad combo on this build
  esac
  [$rc -eq 0] && { printf '%s\n' "$out"; return; }

  # 2) passive only
  out="$($SUDO "$IW" dev "$IF" scan passive 2>/dev/null)"; rc=$?
  case "$rc:$out" in
    0:*Usage*) rc=1;;
  esac
  [$rc -eq 0] && { printf '%s\n' "$out"; return; }

  # 3) plain scan (active)
  out="$($SUDO "$IW" dev "$IF" scan 2>/dev/null)"; rc=$?
  case "$rc:$out" in
    0:*Usage*) rc=1;;
  esac
  [$rc -eq 0] && { printf '%s\n' "$out"; return; }

  # 4) give up
  printf '%s' ""
}

SCAN_OUT="$(run_scan)"

# If scan failed or returned nothing, emit zeros and exit cleanly
if [-z "$SCAN_OUT"]; then
  echo "scan_visible_bssids_total=0"
  echo "scan_visible_bssids_24g=0"
  echo "scan_visible_bssids_5g=0"
  echo "scan_visible_bssids_6g=0"
  echo "scan_visible_channels_total=0"
  exit 0
fi

# Parse with portable awk
printf '%s\n' "$SCAN_OUT" | awk '
BEGIN{
  vb=0; v24=0; v5=0; v6=0
}
function band_of_freq(f){
  if (f>=2400 && f<2500) return 24
  if (f>=5000 && f<6000) return 5
  if (f>=5925 && f<7125) return 6
  return 0
}
function ch2g_from_freq(f){
  if (f==2484) return 14
  if (f>=2412 && f<=2472) return int((f-2412)/5)+1
  return 0
}

/^BSS[[:space:]]/{
  vb++; freq_seen=0; next
}

/^[[:space:]]+freq:[[:space:]]*/{
  if (freq_seen) next
  freq_seen=1
  f=$0; gsub(/[^0-9]/,"",f); f+=0
  b=band_of_freq(f)
  if (b==24){
    v24++
    ch=ch2g_from_freq(f); if (ch>0) ch24[ch]=1
  } else if (b==5){
    v5++; ch5[f]=1 # freq key for 5 GHz
  } else if (b==6){
    v6++; ch6[f]=1 # freq key for 6 GHz
  }
  next
}

END{
  visible_channels_total=0
  for (k in ch24) visible_channels_total++
  for (k in ch5) visible_channels_total++
  for (k in ch6) visible_channels_total++

  print "scan_visible_bssids_total=" vb
  print "scan_visible_bssids_24g=" v24
  print "scan_visible_bssids_5g=" v5
  print "scan_visible_bssids_6g=" v6
  print "scan_visible_channels_total=" visible_channels_total
}
'

```

* * *

## 4. Sample Output

```plaintext
scan_visible_bssids_total=42
scan_visible_bssids_24g=18
scan_visible_bssids_5g=23
scan_visible_bssids_6g=1
scan_visible_channels_total=21

```

* * *

## 5. Closing Remarks

Use this script to baseline Wi‑Fi density and band adoption around agents, or to verify improvements after channel/Tx‑power changes.  
It’s resilient across differing `iw` builds and cleanly degrades to zeroed metrics if scanning isn’t possible.

**Extensions you could try:**

- Emit **unique channel counts per band** (e.g., `visible_channels_24g`)
- Add **RSSI/quality buckets** (e.g., `>-70 dBm`) for interference severity
- Output **JSON** for easier ingestion and historical trending
- Accept interface via `IF` env var: `IF=wlp2s0 SUDO= ./wifi_scan.sh` (skip sudo when not needed)

---

_[View the full topic](https://community.netbeez.net/t/wi-fi-neighborhood-counters-script/302)._
