Compare commits
	
		
			2 Commits
		
	
	
		
			3c6ea1ffd0
			...
			94cac54716
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 94cac54716 | |||
| c57763c016 | 
@ -3,11 +3,11 @@ datapath: "/data/SDS/"                    # SC3 Datapath
 | 
				
			|||||||
networks: ["1Y", "HA", "MK"]              # select networks, list or str
 | 
					networks: ["1Y", "HA", "MK"]              # select networks, list or str
 | 
				
			||||||
stations: "*"                             # select stations, list or str
 | 
					stations: "*"                             # select stations, list or str
 | 
				
			||||||
locations: "*"                            # select locations, list or str
 | 
					locations: "*"                            # select locations, list or str
 | 
				
			||||||
stations_blacklist: ["TEST", "EREA", "DOMV"]      # exclude these stations
 | 
					stations_blacklist: ["TEST", "EREA", "DOMV", "LFKM", "GR19", "LAKA"]      # exclude these stations
 | 
				
			||||||
networks_blacklist: []                    # exclude these networks
 | 
					networks_blacklist: []                    # exclude these networks
 | 
				
			||||||
interval: 60               # Perform checks every x seconds
 | 
					interval: 60               # Perform checks every x seconds
 | 
				
			||||||
n_track: 360               # wait n_track * intervals before performing an action (i.e. send mail/end highlight status)
 | 
					n_track: 360               # wait n_track * intervals before performing an action (i.e. send mail/end highlight status)
 | 
				
			||||||
timespan: 3                # Check data of the recent x days
 | 
					timespan: 7                # Check data of the recent x days
 | 
				
			||||||
verbosity: 0               # verbosity flag for program console output (not logging)
 | 
					verbosity: 0               # verbosity flag for program console output (not logging)
 | 
				
			||||||
logging_level: WARN        # set logging level (info, warning, debug)
 | 
					logging_level: WARN        # set logging level (info, warning, debug)
 | 
				
			||||||
track_changes: True        # tracks all changes since GUI startup by text highlighting (GUI only)
 | 
					track_changes: True        # tracks all changes since GUI startup by text highlighting (GUI only)
 | 
				
			||||||
@ -40,6 +40,7 @@ POWBOX:
 | 
				
			|||||||
THRESHOLDS:
 | 
					THRESHOLDS:
 | 
				
			||||||
  pb_thresh: 0.2               # Threshold for PowBox Voltage check +/- (V)
 | 
					  pb_thresh: 0.2               # Threshold for PowBox Voltage check +/- (V)
 | 
				
			||||||
  max_temp: 50                 # max temperature for temperature warning
 | 
					  max_temp: 50                 # max temperature for temperature warning
 | 
				
			||||||
 | 
					  critical_temp: 65            # max temperature for critical warning (fail)
 | 
				
			||||||
  low_volt: 12                 # min voltage for low voltage warning
 | 
					  low_volt: 12                 # min voltage for low voltage warning
 | 
				
			||||||
  high_volt: 14.8              # max voltage for over voltage warning
 | 
					  high_volt: 14.8              # max voltage for over voltage warning
 | 
				
			||||||
  unclassified: 5              # min voltage samples not classified for warning
 | 
					  unclassified: 5              # min voltage samples not classified for warning
 | 
				
			||||||
