diff --git a/frigate/comms/mqtt.py b/frigate/comms/mqtt.py index eaaadfe9f..ca9d03da7 100644 --- a/frigate/comms/mqtt.py +++ b/frigate/comms/mqtt.py @@ -17,7 +17,8 @@ class MqttClient(Communicator): # type: ignore[misc] def __init__(self, config: FrigateConfig) -> None: self.config = config self.mqtt_config = config.mqtt - self.connected: bool = False + self.connected = False + self.started = False def subscribe(self, receiver: Callable) -> None: """Wrapper for allowing dispatcher to subscribe.""" @@ -27,7 +28,8 @@ class MqttClient(Communicator): # type: ignore[misc] def publish(self, topic: str, payload: Any, retain: bool = False) -> None: """Wrapper for publishing when client is in valid state.""" if not self.connected: - logger.error(f"Unable to publish to {topic}: client is not connected") + if self.started: + logger.error(f"Unable to publish to {topic}: client is not connected") return self.client.publish( @@ -197,14 +199,6 @@ class MqttClient(Communicator): # type: ignore[misc] for name in self.config.cameras.keys(): for callback in callback_types: - # We need to pre-clear existing set topics because in previous - # versions the webUI retained on the /set topic but this is - # no longer the case. - self.client.publish( - f"{self.mqtt_config.topic_prefix}/{name}/{callback}/set", - None, - retain=True, - ) self.client.message_callback_add( f"{self.mqtt_config.topic_prefix}/{name}/{callback}/set", self.on_mqtt_command, @@ -253,6 +247,7 @@ class MqttClient(Communicator): # type: ignore[misc] # with connect_async, retries are handled automatically self.client.connect_async(self.mqtt_config.host, self.mqtt_config.port, 60) self.client.loop_start() + self.started = True except Exception as e: logger.error(f"Unable to connect to MQTT server: {e}") return diff --git a/frigate/review/maintainer.py b/frigate/review/maintainer.py index d87e1d33c..38ed59294 100644 --- a/frigate/review/maintainer.py +++ b/frigate/review/maintainer.py @@ -347,7 +347,7 @@ class ReviewSegmentMaintainer(threading.Thread): if len(active_objects) > 0: detections: dict[str, str] = {} - sub_labels = dict[str, str] = {} + sub_labels: dict[str, str] = {} zones: list[str] = [] severity = None diff --git a/frigate/util/services.py b/frigate/util/services.py index 7ff46f039..a71729263 100644 --- a/frigate/util/services.py +++ b/frigate/util/services.py @@ -257,6 +257,40 @@ def get_amd_gpu_stats() -> dict[str, str]: def get_intel_gpu_stats() -> dict[str, str]: """Get stats using intel_gpu_top.""" + + def get_stats_manually(output: str) -> dict[str, str]: + """Find global stats via regex when json fails to parse.""" + reading = "".join(output) + results: dict[str, str] = {} + + # render is used for qsv + render = [] + for result in re.findall(r'"Render/3D/0":{[a-z":\d.,%]+}', reading): + packet = json.loads(result[14:]) + single = packet.get("busy", 0.0) + render.append(float(single)) + + if render: + render_avg = sum(render) / len(render) + else: + render_avg = 1 + + # video is used for vaapi + video = [] + for result in re.findall(r'"Video/\d":{[a-z":\d.,%]+}', reading): + packet = json.loads(result[10:]) + single = packet.get("busy", 0.0) + video.append(float(single)) + + if video: + video_avg = sum(video) / len(video) + else: + video_avg = 1 + + results["gpu"] = f"{round((video_avg + render_avg) / 2, 2)}%" + results["mem"] = "-%" + return results + intel_gpu_top_command = [ "timeout", "0.5s", @@ -284,22 +318,7 @@ def get_intel_gpu_stats() -> dict[str, str]: try: data = json.loads(f"[{output}]") except json.JSONDecodeError: - data = None - - # json is incomplete, remove characters until we get to valid json - while True: - while output and output[-1] != "}": - output = output[:-1] - - if not output: - return {"gpu": "", "mem": ""} - - try: - data = json.loads(f"[{output}]") - break - except json.JSONDecodeError: - output = output[:-1] - continue + return get_stats_manually(output) results: dict[str, str] = {} render = {"global": []}