Improve temperature sensor display with grouped categories

This commit is contained in:
devmatrix 2026-02-20 22:48:01 +00:00
parent 8cf9957518
commit 25d24f07de
3 changed files with 469 additions and 38 deletions

View File

@ -113,7 +113,7 @@ class HTTPSensorClient:
return temps return temps
def _classify_sensor_name(self, name: str, chip: str) -> str: def _classify_sensor_name(self, name: str, chip: str) -> str:
"""Classify sensor location from name.""" """Classify sensor location from name with detailed categories."""
import re import re
name_lower = name.lower() name_lower = name.lower()
chip_lower = chip.lower() chip_lower = chip.lower()
@ -139,9 +139,19 @@ class HTTPSensorClient:
return "cpu" return "cpu"
elif "tdie" in name_lower or "tctl" in name_lower: elif "tdie" in name_lower or "tctl" in name_lower:
return "cpu" return "cpu"
elif "pcie" in name_lower or "nvme" in name_lower or "composite" in name_lower: elif "nvme" in name_lower or "composite" in name_lower:
return "nvme"
elif "raid" in name_lower or "megaraid" in name_lower:
return "raid"
elif "pcie" in name_lower:
return "pcie" return "pcie"
elif "loc1" in name_lower or "loc2" in name_lower: elif "inlet" in name_lower or "ambient" in name_lower or "room" in name_lower:
return "ambient"
elif "exhaust" in name_lower or "outlet" in name_lower:
return "exhaust"
elif "inlet" in name_lower:
return "inlet"
elif "loc1" in name_lower or "loc2" in name_lower or "chipset" in name_lower:
return "chipset" return "chipset"
return "other" return "other"

View File

