mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-01-22 20:18:30 +03:00
Refactor temperature reporting for detectors and implement Hailo temp reading (#21395)
* Add Hailo temperature retrieval * Refactor `get_hailo_temps()` to use ctxmanager * Show Hailo temps in system UI * Move hailo_platform import to get_hailo_temps * Refactor temperatures calculations to use within detector block * Adjust webUI to handle new location --------- Co-authored-by: tigattack <10629864+tigattack@users.noreply.github.com>
This commit is contained in:
parent
f9e06bb7b7
commit
b8bc98a423
@ -22,6 +22,7 @@ from frigate.util.services import (
|
|||||||
get_bandwidth_stats,
|
get_bandwidth_stats,
|
||||||
get_cpu_stats,
|
get_cpu_stats,
|
||||||
get_fs_type,
|
get_fs_type,
|
||||||
|
get_hailo_temps,
|
||||||
get_intel_gpu_stats,
|
get_intel_gpu_stats,
|
||||||
get_jetson_stats,
|
get_jetson_stats,
|
||||||
get_nvidia_gpu_stats,
|
get_nvidia_gpu_stats,
|
||||||
@ -91,9 +92,76 @@ def get_temperatures() -> dict[str, float]:
|
|||||||
if temp is not None:
|
if temp is not None:
|
||||||
temps[apex] = temp
|
temps[apex] = temp
|
||||||
|
|
||||||
|
# Get temperatures for Hailo devices
|
||||||
|
temps.update(get_hailo_temps())
|
||||||
|
|
||||||
return temps
|
return temps
|
||||||
|
|
||||||
|
|
||||||
|
def get_detector_temperature(
|
||||||
|
detector_type: str,
|
||||||
|
detector_index_by_type: dict[str, int],
|
||||||
|
) -> Optional[float]:
|
||||||
|
"""Get temperature for a specific detector based on its type."""
|
||||||
|
if detector_type == "edgetpu":
|
||||||
|
# Get temperatures for all attached Corals
|
||||||
|
base = "/sys/class/apex/"
|
||||||
|
if os.path.isdir(base):
|
||||||
|
apex_devices = sorted(os.listdir(base))
|
||||||
|
index = detector_index_by_type.get("edgetpu", 0)
|
||||||
|
if index < len(apex_devices):
|
||||||
|
apex_name = apex_devices[index]
|
||||||
|
temp = read_temperature(os.path.join(base, apex_name, "temp"))
|
||||||
|
if temp is not None:
|
||||||
|
return temp
|
||||||
|
elif detector_type == "hailo8l":
|
||||||
|
# Get temperatures for Hailo devices
|
||||||
|
hailo_temps = get_hailo_temps()
|
||||||
|
if hailo_temps:
|
||||||
|
hailo_device_names = sorted(hailo_temps.keys())
|
||||||
|
index = detector_index_by_type.get("hailo8l", 0)
|
||||||
|
if index < len(hailo_device_names):
|
||||||
|
device_name = hailo_device_names[index]
|
||||||
|
return hailo_temps[device_name]
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_detector_stats(
|
||||||
|
stats_tracking: StatsTrackingTypes,
|
||||||
|
) -> dict[str, dict[str, Any]]:
|
||||||
|
"""Get stats for all detectors, including temperatures based on detector type."""
|
||||||
|
detector_stats: dict[str, dict[str, Any]] = {}
|
||||||
|
detector_type_indices: dict[str, int] = {}
|
||||||
|
|
||||||
|
for name, detector in stats_tracking["detectors"].items():
|
||||||
|
pid = detector.detect_process.pid if detector.detect_process else None
|
||||||
|
detector_type = detector.detector_config.type
|
||||||
|
|
||||||
|
# Keep track of the index for each detector type to match temperatures correctly
|
||||||
|
current_index = detector_type_indices.get(detector_type, 0)
|
||||||
|
detector_type_indices[detector_type] = current_index + 1
|
||||||
|
|
||||||
|
detector_stat = {
|
||||||
|
"inference_speed": round(detector.avg_inference_speed.value * 1000, 2), # type: ignore[attr-defined]
|
||||||
|
# issue https://github.com/python/typeshed/issues/8799
|
||||||
|
# from mypy 0.981 onwards
|
||||||
|
"detection_start": detector.detection_start.value, # type: ignore[attr-defined]
|
||||||
|
# issue https://github.com/python/typeshed/issues/8799
|
||||||
|
# from mypy 0.981 onwards
|
||||||
|
"pid": pid,
|
||||||
|
}
|
||||||
|
|
||||||
|
temp = get_detector_temperature(detector_type, {detector_type: current_index})
|
||||||
|
|
||||||
|
if temp is not None:
|
||||||
|
detector_stat["temperature"] = round(temp, 1)
|
||||||
|
|
||||||
|
detector_stats[name] = detector_stat
|
||||||
|
|
||||||
|
return detector_stats
|
||||||
|
|
||||||
|
|
||||||
def get_processing_stats(
|
def get_processing_stats(
|
||||||
config: FrigateConfig, stats: dict[str, str], hwaccel_errors: list[str]
|
config: FrigateConfig, stats: dict[str, str], hwaccel_errors: list[str]
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -319,18 +387,7 @@ def stats_snapshot(
|
|||||||
**connection_quality,
|
**connection_quality,
|
||||||
}
|
}
|
||||||
|
|
||||||
stats["detectors"] = {}
|
stats["detectors"] = get_detector_stats(stats_tracking)
|
||||||
for name, detector in stats_tracking["detectors"].items():
|
|
||||||
pid = detector.detect_process.pid if detector.detect_process else None
|
|
||||||
stats["detectors"][name] = {
|
|
||||||
"inference_speed": round(detector.avg_inference_speed.value * 1000, 2), # type: ignore[attr-defined]
|
|
||||||
# issue https://github.com/python/typeshed/issues/8799
|
|
||||||
# from mypy 0.981 onwards
|
|
||||||
"detection_start": detector.detection_start.value, # type: ignore[attr-defined]
|
|
||||||
# issue https://github.com/python/typeshed/issues/8799
|
|
||||||
# from mypy 0.981 onwards
|
|
||||||
"pid": pid,
|
|
||||||
}
|
|
||||||
stats["camera_fps"] = round(total_camera_fps, 2)
|
stats["camera_fps"] = round(total_camera_fps, 2)
|
||||||
stats["process_fps"] = round(total_process_fps, 2)
|
stats["process_fps"] = round(total_process_fps, 2)
|
||||||
stats["skipped_fps"] = round(total_skipped_fps, 2)
|
stats["skipped_fps"] = round(total_skipped_fps, 2)
|
||||||
@ -416,7 +473,6 @@ def stats_snapshot(
|
|||||||
"version": VERSION,
|
"version": VERSION,
|
||||||
"latest_version": stats_tracking["latest_frigate_version"],
|
"latest_version": stats_tracking["latest_frigate_version"],
|
||||||
"storage": {},
|
"storage": {},
|
||||||
"temperatures": get_temperatures(),
|
|
||||||
"last_updated": int(time.time()),
|
"last_updated": int(time.time()),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -549,6 +549,53 @@ def get_jetson_stats() -> Optional[dict[int, dict]]:
|
|||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def get_hailo_temps() -> dict[str, float]:
|
||||||
|
"""Get temperatures for Hailo devices."""
|
||||||
|
try:
|
||||||
|
from hailo_platform import Device
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
temps = {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
device_ids = Device.scan()
|
||||||
|
for i, device_id in enumerate(device_ids):
|
||||||
|
try:
|
||||||
|
with Device(device_id) as device:
|
||||||
|
temp_info = device.control.get_chip_temperature()
|
||||||
|
|
||||||
|
# Get board name and normalise it
|
||||||
|
identity = device.control.identify()
|
||||||
|
board_name = None
|
||||||
|
for line in str(identity).split("\n"):
|
||||||
|
if line.startswith("Board Name:"):
|
||||||
|
board_name = (
|
||||||
|
line.split(":", 1)[1].strip().lower().replace("-", "")
|
||||||
|
)
|
||||||
|
break
|
||||||
|
|
||||||
|
if not board_name:
|
||||||
|
board_name = f"hailo{i}"
|
||||||
|
|
||||||
|
# Use indexed name if multiple devices, otherwise just the board name
|
||||||
|
device_name = (
|
||||||
|
f"{board_name}-{i}" if len(device_ids) > 1 else board_name
|
||||||
|
)
|
||||||
|
|
||||||
|
# ts1_temperature is also available, but appeared to be the same as ts0 in testing.
|
||||||
|
temps[device_name] = round(temp_info.ts0_temperature, 1)
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(
|
||||||
|
f"Failed to get temperature for Hailo device {device_id}: {e}"
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f"Failed to scan for Hailo devices: {e}")
|
||||||
|
|
||||||
|
return temps
|
||||||
|
|
||||||
|
|
||||||
def ffprobe_stream(ffmpeg, path: str, detailed: bool = False) -> sp.CompletedProcess:
|
def ffprobe_stream(ffmpeg, path: str, detailed: bool = False) -> sp.CompletedProcess:
|
||||||
"""Run ffprobe on stream."""
|
"""Run ffprobe on stream."""
|
||||||
clean_path = escape_special_characters(path)
|
clean_path = escape_special_characters(path)
|
||||||
|
|||||||
@ -41,6 +41,7 @@ export type DetectorStats = {
|
|||||||
detection_start: number;
|
detection_start: number;
|
||||||
inference_speed: number;
|
inference_speed: number;
|
||||||
pid: number;
|
pid: number;
|
||||||
|
temperature?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EmbeddingsStats = {
|
export type EmbeddingsStats = {
|
||||||
@ -72,7 +73,6 @@ export type GpuInfo = "vainfo" | "nvinfo";
|
|||||||
export type ServiceStats = {
|
export type ServiceStats = {
|
||||||
last_updated: number;
|
last_updated: number;
|
||||||
storage: { [path: string]: StorageStats };
|
storage: { [path: string]: StorageStats };
|
||||||
temperatures: { [apex: string]: number };
|
|
||||||
uptime: number;
|
uptime: number;
|
||||||
latest_version: string;
|
latest_version: string;
|
||||||
version: string;
|
version: string;
|
||||||
|
|||||||
@ -127,13 +127,6 @@ export default function GeneralMetrics({
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
|
||||||
statsHistory.length > 0 &&
|
|
||||||
Object.keys(statsHistory[0].service.temperatures).length == 0
|
|
||||||
) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const series: {
|
const series: {
|
||||||
[key: string]: { name: string; data: { x: number; y: number }[] };
|
[key: string]: { name: string; data: { x: number; y: number }[] };
|
||||||
} = {};
|
} = {};
|
||||||
@ -143,22 +136,22 @@ export default function GeneralMetrics({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object.entries(stats.detectors).forEach(([key], cIdx) => {
|
Object.entries(stats.detectors).forEach(([key, detectorStats]) => {
|
||||||
if (!key.includes("coral")) {
|
if (detectorStats.temperature === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cIdx <= Object.keys(stats.service.temperatures).length) {
|
if (!(key in series)) {
|
||||||
if (!(key in series)) {
|
series[key] = {
|
||||||
series[key] = {
|
name: key,
|
||||||
name: key,
|
data: [],
|
||||||
data: [],
|
};
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const temp = Object.values(stats.service.temperatures)[cIdx];
|
|
||||||
series[key].data.push({ x: statsIdx + 1, y: Math.round(temp) });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
series[key].data.push({
|
||||||
|
x: statsIdx + 1,
|
||||||
|
y: Math.round(detectorStats.temperature),
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user