Implement fan groups, per-fan controls, theme toggle, footer links
This commit is contained in:
parent
1b93f71a19
commit
8d06f60945
585
server.log
585
server.log
|
|
@ -1,98 +1,549 @@
|
||||||
INFO: Started server process [70935]
|
INFO: Started server process [71515]
|
||||||
INFO: Waiting for application startup.
|
INFO: Waiting for application startup.
|
||||||
2026-02-20 20:04:15,011 - fan_controller - INFO - Loaded config from /home/devmatrix/projects/fan-controller-v2/data/config.json
|
2026-02-20 20:06:54,388 - fan_controller - INFO - Loaded config from /home/devmatrix/projects/fan-controller-v2/data/config.json
|
||||||
2026-02-20 20:04:15,011 - __main__ - INFO - Auto-starting fan control (enabled in config)
|
2026-02-20 20:06:54,388 - __main__ - INFO - Auto-starting fan control (enabled in config)
|
||||||
2026-02-20 20:04:15,162 - fan_controller - INFO - Connected to IPMI at 192.168.5.191
|
2026-02-20 20:06:54,546 - fan_controller - INFO - Connected to IPMI at 192.168.5.191
|
||||||
2026-02-20 20:04:15,162 - fan_controller - INFO - HTTP sensor client initialized for http://192.168.5.200:8888
|
2026-02-20 20:06:54,546 - fan_controller - INFO - HTTP sensor client initialized for http://192.168.5.200:8888
|
||||||
2026-02-20 20:04:15,163 - fan_controller - INFO - IPMI Controller service started
|
2026-02-20 20:06:54,547 - fan_controller - INFO - IPMI Controller service started
|
||||||
INFO: Application startup complete.
|
INFO: Application startup complete.
|
||||||
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
|
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
|
||||||
2026-02-20 20:04:15,314 - fan_controller - INFO - Manual fan control enabled
|
INFO: 192.168.5.30:61891 - "GET /api/status HTTP/1.1" 401 Unauthorized
|
||||||
INFO: 192.168.5.30:62669 - "GET /api/status HTTP/1.1" 401 Unauthorized
|
2026-02-20 20:06:54,707 - fan_controller - INFO - Manual fan control enabled
|
||||||
INFO: 192.168.5.30:62669 - "GET /login HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:61891 - "GET /login HTTP/1.1" 200 OK
|
||||||
INFO: 192.168.5.30:62669 - "GET /icons/favicon.svg HTTP/1.1" 304 Not Modified
|
INFO: 192.168.5.30:61891 - "GET /icons/favicon.svg HTTP/1.1" 304 Not Modified
|
||||||
2026-02-20 20:04:20,942 - fan_controller - INFO - Fan 0xff speed set to 27%
|
2026-02-20 20:06:59,911 - fan_controller - INFO - Fan 0xff speed set to 27%
|
||||||
2026-02-20 20:04:20,942 - fan_controller - INFO - All fans set to 27% (Temp 36.0°C)
|
2026-02-20 20:06:59,911 - fan_controller - INFO - All fans set to 27% (Temp 36.0°C)
|
||||||
2026-02-20 20:04:36,853 - fan_controller - INFO - Fan 0xff speed set to 31%
|
|
||||||
2026-02-20 20:04:36,853 - fan_controller - INFO - All fans set to 31% (Temp 38.0°C)
|
|
||||||
INFO: 127.0.0.1:34870 - "GET /api/status HTTP/1.1" 401 Unauthorized
|
|
||||||
2026-02-20 20:04:51,781 - fan_controller - INFO - Fan 0xff speed set to 27%
|
|
||||||
2026-02-20 20:04:51,781 - fan_controller - INFO - All fans set to 27% (Temp 36.0°C)
|
|
||||||
2026-02-20 20:05:07,261 - fan_controller - INFO - Fan 0xff speed set to 25%
|
|
||||||
2026-02-20 20:05:07,261 - fan_controller - INFO - All fans set to 25% (Temp 35.0°C)
|
|
||||||
INFO: 192.168.5.30:65404 - "GET /login HTTP/1.1" 200 OK
|
|
||||||
INFO: 192.168.5.30:65404 - "GET /favicon.ico HTTP/1.1" 200 OK
|
|
||||||
/home/devmatrix/projects/fan-controller-v2/web_server.py:153: 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).
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:153: 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))
|
self._sessions[token] = (username, datetime.utcnow() + timedelta(days=7))
|
||||||
INFO: 192.168.5.30:65404 - "POST /api/auth/login HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:52052 - "POST /api/auth/login HTTP/1.1" 200 OK
|
||||||
INFO: 192.168.5.30:65404 - "GET / HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:52052 - "GET / HTTP/1.1" 200 OK
|
||||||
INFO: 192.168.5.30:65404 - "GET /icons/sun.svg HTTP/1.1" 304 Not Modified
|
INFO: 192.168.5.30:52052 - "GET /icons/auto-mode.svg HTTP/1.1" 200 OK
|
||||||
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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).
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:
|
if datetime.utcnow() > expiry:
|
||||||
INFO: 192.168.5.30:58005 - "GET /api/status HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:55325 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
INFO: 192.168.5.30:64268 - "GET /icons/lock-closed.svg HTTP/1.1" 304 Not Modified
|
INFO: 192.168.5.30:63188 - "GET /icons/thermometer.svg HTTP/1.1" 304 Not Modified
|
||||||
INFO: 192.168.5.30:63723 - "GET /icons/auto-mode.svg HTTP/1.1" 304 Not Modified
|
INFO: 192.168.5.30:63188 - "GET /favicon.ico HTTP/1.1" 200 OK
|
||||||
INFO: 192.168.5.30:65404 - "GET /icons/thermometer.svg HTTP/1.1" 304 Not Modified
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
INFO: 192.168.5.30:64382 - "GET /icons/server-stack.svg HTTP/1.1" 304 Not Modified
|
|
||||||
INFO: 192.168.5.30:50712 - "GET /icons/arrow-right-on-rectangle.svg HTTP/1.1" 304 Not Modified
|
|
||||||
INFO: 192.168.5.30:58005 - "GET /icons/list-bullet.svg HTTP/1.1" 304 Not Modified
|
|
||||||
INFO: 192.168.5.30:63723 - "GET /icons/chart-bar.svg HTTP/1.1" 304 Not Modified
|
|
||||||
INFO: 192.168.5.30:64268 - "GET /icons/adjustments-horizontal.svg HTTP/1.1" 304 Not Modified
|
|
||||||
INFO: 192.168.5.30:65404 - "GET /icons/document-text.svg HTTP/1.1" 304 Not Modified
|
|
||||||
INFO: 192.168.5.30:65404 - "GET /favicon.ico HTTP/1.1" 200 OK
|
|
||||||
2026-02-20 20:05:22,464 - fan_controller - INFO - Fan 0xff speed set to 27%
|
|
||||||
2026-02-20 20:05:22,464 - fan_controller - INFO - All fans set to 27% (Temp 36.0°C)
|
|
||||||
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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).
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:
|
if datetime.utcnow() > expiry:
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
|
||||||
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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).
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:
|
if datetime.utcnow() > expiry:
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:07:15,453 - fan_controller - INFO - Fan 0xff speed set to 25%
|
||||||
|
2026-02-20 20:07:15,453 - fan_controller - INFO - All fans set to 25% (Temp 35.0°C)
|
||||||
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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).
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:
|
if datetime.utcnow() > expiry:
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
|
||||||
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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).
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:
|
if datetime.utcnow() > expiry:
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 127.0.0.1:50858 - "GET /icons/auto-mode.svg HTTP/1.1" 200 OK
|
||||||
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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).
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:
|
if datetime.utcnow() > expiry:
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
2026-02-20 20:05:53,251 - fan_controller - INFO - Fan 0xff speed set to 29%
|
2026-02-20 20:07:30,915 - fan_controller - INFO - Fan 0xff speed set to 29%
|
||||||
2026-02-20 20:05:53,251 - fan_controller - INFO - All fans set to 29% (Temp 37.0°C)
|
2026-02-20 20:07:30,915 - fan_controller - INFO - All fans set to 29% (Temp 37.0°C)
|
||||||
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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).
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:
|
if datetime.utcnow() > expiry:
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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).
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:
|
if datetime.utcnow() > expiry:
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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).
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:
|
if datetime.utcnow() > expiry:
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
2026-02-20 20:06:08,235 - fan_controller - INFO - Fan 0xff speed set to 25%
|
2026-02-20 20:07:45,964 - fan_controller - INFO - Fan 0xff speed set to 27%
|
||||||
2026-02-20 20:06:08,235 - fan_controller - INFO - All fans set to 25% (Temp 35.0°C)
|
2026-02-20 20:07:45,965 - fan_controller - INFO - All fans set to 27% (Temp 36.0°C)
|
||||||
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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).
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:
|
if datetime.utcnow() > expiry:
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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).
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:
|
if datetime.utcnow() > expiry:
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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).
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:
|
if datetime.utcnow() > expiry:
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
2026-02-20 20:06:23,620 - fan_controller - INFO - Fan 0xff speed set to 29%
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
2026-02-20 20:06:23,620 - fan_controller - INFO - All fans set to 29% (Temp 37.0°C)
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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).
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:
|
if datetime.utcnow() > expiry:
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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).
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
if datetime.utcnow() > expiry:
|
||||||
INFO: 192.168.5.30:65404 - "GET /api/status HTTP/1.1" 200 OK
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:63188 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:09:03,867 - fan_controller - INFO - Fan 0xff speed set to 29%
|
||||||
|
2026-02-20 20:09:03,867 - fan_controller - INFO - All fans set to 29% (Temp 37.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:09:19,798 - fan_controller - INFO - Fan 0xff speed set to 31%
|
||||||
|
2026-02-20 20:09:19,799 - fan_controller - INFO - All fans set to 31% (Temp 38.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:55296 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:09:35,346 - fan_controller - INFO - Fan 0xff speed set to 29%
|
||||||
|
2026-02-20 20:09:35,347 - fan_controller - INFO - All fans set to 29% (Temp 37.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:09:50,823 - fan_controller - INFO - Fan 0xff speed set to 27%
|
||||||
|
2026-02-20 20:09:50,823 - fan_controller - INFO - All fans set to 27% (Temp 36.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:10:06,006 - fan_controller - INFO - Fan 0xff speed set to 31%
|
||||||
|
2026-02-20 20:10:06,006 - fan_controller - INFO - All fans set to 31% (Temp 38.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:57942 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:10:54,206 - fan_controller - INFO - Fan 0xff speed set to 27%
|
||||||
|
2026-02-20 20:10:54,206 - fan_controller - INFO - All fans set to 27% (Temp 36.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:64073 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:13:15,599 - fan_controller - INFO - Fan 0xff speed set to 25%
|
||||||
|
2026-02-20 20:13:15,600 - fan_controller - INFO - All fans set to 25% (Temp 35.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:13:32,024 - fan_controller - INFO - Fan 0xff speed set to 27%
|
||||||
|
2026-02-20 20:13:32,025 - fan_controller - INFO - All fans set to 27% (Temp 36.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:13:48,155 - fan_controller - INFO - Fan 0xff speed set to 29%
|
||||||
|
2026-02-20 20:13:48,156 - fan_controller - INFO - All fans set to 29% (Temp 37.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:14:04,773 - fan_controller - INFO - Fan 0xff speed set to 25%
|
||||||
|
2026-02-20 20:14:04,774 - fan_controller - INFO - All fans set to 25% (Temp 35.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:14:20,306 - fan_controller - INFO - Fan 0xff speed set to 29%
|
||||||
|
2026-02-20 20:14:20,307 - fan_controller - INFO - All fans set to 29% (Temp 37.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:14:36,209 - fan_controller - INFO - Fan 0xff speed set to 27%
|
||||||
|
2026-02-20 20:14:36,209 - fan_controller - INFO - All fans set to 27% (Temp 36.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:14:51,615 - fan_controller - INFO - Fan 0xff speed set to 29%
|
||||||
|
2026-02-20 20:14:51,616 - fan_controller - INFO - All fans set to 29% (Temp 37.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:15:22,579 - fan_controller - INFO - Fan 0xff speed set to 27%
|
||||||
|
2026-02-20 20:15:22,579 - fan_controller - INFO - All fans set to 27% (Temp 36.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:15:37,470 - fan_controller - INFO - Fan 0xff speed set to 29%
|
||||||
|
2026-02-20 20:15:37,470 - fan_controller - INFO - All fans set to 29% (Temp 37.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET / HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /icons/favicon.svg HTTP/1.1" 304 Not Modified
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:60159 - "GET /icons/lock-closed.svg HTTP/1.1" 304 Not Modified
|
||||||
|
INFO: 192.168.5.30:57390 - "GET /icons/auto-mode.svg HTTP/1.1" 304 Not Modified
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /icons/sun.svg HTTP/1.1" 304 Not Modified
|
||||||
|
INFO: 192.168.5.30:55085 - "GET /icons/server-stack.svg HTTP/1.1" 304 Not Modified
|
||||||
|
INFO: 192.168.5.30:51598 - "GET /icons/arrow-right-on-rectangle.svg HTTP/1.1" 304 Not Modified
|
||||||
|
INFO: 192.168.5.30:50577 - "GET /icons/thermometer.svg HTTP/1.1" 304 Not Modified
|
||||||
|
INFO: 192.168.5.30:57390 - "GET /icons/adjustments-horizontal.svg HTTP/1.1" 304 Not Modified
|
||||||
|
INFO: 192.168.5.30:60159 - "GET /icons/list-bullet.svg HTTP/1.1" 304 Not Modified
|
||||||
|
INFO: 192.168.5.30:51598 - "GET /icons/chart-bar.svg HTTP/1.1" 304 Not Modified
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /icons/document-text.svg HTTP/1.1" 304 Not Modified
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /favicon.ico HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:15:52,508 - fan_controller - INFO - Fan 0xff speed set to 27%
|
||||||
|
2026-02-20 20:15:52,508 - fan_controller - INFO - All fans set to 27% (Temp 36.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:16:39,127 - fan_controller - INFO - Fan 0xff speed set to 25%
|
||||||
|
2026-02-20 20:16:39,127 - fan_controller - INFO - All fans set to 25% (Temp 35.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:16:55,091 - fan_controller - INFO - Fan 0xff speed set to 27%
|
||||||
|
2026-02-20 20:16:55,092 - fan_controller - INFO - All fans set to 27% (Temp 36.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:17:11,182 - fan_controller - INFO - Fan 0xff speed set to 25%
|
||||||
|
2026-02-20 20:17:11,182 - fan_controller - INFO - All fans set to 25% (Temp 35.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:17:26,052 - fan_controller - INFO - Fan 0xff speed set to 29%
|
||||||
|
2026-02-20 20:17:26,052 - fan_controller - INFO - All fans set to 29% (Temp 37.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:17:41,039 - fan_controller - INFO - Fan 0xff speed set to 27%
|
||||||
|
2026-02-20 20:17:41,040 - fan_controller - INFO - All fans set to 27% (Temp 36.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:18:13,111 - fan_controller - INFO - Fan 0xff speed set to 31%
|
||||||
|
2026-02-20 20:18:13,111 - fan_controller - INFO - All fans set to 31% (Temp 38.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:18:28,096 - fan_controller - INFO - Fan 0xff speed set to 27%
|
||||||
|
2026-02-20 20:18:28,097 - fan_controller - INFO - All fans set to 27% (Temp 36.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:18:44,743 - fan_controller - INFO - Fan 0xff speed set to 29%
|
||||||
|
2026-02-20 20:18:44,743 - fan_controller - INFO - All fans set to 29% (Temp 37.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
2026-02-20 20:19:00,200 - fan_controller - INFO - Fan 0xff speed set to 27%
|
||||||
|
2026-02-20 20:19:00,201 - fan_controller - INFO - All fans set to 27% (Temp 36.0°C)
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
/home/devmatrix/projects/fan-controller-v2/web_server.py:160: 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:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
INFO: 192.168.5.30:59075 - "GET /api/status HTTP/1.1" 200 OK
|
||||||
|
|
|
||||||
275
web_server.py
275
web_server.py
|
|
@ -102,7 +102,8 @@ class FanGroupCreate(BaseModel):
|
||||||
|
|
||||||
class ManualSpeedRequest(BaseModel):
|
class ManualSpeedRequest(BaseModel):
|
||||||
speed: int = Field(..., ge=0, le=100)
|
speed: int = Field(..., ge=0, le=100)
|
||||||
fan_id: str = "0xff"
|
fan_id: Optional[str] = "0xff"
|
||||||
|
group: Optional[str] = None
|
||||||
|
|
||||||
class IdentifyRequest(BaseModel):
|
class IdentifyRequest(BaseModel):
|
||||||
fan_id: str
|
fan_id: str
|
||||||
|
|
@ -554,7 +555,7 @@ def get_html(theme="dark"):
|
||||||
<button class="tab active" onclick="showTab('ipmi')"><span class="icon-svg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="2" y="3" width="20" height="6" rx="2"/><rect x="2" y="11" width="20" height="6" rx="2"/><rect x="2" y="19" width="20" height="3" rx="1.5"/></svg></span>IPMI</button>
|
<button class="tab active" onclick="showTab('ipmi')"><span class="icon-svg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><rect x="2" y="3" width="20" height="6" rx="2"/><rect x="2" y="11" width="20" height="6" rx="2"/><rect x="2" y="19" width="20" height="3" rx="1.5"/></svg></span>IPMI</button>
|
||||||
<button class="tab" onclick="showTab('http')"><span class="icon-svg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></span>HTTP</button>
|
<button class="tab" onclick="showTab('http')"><span class="icon-svg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="10"/><path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></span>HTTP</button>
|
||||||
<button class="tab" onclick="showTab('control')"><span class="icon-svg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg></span>Control</button>
|
<button class="tab" onclick="showTab('control')"><span class="icon-svg"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg></span>Control</button>
|
||||||
<button class="tab" onclick="showTab('fans')"><img src="/icons/favicon.svg" class="icon-svg" alt=""> Fans</button>
|
<button class="tab" onclick="showTab('fans')"><img src="/icons/favicon.svg" class="icon-svg" alt=""> Fan Groups</button>
|
||||||
<button class="tab" onclick="showTab('curves')"><img src="/icons/chart-bar.svg" class="icon-svg" alt=""> Curves</button>
|
<button class="tab" onclick="showTab('curves')"><img src="/icons/chart-bar.svg" class="icon-svg" alt=""> Curves</button>
|
||||||
<button class="tab" onclick="showTab('logs')"><img src="/icons/document-text.svg" class="icon-svg" alt=""> Logs</button>
|
<button class="tab" onclick="showTab('logs')"><img src="/icons/document-text.svg" class="icon-svg" alt=""> Logs</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -646,15 +647,21 @@ def get_html(theme="dark"):
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="tab-fans" class="tab-content">
|
<div id="tab-fans" class="tab-content">
|
||||||
<h3>Fan Configuration</h3>
|
<h3>Fan Groups Management</h3>
|
||||||
|
<div id="fan-groups-list" style="margin-bottom:20px;">
|
||||||
|
<p style="color:var(--text-secondary);">Loading fan groups...</p>
|
||||||
|
</div>
|
||||||
|
<h4>Individual Fan Configuration</h4>
|
||||||
<div id="fan-config-list">
|
<div id="fan-config-list">
|
||||||
<p style="color:var(--text-secondary);">Connect to IPMI to see fans</p>
|
<p style="color:var(--text-secondary);">Connect to IPMI to see fans</p>
|
||||||
</div>
|
</div>
|
||||||
<h4 style="margin-top:20px;">Fan Groups</h4>
|
|
||||||
<div id="fan-groups-list">
|
<h4 style="margin-top:20px;">Quick Actions</h4>
|
||||||
<p style="color:var(--text-secondary);">No groups defined</p>
|
<div style="display:flex;gap:10px;flex-wrap:wrap;">
|
||||||
|
<button class="secondary" onclick="setAllFans(50)">Set All 50%</button>
|
||||||
|
<button class="secondary" onclick="setAllFans(75)">Set All 75%</button>
|
||||||
|
<button class="secondary" onclick="setAllFans(100)">Set All 100%</button>
|
||||||
</div>
|
</div>
|
||||||
<button class="secondary" onclick="showGroupModal()">+ Add Group</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="tab-curves" class="tab-content">
|
<div id="tab-curves" class="tab-content">
|
||||||
|
|
@ -697,6 +704,44 @@ def get_html(theme="dark"):
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Fan Group Modal -->
|
||||||
|
<div class="modal" id="group-modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<h3>Manage Fan Group</h3>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Group Name</label>
|
||||||
|
<input type="text" id="group-name" placeholder="e.g., CPU Fans, Rear Fans">
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Select Fans for Group</label>
|
||||||
|
<div id="group-fan-selection" style="max-height:200px;overflow-y:auto;">
|
||||||
|
<p style="color:var(--text-secondary);">Connect to IPMI to see fans</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="display:flex;gap:10px;margin-top:15px;">
|
||||||
|
<button class="secondary" style="flex:1;" onclick="hideModal('group-modal')">Cancel</button>
|
||||||
|
<button class="primary" style="flex:1;" onclick="saveGroup()">Save Group</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Per-Fan Speed Modal -->
|
||||||
|
<div class="modal" id="fan-speed-modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<h3>Set Fan Speed</h3>
|
||||||
|
<div id="fan-speed-target" style="margin-bottom:15px;font-weight:bold;"></div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>Speed: <span id="fan-speed-val">50%</span></label>
|
||||||
|
<input type="range" id="fan-speed-slider" min="0" max="100" value="50"
|
||||||
|
oninput="document.getElementById('fan-speed-val').textContent = this.value + '%'">
|
||||||
|
</div>
|
||||||
|
<div style="display:flex;gap:10px;margin-top:15px;">
|
||||||
|
<button class="secondary" style="flex:1;" onclick="hideModal('fan-speed-modal')">Cancel</button>
|
||||||
|
<button class="primary" style="flex:1;" onclick="applyFanSpeed()">Apply</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
let currentStatus = {{}};
|
let currentStatus = {{}};
|
||||||
let currentConfig = {{}};
|
let currentConfig = {{}};
|
||||||
|
|
@ -706,7 +751,7 @@ def get_html(theme="dark"):
|
||||||
const current = localStorage.getItem('theme') || 'dark';
|
const current = localStorage.getItem('theme') || 'dark';
|
||||||
const next = current === 'dark' ? 'light' : 'dark';
|
const next = current === 'dark' ? 'light' : 'dark';
|
||||||
localStorage.setItem('theme', next);
|
localStorage.setItem('theme', next);
|
||||||
location.reload();
|
window.location.href = window.location.pathname + '?theme=' + next;
|
||||||
}}
|
}}
|
||||||
|
|
||||||
// Load saved theme
|
// Load saved theme
|
||||||
|
|
@ -782,6 +827,57 @@ def get_html(theme="dark"):
|
||||||
// Fan grid
|
// Fan grid
|
||||||
const fans = currentStatus.fans || [];
|
const fans = currentStatus.fans || [];
|
||||||
const fanConfigs = currentStatus.config?.fans || {{}};
|
const fanConfigs = currentStatus.config?.fans || {{}};
|
||||||
|
const fanGroups = currentStatus.config?.fan_groups || {{}};
|
||||||
|
|
||||||
|
// Update Fan Groups tab
|
||||||
|
const fanGroupsList = document.getElementById('fan-groups-list');
|
||||||
|
if (Object.keys(fanGroups).length === 0) {{
|
||||||
|
fanGroupsList.innerHTML = '<p style="color:var(--text-secondary);">No groups defined. Groups let you control multiple fans together.</p>' +
|
||||||
|
'<button class="secondary" onclick="showGroupModal()">+ Create First Group</button>';
|
||||||
|
}} else {{
|
||||||
|
fanGroupsList.innerHTML = Object.entries(fanGroups).map(([name, group]) => {{
|
||||||
|
const fanCount = group.fan_ids?.length || 0;
|
||||||
|
return `<div class="fan-card" style="margin-bottom:10px;">
|
||||||
|
<div style="display:flex;justify-content:space-between;align-items:center;">
|
||||||
|
<div>
|
||||||
|
<div class="fan-name">${{name}}</div>
|
||||||
|
<div class="fan-info">${{fanCount}} fan${{fanCount !== 1 ? 's' : ''}}</div>
|
||||||
|
</div>
|
||||||
|
<div style="display:flex;gap:5px;">
|
||||||
|
<button class="secondary small" onclick="showFanSpeedModal('${{name}}', true)">Set Speed</button>
|
||||||
|
<button class="secondary small" onclick="showGroupModal('${{name}}')">Edit</button>
|
||||||
|
<button class="danger small" onclick="deleteGroup('${{name}}')">Delete</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}}).join('') + '<button class="secondary" onclick="showGroupModal()" style="margin-top:10px;">+ Add Group</button>';
|
||||||
|
}}
|
||||||
|
|
||||||
|
// Update Individual Fan Config
|
||||||
|
const fanConfigList = document.getElementById('fan-config-list');
|
||||||
|
if (fans.length === 0) {{
|
||||||
|
fanConfigList.innerHTML = '<p style="color:var(--text-secondary);">Connect to IPMI to see fans</p>';
|
||||||
|
}} else {{
|
||||||
|
fanConfigList.innerHTML = fans.map(f => {{
|
||||||
|
const cfg = fanConfigs[f.fan_id] || {{}};
|
||||||
|
const name = cfg.name || `Fan ${{f.fan_number}}`;
|
||||||
|
const group = Object.entries(fanGroups).find(([n, g]) => g.fan_ids?.includes(f.fan_id));
|
||||||
|
const groupName = group ? group[0] : 'No group';
|
||||||
|
return `<div class="fan-card" style="margin-bottom:10px;">
|
||||||
|
<div style="display:flex;justify-content:space-between;align-items:center;">
|
||||||
|
<div>
|
||||||
|
<div class="fan-name">${{name}}</div>
|
||||||
|
<div class="fan-info">${{f.speed_rpm || 0}} RPM • ${{f.speed_percent || 0}}% • Group: ${{groupName}}</div>
|
||||||
|
</div>
|
||||||
|
<div style="display:flex;gap:5px;">
|
||||||
|
<button class="secondary small" onclick="showFanSpeedModal('${{f.fan_id}}', false)">Set Speed</button>
|
||||||
|
<button class="secondary small" onclick="identifyFan('${{f.fan_id}}')">Identify</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
}}).join('');
|
||||||
|
}}
|
||||||
|
|
||||||
const fanGrid = document.getElementById('fan-grid');
|
const fanGrid = document.getElementById('fan-grid');
|
||||||
if (fans.length > 0) {{
|
if (fans.length > 0) {{
|
||||||
fanGrid.innerHTML = fans.map(f => {{
|
fanGrid.innerHTML = fans.map(f => {{
|
||||||
|
|
@ -940,6 +1036,118 @@ def get_html(theme="dark"):
|
||||||
const res = await api('/api/fans/stop-identify', {{method: 'POST'}});
|
const res = await api('/api/fans/stop-identify', {{method: 'POST'}});
|
||||||
log('Identify mode stopped');
|
log('Identify mode stopped');
|
||||||
hideModal('identify-modal');
|
hideModal('identify-modal');
|
||||||
|
fetchStatus();
|
||||||
|
}}
|
||||||
|
|
||||||
|
// Fan Group Management
|
||||||
|
let currentFanSpeedTarget = null;
|
||||||
|
|
||||||
|
function showGroupModal(groupName = null) {{
|
||||||
|
const fans = currentStatus.fans || [];
|
||||||
|
const container = document.getElementById('group-fan-selection');
|
||||||
|
|
||||||
|
if (fans.length === 0) {{
|
||||||
|
container.innerHTML = '<p style="color:var(--text-secondary);">No fans available. Connect to IPMI first.</p>';
|
||||||
|
}} else {{
|
||||||
|
const fanConfigs = currentStatus.config?.fans || {{}};
|
||||||
|
container.innerHTML = fans.map(f => {{
|
||||||
|
const cfg = fanConfigs[f.fan_id] || {{}};
|
||||||
|
const name = cfg.name || `Fan ${{f.fan_number}}`;
|
||||||
|
return `<label style="display:block;margin:5px 0;cursor:pointer;">
|
||||||
|
<input type="checkbox" value="${{f.fan_id}}" class="group-fan-checkbox"> ${{name}} (${{f.fan_id}})
|
||||||
|
</label>`;
|
||||||
|
}}).join('');
|
||||||
|
}}
|
||||||
|
|
||||||
|
document.getElementById('group-name').value = groupName || '';
|
||||||
|
showModal('group-modal');
|
||||||
|
}}
|
||||||
|
|
||||||
|
async function saveGroup() {{
|
||||||
|
const name = document.getElementById('group-name').value.trim();
|
||||||
|
if (!name) {{
|
||||||
|
log('Group name required', 'error');
|
||||||
|
return;
|
||||||
|
}}
|
||||||
|
|
||||||
|
const fanIds = Array.from(document.querySelectorAll('.group-fan-checkbox:checked')).map(cb => cb.value);
|
||||||
|
if (fanIds.length === 0) {{
|
||||||
|
log('Select at least one fan', 'error');
|
||||||
|
return;
|
||||||
|
}}
|
||||||
|
|
||||||
|
const res = await api('/api/fans/groups', {{
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({{name, fan_ids: fanIds}})
|
||||||
|
}});
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
if (data.success) {{
|
||||||
|
log(`Group "${{name}}" saved`, 'success');
|
||||||
|
hideModal('group-modal');
|
||||||
|
fetchStatus();
|
||||||
|
}} else {{
|
||||||
|
log('Failed: ' + data.error, 'error');
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
function showFanSpeedModal(target, isGroup = false) {{
|
||||||
|
currentFanSpeedTarget = {{target, isGroup}};
|
||||||
|
document.getElementById('fan-speed-target').textContent = `Setting speed for: ${{target}}`;
|
||||||
|
document.getElementById('fan-speed-slider').value = 50;
|
||||||
|
document.getElementById('fan-speed-val').textContent = '50%';
|
||||||
|
showModal('fan-speed-modal');
|
||||||
|
}}
|
||||||
|
|
||||||
|
async function applyFanSpeed() {{
|
||||||
|
const speed = parseInt(document.getElementById('fan-speed-slider').value);
|
||||||
|
const {{target, isGroup}} = currentFanSpeedTarget;
|
||||||
|
|
||||||
|
const res = await api('/api/control/manual', {{
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({{speed, fan_id: isGroup ? null : target, group: isGroup ? target : null}})
|
||||||
|
}});
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
if (data.success) {{
|
||||||
|
log(`${{isGroup ? 'Group' : 'Fan'}} "${{target}}" set to ${{speed}}%`, 'success');
|
||||||
|
hideModal('fan-speed-modal');
|
||||||
|
fetchStatus();
|
||||||
|
}} else {{
|
||||||
|
log('Failed: ' + data.error, 'error');
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
async function setAllFans(speed) {{
|
||||||
|
const res = await api('/api/control/manual', {{
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({{speed, fan_id: '0xff'}})
|
||||||
|
}});
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
if (data.success) {{
|
||||||
|
log(`All fans set to ${{speed}}%`, 'success');
|
||||||
|
fetchStatus();
|
||||||
|
}} else {{
|
||||||
|
log('Failed: ' + data.error, 'error');
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
|
||||||
|
async function deleteGroup(name) {{
|
||||||
|
if (!confirm(`Delete group "${{name}}"?`)) return;
|
||||||
|
|
||||||
|
const res = await api('/api/fans/groups', {{
|
||||||
|
method: 'DELETE',
|
||||||
|
body: JSON.stringify({{name}})
|
||||||
|
}});
|
||||||
|
|
||||||
|
const data = await res.json();
|
||||||
|
if (data.success) {{
|
||||||
|
log(`Group "${{name}}" deleted`, 'success');
|
||||||
|
fetchStatus();
|
||||||
|
}} else {{
|
||||||
|
log('Failed: ' + data.error, 'error');
|
||||||
|
}}
|
||||||
}}
|
}}
|
||||||
|
|
||||||
// Save functions
|
// Save functions
|
||||||
|
|
@ -1037,6 +1245,15 @@ def get_html(theme="dark"):
|
||||||
setInterval(fetchStatus, 3000);
|
setInterval(fetchStatus, 3000);
|
||||||
fetchStatus();
|
fetchStatus();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<footer style="text-align:center;padding:20px;color:var(--text-secondary);font-size:0.85rem;border-top:1px solid var(--border);margin-top:20px;">
|
||||||
|
<div style="margin-bottom:10px;">
|
||||||
|
<a href="https://github.com/ImpulsiveFPS/IPMI-Controller/issues" target="_blank" style="color:var(--accent-primary);text-decoration:none;margin:0 10px;">🐛 Report Bug</a>
|
||||||
|
<a href="https://github.com/ImpulsiveFPS/IPMI-Controller" target="_blank" style="color:var(--accent-primary);text-decoration:none;margin:0 10px;">📁 GitHub Repo</a>
|
||||||
|
<a href="https://ko-fi.com/impulsivefps" target="_blank" style="color:var(--accent-primary);text-decoration:none;margin:0 10px;">☕ Support on Ko-fi</a>
|
||||||
|
</div>
|
||||||
|
<div>IPMI Controller v3.0.0 - Built by ImpulsiveFPS</div>
|
||||||
|
</footer>
|
||||||
</body>
|
</body>
|
||||||
</html>'''
|
</html>'''
|
||||||
|
|
||||||
|
|
@ -1320,6 +1537,20 @@ async def api_control_manual(req: ManualSpeedRequest, username: str = Depends(ge
|
||||||
if not service._init_controller():
|
if not service._init_controller():
|
||||||
return {"success": False, "error": "Not connected"}
|
return {"success": False, "error": "Not connected"}
|
||||||
|
|
||||||
|
# Handle group speed setting
|
||||||
|
if req.group:
|
||||||
|
groups = service.config.get('fan_groups', {})
|
||||||
|
if req.group not in groups:
|
||||||
|
return {"success": False, "error": f"Group '{req.group}' not found"}
|
||||||
|
|
||||||
|
fan_ids = groups[req.group].get('fan_ids', [])
|
||||||
|
success = True
|
||||||
|
for fan_id in fan_ids:
|
||||||
|
if not service.set_manual_speed(req.speed, fan_id):
|
||||||
|
success = False
|
||||||
|
return {"success": success}
|
||||||
|
|
||||||
|
# Handle individual fan or all fans
|
||||||
if service.set_manual_speed(req.speed, req.fan_id):
|
if service.set_manual_speed(req.speed, req.fan_id):
|
||||||
return {"success": True}
|
return {"success": True}
|
||||||
return {"success": False, "error": "Failed"}
|
return {"success": False, "error": "Failed"}
|
||||||
|
|
@ -1419,6 +1650,34 @@ async def api_stop_identify(username: str = Depends(get_current_user)):
|
||||||
service.stop_identify()
|
service.stop_identify()
|
||||||
return {"success": True}
|
return {"success": True}
|
||||||
|
|
||||||
|
# Fan Groups API
|
||||||
|
@app.post("/api/fans/groups")
|
||||||
|
async def api_save_group(data: dict, username: str = Depends(get_current_user)):
|
||||||
|
service = get_service(str(CONFIG_FILE))
|
||||||
|
name = data.get('name')
|
||||||
|
fan_ids = data.get('fan_ids', [])
|
||||||
|
|
||||||
|
if not name:
|
||||||
|
return {"success": False, "error": "Group name required"}
|
||||||
|
|
||||||
|
if 'fan_groups' not in service.config:
|
||||||
|
service.config['fan_groups'] = {}
|
||||||
|
|
||||||
|
service.config['fan_groups'][name] = {'fan_ids': fan_ids}
|
||||||
|
service._save_config()
|
||||||
|
return {"success": True}
|
||||||
|
|
||||||
|
@app.delete("/api/fans/groups")
|
||||||
|
async def api_delete_group(data: dict, username: str = Depends(get_current_user)):
|
||||||
|
service = get_service(str(CONFIG_FILE))
|
||||||
|
name = data.get('name')
|
||||||
|
|
||||||
|
if 'fan_groups' in service.config and name in service.config['fan_groups']:
|
||||||
|
del service.config['fan_groups'][name]
|
||||||
|
service._save_config()
|
||||||
|
return {"success": True}
|
||||||
|
return {"success": False, "error": "Group not found"}
|
||||||
|
|
||||||
# Public API (no auth required - for external integrations)
|
# Public API (no auth required - for external integrations)
|
||||||
@app.get("/api/public/status")
|
@app.get("/api/public/status")
|
||||||
async def api_public_status():
|
async def api_public_status():
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue