Added webcontrol API
This commit is contained in:
		
							parent
							
								
									a13f099e14
								
							
						
					
					
						commit
						ce6b363d4e
					
				| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
mqtt:
 | 
			
		||||
  host: 192.168.0.6
 | 
			
		||||
  host: mqtt
 | 
			
		||||
  user: '{FRIGATE_MQTT_USERNAME}'
 | 
			
		||||
  password: '{FRIGATE_MQTT_PASSWORD}'
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -45,7 +45,9 @@ services:
 | 
			
		|||
#    networks:
 | 
			
		||||
#    - frigate
 | 
			
		||||
    ports:
 | 
			
		||||
    - 127.0.0.1:5000:5000
 | 
			
		||||
    - 127.0.0.1:10000:5000
 | 
			
		||||
    extra_hosts:
 | 
			
		||||
    - mqtt:192.168.0.6
 | 
			
		||||
  notify:
 | 
			
		||||
    container_name: frigate-notify
 | 
			
		||||
    image: frigate-notify:latest
 | 
			
		||||
| 
						 | 
				
			
			@ -63,6 +65,32 @@ services:
 | 
			
		|||
      source: /etc/localtime
 | 
			
		||||
      target: /etc/localtime
 | 
			
		||||
      read_only: true
 | 
			
		||||
    extra_hosts:
 | 
			
		||||
    - mqtt:192.168.0.6
 | 
			
		||||
  webcontrol:
 | 
			
		||||
    container_name: frigate-webcontrol
 | 
			
		||||
    image: frigate-webcontrol:latest
 | 
			
		||||
    labels:
 | 
			
		||||
      autoheal: 'true'
 | 
			
		||||
    restart: unless-stopped
 | 
			
		||||
    healthcheck:
 | 
			
		||||
      test: curl -s -f http://localhost -o /dev/null
 | 
			
		||||
      interval: 60s
 | 
			
		||||
      retries: 1
 | 
			
		||||
      start_period: 30s
 | 
			
		||||
      timeout: 30s
 | 
			
		||||
    environment:
 | 
			
		||||
      MQTT_USERNAME: frigate
 | 
			
		||||
      MQTT_PASSWORD: ${MQTT_PASSWORD}
 | 
			
		||||
    volumes:
 | 
			
		||||
    - type: bind
 | 
			
		||||
      source: /etc/localtime
 | 
			
		||||
      target: /etc/localtime
 | 
			
		||||
      read_only: true
 | 
			
		||||
    ports:
 | 
			
		||||
    - 127.0.0.1:10001:80
 | 
			
		||||
    extra_hosts:
 | 
			
		||||
    - mqtt:192.168.0.6
 | 
			
		||||
#  mqtt:
 | 
			
		||||
#    container_name: mqtt
 | 
			
		||||
