From a748ea5ccfd84f7218dcd4c94b70f4778d3bee58 Mon Sep 17 00:00:00 2001 From: Kim - DG9VH Date: Tue, 3 Nov 2020 12:11:23 +0100 Subject: [PATCH] First functional codebase First codebase with readme for successful installation... maybe --- README.md | 30 ++++++- html/.index.html.swp | Bin 0 -> 1024 bytes html/index.html | 160 ++++++++++++++++++++++++++++++++++++ html/js/functions.js | 159 +++++++++++++++++++++++++++++++++++ img/Screenshot.png | Bin 0 -> 71958 bytes logtailer.ini | 9 ++ logtailer.py | 102 +++++++++++++++++++++++ systemd/http.server.service | 13 +++ systemd/logtailer.service | 14 ++++ 9 files changed, 486 insertions(+), 1 deletion(-) create mode 100644 html/.index.html.swp create mode 100644 html/index.html create mode 100644 html/js/functions.js create mode 100644 img/Screenshot.png create mode 100644 logtailer.ini create mode 100644 logtailer.py create mode 100644 systemd/http.server.service create mode 100644 systemd/logtailer.service diff --git a/README.md b/README.md index adb7d57..21c35ea 100644 --- a/README.md +++ b/README.md @@ -1 +1,29 @@ -# MMDVMHost-Websocketboard \ No newline at end of file +# MMDVMHost-Websocketboard + +## Introduction +This is a very first development version of my new MMDVMDash using websockets-technology to get rid of high load on Raspberry Pi and others and keep those temperature down. + +Also this should improve user experience. + +## Installation +You'll need to install several python3 modules. A concrete list will follow here later. + +### Installation steps +* clone this repository to your home-directory +* create directory with `sudo mkdir /opt/MMDVMDash` +* change ownership to your user for example with `sudo chown -R pi /opt/MMDVMDash` +* copy all files from repository into this folder +* modify *logtailer.ini* to fit your needs +* copy files in */opt/MMDVMDash/systemd* to */etc/systemd/system* or similar corresponding to your system +* modify both scripts to fit your needs +* enable services with following commmands, this results in starting both automatically after reboot: + * `sudo systemctl enable http.server.service` + * `sudo systemctl enable logtailer.service` +* start services with following commmands: + * `sudo systemctl enable http.server.service` + * `sudo systemctl enable logtailer.service` + +Finally you should be able to get the new Dashboard calling the hostname of your hotspot + +## Screenshots +![Screenshot of MMDVMDash Websocketboard](img/Screenshot.png "Screenshot of MMDVMDash Websocketboard") \ No newline at end of file diff --git a/html/.index.html.swp b/html/.index.html.swp new file mode 100644 index 0000000000000000000000000000000000000000..3c0fe218f906905f5222b389be2c29e7d5c36cbd GIT binary patch literal 1024 zcmYc?$V<%2S1{HyVn6`_tPBhVnJ7XyIVokisp*M0rQs6#`2{8VzP>JDzAlNy8TuI| bxjFioc`2zCdLSlT*(hT)1V%%EP9XpQPYn@N literal 0 HcmV?d00001 diff --git a/html/index.html b/html/index.html new file mode 100644 index 0000000..3963499 --- /dev/null +++ b/html/index.html @@ -0,0 +1,160 @@ + + + + + + + + + + + MMDVM-Dashboard by DG9VH + + + + + + + + + + + + + DG9VH - MMDVM-Dashboard by DG9VH + + + + + + +
+
+
+ +
Last Heard List of today's callsigns.
+
+ +
+ + + + + + + + + + + + + + +
Time (UTC)ModeCallsignTargetSourceDur (s)LossBERQSO
+
+
+
+
+
+
+ +
Local Heard List of today
+
+ +
+ + + + + + + + + + + + +
Time (UTC)ModeCallsignTargetSourceDur (s)BER
+
+
+
+
+
+
+ +
Currently in QSO
+
+ +
+ + + + + + + + +
CallsignAdded at
+
+
+
+
+
+ + + + diff --git a/html/js/functions.js b/html/js/functions.js new file mode 100644 index 0000000..bbc7cba --- /dev/null +++ b/html/js/functions.js @@ -0,0 +1,159 @@ +// 00000000001111111111222222222233333333334444444444555555555566666666667777777777888888888899999999990000000000111111111122222222223333333333 +// 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +// M: 2020-11-01 21:33:27.454 YSF, received network data from DG2MAS to DG-ID 0 at DG2MAS +// M: 2020-11-01 21:33:35.025 YSF, received network end of transmission from DG2MAS to DG-ID 0, 7.7 seconds, 0% packet loss, BER: 0.0% +function getTimestamp(logline) { + return logline.substring(3,22); +} + +function getMode(logline) { + return logline.substring(27, logline.indexOf(",")); +} + +function getCallsign(logline) { + return logline.substring(logline.indexOf("from") + 5, logline.indexOf("to")); +} + +function getTarget(logline) { + if(logline.indexOf("at") > 0) { + return logline.substring(logline.indexOf("to") + 3, logline.lastIndexOf("at")); + } else { + return logline.substring(logline.indexOf("to") + 3, logline.substring(logline.indexOf("to") + 3).indexOf(",") + logline.indexOf("to") + 3); + } +} + +function getSource(logline) { + val = logline.substring(logline.indexOf("received") + 9); + val = val.substring(0, val.indexOf(" ")); + if (val == "network") + val = "Net"; + return val; +} + +function getDuration(logline) { + if(logline.lastIndexOf("seconds") > 0) { + val = logline.substring(0, logline.lastIndexOf("seconds")); + val = val.substring(val.lastIndexOf(",") + 2); + return val; + } else { + return ""; + } +} + +function getLoss(logline) { + if(logline.lastIndexOf("seconds") > 0) { + val = logline.substring(logline.lastIndexOf("seconds") + 9, logline.indexOf("%")); + if (val.indexOf("BER") == -1) { + return val; + } else { + return ""; + } + } else { + return ""; + } +} + +function getBER(logline) { + if(logline.lastIndexOf("BER") > 0) { + return logline.substring(logline.lastIndexOf("BER") + 4); + } else { + return ""; + } +} + + +function getAddToQSO(logline) { + retval = '
'; + return retval; +} + +function clocktime() { + var now = new Date(), + h = now.getHours(), + m = now.getMinutes(), + s = now.getSeconds(); + m = leadingZero(m); + s = leadingZero(s); + return h + ':' + m + ':' + s; + +} + +function leadingZero(zahl) { + zahl = (zahl < 10 ? '0' : '' )+ zahl; + return zahl; +} + +function copyToQSO(callsign) { + $(document).ready(function() { + t_qso.row.add( [ + callsign, + new Date().toUTCString() + ] ).draw(); + }); + alert("" + callsign + " added to in QSO-Tab"); + +} + +function getLastHeard(document, event) { +// 00000000001111111111222222222233333333334444444444555555555566666666667777777777888888888899999999990000000000111111111122222222223333333333 +// 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +// M: 2020-11-01 21:33:27.454 YSF, received network data from DG2MAS to DG-ID 0 at DG2MAS +// M: 2020-11-01 21:33:35.025 YSF, received network end of transmission from DG2MAS to DG-ID 0, 7.7 seconds, 0% packet loss, BER: 0.0% + $(document).ready(function() { + var rowIndexes = []; + t_lh.rows( function ( idx, data, node ) { + if(data[2] === getCallsign(event.data)){ + rowIndexes.push(idx); + } + return false; + }); + if (rowIndexes[0]) { + newData = [ + getTimestamp(event.data), + getMode(event.data), + getCallsign(event.data), + getTarget(event.data), + getSource(event.data), + getDuration(event.data), + getLoss(event.data), + getBER(event.data), + getAddToQSO(event.data) + ] + t_lh.row(rowIndexes[0]).data( newData ).draw(); + } else { + t_lh.row.add( [ + getTimestamp(event.data), + getMode(event.data), + getCallsign(event.data), + getTarget(event.data), + getSource(event.data), + getDuration(event.data), + getLoss(event.data), + getBER(event.data), + getAddToQSO(event.data) + ] ).draw(); + } + }); +} + +function getLocalHeard(document, event) { +// 00000000001111111111222222222233333333334444444444555555555566666666667777777777888888888899999999990000000000111111111122222222223333333333 +// 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789 +// M: 2020-11-01 21:33:27.454 YSF, received network data from DG2MAS to DG-ID 0 at DG2MAS +// M: 2020-11-01 21:33:35.025 YSF, received network end of transmission from DG2MAS to DG-ID 0, 7.7 seconds, 0% packet loss, BER: 0.0% + $(document).ready(function() { + if (getSource(event.data) == "RF") { + if (getDuration(event.data) !== "") { + t_localh.row.add( [ + getTimestamp(event.data), + getMode(event.data), + getCallsign(event.data), + getTarget(event.data), + getSource(event.data), + getDuration(event.data), + getBER(event.data) + ] ).draw(); + } + } + }); +} diff --git a/img/Screenshot.png b/img/Screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..efb7250c760ce6638216ffee4a8725c67fd71ecc GIT binary patch literal 71958 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 yt_9F&{}OETe+c literal 0 HcmV?d00001 diff --git a/logtailer.ini b/logtailer.ini new file mode 100644 index 0000000..caa3bb9 --- /dev/null +++ b/logtailer.ini @@ -0,0 +1,9 @@ +[DEFAULT] +Host=0.0.0.0 +Port=5678 +Webport=8080 + +[MMDVMHost] +Logdir=/mnt/ramdisk/ +Prefix=MMDVM +Num_Lines=10000 diff --git a/logtailer.py b/logtailer.py new file mode 100644 index 0000000..b3536d7 --- /dev/null +++ b/logtailer.py @@ -0,0 +1,102 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +#import time +import datetime +import os.path +import asyncio +import logging +import argparse +import websockets +import http.server +import socketserver +import configparser +import os +from collections import deque +from urllib.parse import urlparse, parse_qs +from ansi2html import Ansi2HTMLConverter +from threading import Thread + +current_dir = os.getcwd() +config = configparser.ConfigParser() +config.read(current_dir + '/logtailer.ini') + +NUM_LINES = int(config['MMDVMHost']['Num_Lines']) + +# init +logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s', level=logging.INFO) +conv = Ansi2HTMLConverter(inline=True) + +@asyncio.coroutine +def view_log(websocket, path): + global config + logging.info('Connected, remote={}, path={}'.format(websocket.remote_address, path)) + + try: + now = datetime.datetime.now() + year = str(now.year) + month = str(now.month) + if len(month) == 1: + month = "0" + month + day = str(now.day) + if len(day) == 1: + day = "0" + day + + file_path = config['MMDVMHost']['Logdir']+config['MMDVMHost']['Prefix']+"-"+year+"-"+month+"-"+day+".log" + + if not os.path.isfile(file_path): + raise ValueError('Not found') + + path = file_path + with open(file_path) as f: + + content = ''.join(deque(f, NUM_LINES)) + content = conv.convert(content, full=False) + lines = content.split("\n") + for line in lines: + if line.find('received') >0 and not line.find('network watchdog') > 0: + yield from websocket.send(line) + + while True: + content = f.read() + if content: + content = conv.convert(content, full=False) + yield from websocket.send(content) + else: + yield from asyncio.sleep(1) + + except ValueError as e: + try: + yield from websocket.send('{}'.format(e)) + yield from websocket.close() + except Exception: + pass + + log_close(websocket, path, e) + + except Exception as e: + log_close(websocket, path, e) + + else: + log_close(websocket, path) + + +def log_close(websocket, path, exception=None): + message = 'Closed, remote={}, path={}'.format(websocket.remote_address, path) + if exception is not None: + message += ', exception={}'.format(exception) + logging.info(message) + + +def websocketserver(): + start_server = websockets.serve(view_log, config['DEFAULT']['Host'], config['DEFAULT']['Port']) + asyncio.get_event_loop().run_until_complete(start_server) + asyncio.get_event_loop().run_forever() + + +def main(): + websocketserver() + + +if __name__ == '__main__': + main() diff --git a/systemd/http.server.service b/systemd/http.server.service new file mode 100644 index 0000000..7342800 --- /dev/null +++ b/systemd/http.server.service @@ -0,0 +1,13 @@ +[Unit] +Description=Python3 http.server +After=network.target + +[Service] +ExecStartPre=/bin/sleep 30 +Type=simple +Restart=always +# Modify for different location of Python3 or other port +ExecStart=/usr/bin/python3 -m http.server 8000 --directory /opt/MMDVMDash/html + +[Install] +WantedBy=multi-user.target diff --git a/systemd/logtailer.service b/systemd/logtailer.service new file mode 100644 index 0000000..7e65f4c --- /dev/null +++ b/systemd/logtailer.service @@ -0,0 +1,14 @@ +[Unit] +Description=Python3 logtailer for MMDVMDash +After=network.target + +[Service] +ExecStartPre=/bin/sleep 30 +Type=simple +Restart=always +# Modify for different location of Python3 or other port +WorkingDirectory=/opt/MMDVMDash/ +ExecStart=/usr/bin/python3 /opt/MMDVMDash/logtailer.py + +[Install] +WantedBy=multi-user.target