diff --git a/__pycache__/fan_controller.cpython-312.pyc b/__pycache__/fan_controller.cpython-312.pyc index ea1e65d..a8884b9 100644 Binary files a/__pycache__/fan_controller.cpython-312.pyc and b/__pycache__/fan_controller.cpython-312.pyc differ diff --git a/__pycache__/web_server.cpython-312.pyc b/__pycache__/web_server.cpython-312.pyc new file mode 100644 index 0000000..a8132f7 Binary files /dev/null and b/__pycache__/web_server.cpython-312.pyc differ diff --git a/data/config.json b/data/config.json index 6cd8e40..b828e37 100644 --- a/data/config.json +++ b/data/config.json @@ -186,5 +186,5 @@ } }, "theme": "dark", - "active_curve": "Balanced" + "active_curve": "Performance" } \ No newline at end of file diff --git a/data/users.json b/data/users.json deleted file mode 100644 index eb8443e..0000000 --- a/data/users.json +++ /dev/null @@ -1 +0,0 @@ -{"users": {"admin": "ecd71870d1963316a97e3ac3408c9835ad8cf0f3c1bc703527c30265534f75ae"}} \ No newline at end of file diff --git a/fan_controller.py b/fan_controller.py index 2dbb05c..cf83b1f 100644 --- a/fan_controller.py +++ b/fan_controller.py @@ -348,22 +348,58 @@ class IPMIControllerService: # Sensor Selection "primary_sensor": "cpu", # cpu, cpu1, cpu2, inlet, exhaust, pcie, etc. - "sensor_preference": "ipmi", # ipmi, http, auto + "sensor_preference": "auto", # ipmi, http, auto # Fan Configuration "fans": {}, # fan_id -> {"name": "Custom Name", "group": "group1"} "fan_groups": {}, # group_name -> {"fans": ["0x00", "0x01"], "curve": "Default"} # Fan Curves + "active_curve": "Balanced", "fan_curves": { - "Default": { + "Balanced": { "points": [ - {"temp": 30, "speed": 15}, - {"temp": 40, "speed": 25}, - {"temp": 50, "speed": 40}, - {"temp": 60, "speed": 60}, - {"temp": 70, "speed": 80}, - {"temp": 80, "speed": 100}, + {"temp": 30, "speed": 10}, + {"temp": 35, "speed": 12}, + {"temp": 40, "speed": 15}, + {"temp": 45, "speed": 20}, + {"temp": 50, "speed": 30}, + {"temp": 55, "speed": 40}, + {"temp": 60, "speed": 55}, + {"temp": 65, "speed": 70}, + {"temp": 70, "speed": 85}, + {"temp": 75, "speed": 95}, + {"temp": 80, "speed": 100} + ], + "sensor_source": "cpu", + "applies_to": "all" + }, + "Silent": { + "points": [ + {"temp": 30, "speed": 5}, + {"temp": 40, "speed": 10}, + {"temp": 50, "speed": 15}, + {"temp": 55, "speed": 25}, + {"temp": 60, "speed": 35}, + {"temp": 65, "speed": 50}, + {"temp": 70, "speed": 70}, + {"temp": 75, "speed": 85}, + {"temp": 80, "speed": 100} + ], + "sensor_source": "cpu", + "applies_to": "all" + }, + "Performance": { + "points": [ + {"temp": 30, "speed": 20}, + {"temp": 35, "speed": 25}, + {"temp": 40, "speed": 35}, + {"temp": 45, "speed": 45}, + {"temp": 50, "speed": 55}, + {"temp": 55, "speed": 70}, + {"temp": 60, "speed": 85}, + {"temp": 65, "speed": 95}, + {"temp": 70, "speed": 100} ], "sensor_source": "cpu", "applies_to": "all" diff --git a/server.log b/server.log index 1b4e7c8..ebd2c40 100644 --- a/server.log +++ b/server.log @@ -1,26 +1,9 @@ -INFO: Started server process [29754] +INFO: Started server process [33302] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit) -INFO: 192.168.5.30:55306 - "GET /api/status HTTP/1.1" 401 Unauthorized -INFO: 192.168.5.30:55306 - "GET /login HTTP/1.1" 200 OK -INFO: 192.168.5.30:54183 - "GET /login HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:149: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - self._sessions[token] = (username, datetime.utcnow() + timedelta(days=7)) -INFO: 127.0.0.1:36770 - "POST /api/auth/login HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -2026-02-20 17:23:59,479 - fan_controller - INFO - Loaded config from /home/devmatrix/projects/fan-controller-v2/data/config.json -2026-02-20 17:23:59,481 - fan_controller - INFO - Saved config to /home/devmatrix/projects/fan-controller-v2/data/config.json -2026-02-20 17:23:59,638 - fan_controller - INFO - Connected to IPMI at 192.168.5.191 -2026-02-20 17:23:59,638 - fan_controller - INFO - HTTP sensor client initialized for http://192.168.5.200:8888 -2026-02-20 17:23:59,639 - fan_controller - INFO - IPMI Controller service started -INFO: 127.0.0.1:36774 - "POST /api/control/auto HTTP/1.1" 200 OK -2026-02-20 17:23:59,796 - fan_controller - INFO - Manual fan control enabled -2026-02-20 17:24:04,639 - fan_controller - INFO - Fan 0xff speed set to 12% -2026-02-20 17:24:04,640 - fan_controller - INFO - All fans set to 12% (Temp 35.0°C) -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 127.0.0.1:34428 - "GET /api/status HTTP/1.1" 200 OK -2026-02-20 17:24:19,530 - fan_controller - INFO - Fan 0xff speed set to 13% -2026-02-20 17:24:19,531 - fan_controller - INFO - All fans set to 13% (Temp 37.0°C) +INFO: 127.0.0.1:44708 - "GET / HTTP/1.1" 200 OK +INFO: 192.168.5.30:64440 - "GET /login HTTP/1.1" 200 OK +INFO: 192.168.5.30:56562 - "GET /favicon.ico HTTP/1.1" 200 OK +INFO: 192.168.5.30:49401 - "POST /api/setup/test-ipmi HTTP/1.1" 200 OK +INFO: 192.168.5.30:49401 - "GET /favicon.ico HTTP/1.1" 200 OK diff --git a/web_server.py b/web_server.py index b029d1d..1103f9c 100644 --- a/web_server.py +++ b/web_server.py @@ -49,6 +49,9 @@ class SetupRequest(BaseModel): ipmi_username: str ipmi_password: str ipmi_port: int = 623 + http_sensor_enabled: Optional[bool] = False + http_sensor_url: Optional[str] = None + http_sensor_timeout: Optional[int] = 10 class IPMIConfig(BaseModel): host: str @@ -1142,135 +1145,8 @@ LOGIN_HTML = ''' ''' -SETUP_HTML = ''' - - - - - - Setup - IPMI Controller - - - -
-

