Merge remote-tracking branch 'refs/remotes/upstream/dev' into dev

This commit is contained in:
kensand 2024-08-07 21:16:46 -04:00
commit 31bec12758
9 changed files with 183 additions and 175 deletions

View File

@ -80,6 +80,14 @@ model:
input_pixel_format: "bgr"
```
#### `labelmap`
:::warning
If the labelmap is customized then the labels used for alerts will need to be adjusted as well. See [alert labels](../configuration/review.md#restricting-alerts-to-specific-labels) for more info.
:::
The labelmap can be customized to your needs. A common reason to do this is to combine multiple object types that are easily confused when you don't need to be as granular such as car/truck. By default, truck is renamed to car because they are often confused. You cannot add new object types, but you can change the names of existing objects in the model.
```yaml

View File

@ -111,6 +111,6 @@ camera_groups:
cameras:
- driveway_cam
- garage_cam
icon: car
icon: LuCar
order: 0
```

View File

@ -81,6 +81,15 @@ detectors:
device: ""
```
### Single PCIE/M.2 Coral
```yaml
detectors:
coral:
type: edgetpu
device: pci
```
### Multiple PCIE/M.2 Corals
```yaml
@ -136,23 +145,7 @@ model:
#### YOLOX
This detector also supports YOLOX. Frigate does not come with any YOLOX models preloaded, so you will need to supply your own models. This detector has been verified to work with the [yolox_tiny](https://github.com/openvinotoolkit/open_model_zoo/tree/master/models/public/yolox-tiny) model from Intel's Open Model Zoo. You can follow [these instructions](https://github.com/openvinotoolkit/open_model_zoo/tree/master/models/public/yolox-tiny#download-a-model-and-convert-it-into-openvino-ir-format) to retrieve the OpenVINO-compatible `yolox_tiny` model. Make sure that the model input dimensions match the `width` and `height` parameters, and `model_type` is set accordingly. See [Full Configuration Reference](/configuration/reference.md) for a list of possible `model_type` options. Below is an example of how `yolox_tiny` can be used in Frigate:
```yaml
detectors:
ov:
type: openvino
device: GPU
model:
width: 416
height: 416
input_tensor: nchw
input_pixel_format: bgr
model_type: yolox
path: /path/to/yolox_tiny.xml
labelmap_path: /path/to/coco_80cl.txt
```
This detector also supports YOLOX. Frigate does not come with any YOLOX models preloaded, so you will need to supply your own models.
#### YOLO-NAS

View File

@ -5,6 +5,12 @@ title: Installation
Frigate is a Docker container that can be run on any Docker host including as a [HassOS Addon](https://www.home-assistant.io/addons/). Note that a Home Assistant Addon is **not** the same thing as the integration. The [integration](/integrations/home-assistant) is required to integrate Frigate into Home Assistant.
:::tip
If you already have Frigate installed as a Home Assistant addon, check out the [getting started guide](../guides/getting_started#configuring-frigate) to configure Frigate.
:::
## Dependencies
**MQTT broker (optional)** - An MQTT broker is optional with Frigate, but is required for the Home Assistant integration. If using Home Assistant, Frigate and Home Assistant must be connected to the same MQTT broker.

View File

@ -5,9 +5,17 @@ title: Getting started
# Getting Started
:::tip
If you already have an environment with Linux and Docker installed, you can continue to [Installing Frigate](#installing-frigate) below.
If you already have Frigate installed in Docker or as a Home Assistant addon, you can continue to [Configuring Frigate](#configuring-frigate) below.
:::
## Setting up hardware
This section guides you through setting up a server with Debian Bookworm and Docker. If you already have an environment with Linux and Docker installed, you can continue to [Installing Frigate](#installing-frigate) below.
This section guides you through setting up a server with Debian Bookworm and Docker.
### Install Debian 12 (Bookworm)
@ -77,20 +85,19 @@ This section shows how to create a minimal directory structure for a Docker inst
### Setup directories
Frigate requires a valid config file to start. The following directory structure is the bare minimum to get started. Once Frigate is running, you can use the built-in config editor which supports config validation.
Frigate will create a config file if one does not exist on the initial startup. The following directory structure is the bare minimum to get started. Once Frigate is running, you can use the built-in config editor which supports config validation.
```
.
├── docker-compose.yml
├── config/
│ └── config.yml
└── storage/
```
This will create the above structure:
```bash
mkdir storage config && touch docker-compose.yml config/config.yml
mkdir storage config && touch docker-compose.yml
```
If you are setting up Frigate on a Linux device via SSH, you can use [nano](https://itsfoss.com/nano-editor-guide/) to edit the following files. If you prefer to edit remote files with a full editor instead of a terminal, I recommend using [Visual Studio Code](https://code.visualstudio.com/) with the [Remote SSH extension](https://code.visualstudio.com/docs/remote/ssh-tutorial).
@ -121,22 +128,6 @@ services:
- "8554:8554" # RTSP feeds
```
`config.yml`
```yaml
mqtt:
enabled: False
cameras:
dummy_camera: # <--- this will be changed to your actual camera later
enabled: False
ffmpeg:
inputs:
- path: rtsp://127.0.0.1:554/rtsp
roles:
- detect
```
Now you should be able to start Frigate by running `docker compose up -d` from within the folder containing `docker-compose.yml`. On startup, an admin user and password will be created and outputted in the logs. You can see this by running `docker logs frigate`. Frigate should now be accessible at `https://server_ip:8971` where you can login with the `admin` user and finish the configuration using the built-in configuration editor.
## Configuring Frigate
@ -274,13 +265,11 @@ cameras:
- 0,461,3,0,1919,0,1919,843,1699,492,1344,458,1346,336,973,317,869,375,866,432
```
### Step 6: Enable recording and/or snapshots
### Step 6: Enable recordings
In order to see Events in the Frigate UI, either snapshots or record will need to be enabled.
In order to review activity in the Frigate UI, recordings need to be enabled.
#### Record
To enable recording video, add the `record` role to a stream and enable it in the config. If record is disabled in the config, turning it on via the UI will not have any effect.
To enable recording video, add the `record` role to a stream and enable it in the config. If record is disabled in the config, it won't be possible to enable it in the UI.
```yaml
mqtt: ...
@ -307,26 +296,6 @@ If you don't have separate streams for detect and record, you would just add the
By default, Frigate will retain video of all events for 10 days. The full set of options for recording can be found [here](../configuration/reference.md).
#### Snapshots
To enable snapshots of your events, just enable it in the config. Snapshots are taken from the detect stream because it is the only stream decoded.
```yaml
mqtt: ...
detectors: ...
cameras:
name_of_your_camera: ...
detect: ...
record: ...
snapshots: # <----- Enable snapshots
enabled: True
motion: ...
```
By default, Frigate will retain snapshots of all events for 10 days. The full set of options for snapshots can be found [here](../configuration/reference.md).
### Step 7: Complete config
At this point you have a complete config with basic functionality. You can see the [full config reference](../configuration/reference.md) for a complete list of configuration options.
@ -336,6 +305,8 @@ At this point you have a complete config with basic functionality. You can see t
Now that you have a working install, you can use the following documentation for additional features:
1. [Configuring go2rtc](configuring_go2rtc.md) - Additional live view options and RTSP relay
2. [Home Assistant Integration](../integrations/home-assistant.md) - Integrate with Home Assistant
3. [Masks](../configuration/masks.md)
4. [Zones](../configuration/zones.md)
2. [Zones](../configuration/zones.md)
3. [Review](../configuration/review.md)
4. [Masks](../configuration/masks.md)
5. [Home Assistant Integration](../integrations/home-assistant.md) - Integrate with Home Assistant

