mqttGeo / csv2geojs.py /
7870b73 3 years ago
1 contributor
279 lines | 10.205kb
#!/usr/bin/python3
import time
import configuration
circleOpacity=0.2
useLeafletLocal=1
MAPBOXTOKEN="pk.eyJ1IjoieWFuaWtjYXdpZHJvbmUiLCJhIjoiY2p4dmlheGtzMDN0dTNoa2R2b2sxZndkNSJ9.Tfd-xcohTT4x7nEe5_6Rxg"

server = configuration.get_server() 

# Leaflet
# https://unpkg.com/leaflet@1.7.1/dist/leaflet.js
# https://unpkg.com/leaflet@1.7.1/dist/leaflet.css

def networkSurveyColorRSSI(rssi):
    color="#888"
    if float(rssi) < -105:
        color="#f00"
    elif float(rssi) < -95:
        color="#ff6600"
    elif float(rssi) < -85:
        color="#ffa500"
    elif float(rssi) < -80:
        color="#ffab40"
    else:
        color="#15ab00"
    return color

def networkSurveyColor(snr):
    color="#888"
    if float(snr) <= -7.5:
        #sf12
        color="#f00"
    elif float(snr) <= -5:
        #sf11
        #color="#ff6600"
        color="#a35c00"
    elif float(snr) < -2.5:
        #sf10
        #color="#ffa500"
        color="#7a8500"
    elif float(snr) < -0:
        #sf9
        #color="#ffab40"
        color="#52ad00"
    elif float(snr) < 2.5:
        #sf8
        #color="#ffab40"
        color="#29d600"
    else:
        #sf7
        color="#15ab00"
    return color

def networkSurveySetLeaflet(useLocal):
    global useLeafletLocal
    if True is useLocal:
        useLeafletLocal=1
    else:
        useLeafletLocal=0

def networkSurveyAddLeaflet():
    global useLeafletLocal
    leaflet=""
    leafletCssPath="leaflet.css"
    leafletJsPath="leaflet.js"
    if useLeafletLocal is 0:
        leafletCssPath="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
        leafletJsPath="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
    leaflet+="  <link rel=\"stylesheet\" href=\""+leafletCssPath+"\"\n"
    leaflet+="    integrity=\"sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A==\"\n"
    leaflet+="    crossorigin=\"\"/>\n"
    leaflet+="  <script src=\""+leafletJsPath+"\"\n"
    leaflet+="    integrity=\"sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA==\"\ncrossorigin=\"\"/>\n"
    leaflet+="  </script>\n"
    return leaflet

def networkSurveySetMapboxApiToken():
    global MAPBOXTOKEN
    return MAPBOXTOKEN