@ -1,21 +1,16 @@
INFO: Started server process [103738] INFO: Started server process [105401]
INFO: Waiting for application startup. INFO: Waiting for application startup.
2026-02-20 22:29:23,172 - fan_controller - INFO - Loaded config from /home/devmatrix/projects/fan-controller-v2/data/config.json 2026-02-20 22:36:05,954 - fan_controller - INFO - Loaded config from /home/devmatrix/projects/fan-controller-v2/data/config.json
2026-02-20 22:29:23,173 - __main__ - INFO - Auto-starting fan control (enabled in config) 2026-02-20 22:36:05,955 - __main__ - INFO - Auto-starting fan control (enabled in config)
2026-02-20 22:29:23,328 - fan_controller - INFO - Connected to IPMI at 192.168.5.191 2026-02-20 22:36:06,109 - fan_controller - INFO - Connected to IPMI at 192.168.5.191
2026-02-20 22:29:23,329 - fan_controller - INFO - HTTP sensor client initialized for http://192.168.5.200:8888 2026-02-20 22:36:06,110 - fan_controller - INFO - HTTP sensor client initialized for http://192.168.5.200:8888
2026-02-20 22:29:23,330 - fan_controller - INFO - IPMI Controller service started 2026-02-20 22:36:06,111 - 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 22:29:23,495 - fan_controller - INFO - Manual fan control enabled 2026-02-20 22:36:06,301 - fan_controller - INFO - Manual fan control enabled
INFO: 192.168.5.30:54938 - "GET /api/status HTTP/1.1" 401 Unauthorized 2026-02-20 22:36:11,732 - fan_controller - INFO - Fan 0xff speed set to 14%
INFO: 192.168.5.30:54938 - "GET /login HTTP/1.1" 200 OK 2026-02-20 22:36:11,732 - fan_controller - INFO - All fans set to 14% (Temp 38.0°C)
2026-02-20 22:29:29,168 - fan_controller - INFO - Fan 0xff speed set to 14% INFO: 192.168.5.30:57657 - "GET / HTTP/1.1" 500 Internal Server Error
2026-02-20 22:29:29,168 - fan_controller - INFO - All fans set to 14% (Temp 38.0°C)
/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
self._sessions[token] = (username, datetime.utcnow() + timedelta(days=7))
INFO: 192.168.5.30:50571 - "POST /api/auth/login HTTP/1.1" 200 OK
INFO: 192.168.5.30:50571 - "GET / HTTP/1.1" 500 Internal Server Error
ERROR: Exception in ASGI application ERROR: Exception in ASGI application
Traceback (most recent call last): Traceback (most recent call last):
File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 419, in run_asgi File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 419, in run_asgi
@ -70,13 +65,8 @@ Traceback (most recent call last):
<style>body{padding-bottom:80px !important;}</style> <style>body{padding-bottom:80px !important;}</style>
^^^^^^^ ^^^^^^^
NameError: name 'padding' is not defined NameError: name 'padding' is not defined
INFO: 192.168.5.30:64908 - "GET /http%3A//192.168.5.210%3A3000/favicon.ico HTTP/1.1" 404 Not Found INFO: 192.168.5.30:65161 - "GET /favicon.ico HTTP/1.1" 200 OK
INFO: 192.168.5.30:64908 - "GET /login HTTP/1.1" 200 OK INFO: 192.168.5.30:65161 - "GET / HTTP/1.1" 500 Internal Server Error
INFO: 192.168.5.30:64908 - "GET /favicon.ico HTTP/1.1" 200 OK
/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
self._sessions[token] = (username, datetime.utcnow() + timedelta(days=7))
INFO: 192.168.5.30:52032 - "POST /api/auth/login HTTP/1.1" 200 OK
INFO: 192.168.5.30:52032 - "GET / HTTP/1.1" 500 Internal Server Error
ERROR: Exception in ASGI application ERROR: Exception in ASGI application
Traceback (most recent call last): Traceback (most recent call last):
File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 419, in run_asgi File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 419, in run_asgi
@ -131,4 +121,346 @@ Traceback (most recent call last):
<style>body{padding-bottom:80px !important;}</style> <style>body{padding-bottom:80px !important;}</style>
^^^^^^^ ^^^^^^^
NameError: name 'padding' is not defined NameError: name 'padding' is not defined
INFO: 192.168.5.30:51945 - "GET /http%3A//192.168.5.210%3A3000/favicon.ico HTTP/1.1" 404 Not Found INFO: 192.168.5.30:51526 - "GET /favicon.ico HTTP/1.1" 200 OK
INFO: 192.168.5.30:53588 - "GET / HTTP/1.1" 500 Internal Server Error
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 419, in run_asgi
result = await app( # type: ignore[func-returns-value]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
return await self.app(scope, receive, send)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__
await super().__call__(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/applications.py", line 123, in __call__
await self.middleware_stack(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 186, in __call__
raise exc
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 164, in __call__
await self.app(scope, receive, _send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 83, in __call__
await self.app(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
raise exc
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
await app(scope, receive, sender)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 762, in __call__
await self.middleware_stack(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 782, in app
await route.handle(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 297, in handle
await self.app(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 77, in app
await wrap_app_handling_exceptions(app, request)(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
raise exc
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
await app(scope, receive, sender)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 72, in app
response = await func(request)
^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 299, in app
raise e
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 294, in app
raw_response = await run_endpoint_function(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 191, in run_endpoint_function
return await dependant.call(**values)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/projects/fan-controller-v2/web_server.py", line 1592, in root
return HTMLResponse(content=get_html(theme))
^^^^^^^^^^^^^^^
File "/home/devmatrix/projects/fan-controller-v2/web_server.py", line 1424, in get_html
<style>body{padding-bottom:80px !important;}</style>
^^^^^^^
NameError: name 'padding' is not defined
INFO: 192.168.5.30:58112 - "GET /favicon.ico HTTP/1.1" 200 OK
INFO: 192.168.5.30:61736 - "GET / HTTP/1.1" 500 Internal Server Error
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 419, in run_asgi
result = await app( # type: ignore[func-returns-value]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
return await self.app(scope, receive, send)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__
await super().__call__(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/applications.py", line 123, in __call__
await self.middleware_stack(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 186, in __call__
raise exc
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 164, in __call__
await self.app(scope, receive, _send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 83, in __call__
await self.app(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
raise exc
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
await app(scope, receive, sender)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 762, in __call__
await self.middleware_stack(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 782, in app
await route.handle(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 297, in handle
await self.app(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 77, in app
await wrap_app_handling_exceptions(app, request)(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
raise exc
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
await app(scope, receive, sender)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 72, in app
response = await func(request)
^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 299, in app
raise e
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 294, in app
raw_response = await run_endpoint_function(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 191, in run_endpoint_function
return await dependant.call(**values)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/projects/fan-controller-v2/web_server.py", line 1592, in root
if not user_manager.is_setup_complete():
^^^^^^^^^^^^^
File "/home/devmatrix/projects/fan-controller-v2/web_server.py", line 1424, in get_html
<a href="https://github.com/ImpulsiveFPS/IPMI-Controller" target="_blank" style="color:var(--accent-primary);text-decoration:none;margin:0 10px;">📁 GitHub Repo</a>
^^^^^^^
NameError: name 'padding' is not defined
INFO: 192.168.5.30:64381 - "GET /favicon.ico HTTP/1.1" 200 OK
INFO: 192.168.5.30:64381 - "GET / HTTP/1.1" 500 Internal Server Error
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 419, in run_asgi
result = await app( # type: ignore[func-returns-value]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
return await self.app(scope, receive, send)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__
await super().__call__(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/applications.py", line 123, in __call__
await self.middleware_stack(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 186, in __call__
raise exc
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 164, in __call__
await self.app(scope, receive, _send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 83, in __call__
await self.app(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
raise exc
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
await app(scope, receive, sender)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 762, in __call__
await self.middleware_stack(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 782, in app
await route.handle(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 297, in handle
await self.app(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 77, in app
await wrap_app_handling_exceptions(app, request)(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
raise exc
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
await app(scope, receive, sender)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 72, in app
response = await func(request)
^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 299, in app
raise e
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 294, in app
raw_response = await run_endpoint_function(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 191, in run_endpoint_function
return await dependant.call(**values)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/projects/fan-controller-v2/web_server.py", line 1592, in root
if not user_manager.is_setup_complete():
^^^^^^^^^^^^^
File "/home/devmatrix/projects/fan-controller-v2/web_server.py", line 1424, in get_html
<a href="https://github.com/ImpulsiveFPS/IPMI-Controller" target="_blank" style="color:var(--accent-primary);text-decoration:none;margin:0 10px;">📁 GitHub Repo</a>
^^^^^^^
NameError: name 'padding' is not defined
INFO: 192.168.5.30:59631 - "GET / HTTP/1.1" 500 Internal Server Error
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 419, in run_asgi
result = await app( # type: ignore[func-returns-value]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
return await self.app(scope, receive, send)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__
await super().__call__(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/applications.py", line 123, in __call__
await self.middleware_stack(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 186, in __call__
raise exc
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 164, in __call__
await self.app(scope, receive, _send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 83, in __call__
await self.app(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
raise exc
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
await app(scope, receive, sender)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 762, in __call__
await self.middleware_stack(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 782, in app
await route.handle(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 297, in handle
await self.app(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 77, in app
await wrap_app_handling_exceptions(app, request)(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
raise exc
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
await app(scope, receive, sender)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 72, in app
response = await func(request)
^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 299, in app
raise e
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 294, in app
raw_response = await run_endpoint_function(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 191, in run_endpoint_function
return await dependant.call(**values)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/projects/fan-controller-v2/web_server.py", line 1592, in root
if not user_manager.is_setup_complete():
^^^^^^^^^^^^^
File "/home/devmatrix/projects/fan-controller-v2/web_server.py", line 1424, in get_html
<a href="https://github.com/ImpulsiveFPS/IPMI-Controller" target="_blank" style="color:var(--accent-primary);text-decoration:none;margin:0 10px;">📁 GitHub Repo</a>
^^^^^^^
NameError: name 'padding' is not defined
INFO: 192.168.5.30:56967 - "GET /favicon.ico HTTP/1.1" 200 OK
INFO: 192.168.5.30:56967 - "GET / HTTP/1.1" 500 Internal Server Error
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 419, in run_asgi
result = await app( # type: ignore[func-returns-value]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
return await self.app(scope, receive, send)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__
await super().__call__(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/applications.py", line 123, in __call__
await self.middleware_stack(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 186, in __call__
raise exc
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 164, in __call__
await self.app(scope, receive, _send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 83, in __call__
await self.app(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
raise exc
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
await app(scope, receive, sender)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 762, in __call__
await self.middleware_stack(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 782, in app
await route.handle(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 297, in handle
await self.app(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 77, in app
await wrap_app_handling_exceptions(app, request)(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
raise exc
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
await app(scope, receive, sender)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 72, in app
response = await func(request)
^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 299, in app
raise e
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 294, in app
raw_response = await run_endpoint_function(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 191, in run_endpoint_function
return await dependant.call(**values)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/projects/fan-controller-v2/web_server.py", line 1592, in root
if not user_manager.is_setup_complete():
^^^^^^^^^^^^^
File "/home/devmatrix/projects/fan-controller-v2/web_server.py", line 1424, in get_html
<a href="https://github.com/ImpulsiveFPS/IPMI-Controller" target="_blank" style="color:var(--accent-primary);text-decoration:none;margin:0 10px;">📁 GitHub Repo</a>
^^^^^^^
NameError: name 'padding' is not defined
INFO: 192.168.5.30:51136 - "GET /favicon.ico HTTP/1.1" 200 OK
INFO: 192.168.5.30:51136 - "GET / HTTP/1.1" 500 Internal Server Error
ERROR: Exception in ASGI application
Traceback (most recent call last):
File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/protocols/http/httptools_impl.py", line 419, in run_asgi
result = await app( # type: ignore[func-returns-value]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 84, in __call__
return await self.app(scope, receive, send)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__
await super().__call__(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/applications.py", line 123, in __call__
await self.middleware_stack(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 186, in __call__
raise exc
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/errors.py", line 164, in __call__
await self.app(scope, receive, _send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/cors.py", line 83, in __call__
await self.app(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 62, in __call__
await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
raise exc
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
await app(scope, receive, sender)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 762, in __call__
await self.middleware_stack(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 782, in app
await route.handle(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 297, in handle
await self.app(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 77, in app
await wrap_app_handling_exceptions(app, request)(scope, receive, send)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
raise exc
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
await app(scope, receive, sender)
File "/home/devmatrix/.local/lib/python3.12/site-packages/starlette/routing.py", line 72, in app
response = await func(request)
^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 299, in app
raise e
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 294, in app
raw_response = await run_endpoint_function(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/.local/lib/python3.12/site-packages/fastapi/routing.py", line 191, in run_endpoint_function
return await dependant.call(**values)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/devmatrix/projects/fan-controller-v2/web_server.py", line 1592, in root
if not user_manager.is_setup_complete():
^^^^^^^^^^^^^
File "/home/devmatrix/projects/fan-controller-v2/web_server.py", line 1424, in get_html
<a href="https://github.com/ImpulsiveFPS/IPMI-Controller" target="_blank" style="color:var(--accent-primary);text-decoration:none;margin:0 10px;">📁 GitHub Repo</a>
^^^^^^^
NameError: name 'padding' is not defined
2026-02-20 22:45:21,250 - fan_controller - INFO - Fan 0xff speed set to 15%
2026-02-20 22:45:21,250 - fan_controller - INFO - All fans set to 15% (Temp 40.0°C)
2026-02-20 22:45:36,965 - fan_controller - INFO - Fan 0xff speed set to 14%
2026-02-20 22:45:36,965 - fan_controller - INFO - All fans set to 14% (Temp 39.0°C)
2026-02-20 22:46:56,801 - fan_controller - INFO - Fan 0xff speed set to 15%
2026-02-20 22:46:56,801 - fan_controller - INFO - All fans set to 15% (Temp 40.0°C)
2026-02-20 22:47:12,899 - fan_controller - INFO - Fan 0xff speed set to 14%
2026-02-20 22:47:12,900 - fan_controller - INFO - All fans set to 14% (Temp 38.0°C)

View File

@ -541,8 +541,13 @@ def get_html(theme="dark"):
<!-- Temperatures --> <!-- Temperatures -->
<div class="card"> <div class="card">
<h2><img src="/icons/thermometer.svg" class="icon-svg" alt=""> Temperatures</h2> <h2><img src="/icons/thermometer.svg" class="icon-svg" alt=""> Temperatures</h2>
<div class="temp-grid" id="temp-grid"> <div id="temp-container">
<div class="temp-item"><span>Loading...</span></div> <div id="temp-cpu1" style="margin-bottom:15px;"></div>
<div id="temp-cpu2" style="margin-bottom:15px;"></div>
<div id="temp-nvme" style="margin-bottom:15px;"></div>
<div id="temp-raid" style="margin-bottom:15px;"></div>
<div id="temp-ambient" style="margin-bottom:15px;"></div>
<div id="temp-other"></div>
</div> </div>
</div> </div>
@ -858,17 +863,101 @@ def get_html(theme="dark"):
document.getElementById('val-sensors').textContent = temps.length; document.getElementById('val-sensors').textContent = temps.length;
// Temperature grid // Temperature display - grouped by category
const tempGrid = document.getElementById('temp-grid'); const temps = currentStatus.temperatures || [];
if (temps.length > 0) {{
tempGrid.innerHTML = temps.map(t => {{ // Group temperatures by location
const groups = {{
cpu1: [], cpu2: [], nvme: [], raid: [], ambient: [], exhaust: [], inlet: [], pcie: [], chipset: [], other: []
}};
temps.forEach(t => {{
const loc = t.location || 'other';
if (groups[loc]) groups[loc].push(t);
else groups.other.push(t);
}});
// Render CPU 1 Cores
const cpu1El = document.getElementById('temp-cpu1');
if (groups.cpu1.length > 0) {{
const cores = groups.cpu1.filter(t => t.name.toLowerCase().includes('core'));
const others = groups.cpu1.filter(t => !t.name.toLowerCase().includes('core'));
let html = '<h4 style="color:var(--accent-primary);margin-bottom:8px;font-size:0.9rem;">🖥️ CPU 1</h4><div class="temp-grid">';
cores.forEach((t, i) => {{
const cls = t.value > 70 ? 'high' : t.value > 50 ? 'medium' : 'low'; const cls = t.value > 70 ? 'high' : t.value > 50 ? 'medium' : 'low';
return `<div class="temp-item"> html += `<div class="temp-item"><span>Core ${{(i+1)}}</span><span class="temp-value ${{cls}}">${{t.value.toFixed(1)}}°C</span></div>`;
<span>${{t.name}}</span> }});
<span class="temp-value ${{cls}}">${{t.value.toFixed(1)}}°C</span> others.forEach(t => {{
</div>`; const cls = t.value > 70 ? 'high' : t.value > 50 ? 'medium' : 'low';
}}).join(''); const label = t.name.toLowerCase().includes('package') ? 'Package' : t.name;
}} html += `<div class="temp-item"><span>${{label}}</span><span class="temp-value ${{cls}}">${{t.value.toFixed(1)}}°C</span></div>`;
}});
cpu1El.innerHTML = html + '</div>';
}} else cpu1El.innerHTML = '';
// Render CPU 2 Cores
const cpu2El = document.getElementById('temp-cpu2');
if (groups.cpu2.length > 0) {{
const cores = groups.cpu2.filter(t => t.name.toLowerCase().includes('core'));
const others = groups.cpu2.filter(t => !t.name.toLowerCase().includes('core'));
let html = '<h4 style="color:var(--accent-primary);margin-bottom:8px;font-size:0.9rem;">🖥️ CPU 2</h4><div class="temp-grid">';
cores.forEach((t, i) => {{
const cls = t.value > 70 ? 'high' : t.value > 50 ? 'medium' : 'low';
html += `<div class="temp-item"><span>Core ${{(i+1)}}</span><span class="temp-value ${{cls}}">${{t.value.toFixed(1)}}°C</span></div>`;
}});
others.forEach(t => {{
const cls = t.value > 70 ? 'high' : t.value > 50 ? 'medium' : 'low';
const label = t.name.toLowerCase().includes('package') ? 'Package' : t.name;
html += `<div class="temp-item"><span>${{label}}</span><span class="temp-value ${{cls}}">${{t.value.toFixed(1)}}°C</span></div>`;
}});
cpu2El.innerHTML = html + '</div>';
}} else cpu2El.innerHTML = '';
// Render NVMe
const nvmeEl = document.getElementById('temp-nvme');
if (groups.nvme.length > 0) {{
let html = '<h4 style="color:var(--accent-primary);margin-bottom:8px;font-size:0.9rem;">💾 NVMe SSD</h4><div class="temp-grid">';
groups.nvme.forEach((t, i) => {{
const cls = t.value > 70 ? 'high' : t.value > 50 ? 'medium' : 'low';
html += `<div class="temp-item"><span>NVMe ${{(i+1)}}</span><span class="temp-value ${{cls}}">${{t.value.toFixed(1)}}°C</span></div>`;
}});
nvmeEl.innerHTML = html + '</div>';
}} else nvmeEl.innerHTML = '';
// Render RAID
const raidEl = document.getElementById('temp-raid');
if (groups.raid.length > 0) {{
let html = '<h4 style="color:var(--accent-primary);margin-bottom:8px;font-size:0.9rem;">🔒 RAID Controller</h4><div class="temp-grid">';
groups.raid.forEach((t, i) => {{
const cls = t.value > 70 ? 'high' : t.value > 50 ? 'medium' : 'low';
html += `<div class="temp-item"><span>Controller ${{(i+1)}}</span><span class="temp-value ${{cls}}">${{t.value.toFixed(1)}}°C</span></div>`;
}});
raidEl.innerHTML = html + '</div>';
}} else raidEl.innerHTML = '';
// Render Ambient
const ambientEl = document.getElementById('temp-ambient');
if (groups.ambient.length > 0 || groups.exhaust.length > 0 || groups.inlet.length > 0) {{
let html = '<h4 style="color:var(--accent-primary);margin-bottom:8px;font-size:0.9rem;">🌡️ Ambient / System</h4><div class="temp-grid">';
[...groups.ambient, ...groups.exhaust, ...groups.inlet].forEach(t => {{
const cls = t.value > 40 ? 'high' : 'low';
const label = t.location === 'exhaust' ? 'Exhaust' : t.location === 'inlet' ? 'Inlet' : 'Ambient';
html += `<div class="temp-item"><span>${{label}}</span><span class="temp-value ${{cls}}">${{t.value.toFixed(1)}}°C</span></div>`;
}});
ambientEl.innerHTML = html + '</div>';
}} else ambientEl.innerHTML = '';
// Render Others
const otherEl = document.getElementById('temp-other');
const others = [...groups.pcie, ...groups.chipset, ...groups.other];
if (others.length > 0) {{
let html = '<h4 style="color:var(--accent-primary);margin-bottom:8px;font-size:0.9rem;">📊 Other Sensors</h4><div class="temp-grid">';
others.forEach(t => {{
const cls = t.value > 70 ? 'high' : t.value > 50 ? 'medium' : 'low';
html += `<div class="temp-item"><span>${{t.name}}</span><span class="temp-value ${{cls}}">${{t.value.toFixed(1)}}°C</span></div>`;
}});
otherEl.innerHTML = html + '</div>';
}} else otherEl.innerHTML = '';
// Fan grid // Fan grid
const fans = currentStatus.fans || []; const fans = currentStatus.fans || [];