-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathapp.py
270 lines (221 loc) · 7.94 KB
/
app.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
# -*- coding: utf-8 -*-
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.graph_objs as go
from plotly import subplots
import ctypes
import numpy as np
import pandas as pd
import re
import logging
import load_triton_log
from datetime import datetime, timedelta
from pytz import timezone
import json
import socket
import argparse
# TODO Optimize Colors
# TODO Catch if sensor on top is disabled, switch between 2 MC Sensors?
config_file='triton200.json'
parser = argparse.ArgumentParser()
parser.add_argument('--filename', default='triton200.json')
parser.add_argument('--port', type=int, default=8080)
parser.add_argument('--host', type=str, default='auto')
args = parser.parse_args()
config_file = args.filename
port = args.port
if args.host == 'auto':
host = socket.gethostname()
else:
host = args.host
logger = logging.getLogger('tritonMonitor.app')
logger.setLevel(logging.DEBUG)
handler = logging.StreamHandler()
handler.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(levelname)s - %(message)s")
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.debug(host)
with open(config_file,'r') as file:
settings=json.load(file)
Log = load_triton_log.TritonLogReader(settings['log_file'])
Log.logger = logger
# Create main plot for the dashboard view
def m_str(val, unit='K'):
if val < 1:
unit = 'm' + unit
val *= 1e3
return f"{val:.1f} {unit}"
def make_static_traces(df, duration=None):
if duration is not None:
start_time = df['Time'].iloc[-1] - timedelta(days=duration)
else:
start_time = df['Time'].iloc[0]
temp_traces = [
go.Scatter(
x=df.loc[df[f'{trace} t(s)']>=start_time,f'{trace} t(s)'],
y=df.loc[df[f'{trace} t(s)']>=start_time,f'{trace} T(K)'],
legendgroup='temperature',
name=f'{trace} T(K)',
) for trace in settings['lakeshore_sensors']
]
pressure_traces = [
go.Scatter(
x=df.loc[df['Time']>=start_time,'Time'],
y=df.loc[df['Time']>=start_time,f'{trace}'],
legendgroup='pressure',
name=f'{trace}',
) for trace in settings['pressure_sensors']
]
return temp_traces + pressure_traces, [1]*len(temp_traces) + [2]*len(pressure_traces)
def make_static_figure(df, duration=None, lightweight_mode=True):
traces, subplot = make_static_traces(df, duration=duration)
fig = subplots.make_subplots(
rows=2,
cols=1,
specs=[[{}], [{}]],
shared_xaxes=True,
vertical_spacing=0.07,
subplot_titles=('Temperature Sensors', 'Pressure Sensors'),
print_grid=False
)
fig.add_traces(traces, rows=subplot, cols=[1]*len(traces))
fig['layout'].update(**settings['layout'])
val_RuOx = Log.df[settings['MC_RuOx']].iloc[-1]
val_Cernox = Log.df[settings['MC_Cernox']].iloc[-1]
if val_RuOx<3 or val_Cernox<3:
scale = "log"
else:
scale = "linear"
fig.update_layout(yaxis_type=scale)
for row in range(1,3):
fig.update_xaxes(gridcolor=settings['gridcolor'], zerolinecolor=settings['zerolinecolor'], row=row, col=1)
fig.update_yaxes(gridcolor=settings['gridcolor'], zerolinecolor=settings['zerolinecolor'], row=row, col=1)
return fig
# Create dash app, expose flask server (change localhost to expose server?)
app = dash.Dash(__name__, external_stylesheets=settings['external_stylesheets'],show_undo_redo=False)
server = app.server
app.title = settings['fridge_name'] + ' Fridge Monitor'
logger.debug('Creating Layout')
# Create Page Layout
dashboard = [html.Div( # Live Dashboard Part
style={
'columnCount': 4,
'textAlign': 'left',
'color': settings['colors']['text'],
'padding': 20
},
children=[
html.H4('Last Log Read', id='log header'),
html.H2('Last Log Read', id='update_time'),
html.H4('MC Temperature'),
html.H2('MC Temp', id='mc_temp_disp'),
html.H4('P2 Condenser'),
html.H2('P2', id='P2_disp'),
html.H4('Magnet Temperature'),
html.H2('Magnet Temp', id='magnet_temp_disp')
]
),
dcc.Interval(
id='interval-component',
interval=60*1000, # in milliseconds
n_intervals=0
),
dcc.Graph(id='static_plot')]
# Does it make sense to create 3 subplots for logviewer?
log_reader = [html.Label('MISC Channels',
style={'textAlign': 'center',
'color': settings['colors']['text']}, ),
dcc.Dropdown( # Log Reader Part
options=[
{'label': f'{trace}', 'value': f'{trace}'} for trace in settings['misc_sensors']
],
value=['turbo power(W)'],
multi=True,
style={
'background': settings['colors']['background'],
'color': settings['colors']['text']
},
id='misc_dropdown'
),
dcc.Graph(id='misc_plot')]
page_fridge_1 = dashboard + log_reader
app.layout = html.Div( # Main Div
style={'backgroundColor': settings['colors']['background']},
children=[
html.H1( #Header
children=settings['fridge_name'],
style={
'textAlign': 'center',
'color': settings['colors']['text'],
'padding': 15
}
)
]
+ page_fridge_1 # Page Content
)
# create callbacks
logger.debug('Creating callbacks')
@app.callback(
Output('static_plot', 'figure'),
[Input('interval-component', 'n_intervals')])
def update_static_figure(n_intervals):
logger.debug(f"{datetime.now().strftime('%H:%M:%S - %d.%m.%Y')}:Refreshing log")
Log.refresh()
with open(config_file,'r') as file:
settings=json.load(file)
fig = make_static_figure(Log.df,duration=settings['duration'])
fig.layout.uirevision = True
return fig
@app.callback(
Output('update_time', 'children'),
[Input('interval-component', 'n_intervals')])
def update_time_disp(n_intervals):
logger.debug('Refreshing update time disp')
return Log.last_refresh.strftime('%H:%M:%S %d.%m.%Y')
@app.callback(
Output('mc_temp_disp', 'children'),
[Input('interval-component', 'n_intervals')])
def update_mc_temp_disp(n_intervals):
logger.debug('Refreshing update MC Temp disp')
val_RuOx = Log.df[settings['MC_RuOx']].iloc[-1]
val_Cernox = Log.df[settings['MC_Cernox']].iloc[-1]
if val_Cernox is None:
val_ret = val_RuOx
elif val_RuOx >= 70:
val_ret = val_Cernox
else:
val_ret = val_RuOx
return m_str(val_ret)
@app.callback(
Output('P2_disp', 'children'),
[Input('interval-component', 'n_intervals')])
def update_P2_disp(n_intervals):
logger.debug('Refreshing P2 disp')
return m_str(Log.df['P2 Condense (Bar)'].iloc[-1], unit='bar')
@app.callback(
Output('magnet_temp_disp', 'children'),
[Input('interval-component', 'n_intervals')])
def update_magnet_temp_disp(n_intervals):
logger.debug('Refreshing Magnet Temp disp')
return m_str(Log.df[settings['Magnet']].iloc[-1])
@app.callback(
Output('misc_plot', 'figure'),
[Input('misc_dropdown', 'value')])
def update_misc_figure(plot_traces):
traces = [
go.Scatter(
x=Log.df['Time'],
y=Log.df[plot_trace],
name=plot_trace
) for plot_trace in plot_traces
]
return {
'data': traces,
'layout': settings['layout']
}
if __name__ == '__main__':
logger.debug('Starting app')
app.run_server(debug=True, host=host, port = port)