Skip to main content

Terminal tool that monitors internet reachability and WiFi signal strength once per second, with a live UI, JSON logging, and matplotlib graphs.

Project description

๐Ÿ“ถ WiFi Observer

A terminal tool that tells you โ€” every second โ€” whether your problem is the internet or your WiFi.

License: MIT Python 3.8+ Platform: Linux PRs Welcome Made with: Python & Bash

WiFi Observer continuously monitors two independent things โ€” internet reachability (via ping) and WiFi signal strength (in dBm) โ€” so you can tell why your connection is bad, not just that it is. It runs entirely in your terminal, keeps a live history in memory, logs every sample to JSON, and draws a graph of the session. Built with the Python standard library + Bash; the only optional dependency is matplotlib (for graphs), installed automatically on first run.


๐Ÿ“‘ Table of contents


Why

A plain ping test lumps two different failures together. WiFi Observer separates them:

WiFi signal Internet Likely culprit
Strong & stable Down / lossy ISP / router โ€” not your WiFi
Weak / unstable Down / lossy Your WiFi โ€” distance, walls, interference
Strong & stable Fine All good โœ…

So instead of "the internet is slow," you get an answer you can act on.


Demo

โ”Œโ”€ WiFi Observer โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
 SSID: HomeNet-5G   iface: wlan0
 elapsed: 00:04:12   remaining: 00:05:48
 log โ†’ logs/2026-06-28/wifi-215205.jsonl

 INTERNET   โ— UP     target 8.8.8.8
   latency : last 23.4 ms   avg 26.1   min 18.0   max 142.0 ms
   quality : packet loss  0.8%  (2/250)   jitter 5.2 ms
   outages : 2   downtime 00:04   longest 00:03

 WIFI SIGNAL   -47 dBm (Excellent)
   stability : STABLE  (ยฑ1.8 dBm)   min -52   max -44   avg -47.3 dBm

 latency  โ–โ–‚โ–ƒโ–ˆโ–‚โ–‚โ–ƒโ–ƒโ–‚ยทโ–‚โ–ƒโ–‚โ–‚   (ยท = a probe with no reply / outage)
 signal   โ–…โ–…โ–†โ–†โ–…โ–…โ–„โ–…โ–…โ–†โ–†โ–…โ–„โ–…
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
 [g] save graph    [q] quit    (Ctrl+C also quits)

The exported graph stacks internet latency (outages marked in red) over WiFi signal strength (with quality reference lines), sharing a time axis.

๐Ÿ’ก Tip: drop a real screenshot/GIF here (e.g. docs/demo.png) before publishing.


Features

  • ๐Ÿ“ก Two metrics at once โ€” internet reachability and WiFi signal, sampled every second.
  • ๐Ÿ–ฅ๏ธ Live terminal UI โ€” single self-refreshing screen with two labelled sections and sparklines.
  • โฑ๏ธ Pick a duration on start โ€” 1 min / 10 min / 1 hr / until you close it, with a live countdown.
  • โŒจ๏ธ Interactive keys โ€” g saves a graph instantly, q quits.
  • ๐Ÿ“ JSON logging โ€” every sample appended (JSON-lines), crash-safe.
  • ๐Ÿ“Š Graphs ("maps") โ€” matplotlib charts generated from inside the app and on exit.
  • ๐Ÿ—‚๏ธ Date-organised output โ€” logs, summary, and graph grouped under logs/YYYY-MM-DD/.
  • ๐Ÿ”ง Near-zero setup โ€” monitor is stdlib-only; matplotlib is auto-installed into a local .venv.
  • ๐Ÿ›Ÿ Degrades gracefully โ€” no colours? no matplotlib? not a TTY? It still runs and tells you.

Installation

# 1. Clone
git clone https://github.com/biswanathamz/wifi-observer.git
cd wifi-observer

# 2. Run โ€” that's it.
./run.sh

There is no build step. The monitor uses only the Python 3 standard library and the system ping. The first run bootstraps a local .venv and installs matplotlib so graphs work (skip with ./run.sh --no-graph-setup).

Prefer to manage deps yourself? pip install matplotlib and run python3 wifi_observer.py directly.

Install as a command (optional)

Install it as a proper CLI so wifi-observer is on your PATH:

pip install .                 # core only (stdlib monitor)
pip install '.[graph]'        # + matplotlib, for the `g` graph feature
wifi-observer --help

Without the graph extra the monitor still runs fully; graphs are simply skipped until matplotlib is present.


Usage

