Compare commits
8 Commits
a6475f2c3b
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| e1a3b498e5 | |||
| 9e1ebebeb2 | |||
| 2af30f3a32 | |||
| f3ccaaefd8 | |||
| a15aee1da6 | |||
| 353f073d12 | |||
| 10e2322882 | |||
| 72e3ede52f |
12
README.md
12
README.md
@@ -1,6 +1,6 @@
|
|||||||
# survBot
|
# survBot
|
||||||
|
|
||||||
version: 0.1
|
version: 0.2
|
||||||
|
|
||||||
survBot is a small program used to track station quality channels of DSEBRA stations via PowBox output over SOH channels
|
survBot is a small program used to track station quality channels of DSEBRA stations via PowBox output over SOH channels
|
||||||
by analysing contents of a Seiscomp3 datapath.
|
by analysing contents of a Seiscomp3 datapath.
|
||||||
@@ -40,8 +40,16 @@ The GUI can be loaded via
|
|||||||
python survBotGui.py
|
python survBotGui.py
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Version Changes
|
||||||
|
- surveillance of mass, clock and gaps
|
||||||
|
- individual mailing lists for different stations
|
||||||
|
- html mail with recent status information
|
||||||
|
- updated web page design
|
||||||
|
- restructured parameter file
|
||||||
|
- recognize if PBox is disconnected
|
||||||
|
|
||||||
## Staff
|
## Staff
|
||||||
|
|
||||||
Original author: M.Paffrath (marcel.paffrath@rub.de)
|
Original author: M.Paffrath (marcel.paffrath@rub.de)
|
||||||
|
|
||||||
November 2022
|
June 2023
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# survBot is a small program used to track station quality channels of DSEBRA stations via PowBox output
|
||||||
|
# over SOH channels by analysing contents of a Seiscomp3 datapath.
|
||||||
|
__version__ = "0.2"
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ add_global_links:
|
|||||||
- {"text": "show recent events on map",
|
- {"text": "show recent events on map",
|
||||||
"URL": "https://fdsnws.geophysik.ruhr-uni-bochum.de/map/?lat=39.5&lon=21&zoom=7&baselayer=mapnik"}
|
"URL": "https://fdsnws.geophysik.ruhr-uni-bochum.de/map/?lat=39.5&lon=21&zoom=7&baselayer=mapnik"}
|
||||||
|
|
||||||
# html logo at page bottom
|
# html logo at page bottom (path relative to html directory)
|
||||||
html_logo: "figures/Logo_RUB_BLAU_rgb.png"
|
html_logo: "figures/Logo_RUB_BLAU_rgb.png"
|
||||||
|
|
||||||
# E-mail notifications
|
# E-mail notifications
|
||||||
|
|||||||
@@ -3,27 +3,23 @@ body {
|
|||||||
place-items: center;
|
place-items: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding-bottom: 30px;
|
padding-bottom: 30px;
|
||||||
font-family: "Helvetica", "sans-serif"
|
font-family: "Helvetica", "sans-serif";
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
position: relative
|
position: relative
|
||||||
}
|
}
|
||||||
|
|
||||||
#managerTable {
|
|
||||||
max-height: 800px;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
td {
|
||||||
border-radius: 4px;
|
border-radius: 2px;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
th {
|
th {
|
||||||
background-color: #999;
|
background-color: #999;
|
||||||
border-radius: 4px;
|
color: #fff;
|
||||||
|
border-radius: 2px;
|
||||||
padding: 3px 1px;
|
padding: 3px 1px;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
@@ -35,7 +31,7 @@ a:link, a:visited {
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
display: block;
|
display: block;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
border: 1px solid #bbb;
|
border: 1px solid #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
|
|||||||
@@ -3,37 +3,35 @@ body {
|
|||||||
place-items: center;
|
place-items: center;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
padding-bottom: 30px;
|
padding-bottom: 30px;
|
||||||
font-family: "Helvetica", "sans-serif"
|
font-family: "Helvetica", "sans-serif";
|
||||||
}
|
}
|
||||||
|
|
||||||
table {
|
table {
|
||||||
position: relative
|
position: relative
|
||||||
}
|
}
|
||||||
|
|
||||||
#managerTable {
|
|
||||||
max-height: 800px;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
td {
|
td {
|
||||||
border-radius: 4px;
|
border-radius: 3px;
|
||||||
padding: 10px 2px;
|
padding: 10px 2px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
th {
|
th {
|
||||||
background-color: #999;
|
background-color: #999;
|
||||||
border-radius: 4px;
|
color: #fff;
|
||||||
|
border-radius: 3px;
|
||||||
padding: 10px, 2px;
|
padding: 10px, 2px;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:link {
|
a:link, a:visited {
|
||||||
background-color: #e8e8e8;
|
background-color: #e8e8e8;
|
||||||
color: #000;
|
color: #000;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
display: block;
|
display: block;
|
||||||
border-radius: 4px;
|
border-radius: 6px;
|
||||||
border: 1px solid #bbb;
|
border: 1px solid #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:hover {
|
a:hover {
|
||||||
@@ -49,9 +47,9 @@ a:hover {
|
|||||||
animation: blinkingBackground 2s infinite;
|
animation: blinkingBackground 2s infinite;
|
||||||
}
|
}
|
||||||
@keyframes blinkingBackground{
|
@keyframes blinkingBackground{
|
||||||
0% { background-color: #ffee00;}
|
0% { background-color: #ffcc00;}
|
||||||
50% { background-color: #ff3200;}
|
50% { background-color: #ff3200;}
|
||||||
100% { background-color: #ffee00;}
|
100% { background-color: #ffcc00;}
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer {
|
.footer {
|
||||||
|
|||||||
11
survBot.py
11
survBot.py
@@ -504,12 +504,21 @@ class SurveillanceBot(object):
|
|||||||
|
|
||||||
outfile.write(finish_html_table())
|
outfile.write(finish_html_table())
|
||||||
|
|
||||||
|
# add optional links below html table
|
||||||
for dct in self.add_global_links:
|
for dct in self.add_global_links:
|
||||||
link_str = get_html_link(dct.get('text'), dct.get('URL'))
|
link_str = get_html_link(dct.get('text'), dct.get('URL'))
|
||||||
outfile.write(get_html_text(link_str))
|
outfile.write(get_html_text(link_str))
|
||||||
|
|
||||||
|
# add status message
|
||||||
outfile.write(get_html_text(self.status_message))
|
outfile.write(get_html_text(self.status_message))
|
||||||
outfile.write(html_footer(footer_logo=self.parameters.get('html_logo')))
|
|
||||||
|
# write footer with optional logo
|
||||||
|
logo_file = self.parameters.get('html_logo')
|
||||||
|
if not os.path.isfile(pjoin(self.outpath_html, logo_file)):
|
||||||
|
print(f'Specified file {logo_file} not found.')
|
||||||
|
logo_file = None
|
||||||
|
|
||||||
|
outfile.write(html_footer(footer_logo=logo_file))
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f'Could not write HTML table to {fnout}:')
|
print(f'Could not write HTML table to {fnout}:')
|
||||||
|
|||||||
31
utils.py
31
utils.py
@@ -1,8 +1,6 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from functools import partial
|
|
||||||
|
|
||||||
import matplotlib
|
import matplotlib
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
@@ -36,17 +34,17 @@ def get_bg_color(check_key, status, dt_thresh=None, hex=False):
|
|||||||
|
|
||||||
|
|
||||||
def get_color(key):
|
def get_color(key):
|
||||||
# some GUI default colors
|
# some old GUI default colors
|
||||||
# colors_dict = {'FAIL': (255, 50, 0, 255),
|
# colors_dict = {'FAIL': (255, 85, 50, 255),
|
||||||
# 'NO DATA': (255, 255, 125, 255),
|
# 'NO DATA': (255, 255, 125, 255),
|
||||||
# 'WARN': (255, 255, 80, 255),
|
# 'WARN': (255, 255, 80, 255),
|
||||||
# 'OK': (125, 255, 125, 255),
|
# 'OK': (173, 255, 133, 255),
|
||||||
# 'undefined': (230, 230, 230, 255),
|
# 'undefined': (230, 230, 230, 255),
|
||||||
# 'disc': (255, 160, 40, 255),}
|
# 'disc': (255, 160, 40, 255),}
|
||||||
colors_dict = {'FAIL': (195, 29, 14, 255),
|
colors_dict = {'FAIL': (195, 29, 14, 255),
|
||||||
'NO DATA': (255, 255, 125, 255),
|
'NO DATA': (255, 255, 125, 255),
|
||||||
'WARN': (249, 238, 139, 255),
|
'WARN': (250, 192, 63, 255),
|
||||||
'OK': (179, 219, 153, 255),
|
'OK': (185, 245, 145, 255),
|
||||||
'undefined': (240, 240, 240, 255),
|
'undefined': (240, 240, 240, 255),
|
||||||
'disc': (126, 127, 131, 255), }
|
'disc': (126, 127, 131, 255), }
|
||||||
return colors_dict.get(key)
|
return colors_dict.get(key)
|
||||||
@@ -67,18 +65,11 @@ def get_time_delay_color(dt, dt_thresh):
|
|||||||
return get_color('FAIL')
|
return get_color('FAIL')
|
||||||
|
|
||||||
|
|
||||||
def get_warn_color(count):
|
def get_warn_color(count, n_colors=20):
|
||||||
n_colors = 20
|
if count >= n_colors:
|
||||||
# r = np.linspace(158, 255, n_colors, dtype=int)
|
count = -1
|
||||||
# g = np.linspace(255, 255, n_colors, dtype=int)
|
gradient = np.linspace((240, 245, 110, 255), (250, 192, 63, 255), n_colors, dtype=int)
|
||||||
# b = np.linspace(114, 80, n_colors, dtype=int)
|
return tuple(gradient[count])
|
||||||
r = np.linspace(204, 249, n_colors, dtype=int)
|
|
||||||
g = np.linspace(226, 238, n_colors, dtype=int)
|
|
||||||
b = np.linspace(149, 139, n_colors, dtype=int)
|
|
||||||
pad = partial(np.pad, pad_width=(0, 100), mode='edge')
|
|
||||||
r, g, b = map(pad, [r, g, b])
|
|
||||||
color = (r[count], g[count], b[count], 255)
|
|
||||||
return color
|
|
||||||
|
|
||||||
|
|
||||||
def get_mass_color(message):
|
def get_mass_color(message):
|
||||||
@@ -254,4 +245,4 @@ def plot_threshold_lines(fig, channel_threshold_list, parameters, **kwargs):
|
|||||||
if isinstance(warn_thresh, str):
|
if isinstance(warn_thresh, str):
|
||||||
warn_thresh = parameters.get('THRESHOLDS').get(warn_thresh)
|
warn_thresh = parameters.get('THRESHOLDS').get(warn_thresh)
|
||||||
if type(warn_thresh in (float, int)):
|
if type(warn_thresh in (float, int)):
|
||||||
ax.axhline(warn_thresh, **kwargs)
|
ax.axhline(warn_thresh, **kwargs)
|
||||||
|
|||||||
@@ -40,11 +40,11 @@ def get_mail_html_header():
|
|||||||
|
|
||||||
|
|
||||||
def init_html_table():
|
def init_html_table():
|
||||||
return '<div id="managerTable" ><table style="width:100%">\n'
|
return '<table style="width:100%">\n'
|
||||||
|
|
||||||
|
|
||||||
def finish_html_table():
|
def finish_html_table():
|
||||||
return '</table></div>\n'
|
return '</table>\n'
|
||||||
|
|
||||||
|
|
||||||
def html_footer(footer_logo=None):
|
def html_footer(footer_logo=None):
|
||||||
@@ -79,11 +79,9 @@ def get_html_row(items, html_key='td'):
|
|||||||
if item.get('italic'):
|
if item.get('italic'):
|
||||||
text = '<i>' + text + '</i>'
|
text = '<i>' + text + '</i>'
|
||||||
tooltip = item.get('tooltip')
|
tooltip = item.get('tooltip')
|
||||||
color = item.get('color')
|
|
||||||
# check for black background of headers (shouldnt happen anymore)
|
|
||||||
color = '#e6e6e6' if color == '#000000' else color
|
|
||||||
font_color = item.get('font_color')
|
font_color = item.get('font_color')
|
||||||
hyperlink = item.get('hyperlink')
|
hyperlink = item.get('hyperlink')
|
||||||
|
color = 'transparent' if hyperlink else item.get('color')
|
||||||
text_str = get_html_link(text, hyperlink) if hyperlink else text
|
text_str = get_html_link(text, hyperlink) if hyperlink else text
|
||||||
html_class = item.get('html_class')
|
html_class = item.get('html_class')
|
||||||
class_str = f' class="{html_class}"' if html_class else ''
|
class_str = f' class="{html_class}"' if html_class else ''
|
||||||
|
|||||||
Reference in New Issue
Block a user