mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-05-01 02:57:41 +03:00
add enabled switch
This commit is contained in:
parent
38a5797681
commit
aca9e15790
@ -107,6 +107,8 @@ class CameraConfigUpdateSubscriber:
|
|||||||
config.record = updated_config
|
config.record = updated_config
|
||||||
elif update_type == CameraConfigUpdateEnum.review:
|
elif update_type == CameraConfigUpdateEnum.review:
|
||||||
config.review = updated_config
|
config.review = updated_config
|
||||||
|
elif update_type == CameraConfigUpdateEnum.semantic_search:
|
||||||
|
config.semantic_search = updated_config
|
||||||
elif update_type == CameraConfigUpdateEnum.snapshots:
|
elif update_type == CameraConfigUpdateEnum.snapshots:
|
||||||
config.snapshots = updated_config
|
config.snapshots = updated_config
|
||||||
elif update_type == CameraConfigUpdateEnum.zones:
|
elif update_type == CameraConfigUpdateEnum.zones:
|
||||||
|
|||||||
@ -125,10 +125,11 @@ class SemanticSearchConfig(FrigateBaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class TriggerConfig(FrigateBaseModel):
|
class TriggerConfig(FrigateBaseModel):
|
||||||
|
enabled: bool = Field(default=True, title="Enable this trigger")
|
||||||
type: TriggerType = Field(default=TriggerType.DESCRIPTION, title="Type of trigger")
|
type: TriggerType = Field(default=TriggerType.DESCRIPTION, title="Type of trigger")
|
||||||
data: str = Field(title="Trigger content (text phrase or image ID)")
|
data: str = Field(title="Trigger content (text phrase or image ID)")
|
||||||
threshold: float = Field(
|
threshold: float = Field(
|
||||||
title="Confidence score required to run the trigger.",
|
title="Confidence score required to run the trigger",
|
||||||
default=0.8,
|
default=0.8,
|
||||||
gt=0.0,
|
gt=0.0,
|
||||||
le=1.0,
|
le=1.0,
|
||||||
|
|||||||
@ -80,6 +80,16 @@ class SemanticTriggerProcessor(PostProcessorApi):
|
|||||||
)
|
)
|
||||||
|
|
||||||
for trigger in triggers:
|
for trigger in triggers:
|
||||||
|
if (
|
||||||
|
not self.config.cameras[camera]
|
||||||
|
.semantic_search.triggers[trigger["name"]]
|
||||||
|
.enabled
|
||||||
|
):
|
||||||
|
logger.debug(
|
||||||
|
f"Trigger {trigger['name']} is disabled for camera {camera}"
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
logger.debug(
|
logger.debug(
|
||||||
f"Processing {trigger['type']} trigger for {event_id} on {trigger['camera']}: {trigger['name']}"
|
f"Processing {trigger['type']} trigger for {event_id} on {trigger['camera']}: {trigger['name']}"
|
||||||
)
|
)
|
||||||
@ -171,6 +181,7 @@ class SemanticTriggerProcessor(PostProcessorApi):
|
|||||||
.actions
|
.actions
|
||||||
):
|
):
|
||||||
# TODO: handle actions for the trigger
|
# TODO: handle actions for the trigger
|
||||||
|
# notifications already handled by webpush
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if WRITE_DEBUG_IMAGES:
|
if WRITE_DEBUG_IMAGES:
|
||||||
|
|||||||
@ -97,7 +97,11 @@ class EmbeddingMaintainer(threading.Thread):
|
|||||||
self.config_updater = CameraConfigUpdateSubscriber(
|
self.config_updater = CameraConfigUpdateSubscriber(
|
||||||
self.config,
|
self.config,
|
||||||
self.config.cameras,
|
self.config.cameras,
|
||||||
[CameraConfigUpdateEnum.add, CameraConfigUpdateEnum.remove],
|
[
|
||||||
|
CameraConfigUpdateEnum.add,
|
||||||
|
CameraConfigUpdateEnum.remove,
|
||||||
|
CameraConfigUpdateEnum.semantic_search,
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
# Configure Frigate DB
|
# Configure Frigate DB
|
||||||
|
|||||||
@ -693,6 +693,9 @@
|
|||||||
"alreadyExists": "A trigger with this name already exists for this camera."
|
"alreadyExists": "A trigger with this name already exists for this camera."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"enabled": {
|
||||||
|
"description": "Enable or disable this trigger"
|
||||||
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"title": "Trigger Type",
|
"title": "Trigger Type",
|
||||||
"placeholder": "Select trigger type"
|
"placeholder": "Select trigger type"
|
||||||
|
|||||||
@ -34,12 +34,14 @@ import ActivityIndicator from "@/components/indicators/activity-indicator";
|
|||||||
import { FrigateConfig } from "@/types/frigateConfig";
|
import { FrigateConfig } from "@/types/frigateConfig";
|
||||||
import ImagePicker from "@/components/overlay/ImagePicker";
|
import ImagePicker from "@/components/overlay/ImagePicker";
|
||||||
import { Trigger, TriggerAction, TriggerType } from "@/types/trigger";
|
import { Trigger, TriggerAction, TriggerType } from "@/types/trigger";
|
||||||
|
import { Switch } from "@/components/ui/switch";
|
||||||
|
|
||||||
type CreateTriggerDialogProps = {
|
type CreateTriggerDialogProps = {
|
||||||
show: boolean;
|
show: boolean;
|
||||||
trigger: Trigger | null;
|
trigger: Trigger | null;
|
||||||
selectedCamera: string;
|
selectedCamera: string;
|
||||||
onCreate: (
|
onCreate: (
|
||||||
|
enabled: boolean,
|
||||||
name: string,
|
name: string,
|
||||||
type: TriggerType,
|
type: TriggerType,
|
||||||
data: string,
|
data: string,
|
||||||
@ -74,6 +76,7 @@ export default function CreateTriggerDialog({
|
|||||||
}, [config, selectedCamera]);
|
}, [config, selectedCamera]);
|
||||||
|
|
||||||
const formSchema = z.object({
|
const formSchema = z.object({
|
||||||
|
enabled: z.boolean(),
|
||||||
name: z
|
name: z
|
||||||
.string()
|
.string()
|
||||||
.min(2, t("triggers.dialog.form.name.error.minLength"))
|
.min(2, t("triggers.dialog.form.name.error.minLength"))
|
||||||
@ -101,6 +104,7 @@ export default function CreateTriggerDialog({
|
|||||||
resolver: zodResolver(formSchema),
|
resolver: zodResolver(formSchema),
|
||||||
mode: "onChange",
|
mode: "onChange",
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
|
enabled: trigger?.enabled ?? true,
|
||||||
name: trigger?.name ?? "",
|
name: trigger?.name ?? "",
|
||||||
type: trigger?.type ?? "description",
|
type: trigger?.type ?? "description",
|
||||||
data: trigger?.data ?? "",
|
data: trigger?.data ?? "",
|
||||||
@ -115,6 +119,7 @@ export default function CreateTriggerDialog({
|
|||||||
onEdit({ ...values });
|
onEdit({ ...values });
|
||||||
} else {
|
} else {
|
||||||
onCreate(
|
onCreate(
|
||||||
|
values.enabled,
|
||||||
values.name,
|
values.name,
|
||||||
values.type,
|
values.type,
|
||||||
values.data,
|
values.data,
|
||||||
@ -128,6 +133,7 @@ export default function CreateTriggerDialog({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!show) {
|
if (!show) {
|
||||||
form.reset({
|
form.reset({
|
||||||
|
enabled: true,
|
||||||
name: "",
|
name: "",
|
||||||
type: "description",
|
type: "description",
|
||||||
data: "",
|
data: "",
|
||||||
@ -136,6 +142,7 @@ export default function CreateTriggerDialog({
|
|||||||
});
|
});
|
||||||
} else if (trigger) {
|
} else if (trigger) {
|
||||||
form.reset({
|
form.reset({
|
||||||
|
enabled: trigger.enabled,
|
||||||
name: trigger.name,
|
name: trigger.name,
|
||||||
type: trigger.type,
|
type: trigger.type,
|
||||||
data: trigger.data,
|
data: trigger.data,
|
||||||
@ -194,6 +201,29 @@ export default function CreateTriggerDialog({
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<FormField
|
||||||
|
control={form.control}
|
||||||
|
name="enabled"
|
||||||
|
render={({ field }) => (
|
||||||
|
<FormItem className="flex flex-row items-center justify-between">
|
||||||
|
<div className="space-y-0.5">
|
||||||
|
<FormLabel className="text-base">
|
||||||
|
{t("enabled", { ns: "common" })}
|
||||||
|
</FormLabel>
|
||||||
|
<div className="text-sm text-muted-foreground">
|
||||||
|
{t("triggers.dialog.form.enabled.description")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<FormControl>
|
||||||
|
<Switch
|
||||||
|
checked={field.value}
|
||||||
|
onCheckedChange={field.onChange}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
</FormItem>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="type"
|
name="type"
|
||||||
|
|||||||
@ -224,6 +224,7 @@ export interface CameraConfig {
|
|||||||
semantic_search: {
|
semantic_search: {
|
||||||
triggers: {
|
triggers: {
|
||||||
[triggerName: string]: {
|
[triggerName: string]: {
|
||||||
|
enabled: boolean;
|
||||||
type: TriggerType;
|
type: TriggerType;
|
||||||
data: string;
|
data: string;
|
||||||
threshold: number;
|
threshold: number;
|
||||||
|
|||||||
@ -2,6 +2,7 @@ export type TriggerType = "thumbnail" | "description";
|
|||||||
export type TriggerAction = "alert" | "notification";
|
export type TriggerAction = "alert" | "notification";
|
||||||
|
|
||||||
export type Trigger = {
|
export type Trigger = {
|
||||||
|
enabled: boolean;
|
||||||
name: string;
|
name: string;
|
||||||
type: TriggerType;
|
type: TriggerType;
|
||||||
data: string;
|
data: string;
|
||||||
|
|||||||
@ -36,6 +36,7 @@ type ConfigSetBody = {
|
|||||||
triggers?: {
|
triggers?: {
|
||||||
[key: string]:
|
[key: string]:
|
||||||
| {
|
| {
|
||||||
|
enabled: boolean;
|
||||||
type: string;
|
type: string;
|
||||||
data: string;
|
data: string;
|
||||||
threshold: number;
|
threshold: number;
|
||||||
@ -84,6 +85,7 @@ export default function TriggerView({
|
|||||||
return Object.entries(
|
return Object.entries(
|
||||||
config.cameras[selectedCamera].semantic_search.triggers,
|
config.cameras[selectedCamera].semantic_search.triggers,
|
||||||
).map(([name, trigger]) => ({
|
).map(([name, trigger]) => ({
|
||||||
|
enabled: trigger.enabled,
|
||||||
name,
|
name,
|
||||||
type: trigger.type,
|
type: trigger.type,
|
||||||
data: trigger.data,
|
data: trigger.data,
|
||||||
@ -99,7 +101,7 @@ export default function TriggerView({
|
|||||||
const saveToConfig = useCallback(
|
const saveToConfig = useCallback(
|
||||||
(trigger: Trigger, isEdit: boolean) => {
|
(trigger: Trigger, isEdit: boolean) => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
const { name, type, data, threshold, actions } = trigger;
|
const { enabled, name, type, data, threshold, actions } = trigger;
|
||||||
const embeddingBody: TriggerEmbeddingBody = { type, data, threshold };
|
const embeddingBody: TriggerEmbeddingBody = { type, data, threshold };
|
||||||
const embeddingUrl = isEdit
|
const embeddingUrl = isEdit
|
||||||
? `/trigger/embedding/${selectedCamera}/${name}`
|
? `/trigger/embedding/${selectedCamera}/${name}`
|
||||||
@ -117,6 +119,7 @@ export default function TriggerView({
|
|||||||
semantic_search: {
|
semantic_search: {
|
||||||
triggers: {
|
triggers: {
|
||||||
[name]: {
|
[name]: {
|
||||||
|
enabled,
|
||||||
type,
|
type,
|
||||||
data,
|
data,
|
||||||
threshold,
|
threshold,
|
||||||
@ -172,6 +175,7 @@ export default function TriggerView({
|
|||||||
|
|
||||||
const onCreate = useCallback(
|
const onCreate = useCallback(
|
||||||
(
|
(
|
||||||
|
enabled: boolean,
|
||||||
name: string,
|
name: string,
|
||||||
type: TriggerType,
|
type: TriggerType,
|
||||||
data: string,
|
data: string,
|
||||||
@ -179,7 +183,7 @@ export default function TriggerView({
|
|||||||
actions: TriggerAction[],
|
actions: TriggerAction[],
|
||||||
) => {
|
) => {
|
||||||
setUnsavedChanges(true);
|
setUnsavedChanges(true);
|
||||||
saveToConfig({ name, type, data, threshold, actions }, false);
|
saveToConfig({ enabled, name, type, data, threshold, actions }, false);
|
||||||
setShowCreate(false);
|
setShowCreate(false);
|
||||||
},
|
},
|
||||||
[saveToConfig, setUnsavedChanges],
|
[saveToConfig, setUnsavedChanges],
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user