#!/usr/bin/python3 # For Multithread from threading import Thread # For HTTP server from http.server import BaseHTTPRequestHandler, HTTPServer import os from urllib.parse import urlparse import socket import requests import configuration # For MQTT and plot part import time import csv2geojs import paho.mqtt.client as mqtt # Common import json from userio import * MAXLRR=4 filename="mqttGeo.csv" filenameBase="mqttGeo" server = None broker = None latestHtml = "" def htmlLatest(deveui,subID,FCnt,timeLatest,lat,lon,err,rssi): global latestHtml htmlOutput="\n" htmlOutput+=csv2geojs.networkSurveyAddLeaflet() htmlOutput+="\n" htmlOutput+="\n" htmlOutput+="

"+server['name']+" Latest

\n" htmlOutput+="
\n" if 0 != lat and 0 != lon: xmin=0.999999*lon xmax=1.000001*lon ymin=0.999999*lat ymax=1.000001*lat htmlOutput+="\n" htmlOutput+="

\n" htmlOutput+="

"+deveui+"
\n" htmlOutput+="
"+str(FCnt)+"
\n" htmlOutput+="
"+timeLatest+"
\n" htmlOutput+="
"+str(lat)+" "+str(lon)+" "+str(err)+"
\n" htmlOutput+="
"+str(rssi)+"
\n" htmlOutput+="

\n" htmlOutput+="

\n

\n

\n" htmlOutput+="

\n

\n

\n" htmlOutput+="\n" htmlOutput+="\n" latestHtml = htmlOutput # The callback for when the client receives a CONNACK response from the server. def on_connect(client, userdata, flags, rc): if 0 == rc: ok("MQTT Connected with result code "+str(rc)) client.subscribe("geoloc/#") else: error("MQTT error code "+str(rc)) # The callback for when a PUBLISH message is received from the server. def on_message(client, userdata, msg): json_data=str(msg.payload.decode('ASCII')) parseTopic=msg.topic.split('/') if "uplink" in msg.topic: csvLine="" #print("Uplink received for SubID: "+parseTopic[1]+" and DevEUI: "+parseTopic[3]) try: parsed=json.loads(json_data) pattern = '%Y-%m-%dT%H:%M:%S.%f%z' epoch = int(time.mktime(time.strptime(parsed['DevEUI_uplink']['Time'], pattern))) FCnt=parsed['DevEUI_uplink']['FCntUp'] csvLine+=parseTopic[1]+","+parseTopic[3]+","+parsed['DevEUI_uplink']['Time']+","+str(epoch)+","+str(FCnt) say("UL SubID: "+parseTopic[1]+" DevEUI: "+parseTopic[3]+" Fcnt: "+str(FCnt)) except: try: dlFPort=parsed['DevEUI_downlink_Sent']['FPort'] dlFCntDn=parsed['DevEUI_downlink_Sent']['FCntDn'] say("DL SubID: "+parseTopic[1]+" DevEUI: "+parseTopic[3]+" Fcnt: "+str(dlFCntDn)+" Fport: "+str(dlFPort)) except: with open(server['logfile'],'a+') as f: f.write("------------------------------\nMQTT Error: topic: "+msg.topic+" content: "+msg.payload.decode('ASCII')+"\n------------------------------\n") f.close() warn("Uh ho") return lat=0 lon=0 err=0 isPosition=True if parsed['DevEUI_uplink']['payload'] is not None: if parsed['DevEUI_uplink']['payload']['messageType'] == "POSITION_MESSAGE": try: lat=parsed['DevEUI_uplink']['payload']['gpsLatitude'] lon=parsed['DevEUI_uplink']['payload']['gpsLongitude'] err=parsed['DevEUI_uplink']['payload']['horizontalAccuracy'] except: warn("[WARN] GPS Timeout") return else: isPosition=False say("[WARN] Not a position message:"+parsed['DevEUI_uplink']['payload']['messageType']) return else: isPosition=False warn("[WARN] No decoded payload") with open(server['logfile'],'a+') as f: f.write("------------------------------\nMQTT Not decoded: topic: "+msg.topic+" content: "+msg.payload.decode('ASCII')+"\n------------------------------\n") f.close() return csvLine+=","+str(lat)+","+str(lon)+","+str(err) # Append GW details #parsed['DevEUI_uplink']['Lrrs']['Lrr'] #Lrrid #LrrRSSI #LrrSNR count=0 rssi=100 for lrr in parsed['DevEUI_uplink']['Lrrs']['Lrr']: count+=1 #print(lrr['Lrrid']) if rssi == 100: rssi=lrr['LrrRSSI'] csvLine+=","+lrr['Lrrid']+","+str(lrr['LrrRSSI'])+","+str(lrr['LrrSNR']) i = 0 for i in range(count,MAXLRR): csvLine+=",,," # Appending only if position is different from 0,0 if 0 != lat and 0 != lon: with open(filename,'a+') as f: f.write(csvLine+"\n") f.close() if True == isPosition: htmlLatest(parseTopic[3],parseTopic[1],FCnt,parsed['DevEUI_uplink']['Time'],lat,lon,err,rssi) def httpFromParse(obj): if ".css" not in obj.path and "favicon" not in obj.path and ".png" not in obj.path and ".js" not in obj.path: if obj.headers['X-Real-IP'] is None: say("From: "+obj.client_address[0]+" GET Received : "+obj.path) else: say("From: "+obj.headers['X-Real-IP']+" GET Received : "+obj.path) def httpSubIdList(): global server subIdList = [] with open(server['rawCsv'],'rt') as f: lines=f.readlines() for line in lines: part = line.split(',') subId=part[0] if subId not in subIdList: subIdList.append(subId) f.close() subIdList.sort() content="" content += "" return content def httpDevEuiList(subId): global server devEuiList = [] with open(server['rawCsv'],'rt') as f: lines=f.readlines() for line in lines: part = line.split(',') if subId == part[0]: if part[1] not in devEuiList: devEuiList.append(part[1]) f.close() devEuiList.sort() content="" content += "" return content class MyServer(BaseHTTPRequestHandler): def log_message(self, format, *args): # To silence the default output of server (too verbose) return def do_GET(self): global server global latestHtml rootdir = server['root'] httpFromParse(self) # Load skeletons page = [] data_page = "" data_begin = "" with open(configuration.get_pageBegin(),'r') as fStart: data_begin += fStart.read().replace( 'CSTAPPNAME', server['name'] ) fStart.close() data_end = "" with open(configuration.get_pageEnd(),'r') as fEnd: data_end += fEnd.read().replace( 'CSTAPPNAME', server['name'] ).replace( 'CSTAPPVERSION', server['version'] ) fEnd.close() if self.path == "/" or self.path == "/index.html": # Send list of SubID data_page ="

