Showing 1 changed files with 130 additions and 25 deletions
+130 -25
mqttGeo.py
... ...
@@ -17,19 +17,20 @@ import csv2geojs
17 17
 import paho.mqtt.client as mqtt
18 18
 
19 19
 # Common
20
+import re
20 21
 import json
21 22
 from userio import *
22 23
 
23 24
 MAXLRR=4
24
-filename="mqttGeo.csv"
25
-filenameBase="mqttGeo"
26 25
 
27 26
 server = None
28 27
 broker = None
29 28
 latestHtml = ""
29
+previousLastFcnt = 0
30 30
 
31 31
 def htmlLatest(deveui,subID,FCnt,timeLatest,lat,lon,err,rssi):
32 32
     global latestHtml 
33
+    global previousLastFcnt
33 34
     htmlOutput="<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n"
34 35
 
35 36
     htmlOutput+=csv2geojs.networkSurveyAddLeaflet()
... ...
@@ -41,6 +42,8 @@ def htmlLatest(deveui,subID,FCnt,timeLatest,lat,lon,err,rssi):
41 42
     htmlOutput+="</script>\n"
42 43
     htmlOutput+="<body>\n"
43 44
     htmlOutput+="<h2>"+server['name']+" Latest</h2>\n"
45
+    htmlOutput+="<p>\n<div id=\"home\"><button class=\"btn-green-menu\" onClick=\"window.location.href='.';\">Home</div>\n"
46
+    htmlOutput+="<div id=\"log\"><button class=\"btn-green-menu\" onClick=\"window.location.href='./log';\">Log</div>\n"
44 47
     htmlOutput+="  <div id=\"mapid\" style=\"width: 95%; max-width: 400px; height: 200px; margin: auto\"></div>\n"
45 48
 
46 49
     if 0 != lat and 0 != lon:
... ...
@@ -72,11 +75,12 @@ def htmlLatest(deveui,subID,FCnt,timeLatest,lat,lon,err,rssi):
72 75
     htmlOutput+="<div id=\"deveui\">"+deveui+"</div>\n"
73 76
     htmlOutput+="<div id=\"fcnt\">"+str(FCnt)+"</div>\n"
74 77
     htmlOutput+="<div id=\"time\">"+timeLatest+"</div>\n"
75
-    htmlOutput+="<div id=\"position\">"+str(lat)+" "+str(lon)+" "+str(err)+"</div>\n"
76
-    htmlOutput+="<div id=\"rssi\">"+str(rssi)+"</div>\n"
78
+    htmlOutput+="<div id=\"position\">"+str(lat)+"&#xb0; "+str(lon)+"&#xb0; "+str(err)+"m</div>\n"
79
+    htmlOutput+="<div id=\"rssi\">"+str(rssi)+"dB</div>\n"
80
+    htmlOutput+="<div id=\"delta\">&#x394;: "+str(FCnt-previousLastFcnt)+"</div>\n"
81
+    previousLastFcnt = FCnt
77 82
     htmlOutput+="</p>\n"
78 83
     htmlOutput+="<p>\n<div id=\"reload\"><button class=\"btn-green\" onClick=\"window.location.reload();\">Reload</div>\n</p>\n"
79
-    htmlOutput+="<p>\n<div id=\"home\"><button class=\"btn-green-menu\" onClick=\"window.location.href='.';\">Home</div>\n</p>\n"
80 84
 
81 85
     htmlOutput+="</body>\n"
82 86
     htmlOutput+="</html>\n"
... ...
@@ -103,18 +107,23 @@ def on_message(client, userdata, msg):
103 107
             epoch = int(time.mktime(time.strptime(parsed['DevEUI_uplink']['Time'], pattern)))
104 108
             FCnt=parsed['DevEUI_uplink']['FCntUp']
105 109
             csvLine+=parseTopic[1]+","+parseTopic[3]+","+parsed['DevEUI_uplink']['Time']+","+str(epoch)+","+str(FCnt)
106
-            say("UL SubID: "+parseTopic[1]+" DevEUI: "+parseTopic[3]+" Fcnt: "+str(FCnt))
107 110
         except:
108 111
             try:
109 112
                 dlFPort=parsed['DevEUI_downlink_Sent']['FPort']
110 113
                 dlFCntDn=parsed['DevEUI_downlink_Sent']['FCntDn']
