diff --git a/davisAPI/davisAPI.py b/davisAPI/davisAPI.py index c727b2a..a5742b1 100644 --- a/davisAPI/davisAPI.py +++ b/davisAPI/davisAPI.py @@ -1,12 +1,12 @@ import gc import logging import time -from datetime import datetime - +from datetime import datetime, timedelta +from pprint import pprint import mariadb import serial.tools.list_ports -from PyWeather.weather.stations.davis import VantagePro +#from PyWeather.weather.stations.davis import VantagePro from prediction import run_prediction_module logging.basicConfig(filename="Stations.log", @@ -54,28 +54,27 @@ def write_data(device, station, send=True): def get_previous_values(cursor): - cursor.execute("SELECT SunRise, SunSet, WindDir FROM weather_data ORDER BY DateStamp DESC LIMIT 1") + cursor.execute("SELECT SunRise, SunSet, WindDir, DateStamp FROM weather_data ORDER BY DateStamp DESC LIMIT 1") result = cursor.fetchone() if result is None: - return None, None, None + return None, None, None, None - sun_rise, sun_set, wind_dir = result - return sun_rise, sun_set, wind_dir + sun_rise, sun_set, wind_dir, datestamp = result + return sun_rise, sun_set, wind_dir, datestamp def save_prediction_to_db(predictions): try: - current_timestamp = datetime.now() - sun_rise, sun_set, wind_dir = get_previous_values(cursor) + sun_rise, sun_set, wind_dir, datestamp = get_previous_values(cursor) fields = ['DateStamp', 'SunRise', 'SunSet', 'WindDir'] + list(predictions.keys()) placeholders = ', '.join(['%s'] * len(fields)) field_names = ', '.join(fields) - values = [current_timestamp, sun_rise, sun_set, wind_dir] + list(predictions.values()) - + values = [datestamp + timedelta(minutes = 1), sun_rise, sun_set, wind_dir] + list(predictions.values()) + pprint(dict(zip(fields, values))) sql = f"INSERT INTO weather_data ({field_names}) VALUES ({placeholders})" # cursor.execute(sql, values) # conn.commit() @@ -97,28 +96,31 @@ try: except mariadb.Error as e: logger.error('DB_ERR: ' + str(e)) raise e +while True: + try: + ports = serial.tools.list_ports.comports() + available_ports = {} -try: - ports = serial.tools.list_ports.comports() - available_ports = {} + for port in ports: + if port.serial_number == '0001': + available_ports[port.name] = port.vid - for port in ports: - if port.serial_number == '0001': - available_ports[port.name] = port.vid + devices = [VantagePro(port) for port in available_ports.keys()] + while True: + for i in range(1): + if len(devices) != 0: + logger.info(devices) + # write_data(devices[i], 'st' + str(available_ports[list(available_ports.keys())[i]]), True) + else: + raise Exception('Can`t connect to device') + time.sleep(60) + except Exception as e: + logger.error('Device_error' + str(e)) + predictions = run_prediction_module() + #logger.info(predictions) + if predictions is not None: + save_prediction_to_db(predictions) + time.sleep(60) - devices = [VantagePro(port) for port in available_ports.keys()] - while True: - for i in range(1): - if len(devices) != 0: - logger.info(devices) - # write_data(devices[i], 'st' + str(available_ports[list(available_ports.keys())[i]]), True) - else: - raise Exception("Can't connect to device") - time.sleep(1) -except Exception as e: - logger.error('Device_error: ' + str(e)) - predictions = run_prediction_module() - logger.info(predictions) - if predictions is not None: - save_prediction_to_db(predictions) +#todo переписать под influx, для линухи приколы сделать \ No newline at end of file diff --git a/davisAPI/prediction.py b/davisAPI/prediction.py index 7d8bb21..9c7fa85 100644 --- a/davisAPI/prediction.py +++ b/davisAPI/prediction.py @@ -16,86 +16,88 @@ def run_prediction_module(): FROM weather_data WHERE DateStamp >= '2024-10-14 21:00:00' - INTERVAL 36 HOUR; """ - df = pd.read_sql(query, engine) + df = pd.read_sql(query, engine) # Загружаем данные из SQL-запроса в DataFrame - df['DateStamp'] = pd.to_datetime(df['DateStamp']) - df.set_index('DateStamp', inplace=True) - df.sort_index(inplace=True) + df['DateStamp'] = pd.to_datetime(df['DateStamp']) # Преобразуем столбец 'DateStamp' в формат datetime + df.set_index('DateStamp', inplace=True) # Устанавливаем 'DateStamp' как индекс + df.sort_index(inplace=True) # Сортируем DataFrame по индексу (по дате) - lags = 3 - shifted_dfs = [df] + lags = 3 # Задаем количество временных сдвигов (лагов) + shifted_dfs = [df] # Создаем список для хранения исходного DataFrame и его лаговых версий for lag in range(1, lags + 1): - shifted_df = df.shift(lag).add_suffix(f'_t-{lag}') - shifted_dfs.append(shifted_df) + shifted_df = df.shift(lag).add_suffix(f'_t-{lag}') # Создаем сдвинутый на lag строк DataFrame + shifted_dfs.append(shifted_df) # Добавляем его в список - df_with_lags = pd.concat(shifted_dfs, axis=1) + df_with_lags = pd.concat(shifted_dfs, axis=1) # Объединяем исходный DataFrame и все лаги по столбцам - df_with_lags.dropna(inplace=True) - df_with_lags = df_with_lags.copy() + df_with_lags.dropna(inplace=True) # Удаляем строки с пропущенными значениями + df_with_lags = df_with_lags.copy() # Создаем копию DataFrame (для предотвращения предупреждений) - # Преобразуем BarTrend в числовой формат + # Преобразуем столбец 'BarTrend' в числовой формат, используя кодировщик категорий le = LabelEncoder() df_with_lags['BarTrend_encoded'] = le.fit_transform(df_with_lags['BarTrend']) - # Выбор только числовых данных + # Оставляем в DataFrame только числовые столбцы df_with_lags = df_with_lags.select_dtypes(include=['float64', 'int64']) - # Словари для хранения моделей и MSE + # Создаем словари для хранения моделей и значений MSE models = {} mse_scores = {} - # Обучение моделей для каждого целевого столбца + # Обучаем модели для каждого целевого столбца for target_column in df.columns: - if target_column not in df_with_lags.columns: + if target_column not in df_with_lags.columns: # Пропускаем, если столбец отсутствует в df_with_lags continue - X = df_with_lags.drop(columns=[target_column]).values - y = df_with_lags[target_column].values + X = df_with_lags.drop(columns=[target_column]).values # Признаки - все столбцы, кроме целевого + y = df_with_lags[target_column].values # Целевой столбец + # Разделяем данные на обучающую и тестовую выборки без перемешивания (временной ряд) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, shuffle=False) - model = RandomForestRegressor() - model.fit(X_train, y_train) + model = RandomForestRegressor() # Инициализируем модель случайного леса + model.fit(X_train, y_train) # Обучаем модель - y_pred = model.predict(X_test) - mse = mean_squared_error(y_test, y_pred) - mse_scores[target_column] = mse - models[target_column] = model + y_pred = model.predict(X_test) # Делаем предсказания на тестовой выборке + mse = mean_squared_error(y_test, y_pred) # Вычисляем среднеквадратичную ошибку + mse_scores[target_column] = mse # Сохраняем MSE для целевого столбца + models[target_column] = model # Сохраняем модель для целевого столбца - quality = "хорошая" if mse < 1.0 else "плохая" - print(f"MSE для {target_column}: {mse} ({quality})") + quality = "хорошая" if mse < 1.0 else "плохая" # Определяем качество модели + print(f"MSE для {target_column}: {mse} ({quality})") # Выводим MSE и качество - # Обучаем модель для BarTrend_encoded отдельно - X_bartrend = df_with_lags.drop(columns=['BarTrend_encoded']).values - y_bartrend = df_with_lags['BarTrend_encoded'].values + # Обучаем модель для столбца 'BarTrend_encoded' отдельно + X_bartrend = df_with_lags.drop(columns=['BarTrend_encoded']).values # Признаки + y_bartrend = df_with_lags['BarTrend_encoded'].values # Целевой столбец 'BarTrend_encoded' + # Разделяем данные на обучающую и тестовую выборки без перемешивания X_train_bartrend, X_test_bartrend, y_train_bartrend, y_test_bartrend = train_test_split(X_bartrend, y_bartrend, test_size=0.2, shuffle=False) - model_bartrend = RandomForestRegressor() - model_bartrend.fit(X_train_bartrend, y_train_bartrend) + model_bartrend = RandomForestRegressor() # Инициализируем модель случайного леса + model_bartrend.fit(X_train_bartrend, y_train_bartrend) # Обучаем модель - y_pred_bartrend = model_bartrend.predict(X_test_bartrend) - mse_bartrend = mean_squared_error(y_test_bartrend, y_pred_bartrend) - models['BarTrend_encoded'] = model_bartrend - mse_scores['BarTrend_encoded'] = mse_bartrend + y_pred_bartrend = model_bartrend.predict(X_test_bartrend) # Предсказания на тестовой выборке для 'BarTrend_encoded' + mse_bartrend = mean_squared_error(y_test_bartrend, y_pred_bartrend) # Вычисляем MSE + models['BarTrend_encoded'] = model_bartrend # Сохраняем модель для 'BarTrend_encoded' + mse_scores['BarTrend_encoded'] = mse_bartrend # Сохраняем MSE для 'BarTrend_encoded' - quality_bartrend = "хорошая" if mse_bartrend < 1.0 else "плохая" - print(f"MSE для BarTrend: {mse_bartrend} ({quality_bartrend})") + quality_bartrend = "хорошая" if mse_bartrend < 1.0 else "плохая" # Определяем качество модели для 'BarTrend_encoded' + print(f"MSE для BarTrend: {mse_bartrend} ({quality_bartrend})") # Выводим MSE и качество - last_data = X[-1].reshape(1, -1) + last_data = X[-1].reshape(1, -1) # Берем последнюю строку данных и преобразуем в формат для предсказания - predictions = {} + predictions = {} # Создаем словарь для хранения предсказаний for target_column, model in models.items(): - prediction = model.predict(last_data)[0] + prediction = model.predict(last_data)[0] # Делаем предсказание для последней строки данных if target_column == 'BarTrend_encoded': - prediction = le.inverse_transform([int(prediction)])[0] - predictions['BarTrend'] = prediction - print(f"Предсказание для BarTrend: {prediction}") - break - predictions[target_column] = prediction - print(f"Предсказание для {target_column}: {prediction}") + prediction = le.inverse_transform([int(prediction)])[0] # Декодируем категориальное значение + predictions['BarTrend'] = prediction # Сохраняем предсказание для 'BarTrend' + #print(f"Предсказание для BarTrend: {prediction}") # Выводим предсказание + continue # Продолжаем цикл после предсказания для 'BarTrend_encoded' + predictions[target_column] = prediction # Сохраняем предсказание для остальных столбцов + #print(f"Предсказание для {target_column}: {prediction}") # Выводим предсказание для столбца return predictions # Возвращаем словарь с предсказанными значениями и названиями столбцов