@ -139,7 +140,7 @@ EMAIL:
 | 
				
			|||||||
  mailserver: "localhost"
 | 
					  mailserver: "localhost"
 | 
				
			||||||
  addresses: ["marcel.paffrath@rub.de", "kasper.fischer@rub.de"]  # list of mail addresses for info mails
 | 
					  addresses: ["marcel.paffrath@rub.de", "kasper.fischer@rub.de"]  # list of mail addresses for info mails
 | 
				
			||||||
  sender: "webmaster@geophysik.ruhr-uni-bochum.de" # mail sender
 | 
					  sender: "webmaster@geophysik.ruhr-uni-bochum.de" # mail sender
 | 
				
			||||||
  stations_blacklist: ['GR33']                     # do not send emails for specific stations
 | 
					  stations_blacklist: []                     # do not send emails for specific stations
 | 
				
			||||||
  networks_blacklist: []                           # do not send emails for specific network
 | 
					  networks_blacklist: []                           # do not send emails for specific network
 | 
				
			||||||
  # specify recipients for single stations in a yaml: key = email-address, val = station list (e.g. [1Y.GR01, 1Y.GR02])
 | 
					  # specify recipients for single stations in a yaml: key = email-address, val = station list (e.g. [1Y.GR01, 1Y.GR02])
 | 
				
			||||||
  external_mail_list: "mailing_list.yaml"
 | 
					  external_mail_list: "mailing_list.yaml"
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										56
									
								
								survBot.py
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								survBot.py
									
									
									
									
									
								
							@ -69,6 +69,7 @@ def set_logging_level(params: dict) -> None:
 | 
				
			|||||||
        logging.warning(
 | 
					        logging.warning(
 | 
				
			||||||
            f'Could not set logging level. Parameter logging_level = {logging_level_str} could not be interpreted.')
 | 
					            f'Could not set logging level. Parameter logging_level = {logging_level_str} could not be interpreted.')
 | 
				
			||||||
        return
 | 
					        return
 | 
				
			||||||
 | 
					    logging.info(f'Setting logging level to {logging_level_str}')
 | 
				
			||||||
    logging_level = logging_levels.get(logging_level_str.lower())
 | 
					    logging_level = logging_levels.get(logging_level_str.lower())
 | 
				
			||||||
    logging.basicConfig(level=logging_level)
 | 
					    logging.basicConfig(level=logging_level)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -573,8 +574,6 @@ class StationQC(object):
 | 
				
			|||||||
        :param nsl: dictionary containing network, station and location (key: str)
 | 
					        :param nsl: dictionary containing network, station and location (key: str)
 | 
				
			||||||
        :param parameters: parameters dictionary from parameters.yaml file
 | 
					        :param parameters: parameters dictionary from parameters.yaml file
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        if status_track is None:
 | 
					 | 
				
			||||||
            status_track = {}
 | 
					 | 
				
			||||||
        self.parent = parent
 | 
					        self.parent = parent
 | 
				
			||||||
        self.stream = stream
 | 
					        self.stream = stream
 | 
				
			||||||
        self.nsl = nsl
 | 
					        self.nsl = nsl
 | 
				
			||||||
@ -594,6 +593,8 @@ class StationQC(object):
 | 
				
			|||||||
            status_track = {}
 | 
					            status_track = {}
 | 
				
			||||||
        self.status_track = status_track
 | 
					        self.status_track = status_track
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.powbox_active = self.is_pbox_activated_check()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.start()
 | 
					        self.start()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
@ -645,7 +646,8 @@ class StationQC(object):
 | 
				
			|||||||
        send_mail = False
 | 
					        send_mail = False
 | 
				
			||||||
        new_error = StatusError(count=count, show_count=self.parameters.get('warn_count'))
 | 
					        new_error = StatusError(count=count, show_count=self.parameters.get('warn_count'))
 | 
				
			||||||
        if disc:
 | 
					        if disc:
 | 
				
			||||||
            new_error.set_disconnected()
 | 
					            msg = disc if type(disc) == str else None
 | 
				
			||||||
 | 
					            new_error.set_disconnected(msg)
 | 
				
			||||||
        current_status = self.status_dict.get(key)
 | 
					        current_status = self.status_dict.get(key)
 | 
				
			||||||
        if current_status.is_error:
 | 
					        if current_status.is_error:
 | 
				
			||||||
            current_status.count += count
 | 
					            current_status.count += count
 | 
				
			||||||
