From d330e2e978752ef5fc44dc7acbddd59364babde3 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Thu, 24 Feb 2022 08:57:23 -0700 Subject: [PATCH 01/65] started adding HTML files for the web monitor program --- tools/web_monitor/__init__.py | 5 ++ tools/web_monitor/app.py | 13 +++++ tools/web_monitor/index.py | 7 +++ tools/web_monitor/public/index.html | 69 ++++++++++++++++++++++ tools/web_monitor/scan_page.py | 16 ++++++ tools/web_monitor/static/index.css | 89 +++++++++++++++++++++++++++++ 6 files changed, 199 insertions(+) create mode 100644 tools/web_monitor/__init__.py create mode 100644 tools/web_monitor/app.py create mode 100644 tools/web_monitor/index.py create mode 100644 tools/web_monitor/public/index.html create mode 100644 tools/web_monitor/scan_page.py create mode 100644 tools/web_monitor/static/index.css diff --git a/tools/web_monitor/__init__.py b/tools/web_monitor/__init__.py new file mode 100644 index 00000000..2687e47d --- /dev/null +++ b/tools/web_monitor/__init__.py @@ -0,0 +1,5 @@ +from tools.web_monitor.app import app + +if __name__ == '__main__': + # app.run for running the sanic app inside the file + app.run(host="0.0.0.0", port=80) diff --git a/tools/web_monitor/app.py b/tools/web_monitor/app.py new file mode 100644 index 00000000..650704b0 --- /dev/null +++ b/tools/web_monitor/app.py @@ -0,0 +1,13 @@ +import socketio +from sanic import Sanic + +app = Sanic("App") + +# attach socketio +sio = socketio.AsyncServer(async_mode="sanic") +sio.attach(app) + +app.static('/', "./public/index.html") +app.static('/index.css', "./static/index.css") + +app.static('/scan', "./public/scan.html") diff --git a/tools/web_monitor/index.py b/tools/web_monitor/index.py new file mode 100644 index 00000000..d9e0388a --- /dev/null +++ b/tools/web_monitor/index.py @@ -0,0 +1,7 @@ +from tools.web_monitor.app import sio + + +@sio.event +async def connect(sid, _environ) -> None: + """Event for connection""" + await sio.emit('init', "hello") diff --git a/tools/web_monitor/public/index.html b/tools/web_monitor/public/index.html new file mode 100644 index 00000000..e001c418 --- /dev/null +++ b/tools/web_monitor/public/index.html @@ -0,0 +1,69 @@ + + + + + + + + Title + + + + + + + + + + + + + + + + +
+ +
+ + + + diff --git a/tools/web_monitor/scan_page.py b/tools/web_monitor/scan_page.py new file mode 100644 index 00000000..af5b2ea5 --- /dev/null +++ b/tools/web_monitor/scan_page.py @@ -0,0 +1,16 @@ +from tools.web_monitor.app import sio +import json + + +async def scan_found_miner(miner): + """Send data to client that a miner was scanned. + + :param miner: The miner object that was scanned. + """ + await sio.emit('scan_found_miner', json.dumps( + { + "ip": str(miner.ip), + "model": str(miner.model), + "api": str(miner.api_type) + } + )) diff --git a/tools/web_monitor/static/index.css b/tools/web_monitor/static/index.css new file mode 100644 index 00000000..6949a379 --- /dev/null +++ b/tools/web_monitor/static/index.css @@ -0,0 +1,89 @@ +body { + min-height: 100vh; + min-height: -webkit-fill-available; +} + +html { + height: -webkit-fill-available; +} + +main { + display: flex; + flex-wrap: nowrap; + height: 100vh; + height: -webkit-fill-available; + max-height: 100vh; + overflow-x: auto; + overflow-y: hidden; +} + +.b-example-divider { + flex-shrink: 0; + width: 1.5rem; + height: 100vh; + background-color: rgba(0, 0, 0, .1); + border: solid rgba(0, 0, 0, .15); + border-width: 1px 0; + box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15); +} + +.bi { + vertical-align: -.125em; + pointer-events: none; + fill: currentColor; +} + +.dropdown-toggle { outline: 0; } + +.nav-flush .nav-link { + border-radius: 0; +} + +.btn-toggle { + display: inline-flex; + align-items: center; + padding: .25rem .5rem; + font-weight: 600; + color: rgba(0, 0, 0, .65); + background-color: transparent; + border: 0; +} +.btn-toggle:hover, +.btn-toggle:focus { + color: rgba(0, 0, 0, .85); + background-color: #d2f4ea; +} + +.btn-toggle::before { + width: 1.25em; + line-height: 0; + content: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='rgba%280,0,0,.5%29' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 14l6-6-6-6'/%3e%3c/svg%3e"); + transition: transform .35s ease; + transform-origin: .5em 50%; +} + +.btn-toggle[aria-expanded="true"] { + color: rgba(0, 0, 0, .85); +} +.btn-toggle[aria-expanded="true"]::before { + transform: rotate(90deg); +} + +.btn-toggle-nav a { + display: inline-flex; + padding: .1875rem .5rem; + margin-top: .125rem; + margin-left: 1.25rem; + text-decoration: none; +} +.btn-toggle-nav a:hover, +.btn-toggle-nav a:focus { + background-color: #d2f4ea; +} + +.scrollarea { + overflow-y: auto; +} + +.fw-semibold { font-weight: 600; } +.lh-tight { line-height: 1.25; } From c6305c57cf253d9789179152bf4c1bf66220c7b2 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Thu, 24 Feb 2022 09:13:07 -0700 Subject: [PATCH 02/65] improved formatting of index.html --- tools/web_monitor/public/index.html | 71 +++++++++++++++-------------- tools/web_monitor/static/index.css | 44 +----------------- 2 files changed, 39 insertions(+), 76 deletions(-) diff --git a/tools/web_monitor/public/index.html b/tools/web_monitor/public/index.html index e001c418..81b5f2f6 100644 --- a/tools/web_monitor/public/index.html +++ b/tools/web_monitor/public/index.html @@ -22,45 +22,48 @@ -
-
+ diff --git a/tools/web_monitor/static/index.css b/tools/web_monitor/static/index.css index 6949a379..42b64d41 100644 --- a/tools/web_monitor/static/index.css +++ b/tools/web_monitor/static/index.css @@ -17,16 +17,6 @@ main { overflow-y: hidden; } -.b-example-divider { - flex-shrink: 0; - width: 1.5rem; - height: 100vh; - background-color: rgba(0, 0, 0, .1); - border: solid rgba(0, 0, 0, .15); - border-width: 1px 0; - box-shadow: inset 0 .5em 1.5em rgba(0, 0, 0, .1), inset 0 .125em .5em rgba(0, 0, 0, .15); -} - .bi { vertical-align: -.125em; pointer-events: none; @@ -39,36 +29,6 @@ main { border-radius: 0; } -.btn-toggle { - display: inline-flex; - align-items: center; - padding: .25rem .5rem; - font-weight: 600; - color: rgba(0, 0, 0, .65); - background-color: transparent; - border: 0; -} -.btn-toggle:hover, -.btn-toggle:focus { - color: rgba(0, 0, 0, .85); - background-color: #d2f4ea; -} - -.btn-toggle::before { - width: 1.25em; - line-height: 0; - content: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='rgba%280,0,0,.5%29' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M5 14l6-6-6-6'/%3e%3c/svg%3e"); - transition: transform .35s ease; - transform-origin: .5em 50%; -} - -.btn-toggle[aria-expanded="true"] { - color: rgba(0, 0, 0, .85); -} -.btn-toggle[aria-expanded="true"]::before { - transform: rotate(90deg); -} - .btn-toggle-nav a { display: inline-flex; padding: .1875rem .5rem; @@ -76,9 +36,10 @@ main { margin-left: 1.25rem; text-decoration: none; } + .btn-toggle-nav a:hover, .btn-toggle-nav a:focus { - background-color: #d2f4ea; + background-color: #0d6efd; } .scrollarea { @@ -86,4 +47,3 @@ main { } .fw-semibold { font-weight: 600; } -.lh-tight { line-height: 1.25; } From 30b33150844df532c381bcaf17d38d68dac2ca87 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Thu, 24 Feb 2022 15:25:49 -0700 Subject: [PATCH 03/65] added the required directories for settings and scanning --- settings/settings.toml | 2 +- tools/web_monitor/app.py | 2 + tools/web_monitor/public/index.html | 123 +++++++++++++++++-------- tools/web_monitor/public/scan.html | 115 +++++++++++++++++++++++ tools/web_monitor/public/settings.html | 115 +++++++++++++++++++++++ tools/web_monitor/static/index.css | 83 +++++++++++++++++ tools/web_monitor/static/index.js | 53 +++++++++++ 7 files changed, 452 insertions(+), 41 deletions(-) create mode 100644 tools/web_monitor/public/scan.html create mode 100644 tools/web_monitor/public/settings.html create mode 100644 tools/web_monitor/static/index.js diff --git a/settings/settings.toml b/settings/settings.toml index aa987959..d67ab1a4 100644 --- a/settings/settings.toml +++ b/settings/settings.toml @@ -11,4 +11,4 @@ reboot_threads = 300 # tool or the privileged API will not work using admin as the password. # If you change the password, you can pass that password here. -whatsminer_pwd = "admin" \ No newline at end of file +whatsminer_pwd = "admin" diff --git a/tools/web_monitor/app.py b/tools/web_monitor/app.py index 650704b0..401835ad 100644 --- a/tools/web_monitor/app.py +++ b/tools/web_monitor/app.py @@ -9,5 +9,7 @@ sio.attach(app) app.static('/', "./public/index.html") app.static('/index.css', "./static/index.css") +app.static('/index.js', "./static/index.js") app.static('/scan', "./public/scan.html") +app.static('/settings', "./public/settings.html") diff --git a/tools/web_monitor/public/index.html b/tools/web_monitor/public/index.html index 81b5f2f6..0298cca6 100644 --- a/tools/web_monitor/public/index.html +++ b/tools/web_monitor/public/index.html @@ -20,53 +20,96 @@ + + + + + + + + -
-
- - - Home - + - -
  • - - -
    -
    -

    hi

    -
    +
    + - - +
    diff --git a/tools/web_monitor/public/scan.html b/tools/web_monitor/public/scan.html new file mode 100644 index 00000000..04335d02 --- /dev/null +++ b/tools/web_monitor/public/scan.html @@ -0,0 +1,115 @@ + + + + + + + + Title + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/web_monitor/public/settings.html b/tools/web_monitor/public/settings.html new file mode 100644 index 00000000..3bd096cf --- /dev/null +++ b/tools/web_monitor/public/settings.html @@ -0,0 +1,115 @@ + + + + + + + + Title + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/web_monitor/static/index.css b/tools/web_monitor/static/index.css index 42b64d41..388b1403 100644 --- a/tools/web_monitor/static/index.css +++ b/tools/web_monitor/static/index.css @@ -47,3 +47,86 @@ main { } .fw-semibold { font-weight: 600; } + +.sidebar { + position: fixed; + top: 0; + /* rtl:raw: + right: 0; + */ + bottom: 0; + /* rtl:remove */ + left: 0; + z-index: 100; /* Behind the navbar */ + padding: 0px 0 0; /* Height of navbar */ + box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1); +} + +@media (max-width: 767.98px) { + .sidebar { + top: 48px; + } +} + +.sidebar-sticky { + position: relative; + top: 0; + height: calc(100vh - 48px); + padding-top: .5rem; + overflow-x: hidden; + overflow-y: auto; +} + +.sidebar .nav-link { + font-weight: 500; + color: #333; +} + +.sidebar .nav-link .feather { + margin-right: 4px; + color: #727272; +} + +.sidebar .nav-link.active { + color: #2470dc; +} + +.sidebar .nav-link:hover .feather, +.sidebar .nav-link.active .feather { + color: inherit; +} + +.sidebar-heading { + font-size: .75rem; + text-transform: uppercase; +} + +.navbar-brand { + padding-top: .75rem; + padding-bottom: .75rem; + font-size: 1rem; + background-color: rgba(0, 0, 0, .25); + box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25); +} + +.navbar .navbar-toggler { + top: .25rem; + right: 1rem; +} + +.navbar .form-control { + padding: .75rem 1rem; + border-width: 0; + border-radius: 0; +} + +.form-control-dark { + color: #fff; + background-color: rgba(255, 255, 255, .1); + border-color: rgba(255, 255, 255, .1); +} + +.form-control-dark:focus { + border-color: transparent; + box-shadow: 0 0 0 3px rgba(255, 255, 255, .25); +} diff --git a/tools/web_monitor/static/index.js b/tools/web_monitor/static/index.js new file mode 100644 index 00000000..7c2402ae --- /dev/null +++ b/tools/web_monitor/static/index.js @@ -0,0 +1,53 @@ +/* globals Chart:false, feather:false */ + +(function () { + 'use strict' + + feather.replace({ 'aria-hidden': 'true' }) + + // Graphs + var ctx = document.getElementById('myChart') + // eslint-disable-next-line no-unused-vars + var myChart = new Chart(ctx, { + type: 'line', + data: { + labels: [ + 'Sunday', + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday' + ], + datasets: [{ + data: [ + 15339, + 21345, + 18483, + 24003, + 23489, + 24092, + 12034 + ], + lineTension: 0, + backgroundColor: 'transparent', + borderColor: '#007bff', + borderWidth: 4, + pointBackgroundColor: '#007bff' + }] + }, + options: { + scales: { + yAxes: [{ + ticks: { + beginAtZero: false + } + }] + }, + legend: { + display: false + } + } + }) +})() From da5a784214b220bcf5ae7cab6528411bc04e1bfa Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Thu, 24 Feb 2022 15:59:48 -0700 Subject: [PATCH 04/65] switched to fastAPi and jinja 2 for templates and html --- tools/web_monitor/app.py | 29 +++-- tools/web_monitor/public/scan.html | 115 ------------------ tools/web_monitor/public/settings.html | 115 ------------------ tools/web_monitor/static/index.js | 53 -------- .../static/{index.css => navbar.css} | 0 tools/web_monitor/templates/index.html | 4 + .../index.html => templates/navbar.html} | 7 +- 7 files changed, 27 insertions(+), 296 deletions(-) delete mode 100644 tools/web_monitor/public/scan.html delete mode 100644 tools/web_monitor/public/settings.html delete mode 100644 tools/web_monitor/static/index.js rename tools/web_monitor/static/{index.css => navbar.css} (100%) create mode 100644 tools/web_monitor/templates/index.html rename tools/web_monitor/{public/index.html => templates/navbar.html} (96%) diff --git a/tools/web_monitor/app.py b/tools/web_monitor/app.py index 401835ad..68aad1ec 100644 --- a/tools/web_monitor/app.py +++ b/tools/web_monitor/app.py @@ -1,15 +1,22 @@ -import socketio -from sanic import Sanic +import json +import asyncio +import uvicorn +from fastapi import FastAPI +from fastapi import Request +from fastapi import WebSocket +from fastapi.templating import Jinja2Templates +from fastapi.staticfiles import StaticFiles -app = Sanic("App") +app = FastAPI() -# attach socketio -sio = socketio.AsyncServer(async_mode="sanic") -sio.attach(app) +app.mount("/static", StaticFiles(directory="static"), name="static") +templates = Jinja2Templates(directory="templates") -app.static('/', "./public/index.html") -app.static('/index.css', "./static/index.css") -app.static('/index.js', "./static/index.js") -app.static('/scan', "./public/scan.html") -app.static('/settings', "./public/settings.html") +@app.route("/") +def dashboard(request: Request): + return templates.TemplateResponse("index.html", {"request": request}) + + +if __name__ == "__main__": + uvicorn.run("app:app", host="127.0.0.1", port=80, debug=True) diff --git a/tools/web_monitor/public/scan.html b/tools/web_monitor/public/scan.html deleted file mode 100644 index 04335d02..00000000 --- a/tools/web_monitor/public/scan.html +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - - - Title - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tools/web_monitor/public/settings.html b/tools/web_monitor/public/settings.html deleted file mode 100644 index 3bd096cf..00000000 --- a/tools/web_monitor/public/settings.html +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - - - Title - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tools/web_monitor/static/index.js b/tools/web_monitor/static/index.js deleted file mode 100644 index 7c2402ae..00000000 --- a/tools/web_monitor/static/index.js +++ /dev/null @@ -1,53 +0,0 @@ -/* globals Chart:false, feather:false */ - -(function () { - 'use strict' - - feather.replace({ 'aria-hidden': 'true' }) - - // Graphs - var ctx = document.getElementById('myChart') - // eslint-disable-next-line no-unused-vars - var myChart = new Chart(ctx, { - type: 'line', - data: { - labels: [ - 'Sunday', - 'Monday', - 'Tuesday', - 'Wednesday', - 'Thursday', - 'Friday', - 'Saturday' - ], - datasets: [{ - data: [ - 15339, - 21345, - 18483, - 24003, - 23489, - 24092, - 12034 - ], - lineTension: 0, - backgroundColor: 'transparent', - borderColor: '#007bff', - borderWidth: 4, - pointBackgroundColor: '#007bff' - }] - }, - options: { - scales: { - yAxes: [{ - ticks: { - beginAtZero: false - } - }] - }, - legend: { - display: false - } - } - }) -})() diff --git a/tools/web_monitor/static/index.css b/tools/web_monitor/static/navbar.css similarity index 100% rename from tools/web_monitor/static/index.css rename to tools/web_monitor/static/navbar.css diff --git a/tools/web_monitor/templates/index.html b/tools/web_monitor/templates/index.html new file mode 100644 index 00000000..b83f025d --- /dev/null +++ b/tools/web_monitor/templates/index.html @@ -0,0 +1,4 @@ +{% extends 'navbar.html'%} +{% block content %} +

    Hi

    +{% endblock content %} diff --git a/tools/web_monitor/public/index.html b/tools/web_monitor/templates/navbar.html similarity index 96% rename from tools/web_monitor/public/index.html rename to tools/web_monitor/templates/navbar.html index 0298cca6..0293c1e4 100644 --- a/tools/web_monitor/public/index.html +++ b/tools/web_monitor/templates/navbar.html @@ -3,7 +3,7 @@ - + Title @@ -51,7 +51,7 @@
    From cf3163dccf67f4c952b56f8be2029e9399c9a0bb Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Fri, 25 Feb 2022 15:58:01 -0700 Subject: [PATCH 05/65] added the scan page to scan for miners on a subnet --- tools/web_monitor/app.py | 45 +++++++++++- tools/web_monitor/index.py | 7 -- tools/web_monitor/miner_factory.py | 7 ++ tools/web_monitor/templates/navbar.html | 4 +- tools/web_monitor/templates/scan.html | 96 +++++++++++++++++++++++++ 5 files changed, 147 insertions(+), 12 deletions(-) create mode 100644 tools/web_monitor/miner_factory.py create mode 100644 tools/web_monitor/templates/scan.html diff --git a/tools/web_monitor/app.py b/tools/web_monitor/app.py index 68aad1ec..a83e7d89 100644 --- a/tools/web_monitor/app.py +++ b/tools/web_monitor/app.py @@ -3,9 +3,11 @@ import asyncio import uvicorn from fastapi import FastAPI from fastapi import Request -from fastapi import WebSocket +from fastapi import WebSocket, WebSocketDisconnect from fastapi.templating import Jinja2Templates from fastapi.staticfiles import StaticFiles +from tools.web_monitor.miner_factory import miner_factory +from network import MinerNetwork app = FastAPI() @@ -13,10 +15,47 @@ app.mount("/static", StaticFiles(directory="static"), name="static") templates = Jinja2Templates(directory="templates") -@app.route("/") +@app.get("/") def dashboard(request: Request): return templates.TemplateResponse("index.html", {"request": request}) +@app.get("/scan") +def scan(request: Request): + return templates.TemplateResponse("scan.html", {"request": request}) + + +@app.websocket("/scan/ws") +async def websocket_scan(websocket: WebSocket): + await websocket.accept() + try: + while True: + network_ip = await websocket.receive_text() + if "/" in network_ip: + network_ip, network_subnet = network_ip.split("/") + network = MinerNetwork(network_ip, mask=network_subnet) + else: + network = MinerNetwork(network_ip) + miner_generator = network.scan_network_generator() + miners = [] + async for miner in miner_generator: + if miner: + miners.append(miner) + + get_miner_genenerator = miner_factory.get_miner_generator(miners) + all_miners = [] + async for found_miner in get_miner_genenerator: + all_miners.append({"ip": found_miner.ip, "model": await found_miner.get_model()}) + all_miners.sort(key=lambda x: x["ip"]) + send_miners = [] + for miner in all_miners: + send_miners.append({"ip": str(miner["ip"]), "model": miner["model"]}) + await websocket.send_json(send_miners) + + await websocket.send_text("Done") + except WebSocketDisconnect: + pass + + if __name__ == "__main__": - uvicorn.run("app:app", host="127.0.0.1", port=80, debug=True) + uvicorn.run("app:app", host="127.0.0.1", port=80) diff --git a/tools/web_monitor/index.py b/tools/web_monitor/index.py index d9e0388a..e69de29b 100644 --- a/tools/web_monitor/index.py +++ b/tools/web_monitor/index.py @@ -1,7 +0,0 @@ -from tools.web_monitor.app import sio - - -@sio.event -async def connect(sid, _environ) -> None: - """Event for connection""" - await sio.emit('init', "hello") diff --git a/tools/web_monitor/miner_factory.py b/tools/web_monitor/miner_factory.py new file mode 100644 index 00000000..157b743a --- /dev/null +++ b/tools/web_monitor/miner_factory.py @@ -0,0 +1,7 @@ +""" +This file stores the MinerFactory instance used by the WebMonitor for use in other files. +""" + +from miners.miner_factory import MinerFactory + +miner_factory = MinerFactory() diff --git a/tools/web_monitor/templates/navbar.html b/tools/web_monitor/templates/navbar.html index 0293c1e4..5a92c6a6 100644 --- a/tools/web_monitor/templates/navbar.html +++ b/tools/web_monitor/templates/navbar.html @@ -107,11 +107,11 @@ -
    +
    {% block content %} {% endblock content %} -
    +
    diff --git a/tools/web_monitor/templates/scan.html b/tools/web_monitor/templates/scan.html new file mode 100644 index 00000000..ba37ad45 --- /dev/null +++ b/tools/web_monitor/templates/scan.html @@ -0,0 +1,96 @@ +{% extends 'navbar.html'%} +{% block content %} +
    +
    +
    + Subnet + + +
    +
    +
    + +
    + + + + + + + + + + + + +
    + + IPModel
    +
    + + + + +{% endblock content %} From c8824f86afb2ae43ec44f004223df72bf13cc499 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Fri, 25 Feb 2022 16:11:06 -0700 Subject: [PATCH 06/65] fixed some formwatting on the scan page --- tools/web_monitor/templates/scan.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/web_monitor/templates/scan.html b/tools/web_monitor/templates/scan.html index ba37ad45..617776d0 100644 --- a/tools/web_monitor/templates/scan.html +++ b/tools/web_monitor/templates/scan.html @@ -5,14 +5,14 @@
    Subnet - +
    - + - + @@ -51,45 +51,53 @@ var ws = new WebSocket("ws://localhost:80/scan/ws"); ws.onmessage = function(event) { if (event.data == "Done") { + document.getElementById("scanButton").innerHTML = "Scan" + document.getElementById("scanButton").disabled = false document.getElementById("selectAllCheckbox").disabled = false document.getElementById("scanStatus").innerHTML = document.getElementById('minerTable').rows.length + " Miners" } else { - document.getElementById("selectAllCheckbox").disabled = true - document.getElementById("scanStatus").innerHTML = "Scanning..." + var miner_data = JSON.parse(event.data) + var miners = document.getElementById('minerTable') + miners.innerHTML = "" + miner_data.forEach(function(miner) { + console.log(miner) + var tr = document.createElement('tr') + + var checkbox_td = document.createElement('td') + checkbox_td.innerHTML = '' + checkbox_td.className = "active" + + var ip_td = document.createElement('td') + ip_td.innerHTML = miner["ip"] + + var model_td = document.createElement('td') + model_td.innerHTML = miner["model"] + + var empty_td = document.createElement('td') + + tr.append(checkbox_td) + tr.append(ip_td) + tr.append(model_td) + tr.append(empty_td) + + miners.append(tr) + }); }; - var miner_data = JSON.parse(event.data) - var miners = document.getElementById('minerTable') - miners.innerHTML = "" - miner_data.forEach(function(miner) { - console.log(miner) - var tr = document.createElement('tr') - - var checkbox_td = document.createElement('td') - checkbox_td.innerHTML = '' - checkbox_td.className = "active" - - var ip_td = document.createElement('td') - ip_td.innerHTML = miner["ip"] - - var model_td = document.createElement('td') - model_td.innerHTML = miner["model"] - - var empty_td = document.createElement('td') - - tr.append(checkbox_td) - tr.append(ip_td) - tr.append(model_td) - tr.append(empty_td) - - miners.append(tr) - }); }; function sendMessage(event) { var input = document.getElementById("messageText") + var miners = document.getElementById('minerTable') + miners.innerHTML = "" document.getElementById("scanStatus").innerHTML = "Scanning..." - ws.send(input.value) - input.value = '' - event.preventDefault() + document.getElementById("scanButton").innerHTML = "Scanning..." + document.getElementById("scanButton").disabled = true + document.getElementById("selectAllCheckbox").disabled = true + if (input.value != "") { + ws.send(input.value) + event.preventDefault() + } else { + ws.send("192.168.1.0/24") + }; } From d9f8f53a10dbc17be16c365bfc7058106a9dabb2 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Mon, 28 Feb 2022 15:15:57 -0700 Subject: [PATCH 08/65] added add selected miners button --- tools/web_monitor/app.py | 68 ++++++++++++++++++--------- tools/web_monitor/templates/scan.html | 24 +++++++++- 2 files changed, 69 insertions(+), 23 deletions(-) diff --git a/tools/web_monitor/app.py b/tools/web_monitor/app.py index 3cf512c0..603f8cc9 100644 --- a/tools/web_monitor/app.py +++ b/tools/web_monitor/app.py @@ -25,37 +25,63 @@ def scan(request: Request): return templates.TemplateResponse("scan.html", {"request": request}) +@app.post("/scan/add_miners") +def add_miners_scan(request: Request): + print(request) + return scan + + @app.websocket("/scan/ws") async def websocket_scan(websocket: WebSocket): await websocket.accept() + cur_task = None try: while True: - network_ip = await websocket.receive_text() - if "/" in network_ip: - network_ip, network_subnet = network_ip.split("/") - network = MinerNetwork(network_ip, mask=network_subnet) + ws_data = await websocket.receive_text() + if "-Cancel-" in ws_data: + if cur_task: + cur_task.cancel() + try: + await cur_task + except asyncio.CancelledError: + cur_task = None + await websocket.send_text("Cancelled") else: - network = MinerNetwork(network_ip) - miner_generator = network.scan_network_generator() - miners = [] - async for miner in miner_generator: - if miner: - miners.append(miner) - - get_miner_genenerator = miner_factory.get_miner_generator(miners) - all_miners = [] - async for found_miner in get_miner_genenerator: - all_miners.append({"ip": found_miner.ip, "model": await found_miner.get_model()}) - all_miners.sort(key=lambda x: x["ip"]) - send_miners = [] - for miner in all_miners: - send_miners.append({"ip": str(miner["ip"]), "model": miner["model"]}) - await websocket.send_json(send_miners) - await websocket.send_text("Done") + cur_task = asyncio.create_task(do_websocket_scan(websocket, ws_data)) + if cur_task and cur_task.done(): + cur_task = None except WebSocketDisconnect: print("Websocket disconnected.") pass +async def do_websocket_scan(websocket: WebSocket, network_ip: str): + try: + if "/" in network_ip: + network_ip, network_subnet = network_ip.split("/") + network = MinerNetwork(network_ip, mask=network_subnet) + else: + network = MinerNetwork(network_ip) + miner_generator = network.scan_network_generator() + miners = [] + async for miner in miner_generator: + if miner: + miners.append(miner) + + get_miner_genenerator = miner_factory.get_miner_generator(miners) + all_miners = [] + async for found_miner in get_miner_genenerator: + all_miners.append( + {"ip": found_miner.ip, "model": await found_miner.get_model()}) + all_miners.sort(key=lambda x: x["ip"]) + send_miners = [] + for miner in all_miners: + send_miners.append( + {"ip": str(miner["ip"]), "model": miner["model"]}) + await websocket.send_json(send_miners) + await websocket.send_text("Done") + except asyncio.CancelledError: + raise + if __name__ == "__main__": uvicorn.run("app:app", host="127.0.0.1", port=80) diff --git a/tools/web_monitor/templates/scan.html b/tools/web_monitor/templates/scan.html index dc1ac58c..f5d24cce 100644 --- a/tools/web_monitor/templates/scan.html +++ b/tools/web_monitor/templates/scan.html @@ -5,11 +5,16 @@
    Subnet - + +
    +
    + +
    +
    From 6b3e525f459a4625b6a7e1776c0af4b0bb6c61a0 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Mon, 28 Feb 2022 14:10:43 -0700 Subject: [PATCH 07/65] improved formatting on scan page and made the scan a bit more robust --- tools/web_monitor/app.py | 2 +- tools/web_monitor/templates/scan.html | 76 +++++++++++++++------------ 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/tools/web_monitor/app.py b/tools/web_monitor/app.py index a83e7d89..3cf512c0 100644 --- a/tools/web_monitor/app.py +++ b/tools/web_monitor/app.py @@ -51,9 +51,9 @@ async def websocket_scan(websocket: WebSocket): for miner in all_miners: send_miners.append({"ip": str(miner["ip"]), "model": miner["model"]}) await websocket.send_json(send_miners) - await websocket.send_text("Done") except WebSocketDisconnect: + print("Websocket disconnected.") pass diff --git a/tools/web_monitor/templates/scan.html b/tools/web_monitor/templates/scan.html index 617776d0..dc1ac58c 100644 --- a/tools/web_monitor/templates/scan.html +++ b/tools/web_monitor/templates/scan.html @@ -4,8 +4,8 @@
    Subnet - - + +
    @@ -19,7 +19,7 @@
    IP Model0 Miners
    @@ -55,6 +60,13 @@ document.getElementById("scanButton").disabled = false document.getElementById("selectAllCheckbox").disabled = false document.getElementById("scanStatus").innerHTML = document.getElementById('minerTable').rows.length + " Miners" + document.getElementById("cancelButton").style = "display:none;" + } else if (event.data == "Cancelled") { + document.getElementById("scanButton").innerHTML = "Scan" + document.getElementById("scanButton").disabled = false + document.getElementById("selectAllCheckbox").disabled = false + document.getElementById("scanStatus").innerHTML = document.getElementById('minerTable').rows.length + " Miners" + document.getElementById("cancelButton").style = "display:none;" } else { var miner_data = JSON.parse(event.data) var miners = document.getElementById('minerTable') @@ -84,7 +96,7 @@ }); }; }; - function sendMessage(event) { + function scanMiners(event) { var input = document.getElementById("messageText") var miners = document.getElementById('minerTable') miners.innerHTML = "" @@ -92,6 +104,7 @@ document.getElementById("scanButton").innerHTML = "Scanning..." document.getElementById("scanButton").disabled = true document.getElementById("selectAllCheckbox").disabled = true + document.getElementById("cancelButton").style = "" if (input.value != "") { ws.send(input.value) event.preventDefault() @@ -99,6 +112,13 @@ ws.send("192.168.1.0/24") }; } + function cancelScan(event) { + document.getElementById("scanStatus").innerHTML = "Canceling..." + document.getElementById("scanButton").innerHTML = "Canceling..." + document.getElementById("cancelButton").style = "display:none;" + ws.send("-Cancel-") + } + {% endblock content %} From 3ae29c3883c3352572ac89b9c91ee0db7f22b2a9 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Mon, 28 Feb 2022 16:28:40 -0700 Subject: [PATCH 09/65] added basic addition of miners to the list and improved some functionality of the web tool --- tools/web_monitor/app.py | 4 ++-- tools/web_monitor/templates/scan.html | 28 +++++++++++++++++++++------ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/tools/web_monitor/app.py b/tools/web_monitor/app.py index 603f8cc9..4c11ca3c 100644 --- a/tools/web_monitor/app.py +++ b/tools/web_monitor/app.py @@ -26,8 +26,8 @@ def scan(request: Request): @app.post("/scan/add_miners") -def add_miners_scan(request: Request): - print(request) +async def add_miners_scan(request: Request): + print(await request.json()) return scan diff --git a/tools/web_monitor/templates/scan.html b/tools/web_monitor/templates/scan.html index f5d24cce..f2648943 100644 --- a/tools/web_monitor/templates/scan.html +++ b/tools/web_monitor/templates/scan.html @@ -12,7 +12,7 @@
    - +
    @@ -53,6 +53,9 @@ }); {% endblock content %} From 19ee9eb18f2fdd280420c9d52f84dea773bfa592 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Tue, 1 Mar 2022 11:30:48 -0700 Subject: [PATCH 10/65] further improved formatting of scan page, added disabled checkboxes on scan, updated miner count on add --- tools/web_monitor/templates/scan.html | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tools/web_monitor/templates/scan.html b/tools/web_monitor/templates/scan.html index f2648943..18363cb7 100644 --- a/tools/web_monitor/templates/scan.html +++ b/tools/web_monitor/templates/scan.html @@ -64,12 +64,14 @@ document.getElementById("selectAllCheckbox").disabled = false document.getElementById("scanStatus").innerHTML = document.getElementById('minerTable').rows.length + " Miners" document.getElementById("cancelButton").style = "display:none;" + enableCheckboxes(); } else if (event.data == "Cancelled") { document.getElementById("scanButton").innerHTML = "Scan" document.getElementById("scanButton").disabled = false document.getElementById("selectAllCheckbox").disabled = false document.getElementById("scanStatus").innerHTML = document.getElementById('minerTable').rows.length + " Miners" document.getElementById("cancelButton").style = "display:none;" + enableCheckboxes(); } else { var miner_data = JSON.parse(event.data) var miners = document.getElementById('minerTable') @@ -97,6 +99,7 @@ miners.append(tr) }); + disableCheckboxes(); }; }; function scanMiners(event) { @@ -123,7 +126,7 @@ }; function addMiners(event) { var checkedBoxes = document.querySelectorAll('input[name=minerCheckboxes]:checked'); - if !(checkedBoxes.length == 0) { + if (checkedBoxes.length != 0) { var minerList = []; for (i = 0; i< checkedBoxes.length; i++) { minerList.push(checkedBoxes[i].defaultValue); @@ -133,6 +136,19 @@ var tr_to_remove = document.getElementById(minerList[i]) tr_to_remove.remove() } + document.getElementById("scanStatus").innerHTML = document.getElementById('minerTable').rows.length + " Miners" + }; + }; + function disableCheckboxes() { + var checkBoxes = document.querySelectorAll('input[name=minerCheckboxes]'); + for (i = 0; i< checkBoxes.length; i++) { + checkBoxes[i].disabled = true + }; + }; + function enableCheckboxes() { + var checkBoxes = document.querySelectorAll('input[name=minerCheckboxes]'); + for (i = 0; i< checkBoxes.length; i++) { + checkBoxes[i].disabled = false }; }; From a72c4f779700e3bc914756972632699cda18423d Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Tue, 1 Mar 2022 12:28:36 -0700 Subject: [PATCH 11/65] finished up scan page, added the ability to add miners and them get listed in the miner list, and started adding the individual miner pages --- tools/web_monitor/app.py | 36 ++++++++++++++++++++++--- tools/web_monitor/static/navbar.css | 19 +++++++++++++ tools/web_monitor/templates/navbar.html | 28 +++++++------------ 3 files changed, 60 insertions(+), 23 deletions(-) diff --git a/tools/web_monitor/app.py b/tools/web_monitor/app.py index 4c11ca3c..edce3070 100644 --- a/tools/web_monitor/app.py +++ b/tools/web_monitor/app.py @@ -1,4 +1,5 @@ import json +import os import asyncio import uvicorn from fastapi import FastAPI @@ -17,17 +18,43 @@ templates = Jinja2Templates(directory="templates") @app.get("/") def dashboard(request: Request): - return templates.TemplateResponse("index.html", {"request": request}) + return templates.TemplateResponse("index.html", { + "request": request, + "cur_miners": get_current_miner_list() + }) @app.get("/scan") def scan(request: Request): - return templates.TemplateResponse("scan.html", {"request": request}) + return templates.TemplateResponse("scan.html", { + "request": request, + "cur_miners": get_current_miner_list() + }) + + +@app.get("/miner") +def miner(request: Request, miner_ip): + return get_miner + +@app.get("/miner/{miner_ip}") +def get_miner(request: Request, miner_ip): + return miner_ip + +def get_current_miner_list(): + cur_miners = [] + if os.path.exists(os.path.join(os.getcwd(), "miner_list.txt")): + with open(os.path.join(os.getcwd(), "miner_list.txt")) as file: + for line in file.readlines(): + cur_miners.append(line.strip()) + return cur_miners @app.post("/scan/add_miners") async def add_miners_scan(request: Request): - print(await request.json()) + miners = await request.json() + with open("miner_list.txt", "a+") as file: + for miner in miners["miners"]: + file.write(miner + "\n") return scan @@ -56,6 +83,7 @@ async def websocket_scan(websocket: WebSocket): async def do_websocket_scan(websocket: WebSocket, network_ip: str): + cur_miners = get_current_miner_list() try: if "/" in network_ip: network_ip, network_subnet = network_ip.split("/") @@ -65,7 +93,7 @@ async def do_websocket_scan(websocket: WebSocket, network_ip: str): miner_generator = network.scan_network_generator() miners = [] async for miner in miner_generator: - if miner: + if miner and str(miner) not in cur_miners: miners.append(miner) get_miner_genenerator = miner_factory.get_miner_generator(miners) diff --git a/tools/web_monitor/static/navbar.css b/tools/web_monitor/static/navbar.css index 388b1403..8e8e0091 100644 --- a/tools/web_monitor/static/navbar.css +++ b/tools/web_monitor/static/navbar.css @@ -130,3 +130,22 @@ main { border-color: transparent; box-shadow: 0 0 0 3px rgba(255, 255, 255, .25); } + +.btn-toggle-nav{ + max-height: 300px; + -webkit-overflow-scrolling: touch; +} + +/* Scrollbar */ +.btn-toggle-nav::-webkit-scrollbar { + width: 5px; +} +.btn-toggle-nav::-webkit-scrollbar-track { + box-shadow: inset 0 0 5px grey; + border-radius: 10px; +} +.btn-toggle-nav::-webkit-scrollbar-thumb { + background-image: linear-gradient(180deg, #D0368A 0%, #708AD4 99%); + box-shadow: inset 2px 2px 5px 0 rgba(#fff, 0.5); + border-radius: 100px; +} diff --git a/tools/web_monitor/templates/navbar.html b/tools/web_monitor/templates/navbar.html index 5a92c6a6..0f62b115 100644 --- a/tools/web_monitor/templates/navbar.html +++ b/tools/web_monitor/templates/navbar.html @@ -70,25 +70,15 @@ Miners
    -
    From 2c2648cbe7a9767514058e5af61b7f8ecbd1479a Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Tue, 1 Mar 2022 12:51:49 -0700 Subject: [PATCH 12/65] improved navbar formatting, added active formats for all miners, moved add miners to a miner subtab --- tools/web_monitor/app.py | 8 +++++++- tools/web_monitor/templates/miner.html | 4 ++++ tools/web_monitor/templates/navbar.html | 20 +++++++++----------- 3 files changed, 20 insertions(+), 12 deletions(-) create mode 100644 tools/web_monitor/templates/miner.html diff --git a/tools/web_monitor/app.py b/tools/web_monitor/app.py index edce3070..d35f94c7 100644 --- a/tools/web_monitor/app.py +++ b/tools/web_monitor/app.py @@ -36,9 +36,15 @@ def scan(request: Request): def miner(request: Request, miner_ip): return get_miner + @app.get("/miner/{miner_ip}") def get_miner(request: Request, miner_ip): - return miner_ip + return templates.TemplateResponse("miner.html", { + "request": request, + "cur_miners": get_current_miner_list(), + "miner": miner_ip + }) + def get_current_miner_list(): cur_miners = [] diff --git a/tools/web_monitor/templates/miner.html b/tools/web_monitor/templates/miner.html new file mode 100644 index 00000000..fb10f31f --- /dev/null +++ b/tools/web_monitor/templates/miner.html @@ -0,0 +1,4 @@ +{% extends 'navbar.html'%} +{% block content %} +{{miner}} +{% endblock content %} diff --git a/tools/web_monitor/templates/navbar.html b/tools/web_monitor/templates/navbar.html index 0f62b115..1ddf4212 100644 --- a/tools/web_monitor/templates/navbar.html +++ b/tools/web_monitor/templates/navbar.html @@ -51,29 +51,27 @@
    @@ -58,6 +58,18 @@ ws.onmessage = function(event) { if (minerDataChart.data.datasets[0].data.length > 50) minerDataChart.data.datasets[0].data.shift(); minerDataChart.data.labels.push(datetime.toLocaleString(luxon.DateTime.TIME_WITH_SECONDS)); minerDataChart.data.datasets[0].data.push(new_data["hashrate"]); + fan1Chart.data.datasets[0].data = [new_data["fans"][0], 6000-new_data["fans"][0]] + fan2Chart.data.datasets[0].data = [new_data["fans"][1], 6000-new_data["fans"][1]] + fan3Chart.data.datasets[0].data = [new_data["fans"][2], 6000-new_data["fans"][2]] + fan4Chart.data.datasets[0].data = [new_data["fans"][3], 6000-new_data["fans"][3]] + document.getElementById("fan1").innerHTML = "Fan 1: " + new_data["fans"][0] + document.getElementById("fan2").innerHTML = "Fan 2: " + new_data["fans"][1] + document.getElementById("fan3").innerHTML = "Fan 3: " + new_data["fans"][2] + document.getElementById("fan4").innerHTML = "Fan 4: " + new_data["fans"][3] + fan1Chart.update(); + fan2Chart.update(); + fan3Chart.update(); + fan4Chart.update(); minerDataChart.update(); }; }; @@ -144,7 +156,7 @@ var options_fans = { var fanCtx = document.getElementById("fan-chart-1").getContext("2d"); var fanWidth = document.getElementById("fan-chart-1").width; -var fanChartGradient = fanCtx.createLinearGradient(0, 0, fanWidth, -(1/2)*fanWidth) +var fanChartGradient = fanCtx.createLinearGradient(0, 0, fanWidth, -fanWidth) fanChartGradient.addColorStop(0, '#D0368A'); fanChartGradient.addColorStop(1, '#708AD4'); @@ -155,7 +167,7 @@ var fan1Chart = new Chart(document.getElementById("fan-chart-1"), { labels: ["Fan 1"], datasets: [ { - data: [100, 100], + data: [0, 6000], // add colors backgroundColor: [ fanChartGradient, @@ -172,7 +184,7 @@ var fan2Chart = new Chart(document.getElementById("fan-chart-2"), { labels: ["Fan 2"], datasets: [ { - data: [300, 100], + data: [0, 6000], // add colors backgroundColor: [ fanChartGradient, @@ -189,7 +201,7 @@ var fan3Chart = new Chart(document.getElementById("fan-chart-3"), { labels: ["Fan 3"], datasets: [ { - data: [200, 100], + data: [0, 6000], // add colors backgroundColor: [ fanChartGradient, @@ -206,7 +218,7 @@ var fan4Chart = new Chart(document.getElementById("fan-chart-4"), { labels: ["Fan 4"], datasets: [ { - data: [500, 100], + data: [0, 6000], // add colors backgroundColor: [ fanChartGradient, From 5f355c833bc7d45f7bbf302e2c212311d2a73ead Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Wed, 2 Mar 2022 15:38:29 -0700 Subject: [PATCH 21/65] added fan and hashrate data for S19s and Whatsminers --- tools/web_monitor/app.py | 47 ++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/tools/web_monitor/app.py b/tools/web_monitor/app.py index 51700976..11dfb1a9 100644 --- a/tools/web_monitor/app.py +++ b/tools/web_monitor/app.py @@ -47,21 +47,42 @@ async def miner_websocket(websocket: WebSocket, miner_ip): try: cur_miner = await asyncio.wait_for(miner_factory.get_miner(str(miner_ip)), 5) - data = await asyncio.wait_for(cur_miner.api.multicommand("summary", "fans"), 5) + data = await asyncio.wait_for(cur_miner.api.multicommand("summary", "fans", "stats"), 5) - miner_summary = data["summary"][0] + miner_summary = None + miner_stats = None miner_fans = None + if "summary" in data.keys(): + miner_summary = data["summary"][0] + elif "SUMMARY" in data.keys(): + miner_summary = data + miner_fans = {"FANS": []} + for item in ["Fan Speed In", "Fan Speed Out"]: + if item in miner_summary["SUMMARY"][0].keys(): + miner_fans["FANS"].append({"RPM": miner_summary["SUMMARY"][0][item]}) + if "fans" in data.keys(): miner_fans = data["fans"][0] - if 'MHS av' in miner_summary['SUMMARY'][0].keys(): - hashrate = format( - round(miner_summary['SUMMARY'][0]['MHS av'] / 1000000, - 2), ".2f") - elif 'GHS av' in miner_summary['summary'][0]['SUMMARY'][0].keys(): - hashrate = format( - round(miner_summary['SUMMARY'][0]['GHS av'] / 1000, 2), - ".2f") + if "stats" in data.keys(): + miner_stats = data["stats"][0] + miner_fans = {"FANS": []} + for item in ["fan1", "fan2", "fan3", "fan4"]: + if item in miner_stats["STATS"][1].keys(): + miner_fans["FANS"].append({"RPM": miner_stats["STATS"][1][item]}) + + + if miner_summary: + if 'MHS av' in miner_summary['SUMMARY'][0].keys(): + hashrate = format( + round(miner_summary['SUMMARY'][0]['MHS av'] / 1000000, + 2), ".2f") + elif 'GHS av' in miner_summary['SUMMARY'][0].keys(): + hashrate = format( + round(miner_summary['SUMMARY'][0]['GHS av'] / 1000, 2), + ".2f") + else: + hashrate = 0 else: hashrate = 0 @@ -71,6 +92,9 @@ async def miner_websocket(websocket: WebSocket, miner_ip): for fan in miner_fans["FANS"]: fan_speeds.append(fan["RPM"]) + while len(fan_speeds) < 5: + fan_speeds.append(0) + data = {"hashrate": hashrate, "fans": fan_speeds, @@ -81,7 +105,8 @@ async def miner_websocket(websocket: WebSocket, miner_ip): data = {"error": "The miner is not responding."} await websocket.send_json(data) await asyncio.sleep(.5) - except KeyError: + except KeyError as e: + print(e) data = {"error": "The miner returned incorrect data."} await websocket.send_json(data) await asyncio.sleep(.5) From 1db15a741eab7143ea9a0b227e8f17a0bd80eaae Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Wed, 2 Mar 2022 15:47:17 -0700 Subject: [PATCH 22/65] added spinner to scan --- tools/web_monitor/templates/scan.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/web_monitor/templates/scan.html b/tools/web_monitor/templates/scan.html index 18363cb7..3708dfaf 100644 --- a/tools/web_monitor/templates/scan.html +++ b/tools/web_monitor/templates/scan.html @@ -106,8 +106,8 @@ var input = document.getElementById("messageText") var miners = document.getElementById('minerTable') miners.innerHTML = "" - document.getElementById("scanStatus").innerHTML = "Scanning..." - document.getElementById("scanButton").innerHTML = "Scanning..." + document.getElementById("scanStatus").innerHTML = " Scanning" + document.getElementById("scanButton").innerHTML = " Scanning" document.getElementById("scanButton").disabled = true document.getElementById("selectAllCheckbox").disabled = true document.getElementById("cancelButton").style = "" From b66cf6f0bae71fe79d408463f49d8698152bfc7e Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Wed, 2 Mar 2022 15:54:49 -0700 Subject: [PATCH 23/65] added different select gradient --- tools/web_monitor/static/navbar.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/web_monitor/static/navbar.css b/tools/web_monitor/static/navbar.css index 3f3c7465..569caa00 100644 --- a/tools/web_monitor/static/navbar.css +++ b/tools/web_monitor/static/navbar.css @@ -155,7 +155,7 @@ main { } .nav-link:hover { - background-image: linear-gradient(180deg, #D0368A 0%, #708AD4 99%); + background-image: linear-gradient(180deg, #760A45 0%, #23449F 99%); } .nav-link { From 58cc64d17b6abde97132aa5dfff3d5eda801cfe7 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Fri, 4 Mar 2022 11:24:06 -0700 Subject: [PATCH 24/65] strated on basic framework for dashboard in web_monitor --- tools/web_monitor/app.py | 63 +++++++++++++++++++++++-- tools/web_monitor/static/navbar.css | 1 + tools/web_monitor/templates/index.html | 46 +++++++++++++++++- tools/web_monitor/templates/navbar.html | 8 ++-- 4 files changed, 109 insertions(+), 9 deletions(-) diff --git a/tools/web_monitor/app.py b/tools/web_monitor/app.py index 11dfb1a9..767b0eca 100644 --- a/tools/web_monitor/app.py +++ b/tools/web_monitor/app.py @@ -4,6 +4,7 @@ import datetime import os import asyncio import uvicorn +import websockets.exceptions from fastapi import FastAPI from fastapi import Request from fastapi import WebSocket, WebSocketDisconnect @@ -19,6 +20,11 @@ templates = Jinja2Templates(directory="templates") @app.get("/") +def index(): + return dashboard() + + +@app.get("/dashboard") def dashboard(request: Request): return templates.TemplateResponse("index.html", { "request": request, @@ -26,6 +32,57 @@ def dashboard(request: Request): }) +@app.websocket("/dashboard/ws") +async def dashboard_websocket(websocket: WebSocket): + await websocket.accept() + try: + while True: + miners = get_current_miner_list() + all_miner_data = [] + data_gen = asyncio.as_completed([get_miner_data_dashboard(miner) for miner in miners]) + for all_data in data_gen: + data_point = await all_data + all_miner_data.append(data_point) + all_miner_data.sort(key=lambda x: x["ip"]) + try: + await websocket.send_json({"datetime": datetime.datetime.now().isoformat(), + "miners": all_miner_data}) + except websockets.exceptions.ConnectionClosedOK: + print("disconnected") + await asyncio.sleep(5) + except WebSocketDisconnect: + print("Websocket disconnected.") + pass + + +async def get_miner_data_dashboard(miner_ip): + try: + miner = await asyncio.wait_for(miner_factory.get_miner(miner_ip), 5) + + miner_summary = await asyncio.wait_for(miner.api.summary(), 5) + if miner_summary: + if 'MHS av' in miner_summary['SUMMARY'][0].keys(): + hashrate = format( + round(miner_summary['SUMMARY'][0]['MHS av'] / 1000000, + 2), ".2f") + elif 'GHS av' in miner_summary['SUMMARY'][0].keys(): + hashrate = format( + round(miner_summary['SUMMARY'][0]['GHS av'] / 1000, 2), + ".2f") + else: + hashrate = 0 + else: + hashrate = 0 + + return {"ip": str(miner.ip), "hashrate": hashrate} + + except asyncio.exceptions.TimeoutError: + return {"ip": miner_ip, "error": "The miner is not responding."} + + except KeyError: + return {"ip": miner_ip, "error": "The miner returned unusable/unsupported data."} + + @app.get("/scan") def scan(request: Request): return templates.TemplateResponse("scan.html", { @@ -35,7 +92,7 @@ def scan(request: Request): @app.get("/miner") -def miner(request: Request, miner_ip): +def miner(_request: Request, _miner_ip): return get_miner @@ -71,7 +128,6 @@ async def miner_websocket(websocket: WebSocket, miner_ip): if item in miner_stats["STATS"][1].keys(): miner_fans["FANS"].append({"RPM": miner_stats["STATS"][1][item]}) - if miner_summary: if 'MHS av' in miner_summary['SUMMARY'][0].keys(): hashrate = format( @@ -95,7 +151,6 @@ async def miner_websocket(websocket: WebSocket, miner_ip): while len(fan_speeds) < 5: fan_speeds.append(0) - data = {"hashrate": hashrate, "fans": fan_speeds, "datetime": datetime.datetime.now().isoformat()} @@ -107,7 +162,7 @@ async def miner_websocket(websocket: WebSocket, miner_ip): await asyncio.sleep(.5) except KeyError as e: print(e) - data = {"error": "The miner returned incorrect data."} + data = {"error": "The miner returned unusable/unsupported data."} await websocket.send_json(data) await asyncio.sleep(.5) except WebSocketDisconnect: diff --git a/tools/web_monitor/static/navbar.css b/tools/web_monitor/static/navbar.css index 569caa00..1d582b38 100644 --- a/tools/web_monitor/static/navbar.css +++ b/tools/web_monitor/static/navbar.css @@ -151,6 +151,7 @@ main { } .nav-pills .nav-link.active { + color: #212529; background-image: linear-gradient(180deg, #D0368A 0%, #708AD4 99%); } diff --git a/tools/web_monitor/templates/index.html b/tools/web_monitor/templates/index.html index b83f025d..8bed0a8b 100644 --- a/tools/web_monitor/templates/index.html +++ b/tools/web_monitor/templates/index.html @@ -1,4 +1,48 @@ {% extends 'navbar.html'%} {% block content %} -

    Hi

    +
    + +
    + + + + +
    + + + {% endblock content %} diff --git a/tools/web_monitor/templates/navbar.html b/tools/web_monitor/templates/navbar.html index 1ddf4212..d2037c09 100644 --- a/tools/web_monitor/templates/navbar.html +++ b/tools/web_monitor/templates/navbar.html @@ -51,27 +51,27 @@
    -
    -
    -

    hi

    -
    +
    + - - +
    diff --git a/tools/web_monitor/public/scan.html b/tools/web_monitor/public/scan.html new file mode 100644 index 00000000..04335d02 --- /dev/null +++ b/tools/web_monitor/public/scan.html @@ -0,0 +1,115 @@ + + + + + + + + Title + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/web_monitor/public/settings.html b/tools/web_monitor/public/settings.html new file mode 100644 index 00000000..3bd096cf --- /dev/null +++ b/tools/web_monitor/public/settings.html @@ -0,0 +1,115 @@ + + + + + + + + Title + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tools/web_monitor/static/index.css b/tools/web_monitor/static/index.css index 42b64d41..388b1403 100644 --- a/tools/web_monitor/static/index.css +++ b/tools/web_monitor/static/index.css @@ -47,3 +47,86 @@ main { } .fw-semibold { font-weight: 600; } + +.sidebar { + position: fixed; + top: 0; + /* rtl:raw: + right: 0; + */ + bottom: 0; + /* rtl:remove */ + left: 0; + z-index: 100; /* Behind the navbar */ + padding: 0px 0 0; /* Height of navbar */ + box-shadow: inset -1px 0 0 rgba(0, 0, 0, .1); +} + +@media (max-width: 767.98px) { + .sidebar { + top: 48px; + } +} + +.sidebar-sticky { + position: relative; + top: 0; + height: calc(100vh - 48px); + padding-top: .5rem; + overflow-x: hidden; + overflow-y: auto; +} + +.sidebar .nav-link { + font-weight: 500; + color: #333; +} + +.sidebar .nav-link .feather { + margin-right: 4px; + color: #727272; +} + +.sidebar .nav-link.active { + color: #2470dc; +} + +.sidebar .nav-link:hover .feather, +.sidebar .nav-link.active .feather { + color: inherit; +} + +.sidebar-heading { + font-size: .75rem; + text-transform: uppercase; +} + +.navbar-brand { + padding-top: .75rem; + padding-bottom: .75rem; + font-size: 1rem; + background-color: rgba(0, 0, 0, .25); + box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25); +} + +.navbar .navbar-toggler { + top: .25rem; + right: 1rem; +} + +.navbar .form-control { + padding: .75rem 1rem; + border-width: 0; + border-radius: 0; +} + +.form-control-dark { + color: #fff; + background-color: rgba(255, 255, 255, .1); + border-color: rgba(255, 255, 255, .1); +} + +.form-control-dark:focus { + border-color: transparent; + box-shadow: 0 0 0 3px rgba(255, 255, 255, .25); +} diff --git a/tools/web_monitor/static/index.js b/tools/web_monitor/static/index.js new file mode 100644 index 00000000..7c2402ae --- /dev/null +++ b/tools/web_monitor/static/index.js @@ -0,0 +1,53 @@ +/* globals Chart:false, feather:false */ + +(function () { + 'use strict' + + feather.replace({ 'aria-hidden': 'true' }) + + // Graphs + var ctx = document.getElementById('myChart') + // eslint-disable-next-line no-unused-vars + var myChart = new Chart(ctx, { + type: 'line', + data: { + labels: [ + 'Sunday', + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday' + ], + datasets: [{ + data: [ + 15339, + 21345, + 18483, + 24003, + 23489, + 24092, + 12034 + ], + lineTension: 0, + backgroundColor: 'transparent', + borderColor: '#007bff', + borderWidth: 4, + pointBackgroundColor: '#007bff' + }] + }, + options: { + scales: { + yAxes: [{ + ticks: { + beginAtZero: false + } + }] + }, + legend: { + display: false + } + } + }) +})() From 92a65c89777d3cb77a7c0dfec0675b3698696edf Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Thu, 24 Feb 2022 15:59:48 -0700 Subject: [PATCH 35/65] switched to fastAPi and jinja 2 for templates and html --- tools/web_monitor/app.py | 29 +++-- tools/web_monitor/public/scan.html | 115 ------------------ tools/web_monitor/public/settings.html | 115 ------------------ tools/web_monitor/static/index.js | 53 -------- .../static/{index.css => navbar.css} | 0 tools/web_monitor/templates/index.html | 4 + .../index.html => templates/navbar.html} | 7 +- 7 files changed, 27 insertions(+), 296 deletions(-) delete mode 100644 tools/web_monitor/public/scan.html delete mode 100644 tools/web_monitor/public/settings.html delete mode 100644 tools/web_monitor/static/index.js rename tools/web_monitor/static/{index.css => navbar.css} (100%) create mode 100644 tools/web_monitor/templates/index.html rename tools/web_monitor/{public/index.html => templates/navbar.html} (96%) diff --git a/tools/web_monitor/app.py b/tools/web_monitor/app.py index 401835ad..68aad1ec 100644 --- a/tools/web_monitor/app.py +++ b/tools/web_monitor/app.py @@ -1,15 +1,22 @@ -import socketio -from sanic import Sanic +import json +import asyncio +import uvicorn +from fastapi import FastAPI +from fastapi import Request +from fastapi import WebSocket +from fastapi.templating import Jinja2Templates +from fastapi.staticfiles import StaticFiles -app = Sanic("App") +app = FastAPI() -# attach socketio -sio = socketio.AsyncServer(async_mode="sanic") -sio.attach(app) +app.mount("/static", StaticFiles(directory="static"), name="static") +templates = Jinja2Templates(directory="templates") -app.static('/', "./public/index.html") -app.static('/index.css', "./static/index.css") -app.static('/index.js', "./static/index.js") -app.static('/scan', "./public/scan.html") -app.static('/settings', "./public/settings.html") +@app.route("/") +def dashboard(request: Request): + return templates.TemplateResponse("index.html", {"request": request}) + + +if __name__ == "__main__": + uvicorn.run("app:app", host="127.0.0.1", port=80, debug=True) diff --git a/tools/web_monitor/public/scan.html b/tools/web_monitor/public/scan.html deleted file mode 100644 index 04335d02..00000000 --- a/tools/web_monitor/public/scan.html +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - - - Title - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tools/web_monitor/public/settings.html b/tools/web_monitor/public/settings.html deleted file mode 100644 index 3bd096cf..00000000 --- a/tools/web_monitor/public/settings.html +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - - - Title - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tools/web_monitor/static/index.js b/tools/web_monitor/static/index.js deleted file mode 100644 index 7c2402ae..00000000 --- a/tools/web_monitor/static/index.js +++ /dev/null @@ -1,53 +0,0 @@ -/* globals Chart:false, feather:false */ - -(function () { - 'use strict' - - feather.replace({ 'aria-hidden': 'true' }) - - // Graphs - var ctx = document.getElementById('myChart') - // eslint-disable-next-line no-unused-vars - var myChart = new Chart(ctx, { - type: 'line', - data: { - labels: [ - 'Sunday', - 'Monday', - 'Tuesday', - 'Wednesday', - 'Thursday', - 'Friday', - 'Saturday' - ], - datasets: [{ - data: [ - 15339, - 21345, - 18483, - 24003, - 23489, - 24092, - 12034 - ], - lineTension: 0, - backgroundColor: 'transparent', - borderColor: '#007bff', - borderWidth: 4, - pointBackgroundColor: '#007bff' - }] - }, - options: { - scales: { - yAxes: [{ - ticks: { - beginAtZero: false - } - }] - }, - legend: { - display: false - } - } - }) -})() diff --git a/tools/web_monitor/static/index.css b/tools/web_monitor/static/navbar.css similarity index 100% rename from tools/web_monitor/static/index.css rename to tools/web_monitor/static/navbar.css diff --git a/tools/web_monitor/templates/index.html b/tools/web_monitor/templates/index.html new file mode 100644 index 00000000..b83f025d --- /dev/null +++ b/tools/web_monitor/templates/index.html @@ -0,0 +1,4 @@ +{% extends 'navbar.html'%} +{% block content %} +

    Hi

    +{% endblock content %} diff --git a/tools/web_monitor/public/index.html b/tools/web_monitor/templates/navbar.html similarity index 96% rename from tools/web_monitor/public/index.html rename to tools/web_monitor/templates/navbar.html index 0298cca6..0293c1e4 100644 --- a/tools/web_monitor/public/index.html +++ b/tools/web_monitor/templates/navbar.html @@ -3,7 +3,7 @@ - + Title @@ -51,7 +51,7 @@
    From e37e9e22517536aa51a287e2a559c677e9e611a2 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Fri, 25 Feb 2022 15:58:01 -0700 Subject: [PATCH 36/65] added the scan page to scan for miners on a subnet --- tools/web_monitor/app.py | 45 +++++++++++- tools/web_monitor/index.py | 7 -- tools/web_monitor/miner_factory.py | 7 ++ tools/web_monitor/templates/navbar.html | 4 +- tools/web_monitor/templates/scan.html | 96 +++++++++++++++++++++++++ 5 files changed, 147 insertions(+), 12 deletions(-) create mode 100644 tools/web_monitor/miner_factory.py create mode 100644 tools/web_monitor/templates/scan.html diff --git a/tools/web_monitor/app.py b/tools/web_monitor/app.py index 68aad1ec..a83e7d89 100644 --- a/tools/web_monitor/app.py +++ b/tools/web_monitor/app.py @@ -3,9 +3,11 @@ import asyncio import uvicorn from fastapi import FastAPI from fastapi import Request -from fastapi import WebSocket +from fastapi import WebSocket, WebSocketDisconnect from fastapi.templating import Jinja2Templates from fastapi.staticfiles import StaticFiles +from tools.web_monitor.miner_factory import miner_factory +from network import MinerNetwork app = FastAPI() @@ -13,10 +15,47 @@ app.mount("/static", StaticFiles(directory="static"), name="static") templates = Jinja2Templates(directory="templates") -@app.route("/") +@app.get("/") def dashboard(request: Request): return templates.TemplateResponse("index.html", {"request": request}) +@app.get("/scan") +def scan(request: Request): + return templates.TemplateResponse("scan.html", {"request": request}) + + +@app.websocket("/scan/ws") +async def websocket_scan(websocket: WebSocket): + await websocket.accept() + try: + while True: + network_ip = await websocket.receive_text() + if "/" in network_ip: + network_ip, network_subnet = network_ip.split("/") + network = MinerNetwork(network_ip, mask=network_subnet) + else: + network = MinerNetwork(network_ip) + miner_generator = network.scan_network_generator() + miners = [] + async for miner in miner_generator: + if miner: + miners.append(miner) + + get_miner_genenerator = miner_factory.get_miner_generator(miners) + all_miners = [] + async for found_miner in get_miner_genenerator: + all_miners.append({"ip": found_miner.ip, "model": await found_miner.get_model()}) + all_miners.sort(key=lambda x: x["ip"]) + send_miners = [] + for miner in all_miners: + send_miners.append({"ip": str(miner["ip"]), "model": miner["model"]}) + await websocket.send_json(send_miners) + + await websocket.send_text("Done") + except WebSocketDisconnect: + pass + + if __name__ == "__main__": - uvicorn.run("app:app", host="127.0.0.1", port=80, debug=True) + uvicorn.run("app:app", host="127.0.0.1", port=80) diff --git a/tools/web_monitor/index.py b/tools/web_monitor/index.py index d9e0388a..e69de29b 100644 --- a/tools/web_monitor/index.py +++ b/tools/web_monitor/index.py @@ -1,7 +0,0 @@ -from tools.web_monitor.app import sio - - -@sio.event -async def connect(sid, _environ) -> None: - """Event for connection""" - await sio.emit('init', "hello") diff --git a/tools/web_monitor/miner_factory.py b/tools/web_monitor/miner_factory.py new file mode 100644 index 00000000..157b743a --- /dev/null +++ b/tools/web_monitor/miner_factory.py @@ -0,0 +1,7 @@ +""" +This file stores the MinerFactory instance used by the WebMonitor for use in other files. +""" + +from miners.miner_factory import MinerFactory + +miner_factory = MinerFactory() diff --git a/tools/web_monitor/templates/navbar.html b/tools/web_monitor/templates/navbar.html index 0293c1e4..5a92c6a6 100644 --- a/tools/web_monitor/templates/navbar.html +++ b/tools/web_monitor/templates/navbar.html @@ -107,11 +107,11 @@ -
    +
    {% block content %} {% endblock content %} -
    + diff --git a/tools/web_monitor/templates/scan.html b/tools/web_monitor/templates/scan.html new file mode 100644 index 00000000..ba37ad45 --- /dev/null +++ b/tools/web_monitor/templates/scan.html @@ -0,0 +1,96 @@ +{% extends 'navbar.html'%} +{% block content %} +
    +
    +
    + Subnet + + +
    + +
    + +
    +
    + + + + + + + + + + + +
    + + IPModel
    +
    + + + + +{% endblock content %} From 81911ba549af6b87cbd0343f6c41af4a3d030707 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Fri, 25 Feb 2022 16:11:06 -0700 Subject: [PATCH 37/65] fixed some formwatting on the scan page --- tools/web_monitor/templates/scan.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/web_monitor/templates/scan.html b/tools/web_monitor/templates/scan.html index ba37ad45..617776d0 100644 --- a/tools/web_monitor/templates/scan.html +++ b/tools/web_monitor/templates/scan.html @@ -5,14 +5,14 @@
    Subnet - +
    - + - + @@ -51,45 +51,53 @@ var ws = new WebSocket("ws://localhost:80/scan/ws"); ws.onmessage = function(event) { if (event.data == "Done") { + document.getElementById("scanButton").innerHTML = "Scan" + document.getElementById("scanButton").disabled = false document.getElementById("selectAllCheckbox").disabled = false document.getElementById("scanStatus").innerHTML = document.getElementById('minerTable').rows.length + " Miners" } else { - document.getElementById("selectAllCheckbox").disabled = true - document.getElementById("scanStatus").innerHTML = "Scanning..." + var miner_data = JSON.parse(event.data) + var miners = document.getElementById('minerTable') + miners.innerHTML = "" + miner_data.forEach(function(miner) { + console.log(miner) + var tr = document.createElement('tr') + + var checkbox_td = document.createElement('td') + checkbox_td.innerHTML = '' + checkbox_td.className = "active" + + var ip_td = document.createElement('td') + ip_td.innerHTML = miner["ip"] + + var model_td = document.createElement('td') + model_td.innerHTML = miner["model"] + + var empty_td = document.createElement('td') + + tr.append(checkbox_td) + tr.append(ip_td) + tr.append(model_td) + tr.append(empty_td) + + miners.append(tr) + }); }; - var miner_data = JSON.parse(event.data) - var miners = document.getElementById('minerTable') - miners.innerHTML = "" - miner_data.forEach(function(miner) { - console.log(miner) - var tr = document.createElement('tr') - - var checkbox_td = document.createElement('td') - checkbox_td.innerHTML = '' - checkbox_td.className = "active" - - var ip_td = document.createElement('td') - ip_td.innerHTML = miner["ip"] - - var model_td = document.createElement('td') - model_td.innerHTML = miner["model"] - - var empty_td = document.createElement('td') - - tr.append(checkbox_td) - tr.append(ip_td) - tr.append(model_td) - tr.append(empty_td) - - miners.append(tr) - }); }; function sendMessage(event) { var input = document.getElementById("messageText") + var miners = document.getElementById('minerTable') + miners.innerHTML = "" document.getElementById("scanStatus").innerHTML = "Scanning..." - ws.send(input.value) - input.value = '' - event.preventDefault() + document.getElementById("scanButton").innerHTML = "Scanning..." + document.getElementById("scanButton").disabled = true + document.getElementById("selectAllCheckbox").disabled = true + if (input.value != "") { + ws.send(input.value) + event.preventDefault() + } else { + ws.send("192.168.1.0/24") + }; } From 6d711520fcdd80dcde6293b51f8b45bbfde98626 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Mon, 28 Feb 2022 15:15:57 -0700 Subject: [PATCH 39/65] added add selected miners button --- tools/web_monitor/app.py | 68 ++++++++++++++++++--------- tools/web_monitor/templates/scan.html | 24 +++++++++- 2 files changed, 69 insertions(+), 23 deletions(-) diff --git a/tools/web_monitor/app.py b/tools/web_monitor/app.py index 3cf512c0..603f8cc9 100644 --- a/tools/web_monitor/app.py +++ b/tools/web_monitor/app.py @@ -25,37 +25,63 @@ def scan(request: Request): return templates.TemplateResponse("scan.html", {"request": request}) +@app.post("/scan/add_miners") +def add_miners_scan(request: Request): + print(request) + return scan + + @app.websocket("/scan/ws") async def websocket_scan(websocket: WebSocket): await websocket.accept() + cur_task = None try: while True: - network_ip = await websocket.receive_text() - if "/" in network_ip: - network_ip, network_subnet = network_ip.split("/") - network = MinerNetwork(network_ip, mask=network_subnet) + ws_data = await websocket.receive_text() + if "-Cancel-" in ws_data: + if cur_task: + cur_task.cancel() + try: + await cur_task + except asyncio.CancelledError: + cur_task = None + await websocket.send_text("Cancelled") else: - network = MinerNetwork(network_ip) - miner_generator = network.scan_network_generator() - miners = [] - async for miner in miner_generator: - if miner: - miners.append(miner) - - get_miner_genenerator = miner_factory.get_miner_generator(miners) - all_miners = [] - async for found_miner in get_miner_genenerator: - all_miners.append({"ip": found_miner.ip, "model": await found_miner.get_model()}) - all_miners.sort(key=lambda x: x["ip"]) - send_miners = [] - for miner in all_miners: - send_miners.append({"ip": str(miner["ip"]), "model": miner["model"]}) - await websocket.send_json(send_miners) - await websocket.send_text("Done") + cur_task = asyncio.create_task(do_websocket_scan(websocket, ws_data)) + if cur_task and cur_task.done(): + cur_task = None except WebSocketDisconnect: print("Websocket disconnected.") pass +async def do_websocket_scan(websocket: WebSocket, network_ip: str): + try: + if "/" in network_ip: + network_ip, network_subnet = network_ip.split("/") + network = MinerNetwork(network_ip, mask=network_subnet) + else: + network = MinerNetwork(network_ip) + miner_generator = network.scan_network_generator() + miners = [] + async for miner in miner_generator: + if miner: + miners.append(miner) + + get_miner_genenerator = miner_factory.get_miner_generator(miners) + all_miners = [] + async for found_miner in get_miner_genenerator: + all_miners.append( + {"ip": found_miner.ip, "model": await found_miner.get_model()}) + all_miners.sort(key=lambda x: x["ip"]) + send_miners = [] + for miner in all_miners: + send_miners.append( + {"ip": str(miner["ip"]), "model": miner["model"]}) + await websocket.send_json(send_miners) + await websocket.send_text("Done") + except asyncio.CancelledError: + raise + if __name__ == "__main__": uvicorn.run("app:app", host="127.0.0.1", port=80) diff --git a/tools/web_monitor/templates/scan.html b/tools/web_monitor/templates/scan.html index dc1ac58c..f5d24cce 100644 --- a/tools/web_monitor/templates/scan.html +++ b/tools/web_monitor/templates/scan.html @@ -5,11 +5,16 @@
    Subnet - + +
    +
    + +
    +
    From 584de409833e6c26cfba7718ece23564cfa081ea Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Mon, 28 Feb 2022 14:10:43 -0700 Subject: [PATCH 38/65] improved formatting on scan page and made the scan a bit more robust --- tools/web_monitor/app.py | 2 +- tools/web_monitor/templates/scan.html | 76 +++++++++++++++------------ 2 files changed, 43 insertions(+), 35 deletions(-) diff --git a/tools/web_monitor/app.py b/tools/web_monitor/app.py index a83e7d89..3cf512c0 100644 --- a/tools/web_monitor/app.py +++ b/tools/web_monitor/app.py @@ -51,9 +51,9 @@ async def websocket_scan(websocket: WebSocket): for miner in all_miners: send_miners.append({"ip": str(miner["ip"]), "model": miner["model"]}) await websocket.send_json(send_miners) - await websocket.send_text("Done") except WebSocketDisconnect: + print("Websocket disconnected.") pass diff --git a/tools/web_monitor/templates/scan.html b/tools/web_monitor/templates/scan.html index 617776d0..dc1ac58c 100644 --- a/tools/web_monitor/templates/scan.html +++ b/tools/web_monitor/templates/scan.html @@ -4,8 +4,8 @@
    Subnet - - + +
    @@ -19,7 +19,7 @@
    IP Model0 Miners
    @@ -55,6 +60,13 @@ document.getElementById("scanButton").disabled = false document.getElementById("selectAllCheckbox").disabled = false document.getElementById("scanStatus").innerHTML = document.getElementById('minerTable').rows.length + " Miners" + document.getElementById("cancelButton").style = "display:none;" + } else if (event.data == "Cancelled") { + document.getElementById("scanButton").innerHTML = "Scan" + document.getElementById("scanButton").disabled = false + document.getElementById("selectAllCheckbox").disabled = false + document.getElementById("scanStatus").innerHTML = document.getElementById('minerTable').rows.length + " Miners" + document.getElementById("cancelButton").style = "display:none;" } else { var miner_data = JSON.parse(event.data) var miners = document.getElementById('minerTable') @@ -84,7 +96,7 @@ }); }; }; - function sendMessage(event) { + function scanMiners(event) { var input = document.getElementById("messageText") var miners = document.getElementById('minerTable') miners.innerHTML = "" @@ -92,6 +104,7 @@ document.getElementById("scanButton").innerHTML = "Scanning..." document.getElementById("scanButton").disabled = true document.getElementById("selectAllCheckbox").disabled = true + document.getElementById("cancelButton").style = "" if (input.value != "") { ws.send(input.value) event.preventDefault() @@ -99,6 +112,13 @@ ws.send("192.168.1.0/24") }; } + function cancelScan(event) { + document.getElementById("scanStatus").innerHTML = "Canceling..." + document.getElementById("scanButton").innerHTML = "Canceling..." + document.getElementById("cancelButton").style = "display:none;" + ws.send("-Cancel-") + } + {% endblock content %} From 3002cb4e97d37b1315c62a689d22d239655cf381 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Mon, 28 Feb 2022 16:28:40 -0700 Subject: [PATCH 40/65] added basic addition of miners to the list and improved some functionality of the web tool --- tools/web_monitor/app.py | 4 ++-- tools/web_monitor/templates/scan.html | 28 +++++++++++++++++++++------ 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/tools/web_monitor/app.py b/tools/web_monitor/app.py index 603f8cc9..4c11ca3c 100644 --- a/tools/web_monitor/app.py +++ b/tools/web_monitor/app.py @@ -26,8 +26,8 @@ def scan(request: Request): @app.post("/scan/add_miners") -def add_miners_scan(request: Request): - print(request) +async def add_miners_scan(request: Request): + print(await request.json()) return scan diff --git a/tools/web_monitor/templates/scan.html b/tools/web_monitor/templates/scan.html index f5d24cce..f2648943 100644 --- a/tools/web_monitor/templates/scan.html +++ b/tools/web_monitor/templates/scan.html @@ -12,7 +12,7 @@
    - +
    @@ -53,6 +53,9 @@ }); {% endblock content %} From 385943755d104f314a972cbdf0539dc3ba40e451 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Tue, 1 Mar 2022 11:30:48 -0700 Subject: [PATCH 41/65] further improved formatting of scan page, added disabled checkboxes on scan, updated miner count on add --- tools/web_monitor/templates/scan.html | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/tools/web_monitor/templates/scan.html b/tools/web_monitor/templates/scan.html index f2648943..18363cb7 100644 --- a/tools/web_monitor/templates/scan.html +++ b/tools/web_monitor/templates/scan.html @@ -64,12 +64,14 @@ document.getElementById("selectAllCheckbox").disabled = false document.getElementById("scanStatus").innerHTML = document.getElementById('minerTable').rows.length + " Miners" document.getElementById("cancelButton").style = "display:none;" + enableCheckboxes(); } else if (event.data == "Cancelled") { document.getElementById("scanButton").innerHTML = "Scan" document.getElementById("scanButton").disabled = false document.getElementById("selectAllCheckbox").disabled = false document.getElementById("scanStatus").innerHTML = document.getElementById('minerTable').rows.length + " Miners" document.getElementById("cancelButton").style = "display:none;" + enableCheckboxes(); } else { var miner_data = JSON.parse(event.data) var miners = document.getElementById('minerTable') @@ -97,6 +99,7 @@ miners.append(tr) }); + disableCheckboxes(); }; }; function scanMiners(event) { @@ -123,7 +126,7 @@ }; function addMiners(event) { var checkedBoxes = document.querySelectorAll('input[name=minerCheckboxes]:checked'); - if !(checkedBoxes.length == 0) { + if (checkedBoxes.length != 0) { var minerList = []; for (i = 0; i< checkedBoxes.length; i++) { minerList.push(checkedBoxes[i].defaultValue); @@ -133,6 +136,19 @@ var tr_to_remove = document.getElementById(minerList[i]) tr_to_remove.remove() } + document.getElementById("scanStatus").innerHTML = document.getElementById('minerTable').rows.length + " Miners" + }; + }; + function disableCheckboxes() { + var checkBoxes = document.querySelectorAll('input[name=minerCheckboxes]'); + for (i = 0; i< checkBoxes.length; i++) { + checkBoxes[i].disabled = true + }; + }; + function enableCheckboxes() { + var checkBoxes = document.querySelectorAll('input[name=minerCheckboxes]'); + for (i = 0; i< checkBoxes.length; i++) { + checkBoxes[i].disabled = false }; }; From 3558a1a6b1b6f96aa8b5624793009fdf23664a61 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Tue, 1 Mar 2022 12:28:36 -0700 Subject: [PATCH 42/65] finished up scan page, added the ability to add miners and them get listed in the miner list, and started adding the individual miner pages --- tools/web_monitor/app.py | 36 ++++++++++++++++++++++--- tools/web_monitor/static/navbar.css | 19 +++++++++++++ tools/web_monitor/templates/navbar.html | 28 +++++++------------ 3 files changed, 60 insertions(+), 23 deletions(-) diff --git a/tools/web_monitor/app.py b/tools/web_monitor/app.py index 4c11ca3c..edce3070 100644 --- a/tools/web_monitor/app.py +++ b/tools/web_monitor/app.py @@ -1,4 +1,5 @@ import json +import os import asyncio import uvicorn from fastapi import FastAPI @@ -17,17 +18,43 @@ templates = Jinja2Templates(directory="templates") @app.get("/") def dashboard(request: Request): - return templates.TemplateResponse("index.html", {"request": request}) + return templates.TemplateResponse("index.html", { + "request": request, + "cur_miners": get_current_miner_list() + }) @app.get("/scan") def scan(request: Request): - return templates.TemplateResponse("scan.html", {"request": request}) + return templates.TemplateResponse("scan.html", { + "request": request, + "cur_miners": get_current_miner_list() + }) + + +@app.get("/miner") +def miner(request: Request, miner_ip): + return get_miner + +@app.get("/miner/{miner_ip}") +def get_miner(request: Request, miner_ip): + return miner_ip + +def get_current_miner_list(): + cur_miners = [] + if os.path.exists(os.path.join(os.getcwd(), "miner_list.txt")): + with open(os.path.join(os.getcwd(), "miner_list.txt")) as file: + for line in file.readlines(): + cur_miners.append(line.strip()) + return cur_miners @app.post("/scan/add_miners") async def add_miners_scan(request: Request): - print(await request.json()) + miners = await request.json() + with open("miner_list.txt", "a+") as file: + for miner in miners["miners"]: + file.write(miner + "\n") return scan @@ -56,6 +83,7 @@ async def websocket_scan(websocket: WebSocket): async def do_websocket_scan(websocket: WebSocket, network_ip: str): + cur_miners = get_current_miner_list() try: if "/" in network_ip: network_ip, network_subnet = network_ip.split("/") @@ -65,7 +93,7 @@ async def do_websocket_scan(websocket: WebSocket, network_ip: str): miner_generator = network.scan_network_generator() miners = [] async for miner in miner_generator: - if miner: + if miner and str(miner) not in cur_miners: miners.append(miner) get_miner_genenerator = miner_factory.get_miner_generator(miners) diff --git a/tools/web_monitor/static/navbar.css b/tools/web_monitor/static/navbar.css index 388b1403..8e8e0091 100644 --- a/tools/web_monitor/static/navbar.css +++ b/tools/web_monitor/static/navbar.css @@ -130,3 +130,22 @@ main { border-color: transparent; box-shadow: 0 0 0 3px rgba(255, 255, 255, .25); } + +.btn-toggle-nav{ + max-height: 300px; + -webkit-overflow-scrolling: touch; +} + +/* Scrollbar */ +.btn-toggle-nav::-webkit-scrollbar { + width: 5px; +} +.btn-toggle-nav::-webkit-scrollbar-track { + box-shadow: inset 0 0 5px grey; + border-radius: 10px; +} +.btn-toggle-nav::-webkit-scrollbar-thumb { + background-image: linear-gradient(180deg, #D0368A 0%, #708AD4 99%); + box-shadow: inset 2px 2px 5px 0 rgba(#fff, 0.5); + border-radius: 100px; +} diff --git a/tools/web_monitor/templates/navbar.html b/tools/web_monitor/templates/navbar.html index 5a92c6a6..0f62b115 100644 --- a/tools/web_monitor/templates/navbar.html +++ b/tools/web_monitor/templates/navbar.html @@ -70,25 +70,15 @@ Miners
    -
    From f8899521bcff7bc05e9959a1b54cdec464622b16 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Tue, 1 Mar 2022 12:51:49 -0700 Subject: [PATCH 43/65] improved navbar formatting, added active formats for all miners, moved add miners to a miner subtab --- tools/web_monitor/app.py | 8 +++++++- tools/web_monitor/templates/miner.html | 4 ++++ tools/web_monitor/templates/navbar.html | 20 +++++++++----------- 3 files changed, 20 insertions(+), 12 deletions(-) create mode 100644 tools/web_monitor/templates/miner.html diff --git a/tools/web_monitor/app.py b/tools/web_monitor/app.py index edce3070..d35f94c7 100644 --- a/tools/web_monitor/app.py +++ b/tools/web_monitor/app.py @@ -36,9 +36,15 @@ def scan(request: Request): def miner(request: Request, miner_ip): return get_miner + @app.get("/miner/{miner_ip}") def get_miner(request: Request, miner_ip): - return miner_ip + return templates.TemplateResponse("miner.html", { + "request": request, + "cur_miners": get_current_miner_list(), + "miner": miner_ip + }) + def get_current_miner_list(): cur_miners = [] diff --git a/tools/web_monitor/templates/miner.html b/tools/web_monitor/templates/miner.html new file mode 100644 index 00000000..fb10f31f --- /dev/null +++ b/tools/web_monitor/templates/miner.html @@ -0,0 +1,4 @@ +{% extends 'navbar.html'%} +{% block content %} +{{miner}} +{% endblock content %} diff --git a/tools/web_monitor/templates/navbar.html b/tools/web_monitor/templates/navbar.html index 0f62b115..1ddf4212 100644 --- a/tools/web_monitor/templates/navbar.html +++ b/tools/web_monitor/templates/navbar.html @@ -51,29 +51,27 @@
    @@ -58,6 +58,18 @@ ws.onmessage = function(event) { if (minerDataChart.data.datasets[0].data.length > 50) minerDataChart.data.datasets[0].data.shift(); minerDataChart.data.labels.push(datetime.toLocaleString(luxon.DateTime.TIME_WITH_SECONDS)); minerDataChart.data.datasets[0].data.push(new_data["hashrate"]); + fan1Chart.data.datasets[0].data = [new_data["fans"][0], 6000-new_data["fans"][0]] + fan2Chart.data.datasets[0].data = [new_data["fans"][1], 6000-new_data["fans"][1]] + fan3Chart.data.datasets[0].data = [new_data["fans"][2], 6000-new_data["fans"][2]] + fan4Chart.data.datasets[0].data = [new_data["fans"][3], 6000-new_data["fans"][3]] + document.getElementById("fan1").innerHTML = "Fan 1: " + new_data["fans"][0] + document.getElementById("fan2").innerHTML = "Fan 2: " + new_data["fans"][1] + document.getElementById("fan3").innerHTML = "Fan 3: " + new_data["fans"][2] + document.getElementById("fan4").innerHTML = "Fan 4: " + new_data["fans"][3] + fan1Chart.update(); + fan2Chart.update(); + fan3Chart.update(); + fan4Chart.update(); minerDataChart.update(); }; }; @@ -144,7 +156,7 @@ var options_fans = { var fanCtx = document.getElementById("fan-chart-1").getContext("2d"); var fanWidth = document.getElementById("fan-chart-1").width; -var fanChartGradient = fanCtx.createLinearGradient(0, 0, fanWidth, -(1/2)*fanWidth) +var fanChartGradient = fanCtx.createLinearGradient(0, 0, fanWidth, -fanWidth) fanChartGradient.addColorStop(0, '#D0368A'); fanChartGradient.addColorStop(1, '#708AD4'); @@ -155,7 +167,7 @@ var fan1Chart = new Chart(document.getElementById("fan-chart-1"), { labels: ["Fan 1"], datasets: [ { - data: [100, 100], + data: [0, 6000], // add colors backgroundColor: [ fanChartGradient, @@ -172,7 +184,7 @@ var fan2Chart = new Chart(document.getElementById("fan-chart-2"), { labels: ["Fan 2"], datasets: [ { - data: [300, 100], + data: [0, 6000], // add colors backgroundColor: [ fanChartGradient, @@ -189,7 +201,7 @@ var fan3Chart = new Chart(document.getElementById("fan-chart-3"), { labels: ["Fan 3"], datasets: [ { - data: [200, 100], + data: [0, 6000], // add colors backgroundColor: [ fanChartGradient, @@ -206,7 +218,7 @@ var fan4Chart = new Chart(document.getElementById("fan-chart-4"), { labels: ["Fan 4"], datasets: [ { - data: [500, 100], + data: [0, 6000], // add colors backgroundColor: [ fanChartGradient, From e974c77359e4747b7688f2e92d58e81b6ed0725f Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Wed, 2 Mar 2022 15:38:29 -0700 Subject: [PATCH 52/65] added fan and hashrate data for S19s and Whatsminers --- tools/web_monitor/app.py | 47 ++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/tools/web_monitor/app.py b/tools/web_monitor/app.py index 51700976..11dfb1a9 100644 --- a/tools/web_monitor/app.py +++ b/tools/web_monitor/app.py @@ -47,21 +47,42 @@ async def miner_websocket(websocket: WebSocket, miner_ip): try: cur_miner = await asyncio.wait_for(miner_factory.get_miner(str(miner_ip)), 5) - data = await asyncio.wait_for(cur_miner.api.multicommand("summary", "fans"), 5) + data = await asyncio.wait_for(cur_miner.api.multicommand("summary", "fans", "stats"), 5) - miner_summary = data["summary"][0] + miner_summary = None + miner_stats = None miner_fans = None + if "summary" in data.keys(): + miner_summary = data["summary"][0] + elif "SUMMARY" in data.keys(): + miner_summary = data + miner_fans = {"FANS": []} + for item in ["Fan Speed In", "Fan Speed Out"]: + if item in miner_summary["SUMMARY"][0].keys(): + miner_fans["FANS"].append({"RPM": miner_summary["SUMMARY"][0][item]}) + if "fans" in data.keys(): miner_fans = data["fans"][0] - if 'MHS av' in miner_summary['SUMMARY'][0].keys(): - hashrate = format( - round(miner_summary['SUMMARY'][0]['MHS av'] / 1000000, - 2), ".2f") - elif 'GHS av' in miner_summary['summary'][0]['SUMMARY'][0].keys(): - hashrate = format( - round(miner_summary['SUMMARY'][0]['GHS av'] / 1000, 2), - ".2f") + if "stats" in data.keys(): + miner_stats = data["stats"][0] + miner_fans = {"FANS": []} + for item in ["fan1", "fan2", "fan3", "fan4"]: + if item in miner_stats["STATS"][1].keys(): + miner_fans["FANS"].append({"RPM": miner_stats["STATS"][1][item]}) + + + if miner_summary: + if 'MHS av' in miner_summary['SUMMARY'][0].keys(): + hashrate = format( + round(miner_summary['SUMMARY'][0]['MHS av'] / 1000000, + 2), ".2f") + elif 'GHS av' in miner_summary['SUMMARY'][0].keys(): + hashrate = format( + round(miner_summary['SUMMARY'][0]['GHS av'] / 1000, 2), + ".2f") + else: + hashrate = 0 else: hashrate = 0 @@ -71,6 +92,9 @@ async def miner_websocket(websocket: WebSocket, miner_ip): for fan in miner_fans["FANS"]: fan_speeds.append(fan["RPM"]) + while len(fan_speeds) < 5: + fan_speeds.append(0) + data = {"hashrate": hashrate, "fans": fan_speeds, @@ -81,7 +105,8 @@ async def miner_websocket(websocket: WebSocket, miner_ip): data = {"error": "The miner is not responding."} await websocket.send_json(data) await asyncio.sleep(.5) - except KeyError: + except KeyError as e: + print(e) data = {"error": "The miner returned incorrect data."} await websocket.send_json(data) await asyncio.sleep(.5) From f613cc039ff2881f609454e50c4129c3228fd89b Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Wed, 2 Mar 2022 15:47:17 -0700 Subject: [PATCH 53/65] added spinner to scan --- tools/web_monitor/templates/scan.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/web_monitor/templates/scan.html b/tools/web_monitor/templates/scan.html index 18363cb7..3708dfaf 100644 --- a/tools/web_monitor/templates/scan.html +++ b/tools/web_monitor/templates/scan.html @@ -106,8 +106,8 @@ var input = document.getElementById("messageText") var miners = document.getElementById('minerTable') miners.innerHTML = "" - document.getElementById("scanStatus").innerHTML = "Scanning..." - document.getElementById("scanButton").innerHTML = "Scanning..." + document.getElementById("scanStatus").innerHTML = " Scanning" + document.getElementById("scanButton").innerHTML = " Scanning" document.getElementById("scanButton").disabled = true document.getElementById("selectAllCheckbox").disabled = true document.getElementById("cancelButton").style = "" From 42f51466322a43f1c6cafe7f656d28397dd5fa49 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Wed, 2 Mar 2022 15:54:49 -0700 Subject: [PATCH 54/65] added different select gradient --- tools/web_monitor/static/navbar.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/web_monitor/static/navbar.css b/tools/web_monitor/static/navbar.css index 3f3c7465..569caa00 100644 --- a/tools/web_monitor/static/navbar.css +++ b/tools/web_monitor/static/navbar.css @@ -155,7 +155,7 @@ main { } .nav-link:hover { - background-image: linear-gradient(180deg, #D0368A 0%, #708AD4 99%); + background-image: linear-gradient(180deg, #760A45 0%, #23449F 99%); } .nav-link { From 87b8de90290968e2666be07aca3e48bfb97894e9 Mon Sep 17 00:00:00 2001 From: UpstreamData Date: Fri, 4 Mar 2022 11:24:06 -0700 Subject: [PATCH 55/65] strated on basic framework for dashboard in web_monitor --- tools/web_monitor/app.py | 63 +++++++++++++++++++++++-- tools/web_monitor/static/navbar.css | 1 + tools/web_monitor/templates/index.html | 46 +++++++++++++++++- tools/web_monitor/templates/navbar.html | 8 ++-- 4 files changed, 109 insertions(+), 9 deletions(-) diff --git a/tools/web_monitor/app.py b/tools/web_monitor/app.py index 11dfb1a9..767b0eca 100644 --- a/tools/web_monitor/app.py +++ b/tools/web_monitor/app.py @@ -4,6 +4,7 @@ import datetime import os import asyncio import uvicorn +import websockets.exceptions from fastapi import FastAPI from fastapi import Request from fastapi import WebSocket, WebSocketDisconnect @@ -19,6 +20,11 @@ templates = Jinja2Templates(directory="templates") @app.get("/") +def index(): + return dashboard() + + +@app.get("/dashboard") def dashboard(request: Request): return templates.TemplateResponse("index.html", { "request": request, @@ -26,6 +32,57 @@ def dashboard(request: Request): }) +@app.websocket("/dashboard/ws") +async def dashboard_websocket(websocket: WebSocket): + await websocket.accept() + try: + while True: + miners = get_current_miner_list() + all_miner_data = [] + data_gen = asyncio.as_completed([get_miner_data_dashboard(miner) for miner in miners]) + for all_data in data_gen: + data_point = await all_data + all_miner_data.append(data_point) + all_miner_data.sort(key=lambda x: x["ip"]) + try: + await websocket.send_json({"datetime": datetime.datetime.now().isoformat(), + "miners": all_miner_data}) + except websockets.exceptions.ConnectionClosedOK: + print("disconnected") + await asyncio.sleep(5) + except WebSocketDisconnect: + print("Websocket disconnected.") + pass + + +async def get_miner_data_dashboard(miner_ip): + try: + miner = await asyncio.wait_for(miner_factory.get_miner(miner_ip), 5) + + miner_summary = await asyncio.wait_for(miner.api.summary(), 5) + if miner_summary: + if 'MHS av' in miner_summary['SUMMARY'][0].keys(): + hashrate = format( + round(miner_summary['SUMMARY'][0]['MHS av'] / 1000000, + 2), ".2f") + elif 'GHS av' in miner_summary['SUMMARY'][0].keys(): + hashrate = format( + round(miner_summary['SUMMARY'][0]['GHS av'] / 1000, 2), + ".2f") + else: + hashrate = 0 + else: + hashrate = 0 + + return {"ip": str(miner.ip), "hashrate": hashrate} + + except asyncio.exceptions.TimeoutError: + return {"ip": miner_ip, "error": "The miner is not responding."} + + except KeyError: + return {"ip": miner_ip, "error": "The miner returned unusable/unsupported data."} + + @app.get("/scan") def scan(request: Request): return templates.TemplateResponse("scan.html", { @@ -35,7 +92,7 @@ def scan(request: Request): @app.get("/miner") -def miner(request: Request, miner_ip): +def miner(_request: Request, _miner_ip): return get_miner @@ -71,7 +128,6 @@ async def miner_websocket(websocket: WebSocket, miner_ip): if item in miner_stats["STATS"][1].keys(): miner_fans["FANS"].append({"RPM": miner_stats["STATS"][1][item]}) - if miner_summary: if 'MHS av' in miner_summary['SUMMARY'][0].keys(): hashrate = format( @@ -95,7 +151,6 @@ async def miner_websocket(websocket: WebSocket, miner_ip): while len(fan_speeds) < 5: fan_speeds.append(0) - data = {"hashrate": hashrate, "fans": fan_speeds, "datetime": datetime.datetime.now().isoformat()} @@ -107,7 +162,7 @@ async def miner_websocket(websocket: WebSocket, miner_ip): await asyncio.sleep(.5) except KeyError as e: print(e) - data = {"error": "The miner returned incorrect data."} + data = {"error": "The miner returned unusable/unsupported data."} await websocket.send_json(data) await asyncio.sleep(.5) except WebSocketDisconnect: diff --git a/tools/web_monitor/static/navbar.css b/tools/web_monitor/static/navbar.css index 569caa00..1d582b38 100644 --- a/tools/web_monitor/static/navbar.css +++ b/tools/web_monitor/static/navbar.css @@ -151,6 +151,7 @@ main { } .nav-pills .nav-link.active { + color: #212529; background-image: linear-gradient(180deg, #D0368A 0%, #708AD4 99%); } diff --git a/tools/web_monitor/templates/index.html b/tools/web_monitor/templates/index.html index b83f025d..8bed0a8b 100644 --- a/tools/web_monitor/templates/index.html +++ b/tools/web_monitor/templates/index.html @@ -1,4 +1,48 @@ {% extends 'navbar.html'%} {% block content %} -

    Hi

    +
    + +
    + + + + +
    + + + {% endblock content %} diff --git a/tools/web_monitor/templates/navbar.html b/tools/web_monitor/templates/navbar.html index 1ddf4212..d2037c09 100644 --- a/tools/web_monitor/templates/navbar.html +++ b/tools/web_monitor/templates/navbar.html @@ -51,27 +51,27 @@