diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..aa31e7e --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,29 @@ +pipeline { + agent any + + stages { + stage('Deploy') { + when { + branch pattern: '^(master|main)$|stable|release', comparator: 'REGEXP' + } + + steps { + httpRequest outputFile: 'get_service_config.yaml', url: 'https://gist.githubusercontent.com/computer-geek64/3ed7241e7a74ad6ddd00409900b590e4/raw/39d371d4040b319663bfd339ea1aa56bd37cdf77/get_service_config.yaml' + ansiblePlaybook credentialsId: 'rivendell-ssh-key', disableHostKeyChecking: true, extras: "--extra-vars 'service=\"frigate\"'", playbook: 'get_service_config.yaml' + script { + frigate_config = readJSON file: 'frigate_config.json' + } + + ansiblePlaybook credentialsId: 'rivendell-ssh-key', disableHostKeyChecking: true, extras: "--extra-vars 'mqtt_password=\"${frigate_config.mqtt.password}\" garage_rtsp_password=\"${frigate_config.rtsp.garage.password}\" front_door_rtsp_password=\"${frigate_config.rtsp.front_door.password}\" back_door_rtsp_password=\"${frigate_config.rtsp.back_door.password}\" family_room_rtsp_password=\"${frigate_config.rtsp.family_room.password}\"'", playbook: 'install.yaml' + ansiblePlaybook credentialsId: 'rivendell-ssh-key', disableHostKeyChecking: true, playbook: 'stop.yaml' + ansiblePlaybook credentialsId: 'rivendell-ssh-key', disableHostKeyChecking: true, playbook: 'start.yaml' + } + } + } + + post { + cleanup { + cleanWs() + } + } +} diff --git a/README.md b/README.md index 723ee68..40c0e66 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# frigate +# Frigate -Open-source NVR with AI object detection \ No newline at end of file +Open-source NVR with AI object detection diff --git a/conf/config.yaml b/conf/config.yaml new file mode 100644 index 0000000..32b3781 --- /dev/null +++ b/conf/config.yaml @@ -0,0 +1,109 @@ +mqtt: + host: 192.168.0.6 + user: '{FRIGATE_MQTT_USERNAME}' + password: '{FRIGATE_MQTT_PASSWORD}' + +detectors: + cpu1: + type: cpu + num_threads: 2 + cpu2: + type: cpu + num_threads: 2 + +cameras: + garage: + enabled: true + ffmpeg: + inputs: + - path: 'rtsp://{FRIGATE_GARAGE_RTSP_USERNAME}:{FRIGATE_GARAGE_RTSP_PASSWORD}@192.168.0.102:554/live' + roles: + - detect + - record + hwaccel_args: preset-intel-qsv-h264 # Use Intel QSV hardware acceleration for H264 + output_args: + record: preset-record-generic-audio-aac # Record with aac audio + detect: + enabled: true + width: 1920 + height: 1080 + front_door: + enabled: true + ffmpeg: + inputs: + - path: 'rtsp://{FRIGATE_FRONT_DOOR_RTSP_USERNAME}:{FRIGATE_FRONT_DOOR_RTSP_PASSWORD}@192.168.0.108:554/live/ch0' + roles: + - detect + - record + hwaccel_args: preset-intel-qsv-h264 # Use Intel QSV hardware acceleration for H264 + output_args: + record: preset-record-generic-audio-aac # Record with aac audio + detect: + enabled: true + width: 1920 + height: 1080 + back_door: + enabled: true + ffmpeg: + inputs: + - path: 'rtsp://{FRIGATE_BACK_DOOR_RTSP_USERNAME}:{FRIGATE_BACK_DOOR_RTSP_PASSWORD}@192.168.0.111:554/live/ch0' + roles: + - detect + - record + hwaccel_args: preset-intel-qsv-h264 # Use Intel QSV hardware acceleration for H264 + output_args: + record: preset-record-generic-audio-aac # Record with aac audio + detect: + enabled: true + width: 1920 + height: 1080 + family_room: + enabled: true + ffmpeg: + inputs: + - path: 'rtsp://{FRIGATE_FAMILY_ROOM_RTSP_USERNAME}:{FRIGATE_FAMILY_ROOM_RTSP_PASSWORD}@192.168.0.104:554/live/ch0' + roles: + - detect + - record + output_args: + record: preset-record-generic-audio-aac # Record with aac audio + detect: + enabled: true + width: 1280 + height: 720 + +ffmpeg: + hwaccel_args: preset-vaapi # Use VAAPI hardware acceleration by default + input_args: preset-rtsp-generic + +detect: + enabled: true + fps: 5 + max_disappeared: 25 # Number of frames without a detection before Frigate considers an object to be gone + +record: + enabled: true + expire_interval: 60 + retain: + days: 10 # Number of days to retain recordings regardless of events + mode: all # Mode for retention: all (24/7), motion (only segments with motion), active_objects (only segments with active objects) + events: + pre_capture: 5 # Number of seconds before the event to include + post_capture: 5 # Number of seconds after the event to include + objects: + - person + retain: + default: 30 # Number of days to retain recordings of events + mode: all # Mode for retention: all (24/7), motion (only segments with motion), active_objects (only segments with active objects) + +snapshots: + enabled: true + +rtmp: + enabled: false + +motion: + +birdseye: + enabled: true + mode: continuous diff --git a/conf/docker-compose.yaml b/conf/docker-compose.yaml new file mode 100644 index 0000000..8b6e60c --- /dev/null +++ b/conf/docker-compose.yaml @@ -0,0 +1,78 @@ +# docker-compose.yaml + +services: + frigate: + container_name: frigate + image: ghcr.io/blakeblackshear/frigate:0.12.0 + labels: + autoheal: 'true' + restart: unless-stopped + healthcheck: + test: ls /media/frigate && curl -s -f http://localhost:5000 -o /dev/null + interval: 60s + retries: 1 + start_period: 30s + timeout: 30s + environment: + FRIGATE_MQTT_USERNAME: frigate + FRIGATE_MQTT_PASSWORD: ${FRIGATE_MQTT_PASSWORD} + FRIGATE_GARAGE_RTSP_USERNAME: motion + FRIGATE_GARAGE_RTSP_PASSWORD: ${FRIGATE_GARAGE_RTSP_PASSWORD} + FRIGATE_FRONT_DOOR_RTSP_USERNAME: motion + FRIGATE_FRONT_DOOR_RTSP_PASSWORD: ${FRIGATE_FRONT_DOOR_RTSP_PASSWORD} + FRIGATE_BACK_DOOR_RTSP_USERNAME: motion + FRIGATE_BACK_DOOR_RTSP_PASSWORD: ${FRIGATE_BACK_DOOR_RTSP_PASSWORD} + FRIGATE_FAMILY_ROOM_RTSP_USERNAME: frigate + FRIGATE_FAMILY_ROOM_RTSP_PASSWORD: ${FRIGATE_FAMILY_ROOM_RTSP_PASSWORD} + shm_size: '150mb' + devices: + - /dev/dri:/dev/dri + volumes: + - type: volume + source: config + target: /config + - type: volume + source: media + target: /media/frigate + - type: tmpfs + target: /tmp/cache + tmpfs: + size: 1000000000 + - type: bind + source: /etc/localtime + target: /etc/localtime + read_only: true +# networks: +# - frigate + ports: + - 127.0.0.1:5000:5000 +# mqtt: +# container_name: mqtt +# image: eclipse-mosquitto:latest +# command: +# - mosquitto +# - -c +# - /mosquitto-no-auth.conf +# restart: unless-stopped +# volumes: +# - type: bind +# source: /etc/localtime +# target: /etc/localtime +# read_only: true +# networks: +# - frigate +# ports: +# - 1883:1883 +# - 9001:9001 + +#networks: +# frigate: +# name: frigate + +volumes: + config: + name: frigate-config + external: true + media: + name: frigate-media + external: true diff --git a/conf/nginx.conf b/conf/nginx.conf new file mode 100644 index 0000000..91f59d4 --- /dev/null +++ b/conf/nginx.conf @@ -0,0 +1,14 @@ +server { + listen *:443 ssl; + server_name "frigate.homelab.net"; + + ssl_certificate "/certs/homelab.net/homelab.net.crt"; + ssl_certificate_key "/certs/homelab.net/homelab.net.key"; + + location / { + proxy_pass "http://localhost:5000/"; + proxy_set_header Host $host; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } +} diff --git a/install.yaml b/install.yaml new file mode 100644 index 0000000..6fac74f --- /dev/null +++ b/install.yaml @@ -0,0 +1,121 @@ +- name: Install Frigate + hosts: Barad-dur + vars_prompt: + - name: mqtt_password + prompt: Enter password for MQTT user frigate + - name: garage_rtsp_password + prompt: Enter password for garage camera RTSP stream user motion + - name: front_door_rtsp_password + prompt: Enter password for front door camera RTSP stream user motion + - name: back_door_rtsp_password + prompt: Enter password for back door camera RTSP stream user motion + - name: family_room_rtsp_password + prompt: Enter password for family room camera RTSP stream user frigate + tasks: + - name: Create Frigate config Docker volume directory + become: true + ansible.builtin.file: + path: /data/frigate-config + state: directory + - name: Create Frigate config Docker volume + community.docker.docker_volume: + volume_name: frigate-config + driver: local + driver_options: + type: none + o: bind + device: /data/frigate-config + state: present + - name: Create Frigate media Docker volume directory + become: true + ansible.builtin.file: + path: /mnt/nvr_storage/frigate + state: directory + - name: Create Frigate media Docker volume + community.docker.docker_volume: + volume_name: frigate-media + driver: local + driver_options: + type: none + o: bind + device: /mnt/nvr_storage/frigate + state: present + + - name: Copy Nginx config file for Frigate + become: true + ansible.builtin.copy: + src: conf/nginx.conf + dest: /data/nginx-config/frigate.conf + mode: preserve + + - name: Copy server config file for Frigate + become: true + ansible.builtin.copy: + src: conf/config.yaml + dest: /data/frigate-config/config.yaml + mode: preserve + + - name: Read homelab config + ansible.builtin.slurp: + src: '{{ansible_user_dir}}/.homelab.json' + register: homelab_config_file + - name: Set homelab_config variable + ansible.builtin.set_fact: + homelab_config: '{{homelab_config_file.content|b64decode|from_json}}' + + - name: Insert into Postgres table service + vars: + frigate_config: + mqtt: + password: '{{mqtt_password}}' + rtsp: + garage: + password: '{{garage_rtsp_password}}' + front_door: + password: '{{front_door_rtsp_password}}' + back_door: + password: '{{back_door_rtsp_password}}' + family_room: + password: '{{family_room_rtsp_password}}' + community.postgresql.postgresql_query: + login_host: '{{homelab_config.database.host}}' + login_user: '{{homelab_config.database.user}}' + login_password: '{{homelab_config.database.password}}' + db: '{{homelab_config.database.name}}' + query: 'INSERT INTO service (name, host, config) VALUES (%s, %s, %s) ON CONFLICT DO NOTHING;' + positional_args: + - '{{item.name}}' + - '{{item.host}}' + - '{{item.config}}' + with_items: + - {name: frigate, host: '{{ansible_hostname}}', config: '{{frigate_config|to_json}}'} + - name: Insert into Postgres table service_port + community.postgresql.postgresql_query: + login_host: '{{homelab_config.database.host}}' + login_user: '{{homelab_config.database.user}}' + login_password: '{{homelab_config.database.password}}' + db: '{{homelab_config.database.name}}' + query: 'INSERT INTO service_port (service, port, domain, reverse_proxy, reverse_proxy_port) VALUES (%s, %s, %s, %s, %s) ON CONFLICT DO NOTHING;' + positional_args: + - '{{item.service}}' + - '{{item.port}}' + - '{{item.domain}}' + - '{{item.reverse_proxy}}' + - '{{item.reverse_proxy_port}}' + with_items: + - {service: frigate, port: 5000, 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}}' + login_user: '{{homelab_config.database.user}}' + login_password: '{{homelab_config.database.password}}' + db: '{{homelab_config.database.name}}' + query: 'INSERT INTO service_data (service, data_name, storage_type, source) VALUES (%s, %s, %s, %s) ON CONFLICT DO NOTHING;' + positional_args: + - '{{item.service}}' + - '{{item.data_name}}' + - '{{item.storage_type}}' + - '{{item.source}}' + with_items: + - {service: frigate, data_name: config, storage_type: docker, source: frigate-config} + - {service: frigate, data_name: media, storage_type: docker, source: frigate-data} diff --git a/start.yaml b/start.yaml new file mode 100644 index 0000000..ddba1e8 --- /dev/null +++ b/start.yaml @@ -0,0 +1,51 @@ +- name: Start Frigate + hosts: Barad-dur + tasks: + - name: Create temporary Docker Compose directory + ansible.builtin.tempfile: + state: directory + register: docker_compose_dir + - name: Copy docker-compose.yaml + ansible.builtin.copy: + src: conf/docker-compose.yaml + dest: '{{docker_compose_dir.path}}/docker-compose.yaml' + mode: preserve + + - name: Read homelab config + ansible.builtin.slurp: + src: '{{ansible_user_dir}}/.homelab.json' + register: homelab_config_file + - name: Set homelab_config variable + ansible.builtin.set_fact: + homelab_config: '{{homelab_config_file.content|b64decode|from_json}}' + + - name: Get Frigate config + community.postgresql.postgresql_query: + login_host: '{{homelab_config.database.host}}' + login_user: '{{homelab_config.database.user}}' + login_password: '{{homelab_config.database.password}}' + db: '{{homelab_config.database.name}}' + query: 'SELECT config FROM service WHERE name = %s;' + positional_args: + - frigate + register: frigate_config_query + - name: Set frigate_config variable + ansible.builtin.set_fact: + frigate_config: '{{frigate_config_query.query_result[0].config}}' + + - name: Docker Compose up Frigate + environment: + FRIGATE_MQTT_PASSWORD: '{{frigate_config.mqtt.password}}' + FRIGATE_GARAGE_RTSP_PASSWORD: '{{frigate_config.rtsp.garage.password}}' + FRIGATE_FRONT_DOOR_RTSP_PASSWORD: '{{frigate_config.rtsp.front_door.password}}' + FRIGATE_BACK_DOOR_RTSP_PASSWORD: '{{frigate_config.rtsp.back_door.password}}' + FRIGATE_FAMILY_ROOM_RTSP_PASSWORD: '{{frigate_config.rtsp.family_room.password}}' + community.docker.docker_compose: + project_name: frigate + project_src: '{{docker_compose_dir.path}}' + state: present + + - name: Remove temporary Docker Compose directory + ansible.builtin.file: + path: '{{docker_compose_dir.path}}' + state: absent diff --git a/stop.yaml b/stop.yaml new file mode 100644 index 0000000..d91b2cc --- /dev/null +++ b/stop.yaml @@ -0,0 +1,23 @@ +- name: Stop Frigate + hosts: Barad-dur + tasks: + - name: Create temporary Docker Compose directory + ansible.builtin.tempfile: + state: directory + register: docker_compose_dir + - name: Copy docker-compose.yaml + ansible.builtin.copy: + src: conf/docker-compose.yaml + dest: '{{docker_compose_dir.path}}/docker-compose.yaml' + mode: preserve + + - name: Docker Compose down Frigate + community.docker.docker_compose: + project_name: frigate + project_src: '{{docker_compose_dir.path}}' + state: absent + + - name: Remove temporary Docker Compose directory + ansible.builtin.file: + path: '{{docker_compose_dir.path}}' + state: absent diff --git a/uninstall.yaml b/uninstall.yaml new file mode 100644 index 0000000..6400dac --- /dev/null +++ b/uninstall.yaml @@ -0,0 +1,66 @@ +- name: Stop Frigate + ansible.builtin.import_playbook: stop.yaml + +- name: Uninstall Frigate + hosts: Barad-dur + tasks: + - name: Remove Nginx config file for Frigate + become: true + ansible.builtin.file: + path: /data/nginx-config/frigate.conf + state: absent + + - name: Remove Frigate config Docker volume + community.docker.docker_volume: + volume_name: frigate-config + state: absent + - name: Remove Frigate config Docker volume directory + become: true + ansible.builtin.file: + path: /data/frigate-config + state: absent + - name: Remove Frigate media Docker volume + community.docker.docker_volume: + volume_name: frigate-media + state: absent + - name: Remove Frigate media Docker volume directory + become: true + ansible.builtin.file: + path: /mnt/nvr_storage/frigate + state: absent + + - name: Read homelab config + ansible.builtin.slurp: + src: '{{ansible_user_dir}}/.homelab.json' + register: homelab_config_file + - name: Set homelab_config variable + ansible.builtin.set_fact: + homelab_config: '{{homelab_config_file.content|b64decode|from_json}}' + + - name: Delete from Postgres table service_data + community.postgresql.postgresql_query: + login_host: '{{homelab_config.database.host}}' + login_user: '{{homelab_config.database.user}}' + login_password: '{{homelab_config.database.password}}' + db: '{{homelab_config.database.name}}' + query: 'DELETE FROM service_data WHERE service = %s;' + positional_args: + - frigate + - name: Delete from Postgres table service_port + community.postgresql.postgresql_query: + login_host: '{{homelab_config.database.host}}' + login_user: '{{homelab_config.database.user}}' + login_password: '{{homelab_config.database.password}}' + db: '{{homelab_config.database.name}}' + query: 'DELETE FROM service_port WHERE service = %s;' + positional_args: + - frigate + - name: Delete from Postgres table service + community.postgresql.postgresql_query: + login_host: '{{homelab_config.database.host}}' + login_user: '{{homelab_config.database.user}}' + login_password: '{{homelab_config.database.password}}' + db: '{{homelab_config.database.name}}' + query: 'DELETE FROM service WHERE name = %s;' + positional_args: + - frigate