{"slug": "show-hn-wisense-wifi-based-human-sensing-in-python-no-camera-required", "title": "Show HN: WiSense – WiFi-based human sensing in Python, no camera required", "summary": "WiSense v0.1.0, an open-source Python library for WiFi-based human sensing using Channel State Information (CSI), has been released on GitHub by developer collabray, enabling presence detection, fall detection, breathing-rate estimation, activity classification, and occupant counting without cameras, cloud APIs, or PyTorch/CUDA at runtime. The statistical detection paths are fully implemented and tested against synthetic CSI data, but the library has not yet been validated on real ESP32 hardware, and no trained ONNX model files ship with the repository.", "body_md": "WiFi CSI (Channel State Information) human sensing for Python -- presence, falls, breathing rate, coarse activity, and occupant count, without a camera, without a cloud API, and without PyTorch/CUDA at runtime.\n\n``` python\nfrom wisense.core import FileCSISource, CSIBuffer, calibrate\nfrom wisense.presence import PresenceDetector\n\nwith FileCSISource(\"capture.csv\", realtime=True) as source:\n    profile = calibrate(source, duration_seconds=30)  # empty-room baseline\n\nwith FileCSISource(\"capture.csv\") as source:\n    buffer = CSIBuffer(capacity=256)\n    buffer.fill_from_source(source, max_frames=64)\n\nresult = PresenceDetector().detect(buffer.snapshot(), calibration=profile)\nprint(result.present, result.confidence)\n```\n\n**v0.1.0, alpha.** The statistical (non-ML) detection path for every\nfeature module below is fully implemented, tested, and works without\nany model file. The optional ONNX inference upgrade path is fully\nimplemented against `onnxruntime.InferenceSession`\n\n, but **no trained\nmodel files ship with this repository** -- see\n[Model Files](#model-files) below.\n\n**This has been validated with unit and integration tests against\nsynthetic CSI data, but not yet against real ESP32 hardware** -- the\nmaintainer doesn't currently have a device to test with. If you try it\non real hardware, bug reports (especially anything in\n`SerialCSISource`\n\n/the ESP32-CSI-Tool line parsing, and the fixed\nthresholds in the statistical baselines) are genuinely the most useful\nthing you can contribute right now. Please open an issue with your\nboard model, firmware version, and, if possible, a short capture file\nreproducing the problem.\n\n```\npip install -e .\n```\n\nRequires Python 3.9+. Core dependencies: `numpy`\n\n, `scipy`\n\n,\n`onnxruntime`\n\n, `pyserial`\n\n. Install extras for development or\nvisualization tooling:\n\n```\npip install -e \".[dev]\"   # pytest, ruff, mypy, black\npip install -e \".[viz]\"   # matplotlib\n```\n\nSee [ examples/presence_demo.py](https://github.com/collabray/wisense/blob/main/examples/presence_demo.py) for a\ncomplete, runnable,\n\n**hardware-free** walkthrough (it replays a small synthetic capture bundled in\n\n`tests/fixtures/`\n\n). Run it with:\n\n```\npython examples/presence_demo.py\n```\n\nFor a real device, see\n[ examples/live_esp32_demo.py](https://github.com/collabray/wisense/blob/main/examples/live_esp32_demo.py), which\n\n**requires a physical ESP32** flashed with\n\n[ESP32-CSI-Tool](https://github.com/StevenMHernandez/ESP32-CSI-Tool)-compatible firmware, connected over USB serial.\n\nThe full walkthrough -- connecting, calibrating, every feature module,\nevent callbacks -- is in [ docs/usage.md](https://github.com/collabray/wisense/blob/main/docs/usage.md). API\nreference is in\n\n[.](https://github.com/collabray/wisense/blob/main/docs/api.md)\n\n`docs/api.md`\n\n| Module | What it does | Statistical baseline | ONNX upgrade path |\n|---|---|---|---|\n`wisense.presence` |\nBinary presence detection | Variance-of-amplitude thresholding against a calibration baseline | Yes |\n`wisense.fall` |\nFall event detection with severity/confidence | Sudden-amplitude-drop-then-stillness signature | Yes |\n`wisense.vitals` |\nPassive breathing-rate estimation | FFT peak detection in the 0.15-0.5 Hz respiration band | No (statistical-only; see docstring) |\n`wisense.activity` |\nCoarse activity classification | Variance + periodicity + transient-level-shift heuristics | Yes |\n`wisense.people` |\nOccupant count estimation | Multipath/frequency-diversity clustering | No (statistical-only; see docstring) |\n`wisense.core` |\nConnection, buffering, filtering, calibration, event callbacks | -- | -- |\n`wisense.models` |\nModel download/cache/checksum/load management | -- | -- |\n\nEvery detection call returns a structured `dataclass`\n\n(never a raw\nimage or unprocessed signal) -- see `docs/api.md`\n\nfor each result\ntype's fields.\n\n```\nCapture Layer (Linux host or ESP32 device)\n  SerialCSISource / NetworkCSISource / FileCSISource\n                    |\n                    v\n         wisense.core\n  CSIBuffer (ring buffer) -> calibration -> filters\n                    |\n                    v\n     Feature modules (presence / fall / vitals /\n       activity / people) -- statistical baseline,\n       or ONNX Runtime inference if a model is configured\n                    |\n                    v\n   Structured output (dataclasses) + event callbacks\n       (on_presence_change / on_fall_detected via\n        wisense.core.events.Monitor)\n```\n\n-- ESP32 running`SerialCSISource`\n\n[ESP32-CSI-Tool](https://github.com/StevenMHernandez/ESP32-CSI-Tool)-compatible firmware, over USB serial. This is the only capture target this repository has parsing code written and tested against.-- UDP or TCP, using a small newline-delimited JSON protocol WiSense defines itself (documented in the class docstring) -- there is no single industry-standard network CSI wire format, so bridging a different capture pipeline (e.g. a Linux host with a CSI-capable driver) to WiSense means emitting frames in this format.`NetworkCSISource`\n\n-- replays a recorded capture from disk in the WiSense CSV format (documented in the class docstring, and produced by`FileCSISource`\n\n`wisense.core.connection.write_capture_csv`\n\n). Works fully offline, no hardware needed -- this is what the tests and`examples/presence_demo.py`\n\nuse.\n\nWiSense ships **no pretrained .onnx model weights**. This is a\ndeliberate design decision: it keeps the pip install small, and every\nfeature module works fully without any model via its statistical\nbaseline method (see the feature table above).\n\nThe ONNX inference path (`model_path=`\n\n/ `use_registry_model=`\n\non each\ndetector/classifier) is fully implemented against\n`onnxruntime.InferenceSession`\n\n, including download/cache/checksum\nmanagement in `wisense.models.registry.ModelRegistry`\n\n. But **training\nand publishing model weights is out of scope for this repository** --\n`ModelRegistry`\n\n's default download URL\n(`DEFAULT_MODEL_BASE_URL`\n\nin `wisense/models/registry.py`\n\n) is an\nintentional, clearly-marked placeholder that will not resolve. If you\ntrain your own model:\n\n- Point\n`PresenceDetector(model_path=\"/path/to/your/model.onnx\")`\n\n(or the equivalent on`FallDetector`\n\n/`ActivityClassifier`\n\n) directly at a local file,**or** - Host your own\n`.onnx`\n\nfiles somewhere and configure`ModelRegistry(base_url=\"https://your-host/...\")`\n\n, then use`use_registry_model=\"yourmodel.onnx\"`\n\n.\n\nEach detector's module docstring documents the exact input/output\ntensor contract your model needs to conform to (e.g. presence models\nmust output `[P(absent), P(present)]`\n\n).\n\nNo accuracy numbers are claimed anywhere in this repository for the\nONNX path, because no benchmarked model exists yet to cite one for.\nThe statistical baseline's behavior is exercised by the test suite\n(see `tests/`\n\n) but has likewise not been benchmarked against a labeled\nreal-world dataset -- treat its outputs as a reasonable engineering\ndefault, not a validated accuracy claim, and calibrate\n(`wisense.core.calibrate`\n\n) for your specific environment before\nrelying on it.\n\nSee [ROADMAP.md](https://github.com/collabray/wisense/blob/main/ROADMAP.md)\nfor what's intentionally scoped out of this release and not yet\nimplemented.\n\n```\npip install -e \".[dev]\"\npytest\n```\n\nEvery module has a `logging.getLogger(\"wisense.<module>\")`\n\nlogger;\nWiSense never configures Python's root logger, so attach your own\nhandler to see output:\n\n``` python\nimport logging\nlogging.getLogger(\"wisense\").addHandler(logging.StreamHandler())\nlogging.getLogger(\"wisense\").setLevel(logging.INFO)\n```\n\nMIT -- see [LICENSE](https://github.com/collabray/wisense/blob/main/LICENSE).", "url": "https://wpnews.pro/news/show-hn-wisense-wifi-based-human-sensing-in-python-no-camera-required", "canonical_source": "https://github.com/collabray/wisense", "published_at": "2026-09-03 08:26:07+00:00", "updated_at": "2026-09-03 08:52:36.131734+00:00", "lang": "en", "topics": ["artificial-intelligence", "machine-learning", "ai-products", "ai-tools", "ai-research"], "entities": ["WiSense", "collabray", "ESP32", "ESP32-CSI-Tool", "Python", "ONNX", "onnxruntime"], "alternates": {"html": "https://wpnews.pro/news/show-hn-wisense-wifi-based-human-sensing-in-python-no-camera-required", "markdown": "https://wpnews.pro/news/show-hn-wisense-wifi-based-human-sensing-in-python-no-camera-required.md", "text": "https://wpnews.pro/news/show-hn-wisense-wifi-based-human-sensing-in-python-no-camera-required.txt", "jsonld": "https://wpnews.pro/news/show-hn-wisense-wifi-based-human-sensing-in-python-no-camera-required.jsonld"}}