@ -1024,9 +1026,12 @@ class StationQC(object):
 | 
				
			|||||||
            self.warn(key, detailed_message=detailed_message, count=n_undervolt,
 | 
					            self.warn(key, detailed_message=detailed_message, count=n_undervolt,
 | 
				
			||||||
                      last_occurrence=self.get_last_occurrence(trace, undervolt))
 | 
					                      last_occurrence=self.get_last_occurrence(trace, undervolt))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def pb_temp_analysis(self, channel='EX1'):
 | 
					    def pb_temp_analysis(self, channel='EX1', t_max_default=50, t_crit_default=70):
 | 
				
			||||||
        """ Analyse PowBox temperature output. """
 | 
					        """ Analyse PowBox temperature output. """
 | 
				
			||||||
        key = 'temp'
 | 
					        key = 'temp'
 | 
				
			||||||
 | 
					        if not self.powbox_active:
 | 
				
			||||||
 | 
					            self.set_pbox_inactive_error(key)
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
        st = self.stream.select(channel=channel)
 | 
					        st = self.stream.select(channel=channel)
 | 
				
			||||||
        trace = self.get_trace(st, key)
 | 
					        trace = self.get_trace(st, key)
 | 
				
			||||||
        if not trace:
 | 
					        if not trace:
 | 
				
			||||||
@ -1047,12 +1052,21 @@ class StationQC(object):
 | 
				
			|||||||
        logging.info(f'Average temperature at {np.nanmean(temp)}\N{DEGREE SIGN}')
 | 
					        logging.info(f'Average temperature at {np.nanmean(temp)}\N{DEGREE SIGN}')
 | 
				
			||||||
        logging.info(f'Peak temperature at {max(temp)}\N{DEGREE SIGN}')
 | 
					        logging.info(f'Peak temperature at {max(temp)}\N{DEGREE SIGN}')
 | 
				
			||||||
        logging.info(f'Min temperature at {min(temp)}\N{DEGREE SIGN}')
 | 
					        logging.info(f'Min temperature at {min(temp)}\N{DEGREE SIGN}')
 | 
				
			||||||
        max_temp = thresholds.get('max_temp')
 | 
					        max_temp = thresholds.get('max_temp', t_max_default)
 | 
				
			||||||
 | 
					        max_temp_crit = thresholds.get('critical_temp', t_crit_default)
 | 
				
			||||||
        t_check = np.where(temp > max_temp)[0]
 | 
					        t_check = np.where(temp > max_temp)[0]
 | 
				
			||||||
        if len(t_check) > 0:
 | 
					        t_check_crit = np.where(temp > max_temp_crit)[0]
 | 
				
			||||||
 | 
					        tcheck_message_template = ('Trace {id}: Temperature over {tmax}' + f'\N{DEGREE SIGN}'
 | 
				
			||||||
 | 
					                                   + '! Current temperature: {temp}' + f'\N{DEGREE SIGN}')
 | 
				
			||||||
 | 
					        if len(t_check_crit) > 0:
 | 
				
			||||||
 | 
					            self.error(key=key,
 | 
				
			||||||
 | 
					                      detailed_message=tcheck_message_template.format(id=trace.get_id(), tmax=max_temp, temp=cur_temp)
 | 
				
			||||||
 | 
					                                       + self.get_last_occurrence_timestring(trace, t_check_crit),
 | 
				
			||||||
 | 
					                      last_occurrence=self.get_last_occurrence(trace, t_check_crit))
 | 
				
			||||||
 | 
					        elif len(t_check) > 0:
 | 
				
			||||||
            self.warn(key=key,
 | 
					            self.warn(key=key,
 | 
				
			||||||
                      detailed_message=f'Trace {trace.get_id()}: '
 | 
					                      detailed_message=tcheck_message_template.format(id=trace.get_id(), tmax=max_temp_crit,
 | 
				
			||||||
                                       f'Temperature over {max_temp}\N{DEGREE SIGN} at {trace.get_id()}!'
 | 
					                                                                      temp=cur_temp)
 | 
				
			||||||
                                       + self.get_last_occurrence_timestring(trace, t_check),
 | 
					                                       + self.get_last_occurrence_timestring(trace, t_check),
 | 
				
			||||||
                      last_occurrence=self.get_last_occurrence(trace, t_check))
 | 
					                      last_occurrence=self.get_last_occurrence(trace, t_check))
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
@ -1108,6 +1122,11 @@ class StationQC(object):
 | 
				
			|||||||
    def pb_power_analysis(self, channel='EX2', pb_dict_key='pb_SOH2'):
 | 
					    def pb_power_analysis(self, channel='EX2', pb_dict_key='pb_SOH2'):
 | 
				
			||||||
        """ Analyse EX2 channel of PowBox """
 | 
					        """ Analyse EX2 channel of PowBox """
 | 
				
			||||||
        keys = ['230V', '12V']
 | 
					        keys = ['230V', '12V']
 | 
				
			||||||
 | 
					        if not self.powbox_active:
 | 
				
			||||||
 | 
					            for key in keys:
 | 
				
			||||||
 | 
					                self.set_pbox_inactive_error(key)
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        st = self.stream.select(channel=channel)
 | 
					        st = self.stream.select(channel=channel)
 | 
				
			||||||
        trace = self.get_trace(st, keys)
 | 
					        trace = self.get_trace(st, keys)
 | 
				
			||||||
        if not trace:
 | 
					        if not trace:
 | 
				
			||||||