111
-                say("DL SubID: "+parseTopic[1]+" DevEUI: "+parseTopic[3]+" Fcnt: "+str(dlFCntDn)+" Fport: "+str(dlFPort))
114
+                say("DL ID: "+parseTopic[1]+" DevEUI: "+parseTopic[3]+" F: "+str(dlFCntDn)+" Fport: "+str(dlFPort))
112 115
             except:
113 116
                 with open(server['logfile'],'a+') as f:
114 117
                     f.write("------------------------------\nMQTT Error: topic: "+msg.topic+" content: "+msg.payload.decode('ASCII')+"\n------------------------------\n")
115 118
                     f.close()
116 119
                 warn("Uh ho")
117 120
             return
121
+        messageType = "UNKNOWN"
122
+        try:
123
+            messageType = parsed['DevEUI_uplink']['payload']['messageType']
124
+        except:
125
+            pass
126
+
118 127
 
119 128
         lat=0
120 129
         lon=0
... ...
@@ -127,23 +136,24 @@ def on_message(client, userdata, msg):
127 136
                     lon=parsed['DevEUI_uplink']['payload']['gpsLongitude']
128 137
                     err=parsed['DevEUI_uplink']['payload']['horizontalAccuracy']
129 138
                 except:
130
-                    warn("[WARN] GPS Timeout")
139
+                    #warn("GPS Timeout")
140
+                    warn("UL ID: "+parseTopic[1]+" D: "+parseTopic[3]+" F: "+str(FCnt)+" Type: "+messageType+" GPS Timeout")
131 141
                     return
132
-
133
-                
134 142
             else:
135 143
                 isPosition=False
136
-                say("[WARN] Not a position message:"+parsed['DevEUI_uplink']['payload']['messageType'])
144
+                say("UL ID: "+parseTopic[1]+" D: "+parseTopic[3]+" F: "+str(FCnt)+" Type: "+messageType)
137 145
                 return
138 146
         else:
139 147
             isPosition=False
140
-            warn("[WARN] No decoded payload")
148
+            warn("No decoded payload")
141 149
             with open(server['logfile'],'a+') as f:
142 150
                 f.write("------------------------------\nMQTT Not decoded: topic: "+msg.topic+" content: "+msg.payload.decode('ASCII')+"\n------------------------------\n")
143 151
                 f.close()
144 152
             return
145 153
         csvLine+=","+str(lat)+","+str(lon)+","+str(err)
146 154
 
155
+        ok("UL ID: "+parseTopic[1]+" D: "+parseTopic[3]+" F: "+str(FCnt)+" Type: "+messageType+" "+str(lat)+" "+str(lon)+" "+str(err))
156
+
147 157
         # Append GW details
148 158
         #parsed['DevEUI_uplink']['Lrrs']['Lrr']
149 159
         #Lrrid
... ...
@@ -163,7 +173,7 @@ def on_message(client, userdata, msg):
163 173
 
164 174
         # Appending only if position is different from 0,0
165 175
         if 0 != lat and 0 != lon:
166
-            with open(filename,'a+') as f:
176
+            with open(server['rawCsv'],'a+') as f:
167 177
                 f.write(csvLine+"\n")
168 178
                 f.close()
169 179
         if True == isPosition:
... ...
@@ -222,6 +232,38 @@ def httpDevEuiList(subId):
222 232
     content += "</ul>"
223 233
     return content 
224 234
 
