WLAN-Reichweiten kartografisch visualisieren

Manchmal kann es vorkommen, dass man sich eine Visualisierung eines WLANs und seiner ungefähren Reichweite wünscht. Zwar gibt es bereits offene WLAN-Karten wie beispielsweise beim WiGLE-Projekt, doch werden jeweils nur die Standorte der jeweiligen WLAN-Netze, nicht aber deren Reichweite kartografiert.

Um diesem Problem zu entgegnen kann man sich der Daten bedienen, die Kismet bzw. GISKismet ohnehin aufzeichnen und zur Verfügung stellen.

Nils hatte vor einiger Zeit einen Patch für GISKismet geschrieben. Dieser hat GISKismet dahingehend erweitert, dass beim Exportieren in eine KML-Datei anhand der GPS-Koordinaten für das stärkste und schwächste WLAN-Signal ein Kreis berechnet und in der KML-Datei entsprechend dargestellt wird.

Leider wurde dieser Patch nicht in das offizielle GISKismet-Projekt übernommen. Da ich ungerne Programme editiere, welche vom Paketmanager aktuell gehalten werden sollen, habe ich mir diese Funktion in einer einfachen Variante nachgebaut. Die Darstellung ist selbstverständlich nur eine theoretische und vereinfachte Abbildung der WLAN-Reichweite anhand des stärksten und schwächsten gemessenen Signals.

Das folgende Skript verwendet die beiden genannten Koordinaten des aufgezeichneten WLAN-Signals und berechnet anhand dieser Daten einen Kreis, welcher die Reichweite eines WLANs ansatzweise darstellt:

#!/usr/bin/env python

# This is script is meant to write a KML file to stdout that
# shows the estimated coverage of a wifi.
# The GPS coordinates can be gathered from giskismet.
# Copy pasted the math part from
# https://gist.github.com/rochacbruno/2883505
# http://stackoverflow.com/questions/15886846/python-elegant-way-of-finding-the-gps-coodinates-of-a-circle-around-a-certain-g


import math, sys

R = 6371
N = 32

try:
        GPSBestLon = float(sys.argv[1])
        GPSBestLat = float(sys.argv[2])
        GPSMinLon = float(sys.argv[3])
        GPSMinLat = float(sys.argv[4])
except:
        print "Usage: %s GPSBestLon GPSBestLat GPSMinLon GPSMinLat" %(sys.argv[0])
        sys.exit(1)

def get_radius():
        # Get the radius of the circle
        dlat = math.radians(GPSBestLat-GPSMinLat)
        dlon = math.radians(GPSBestLon-GPSMinLon)
        a = math.sin(dlat/2) * math.sin(dlat/2) + math.cos(math.radians(GPSMinLat)) * math.cos(math.radians(GPSBestLat)) * math.sin(dlon/2) * math.sin(dlon/2)
        c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
        radius = R * c
        return radius

def calculate_circlepoints(radius):
        circlepoints = []
        for k in xrange(N):
                angle = math.pi*2*k/N
                dx = radius*math.cos(angle)
                dy = radius*math.sin(angle)
                point = {}
                point['lat'] = GPSBestLat + (180/math.pi)*(dy/R)
                point['lon'] = GPSBestLon + (180/math.pi)*(dx/R)/math.cos(GPSBestLat*math.pi/180)
                circlepoints.append(point)
        return circlepoints

def create_output(circlepoints):
        print """<?xml version=\"1.0\" encoding=\"UTF-8\"?>
        <kml xmlns=\"http://www.opengis.net/kml/2.2\">
        <Document>
        <Style id="transBluePoly">
        <LineStyle>
        <width>1.5</width>
        </LineStyle>
        <PolyStyle>
        <color>7dff0000</color>
        </PolyStyle>
        </Style>
        <Placemark>
        <name>Estimated Wifi coverage</name>
        <styleUrl>#transBluePoly</styleUrl>
        <Polygon>
        <visibility>1</visibility>
        <altitudeMode>relativeToGround</altitudeMode>
        <tessellate>1</tessellate>
        <outerBoundaryIs>
        <LinearRing>
        <extrude>1</extrude>
        <coordinates>"""

        for point in circlepoints:
                print "\t%s,%s" %(point['lon'],point['lat'])
        # and print the first one again to have a full circle:
        print "\t%s,%s" %(circlepoints[0]['lon'],circlepoints[0]['lat'])

        print """
        </coordinates>
        </LinearRing>
        </outerBoundaryIs>
        </Polygon>
        </Placemark>
        </Document>
        </kml>"""
        

radius = get_radius()
circlepoints = calculate_circlepoints(radius)
create_output(circlepoints)

GISKismet und dieses Skript lassen sich nun gut kombinieren, um zwei einzelne KML-Dateien zu erstellen, die sich in diversen Programmen wie Google Earth oder Marble öffnen lassen:

ESSID="myessid"
mkdir -p ${ESSID}
giskismet -q "select * from wireless where ESSID=='${ESSID}'" -o ${ESSID}/giskismet.kml
./wifi_coverage.py $(sqlite3 wireless.dbl "select GPSBestLon,GPSBestLat,GPSMinLon,GPSMinLat from wireless where ESSID=\"${ESSID}\" " | sed 's/|/ /g') > ${ESSID}/coverage.kml

In diesem Beispiel sieht man nun als Ergebnis ein Demo-WLAN auf Schloss Benrath mit fiktiven Daten:

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.