View File

@ -13,9 +13,11 @@ import { Button } from "@/components/ui/button";
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Toaster } from "@/components/ui/sonner";
import { cn } from "@/lib/utils";
import { DeleteClipType, Export } from "@/types/export";
import axios from "axios";
import { useCallback, useEffect, useMemo, useState } from "react";
import { isMobile } from "react-device-detect";
import { LuFolderX } from "react-icons/lu";
import { toast } from "sonner";
import useSWR from "swr";
@ -92,6 +94,7 @@ function Exports() {
// Viewing
const [selected, setSelected] = useState<Export>();
const [selectedAspect, setSelectedAspect] = useState(0.0);
return (
<div className="flex size-full flex-col gap-2 overflow-hidden px-1 pt-2 md:p-2">
@ -129,15 +132,27 @@ function Exports() {
}
}}
>
<DialogContent className="max-w-7xl">
<DialogTitle>{selected?.name}</DialogTitle>
<DialogContent
className={cn("max-w-[80%]", isMobile && "landscape:max-w-[60%]")}
>
<DialogTitle className="capitalize">
{selected?.name?.replaceAll("_", " ")}
</DialogTitle>
<video
className="size-full rounded-lg md:rounded-2xl"
className={cn(
"size-full rounded-lg md:rounded-2xl",
selectedAspect < 1.5 && "aspect-video h-full",
)}
playsInline
preload="auto"
autoPlay
controls
muted
onLoadedData={(e) =>
setSelectedAspect(
e.currentTarget.videoWidth / e.currentTarget.videoHeight,
)
}
>
<source
src={`${baseUrl}${selected?.video_path?.replace("/media/frigate/", "")}`}