235
+def escape_ansi(line):
236
+    ansi_escape = re.compile(r'(?:\x1B[@-_]|[\x80-\x9F])[0-?]*[ -/]*[@-~]')
237
+    return ansi_escape.sub('', line)
238
+
239
+def httpReverseLog(numLines):
240
+    global server
241
+    content=""
242
+    #print("Log file:"+server['logfile'])
243
+    cpt = 0
244
+    content+="<h2>"+server['name']+" Log</h2>\n"
245
+    content+="<p>\n<div id=\"latest\"><button class=\"btn-green-menu\" onClick=\"window.location.href='./last';\">Latest</div>\n"
246
+    content+="<div id=\"home\"><button class=\"btn-green-menu\" onClick=\"window.location.href='.';\">Home</div>\n"
247
+    content+="<div id=\"reload\"><button class=\"btn-green\" onClick=\"window.location.reload();\">Reload</div>\n</p>\n"
248
+    content+="<div class=\"loglines\">\n"
249
+    for line in reversed(open(server['logfile']).readlines()):
250
+        lineColor=line.rstrip()
251
+        lineColor =escape_ansi(lineColor)
252
+        lineColor = lineColor.replace("[OK]","<div class=\"logOK\">[OK]</div>")
253
+        lineColor = lineColor.replace("[WARN]","<div class=\"logWARN\">[WARN]</div>")
254
+        lineColor = lineColor.replace("[ERR]","<div class=\"logERROR\">[ERR]</div>")
255
+        lineColor = lineColor.replace(server['name']+" ","")
256
+        lineColor = lineColor.replace("+0000","")
257
+        if not "/log/" in lineColor and not "------------------------------" in lineColor and not "From: " in lineColor:
258
+            cpt += 1
259
+            content+=lineColor+"<br>\n"
260
+
261
+        if cpt >= numLines:
262
+           continue 
263
+
264
+    content+="</div>\n"
265
+    return content
266
+
225 267
 
226 268
 class MyServer(BaseHTTPRequestHandler):
227 269
     def log_message(self, format, *args):
... ...
@@ -246,11 +288,42 @@ class MyServer(BaseHTTPRequestHandler):
246 288
             data_end += fEnd.read().replace( 'CSTAPPNAME', server['name'] ).replace( 'CSTAPPVERSION', server['version'] )
247 289
             fEnd.close()
248 290
 
249
-        if self.path == "/" or self.path == "/index.html":
291
+        if "/favicon.png" in self.path or "/style.css" in self.path:
292
+            splitPath=self.path.split('/')
293
+            localFilename=splitPath[len(splitPath)-1]
294
+            try:
295
+
296
+                f = open(rootdir + "/" + localFilename,'rb') #open requested file
297
+                self.send_response(200)
298
+                if self.path.endswith('.css'):
299
+                    self.send_header('Content-type','text/css')
300
+                elif self.path.endswith('.bmp'):
301
+                    self.send_header('Content-type','image/x-ms-bmp')
302
+                elif self.path.endswith('.png'):
303
+                    self.send_header('Content-type','image/png')
304
+                elif self.path.endswith('.jpg'):
305
+                    self.send_header('Content-type','image/jpeg')
306
+                else:
307
+                    self.send_header('Content-type','text/html')
308
+                self.send_header('Server',server['name']+" v"+server['version'])
309
+                self.end_headers()
310
+                self.wfile.write(f.read())
311
+                f.close()
312
+                return
313
+            except:
314
+                with open(server['logfile'],'a+') as f:
315
+                    f.write("------------------------------\nHTTP 404 "+self.path+"\n------------------------------\n")
316
+                    f.close()
317
+                self.send_header('Server',server['name']+" v"+server['version'])
318
+                self.send_error(404, 'file not found')
319
+
320
+        elif self.path == "/" or self.path == "/index.html":
250 321
             # Send list of SubID
251
-            data_page ="<h2>"+server['name']+" Latest</h2>\n"
322
+            data_page ="<h2>"+server['name']+"</h2>\n"
323
+            data_page += "<p>\n<div id=\"latest\"><button class=\"btn-green-menu\" onClick=\"window.location.href='./last';\">Latest</div>\n"
324
+            data_page += "<div id=\"log\"><button class=\"btn-green-menu\" onClick=\"window.location.href='./log';\">Log</div>\n</p>\n"
325
+            data_page += "<h3>subId List</h3>\n"
252 326
             data_page += httpSubIdList()
253
-            data_page += "<p>\n<div id=\"latest\"><button class=\"btn-green-menu\" onClick=\"window.location.href='./last';\">Latest</div>\n</p>\n"
254 327
 
255 328
             page.append(data_begin)
256 329
             page.append(data_page)
... ...
@@ -262,7 +335,7 @@ class MyServer(BaseHTTPRequestHandler):
262 335
             self.end_headers()
263 336
             self.wfile.write(content.encode('utf-8'))
264 337
 
265
-        elif self.path == "/last" or self.path == "/last/index.html":
338
+        elif self.path == "/last" or self.path == "/last/" or self.path == "/last/index.html":
266 339
             page.append(data_begin)
267 340
             page.append(latestHtml)