./run.sh                      # ping 8.8.8.8 every 1s
./run.sh -H 1.1.1.1 -i 2      # ping Cloudflare, every 2 seconds
./run.sh -H 192.168.1.1       # ping your router (tests the LAN link only)
./run.sh --no-color           # plain text
./run.sh --help               # full option list

On start, choose how long to run:

WiFi Observer โ€” how long should it run?
   [1] 1 minute
   [2] 10 minutes
   [3] 1 hour
   [4] Until I close it
Select 1-4 (default 4):

While running, the UI is interactive:

Key Action
g Generate & save a graph (PNG) right now
q Quit and print the session summary
Ctrl+C Also quits cleanly

A graph is also saved automatically on exit, and everything lands under logs/<today>/.


Configuration

Flag Default Description
-H, --host 8.8.8.8 Host/IP to ping (an IP avoids DNS; a hostname is resolved by ping).
-i, --interval 1.0 Seconds between samples.
-t, --timeout 1.0 Per-ping timeout (s) โ†’ a slow/no reply counts as DOWN.
-n, --history 3600 Samples kept in memory for the live UI / sparklines.
--log PATH auto Custom JSON-lines log path (default logs/<date>/wifi-<time>.jsonl).
--no-log off Disable JSON logging.
--no-color off Plain text, no ANSI colours.
--no-graph-setup off (run.sh) Skip the matplotlib .venv bootstrap.

How it works

Architecture

File Language Role
run.sh Bash Checks deps, bootstraps matplotlib into .venv, launches the app.
wifi_observer.py Python Monitor loop, measurements, statistics, interactive UI, JSON logging.
wifi_observer_plot.py Python Builds the matplotlib figure; used by the app and standalone.

The per-second cycle

  1. Ping the host once โ†’ reachable? + latency.
  2. Read WiFi signal from /proc/net/wireless โ†’ dBm + link quality.
  3. Build a sample record and append it to the in-memory history and the JSON log.
  4. Update running statistics incrementally (counts, sums, sums-of-squares).
  5. Redraw the UI.
  6. Wait out the interval while polling the keyboard for g/q.

How the ping works

No hand-rolled ICMP โ€” it runs the system ping:

ping -c 1 -W <timeout> <host>

-c 1 sends one echo request; -W is the reply timeout. UP/DOWN is decided from ping's exit code (0 = reply); latency is parsed from the output (time=23.4 ms) with a regex. Because the OS ping already holds the ICMP privilege, no sudo is needed. The call is wrapped so a hang or failure can never crash the loop โ€” it just records a DOWN sample.

How the WiFi signal is read

The kernel exposes live wireless stats as text in /proc/net/wireless. The program parses the active interface's row for link quality (โ‰ˆ out of 70 โ†’ a 0โ€“100 % figure) and signal level in dBm. No external command, no privileges.

Statistics

Aggregates are maintained incrementally so each tick is O(1) no matter how long you run: uptime %, packet loss %, latency avg/min/max, jitter (latency std-dev), outage count/total/longest, and signal avg/min/max with std-dev (which drives the stability verdict).

History is a bounded deque (default last 3600 samples โ‰ˆ 1 h), so memory stays capped โ€” while the JSON log keeps the full session on disk, and graphs are built from that log.


Output & file formats

Each run writes into a date folder, all artifacts sharing one basename:

logs/
โ””โ”€โ”€ 2026-06-28/
    โ”œโ”€โ”€ wifi-215205.jsonl         # one JSON object per sample
    โ”œโ”€โ”€ wifi-215205.summary.json  # session aggregates
    โ””โ”€โ”€ wifi-215205.png           # the graph ("map")

Per-sample log line (.jsonl):

{"ts": 1782662252.80, "time": "2026-06-28T21:27:32.802", "internet_up": true,
 "latency_ms": 47.8, "signal_dbm": -63.0, "signal_quality": 67.1, "ssid": "HomeNet-5G"}

Summary (.summary.json) โ€” start/end/duration, config, plus internet and wifi_signal blocks (uptime %, packet loss, latency stats, outages, signal avg/min/max/stddev/stability).

Re-plot any old log standalone:

python3 wifi_observer_plot.py                              # newest log โ†’ <log>.png
python3 wifi_observer_plot.py logs/2026-06-28/wifi-215205.jsonl -o report.png --show

Reading the numbers

WiFi signal (dBm) โ€” higher (closer to 0) is better:

dBm Label Meaning
โ‰ฅ -50 Excellent Right next to the router
-50 to -60 Good Solid, reliable
-60 to -67 Fair Usable; HD video fine
-67 to -75 Weak Drops/slowdowns likely
< -75 Very weak Often unusable

Stability (from signal std-dev): STABLE < 3 dBm, FLUCTUATING < 6 dBm, UNSTABLE โ‰ฅ 6 dBm. Latency / jitter / packet loss โ€” lower is better; high jitter hurts calls/gaming even when average latency looks fine.


Project structure

wifi-observer/
โ”œโ”€โ”€ doc/
โ”‚   โ””โ”€โ”€ SPEC.md              # full specification
โ”œโ”€โ”€ run.sh                   # Bash launcher (+ matplotlib venv bootstrap)
โ”œโ”€โ”€ wifi_observer.py         # Python monitor, UI, logging
โ”œโ”€โ”€ wifi_observer_plot.py    # matplotlib figure builder (UI + standalone)
โ”œโ”€โ”€ LICENSE                  # MIT
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ .venv/                   # auto-created on first run        [git-ignored]
โ””โ”€โ”€ logs/                    # date folders of output           [git-ignored]

Requirements

  • Linux with python3 (3.8+) and ping on PATH. The monitor itself is standard-library only.
  • WiFi signal needs /proc/net/wireless (standard on Linux WiFi). SSID/ interface detection uses iwgetid/nmcli when present; otherwise it shows ?.
  • matplotlib โ€” only for graphs; run.sh installs it into a local .venv on first run (needs python3-venv + network once). Skip with --no-graph-setup.

Platform note: Linux-focused. The ping flags and signal reading target Linux; macOS/Windows support would need contributions (see the roadmap).


Roadmap

Ideas and good first contributions:

  • macOS / Windows support (ping flags + signal reading)
  • Optional gateway probe to pinpoint LAN-vs-WAN faults
  • DNS-resolution check (distinguish "internet down" from "DNS down")
  • Desktop notification on outage start / recovery
  • CSV export and a --summary-only headless mode
  • Configurable thresholds (signal labels, stability bands)

Found a bug or want a feature? Please open an issue.


Contributing

Contributions are welcome! ๐ŸŽ‰

  1. Fork the repo and create a branch: git checkout -b feature/my-change.
  2. Make your change. Keep the monitor standard-library only (matplotlib is fine to import lazily inside wifi_observer_plot.py). Match the existing style.
  3. Test it โ€” run ./run.sh and verify the live UI, logging, and a generated graph. For unreachable-host behaviour, try ./run.sh -H 192.0.2.1 (TEST-NET).
  4. Commit with a clear message and open a Pull Request describing what and why.

Please keep changes focused, document new flags in the README, and be kind in code review. By contributing, you agree your work is licensed under the project's MIT license.


License

Released under the MIT License โ€” free to use, modify, and distribute with attribution. ยฉ 2026 biswanathamz.

โญ If this saved you a frustrating "is it me or the internet?" moment, consider starring the repo.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

wifi_observer-0.1.0.tar.gz (26.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

wifi_observer-0.1.0-py3-none-any.whl (18.2 kB view details)

Uploaded Python 3

File details

Details for the file wifi_observer-0.1.0.tar.gz.

File metadata

  • Download URL: wifi_observer-0.1.0.tar.gz
  • Upload date:
  • Size: 26.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for wifi_observer-0.1.0.tar.gz
Algorithm Hash digest
SHA256 bff924af99ec3a6556ea62552b101fb7fcb441aea3b2dd019a8d80a0557ae4d5
MD5 ef93ce4deec5d865c82eaa9cd0d5ec50
BLAKE2b-256 05180b4a62a65ed1f67b31d5a9c6c0cce63c850346e79f998ac22df5d9653bec

See more details on using hashes here.

Provenance

The following attestation bundles were made for wifi_observer-0.1.0.tar.gz:

Publisher: release.yml on biswanathamz/wifi-observer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file wifi_observer-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: wifi_observer-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 18.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for wifi_observer-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2f2835d00701203b4de756c3f10256b5578534d7fcbfc169b521cbbcb1c48b79
MD5 fb2531b08ccfdbf2ef42bd00895e7422
BLAKE2b-256 ec8f630b3bb7f51b651e642473b65e7ecf2c359df22413f33c0e3bf6889c2fd1

See more details on using hashes here.

Provenance

The following attestation bundles were made for wifi_observer-0.1.0-py3-none-any.whl:

Publisher: release.yml on biswanathamz/wifi-observer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page