completed basic recording functionality
This commit is contained in:
@@ -1,21 +1,20 @@
|
|||||||
from typing import List
|
from typing import List
|
||||||
from tools.cfg_util.record.manager import RecordingManager
|
from tools.cfg_util.record.manager import RecordingManager
|
||||||
from tools.cfg_util.record.layout import record_window
|
import PySimpleGUI as sg
|
||||||
|
|
||||||
|
|
||||||
async def start_recording(ips: List[str], file: str, interval: int = 10):
|
async def start_recording(
|
||||||
|
ips: List[str], file: str, record_window: sg.Window, interval: int = 10
|
||||||
|
):
|
||||||
record_window["start_recording"].update(visible=False)
|
record_window["start_recording"].update(visible=False)
|
||||||
record_window["stop_recording"].update(visible=True)
|
record_window["stop_recording"].update(visible=True)
|
||||||
record_window["pause_recording"].update(visible=True)
|
record_window["pause_recording"].update(visible=True)
|
||||||
record_window["resume_recording"].update(visible=False)
|
record_window["resume_recording"].update(visible=False)
|
||||||
record_window["_placeholder"].update(visible=False)
|
record_window["_placeholder"].update(visible=False)
|
||||||
await RecordingManager().record(
|
await RecordingManager().record(ips, file, record_window, interval=interval)
|
||||||
ips,
|
|
||||||
file,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def pause_recording():
|
async def pause_recording(record_window):
|
||||||
await RecordingManager().pause()
|
await RecordingManager().pause()
|
||||||
record_window["resume_recording"].update(visible=True)
|
record_window["resume_recording"].update(visible=True)
|
||||||
record_window["start_recording"].update(visible=False)
|
record_window["start_recording"].update(visible=False)
|
||||||
@@ -23,7 +22,7 @@ async def pause_recording():
|
|||||||
record_window["pause_recording"].update(visible=False)
|
record_window["pause_recording"].update(visible=False)
|
||||||
|
|
||||||
|
|
||||||
async def stop_recording():
|
async def stop_recording(record_window):
|
||||||
await RecordingManager().stop()
|
await RecordingManager().stop()
|
||||||
record_window["start_recording"].update(visible=True)
|
record_window["start_recording"].update(visible=True)
|
||||||
record_window["stop_recording"].update(visible=False)
|
record_window["stop_recording"].update(visible=False)
|
||||||
@@ -32,7 +31,7 @@ async def stop_recording():
|
|||||||
record_window["_placeholder"].update(visible=True)
|
record_window["_placeholder"].update(visible=True)
|
||||||
|
|
||||||
|
|
||||||
async def resume_recording():
|
async def resume_recording(record_window):
|
||||||
await RecordingManager().resume()
|
await RecordingManager().resume()
|
||||||
record_window["start_recording"].update(visible=False)
|
record_window["start_recording"].update(visible=False)
|
||||||
record_window["stop_recording"].update(visible=True)
|
record_window["stop_recording"].update(visible=True)
|
||||||
|
|||||||
@@ -104,4 +104,5 @@ def record_layout():
|
|||||||
return record_layout
|
return record_layout
|
||||||
|
|
||||||
|
|
||||||
record_window = sg.Window("Record Miner Data", record_layout(), modal=True)
|
def get_record_window():
|
||||||
|
return sg.Window("Record Miner Data", record_layout(), modal=True)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from tools.cfg_util.record.layout import record_window
|
from tools.cfg_util.record.pdf import generate_pdf
|
||||||
|
|
||||||
from miners.miner_factory import MinerFactory
|
from miners.miner_factory import MinerFactory
|
||||||
|
|
||||||
@@ -27,14 +27,15 @@ class RecordingManager(metaclass=Singleton):
|
|||||||
self.miners = []
|
self.miners = []
|
||||||
self.output_file = None
|
self.output_file = None
|
||||||
self.interval = 10
|
self.interval = 10
|
||||||
|
self.record_window = None
|
||||||
|
|
||||||
async def _check_pause(self):
|
async def _check_pause(self):
|
||||||
if self.state == PAUSING:
|
if self.state == PAUSING:
|
||||||
self.state = PAUSED
|
self.state = PAUSED
|
||||||
record_window["record_status"].update("Paused.")
|
self.record_window["record_status"].update("Paused.")
|
||||||
while not self.state == RESUMING and not self.state == STOPPING:
|
while not self.state == RESUMING and not self.state == STOPPING:
|
||||||
await asyncio.sleep(0.1)
|
await asyncio.sleep(0.1)
|
||||||
record_window["record_status"].update("Recording...")
|
self.record_window["record_status"].update("Recording...")
|
||||||
|
|
||||||
async def _record_loop(self):
|
async def _record_loop(self):
|
||||||
while True:
|
while True:
|
||||||
@@ -58,36 +59,39 @@ class RecordingManager(metaclass=Singleton):
|
|||||||
await asyncio.sleep(0.1)
|
await asyncio.sleep(0.1)
|
||||||
|
|
||||||
self.state = DONE
|
self.state = DONE
|
||||||
record_window["record_status"].update("Writing to file...")
|
self.record_window["record_status"].update(
|
||||||
await self.write_output()
|
"Writing to file (this could take a minute)..."
|
||||||
record_window["record_status"].update("")
|
)
|
||||||
|
await asyncio.sleep(0.5)
|
||||||
|
await asyncio.create_task(self.write_output())
|
||||||
|
self.record_window["record_status"].update("")
|
||||||
|
|
||||||
async def write_output(self):
|
async def write_output(self):
|
||||||
from pprint import pprint
|
await generate_pdf(self.data, self.output_file)
|
||||||
|
|
||||||
pprint(self.data)
|
async def record(
|
||||||
|
self, ips: List[str], output_file: str, record_window, interval: int = 10
|
||||||
async def record(self, ips: List[str], output_file: str, interval: int = 10):
|
):
|
||||||
|
self.record_window = record_window
|
||||||
for ip in ips:
|
for ip in ips:
|
||||||
self.data[ip] = []
|
self.data[ip] = []
|
||||||
self.output_file = output_file
|
self.output_file = output_file
|
||||||
self.interval = interval
|
self.interval = interval
|
||||||
self.state = RECORDING
|
self.state = RECORDING
|
||||||
record_window["record_status"].update("Recording...")
|
self.record_window["record_status"].update("Recording...")
|
||||||
async for miner in MinerFactory().get_miner_generator(ips):
|
async for miner in MinerFactory().get_miner_generator(ips):
|
||||||
self.miners.append(miner)
|
self.miners.append(miner)
|
||||||
print(miner)
|
|
||||||
|
|
||||||
asyncio.create_task(self._record_loop())
|
asyncio.create_task(self._record_loop())
|
||||||
|
|
||||||
async def pause(self):
|
async def pause(self):
|
||||||
self.state = PAUSING
|
self.state = PAUSING
|
||||||
record_window["record_status"].update("Pausing...")
|
self.record_window["record_status"].update("Pausing...")
|
||||||
|
|
||||||
async def resume(self):
|
async def resume(self):
|
||||||
self.state = RESUMING
|
self.state = RESUMING
|
||||||
record_window["record_status"].update("Resuming...")
|
self.record_window["record_status"].update("Resuming...")
|
||||||
|
|
||||||
async def stop(self):
|
async def stop(self):
|
||||||
self.state = STOPPING
|
self.state = STOPPING
|
||||||
record_window["record_status"].update("Stopping...")
|
self.record_window["record_status"].update("Stopping...")
|
||||||
|
|||||||
177
tools/cfg_util/record/pdf.py
Normal file
177
tools/cfg_util/record/pdf.py
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
from datetime import datetime, timedelta
|
||||||
|
from typing import List, Dict
|
||||||
|
from data import MinerData
|
||||||
|
|
||||||
|
|
||||||
|
import matplotlib.pyplot as plt
|
||||||
|
from matplotlib.ticker import MultipleLocator
|
||||||
|
from matplotlib.dates import DateFormatter
|
||||||
|
import numpy as np
|
||||||
|
from reportlab.lib import colors
|
||||||
|
from reportlab.lib.pagesizes import letter, inch
|
||||||
|
from reportlab.lib.styles import (
|
||||||
|
ParagraphStyle,
|
||||||
|
TA_CENTER, # noqa - not declared in __all__
|
||||||
|
)
|
||||||
|
from reportlab.lib.utils import ImageReader
|
||||||
|
from reportlab.platypus import (
|
||||||
|
SimpleDocTemplate,
|
||||||
|
KeepInFrame,
|
||||||
|
Table,
|
||||||
|
Image,
|
||||||
|
Paragraph,
|
||||||
|
TableStyle,
|
||||||
|
PageBreak,
|
||||||
|
Spacer,
|
||||||
|
)
|
||||||
|
from io import BytesIO
|
||||||
|
from svglib.svglib import svg2rlg
|
||||||
|
|
||||||
|
|
||||||
|
async def generate_pdf(data: Dict[str, List[MinerData]], file_loc):
|
||||||
|
doc = SimpleDocTemplate(
|
||||||
|
file_loc,
|
||||||
|
pagesize=letter,
|
||||||
|
topMargin=0.25 * inch,
|
||||||
|
leftMargin=1 * inch,
|
||||||
|
rightMargin=1 * inch,
|
||||||
|
bottomMargin=1 * inch,
|
||||||
|
title=f"Recorded Data",
|
||||||
|
)
|
||||||
|
|
||||||
|
elements = []
|
||||||
|
i = 0
|
||||||
|
for item in data.keys():
|
||||||
|
i += 1
|
||||||
|
if not i == 1:
|
||||||
|
elements.append(PageBreak())
|
||||||
|
page_elem = await generate_page(data[item])
|
||||||
|
for elem in page_elem:
|
||||||
|
elements.append(elem)
|
||||||
|
|
||||||
|
doc.build(
|
||||||
|
elements,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def generate_page(data):
|
||||||
|
title_style = ParagraphStyle(
|
||||||
|
"Title",
|
||||||
|
alignment=TA_CENTER,
|
||||||
|
fontSize=25,
|
||||||
|
spaceAfter=40,
|
||||||
|
spaceBefore=150,
|
||||||
|
fontName="Helvetica-Bold",
|
||||||
|
)
|
||||||
|
|
||||||
|
hr_graph = create_hr_graph(data)
|
||||||
|
fan_graph = create_fans_graph(data)
|
||||||
|
temp_graph = create_temp_graph(data)
|
||||||
|
title = Paragraph(data[0].ip, style=title_style)
|
||||||
|
|
||||||
|
elements = [
|
||||||
|
title,
|
||||||
|
await hr_graph,
|
||||||
|
Spacer(0, 40),
|
||||||
|
await temp_graph,
|
||||||
|
Spacer(0, 40),
|
||||||
|
await fan_graph,
|
||||||
|
]
|
||||||
|
return elements
|
||||||
|
|
||||||
|
|
||||||
|
async def create_hr_graph(data):
|
||||||
|
fig, ax = plt.subplots(figsize=(6, 2))
|
||||||
|
xpoints = []
|
||||||
|
ypoints = []
|
||||||
|
for item in data:
|
||||||
|
xpoints.append(item.datetime)
|
||||||
|
ypoints.append(item.hashrate)
|
||||||
|
for label in ax.get_xticklabels() + ax.get_yticklabels():
|
||||||
|
label.set_fontsize(6)
|
||||||
|
ax.plot(xpoints, ypoints)
|
||||||
|
ax.set_ylim(0, max(ypoints) * 1.4)
|
||||||
|
date_form = DateFormatter("%H:%M:%S")
|
||||||
|
ax.xaxis.set_major_formatter(date_form)
|
||||||
|
ax.yaxis.set_major_formatter("{x:1.1f} TH/s")
|
||||||
|
ax.set_title("Hashrate", fontsize=15)
|
||||||
|
ax.yaxis.set_major_locator(MultipleLocator(5))
|
||||||
|
ax.yaxis.set_minor_locator(MultipleLocator(1))
|
||||||
|
|
||||||
|
imgdata = BytesIO()
|
||||||
|
fig.savefig(imgdata, format="svg")
|
||||||
|
imgdata.seek(0) # rewind the data
|
||||||
|
drawing = svg2rlg(imgdata)
|
||||||
|
imgdata.close()
|
||||||
|
plt.close("all")
|
||||||
|
|
||||||
|
hr_graph = KeepInFrame(375, 375, [Image(drawing)], hAlign="CENTER")
|
||||||
|
|
||||||
|
return hr_graph
|
||||||
|
|
||||||
|
|
||||||
|
async def create_fans_graph(data):
|
||||||
|
fig, ax = plt.subplots(figsize=(6, 2))
|
||||||
|
xpoints = []
|
||||||
|
ypoints_f1 = []
|
||||||
|
ypoints_f2 = []
|
||||||
|
ypoints_f3 = []
|
||||||
|
ypoints_f4 = []
|
||||||
|
for item in data:
|
||||||
|
xpoints.append(item.datetime)
|
||||||
|
ypoints_f1.append(item.fan_1)
|
||||||
|
ypoints_f2.append(item.fan_2)
|
||||||
|
ypoints_f3.append(item.fan_3)
|
||||||
|
ypoints_f4.append(item.fan_4)
|
||||||
|
for label in ax.get_xticklabels() + ax.get_yticklabels():
|
||||||
|
label.set_fontsize(6)
|
||||||
|
for ypoints in [ypoints_f1, ypoints_f2, ypoints_f3, ypoints_f4]:
|
||||||
|
if not ypoints == [-1 for x in range(len(ypoints))]:
|
||||||
|
ax.plot(xpoints, ypoints)
|
||||||
|
ax.set_ylim(0, 10000)
|
||||||
|
date_form = DateFormatter("%H:%M:%S")
|
||||||
|
ax.xaxis.set_major_formatter(date_form)
|
||||||
|
ax.yaxis.set_major_formatter("{x:1.0f} RPM")
|
||||||
|
ax.set_title("Fans", fontsize=15)
|
||||||
|
|
||||||
|
imgdata = BytesIO()
|
||||||
|
fig.savefig(imgdata, format="svg")
|
||||||
|
imgdata.seek(0) # rewind the data
|
||||||
|
drawing = svg2rlg(imgdata)
|
||||||
|
imgdata.close()
|
||||||
|
plt.close("all")
|
||||||
|
|
||||||
|
fans_graph = KeepInFrame(375, 375, [Image(drawing)], hAlign="CENTER")
|
||||||
|
|
||||||
|
return fans_graph
|
||||||
|
|
||||||
|
|
||||||
|
async def create_temp_graph(data):
|
||||||
|
fig, ax = plt.subplots(figsize=(6, 2))
|
||||||
|
# plt.figure()
|
||||||
|
xpoints = []
|
||||||
|
ypoints = []
|
||||||
|
for item in data:
|
||||||
|
xpoints.append(item.datetime)
|
||||||
|
ypoints.append(item.temperature_avg)
|
||||||
|
for label in ax.get_xticklabels() + ax.get_yticklabels():
|
||||||
|
label.set_fontsize(6)
|
||||||
|
ax.plot(xpoints, ypoints)
|
||||||
|
ax.set_ylim(0, 130)
|
||||||
|
ax.yaxis.set_major_locator(MultipleLocator(20))
|
||||||
|
ax.yaxis.set_minor_locator(MultipleLocator(5))
|
||||||
|
date_form = DateFormatter("%H:%M:%S")
|
||||||
|
ax.xaxis.set_major_formatter(date_form)
|
||||||
|
ax.yaxis.set_major_formatter("{x:1.1f} C")
|
||||||
|
ax.set_title("Temperature", fontsize=15)
|
||||||
|
|
||||||
|
imgdata = BytesIO()
|
||||||
|
fig.savefig(imgdata, format="svg")
|
||||||
|
imgdata.seek(0) # rewind the data
|
||||||
|
drawing = svg2rlg(imgdata)
|
||||||
|
imgdata.close()
|
||||||
|
plt.close("all")
|
||||||
|
|
||||||
|
temp_graph = KeepInFrame(375, 375, [Image(drawing)], hAlign="CENTER")
|
||||||
|
|
||||||
|
return temp_graph
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
import PySimpleGUI as sg
|
import PySimpleGUI as sg
|
||||||
from tools.cfg_util.record.layout import record_window
|
from tools.cfg_util.record.layout import get_record_window
|
||||||
from tools.cfg_util.record.func import (
|
from tools.cfg_util.record.func import (
|
||||||
start_recording,
|
start_recording,
|
||||||
stop_recording,
|
stop_recording,
|
||||||
@@ -11,8 +11,9 @@ from tools.cfg_util.record.func import (
|
|||||||
|
|
||||||
|
|
||||||
async def record_ui(ips: list):
|
async def record_ui(ips: list):
|
||||||
# if not len(ips) > 0:
|
if not len(ips) > 0:
|
||||||
# return
|
return
|
||||||
|
record_window = get_record_window()
|
||||||
while True:
|
while True:
|
||||||
event, values = record_window.read(0.001)
|
event, values = record_window.read(0.001)
|
||||||
if event in (None, "Close", sg.WIN_CLOSED):
|
if event in (None, "Close", sg.WIN_CLOSED):
|
||||||
@@ -20,13 +21,15 @@ async def record_ui(ips: list):
|
|||||||
|
|
||||||
if event == "start_recording":
|
if event == "start_recording":
|
||||||
if values["record_file"]:
|
if values["record_file"]:
|
||||||
asyncio.create_task(start_recording(ips, values["record_file"]))
|
asyncio.create_task(
|
||||||
|
start_recording(ips, values["record_file"], record_window)
|
||||||
|
)
|
||||||
if event == "stop_recording":
|
if event == "stop_recording":
|
||||||
asyncio.create_task(stop_recording())
|
asyncio.create_task(stop_recording(record_window))
|
||||||
if event == "resume_recording":
|
if event == "resume_recording":
|
||||||
asyncio.create_task(resume_recording())
|
asyncio.create_task(resume_recording(record_window))
|
||||||
if event == "pause_recording":
|
if event == "pause_recording":
|
||||||
asyncio.create_task(pause_recording())
|
asyncio.create_task(pause_recording(record_window))
|
||||||
|
|
||||||
if event == "__TIMEOUT__":
|
if event == "__TIMEOUT__":
|
||||||
await asyncio.sleep(0.001)
|
await asyncio.sleep(0.001)
|
||||||
|
|||||||
Reference in New Issue
Block a user