diff --git a/app.py b/app.py index e0ccead..ca537f6 100644 --- a/app.py +++ b/app.py @@ -105,24 +105,15 @@ def get_timeseries(phase_id): if start_param and end_param: time_filter = f"time >= '{start_param}' AND time <= '{end_param}'" - interval = "1m" + interval = config.DEFAULT_INTERVAL else: clean_range = range_param.replace(" ", "") time_filter = f"time > now() - {clean_range}" - mapping = { - "1h": "10s", - "6h": "30s", - "24h": "2m", - "7d": "10m", - "30d": "30m", - "60d": "1h", - "120d": "2h", - "180d": "4h", - "365d": "6h" - } - - interval = mapping.get(range_param, "1m") + if range_param in config.TIME_RANGES: + interval = config.TIME_RANGES[range_param]['interval'] + else: + interval = config.DEFAULT_INTERVALk query = f''' SELECT mean("value") AS voltage @@ -152,13 +143,17 @@ def get_events(): end_p = request.args.get('end') now_utc = datetime.now(timezone.utc) - # Blokada dla zakresów powyżej 61 dni + # Blokada dla zakresów powyżej MAX_EVENT_RANGE_DAYS if not (start_p and end_p) and "d" in range_p: try: days = int(''.join(filter(str.isdigit, range_p))) - if days > 61: - return jsonify({"error": "range_too_large", "message": "Zbyt duży zakres. Zaznacz obszar na wykresie lub wybierz własny zakres."}) - except: pass + if days > config.MAX_EVENT_RANGE_DAYS: + return jsonify({ + "error": "range_too_large", + "message": f"Zbyt duży zakres. Maksymalnie {config.MAX_EVENT_RANGE_DAYS} dni. Zaznacz obszar na wykresie lub wybierz własny zakres." + }) + except: + pass if start_p and end_p: dt_view_start = datetime.fromisoformat(start_p.replace('Z', '+00:00')) @@ -182,7 +177,7 @@ def get_events(): FROM "{config.MEASUREMENT}" WHERE "entity_id" = '{p_cfg["entity_id"]}' AND {time_filter} - GROUP BY time(1m) fill(0) + GROUP BY time({config.EVENT_DETECTION_INTERVAL}) fill(0) ''' result = client.query(query) points = list(result.get_points()) @@ -197,22 +192,34 @@ def get_events(): v_now = float(val) ev_type = None - if v_now < 100: ev_type = "zanik" - elif 100 <= v_now < 207: ev_type = "niskie" - elif v_now > 253: ev_type = "wysokie" + # Używamy progów z config.VOLTAGE_THRESHOLDS + if v_now < config.VOLTAGE_THRESHOLDS['outage']: + ev_type = "zanik" + elif config.VOLTAGE_THRESHOLDS['outage'] <= v_now < config.VOLTAGE_THRESHOLDS['min_safe']: + ev_type = "niskie" + elif v_now > config.VOLTAGE_THRESHOLDS['max_safe']: + ev_type = "wysokie" + # else: ev_type = None (wartość w zakresie bezpiecznym 207-253V) if ev_type: start_str = points[i]['time'] dt_s = datetime.fromisoformat(start_str.replace('Z', '+00:00')) j = i + while j + 1 < len(points): v_next_val = points[j+1].get('volts') next_type = None if v_next_val is not None: v_next = float(v_next_val) - if v_next < 100: next_type = "zanik" - elif 100 <= v_next < 207: next_type = "niskie" - elif v_next > 253: next_type = "wysokie" + + # Używamy progów z config.VOLTAGE_THRESHOLDS + if v_next < config.VOLTAGE_THRESHOLDS['outage']: + next_type = "zanik" + elif config.VOLTAGE_THRESHOLDS['outage'] <= v_next < config.VOLTAGE_THRESHOLDS['min_safe']: + next_type = "niskie" + elif v_next > config.VOLTAGE_THRESHOLDS['max_safe']: + next_type = "wysokie" + # else: next_type = None (wartość w zakresie bezpiecznym) if next_type == ev_type: j += 1 @@ -224,7 +231,8 @@ def get_events(): duration = (dt_e - dt_s).total_seconds() / 60 + 1 - if duration >= 5.1: + # Używamy progu minimalnego czasu trwania z config + if duration >= config.MIN_EVENT_DURATION_MINUTES: if dt_e >= dt_view_start and dt_s <= dt_view_end: all_events.append({ "start": start_str, @@ -235,6 +243,7 @@ def get_events(): }) i = j i += 1 + return jsonify(sorted(all_events, key=lambda x: x['start'], reverse=True)) except Exception as e: app.logger.error(f"Event Logic Error: {e}") @@ -242,13 +251,12 @@ def get_events(): finally: client.close() - -@app.route('/api/outages/') +@app.route('/api/outages/') def api_outages(phase_id): client = get_influx_client() t_range = request.args.get('range', '24h') entity_id = config.PHASES[phase_id]['entity_id'] - query = f'SELECT "value" FROM "{config.MEASUREMENT}" WHERE "entity_id" = \'{entity_id}\' AND "value" < 10 AND time > now() - {t_range}' + query = f'SELECT "value" FROM "{config.MEASUREMENT}" WHERE "entity_id" = \'{entity_id}\' AND "value" < {config.VOLTAGE_THRESHOLDS["outage_detection"]} AND time > now() - {t_range}' try: result = client.query(query) return jsonify(list(result.get_points())) @@ -274,4 +282,4 @@ if __name__ == '__main__': print("="*50 + "\n") eventlet.spawn(background_voltage_update) - socketio.run(app, host='0.0.0.0', port=config.FLASK_CONFIG['port']) + socketio.run(app, host='0.0.0.0', port=config.FLASK_CONFIG['port']) \ No newline at end of file diff --git a/config.py b/config.py index f2f279c..b3e571b 100644 --- a/config.py +++ b/config.py @@ -35,25 +35,34 @@ PHASES = { # Zakresy czasu TIME_RANGES = { '1h': {'filter': '1h', 'interval': '10s', 'label': '1h'}, - '6h': {'filter': '6h', 'interval': '1m', 'label': '6h'}, - '24h': {'filter': '24h', 'interval': '5m', 'label': '24h'}, - '7d': {'filter': '7d', 'interval': '30m', 'label': '7d'}, - '30d': {'filter': '30d', 'interval': '2h', 'label': '30d'}, - '60d': {'filter': '60d', 'interval': '4h', 'label': '60d'}, - '120d': {'filter': '120d', 'interval': '8h', 'label': '120d'}, - '180d': {'filter': '180d', 'interval': '12h', 'label': '6m'}, - '365d': {'filter': '365d', 'interval': '1d', 'label': '1r'} + '6h': {'filter': '6h', 'interval': '30s', 'label': '6h'}, + '24h': {'filter': '24h', 'interval': '2m', 'label': '24h'}, + '7d': {'filter': '7d', 'interval': '10m', 'label': '7d'}, + '30d': {'filter': '30d', 'interval': '30m', 'label': '30d'}, + '60d': {'filter': '60d', 'interval': '1h', 'label': '60d'}, + '120d': {'filter': '120d', 'interval': '2h', 'label': '120d'}, + '180d': {'filter': '180d', 'interval': '4h', 'label': '6m'}, + '365d': {'filter': '365d', 'interval': '6h', 'label': '1r'} } DEFAULT_TIME_RANGE = '6h' MEASUREMENT = 'V' # ZAKRES BEZPIECZNY: 207V - 253V +# PROGI NAPIĘCIA VOLTAGE_THRESHOLDS = { - 'min_safe': 207, - 'max_safe': 253 + 'outage': 100, # < 100V = zanik + 'min_safe': 207, # Dolny próg bezpieczny + 'max_safe': 253, # Górny próg bezpieczny + 'outage_detection': 10 # Próg dla api_outages } +# PARAMETRY WYKRYWANIA EVENTÓW +MAX_EVENT_RANGE_DAYS = 61 +MIN_EVENT_DURATION_MINUTES = 5.1 +EVENT_DETECTION_INTERVAL = '1m' +DEFAULT_INTERVAL = '1m' + # Skalowanie GAUGE_CONFIG = {'min': 190, 'max': 270} CHART_CONFIG = {'y_min': 190, 'y_max': 270, 'update_interval': 2000}