@ -1129,7 +1148,11 @@ class StationQC(object):
 | 
				
			|||||||
    def pb_rout_charge_analysis(self, channel='EX3', pb_dict_key='pb_SOH3'):
 | 
					    def pb_rout_charge_analysis(self, channel='EX3', pb_dict_key='pb_SOH3'):
 | 
				
			||||||
        """ Analyse EX3 channel of PowBox """
 | 
					        """ Analyse EX3 channel of PowBox """
 | 
				
			||||||
        keys = ['router', 'charger']
 | 
					        keys = ['router', 'charger']
 | 
				
			||||||
        pb_thresh = self.parameters.get('THRESHOLDS').get('pb_1v')
 | 
					        if not self.powbox_active:
 | 
				
			||||||
 | 
					            for key in keys:
 | 
				
			||||||
 | 
					                self.set_pbox_inactive_error(key)
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        st = self.stream.select(channel=channel)
 | 
					        st = self.stream.select(channel=channel)
 | 
				
			||||||
        trace = self.get_trace(st, keys)
 | 
					        trace = self.get_trace(st, keys)
 | 
				
			||||||
        if not trace:
 | 
					        if not trace:
 | 
				
			||||||
@ -1243,6 +1266,10 @@ class StationQC(object):
 | 
				
			|||||||
        with each voltage value associated to the different steps specified in POWBOX > pb_steps. Also raises
 | 
					        with each voltage value associated to the different steps specified in POWBOX > pb_steps. Also raises
 | 
				
			||||||
        self.warn in case there are unassociated voltage values recorded.
 | 
					        self.warn in case there are unassociated voltage values recorded.
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        if not self.powbox_active:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        pb_thresh = self.parameters.get('THRESHOLDS').get('pb_thresh')
 | 
					        pb_thresh = self.parameters.get('THRESHOLDS').get('pb_thresh')
 | 
				
			||||||
        pb_ok = self.parameters.get('POWBOX').get('pb_ok')
 | 
					        pb_ok = self.parameters.get('POWBOX').get('pb_ok')
 | 
				
			||||||
        # possible voltage levels are keys of pb voltage level dict
 | 
					        # possible voltage levels are keys of pb voltage level dict
 | 
				
			||||||
