Skip to content

Commit

Permalink
Merge pull request #3 from jantman/docker
Browse files Browse the repository at this point in the history
Docker
  • Loading branch information
jantman authored Aug 9, 2020
2 parents 6d1f605 + 9895755 commit 15c97b9
Show file tree
Hide file tree
Showing 12 changed files with 369 additions and 31 deletions.
70 changes: 70 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
bin/
include/
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt
pip-selfcheck.json

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover

# Translations
*.mo
*.pot

# Django stuff:
*.log

# Sphinx documentation
docs/build/

# PyBuilder
target/

# virtualenv
bin/
include/

.idea/
result.json
*.json
/*.png
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,5 @@ result.json
/tcp_*.png
/udp_*.png
/channels*.png

pyvenv.cfg
11 changes: 10 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
Changelog
=========

0.1.0 (YYYY-MM-DD)
0.2.0 (2020-08-09)
------------------

* Package via Docker, for easier usage without worrying about dependencies.
* Optional AP name/band annotations on heatmap.
* Add CLI option to disable iwlist scans.
* Add ability to remove survey points.
* Add ability to drag (move) survey points.

0.1.0 (2018-10-30)
------------------

* Initial release
47 changes: 47 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
FROM debian:buster-20200720

ARG build_date
ARG repo_url
ARG repo_ref
USER root

RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
iperf3 \
gcc \
git \
libiw-dev \
python3 \
python3-cffi \
python3-dev \
python3-matplotlib \
python3-pip \
python3-scipy \
python3-setuptools \
python3-wheel \
python3-wxgtk4.0 \
wireless-tools && \
pip3 install \
iperf3 \
iwlib

COPY . /app

RUN cd /app && \
python3 setup.py develop && \
pip3 freeze > /app/requirements.installed

LABEL maintainer="[email protected]" \
org.label-schema.build-date="$build_date" \
org.label-schema.name="jantman/python-wifi-survey-heatmap" \
org.label-schema.url="https://github.com/jantman/python-wifi-survey-heatmap" \
org.label-schema.vcs-url="$repo_url" \
org.label-schema.vcs-ref="$repo_ref" \
org.label-schema.version="$repo_ref" \
org.label-schema.schema-version="1.0"

# For the iperf server, if using for the server side
EXPOSE 5201/tcp
EXPOSE 5201/udp

CMD /bin/bash
52 changes: 50 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ python-wifi-survey-heatmap
:alt: Project Status: WIP – Initial development is in progress, but there has not yet been a stable, usable release suitable for the public.
:target: https://www.repostatus.org/#wip

.. image:: https://img.shields.io/docker/cloud/build/jantman/python-wifi-survey-heatmap.svg
:alt: Docker Hub Build Status
:target: https://hub.docker.com/r/jantman/python-wifi-survey-heatmap

A Python application for Linux machines to perform WiFi site surveys and present
the results as a heatmap overlayed on a floorplan.

Expand All @@ -14,6 +18,8 @@ This is very rough, very alpha code. The heatmap generation code is roughly base
Installation and Dependencies
-----------------------------

**NOTE: These can all be ignored when using Docker. See below.**

* The Python `iwlib <https://pypi.org/project/iwlib/>`_ package, which needs cffi and the Linux ``wireless_tools`` package.
* The Python `iperf3 <https://pypi.org/project/iperf3/>`_ package, which needs `iperf3 <http://software.es.net/iperf/>`_ installed on your system.
* `wxPython Phoenix <https://wiki.wxpython.org/How%20to%20install%20wxPython>`_, which unfortunately must be installed using OS packages or built from source.
Expand Down Expand Up @@ -58,16 +64,25 @@ First connect to the network that you want to survey. Then, run ``sudo wifi-surv

If ``Title.json`` already exists, the data from it will be pre-loaded into the application; this can be used to resume a survey.

When the UI loads, you should see your PNG file displayed. If you click on a point on the PNG, the application should draw a yellow circle there. The status bar at the bottom of the window will show information on each test as it's performed; the full cycle typically takes a minute or a bit more. When the test is complete, the circle should turn green and the status bar will inform you that the data has been written to ``Title.json`` and it's ready for the next measurement. The output file is (re-)written after each measurement completes, so just exit the app when you're finished (or want to resume later). If ``iperf3`` encounters an error, you'll be prompted whether you want to retry or not; if you don't, whatever results iperf was able to obtain will be saved for that point.
When the UI loads, you should see your PNG file displayed. The UI is really simple:

* If you (left / primary) click on a point on the PNG, this will begin a measurement (survey point). The application should draw a yellow circle there. The status bar at the bottom of the window will show information on each test as it's performed; the full cycle typically takes a minute or a bit more. When the test is complete, the circle should turn green and the status bar will inform you that the data has been written to ``Title.json`` and it's ready for the next measurement. If ``iperf3`` encounters an error, you'll be prompted whether you want to retry or not; if you don't, whatever results iperf was able to obtain will be saved for that point.
* The output file is (re-)written after each measurement completes, so just exit the app when you're finished (or want to resume later; specifying the same Title will load the existing points and data from JSON).
* Right (secondary) clicking a point will allow you to delete it. You'll be prompted to confirm.
* Dragging (left/primary click and hold, then drag) an existing point will allow you to move it. You'll be prompted to confirm. This is handy if you accidentally click in the wrong place.

At the end of the process, you should end up with a JSON file in your current directory named after the title you provided to ``wifi-survey`` (``Title.json``) that's owned by root. Fix the permissions if you want.

**Note:** The actual survey methodology is largely up to you. In order to get accurate results, you likely want to manually handle AP associations yourself. Ideally, you lock your client to a single AP and single frequency/band for the survey.

Heatmap Generation
++++++++++++++++++

Once you've performed a survey with a given title and the results are saved in ``Title.json``, run ``wifi-heatmap PNG Title`` to generate heatmap files in the current directory. This process does not require (and shouldn't have) root/sudo and operates only on the JSON data file. For this, it will look better if you use a PNG without the measurement location marks.

The end result of this process for a given survey (Title) should be XX ``.png`` images in your current directory:
You can optionally pass the path to a JSON file mapping the access point MAC addresses (BSSIDs) to friendly names via the ``-a`` / ``--ap-names`` argument. If specified, this will annotate each measurement dot on the heatmap with the name (mapping value) and frequency band of the AP that was connected when the measurement was taken. This can be useful in multi-AP roaming environments.

The end result of this process for a given survey (Title) should be 8 ``.png`` images in your current directory:

* **channels24_TITLE.png** - Bar graph of average signal quality of APs seen on 2.4 GHz channels, by channel. Useful for visualizing channel contention. (Based on 20 MHz channel bandwidth)
* **channels5_TITLE.png** - Bar graph of average signal quality of APs seen on 5 GHz channels, by channel. Useful for visualizing channel contention. (Based on per-channel bandwidth from 20 to 160 MHz)
Expand All @@ -78,6 +93,39 @@ The end result of this process for a given survey (Title) should be XX ``.png``
* **tcp_upload_Mbps_TITLE.png** - Heatmap of iperf3 transfer rate, TCP, uploading from client to server.
* **udp_Mbps_TITLE.png** - Heatmap of iperf3 transfer rate, UDP, uploading from client to server.

Running In Docker
-----------------

Survey
++++++

.. code-block:: bash
docker run \
--net="host" \
--privileged \
--name survey \
-it \
--rm \
-v $(pwd):/pwd \
-w /pwd \
-e DISPLAY=$DISPLAY \
-v "$HOME/.Xauthority:/root/.Xauthority:ro" \
jantman/python-wifi-survey-heatmap \
wifi-survey INTERFACE SERVER FLOORPLAN.png TITLE
Note that running with ``--net="host"`` and ``--privileged`` is required in order to manipulate the host's wireless interface.

Heatmap
+++++++

``docker run -it --rm -v $(pwd):/pwd -w /pwd jantman/python-wifi-survey-heatmap:23429a4 wifi-heatmap floorplan.png DeckTest``

iperf3 server
+++++++++++++

Server: ``docker run -it --rm -p 5201:5201/tcp -p 5201:5201/udp jantman/python-wifi-survey-heatmap iperf3 -s``

Examples
--------

Expand Down
15 changes: 15 additions & 0 deletions build_docker.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/bash -ex

cd "$( dirname "${BASH_SOURCE[0]}" )"
BDATE=$(date +%Y-%m-%dT%H:%M:%S.00%Z)
REF=$(git rev-parse --short HEAD)
if ! git diff --no-ext-diff --quiet --exit-code || ! git diff-index --cached --quiet HEAD --; then
REF="${REF}-dirty"
fi

docker build \
--build-arg "build_date=${BDATE}" \
--build-arg "repo_url=$(git config remote.origin.url)" \
--build-arg "repo_ref=${REF}" \
-t jantman/python-wifi-survey-heatmap:${REF} \
.
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@
requires = [
'cffi>=1.0.0',
'iperf3==0.1.10',
'matplotlib==3.0.1',
'scipy==1.1.0'
'matplotlib==3.3.0',
'scipy==1.5.2'
]

classifiers = [
Expand Down
11 changes: 10 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[tox]
envlist = py27,py34,py35,py36,py37,docs
envlist = py27,py34,py35,py36,py37,docs,docker

[testenv]
deps =
Expand Down Expand Up @@ -58,3 +58,12 @@ commands =
sphinx-build -a -n -W -b linkcheck {toxinidir}/docs/source {toxinidir}/docs/build/html
# build
sphinx-build -a -n -W -b html {toxinidir}/docs/source {toxinidir}/docs/build/html

[testenv:docker]
passenv = TRAVIS* CONTINUOUS_INTEGRATION AWS* READTHEDOCS*
setenv =
TOXINIDIR={toxinidir}
TOXDISTDIR={distdir}
CI=true
commands =
bash build_docker.sh
10 changes: 6 additions & 4 deletions wifi_survey_heatmap/collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,15 @@

class Collector(object):

def __init__(self, interface_name, server_addr):
def __init__(self, interface_name, server_addr, scan=True):
super().__init__()
logger.debug(
'Initializing Collector for interface: %s; iperf server: %s',
interface_name, server_addr
)
self._interface_name = interface_name
self._iperf_server = server_addr
self._scan = scan

def run_iperf(self, udp=False, reverse=False):
client = iperf3.Client()
Expand Down Expand Up @@ -109,7 +110,8 @@ def run(self):
logger.debug('Getting iwconfig...')
res['config'] = get_iwconfig(self._interface_name)
logger.debug('iwconfig result: %s', res['config'])
logger.debug('Scanning...')
res['scan'] = scan(self._interface_name)
logger.debug('scan result: %s', res['scan'])
if self._scan:
logger.debug('Scanning...')
res['scan'] = scan(self._interface_name)
logger.debug('scan result: %s', res['scan'])
return res
Loading

0 comments on commit 15c97b9

Please sign in to comment.