View File

@ -43,6 +43,7 @@ import {
FaSortAmountDown,
FaSortAmountUp,
} from "react-icons/fa";
import { LuFolderX } from "react-icons/lu";
import { PiSlidersHorizontalFill } from "react-icons/pi";
import useSWR from "swr";
import useSWRInfinite from "swr/infinite";
@ -240,96 +241,104 @@ export default function SubmitPlus() {
<PlusSortSelector selectedSort={sort} setSelectedSort={setSort} />
</div>
<div className="no-scrollbar flex size-full flex-1 flex-wrap content-start gap-2 overflow-y-auto md:gap-4">
<div className="grid w-full gap-2 p-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5">
<Dialog
open={upload != undefined}
onOpenChange={(open) => (!open ? setUpload(undefined) : null)}
>
<DialogContent className="md:max-w-2xl lg:max-w-3xl xl:max-w-4xl">
<DialogHeader>
<DialogTitle>Submit To Frigate+</DialogTitle>
<DialogDescription>
Objects in locations you want to avoid are not false
positives. Submitting them as false positives will confuse the
model.
</DialogDescription>
</DialogHeader>
<img
className={`w-full ${grow} bg-black`}
src={`${baseUrl}api/events/${upload?.id}/snapshot.jpg`}
alt={`${upload?.label}`}
/>
<DialogFooter>
<Button onClick={() => setUpload(undefined)}>Cancel</Button>
<Button
className="bg-success"
onClick={() => onSubmitToPlus(false)}
>
This is a {upload?.label}
</Button>
<Button
className="text-white"
variant="destructive"
onClick={() => onSubmitToPlus(true)}
>
This is not a {upload?.label}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
{events?.map((event) => {
if (event.data.type != "object" || event.plus_id) {
return;
}
return (
<div
key={event.id}
className="relative flex aspect-video w-full cursor-pointer items-center justify-center rounded-lg bg-black md:rounded-2xl"
onClick={() => setUpload(event)}
>
<div className="absolute left-0 top-2 z-40">
<Tooltip>
<div className="flex">
<TooltipTrigger asChild>
<div className="mx-3 pb-1 text-sm text-white">
<Chip
className={`z-0 flex items-center justify-between space-x-1 bg-gray-500 bg-gradient-to-br from-gray-400 to-gray-500`}
>
{[event.label].map((object) => {
return getIconForLabel(
object,
"size-3 text-white",
);
})}
<div className="text-xs">
{Math.round(event.data.score * 100)}%
</div>
</Chip>
</div>
</TooltipTrigger>
</div>
<TooltipContent className="capitalize">
{[event.label]
.map((text) => capitalizeFirstLetter(text))
.sort()
.join(", ")
.replaceAll("-verified", "")}
</TooltipContent>
</Tooltip>
</div>
{isValidating ? (
<ActivityIndicator className="absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2" />
) : events?.length === 0 ? (
<div className="absolute left-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 flex-col items-center justify-center text-center">
<LuFolderX className="size-16" />
No snapshots found
</div>
) : (
<div className="grid w-full gap-2 p-2 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-5">
<Dialog
open={upload != undefined}
onOpenChange={(open) => (!open ? setUpload(undefined) : null)}
>
<DialogContent className="md:max-w-2xl lg:max-w-3xl xl:max-w-4xl">
<DialogHeader>
<DialogTitle>Submit To Frigate+</DialogTitle>
<DialogDescription>
Objects in locations you want to avoid are not false
positives. Submitting them as false positives will confuse
the model.
</DialogDescription>
</DialogHeader>
<img
className="aspect-video h-full rounded-lg object-contain md:rounded-2xl"
src={`${baseUrl}api/events/${event.id}/snapshot.jpg`}
loading="lazy"
className={`w-full ${grow} bg-black`}
src={`${baseUrl}api/events/${upload?.id}/snapshot.jpg`}
alt={`${upload?.label}`}
/>
</div>
);
})}
{!isValidating && !isDone && <div ref={lastEventRef} />}
{isValidating && <ActivityIndicator />}
</div>
<DialogFooter>
<Button onClick={() => setUpload(undefined)}>Cancel</Button>
<Button
className="bg-success"
onClick={() => onSubmitToPlus(false)}
>
This is a {upload?.label}
</Button>
<Button
className="text-white"
variant="destructive"
onClick={() => onSubmitToPlus(true)}
>
This is not a {upload?.label}
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
{events?.map((event) => {
if (event.data.type != "object" || event.plus_id) {
return;
}
return (
<div
key={event.id}
className="relative flex aspect-video w-full cursor-pointer items-center justify-center rounded-lg bg-black md:rounded-2xl"
onClick={() => setUpload(event)}
>
<div className="absolute left-0 top-2 z-40">
<Tooltip>
<div className="flex">
<TooltipTrigger asChild>
<div className="mx-3 pb-1 text-sm text-white">
<Chip
className={`z-0 flex items-center justify-between space-x-1 bg-gray-500 bg-gradient-to-br from-gray-400 to-gray-500`}
>
{[event.label].map((object) => {
return getIconForLabel(
object,
"size-3 text-white",
);
})}
<div className="text-xs">
{Math.round(event.data.score * 100)}%
</div>
</Chip>
</div>
</TooltipTrigger>
</div>
<TooltipContent className="capitalize">
{[event.label]
.map((text) => capitalizeFirstLetter(text))
.sort()
.join(", ")
.replaceAll("-verified", "")}
</TooltipContent>
</Tooltip>
</div>
<img
className="aspect-video h-full rounded-lg object-contain md:rounded-2xl"
src={`${baseUrl}api/events/${event.id}/snapshot.jpg`}
loading="lazy"
/>
</div>
);
})}
{!isValidating && !isDone && <div ref={lastEventRef} />}
</div>
)}
</div>
</div>
);

View File

@ -708,25 +708,31 @@ function Timeline({
isMobile && "sm:grid-cols-2",
)}
>
{mainCameraReviewItems.map((review) => {
if (review.severity == "significant_motion") {
return;
}
{mainCameraReviewItems.length === 0 ? (
<div className="mt-5 text-center text-primary">
No events found for this time period.
</div>
) : (
mainCameraReviewItems.map((review) => {
if (review.severity === "significant_motion") {
return;
}
return (
<ReviewCard
key={review.id}
event={review}
currentTime={currentTime}
onClick={() => {
manuallySetCurrentTime(
review.start_time - REVIEW_PADDING,
true,
);
}}
/>
);
})}
return (
<ReviewCard
key={review.id}
event={review}
currentTime={currentTime}
onClick={() => {
manuallySetCurrentTime(
review.start_time - REVIEW_PADDING,
true,
);
}}
/>
);
})
)}
</div>
</div>
)}