@ -1305,6 +1332,13 @@ class StationQC(object):
 | 
				
			|||||||
        """ get UTCDateTime from trace and index"""
 | 
					        """ get UTCDateTime from trace and index"""
 | 
				
			||||||
        return trace.stats.starttime + trace.stats.delta * index
 | 
					        return trace.stats.starttime + trace.stats.delta * index
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def is_pbox_activated_check(self):
 | 
				
			||||||
 | 
					        return self.station not in self.parameters.get('no_pbox_stations', [])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_pbox_inactive_error(self, key):
 | 
				
			||||||
 | 
					        msg = self.parameters.get('no_pbox_stations')[self.station]
 | 
				
			||||||
 | 
					        self.error(key, detailed_message=f'PowBox not connected', disc=msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Status(object):
 | 
					class Status(object):
 | 
				
			||||||
    """ Basic Status class. All status classes are derived from this class."""
 | 
					    """ Basic Status class. All status classes are derived from this class."""
 | 
				
			||||||
@ -1372,8 +1406,10 @@ class StatusError(Status):
 | 
				
			|||||||
        self.set_error()
 | 
					        self.set_error()
 | 
				
			||||||
        self.default_message = message
 | 
					        self.default_message = message
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def set_disconnected(self, message='DCN'):
 | 
					    def set_disconnected(self, message=None):
 | 
				
			||||||
        self.connection_error = True
 | 
					        self.connection_error = True
 | 
				
			||||||
 | 
					        if not message:
 | 
				
			||||||
 | 
					            message = 'DCN'
 | 
				
			||||||
        self.message = message
 | 
					        self.message = message
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def set_connected(self):
 | 
					    def set_connected(self):
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										20
									
								
								utils.py
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								utils.py
									
									
									
									
									
								
							@ -9,6 +9,14 @@ import numpy as np
 | 
				
			|||||||
from obspy import Stream
 | 
					from obspy import Stream
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COLORS_DICT = {'FAIL': (195, 29, 14, 255),
 | 
				
			||||||
 | 
					               'NO DATA': (255, 255, 125, 255),
 | 
				
			||||||
 | 
					               'WARN': (250, 192, 63, 255),
 | 
				
			||||||
 | 
					               'OK': (185, 245, 145, 255),
 | 
				
			||||||
 | 
					               'undefined': (240, 240, 240, 255),
 | 
				
			||||||
 | 
					               'disc': (126, 127, 131, 255), }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_bg_color(check_key, status, dt_thresh=None, hex=False):
 | 
					def get_bg_color(check_key, status, dt_thresh=None, hex=False):
 | 
				
			||||||
    message = status.message
 | 
					    message = status.message
 | 
				
			||||||
    if check_key == 'last active':
 | 
					    if check_key == 'last active':
 | 
				
			||||||
@ -43,13 +51,9 @@ def get_color(key):
 | 
				
			|||||||
    #                'OK': (173, 255, 133, 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),
 | 
					    if not key in COLORS_DICT.keys():
 | 
				
			||||||
                   'NO DATA': (255, 255, 125, 255),
 | 
					        key = 'undefined'
 | 
				
			||||||
                   'WARN': (250, 192, 63, 255),
 | 
					    return COLORS_DICT.get(key)
 | 
				
			||||||
                   'OK': (185, 245, 145, 255),
 | 
					 | 
				
			||||||
                   'undefined': (240, 240, 240, 255),
 | 
					 | 
				
			||||||
                   'disc': (126, 127, 131, 255), }
 | 
					 | 
				
			||||||
    return colors_dict.get(key)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_color_mpl(key):
 | 
					def get_color_mpl(key):
 | 
				
			||||||
@ -84,6 +88,8 @@ def get_mass_color(message):
 | 
				
			|||||||
def get_temp_color(temp, vmin=-10, vmax=60, cmap='coolwarm'):
 | 
					def get_temp_color(temp, vmin=-10, vmax=60, cmap='coolwarm'):
 | 
				
			||||||
    """ Get an rgba temperature value back from specified cmap, linearly interpolated between vmin and vmax. """
 | 
					    """ Get an rgba temperature value back from specified cmap, linearly interpolated between vmin and vmax. """
 | 
				
			||||||
    if type(temp) in [str]:
 | 
					    if type(temp) in [str]:
 | 
				
			||||||
 | 
					        if temp in COLORS_DICT.keys():
 | 
				
			||||||
 | 
					            return get_color(temp)
 | 
				
			||||||
        return get_color('undefined')
 | 
					        return get_color('undefined')
 | 
				
			||||||
    cmap = matplotlib.cm.get_cmap(cmap)
 | 
					    cmap = matplotlib.cm.get_cmap(cmap)
 | 
				
			||||||
    val = (temp - vmin) / (vmax - vmin)
 | 
					    val = (temp - vmin) / (vmax - vmin)
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user