diff --git a/parameters.yaml b/parameters.yaml index 0fdf7c6..5208559 100644 --- a/parameters.yaml +++ b/parameters.yaml @@ -3,7 +3,7 @@ datapath: "/data/SDS/" # SC3 Datapath networks: ["1Y", "HA"] # select networks, list or str stations: "*" # select stations, list or str locations: "*" # select locations, list or str -channels: ["EX1", "EX2", "EX3", "VEI"] # Specify SOH channels, currently supported EX[1-3] and VEI +channels: ["EX1", "EX2", "EX3", "VEI", "LCQ"] # Specify SOH channels, currently supported EX[1-3], VEI, LCQ stations_blacklist: ["TEST", "EREA"] # exclude these stations networks_blacklist: [] # exclude these networks interval: 60 # Perform checks every x seconds @@ -43,6 +43,8 @@ THRESHOLDS: low_volt: 12 # min voltage for low voltage warning high_volt: 14.8 # max voltage for over voltage warning unclassified: 5 # min voltage samples not classified for warning + clockquality_warn: 90 # clock quality ranges from 0 % to 100 % with 100 % being the best level + clockquality_fail: 70 # ---------------------------------------- OPTIONAL PARAMETERS --------------------------------------------------------- @@ -62,7 +64,7 @@ EMAIL: networks_blacklist: [] # do not send emails for specific network # names for plotting of the above defined parameter "channels" in the same order -channel_names: ["Temperature (°C)", "230V/12V Status (V)", "Router/Charger State (V)", "Logger Voltage (V)"] +channel_names: ["Clock Quality (%)", "Temperature (°C)", "230V/12V Status (V)", "Router/Charger State (V)", "Logger Voltage (V)"] # names for plotting (optional) # specify y-ticks (and ylims) giving, (ymin, ymax, step) for each of the above channels (0: default) CHANNEL_TICKS: - [-10, 50, 10] diff --git a/survBot.py b/survBot.py index 10dfabf..0de3f7f 100755 --- a/survBot.py +++ b/survBot.py @@ -61,7 +61,7 @@ def fancy_timestr(dt, thresh=600, modif='+'): class SurveillanceBot(object): def __init__(self, parameter_path, outpath_html=None): - self.keys = ['last active', '230V', '12V', 'router', 'charger', 'voltage', 'temp', 'other'] + self.keys = ['last active', '230V', '12V', 'router', 'charger', 'voltage', 'clock', 'temp', 'other'] self.parameter_path = parameter_path self.update_parameters() self.starttime = UTCDateTime() @@ -685,6 +685,7 @@ class StationQC(object): self.pb_temp_analysis() self.pb_power_analysis() self.pb_rout_charge_analysis() + self.clock_quality_analysis() def return_print_analysis(self): items = [self.nwst_id] @@ -713,6 +714,47 @@ class StationQC(object): def get_last_occurrence(self, trace, indices): return self.get_time(trace, indices[-1]) + def clock_quality_analysis(self, channel='LCQ'): + """ Analyse clock quality """ + key = 'clock' + st = self.stream.select(channel=channel) + trace = self.get_trace(st, key) + if not trace: return + clockQuality = trace.data + clockQuality_warn_level = self.parameters.get('THRESHOLDS').get('clockquality_warn') + clockQuality_fail_level = self.parameters.get('THRESHOLDS').get('clockquality_fail') + + if self.verbosity > 1: + self.print(40 * '-') + self.print('Performing Clock Quality check', flush=False) + + clockQuality_warn = np.where(clockQuality < clockQuality_warn_level)[0] + clockQuality_fail = np.where(clockQuality < clockQuality_fail_level)[0] + + if len(clockQuality_warn) == 0 and len(clockQuality_fail) == 0: + self.status_ok(key, detailed_message=f'ClockQuality={(clockQuality[-1])}') + return + + n_qc_warn = 0 + n_qc_fail = 0 + + warn_message = f'Trace {trace.get_id()}:' + if len(clockQuality_warn) > 0: + # try calculate number of warn peaks from gaps between indices + n_qc_warn = len(np.where(np.diff(clockQuality_warn) > 1)[0]) + 1 + detailed_message = warn_message + f' {n_qc_warn}x Qlock Quality less then {clockQuality_warn_level}' \ + + self.get_last_occurrence_timestring(trace, clockQuality_warn) + self.warn(key, detailed_message=detailed_message, count=n_qc_warn, + last_occurrence=self.get_last_occurrence(trace, clockQuality_warn)) + + if len(clockQuality_fail) > 0: + # try calculate number of fail peaks from gaps between indices + n_qc_fail = len(np.where(np.diff(clockQuality_fail) > 1)[0]) + 1 + detailed_message = warn_message + f' {n_qc_fail}x Qlock Quality less then {clockQuality_fail_level}V ' \ + + self.get_last_occurrence_timestring(trace, clockQuality_fail) + self.error(key, detailed_message=detailed_message, count=n_qc_fail, + last_occurrence=self.get_last_occurrence(trace, clockQuality_fail)) + def voltage_analysis(self, channel='VEI'): """ Analyse voltage channel for over/undervoltage """ key = 'voltage'