diff --git a/.github/ISSUE_TEMPLATE/edgetpu_support_request.yml b/.github/ISSUE_TEMPLATE/detector_support_request.yml similarity index 92% rename from .github/ISSUE_TEMPLATE/edgetpu_support_request.yml rename to .github/ISSUE_TEMPLATE/detector_support_request.yml index aad464edf..3f5b34935 100644 --- a/.github/ISSUE_TEMPLATE/edgetpu_support_request.yml +++ b/.github/ISSUE_TEMPLATE/detector_support_request.yml @@ -1,6 +1,6 @@ -name: EdgeTpu Support Request -description: Support for setting up EdgeTPU in Frigate -title: "[EdgeTPU Support]: " +name: Detector Support Request +description: Support for setting up object detector in Frigate (Coral, OpenVINO, TensorRT, etc.) +title: "[Detector Support]: " labels: ["support", "triage"] assignees: [] body: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 282239aba..8a06ef0e6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,11 @@ jobs: runs-on: ubuntu-latest name: Image Build steps: + - name: Remove unnecessary files + run: | + sudo rm -rf /usr/share/dotnet + sudo rm -rf /usr/local/lib/android + sudo rm -rf /opt/ghc - id: lowercaseRepo uses: ASzc/change-string-case-action@v5 with: diff --git a/docker/rootfs/usr/local/go2rtc/create_config.py b/docker/rootfs/usr/local/go2rtc/create_config.py index d034e044b..d201eb381 100644 --- a/docker/rootfs/usr/local/go2rtc/create_config.py +++ b/docker/rootfs/usr/local/go2rtc/create_config.py @@ -30,6 +30,12 @@ elif config_file.endswith(".json"): go2rtc_config: dict[str, any] = config.get("go2rtc", {}) +# Need to enable CORS for go2rtc so the frigate integration / card work automatically +if go2rtc_config.get("api") is None: + go2rtc_config["api"] = {"origin": "*"} +elif go2rtc_config["api"].get("origin") is None: + go2rtc_config["api"]["origin"] = "*" + # we want to ensure that logs are easy to read if go2rtc_config.get("log") is None: go2rtc_config["log"] = {"format": "text"} diff --git a/docs/docs/frigate/installation.md b/docs/docs/frigate/installation.md index f5afc37c9..03481cfd7 100644 --- a/docs/docs/frigate/installation.md +++ b/docs/docs/frigate/installation.md @@ -163,7 +163,10 @@ docker run -d \ :::caution -Due to limitations in Home Assistant Operating System, utilizing external storage for recordings or snapshots requires [modifying udev rules manually](https://community.home-assistant.io/t/solved-mount-usb-drive-in-hassio-to-be-used-on-the-media-folder-with-udev-customization/258406/46). +There are important limitations in Home Assistant Operating System to be aware of: +- Utilizing external storage for recordings or snapshots requires [modifying udev rules manually](https://community.home-assistant.io/t/solved-mount-usb-drive-in-hassio-to-be-used-on-the-media-folder-with-udev-customization/258406/46). +- AMD GPUs are not supported because HA OS does not include the mesa driver. +- Nvidia GPUs are not supported because addons do not support the nvidia runtime. ::: @@ -194,6 +197,13 @@ There are several versions of the addon available: ## Home Assistant Supervised +:::caution + +There are important limitations in Home Assistant Supervised to be aware of: +- Nvidia GPUs are not supported because addons do not support the nvidia runtime. + +::: + :::tip If possible, it is recommended to run Frigate standalone in Docker and use [Frigate's Proxy Addon](https://github.com/blakeblackshear/frigate-hass-addons/blob/main/frigate_proxy/README.md). diff --git a/frigate/detectors/plugins/cpu_tfl.py b/frigate/detectors/plugins/cpu_tfl.py index 9e24cb1f4..fb9cbbfae 100644 --- a/frigate/detectors/plugins/cpu_tfl.py +++ b/frigate/detectors/plugins/cpu_tfl.py @@ -5,7 +5,11 @@ from frigate.detectors.detection_api import DetectionApi from frigate.detectors.detector_config import BaseDetectorConfig from typing import Literal from pydantic import Extra, Field -import tflite_runtime.interpreter as tflite + +try: + from tflite_runtime.interpreter import Interpreter +except ModuleNotFoundError: + from tensorflow.lite.python.interpreter import Interpreter logger = logging.getLogger(__name__) @@ -22,7 +26,7 @@ class CpuTfl(DetectionApi): type_key = DETECTOR_KEY def __init__(self, detector_config: CpuDetectorConfig): - self.interpreter = tflite.Interpreter( + self.interpreter = Interpreter( model_path=detector_config.model.path or "/cpu_model.tflite", num_threads=detector_config.num_threads or 3, ) diff --git a/frigate/detectors/plugins/edgetpu_tfl.py b/frigate/detectors/plugins/edgetpu_tfl.py index 024e6574b..840d41f66 100644 --- a/frigate/detectors/plugins/edgetpu_tfl.py +++ b/frigate/detectors/plugins/edgetpu_tfl.py @@ -5,8 +5,11 @@ from frigate.detectors.detection_api import DetectionApi from frigate.detectors.detector_config import BaseDetectorConfig from typing import Literal from pydantic import Extra, Field -import tflite_runtime.interpreter as tflite -from tflite_runtime.interpreter import load_delegate + +try: + from tflite_runtime.interpreter import Interpreter, load_delegate +except ModuleNotFoundError: + from tensorflow.lite.python.interpreter import Interpreter, load_delegate logger = logging.getLogger(__name__) @@ -33,7 +36,7 @@ class EdgeTpuTfl(DetectionApi): logger.info(f"Attempting to load TPU as {device_config['device']}") edge_tpu_delegate = load_delegate("libedgetpu.so.1.0", device_config) logger.info("TPU found") - self.interpreter = tflite.Interpreter( + self.interpreter = Interpreter( model_path=detector_config.model.path or "/edgetpu_model.tflite", experimental_delegates=[edge_tpu_delegate], ) diff --git a/frigate/http.py b/frigate/http.py index 1649ab55e..f59e341df 100644 --- a/frigate/http.py +++ b/frigate/http.py @@ -111,6 +111,7 @@ def events_summary(): Event.select( Event.camera, Event.label, + Event.sub_label, fn.strftime( "%Y-%m-%d", fn.datetime( @@ -124,6 +125,7 @@ def events_summary(): .group_by( Event.camera, Event.label, + Event.sub_label, fn.strftime( "%Y-%m-%d", fn.datetime( @@ -322,7 +324,9 @@ def get_sub_labels(): sub_labels.remove(None) if split_joined: - for label in sub_labels: + original_labels = sub_labels.copy() + + for label in original_labels: if "," in label: sub_labels.remove(label) parts = label.split(",") @@ -331,6 +335,7 @@ def get_sub_labels(): if not (part.strip()) in sub_labels: sub_labels.append(part.strip()) + sub_labels.sort() return jsonify(sub_labels) @@ -638,7 +643,13 @@ def events(): sub_label_clauses.append((Event.sub_label.is_null())) for label in filtered_sub_labels: - sub_label_clauses.append((Event.sub_label.cast("text") % f"*{label}*")) + sub_label_clauses.append( + (Event.sub_label.cast("text") == label) + ) # include exact matches + + # include this label when part of a list + sub_label_clauses.append((Event.sub_label.cast("text") % f"*{label},*")) + sub_label_clauses.append((Event.sub_label.cast("text") % f"*, {label}*")) sub_label_clause = reduce(operator.or_, sub_label_clauses) clauses.append((sub_label_clause)) diff --git a/web/src/components/MultiSelect.jsx b/web/src/components/MultiSelect.jsx index 99412e938..226316966 100644 --- a/web/src/components/MultiSelect.jsx +++ b/web/src/components/MultiSelect.jsx @@ -13,9 +13,11 @@ export default function MultiSelect({ className, title, options, selection, onTo const [state, setState] = useState({ showMenu: false, }); - + const isOptionSelected = (item) => { return selection == "all" || selection.split(',').indexOf(item) > -1; } - + + const menuHeight = Math.round(window.innerHeight * 0.55); + return (
{state.showMenu ? ( - setState({ showMenu: false })}> + setState({ showMenu: false })}>
{title}