From c417778a5167caf9f0da9b6d4bf901bf0d9db08f Mon Sep 17 00:00:00 2001 From: ElMoribond Date: Sun, 20 Jun 2021 18:07:24 +0200 Subject: [PATCH] Add ability to restart --- docker-compose.yml | 1 + docker/Dockerfile.base | 10 ++++++++++ docs/docs/installation.md | 2 ++ frigate/mqtt.py | 13 +++++++++++++ frigate/util.py | 5 +++++ web/src/AppBar.jsx | 32 ++++++++++++++++++++++++++++++++ web/src/api/mqtt.jsx | 11 ++++++++++- web/src/icons/FrigateRestart.jsx | 13 +++++++++++++ 8 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 web/src/icons/FrigateRestart.jsx diff --git a/docker-compose.yml b/docker-compose.yml index 197d9e11e..57c9f4b0a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,6 +10,7 @@ services: dockerfile: docker/Dockerfile.dev volumes: - /etc/localtime:/etc/localtime:ro + - /var/run/docker.sock:/var/run/docker.sock:ro - .:/lab/frigate:cached - ./config/config.yml:/config/config.yml:ro - ./debug:/media/frigate diff --git a/docker/Dockerfile.base b/docker/Dockerfile.base index a8d9eae4c..1731e0306 100644 --- a/docker/Dockerfile.base +++ b/docker/Dockerfile.base @@ -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 WHEELS_VERSION ARG FFMPEG_VERSION @@ -18,6 +26,8 @@ COPY --from=ffmpeg /usr/local /usr/local/ COPY --from=wheels /wheels/. /wheels/ +COPY --from=docker /usr/bin/docker /usr/local/bin/docker + ENV FLASK_ENV=development # ENV FONTCONFIG_PATH=/etc/fonts ENV DEBIAN_FRONTEND=noninteractive diff --git a/docs/docs/installation.md b/docs/docs/installation.md index c3f916ad1..45ea37361 100644 --- a/docs/docs/installation.md +++ b/docs/docs/installation.md @@ -46,6 +46,7 @@ services: - /dev/dri/renderD128 # for intel hwaccel, needs to be updated for your hardware volumes: - /etc/localtime:/etc/localtime:ro + - /var/run/docker.sock:/var/run/docker.sock:ro # for Frigate restart with docker command - :/config/config.yml:ro - :/media/frigate - type: tmpfs # Optional: 1GB of memory, reduces SSD/SD Card wear @@ -71,6 +72,7 @@ docker run -d \ -v :/media/frigate \ -v :/config/config.yml:ro \ -v /etc/localtime:/etc/localtime:ro \ + -v /var/run/docker.sock:/var/run/docker.sock:ro \ -e FRIGATE_RTSP_PASSWORD='password' \ -p 5000:5000 \ -p 1935:1935 \ diff --git a/frigate/mqtt.py b/frigate/mqtt.py index bc10e95c8..dddbf4767 100644 --- a/frigate/mqtt.py +++ b/frigate/mqtt.py @@ -13,6 +13,7 @@ from ws4py.server.wsgiutils import WebSocketWSGIApplication from ws4py.websocket import WebSocket from frigate.config import FrigateConfig +from frigate.util import restart_frigate logger = logging.getLogger(__name__) @@ -88,6 +89,14 @@ def create_mqtt_client(config: FrigateConfig, camera_metrics): state_topic = f"{message.topic[:-4]}/state" 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): threading.current_thread().name = "mqtt" 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 ) + 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_client_cert is None diff --git a/frigate/util.py b/frigate/util.py index 17489ee00..a0d932413 100755 --- a/frigate/util.py +++ b/frigate/util.py @@ -383,6 +383,11 @@ def clipped(obj, frame_shape): return False +def restart_frigate(): + sp.run("docker restart $(hostname)", shell=True) + return + + class EventsPerSecond: def __init__(self, max_events=1000): self._start = None diff --git a/web/src/AppBar.jsx b/web/src/AppBar.jsx index 6a3ff2a72..dcc7d94f2 100644 --- a/web/src/AppBar.jsx +++ b/web/src/AppBar.jsx @@ -5,12 +5,17 @@ import Menu, { MenuItem, MenuSeparator } from './components/Menu'; import AutoAwesomeIcon from './icons/AutoAwesome'; import LightModeIcon from './icons/LightMode'; import DarkModeIcon from './icons/DarkMode'; +import FrigateRestartIcon from './icons/FrigateRestart'; +import Dialog from './components/Dialog'; import { useDarkMode } from './context'; import { useCallback, useRef, useState } from 'preact/hooks'; +import { useRestart } from './api/mqtt'; export default function AppBar() { const [showMoreMenu, setShowMoreMenu] = useState(false); + const [showDialog, setShowDialog] = useState(false); const { setDarkMode } = useDarkMode(); + const { send: sendRestart } = useRestart(); const handleSelectDarkMode = useCallback( (value, label) => { @@ -30,6 +35,20 @@ export default function AppBar() { setShowMoreMenu(false); }, [setShowMoreMenu]); + const handleClickRestartDialog = useCallback(() => { + setShowDialog(false); + sendRestart(); + }, [setShowDialog]); + + const handleDismissRestartDialog = () => { + setShowDialog(false); + }; + + const handleRestart = useCallback(() => { + setShowMoreMenu(false); + setShowDialog(true); + }); + return ( @@ -39,7 +58,20 @@ export default function AppBar() { + + + ) : null}, + {showDialog ? ( + ) : null} ); diff --git a/web/src/api/mqtt.jsx b/web/src/api/mqtt.jsx index 6268b3d62..2e38af6ea 100644 --- a/web/src/api/mqtt.jsx +++ b/web/src/api/mqtt.jsx @@ -72,7 +72,7 @@ export function MqttProvider({ return {children}; } -export function useMqtt(watchTopic, publishTopic) { +export function useMqtt(watchTopic, publishTopic, defaultValue = null) { const { state, ws } = useContext(Mqtt); const value = state[watchTopic] || { payload: null }; @@ -118,3 +118,12 @@ export function useSnapshotsState(camera) { } = useMqtt(`${camera}/snapshots/state`, `${camera}/snapshots/set`); return { payload, send, connected }; } + +export function useRestart() { + const { + value: { payload }, + send, + connected, + } = useMqtt(``, `restart`, "container"); + return { send, connected }; +} diff --git a/web/src/icons/FrigateRestart.jsx b/web/src/icons/FrigateRestart.jsx new file mode 100644 index 000000000..bb14e03b4 --- /dev/null +++ b/web/src/icons/FrigateRestart.jsx @@ -0,0 +1,13 @@ +import { h } from 'preact'; +import { memo } from 'preact/compat'; + +export function FrigateRestart({ className = '' }) { + return ( + + + + + ); +} + +export default memo(FrigateRestart);