"+server['name']+" Latest

\n" data_page += httpSubIdList() data_page += "

\n

\n

\n" page.append(data_begin) page.append(data_page) page.append(data_end) content = ''.join(page) self.send_response(200) self.send_header("Content-type", "text/html") self.send_header('Server',server['name']+" v"+server['version']) self.end_headers() self.wfile.write(content.encode('utf-8')) elif self.path == "/last" or self.path == "/last/index.html": page.append(data_begin) page.append(latestHtml) page.append(data_end) content = ''.join(page) self.send_response(200) self.send_header("Content-type", "text/html") self.send_header('Server',server['name']+" v"+server['version']) self.end_headers() self.wfile.write(content.encode('utf-8')) elif "/?" in self.path: uriObject = urlparse(self.path) queries = uriObject.query.split('&') uriParams = {} data_page = "" for query in queries: element=query.split("=") uriParams[element[0]]=element[1] subId=uriParams['subId'] try: devEUI=uriParams['devEUI'] except: devEUI=None if subId is not None and devEUI is None: data_page = csv2geojs.networkSurvey(filename, subId, fileOutput=False) elif subId is not None and devEUI is not None: data_page = csv2geojs.networkSurvey(filename, subId, devEUI, fileOutput=False) data_page += httpDevEuiList(subId) data_page += "

\n

\n" data_page += "
\n

\n" page.append(data_begin) page.append(data_page) page.append(data_end) content = ''.join(page) self.send_response(200) self.send_header("Content-type", "text/html") self.send_header('Server',server['name']+" v"+server['version']) self.end_headers() self.wfile.write(content.encode('utf-8')) else: try: f = open(rootdir + self.path,'rb') #open requested file self.send_response(200) if self.path.endswith('.css'): self.send_header('Content-type','text/css') elif self.path.endswith('.bmp'): self.send_header('Content-type','image/x-ms-bmp') elif self.path.endswith('.png'): self.send_header('Content-type','image/png') elif self.path.endswith('.jpg'): self.send_header('Content-type','image/jpeg') else: self.send_header('Content-type','text/html') self.send_header('Server',server['name']+" v"+server['version']) self.end_headers() self.wfile.write(f.read()) f.close() return except IOError: self.send_header('Server',server['name']+" v"+server['version']) self.send_error(404, 'file not found') with open(server['logfile'],'a+') as f: f.write("------------------------------\nHTTP 404 "+self.path+"\n------------------------------\n") f.close() def mqttInitRun(): global broker broker = configuration.get_broker() if broker is not None: ok("MQTT configuration read successfully") # MQTT client = mqtt.Client() client.on_connect = on_connect client.on_message = on_message try: client.username_pw_set(broker['mqttUser'], password=broker['mqttPassword']) except: error("MQTT Set") try: say("MQTT connecting "+broker['mqttUser']+"@"+broker['address']+":"+str(broker['port'])) client.connect(broker['address'], broker['port'], 60) except: error("MQTT connect") client.loop_forever() def httpInitRun(): global server server = configuration.get_server() if server is not None: ok("HTTP configuration read successfully") say("HTTP "+server['name']+" v"+server['version']) webServer = HTTPServer((server['address'], server['port']), MyServer) say("HTTP started http://%s:%s" % (server['address'], server['port'])) htmlLatest(str(0),str(0),0,str(0),0,0,0,0) try: webServer.serve_forever() except KeyboardInterrupt: pass webServer.server_close() print("HTTP Server stopped.") if __name__ == "__main__": Thread(target = mqttInitRun).start() Thread(target = httpInitRun).start()