268 341
             page.append(data_end)
... ...
@@ -272,8 +345,35 @@ class MyServer(BaseHTTPRequestHandler):
272 345
             self.send_header('Server',server['name']+" v"+server['version'])
273 346
             self.end_headers()
274 347
             self.wfile.write(content.encode('utf-8'))
275
-            
276 348
 
349
+        elif self.path == "/log" or self.path == "/log/" or self.path == "/log/index.html":
350
+            uriObject = urlparse(self.path)
351
+            queries = uriObject.query.split('&')
352
+            uriParams = {} 
353
+
354
+            try:
355
+                for query in queries:
356
+                    element=query.split("=")
357
+                    uriParams[element[0]]=element[1]
358
+            except:
359
+                pass
360
+
361
+            try:
362
+                numLines=uriParams['last']
363
+            except:
364
+                numLines = 50
365
+
366
+            page.append(data_begin)
367
+            data_page = httpReverseLog(numLines)
368
+            page.append(data_page)
369
+            page.append(data_end)
370
+            content = ''.join(page)
371
+            self.send_response(200)
372
+            self.send_header("Content-type", "text/html")
373
+            self.send_header('Server',server['name']+" v"+server['version'])
374
+            self.end_headers()
375
+            self.wfile.write(content.encode('utf-8'))
376
+            
277 377
         elif "/?" in self.path:
278 378
             uriObject = urlparse(self.path)
279 379
             queries = uriObject.query.split('&')
... ...
@@ -290,13 +390,15 @@ class MyServer(BaseHTTPRequestHandler):
290 390
             except:
291 391
                 devEUI=None
292 392
 
393
+            data_page += "<p><div id=\"home\"><button class=\"btn-green-menu\" onClick=\"window.location.href='.';\">Home</div>\n"
394
+            data_page += "<div id=\"latest\"><button class=\"btn-green-menu\" onClick=\"window.location.href='./last';\">Latest</div>\n"
395
+            data_page += "<div id=\"log\"><button class=\"btn-green-menu\" onClick=\"window.location.href='./log';\">Log</div>\n"
396
+
293 397
             if subId is not None and devEUI is None:
294
-                data_page = csv2geojs.networkSurvey(filename, subId, fileOutput=False)
398
+                data_page += csv2geojs.networkSurvey(server['rawCsv'], subId, fileOutput=False)
295 399
             elif subId is not None and devEUI is not None:
296
-                data_page = csv2geojs.networkSurvey(filename, subId, devEUI, fileOutput=False)
400
+                data_page += csv2geojs.networkSurvey(server['rawCsv'], subId, devEUI, fileOutput=False)
297 401
             data_page += httpDevEuiList(subId)
298
-            data_page += "<p>\n<div id=\"latest\"><button class=\"btn-green-menu\" onClick=\"window.location.href='./last';\">Latest</div>\n"
299
-            data_page += "<div id=\"home\"><button class=\"btn-green-menu\" onClick=\"window.location.href='.';\">Home</div>\n</p>\n"
300 402
 
301 403
             page.append(data_begin)
302 404
             page.append(data_page)
... ...
@@ -329,11 +431,11 @@ class MyServer(BaseHTTPRequestHandler):
329 431
                 f.close()
330 432
                 return
331 433
             except IOError:
332
-                self.send_header('Server',server['name']+" v"+server['version'])
333
-                self.send_error(404, 'file not found')
334 434
                 with open(server['logfile'],'a+') as f:
335 435
                     f.write("------------------------------\nHTTP 404 "+self.path+"\n------------------------------\n")
336 436
                     f.close()
437
+                self.send_header('Server',server['name']+" v"+server['version'])
438
+                self.send_error(404, 'file not found')
337 439
 
338 440
 
339 441
 def mqttInitRun():
... ...
@@ -375,10 +477,13 @@ def httpInitRun():
375 477
         pass
376 478
 
377 479
     webServer.server_close()
378
-    print("HTTP Server stopped.")
480
+    say("HTTP Server stopped.")
379 481
 
380 482
 
381 483
 if __name__ == "__main__":
484
+    server = configuration.get_server()
485
+    say("===============================")
486
+    say("Starting")
382 487
     Thread(target = mqttInitRun).start()
383 488
     Thread(target = httpInitRun).start()
384 489