From c69299d659f6e235a02cf7f737a3bcd0f18c0dde Mon Sep 17 00:00:00 2001 From: Blake Blackshear Date: Wed, 23 Dec 2020 08:54:08 -0600 Subject: [PATCH] enable turning clips on and off via mqtt --- frigate/app.py | 2 +- frigate/config.py | 2 +- frigate/events.py | 3 +++ frigate/mqtt.py | 48 +++++++++++++++++++++++++++++++++++++++-------- 4 files changed, 45 insertions(+), 10 deletions(-) diff --git a/frigate/app.py b/frigate/app.py index 528e1497b..dc36fde5f 100644 --- a/frigate/app.py +++ b/frigate/app.py @@ -119,7 +119,7 @@ class FrigateApp(): self.flask_app = create_app(self.config, self.db, self.camera_metrics, self.detectors, self.detected_frames_processor) def init_mqtt(self): - self.mqtt_client = create_mqtt_client(self.config.mqtt) + self.mqtt_client = create_mqtt_client(self.config) def start_detectors(self): model_shape = (self.config.model.height, self.config.model.width) diff --git a/frigate/config.py b/frigate/config.py index 369e3a512..d455f2187 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -806,7 +806,7 @@ class CameraConfig(): ffmpeg_output_args = self.ffmpeg.output_args['rtmp'] + [ f"rtmp://127.0.0.1/live/{self.name}" ] + ffmpeg_output_args - if 'clips' in ffmpeg_input.roles and self.clips.enabled: + if 'clips' in ffmpeg_input.roles: ffmpeg_output_args = self.ffmpeg.output_args['clips'] + [ f"{os.path.join(CACHE_DIR, self.name)}-%Y%m%d%H%M%S.mp4" ] + ffmpeg_output_args diff --git a/frigate/events.py b/frigate/events.py index 0383455f9..86342e9b8 100644 --- a/frigate/events.py +++ b/frigate/events.py @@ -102,6 +102,7 @@ class EventProcessor(threading.Thread): sorted_clips = sorted([c for c in self.cached_clips.values() if c['camera'] == camera], key = lambda i: i['start_time']) while len(sorted_clips) == 0 or sorted_clips[-1]['start_time'] + sorted_clips[-1]['duration'] < event_data['end_time']+post_capture: + logger.debug(f"No cache clips for {camera}. Waiting...") time.sleep(5) self.refresh_cache() # get all clips from the camera with the event sorted @@ -162,12 +163,14 @@ class EventProcessor(threading.Thread): self.refresh_cache() continue + logger.debug(f"Event received: {event_type} {camera} {event_data['id']}") self.refresh_cache() clips_config = self.config.cameras[camera].clips # if save clips is not enabled for this camera, just continue if not clips_config.enabled: + logger.debug(f"Clips not enabled for {camera}. Not making a clip.") if event_type == 'end': self.event_processed_queue.put((event_data['id'], camera)) continue diff --git a/frigate/mqtt.py b/frigate/mqtt.py index 962015816..5d79c334e 100644 --- a/frigate/mqtt.py +++ b/frigate/mqtt.py @@ -3,12 +3,31 @@ import threading import paho.mqtt.client as mqtt -from frigate.config import MqttConfig +from frigate.config import FrigateConfig logger = logging.getLogger(__name__) -def create_mqtt_client(config: MqttConfig): - client = mqtt.Client(client_id=config.client_id) +def create_mqtt_client(config: FrigateConfig): + mqtt_config = config.mqtt + + def on_clips_command(client, userdata, message): + payload = message.payload.decode() + logger.debug(f"on_clips_toggle: {message.topic} {payload}") + + camera_name = message.topic.split('/')[-3] + command = message.topic.split('/')[-1] + + if payload == 'ON': + config.cameras[camera_name].clips._enabled = True + elif payload == 'OFF': + config.cameras[camera_name].clips._enabled = False + else: + logger.warning(f"Received unsupported value at {message.topic}: {payload}") + + if command == "set": + state_topic = f"{message.topic[:-4]}/state" + client.publish(state_topic, payload, retain=True) + def on_connect(client, userdata, flags, rc): threading.current_thread().name = "mqtt" if rc != 0: @@ -22,15 +41,28 @@ def create_mqtt_client(config: MqttConfig): logger.error("Unable to connect to MQTT: Connection refused. Error code: " + str(rc)) logger.info("MQTT connected") - client.publish(config.topic_prefix+'/available', 'online', retain=True) + client.publish(mqtt_config.topic_prefix+'/available', 'online', retain=True) + + client = mqtt.Client(client_id=mqtt_config.client_id) client.on_connect = on_connect - client.will_set(config.topic_prefix+'/available', payload='offline', qos=1, retain=True) - if not config.user is None: - client.username_pw_set(config.user, password=config.password) + client.will_set(mqtt_config.topic_prefix+'/available', payload='offline', qos=1, retain=True) + + # register callbacks + for name in config.cameras.keys(): + clips_topic = f"{mqtt_config.topic_prefix}/{name}/clips/#" + client.message_callback_add(clips_topic, on_clips_command) + + if not mqtt_config.user is None: + client.username_pw_set(mqtt_config.user, password=mqtt_config.password) try: - client.connect(config.host, config.port, 60) + client.connect(mqtt_config.host, mqtt_config.port, 60) except Exception as e: logger.error(f"Unable to connect to MQTT server: {e}") raise + client.loop_start() + + clips_topic = f"{mqtt_config.topic_prefix}/+/clips/#" + client.subscribe(clips_topic) + return client