def networkSurvey(filename, subId, devEUI = None, fileOutput= True, latestRecords=0):
    global server
    global circleOpacity
    latest=int(latestRecords)
    start_time = time.time()
    htmlOutput="<!DOCTYPE html>\n"
    htmlOutput+="<html>\n"
    htmlOutput+="<head>\n"
    htmlOutput+="  <title>"+server['name']+"</title>\n"
    htmlOutput+="  <meta charset=\"utf-8\" />\n"
    htmlOutput+="  <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n"
    htmlOutput+="  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n"

    htmlOutput+=networkSurveyAddLeaflet()

    htmlOutput+="<style>\n"
    htmlOutput+="html {\n"
    htmlOutput+="    font-family: \"Lucida Sans\", sans-serif; text-align: center;\n"
    htmlOutput+="}\n"
    htmlOutput+="#deveui { font-size: 1.1em; }\n"
    htmlOutput+="#fcnt { font-size: 1.4em; }\n"
    htmlOutput+="#time { font-size: 1.1em; }\n"
    htmlOutput+="#position { display: inline-block; font-size: 1.1em; }\n"
    htmlOutput+="button {\n"
    htmlOutput+="  position: relative;\n"
    htmlOutput+="  width: 200px;\n"
    htmlOutput+="  height: 24px;\n"
    htmlOutput+="  margin: 8px auto;\n"
    htmlOutput+="  padding: 0;\n"
    htmlOutput+="  font-size: 16px;\n"
    htmlOutput+="  text-align: center;\n"
    htmlOutput+="  color: white;\n"
    htmlOutput+="  border: none;\n"
    htmlOutput+="  outline: none;\n"
    htmlOutput+="  cursor: pointer;\n"
    htmlOutput+="  overflow: hidden;\n"
    htmlOutput+="  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);\n"
    htmlOutput+="  transition: transform 0.4s ease-in-out;\n"
    htmlOutput+="}\n"
    htmlOutput+=".btn-green {\n"
    htmlOutput+="  background: #1abc9c;\n"
    htmlOutput+="  border-bottom: 2px solid #12ab8d;\n"
    htmlOutput+="  box-shadow: inset 0 -2px #12ab8d;\n"
    htmlOutput+="}\n"
    htmlOutput+="</style>\n"
    htmlOutput+="</head>\n"
    htmlOutput+="<body>\n"
    if fileOutput is True:
        htmlOutput += "<h2>"+filename+" - "+subId+"</h2>"
    #htmlOutput+="  <div id=\"mapid\" style=\"width: 95%; max-width: 400px; height: 400px; margin: auto\"></div>\n"
    htmlOutput+="  <div id=\"mapid\"></div>\n"
    htmlOutput+="\n"
    htmlOutput+="<script>\n"

    latMin=90
    lonMin=180
    latMax=-90
    lonMax=-180
    pointList=""
    count = 0
    countRaw = 0
    lastLine=""
    if latest == 0:
        latest = 100000
    with open(filename, "rt") as fin:
        lines=reversed(fin.readlines())
        for line in lines:
            part=line.split(',')

            radius=part[7]
            solver=0
            if part[19].replace("\n","") == "1":
                radius=10
                solver=1

            countRaw += 1
            if subId == part[0]:
                if devEUI is None:
                    if part[5] is not "0" and part[6] is not "0":
                        if lastLine is "":
                            lastLine = line
                        count += 1
                        if count > latest:
                            break
                        color=networkSurveyColor(part[10])
                        jsLine="  L.circle(["+part[5]+","+part[6]+"],{color: '"+color+"', fillcolor: '"+color+"', fillOpacity: "+str(circleOpacity)+", radius:"+str(radius)+"}).addTo(mymap); //"+part[2]+" "+part[9]+" "+part[10]+"\n"
                        if float(part[5]) > latMax:
                            latMax=float(part[5])
                        if float(part[5]) < latMin:
                            latMin=float(part[5])
                        if float(part[6]) > lonMax:
                            lonMax=float(part[6])
                        if float(part[6]) < lonMin:
                            lonMin=float(part[6])
                        pointList+=jsLine
                elif part[1] == devEUI:
                    if part[5] is not "0" and part[6] is not "0":
                        if lastLine is "":
                            lastLine = line
                        count += 1
                        if count > latest:
                            break
                        color=networkSurveyColor(part[10])
                        if solver == 0:
                            jsLine="  L.circle(["+part[5]+","+part[6]+"],{color: '"+color+"', fillcolor: '"+color+"', fillOpacity: "+str(circleOpacity)+", radius:"+str(radius)+"}).addTo(mymap); //"+part[2]+" "+part[9]+" "+part[10]+"\n"
                        else:
                            jsLine="  L.circle(["+part[5]+","+part[6]+"],{color: '"+color+"', fillcolor: '"+color+"', fillOpacity: "+str(circleOpacity)+", radius:"+str(radius)+"}).addTo(mymap); //"+part[2]+" "+part[9]+" "+part[10]+"  solved, real err:"+str(part[7])+"\n"
                        if float(part[5]) > latMax:
                            latMax=float(part[5])
                        if float(part[5]) < latMin:
                            latMin=float(part[5])
                        if float(part[6]) > lonMax:
                            lonMax=float(part[6])
                        if float(part[6]) < lonMin:
                            lonMin=float(part[6])
                        pointList+=jsLine

        fin.close()

    # Adapt Zoom to Max(DeltaLat, DeltaLon)
    latDelta=latMax-latMin
    lonDelta=lonMax-lonMin
    posDelta=latDelta
    zoomValue=13
    if lonDelta > latDelta:
        posDelta = lonDelta
    if posDelta < 0.00075:
        zoomValue=19
    elif posDelta < 0.0015:
        zoomValue=18
    elif posDelta < 0.003:
        zoomValue=17
    elif posDelta < 0.006:
        zoomValue=16
    elif posDelta < 0.012:
        zoomValue=15
    #print(str(posDelta)+" : "+str(zoomValue))


    # Adapt Radius to number of circles
    #radiusValue=5
    #if count < 50:
    #    radiusValue=1
    #elif count < 100:
    #    radiusValue=10
    #elif count < 500:
    #    radiusValue=5
    #elif count < 1000:
    #    radiusValue=2
    #elif count < 2000:
    #    radiusValue=1
    #pointList=pointList.replace("XXXX",str(radiusValue))



    #print(str(posDelta))
    latMid=(latMin+latMax)/2
    lonMid=(lonMin+lonMax)/2
    htmlOutput+="  var mymap = L.map('mapid').setView(["+str(latMid)+", "+str(lonMid)+"], "+str(zoomValue)+");\n"
    htmlOutput+="\n"
    htmlOutput+="        L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token="+networkSurveySetMapboxApiToken()+"', {\n"
    htmlOutput+="                maxZoom: 20,\n"
    htmlOutput+="                attribution: 'Map data &copy; <a href=\"https://www.openstreetmap.org/copyright\">OpenStreetMap</a> contributors, ' +\n"
    htmlOutput+="                        'Imagery © <a href=\"https://www.mapbox.com/\">Mapbox</a>',\n"
    htmlOutput+="                id: 'mapbox/streets-v11',\n"
    htmlOutput+="                tileSize: 512,\n"
    htmlOutput+="                zoomOffset: -1\n"
    htmlOutput+="        }).addTo(mymap);\n"
    htmlOutput+="\n"
    htmlOutput+= pointList
    htmlOutput+="</script>\n"

    deltaTime = float(int(100*(time.time() - start_time)))/100
    htmlOutput+="<p>Took: "+str(deltaTime)+" seconds</p>\n"

    lastOutput="<p>\n"
    if countRaw != 0:
        part=lastLine.split(',')
        try:
            lastOutput+="<div id=\"deveui\">"+part[1]+"</div>\n"
            lastOutput+="<div id=\"fcnt\">"+part[4]+"</div>\n"
            lastOutput+="<div id=\"time\">"+part[2]+"</div>\n"
            lastOutput+="<div id=\"position\">"+part[5]+" "+part[6]+" "+part[7]+"</div>\n"
        except:
            pass
    lastOutput+="<div id=\"reload\"><button class=\"btn-green\" onClick=\"window.location.reload();\">Reload</div>\n"
    lastOutput+="</p>\n"
    htmlOutput+=lastOutput

    htmlOutput+="</body>\n"
    htmlOutput+="</html>\n"

    if fileOutput is True:
        filenameSurvey="networkSurvey-"+str(subId)+".html"
        with open(filenameSurvey,"w") as f:
            f.write(htmlOutput+"\n")
            f.close()
    return htmlOutput