feat(axelera): report Metis board temperature in detector stats

Use the SDK's axcmd --board-temp through the board controller, which is
safe to call while an inference stream is active. Matches the hailo8l
pattern of exposing temperature via detectors.*.temperature.
This commit is contained in:
patrykorwat 2026-08-19 11:35:26 +00:00
parent ed1329c8de
commit f1eef0da66
3 changed files with 61 additions and 2 deletions

View File

@ -574,16 +574,26 @@ The operator build is architecture-specific. Build and validate the image on the
:::
Then pass the Metis device into the container. Add the following lines to your `docker-compose.yml`:
Then pass the Metis device and the GPU/dma-buf nodes into the container. Add the following lines to your `docker-compose.yml`:
```yaml
devices:
- /dev/metis-0-1-0
- /dev/dma_heap/system:/dev/dma_heap/system
- /dev/dri/renderD128:/dev/dri/renderD128 # Intel/AMD GPU render node (OpenCL)
```
The SDK needs the dma-buf exporter for its shared-memory pool (`No dmabuf driver found` at startup means it is missing). The GPU render node is required for the SDK to detect OpenCL and use the GPU hardware path (`hardware_caps.opencl`); without it the SDK falls back to software decoding. Which nodes exist depends on the host (Intel iGPU render nodes are numbered, e.g. `renderD128`; AMD uses `renderD129`).
Metis device node names depend on the driver version (for example `/dev/metis-0-1-0` or `/dev/metis-0:1:0`); list the nodes under `/dev/metis*` after installing the driver and pass the one that appears for your card.
If you are using `docker run`, add this option to your command: `--device /dev/metis-0-1-0`
If you are using `docker run`, add these options to your command:
```bash
--device /dev/metis-0-1-0 \
--device /dev/dma_heap/system:/dev/dma_heap/system \
--device /dev/dri/renderD128:/dev/dri/renderD128
```
#### Configuration

View File

@ -21,6 +21,7 @@ from frigate.util.services import (
calculate_shm_requirements,
get_amd_gpu_stats,
get_axcl_npu_stats,
get_axelera_board_temp,
get_bandwidth_stats,
get_cpu_stats,
get_fs_type,
@ -132,6 +133,10 @@ def get_detector_temperature(
# Rockchip temperatures are handled by the GPU / NPU stats
# as there are not detector specific temperatures
pass
elif detector_type == "axelera":
# Axelera Metis temperature is read from the board controller
# through the SDK's axcmd tool
return get_axelera_board_temp()
return None

View File

@ -800,6 +800,50 @@ def get_axcl_npu_stats() -> dict[str, str | float] | None:
return None
def get_axelera_board_temp() -> float | None:
"""Get the Axelera Metis board temperature through the SDK's axcmd tool.
The read goes through the board controller and does not open an inference
stream, so it is safe to call while a detector is running.
"""
axcmd_path = None
for candidate in (
shutil.which("axcmd"),
"/usr/local/bin/axcmd",
"/opt/axelera/runtime-1.8.0-1/bin/axcmd",
):
if candidate and os.path.exists(candidate):
axcmd_path = candidate
break
if axcmd_path is None:
return None
try:
result = sp.run(
[axcmd_path, "--board-temp"],
capture_output=True,
text=True,
timeout=5,
)
except (OSError, sp.TimeoutExpired):
return None
if result.returncode != 0:
return None
match = re.search(r"=\s*([\d.]+)", result.stdout)
if match is None:
return None
try:
return round(float(match.group(1)), 1)
except ValueError:
return None
def try_get_info(f, h, default="N/A", sensor=None):
try:
if h: