Skip to content
Snippets Groups Projects

WIP: pwb Testing GUI

Open Evan Paul Mladina requested to merge pwbGUI into master
1 file
+ 1130
0
Compare changes
  • Side-by-side
  • Inline
+ 1130
0
#!/usr/bin/env python3
import dash
import dash_table
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import plotly
import os
import io
import sys
from glob import glob
import time
import subprocess
import json
from production_database_scripts.itk_pdb import dbAccess
import re
import plotly.graph_objects as go
import pandas
import itertools
import signal
class Process:
def __init__(self, cmd, f):
self.cmd=cmd
self.proc=None
self.f=None
self.stdin = subprocess.PIPE
self.path_stdout='{}.out'.format(time.strftime("%Y%m%d-%H%M%S"))
print('store output in', self.path_stdout)
@property
def running(self):
if self.proc==None:
return False
return self.proc.poll()==None
@property
def returncode(self):
if self.proc==None:
return None
return self.proc.poll()
def communicate(self, cmd):
return self.proc.communicate(cmd)
def run(self):
if self.running:
# Already running...
return
# Prepare place to store the output
# self.fh_stdout=open(self.path_stdout, 'w')
# Start the process
# self.proc=subprocess.Popen(self.cmd, stdout=self.fh_stdout)
self.proc=subprocess.Popen(self.cmd, stdin = subprocess.PIPE, stdout = self.f, stderr = self.f, bufsize = 1, universal_newlines=True, shell=False)
def stop(self):
if not self.running:
# Not running
return
self.proc.terminate()
processes = [None]*10
initial_run_storage=['Stopped']*10
### Make text files ###
for i in range(0,10):
open('terminal_text_' + str(i) + '.txt', 'w').close()
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
colors={'background':'#8E8D8A',
'divs':'#EAE7DC',
'text':'#C5C6C7',
'button':'#85DCB',
'debug':'#FF6666',
'Running':'green',
'Done':'yellow',
'Error':'red',
'Stopped':'blue',
'running-panel':'yellow'
}
runStyle = {'backgroundColor':colors['running-panel']}
initial_trig = [0,0]
initial_button = {'0':False, '1':False, '2':False, '3':False, '4':False, '5':False, '6':False, '7':False, '8':False, '9':False}
initial_button_colors = {'0':{}, '1':{}, '2':{}, '3':{}, '4':{}, '5':{}, '6':{}, '7':{}, '8':{}, '9':{}}
initial_tabs = {'0':{}, '1':{}, '2':{}, '3':{}, '4':{}, '5':{}, '6':{}, '7':{}, '8':{}, '9':{}}
app.layout = html.Div(children=[
dcc.Store(id = 'login'),
html.Div(id='itk', children=[
html.H1(children=["ATLAS Powerboard Testing"]),
html.Div(children=[
dcc.Input(id = 'pass-1', type = 'password', placeholder='ITk Database Password 1')],
style={'margin-left':20, 'margin-right':5, 'display':'inline-block'}),
html.Div(children=[
dcc.Input(id = 'pass-2', type = 'password', placeholder='ITk Database Password 2')],
style={'margin-right':10, 'display':'inline-block'}),
html.Button(id = 'itk-button', n_clicks=0, children='Login'),
html.Div(children=[
html.Button(id = 'skip-login', n_clicks=0, children='Test Without Uploading')],
style={'display':'inline-block', 'margin-left':80})
]),
html.Div(id='test-page', children=[
html.Div(id='temp-div'),
html.Div(id='temp-tab-checker'),
html.Div(id='run-storage-div'),
dcc.Store(id='run-storage', storage_type='memory'),
dcc.Store(id='diag-storage', storage_type='local'),
dcc.Store(id='mass-storage', storage_type='local'),
dcc.Store(id='panel-storage', storage_type='session'),
dcc.Store(id='eff-table-storage', storage_type='local'),
dcc.Store(id='diagnostic-button-storage', storage_type='local'),
dcc.Store(id='mass-button-storage', storage_type='local'),
dcc.Store(id='tab-storage', storage_type='local'),
dcc.Tabs(id='tabs', value='0', children=[
dcc.Tab(id='tab-0', label='Panel 0', value='0'),
dcc.Tab(id='tab-1', label='Panel 1', value='1'),
dcc.Tab(id='tab-2', label='Panel 2', value='2'),
dcc.Tab(id='tab-3', label='Panel 3', value='3'),
dcc.Tab(id='tab-4', label='Panel 4', value='4'),
dcc.Tab(id='tab-5', label='Panel 5', value='5'),
dcc.Tab(id='tab-6', label='Panel 6', value='6'),
dcc.Tab(id='tab-7', label='Panel 7', value='7'),
dcc.Tab(id='tab-8', label='Panel 8', value='8'),
dcc.Tab(id='tab-9', label='Panel 9', value='9')
]),
html.Div(id='ip'),
html.Div(id='tab-store-div'),
html.Div(id='test-display', children=[""]),
html.Div(id='trigger-test-display', children=["2"]),
html.Div(id='display-debug-mode', children=[
dcc.Checklist(id='debug-mode', options = [
{'label': 'Disable Automatic Uploading', 'value': 'disable'}],
value = [])],
style={}),
html.H1(id='ATLAS-title', children=["ATLAS Powerboard Testing"],
style={'text-align':'center'}),
html.Div(id='panel-div', children=[
dcc.Interval(
id='interval-component',
interval = 1*500,
n_intervals = 0
),
html.Div(children=[
dcc.Input(id='panel-number', value='', placeholder='Panel number'),
html.Button(id='panel-populate-button', n_clicks=0, children='AutoFill Panel', style={'background-color':colors['button']})],
style={'padding-bottom':40, 'padding-top':20}),
html.Div(children=[
dcc.Input(id='version', placeholder='Powerboard Version Number'),
dcc.Input(id='batch', placeholder='Powerboard Batch Number')],
style={'padding-bottom':20}),
html.Div(children=[
html.Div(children=[
dcc.Checklist(id='pb-0', options = [
{'label': 'Board 0', 'value': '0'}],
value = ['0']),
dcc.Input(id='serial-0', placeholder='PB0 Serial Number')],
style={'padding-bottom':10}),
html.Div(children=[
dcc.Checklist(id='pb-1', options = [
{'label': 'Board 1', 'value': '1'}],
value = ['1']),
dcc.Input(id='serial-1', placeholder='PB1 Serial Number')],
style={'padding-bottom':10}),
html.Div(children=[
dcc.Checklist(id='pb-2', options = [
{'label': 'Board 2', 'value': '2'}],
value = ['2']),
dcc.Input(id='serial-2', placeholder='PB2 Serial Number')],
style={'padding-bottom':10}),
html.Div(children=[
dcc.Checklist(id='pb-3', options = [
{'label': 'Board 3', 'value': '3'}],
value = ['3']),
dcc.Input(id='serial-3', placeholder='PB3 Serial Number')],
style={'padding-bottom':10}),
html.Div(children=[
dcc.Checklist(id='pb-4', options = [
{'label': 'Board 4', 'value': '4'}],
value = ['4']),
dcc.Input(id='serial-4', placeholder='PB4 Serial Number')],
style={'padding-bottom':10})],
style={'display':'inline-block'}),
html.Div(children=[
html.Div(children=[
dcc.Checklist(id='pb-5', options = [
{'label': 'Board 5', 'value': '5'}],
value = ['5']),
dcc.Input(id='serial-5', placeholder='PB5 Serial Number')],
style={'padding-bottom':10}),
html.Div(children=[
dcc.Checklist(id='pb-6', options = [
{'label': 'Board 6', 'value': '6'}],
value = ['6']),
dcc.Input(id='serial-6', placeholder='PB6 Serial Number')],
style={'padding-bottom':10}),
html.Div(children=[
dcc.Checklist(id='pb-7', options = [
{'label': 'Board 7', 'value': '7'}],
value = ['7']),
dcc.Input(id='serial-7', placeholder='PB7 Serial Number')],
style={'padding-bottom':10}),
html.Div(children=[
dcc.Checklist(id='pb-8', options = [
{'label': 'Board 8', 'value': '8'}],
value = ['8']),
dcc.Input(id='serial-8', placeholder='PB8 Serial Number')],
style={'padding-bottom':10}),
html.Div(children=[
dcc.Checklist(id='pb-9', options = [
{'label': 'Board 9', 'value': '9'}],
value = ['9']),
dcc.Input(id='serial-9', placeholder='PB9 Serial Number')],
style={'padding-bottom':10})],
style={'display':'inline-block'}),
html.Div(children=[
html.Button(id='diagnostic-table-button', n_clicks=0, children='Diagnostic Table')]),
],
style={'margin-left':20, 'backgroundColor':colors['divs'],'display':'inline-block', 'padding':20, 'border':'outset'}
),
html.Div(children=[
html.Div(children=[
dcc.RadioItems(id='QC-Reception', options = [
{'label': 'QC Testing', 'value': 'qc'},
{'label': 'Reception Testing', 'value': 'r'}],
value='qc')],
style={'margin-bottom':30}),
html.Div(children=[
dcc.RadioItems(id='debug', options = [
{'label': 'None', 'value': ''},
{'label': 'Debug', 'value': '-d'},
{'label': 'Super Debug', 'value': '-dddd'}],
value = ''),
html.Button(id='diagnostic-test-button', n_clicks=0, children='Run Diagnostic Test'),
html.Button(id='mass-test-button', n_clicks=0, children='Run Characterization Test'),
html.Button(id='stop-button', n_clicks=0, children='Stop Test'),
html.Div(id='hidden-diag-div', children=''),
html.Div(id='hidden-mass-div', children=''),
html.Div(id='hidden-stop-div', children=''),
html.Div(id='diagnostic-pull', children="")],
style={'padding-bottom':20}),
html.Div(children=[
html.Div(id='display-test',style={'fontSize': 16, 'font-family':"Lucida Sans Unicode", 'whiteSpace':'pre-wrap', 'wordBreak': 'break-all', 'width':'100%', 'height':'100%', 'overflow':'scroll'})],
style={'display':'inline-block', 'border': '8px solid gray', 'width':'1000px', 'height':'600px'}),
html.Div(id='display-diagnostic-test-check', children = ''),
html.Div(id='display-mass-test-check', children = ''),
html.Div([
html.Div(children=[
dcc.Graph(
id='lviv-graph'),
dcc.Graph(
id='eff-graph')],
style={'display':'inline-block'}
),
html.Div(children=[
dcc.Graph(
id='icur-graph'),
dcc.Graph(
id='ocur-graph')],
style={'display':'inline-block'}),
html.Div(children=[
dcc.Graph(
id='gain0-graph'),
dcc.Graph(
id='gain1-graph')],
style={'display':'inline-block'}
),
html.Div(children=[
dcc.Graph(
id='gain2-graph'),
dcc.Graph(
id='gain4-graph')],
style={'display':'inline-block'}
),
html.Div(children=[
dcc.Graph(
id='gain8-graph'),
dcc.Graph(
id='eff-table')],
style={'display':'inline-block'})
],
style={'height':2500, 'width':1000, 'border-style':'outset'}
)],
style={'margin-left':20, 'backgroundColor':colors['divs'], 'display':'inline-block', 'vertical-align':'top', 'padding':30, 'border-style':'inset'}
)
],
style={'backgroundColor':colors['background'], 'position':'absolute', 'top':0, 'bottom':0, 'left':0, 'right':0, 'margin':'auto', 'display':'none'})
])
@app.callback(
Output('debug-mode', 'value'),
[Input('skip-login', 'n_clicks')])
def skipLogin(button):
if(button==0):
return []
else:
return ['disable']
@app.callback(
[Output('test-page', 'style'),
Output('login', 'data'),
Output('itk', 'style'),
Output('ATLAS-title', 'children'),
Output('pass-1', 'value'),
Output('pass-2', 'value'),
Output('display-debug-mode', 'style'),
Output('panel-div', 'style')],
[Input('itk-button', 'n_clicks'),
Input('skip-login', 'n_clicks'),
Input('debug-mode', 'value')],
[State('pass-1', 'value'),
State('pass-2', 'value')])
def displayTestPage(button, skipLogin, debug, pass1, pass2):
if(button==0 and skipLogin==0):
return {'backgroundColor':colors['background'], 'position':'absolute', 'top':0, 'bottom':0, 'left':0, 'right':0, 'margin':'auto', 'display':'none'}, [], {'display':'inline'}, '', '', '', {}, {'margin-left':20, 'backgroundColor':colors['divs'],'display':'inline-block', 'padding':20}
if(skipLogin==1):
return {'backgroundColor':colors['background'], 'position':'absolute', 'top':0, 'bottom':0, 'left':0, 'right':0, 'margin':'auto', 'display':'inline'}, [], {'display':'none'}, 'ATLAS Powerboard Testing (Debug Mode)', '', '', {'display':'none'}, {'margin-left':20, 'backgroundColor':colors['debug'],'display':'inline-block', 'padding':20, 'border-style':'outset'}
else:
context = dash.callback_context.triggered[0]['prop_id'].split('.')[0]
context_value=dash.callback_context.triggered[0]['value']
if(context=='itk-button'):
if(pass1=='' or pass2==''):
return {'backgroundColor':colors['background'], 'position':'absolute', 'top':0, 'bottom':0, 'left':0, 'right':0, 'margin':'auto', 'display':'none'}, [], {'display':'inline'}, '', '', '', {}, {'margin-left':20, 'backgroundColor':colors['divs'],'display':'inline-block', 'padding':20}
else:
try:
os.environ["ITK_DB_AUTH"] = dbAccess.authenticate(pass1, pass2)
return {'backgroundColor':colors['background'], 'position':'absolute', 'top':0, 'bottom':0, 'left':0, 'right':0, 'margin':'auto', 'display':'inline'}, [pass1, pass2], {'display':'none'}, 'ATLAS Powerboard Testing', '', '', {}, {'margin-left':20, 'backgroundColor':colors['divs'],'display':'inline-block', 'padding':20, 'border-style':'outset'}
except:
return {'backgroundColor':colors['background'], 'position':'absolute', 'top':0, 'bottom':0, 'left':0, 'right':0, 'margin':'auto', 'display':'none'}, [], {'display':'inline'}, '', '', '', {}, {'margin-left':20, 'backgroundColor':colors['divs'],'display':'inline-block', 'padding':20, 'border-style':'outset'}
elif(context=='skip-login'):
return {'backgroundColor':colors['background'], 'position':'absolute', 'top':0, 'bottom':0, 'left':0, 'right':0, 'margin':'auto', 'display':'inline'}, [], {'display':'none'}, 'ATLAS Powerboard Testing (Debug Mode)', '', '', {'display':'none'}, {'margin-left':20, 'backgroundColor':colors['debug'],'display':'inline-block', 'padding':20, 'border-style':'outset'}
else:
if(context_value==['disable']):
return {'backgroundColor':colors['background'], 'position':'absolute', 'top':0, 'bottom':0, 'left':0, 'right':0, 'margin':'auto', 'display':'inline'}, [pass1, pass2], {'display':'none'}, 'ATLAS Powerboard Testing (Debug Mode)', '', '', {}, {'margin-left':20, 'backgroundColor':colors['debug'],'display':'inline-block', 'padding':20, 'border-style':'outset'}
else:
return {'backgroundColor':colors['background'], 'position':'absolute', 'top':0, 'bottom':0, 'left':0, 'right':0, 'margin':'auto', 'display':'inline'}, [pass1, pass2], {'display':'none'}, 'ATLAS Powerboard Testing', '', '', {}, {'margin-left':20, 'backgroundColor':colors['divs'],'display':'inline-block', 'padding':20, 'border-style':'outset'}
@app.callback(
Output('temp-div', 'children'),
[Input('interval-component', 'n_intervals')])
def intervalTest(interval):
return str(interval)
@app.callback(
Output('ip', 'children'),
[Input('tabs', 'value')])
def switch_panel(tab):
if tab=='0':
return 'epmladina@128.3.2.147'
if tab=='1':
return 'epmladina@128.3.2.147'
if tab=='2':
return 'ip-2'
if tab=='3':
return 'ip-3'
if tab=='4':
return 'ip-4'
if tab=='5':
return 'ip-5'
if tab=='6':
return 'ip-6'
if tab=='7':
return 'ip-7'
if tab=='8':
return 'ip-8'
if tab=='9':
return 'ip-9'
@app.callback(
Output('panel-storage', 'data'),
[Input('panel-number', 'value'),
Input('debug', 'value'),
Input('version', 'value'),
Input('batch', 'value'),
Input('pb-0', 'value'),
Input('serial-0', 'value'),
Input('pb-1', 'value'),
Input('serial-1', 'value'),
Input('pb-2', 'value'),
Input('serial-2', 'value'),
Input('pb-3', 'value'),
Input('serial-3', 'value'),
Input('pb-4', 'value'),
Input('serial-4', 'value'),
Input('pb-5', 'value'),
Input('serial-5', 'value'),
Input('pb-6', 'value'),
Input('serial-6', 'value'),
Input('pb-7', 'value'),
Input('serial-7', 'value'),
Input('pb-8', 'value'),
Input('serial-8', 'value'),
Input('pb-9', 'value'),
Input('serial-9', 'value')],
[State('panel-populate-button', 'n_clicks'),
State('tabs', 'value'),
State('panel-storage', 'data')])
def update_panel_storage(*args):
data = args[26] or {}
data[args[25]] = args[0:25]
return data
#@app.callback(
# Output('display-test', 'children'),
# [Input('interval-component', 'n_intervals'),
# Input('tabs', 'value')])
#def display_test(n, tab):
# reaesc = re.compile(r'\x1b[^m]*m')
# with open('terminal_text_' + tab + '.txt') as f:
# origFile = f.read()
# regFile = reaesc.sub('', origFile)
# f.close()
# return regFile
@app.callback(
[Output('panel-number', 'value'),
Output('debug', 'value'),
Output('version', 'value'),
Output('batch', 'value'),
Output('pb-0', 'value'),
Output('serial-0', 'value'),
Output('pb-1', 'value'),
Output('serial-1', 'value'),
Output('pb-2', 'value'),
Output('serial-2', 'value'),
Output('pb-3', 'value'),
Output('serial-3', 'value'),
Output('pb-4', 'value'),
Output('serial-4', 'value'),
Output('pb-5', 'value'),
Output('serial-5', 'value'),
Output('pb-6', 'value'),
Output('serial-6', 'value'),
Output('pb-7', 'value'),
Output('serial-7', 'value'),
Output('pb-8', 'value'),
Output('serial-8', 'value'),
Output('pb-9', 'value'),
Output('serial-9', 'value')],
[Input('panel-populate-button', 'n_clicks'),
Input('tabs', 'value')],
[State('panel-number', 'value'),
State('panel-storage', 'data')])
def populatePanel(button, tab, panelNum, data):
if(data is not None):
if(button==data['0'][24]):
if(tab in data):
return data[tab][0:24]
else:
return ['', '', '','',['0'],'',['1'],'',['2'],'',['3'],'',['4'],'',['5'],'',['6'],'',['7'],'',['8'],'',['9'],'']
###### TODO: update directory
else:
if(button!=0 and os.path.exists("panelNumbers/panel" + panelNum + ".json")):
f = open("panelNumbers/panel" + panelNum + ".json")
json_data = json.load(f)
contents = []
contents.append(data[tab][0])
contents.append(data[tab][1])
contents.append(json_data[panelNum]['version'])
contents.append(json_data[panelNum]['batch'])
for i in range (0,10):
if(json_data[panelNum]['serials'][i] == ''):
contents.append([''])
else:
contents.append([str(i)])
contents.append(json_data[panelNum]['serials'][i])
return contents
else:
return ['', '', '','',['0'],'',['1'],'',['2'],'',['3'],'',['4'],'',['5'],'',['6'],'',['7'],'',['8'],'',['9'],'']
else:
return ['', '', '','',['0'],'',['1'],'',['2'],'',['3'],'',['4'],'',['5'],'',['6'],'',['7'],'',['8'],'',['9'],'']
@app.callback(
Output('run-storage-div', 'children'),
[Input('interval-component', 'n_intervals')])
def updatePanelColorsDiv(interval):
global processes
status = []
for i in range(0,10):
if processes[i] == None:
status.append('Stopped')
elif processes[i].poll() == None:
status.append('Running')
elif processes[i].poll() >= 0:
status.append('Done')
else:
status.append('Killed')
return status
@app.callback(
Output('run-storage', 'data'),
[Input('interval-component', 'n_intervals')])
def updatePanelColors(interval):
global processes
status = []
for i in range(0,10):
if processes[i] == None:
status.append('Stopped')
elif processes[i].poll() == None:
status.append('Running')
elif processes[i].poll() >= 0:
status.append('Done')
else:
status.append('Killed')
return status
# if (runStorage === undefined) {
# for (i=0; i < 10; i++) {
# tabColors.push('blue');
# tabColors.push('blue');
# }
# } else {
app.clientside_callback(
"""
function(time, runStorage) {
let tabColors = [];
if(runStorage === undefined) {
for(let i=0; i<10; i++){
tabColors.push({'background-color':'black'});
tabColors.push({'background-color':'black'});
}
} else {
for(let i=0; i<runStorage.length; i++) {
if (runStorage[i] == 'Stopped') {
tabColors.push({'background-color':''});
tabColors.push({'background-color':''});
} else if (runStorage[i] == 'Running') {
tabColors.push({'background-color':'green'});
tabColors.push({'background-color':'green'});
} else if (runStorage[i] == 'Done') {
tabColors.push({'background-color':'yellow'});
tabColors.push({'background-color':'yellow'});
} else if (runStorage[i] == 'Error') {
tabColors.push({'background-color':'red'});
tabColors.push({'background-color':'red'});
} else {
tabColors.push({'background-color':'black'});
tabColors.push({'background-color':'black'});
}
}
}
return tabColors;
}
""",
[Output('tab-0', 'style'),
Output('tab-0', 'selected_style'),
Output('tab-1', 'style'),
Output('tab-1', 'selected_style'),
Output('tab-2', 'style'),
Output('tab-2', 'selected_style'),
Output('tab-3', 'style'),
Output('tab-3', 'selected_style'),
Output('tab-4', 'style'),
Output('tab-4', 'selected_style'),
Output('tab-5', 'style'),
Output('tab-5', 'selected_style'),
Output('tab-6', 'style'),
Output('tab-6', 'selected_style'),
Output('tab-7', 'style'),
Output('tab-7', 'selected_style'),
Output('tab-8', 'style'),
Output('tab-8', 'selected_style'),
Output('tab-9', 'style'),
Output('tab-9', 'selected_style')],
[Input('run-storage', 'modified_timestamp')],
[State('run-storage', 'data')]
)
@app.callback(
[Output('hidden-stop-div', 'children')],
[Input('tabs', 'value'),
Input('stop-button', 'n_clicks')])
def stopTest(tab, button):
global processes
if button!=0:
if processes[int(tab)]!=None:
processes[int(tab)].kill()
return ['']
@app.callback(
Output('diag-storage', 'data'),
[Input('diagnostic-test-button', 'n_clicks')],
[State('ip', 'children'),
State('tabs', 'value'),
State('diag-storage', 'data'),
State('debug-mode', 'value'),
State('QC-Reception', 'value'),
State('login', 'data'),
State('panel-number', 'value'),
State('version', 'value'),
State('batch', 'value'),
State('pb-0', 'value'),
State('pb-1', 'value'),
State('pb-2', 'value'),
State('pb-3', 'value'),
State('pb-4', 'value'),
State('pb-5', 'value'),
State('pb-6', 'value'),
State('pb-7', 'value'),
State('pb-8', 'value'),
State('pb-9', 'value'),
State('serial-0', 'value'),
State('serial-1', 'value'),
State('serial-2', 'value'),
State('serial-3', 'value'),
State('serial-4', 'value'),
State('serial-5', 'value'),
State('serial-6', 'value'),
State('serial-7', 'value'),
State('serial-8', 'value'),
State('serial-9', 'value'),
State('debug', 'value')]
)
def runDiagnosticTest(button, ip, tab, data, debugMode, QCRecep, login, *args):
if(button!=0):
global processes
cmd = './bin/pbv3_diagnostic_test_GUI' + getCommand(button, *args)
stopped=False
if processes[int(tab)]!=None:
if processes[int(tab)].poll()!=None:
stopped=True
if processes[int(tab)]==None or stopped:
f = open("terminal_text_" + tab + ".txt", "w")
if(QCRecep=='qc'):
processes[int(tab)] = subprocess.Popen(["ssh", ip, "cd powertools/build; " + cmd], stdin = subprocess.PIPE, stdout = f, stderr = f, universal_newlines=True)
else:
processes[int(tab)] = subprocess.Popen(["cd powertools/build; " + cmd], stdin = subprocess.PIPE, stdout = f, stderr = f, universal_newlines=True)
processes[int(tab)].wait()
if(debugMode!=['disable']):
#upload
pass1=login[0]
pass2=login[1]
if(args[0]==''):
panelNum = 'TEST'
else:
panelNum = args[0]
#This will likely not work. What happens if a test finishes before another but was started after. Will upload the wrong test results.
panel_dates=glob('panel' + panelNum + '/*/')
latest_date=max(panel_dates, key=os.path.getmtime)
upload=subprocess.Popen(["./production_database_scripts/strips/pwbs/uploadPanelTests.py", latest_date, pass1, pass2], stdin=subprocess.PIPE, shell=True)
return data
@app.callback(
Output('mass-storage', 'data'),
[Input('mass-test-button', 'n_clicks')],
[State('ip', 'children'),
State('tabs', 'value'),
State('mass-storage', 'data'),
State('debug-mode', 'value'),
State('QC-Reception', 'value'),
State('login', 'data'),
State('panel-number', 'value'),
State('version', 'value'),
State('batch', 'value'),
State('pb-0', 'value'),
State('pb-1', 'value'),
State('pb-2', 'value'),
State('pb-3', 'value'),
State('pb-4', 'value'),
State('pb-5', 'value'),
State('pb-6', 'value'),
State('pb-7', 'value'),
State('pb-8', 'value'),
State('pb-9', 'value'),
State('serial-0', 'value'),
State('serial-1', 'value'),
State('serial-2', 'value'),
State('serial-3', 'value'),
State('serial-4', 'value'),
State('serial-5', 'value'),
State('serial-6', 'value'),
State('serial-7', 'value'),
State('serial-8', 'value'),
State('serial-9', 'value'),
State('debug', 'value')]
)
def runMassTest(button, ip, tab, data, debugMode, QCRecep, login, *args):
if(button!=0):
global processes
cmd = './bin/pbv3_mass_test_GUI' + getCommand(button, *args)
stopped=False
if processes[int(tab)]!=None:
if processes[int(tab)].poll()!=None:
stopped=True
if processes[int(tab)]==None or stopped:
f = open("terminal_text_" + tab + ".txt", "w")
processes[int(tab)] = subprocess.Popen(["ssh", ip, "cd powertools/build; " + cmd], stdin = subprocess.PIPE, stdout = f, stderr = f, universal_newlines=True)
processes[int(tab)].wait()
if(debugMode!=['disable']):
#upload
pass1=login[0]
pass2=login[1]
if(args[0]==''):
panelNum = 'TEST'
else:
panelNum = args[0]
#This will likely not work. What happens if a test finishes before another but was started after. Will upload the wrong test results.
panel_dates=glob('panel' + panelNum + '/*/')
latest_date=max(panel_dates, key=os.path.getmtime)
upload=subprocess.Popen(["./production_database_scripts/strips/pwbs/uploadPanelTests.py", latest_date, pass1, pass2], stdin=subprocess.PIPE, shell=True)
return data
@app.callback(
Output('diagnostic-pull', 'children'),
[Input('diagnostic-table-button', 'n_clicks')]
)
def displayDiagnosticTable(button):
if(button!=0):
#### Change to open results currently being displayed
subprocess.call(['/misc/petalinux/pbv3_mass_tester/home/epmladina/powertools/build/production_database_scripts/strips/pwbs/makeDiagnosticPlot.py', '/misc/petalinux/pbv3_mass_tester/home/epmladina/powertools/build/panelTEST/2020_01_23-04:44:03'])
subprocess.Popen(['xdg-open', '/misc/petalinux/pbv3_mass_tester/home/epmladina/powertools/build/production_database_scripts/strips/pwbs/report.pdf'])
return ""
#app.clientside_callback(
# """
# function(tab, interval) {
# reaesc = re.compile(r'\x1b[^m]*m')
# with open('terminal_text_' + tab + '.txt') as f:
# text = f.read()
# clean_text = reaesc.sub('', text)
# f.close()
# lviv_pattern = "Running from 6V to 11V[^\\n]*\s([^\[?]*)"
# eff_pattern = "Vin\s*Iin\s*Vout\s*Iout\s*IoutSense\s*Vdcdc[^\n]*\s([^\[?]*)"
# lviv_graph = updateGraphs(lviv_pattern, clean_text, 1, 2, 'LV IV Scan', 'Voltage [V]', 'Current[A]')
# [eff_graph, icur_graph, ocur_graph] = updateEfficiency(eff_pattern, clean_text)
# return clean_text, lviv_graph, eff_graph, icur_graph, ocur_graph
# }
# """,
# [Output('display-test', 'children'),
# Output('lviv-graph', 'figure'),
# Output('eff-graph', 'figure'),
# Output('icur-graph', 'figure'),
# Output('ocur-graph', 'figure')],
# [Input('tabs', 'value'),
# Input('interval-component', 'n_intervals')]
#)
#@app.callback(
# Output('')
def getCommand(button, *args):
pbs = []
for i in range (3,13):
if(len(args[i])==1):
if(args[i][0]):
pbs.append(args[i][0])
pb_string = ' -b ' + ','.join(pbs)
serials = []
for i in range(13,23):
if(args[i] and args[i]!=None and not args[i].isspace()):
serials.append(args[i])
serial_string = ''
if(len(serials)>0):
serial_string = ' -s ' + ','.join(serials)
if(args[0] and args[0]!=None and not args[0].isspace()):
panel_string = ' ' + args[0]
else:
panel_string = ' TEST'
if(args[1] and args[1]!=None and not args[1].isspace()):
version_string = ' -v ' + args[1]
else:
version_string = ''
if(args[2] and args[2]!=None and not args[2].isspace()):
batch_string = ' -a ' + args[2]
else:
batch_string = ''
if(args[23]==''):
debug_string = ''
else:
debug_string = ' ' + args[23]
return panel_string + pb_string + version_string + batch_string + serial_string + debug_string
def updateGraphs(pattern, text, col1, col2, title, xaxis, yaxis):
pbPattern = "Performing full test suite on powerboard \d"
regex = re.compile(pattern)
pbRegex = re.compile(pbPattern)
matches = regex.finditer(text)
pbMatches = pbRegex.finditer(text)
## Line up matches with pb numbers in the event that tests are skipped for a powerboard (resulting in no matches for that board) ##
matchSort = []
pbSort = []
pbStarts = []
for pbNums in pbMatches:
pbSort.append(pbNums)
pbStarts.append(pbNums.start())
matchSort.append(None)
for match in matches:
for i in range(0, len(pbStarts)):
if match.start()>pbStarts[i]:
if(i+1!=len(pbStarts)):
if(match.start()<pbStarts[i+1]):
matchSort[i]=match
else:
matchSort[i]=match
fig = go.Figure()
fig.update_layout(
autosize=False,
showlegend=True,
width=500,
height=500,
title=title,
xaxis_title=xaxis,
yaxis_title=yaxis)
if(matches!=None):
for (pbNums, matched) in zip(pbSort, matchSort):
if(matched==None):
continue
match = matched.group(1)
pbNum = pbNums[0][-1]
x_ax=[]
y_ax=[]
for line in match.splitlines():
splitter=line.split()
x_ax.append(float(splitter[col1]))
y_ax.append(float(splitter[col2]))
fig.add_trace(go.Scatter(x=x_ax, y=y_ax, name='PB ' + pbNum))
return fig
def updateEfficiency(pattern, text):
pbPattern = "Performing full test suite on powerboard \d"
regex = re.compile(pattern)
pbRegex = re.compile(pbPattern)
matches = regex.finditer(text)
pbMatches = pbRegex.finditer(text)
## Line up matches with pb numbers in the event that tests are skipped for a powerboard (resulting in no matches for that board) ##
matchSort = []
pbSort = []
pbStarts = []
for pbNums in pbMatches:
pbSort.append(pbNums)
pbStarts.append(pbNums.start())
matchSort.append(None)
for match in matches:
for i in range(0, len(pbStarts)):
if match.start()>pbStarts[i]:
if(i+1!=len(pbStarts)):
if(match.start()<pbStarts[i+1]):
matchSort[i]=match
else:
matchSort[i]=match
effFig = createFigure('DC/DC Efficiency', 'Load Current [A]', 'Efficiency')
icurFig = createFigure('Input Current Monitor', 'Input Current [A]', 'AMAC Input Current [counts]')
ocurFig = createFigure('Output Current Monitor', 'Output Current [A]', 'AMAC Output Current [counts]')
effTable = createTable(['PB', 'Efficiency at 2A'])
if(matches!=None):
eff_table_entries=['']*10
eff_table_colors=['white']*10
for (pbNums, matched) in zip(pbSort, matchSort):
if(matched==None):
continue
match = matched.group(1)
pbNum = pbNums[0][-1]
x_ax_eff=[]
y_ax_eff=[]
x_ax_icur=[]
y_ax_icur=[]
x_ax_ocur=[]
y_ax_ocur=[]
color = ''
for line in match.splitlines():
splitter=line.split()
########## make sure this is set to ioutsense
## Remove values for which the efficiency is too small (except for the first few values) or too large. (This is caused by overheating.)
if(len(x_ax_eff)>3 and (float(splitter[12])<0.02 or float(splitter[12])>1)):
continue
if(float(splitter[3])==2):
if(float(splitter[12])>0.6):
color = 'green'
else:
color = 'red'
eff_table_entries[int(pbNum)]=splitter[12]
eff_table_colors[int(pbNum)]=color
x_ax_eff.append(float(splitter[3]))
y_ax_eff.append(float(splitter[12]))
x_ax_icur.append(float(splitter[1]))
y_ax_icur.append(float(splitter[9]))
x_ax_ocur.append(float(splitter[3]))
y_ax_ocur.append(float(splitter[10]))
effFig = addTraces(x_ax_eff, y_ax_eff, effFig, pbNum)
icurFig = addTraces(x_ax_icur, y_ax_icur, icurFig, pbNum)
ocurFig = addTraces(x_ax_ocur, y_ax_ocur, ocurFig, pbNum)
effTable = fillTable(eff_table_entries, eff_table_colors, effTable, ['PB', 'Efficiency at 2A'])
return effFig, icurFig, ocurFig, effTable
def updateHV(pattern, text):
pbPattern = "Performing full test suite on powerboard \d"
regex = re.compile(pattern)
pbRegex = re.compile(pbPattern)
matches = regex.finditer(text)
pbMatches = pbRegex.finditer(text)
## Line up matches with pb numbers in the event that tests are skipped for a powerboard (resulting in no matches for that board) ##
matchSort = []
pbSort = []
pbStarts = []
for pbNums in pbMatches:
pbSort.append(pbNums)
pbStarts.append(pbNums.start())
matchSort.append(None)
for match in matches:
for i in range(0, len(pbStarts)):
if match.start()>pbStarts[i]:
if(i+1!=len(pbStarts)):
if(match.start()<pbStarts[i+1]):
matchSort[i]=match
else:
matchSort[i]=match
gain0Fig = createFigure('HV Gain 0', 'HV Current [A]', 'AMAC Reading [counts]')
gain1Fig = createFigure('HV Gain 1', 'HV Current [A]', 'AMAC Reading [counts]')
gain2Fig = createFigure('HV Gain 2', 'HV Current [A]', 'AMAC Reading [counts]')
gain4Fig = createFigure('HV Gain 4', 'HV Current [A]', 'AMAC Reading [counts]')
gain8Fig = createFigure('HV Gain 8', 'HV Current [A]', 'AMAC Reading [counts]')
if(matches!=None):
for (pbNums, matched) in zip(pbSort, matchSort):
if(matched==None):
continue
match = matched.group(1)
pbNum = pbNums[0][-1]
x_gain0=[]
y_gain0=[]
x_gain1=[]
y_gain1=[]
x_gain2=[]
y_gain2=[]
x_gain4=[]
y_gain4=[]
x_gain8=[]
y_gain8=[]
for line in match.splitlines():
splitter=line.split()
x_gain0.append(float(splitter[4]))
y_gain0.append(float(splitter[5]))
x_gain1.append(float(splitter[4]))
y_gain1.append(float(splitter[6]))
x_gain2.append(float(splitter[4]))
y_gain2.append(float(splitter[7]))
x_gain4.append(float(splitter[4]))
y_gain4.append(float(splitter[8]))
x_gain8.append(float(splitter[4]))
y_gain8.append(float(splitter[9]))
gain0Fig = addTraces(x_gain0, y_gain0, gain0Fig, pbNum)
gain1Fig = addTraces(x_gain1, y_gain1, gain1Fig, pbNum)
gain2Fig = addTraces(x_gain2, y_gain2, gain2Fig, pbNum)
gain4Fig = addTraces(x_gain4, y_gain4, gain4Fig, pbNum)
gain8Fig = addTraces(x_gain8, y_gain8, gain8Fig, pbNum)
gain0Fig.update_layout(xaxis_type="log")
gain1Fig.update_layout(xaxis_type="log")
gain2Fig.update_layout(xaxis_type="log")
gain4Fig.update_layout(xaxis_type="log")
gain8Fig.update_layout(xaxis_type="log")
return gain0Fig, gain1Fig, gain2Fig, gain4Fig, gain8Fig
def addTraces(x, y, fig, pbNum):
fig.add_trace(go.Scatter(x=x, y=y, name='PB ' + pbNum))
return fig
def fillTable(eff, color, fig, titles):
pbs=[0,1,2,3,4,5,6,7,8,9]
fig.add_trace(go.Table(header=dict(values=titles),
cells=dict(values=[pbs, eff],
fill_color=[['white']*10, color])))
return fig
def createFigure(title, xaxis, yaxis):
fig = go.Figure()
fig.update_layout(
autosize=False,
showlegend=True,
width=500,
height=500,
title=title,
xaxis_title=xaxis,
yaxis_title=yaxis)
return fig
def createTable(titles):
pbs=[0,1,2,3,4,5,6,7,8,9]
fig = go.Figure(
data = [go.Table(header=dict(values=titles),
cells=dict(values=[pbs, ['']*10]))
])
fig.update_layout(
autosize=False,
width=500,
height=500)
return fig
#def regextest(tab, interval):
# reaesc = re.compile(r'\x1b[^m]*m')
# with open('terminal_text_' + tab + '.txt') as f:
# text = f.read()
# clean_text = reaesc.sub('', text)
# f.close()
#
# lviv_pattern = "Running from 6V to 11V[^\\n]*\s([^\[?]*)"
# eff_pattern = "Vin\s*Iin\s*Vout\s*Iout\s*IoutSense\s*Vdcdc[^\n]*\s([^\[?]*)"
#
# lviv_graph = updateGraphs(lviv_pattern, clean_text, 1, 2, 'LV IV Scan', 'Voltage [V]', 'Current[A]')
# [eff_graph, icur_graph, ocur_graph] = updateEfficiency(eff_pattern, clean_text)
#
# return clean_text, lviv_graph, eff_graph, icur_graph, ocur_graph
@app.callback(
[Output('display-test', 'children'),
Output('lviv-graph', 'figure'),
Output('eff-graph', 'figure'),
Output('icur-graph', 'figure'),
Output('ocur-graph', 'figure'),
Output('eff-table', 'figure'),
Output('gain0-graph', 'figure'),
Output('gain1-graph', 'figure'),
Output('gain2-graph', 'figure'),
Output('gain4-graph', 'figure'),
Output('gain8-graph', 'figure')],
[Input('tabs', 'value'),
Input('interval-component', 'n_intervals')]
)
def regextest(tab, interval):
reaesc = re.compile(r'\x1b[^m]*m')
with open('terminal_text_' + tab + '.txt') as f:
text = f.read()
clean_text = reaesc.sub('', text)
f.close()
lviv_pattern = "Running from 6V to 11V[^\\n]*\s([^\[?]*)"
eff_pattern = "Vin\s*Iin\s*Vout\s*Iout\s*IoutSense\s*Vdcdc[^\n]*\s([^\[?]*)"
hv_pattern = "HV_i_set\s*HV_v_set\s*HV_v\s*HV_i\s*HVout_i\s*Gain 0\s*Gain 1\s*Gain 2\s*Gain 4\s*Gain 8[^\n]*\s([^\[?]*)"
lviv_graph = updateGraphs(lviv_pattern, clean_text, 1, 2, 'LV IV Scan', 'Voltage [V]', 'Current[A]')
[eff_graph, icur_graph, ocur_graph, eff_table] = updateEfficiency(eff_pattern, clean_text)
[gain0_graph, gain1_graph, gain2_graph, gain4_graph, gain8_graph] = updateHV(hv_pattern, clean_text)
return clean_text, lviv_graph, eff_graph, icur_graph, ocur_graph, eff_table, gain0_graph, gain1_graph, gain2_graph, gain4_graph, gain8_graph
if __name__ == '__main__':
app.run_server(debug=True, port='8050')
Loading