diff --git a/.gitignore b/.gitignore index fe5bdf2..429d7fc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .vscode/ .env dev -node_modules \ No newline at end of file +node_modules +__pycache__ \ No newline at end of file diff --git a/client/main.py b/client/main.py index 9b9f670..d1f0e1f 100644 --- a/client/main.py +++ b/client/main.py @@ -1,7 +1,8 @@ -from flask import Flask, Response, jsonify +from flask import Flask, Response, jsonify, request from flask_cors import CORS import system_helpers import stream_helpers +import settings_helpers app = Flask(__name__) CORS(app, resources={r"/*": {"origins": "*"}}) @@ -36,6 +37,23 @@ def toggle_recording(): else: stream_helpers.start_recording() return jsonify({"message": "Recording started"}) + +@app.route('/settings', methods=['GET', 'POST']) +def settings(): + if request.method == 'GET': + return jsonify(settings_helpers.get_settings()) + elif request.method == 'POST': + new_settings = request.json + if "VideoSaveLocation" in new_settings: + success = settings_helpers.update_video_save_location(new_settings["VideoSaveLocation"]) + if success: + return jsonify({"message": "Settings updated"}) + else: + return jsonify({"message": "Invalid directory or insufficient permissions"}), 400 + else: + settings_helpers.update_settings(new_settings) + return jsonify({"message": "Settings updated"}) + if __name__ == "__main__": diff --git a/client/settings/settings.json b/client/settings/settings.json new file mode 100644 index 0000000..5781126 --- /dev/null +++ b/client/settings/settings.json @@ -0,0 +1,23 @@ +{ + "TARGET_BT_ADDRESSES": [ + { + "address": "XX:XX:XX:XX:XX:XX", + "name": "Device 1" + }, + { + "address": "XX:XX:XX:XX:XX:XX", + "name": "Device 2" + } + ], + "TARGET_AP_MAC_ADDRESSES": [ + { + "address": "XX:XX:XX:XX:XX:XX", + "name": "Device 1" + }, + { + "address": "XX:XX:XX:XX:XX:XX", + "name": "Device 2" + } + ], + "VideoSaveLocation": "./recordings" +} \ No newline at end of file diff --git a/client/settings_helpers.py b/client/settings_helpers.py new file mode 100644 index 0000000..14c7f10 --- /dev/null +++ b/client/settings_helpers.py @@ -0,0 +1,37 @@ +import json +import os + +SETTINGS_FILE = './settings/settings.json' + +def get_settings(): + with open(SETTINGS_FILE, 'r') as f: + settings = json.load(f) + return settings + +def update_settings(new_settings): + with open(SETTINGS_FILE, 'r+') as f: + settings = json.load(f) + settings.update(new_settings) + f.seek(0) + json.dump(settings, f, indent=4) + f.truncate() + +def is_valid_directory(path): + if not os.path.exists(path): + try: + os.makedirs(path) + return True + except Exception as e: + print(f"Error creating directory: {e}") + return False + elif os.path.isdir(path) and os.access(path, os.W_OK): + return True + else: + return False + +def update_video_save_location(new_location): + if is_valid_directory(new_location): + update_settings({"VideoSaveLocation": new_location}) + return True + else: + return False diff --git a/client/stream_helpers.py b/client/stream_helpers.py index 230f529..25a79b7 100644 --- a/client/stream_helpers.py +++ b/client/stream_helpers.py @@ -1,5 +1,6 @@ import os import cv2 +import json import threading from datetime import datetime @@ -8,8 +9,8 @@ out = None is_recording = False -# Ensure recordings directory exists -os.makedirs('./recordings', exist_ok=True) +# Load settings.json +SETTINGS_FILE = './settings/settings.json' def generate_frames(): @@ -51,10 +52,16 @@ def start_recording() -> None: Returns: None """ - global out, is_recording + + with open(SETTINGS_FILE, 'r') as f: + settings = json.load(f) + + video_save_location = settings.get('VideoSaveLocation', './recordings') + os.makedirs(video_save_location, exist_ok=True) + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - filename = f'./recordings/output_{timestamp}.avi' + filename = os.path.join(video_save_location, f'output_{timestamp}.avi') fourcc = cv2.VideoWriter_fourcc(*'XVID') with lock: diff --git a/client/system_helpers.py b/client/system_helpers.py index 4b8bfe8..e9abc35 100644 --- a/client/system_helpers.py +++ b/client/system_helpers.py @@ -1,54 +1,60 @@ import psutil -def get_cpu_temp() -> float | None: +def get_cpu_temp() -> int | None: """ Returns the CPU temperature of the Raspberry Pi. Returns: - float: The CPU temperature in Celsius. + int: The CPU temperature in Celsius rounded to the nearest integer. None: If the temperature file is not found. """ + try: with open("/sys/class/thermal/thermal_zone0/temp", "r") as file: temp_str = file.read().strip() cpu_temp = int(temp_str) / 1000.0 - return cpu_temp + return round(cpu_temp) except FileNotFoundError: return None -def get_cpu_load() -> float: +def get_cpu_load() -> int: """ - Returns the CPU load as a percentage. + Returns the CPU load as a percentage, considering the maximum load across all cores. Returns: - float: The CPU load as a percentage. + int: The CPU load as a percentage rounded to the nearest integer. """ - return psutil.cpu_percent(interval=1) + + per_core_loads = psutil.cpu_percent(interval=1, percpu=True) + max_load = max(per_core_loads) + return round(max_load) -def get_storage_info() -> dict[str, float]: +def get_storage_info() -> dict[str, int]: """ Returns the total size and used space of the disk where the root directory is mounted. Returns: - dict[str, float]: A dictionary containing the total and used space in GB. + dict[str, int]: A dictionary containing the total and used space in GB, each rounded to the nearest integer. """ + usage = psutil.disk_usage('/') total = usage.total / (1024 ** 3) # Convert bytes to GB used = usage.used / (1024 ** 3) # Convert bytes to GB - return {'total_gb': total, 'used_gb': used} + return {'total_gb': round(total), 'used_gb': round(used)} -def get_ram_usage() -> dict[str, float]: +def get_ram_usage() -> dict[str, int]: """ Returns the total and used RAM in MB. Returns: - dict[str, float]: A dictionary containing the total and used RAM in MB. + dict[str, int]: A dictionary containing the total and used RAM in MB, each rounded to the nearest integer. """ + mem = psutil.virtual_memory() total = mem.total / (1024 ** 2) # Convert bytes to MB used = mem.used / (1024 ** 2) # Convert bytes to MB - return {'total_mb': total, 'used_mb': used} + return {'total_mb': round(total), 'used_mb': round(used)} diff --git a/server/package-lock.json b/server/package-lock.json index cd30324..23b8418 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -4338,8 +4338,15 @@ } }, "node_modules/server": { - "resolved": "", - "link": true + "version": "0.1.0", + "resolved": "file:", + "dependencies": { + "next": "14.2.5", + "react": "^18", + "react-dom": "^18", + "react-player": "^2.16.0", + "server": "file:" + } }, "node_modules/set-function-length": { "version": "1.2.2", diff --git a/server/src/app/page.tsx b/server/src/app/page.tsx index 18ac987..0c2b432 100644 --- a/server/src/app/page.tsx +++ b/server/src/app/page.tsx @@ -1,5 +1,6 @@ import React from "react"; import ClientVideoPlayer from "@/components/ClientVideoPlayer"; +import SystemMonitor from "@/components/SystemMonitor"; const Home = () => { @@ -25,11 +26,7 @@ const Home = () => { -