mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-02 01:05:20 +03:00
Add ability to restart
This commit is contained in:
parent
6d02150b00
commit
c417778a51
@ -10,6 +10,7 @@ services:
|
|||||||
dockerfile: docker/Dockerfile.dev
|
dockerfile: docker/Dockerfile.dev
|
||||||
volumes:
|
volumes:
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro
|
||||||
- .:/lab/frigate:cached
|
- .:/lab/frigate:cached
|
||||||
- ./config/config.yml:/config/config.yml:ro
|
- ./config/config.yml:/config/config.yml:ro
|
||||||
- ./debug:/media/frigate
|
- ./debug:/media/frigate
|
||||||
|
|||||||
@ -1,3 +1,11 @@
|
|||||||
|
FROM ubuntu:20.04 AS docker
|
||||||
|
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
RUN apt-get -yqq update && \
|
||||||
|
apt-get install -yq --no-install-recommends ca-certificates docker.io && \
|
||||||
|
apt-get autoremove -y && \
|
||||||
|
apt-get clean -y
|
||||||
|
|
||||||
ARG ARCH=amd64
|
ARG ARCH=amd64
|
||||||
ARG WHEELS_VERSION
|
ARG WHEELS_VERSION
|
||||||
ARG FFMPEG_VERSION
|
ARG FFMPEG_VERSION
|
||||||
@ -18,6 +26,8 @@ COPY --from=ffmpeg /usr/local /usr/local/
|
|||||||
|
|
||||||
COPY --from=wheels /wheels/. /wheels/
|
COPY --from=wheels /wheels/. /wheels/
|
||||||
|
|
||||||
|
COPY --from=docker /usr/bin/docker /usr/local/bin/docker
|
||||||
|
|
||||||
ENV FLASK_ENV=development
|
ENV FLASK_ENV=development
|
||||||
# ENV FONTCONFIG_PATH=/etc/fonts
|
# ENV FONTCONFIG_PATH=/etc/fonts
|
||||||
ENV DEBIAN_FRONTEND=noninteractive
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|||||||
@ -46,6 +46,7 @@ services:
|
|||||||
- /dev/dri/renderD128 # for intel hwaccel, needs to be updated for your hardware
|
- /dev/dri/renderD128 # for intel hwaccel, needs to be updated for your hardware
|
||||||
volumes:
|
volumes:
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock:ro # for Frigate restart with docker command
|
||||||
- <path_to_config_file>:/config/config.yml:ro
|
- <path_to_config_file>:/config/config.yml:ro
|
||||||
- <path_to_directory_for_media>:/media/frigate
|
- <path_to_directory_for_media>:/media/frigate
|
||||||
- type: tmpfs # Optional: 1GB of memory, reduces SSD/SD Card wear
|
- type: tmpfs # Optional: 1GB of memory, reduces SSD/SD Card wear
|
||||||
@ -71,6 +72,7 @@ docker run -d \
|
|||||||
-v <path_to_directory_for_media>:/media/frigate \
|
-v <path_to_directory_for_media>:/media/frigate \
|
||||||
-v <path_to_config_file>:/config/config.yml:ro \
|
-v <path_to_config_file>:/config/config.yml:ro \
|
||||||
-v /etc/localtime:/etc/localtime:ro \
|
-v /etc/localtime:/etc/localtime:ro \
|
||||||
|
-v /var/run/docker.sock:/var/run/docker.sock:ro \
|
||||||
-e FRIGATE_RTSP_PASSWORD='password' \
|
-e FRIGATE_RTSP_PASSWORD='password' \
|
||||||
-p 5000:5000 \
|
-p 5000:5000 \
|
||||||
-p 1935:1935 \
|
-p 1935:1935 \
|
||||||
|
|||||||
@ -13,6 +13,7 @@ from ws4py.server.wsgiutils import WebSocketWSGIApplication
|
|||||||
from ws4py.websocket import WebSocket
|
from ws4py.websocket import WebSocket
|
||||||
|
|
||||||
from frigate.config import FrigateConfig
|
from frigate.config import FrigateConfig
|
||||||
|
from frigate.util import restart_frigate
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -88,6 +89,14 @@ def create_mqtt_client(config: FrigateConfig, camera_metrics):
|
|||||||
state_topic = f"{message.topic[:-4]}/state"
|
state_topic = f"{message.topic[:-4]}/state"
|
||||||
client.publish(state_topic, payload, retain=True)
|
client.publish(state_topic, payload, retain=True)
|
||||||
|
|
||||||
|
def on_restart_command(client, userdata, message):
|
||||||
|
payload = message.payload.decode()
|
||||||
|
if payload == "container":
|
||||||
|
logger.warning(f"Restart container received via mqtt")
|
||||||
|
restart_frigate()
|
||||||
|
else:
|
||||||
|
logger.warning(f"Received unsupported value at {message.topic}: {payload}")
|
||||||
|
|
||||||
def on_connect(client, userdata, flags, rc):
|
def on_connect(client, userdata, flags, rc):
|
||||||
threading.current_thread().name = "mqtt"
|
threading.current_thread().name = "mqtt"
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
@ -125,6 +134,10 @@ def create_mqtt_client(config: FrigateConfig, camera_metrics):
|
|||||||
f"{mqtt_config.topic_prefix}/{name}/detect/set", on_detect_command
|
f"{mqtt_config.topic_prefix}/{name}/detect/set", on_detect_command
|
||||||
)
|
)
|
||||||
|
|
||||||
|
client.message_callback_add(
|
||||||
|
f"{mqtt_config.topic_prefix}/restart", on_restart_command
|
||||||
|
)
|
||||||
|
|
||||||
if not mqtt_config.tls_ca_certs is None:
|
if not mqtt_config.tls_ca_certs is None:
|
||||||
if (
|
if (
|
||||||
not mqtt_config.tls_client_cert is None
|
not mqtt_config.tls_client_cert is None
|
||||||
|
|||||||
@ -383,6 +383,11 @@ def clipped(obj, frame_shape):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def restart_frigate():
|
||||||
|
sp.run("docker restart $(hostname)", shell=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
class EventsPerSecond:
|
class EventsPerSecond:
|
||||||
def __init__(self, max_events=1000):
|
def __init__(self, max_events=1000):
|
||||||
self._start = None
|
self._start = None
|
||||||
|
|||||||
@ -5,12 +5,17 @@ import Menu, { MenuItem, MenuSeparator } from './components/Menu';
|
|||||||
import AutoAwesomeIcon from './icons/AutoAwesome';
|
import AutoAwesomeIcon from './icons/AutoAwesome';
|
||||||
import LightModeIcon from './icons/LightMode';
|
import LightModeIcon from './icons/LightMode';
|
||||||
import DarkModeIcon from './icons/DarkMode';
|
import DarkModeIcon from './icons/DarkMode';
|
||||||
|
import FrigateRestartIcon from './icons/FrigateRestart';
|
||||||
|
import Dialog from './components/Dialog';
|
||||||
import { useDarkMode } from './context';
|
import { useDarkMode } from './context';
|
||||||
import { useCallback, useRef, useState } from 'preact/hooks';
|
import { useCallback, useRef, useState } from 'preact/hooks';
|
||||||
|
import { useRestart } from './api/mqtt';
|
||||||
|
|
||||||
export default function AppBar() {
|
export default function AppBar() {
|
||||||
const [showMoreMenu, setShowMoreMenu] = useState(false);
|
const [showMoreMenu, setShowMoreMenu] = useState(false);
|
||||||
|
const [showDialog, setShowDialog] = useState(false);
|
||||||
const { setDarkMode } = useDarkMode();
|
const { setDarkMode } = useDarkMode();
|
||||||
|
const { send: sendRestart } = useRestart();
|
||||||
|
|
||||||
const handleSelectDarkMode = useCallback(
|
const handleSelectDarkMode = useCallback(
|
||||||
(value, label) => {
|
(value, label) => {
|
||||||
@ -30,6 +35,20 @@ export default function AppBar() {
|
|||||||
setShowMoreMenu(false);
|
setShowMoreMenu(false);
|
||||||
}, [setShowMoreMenu]);
|
}, [setShowMoreMenu]);
|
||||||
|
|
||||||
|
const handleClickRestartDialog = useCallback(() => {
|
||||||
|
setShowDialog(false);
|
||||||
|
sendRestart();
|
||||||
|
}, [setShowDialog]);
|
||||||
|
|
||||||
|
const handleDismissRestartDialog = () => {
|
||||||
|
setShowDialog(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleRestart = useCallback(() => {
|
||||||
|
setShowMoreMenu(false);
|
||||||
|
setShowDialog(true);
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<BaseAppBar title={LinkedLogo} overflowRef={moreRef} onOverflowClick={handleShowMenu} />
|
<BaseAppBar title={LinkedLogo} overflowRef={moreRef} onOverflowClick={handleShowMenu} />
|
||||||
@ -39,7 +58,20 @@ export default function AppBar() {
|
|||||||
<MenuSeparator />
|
<MenuSeparator />
|
||||||
<MenuItem icon={LightModeIcon} label="Light" value="light" onSelect={handleSelectDarkMode} />
|
<MenuItem icon={LightModeIcon} label="Light" value="light" onSelect={handleSelectDarkMode} />
|
||||||
<MenuItem icon={DarkModeIcon} label="Dark" value="dark" onSelect={handleSelectDarkMode} />
|
<MenuItem icon={DarkModeIcon} label="Dark" value="dark" onSelect={handleSelectDarkMode} />
|
||||||
|
<MenuSeparator />
|
||||||
|
<MenuItem icon={RestartFrigateIcon} label="Restart Frigate" onSelect={handleRestart} />
|
||||||
</Menu>
|
</Menu>
|
||||||
|
) : null},
|
||||||
|
{showDialog ? (
|
||||||
|
<Dialog
|
||||||
|
onDismiss={handleDismissRestartDialog}
|
||||||
|
title="Restart Frigate"
|
||||||
|
text="Are you sure?"
|
||||||
|
actions={[
|
||||||
|
{ text: 'Yes', color: 'red', onClick: handleClickRestartDialog },
|
||||||
|
{ text: 'Cancel', onClick: handleDismissRestartDialog },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -72,7 +72,7 @@ export function MqttProvider({
|
|||||||
return <Mqtt.Provider value={{ state, ws: wsRef.current }}>{children}</Mqtt.Provider>;
|
return <Mqtt.Provider value={{ state, ws: wsRef.current }}>{children}</Mqtt.Provider>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useMqtt(watchTopic, publishTopic) {
|
export function useMqtt(watchTopic, publishTopic, defaultValue = null) {
|
||||||
const { state, ws } = useContext(Mqtt);
|
const { state, ws } = useContext(Mqtt);
|
||||||
|
|
||||||
const value = state[watchTopic] || { payload: null };
|
const value = state[watchTopic] || { payload: null };
|
||||||
@ -118,3 +118,12 @@ export function useSnapshotsState(camera) {
|
|||||||
} = useMqtt(`${camera}/snapshots/state`, `${camera}/snapshots/set`);
|
} = useMqtt(`${camera}/snapshots/state`, `${camera}/snapshots/set`);
|
||||||
return { payload, send, connected };
|
return { payload, send, connected };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function useRestart() {
|
||||||
|
const {
|
||||||
|
value: { payload },
|
||||||
|
send,
|
||||||
|
connected,
|
||||||
|
} = useMqtt(``, `restart`, "container");
|
||||||
|
return { send, connected };
|
||||||
|
}
|
||||||
|
|||||||
13
web/src/icons/FrigateRestart.jsx
Normal file
13
web/src/icons/FrigateRestart.jsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { h } from 'preact';
|
||||||
|
import { memo } from 'preact/compat';
|
||||||
|
|
||||||
|
export function FrigateRestart({ className = '' }) {
|
||||||
|
return (
|
||||||
|
<svg className={`fill-current ${className}`} viewBox="0 0 24 24">
|
||||||
|
<rect fill="none" height="24" width="24" />
|
||||||
|
<path d="M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1.24 4.26L6.7 14.8c-.45-.83-.7-1.79-.7-2.8 0-3.31 2.69-6 6-6zm6.76 1.74L17.3 9.2c.44.84.7 1.79.7 2.8 0 3.31-2.69 6-6 6v-3l-4 4 4 4v-3c4.42 0 8-3.58 8-8 0-1.57-.46-3.03-1.24-4.26z"/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default memo(FrigateRestart);
|
||||||
Loading…
Reference in New Issue
Block a user