Support adding of camera groups and dynamically updating the config

This commit is contained in:
Nicolas Mowen 2024-03-06 12:35:39 -07:00
parent 2e9c4a8d63
commit b064587a68
3 changed files with 74 additions and 13 deletions

View File

@ -159,9 +159,9 @@ def config():
config["plus"] = {"enabled": current_app.plus_api.is_active()}
for detector, detector_config in config["detectors"].items():
detector_config["model"]["labelmap"] = (
current_app.frigate_config.model.merged_labelmap
)
detector_config["model"][
"labelmap"
] = current_app.frigate_config.model.merged_labelmap
return jsonify(config)
@ -292,7 +292,7 @@ def config_set():
f.close()
# Validate the config schema
try:
FrigateConfig.parse_raw(new_raw_config)
config_obj = FrigateConfig.parse_raw(new_raw_config)
except Exception:
with open(config_file, "w") as f:
f.write(old_raw_config)
@ -314,6 +314,13 @@ def config_set():
500,
)
json = request.get_json(silent=True) or {}
if json.get("requires_restart", 1) == 0:
current_app.frigate_config = FrigateConfig.runtime_config(
config_obj, current_app.plus_api
)
return make_response(
jsonify(
{

View File

@ -204,17 +204,22 @@ def update_yaml_from_url(file_path, url):
key_path.pop(i - 1)
except ValueError:
pass
new_value = new_value_list[0]
update_yaml_file(file_path, key_path, new_value)
if len(new_value_list) > 1:
update_yaml_file(file_path, key_path, new_value_list)
else:
update_yaml_file(file_path, key_path, new_value_list[0])
def update_yaml_file(file_path, key_path, new_value):
yaml = YAML()
yaml.indent(mapping=2, sequence=4, offset=2)
with open(file_path, "r") as f:
data = yaml.load(f)
data = update_yaml(data, key_path, new_value)
with open("/config/test.yaml", "w") as f:
yaml.dump(data, f)
with open(file_path, "w") as f:
yaml.dump(data, f)

View File

@ -19,6 +19,7 @@ import {
DropdownMenuTrigger,
} from "../ui/dropdown-menu";
import FilterCheckBox from "./FilterCheckBox";
import axios from "axios";
type CameraGroupSelectorProps = {
className?: string;
@ -68,7 +69,11 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) {
<div
className={`flex items-center justify-start gap-2 ${className ?? ""} ${isDesktop ? "flex-col" : ""}`}
>
<NewGroupDialog open={addGroup} setOpen={setAddGroup} />
<NewGroupDialog
open={addGroup}
setOpen={setAddGroup}
index={groups.length}
/>
<Tooltip open={tooltip == "home"}>
<TooltipTrigger asChild>
@ -79,7 +84,7 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) {
: "text-muted-foreground bg-secondary focus:text-muted-foreground focus:bg-secondary"
}
size="xs"
onClick={() => navigate(-1)}
onClick={() => (group ? navigate(-1) : null)}
onMouseEnter={() => (isDesktop ? showTooltip("home") : null)}
onMouseLeave={() => (isDesktop ? showTooltip(undefined) : null)}
>
@ -130,16 +135,57 @@ export function CameraGroupSelector({ className }: CameraGroupSelectorProps) {
type NewGroupDialogProps = {
open: boolean;
setOpen: (open: boolean) => void;
index: number;
};
function NewGroupDialog({ open, setOpen }: NewGroupDialogProps) {
const { data: config } = useSWR<FrigateConfig>("config");
function NewGroupDialog({ open, setOpen, index }: NewGroupDialogProps) {
const { data: config, mutate: updateConfig } =
useSWR<FrigateConfig>("config");
const [newTitle, setNewTitle] = useState("");
const [icon, setIcon] = useState("");
const [cameras, setCameras] = useState<string[]>([]);
const [error, setError] = useState("");
const onCreateGroup = useCallback(async () => {
if (!newTitle) {
setError("A title must be selected");
return;
}
if (!icon) {
setError("An icon must be selected");
return;
}
if (!cameras || cameras.length < 2) {
setError("At least 2 cameras must be selected");
return;
}
setError("");
const orderQuery = `camera_groups.${newTitle}.order=${index}`;
const iconQuery = `camera_groups.${newTitle}.icon=${icon}`;
const cameraQueries = cameras
.map((cam) => `&camera_groups.${newTitle}.cameras=${cam}`)
.join("");
const req = axios.put(
`config/set?${orderQuery}&${iconQuery}${cameraQueries}`,
{ requires_restart: 0 },
);
setOpen(false);
if ((await req).status == 200) {
setNewTitle("");
setIcon("");
setCameras([]);
updateConfig();
}
}, [index, cameras, newTitle, icon, setOpen, updateConfig]);
return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogContent className="min-w-0 w-80">
<DialogContent className="min-w-0 w-96">
<DialogTitle>Create New Camera Group</DialogTitle>
<Input
type="text"
@ -198,7 +244,10 @@ function NewGroupDialog({ open, setOpen }: NewGroupDialogProps) {
))}
</DropdownMenuContent>
</DropdownMenu>
<Button variant="select">Submit</Button>
{error && <div className="text-danger">{error}</div>}
<Button variant="select" onClick={onCreateGroup}>
Submit
</Button>
</DialogContent>
</Dialog>
);