#    image: eclipse-mosquitto:latest
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,9 +6,13 @@ server {
 | 
			
		|||
    ssl_certificate_key "/certs/homelab.net/homelab.net.key";
 | 
			
		||||
 | 
			
		||||
    location / {
 | 
			
		||||
        proxy_pass "http://localhost:5000/";
 | 
			
		||||
        proxy_pass "http://localhost:10000/";
 | 
			
		||||
        proxy_set_header Host $host;
 | 
			
		||||
        proxy_set_header Upgrade $http_upgrade;
 | 
			
		||||
        proxy_set_header Connection "upgrade";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    location /webcontrol/ {
 | 
			
		||||
        proxy_pass "http://localhost:10001/";
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										30
									
								
								install.yaml
								
								
								
								
							
							
						
						
									
										30
									
								
								install.yaml
								
								
								
								
							| 
						 | 
				
			
			@ -55,7 +55,7 @@
 | 
			
		|||
      dest: /data/frigate-config/config.yaml
 | 
			
		||||
      mode: preserve
 | 
			
		||||
 | 
			
		||||
  - name: Create temporary Docker build directory
 | 
			
		||||
  - name: Create temporary Docker build directory for frigate-notify
 | 
			
		||||
    ansible.builtin.tempfile:
 | 
			
		||||
      state: directory
 | 
			
		||||
    register: docker_build_dir
 | 
			
		||||
| 
						 | 
				
			
			@ -73,7 +73,30 @@
 | 
			
		|||
      source: build
 | 
			
		||||
      force_source: true
 | 
			
		||||
      state: present
 | 
			
		||||
  - name: Remove temporary Docker build directory
 | 
			
		||||
  - name: Remove temporary Docker build directory for frigate-notify
 | 
			
		||||
    ansible.builtin.file:
 | 
			
		||||
      path: '{{docker_build_dir.path}}'
 | 
			
		||||
      state: absent
 | 
			
		||||
 | 
			
		||||
  - name: Create temporary Docker build directory for frigate-webcontrol
 | 
			
		||||
    ansible.builtin.tempfile:
 | 
			
		||||
      state: directory
 | 
			
		||||
    register: docker_build_dir
 | 
			
		||||
  - name: Copy Docker build directory
 | 
			
		||||
    ansible.builtin.copy:
 | 
			
		||||
      src: webcontrol/
 | 
			
		||||
      dest: '{{docker_build_dir.path}}'
 | 
			
		||||
      mode: preserve
 | 
			
		||||
  - name: Build frigate-webcontrol Docker image
 | 
			
		||||
    ansible.builtin.docker_image:
 | 
			
		||||
      build:
 | 
			
		||||
        path: '{{docker_build_dir.path}}'
 | 
			
		||||
      name: frigate-webcontrol
 | 
			
		||||
      tag: latest
 | 
			
		||||
      source: build
 | 
			
		||||
      force_source: true
 | 
			
		||||
      state: present
 | 
			
		||||
  - name: Remove temporary Docker build directory for frigate-webcontrol
 | 
			
		||||
    ansible.builtin.file:
 | 
			
		||||
      path: '{{docker_build_dir.path}}'
 | 
			
		||||
      state: absent
 | 
			
		||||
| 
						 | 
				
			
			@ -126,7 +149,8 @@
 | 
			
		|||
      - '{{item.reverse_proxy}}'
 | 
			
		||||
      - '{{item.reverse_proxy_port}}'
 | 
			
		||||
    with_items:
 | 
			
		||||
    - {service: frigate, port: 5000, domain: null, reverse_proxy: nginx_barad-dur, reverse_proxy_port: 443}
 | 
			
		||||
    - {service: frigate, port: 10000, domain: null, reverse_proxy: nginx_barad-dur, reverse_proxy_port: 443}
 | 
			
		||||
    - {service: frigate, port: 10001, domain: null, reverse_proxy: nginx_barad-dur, reverse_proxy_port: 443}
 | 
			
		||||
  - name: Insert into Postgres table service_data
 | 
			
		||||
    community.postgresql.postgresql_query:
 | 
			
		||||
      login_host: '{{homelab_config.database.host}}'
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,6 @@ ENTRYPOINT ["python3", "mqtt.py"]
 | 
			
		|||
RUN pip3 install --upgrade pip
 | 
			
		||||
 | 
			
		||||
COPY requirements.txt .
 | 
			
		||||
RUN pip install -r requirements.txt
 | 
			
		||||
RUN pip3 install -r requirements.txt
 | 
			
		||||
 | 
			
		||||
COPY src .
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,12 +24,12 @@ def on_message(client, userdata, message):
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
def subscribe():
 | 
			
		||||
    client = mqtt.Client('frigate_notifications')
 | 
			
		||||
    client = mqtt.Client()
 | 
			
		||||
    client.username_pw_set(os.environ['MQTT_USERNAME'], password=os.environ['MQTT_PASSWORD'])
 | 
			
		||||
    client.on_connect = on_connect
 | 
			
		||||
    client.on_message = on_message
 | 
			
		||||
 | 
			
		||||
    client.connect(host='192.168.0.6', port=1883)
 | 
			
		||||
    client.connect(host='mqtt', port=1883)
 | 
			
		||||
    client.loop_forever()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,7 @@
 | 
			
		|||
import json
 | 
			
		||||
import requests
 | 
			
		||||
from datetime import datetime, timedelta
 | 
			
		||||
 | 
			
		||||
import requests
 | 
			
		||||
 | 
			
		||||
last_notification_time = {}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -30,8 +30,15 @@ def send_notification(event_id, camera, object_label, score, priority=3):
 | 
			
		|||
            {
 | 
			
		||||
                'action': 'http',
 | 
			
		||||
                'label': 'Disable (30m)',
 | 
			
		||||
                'url': 'https://www.google.com/',
 | 
			
		||||
                'method': 'GET',
 | 
			
		||||
                'url': f'https://frigate.homelab.net/webcontrol/camera/{camera}/detect',
 | 
			
		||||
                'method': 'POST',
 | 
			
		||||
                'headers': {
 | 
			
		||||
                    'Content-Type': 'application/json'
 | 
			
		||||
                },
 | 
			
		||||
                'body': json.dumps({
 | 
			
		||||
                    'value': False,
 | 
			
		||||
                    'duration': 30
 | 
			
		||||
                }),
 | 
			
		||||
                'clear': True
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
| 
						 | 
				
			
			@ -49,9 +56,15 @@ def send_notification(event_id, camera, object_label, score, priority=3):
 | 
			
		|||
            {
 | 
			
		||||
                'action': 'http',
 | 
			
		||||
                'label': 'DBL (30m)',
 | 
			
		||||
                'url': 'https://www.google.com/',
 | 
			
		||||
                'method': 'GET',
 | 
			
		||||
                'clear': True
 | 
			
		||||
                'url': f'https://frigate.homelab.net/webcontrol/camera/{camera}/detect',
 | 
			
		||||
                'method': 'POST',
 | 
			
		||||
                'headers': {
 | 
			
		||||
                    'Content-Type': 'application/json'
 | 
			
		||||
                },
 | 
			
		||||
                'body': json.dumps({
 | 
			
		||||
                    'value': False,
 | 
			
		||||
                    'duration': 30
 | 
			
		||||
                })
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    })
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,11 @@
 | 
			
		|||
FROM python:3.11
 | 
			
		||||
WORKDIR /code
 | 
			
		||||
 | 
			
		||||
ENTRYPOINT ["python3", "server.py"]
 | 
			
		||||
 | 
			
		||||
RUN pip3 install --upgrade pip
 | 
			
		||||
 | 
			
		||||
COPY requirements.txt .
 | 
			
		||||
RUN pip3 install -r requirements.txt
 | 
			
		||||
 | 
			
		||||
COPY src .
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,2 @@
 | 
			
		|||
flask==2.3.2
 | 
			
		||||
paho-mqtt==1.6.1
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,37 @@
 | 
			
		|||
import os
 | 
			
		||||
from time import sleep
 | 
			
		||||
from threading import Thread
 | 
			
		||||
 | 
			
		||||
from flask import Blueprint, request, jsonify
 | 
			
		||||
import paho.mqtt.publish as mqtt_publish
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
blueprint = Blueprint('detection', __name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def set_camera_detection(camera: str, value: bool, delay: int = 0) -> None:
 | 
			
		||||
    sleep(delay)
 | 
			
		||||
 | 
			
		||||
    mqtt_publish.single(f'frigate/{camera}/detect/set', 'ON' if value else 'OFF', hostname='mqtt', port=1883, auth={'username': os.environ['MQTT_USERNAME'], 'password': os.environ['MQTT_PASSWORD']})
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@blueprint.route('/camera/<string:camera>/detect', methods=['POST'])
 | 
			
		||||
def camera_detect_POST(camera):
 | 
			
		||||
    if not request.json:
 | 
			
		||||
        return jsonify({
 | 
			
		||||
            'status': 'failure',
 | 
			
		||||
            'description': 'Request body needs to be in JSON format'
 | 
			
		||||
        }), 400
 | 
			
		||||
 | 
			
		||||
    value = request.json.get('value', True)
 | 
			
		||||
    set_camera_detection(camera, value)
 | 
			
		||||
 | 
			
		||||
    duration = request.json.get('duration', 0)
 | 
			
		||||
    if duration > 0:
 | 
			
		||||
        # Start sleeping thread to revert value after duration
 | 
			
		||||
        thread = Thread(target=set_camera_detection, args=(camera, not value, duration * 60))
 | 
			
		||||
        thread.start()
 | 
			
		||||
 | 
			
		||||
    return jsonify({
 | 
			
		||||
        'status': 'success'
 | 
			
		||||
    }), 200
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,20 @@
 | 
			
		|||
from flask import Flask, jsonify
 | 
			
		||||
 | 
			
		||||
import detection
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
app = Flask(__name__)
 | 
			
		||||
app.register_blueprint(detection.blueprint)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@app.route('/', methods=['GET'])
 | 
			
		||||
def home_GET():
 | 
			
		||||
    return jsonify({
 | 
			
		||||
        'status': 'success',
 | 
			
		||||
        'name': 'webcontrol',
 | 
			
		||||
        'description': 'This is a custom webcontrol API for Frigate that allows minimal control over the NVR system through an HTTP API'
 | 
			
		||||
    }), 200
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    app.run(host='0.0.0.0', port=80, debug=False)
 | 
			
		||||
		Loading…
	
		Reference in New Issue