🌡️ IPMI Controller

-

Initial Setup

-
-
-
-

👤 Admin Account

-
-
-
-
-
-
-

🖥️ IPMI Connection

-
-
-
-
-
-
-
- -
-
- - -''' +with open('/home/devmatrix/.openclaw/workspace/setup_html.txt', 'r') as f: + SETUP_HTML = f.read().strip().replace("SETUP_HTML = '''", "").replace("'''", "") # FastAPI app @asynccontextmanager @@ -1344,6 +1220,35 @@ async def api_change_password(data: ChangePassword, username: str = Depends(get_ return {"success": False, "error": "Current password is incorrect"} return {"success": True} +# Setup test endpoints (no auth required for setup) +@app.post("/api/setup/test-ipmi") +async def api_setup_test_ipmi(data: dict): + """Test IPMI connection during setup.""" + from fan_controller import IPMIFanController + try: + controller = IPMIFanController( + host=data.get('host'), + username=data.get('username'), + password=data.get('password'), + port=data.get('port', 623) + ) + if controller.test_connection(): + return {"success": True} + return {"success": False, "error": "Connection failed"} + except Exception as e: + return {"success": False, "error": str(e)} + +@app.post("/api/setup/test-http") +async def api_setup_test_http(data: dict): + """Test HTTP sensor during setup.""" + from fan_controller import HTTPSensorClient + try: + client = HTTPSensorClient(url=data.get('url'), timeout=10) + temps = client.fetch_sensors() + return {"success": True, "sensors": len(temps)} + except Exception as e: + return {"success": False, "error": str(e)} + @app.post("/api/setup") async def api_setup(data: SetupRequest): if user_manager.is_setup_complete(): @@ -1353,12 +1258,20 @@ async def api_setup(data: SetupRequest): return {"success": False, "error": "Failed to create user"} service = get_service(str(CONFIG_FILE)) - service.update_config( - ipmi_host=data.ipmi_host, - ipmi_username=data.ipmi_username, - ipmi_password=data.ipmi_password, - ipmi_port=data.ipmi_port - ) + updates = { + "ipmi_host": data.ipmi_host, + "ipmi_username": data.ipmi_username, + "ipmi_password": data.ipmi_password, + "ipmi_port": data.ipmi_port + } + + # Add HTTP config if provided + if hasattr(data, 'http_sensor_enabled') and data.http_sensor_enabled: + updates["http_sensor_enabled"] = True + updates["http_sensor_url"] = getattr(data, 'http_sensor_url', '') + updates["http_sensor_timeout"] = getattr(data, 'http_sensor_timeout', 10) + + service.update_config(**updates) token = user_manager.create_token(data.admin_username) return {"success": True, "token": token}