From c579cb717680bf3b0ddfb1374a1d0d8f1670065b Mon Sep 17 00:00:00 2001 From: devmatrix Date: Fri, 20 Feb 2026 21:28:19 +0000 Subject: [PATCH] Add auto fan curves option to onboarding and start data polling after setup --- data/config.json | 160 ++++++++++++++++ data/users.json | 1 + server.log | 470 ++++++++++++++++++++++++++++++++++++++++++++++- web_server.py | 21 ++- 4 files changed, 643 insertions(+), 9 deletions(-) create mode 100644 data/config.json create mode 100644 data/users.json diff --git a/data/config.json b/data/config.json new file mode 100644 index 0000000..e2049ba --- /dev/null +++ b/data/config.json @@ -0,0 +1,160 @@ +{ + "ipmi_host": "192.168.5.191", + "ipmi_username": "root", + "ipmi_password": "calvin", + "ipmi_port": 623, + "http_sensor_enabled": true, + "http_sensor_url": "http://192.168.5.200:8888", + "http_sensor_timeout": 10, + "enabled": true, + "poll_interval": 10, + "fan_update_interval": 10, + "min_speed": 10, + "max_speed": 100, + "panic_temp": 85, + "panic_speed": 100, + "panic_on_no_data": true, + "no_data_timeout": 60, + "primary_sensor": "cpu", + "sensor_preference": "auto", + "fans": {}, + "fan_groups": {}, + "active_curve": "Balanced", + "fan_curves": { + "Balanced": { + "points": [ + { + "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" + } + }, + "theme": "dark" +} \ No newline at end of file diff --git a/data/users.json b/data/users.json new file mode 100644 index 0000000..eb8443e --- /dev/null +++ b/data/users.json @@ -0,0 +1 @@ +{"users": {"admin": "ecd71870d1963316a97e3ac3408c9835ad8cf0f3c1bc703527c30265534f75ae"}} \ No newline at end of file diff --git a/server.log b/server.log index caf1f0e..153a7d4 100644 --- a/server.log +++ b/server.log @@ -1,8 +1,468 @@ -INFO: Started server process [74745] +INFO: Started server process [86031] 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:54411 - "GET /api/status HTTP/1.1" 401 Unauthorized -INFO: 192.168.5.30:54411 - "GET /login HTTP/1.1" 200 OK -INFO: 192.168.5.30:54411 - "GET /icons/favicon.svg HTTP/1.1" 304 Not Modified -INFO: 127.0.0.1:58102 - "GET / HTTP/1.1" 200 OK +INFO: 127.0.0.1:52194 - "GET / HTTP/1.1" 200 OK +INFO: 127.0.0.1:52206 - "GET / HTTP/1.1" 200 OK +INFO: 192.168.5.30:65213 - "GET / HTTP/1.1" 200 OK +INFO: 192.168.5.30:65213 - "GET /icons/favicon.svg HTTP/1.1" 304 Not Modified +INFO: 192.168.5.30:65213 - "GET /favicon.ico HTTP/1.1" 200 OK +INFO: 192.168.5.30:49755 - "GET /favicon.ico HTTP/1.1" 200 OK +INFO: 192.168.5.30:60215 - "POST /api/setup/test-ipmi HTTP/1.1" 200 OK +INFO: 192.168.5.30:60215 - "GET /favicon.ico HTTP/1.1" 200 OK +INFO: 192.168.5.30:60215 - "POST /api/setup/test-http HTTP/1.1" 200 OK +2026-02-20 21:14:12,721 - fan_controller - INFO - Saved config to /home/devmatrix/projects/fan-controller-v2/data/config.json +2026-02-20 21:14:12,969 - fan_controller - INFO - Connected to IPMI at 192.168.5.191 +2026-02-20 21:14:12,969 - fan_controller - INFO - HTTP sensor client initialized for http://192.168.5.200:8888 +/home/devmatrix/projects/fan-controller-v2/web_server.py:154: 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: 192.168.5.30:60215 - "POST /api/setup HTTP/1.1" 200 OK +INFO: 192.168.5.30:60215 - "GET / HTTP/1.1" 200 OK +INFO: 192.168.5.30:60215 - "GET /icons/sun.svg HTTP/1.1" 304 Not Modified +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60215 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:49551 - "GET /icons/lock-closed.svg HTTP/1.1" 304 Not Modified +INFO: 192.168.5.30:57842 - "GET /icons/arrow-right-on-rectangle.svg HTTP/1.1" 304 Not Modified +INFO: 192.168.5.30:60455 - "GET /icons/server-stack.svg HTTP/1.1" 304 Not Modified +INFO: 192.168.5.30:49786 - "GET /icons/auto-mode.svg HTTP/1.1" 304 Not Modified +INFO: 192.168.5.30:50500 - "GET /icons/thermometer.svg HTTP/1.1" 304 Not Modified +INFO: 192.168.5.30:60215 - "GET /icons/list-bullet.svg HTTP/1.1" 304 Not Modified +INFO: 192.168.5.30:49551 - "GET /icons/adjustments-horizontal.svg HTTP/1.1" 304 Not Modified +INFO: 192.168.5.30:57842 - "GET /icons/chart-bar.svg HTTP/1.1" 304 Not Modified +INFO: 192.168.5.30:60455 - "GET /icons/document-text.svg HTTP/1.1" 304 Not Modified +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "POST /api/test HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +2026-02-20 21:21:00,661 - fan_controller - INFO - Saved config to /home/devmatrix/projects/fan-controller-v2/data/config.json +2026-02-20 21:21:00,824 - fan_controller - INFO - Manual fan control enabled +2026-02-20 21:21:00,981 - fan_controller - INFO - Connected to IPMI at 192.168.5.191 +2026-02-20 21:21:00,981 - fan_controller - INFO - HTTP sensor client initialized for http://192.168.5.200:8888 +2026-02-20 21:21:00,983 - fan_controller - INFO - IPMI Controller service started +INFO: 192.168.5.30:60455 - "POST /api/control/auto HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +2026-02-20 21:21:01,180 - fan_controller - INFO - Manual fan control enabled +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +2026-02-20 21:21:07,293 - fan_controller - INFO - Fan 0xff speed set to 13% +2026-02-20 21:21:07,293 - fan_controller - INFO - All fans set to 13% (Temp 36.0°C) +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +2026-02-20 21:21:37,253 - fan_controller - INFO - Fan 0xff speed set to 14% +2026-02-20 21:21:37,253 - fan_controller - INFO - All fans set to 14% (Temp 38.0°C) +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +2026-02-20 21:21:53,341 - fan_controller - INFO - Fan 0xff speed set to 13% +2026-02-20 21:21:53,342 - fan_controller - INFO - All fans set to 13% (Temp 36.0°C) +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +2026-02-20 21:24:12,026 - fan_controller - INFO - Fan 0xff speed set to 14% +2026-02-20 21:24:12,026 - fan_controller - INFO - All fans set to 14% (Temp 38.0°C) +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +2026-02-20 21:24:57,318 - fan_controller - INFO - Fan 0xff speed set to 13% +2026-02-20 21:24:57,318 - fan_controller - INFO - All fans set to 13% (Temp 37.0°C) +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +2026-02-20 21:25:13,055 - fan_controller - INFO - Fan 0xff speed set to 15% +2026-02-20 21:25:13,056 - fan_controller - INFO - All fans set to 15% (Temp 40.0°C) +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +2026-02-20 21:25:28,522 - fan_controller - INFO - Fan 0xff speed set to 14% +2026-02-20 21:25:28,522 - fan_controller - INFO - All fans set to 14% (Temp 38.0°C) +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +2026-02-20 21:25:43,706 - fan_controller - INFO - Fan 0xff speed set to 13% +2026-02-20 21:25:43,706 - fan_controller - INFO - All fans set to 13% (Temp 37.0°C) +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +2026-02-20 21:25:58,865 - fan_controller - INFO - Fan 0xff speed set to 14% +2026-02-20 21:25:58,866 - fan_controller - INFO - All fans set to 14% (Temp 38.0°C) +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +2026-02-20 21:26:45,316 - fan_controller - INFO - Fan 0xff speed set to 13% +2026-02-20 21:26:45,316 - fan_controller - INFO - All fans set to 13% (Temp 37.0°C) +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +2026-02-20 21:27:00,582 - fan_controller - INFO - Fan 0xff speed set to 14% +2026-02-20 21:27:00,582 - fan_controller - INFO - All fans set to 14% (Temp 38.0°C) +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +/home/devmatrix/projects/fan-controller-v2/web_server.py:161: 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: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK +INFO: 192.168.5.30:60455 - "GET /api/status HTTP/1.1" 200 OK diff --git a/web_server.py b/web_server.py index 8e2961d..ca84da5 100644 --- a/web_server.py +++ b/web_server.py @@ -53,6 +53,8 @@ class SetupRequest(BaseModel): http_sensor_enabled: Optional[bool] = False http_sensor_url: Optional[str] = None http_sensor_timeout: Optional[int] = 10 + enabled: Optional[bool] = False + active_curve: Optional[str] = "Balanced" class IPMIConfig(BaseModel): host: str @@ -1649,17 +1651,28 @@ async def api_setup(data: SetupRequest): "ipmi_host": data.ipmi_host, "ipmi_username": data.ipmi_username, "ipmi_password": data.ipmi_password, - "ipmi_port": data.ipmi_port + "ipmi_port": data.ipmi_port, + "enabled": data.enabled or False, + "active_curve": data.active_curve or "Balanced" } # Add HTTP config if provided - if hasattr(data, 'http_sensor_enabled') and data.http_sensor_enabled: + if 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) + updates["http_sensor_url"] = data.http_sensor_url or '' + updates["http_sensor_timeout"] = data.http_sensor_timeout or 10 service.update_config(**updates) + # Initialize controller and start polling if auto is enabled + if data.enabled: + logger.info("Setup complete - auto fan control enabled, starting service...") + if service._init_controller(): + service.start() + logger.info("Fan control service started successfully") + else: + logger.warning("Could not connect to IPMI - service not started") + token = user_manager.create_token(data.admin_username) return {"success": True, "token": token}