diff --git a/group_vars/all b/group_vars/all
index b5178a6..ba7b9dd 100644
--- a/group_vars/all
+++ b/group_vars/all
@@ -124,6 +124,9 @@ http_pfx_gitea: /git
# URL prefix of LDAP-Account-Manager (web UI for LDAP).
http_pfx_lam: /account
+# URL prefix of Motion (video surveillance).
+http_pfx_motion: /netcam
+
# URL prefix of Movim (XMPP web client).
http_pfx_movim: /social
@@ -308,6 +311,32 @@ media_minidlna_conf: |
root_container=B
friendly_name=HomeMedia
+# Motion data directory
+motion_data: /var/lib/motion
+motion_cloud_url: 'https://www.mediafire.com/'
+motion_cloud_login: login
+motion_cloud_password: password
+motion_cloud_id: app_id_xxxxx
+motion_cloud_key: xxxxxxxxxx…xxxxxxxxxx
+motion_email_recipient: hostmaster@localhost
+motion_cameras: '[
+ {
+ "id": 1, "name": "street door",
+ "url": "rtsp://user:password@street.example.org:554/videoMain",
+ "width": 640, "height": 360,
+ "mask_file": "example_mask_640_360.pgm",
+ "framerate": 5
+ },
+ {
+ "id": 2, "name": "garden door",
+ "url": "rtsp://user:password@garden.example.org:554/videoMain",
+ "width": 640, "height": 360,
+ "mask_file": null,
+ "framerate": 5
+ }
+ ]'
+motion_web_title: "Video surveillance"
+
# Name of the Movim database in PostgreSQL.
movim_db: movim
diff --git a/roles/dmz_motion_front/handlers/main.yml b/roles/dmz_motion_front/handlers/main.yml
new file mode 100644
index 0000000..8f91f95
--- /dev/null
+++ b/roles/dmz_motion_front/handlers/main.yml
@@ -0,0 +1,10 @@
+---
+# The home-server project produces a multi-purpose setup using Ansible.
+# Copyright © 2018 Y. Gablin, under the GPL-3.0-or-later license.
+# Full licensing information in the LICENSE file, or gnu.org/licences/gpl-3.0.txt if the file is missing.
+
+- name: restart nginx.service
+ systemd:
+ daemon_reload: true
+ name: nginx.service
+ state: restarted
diff --git a/roles/dmz_motion_front/meta.OK/main.yml b/roles/dmz_motion_front/meta.OK/main.yml
new file mode 100644
index 0000000..7f3de13
--- /dev/null
+++ b/roles/dmz_motion_front/meta.OK/main.yml
@@ -0,0 +1,7 @@
+---
+# The home-server project produces a multi-purpose setup using Ansible.
+# Copyright © 2018 Y. Gablin, under the GPL-3.0-or-later license.
+# Full licensing information in the LICENSE file, or gnu.org/licences/gpl-3.0.txt if the file is missing.
+
+dependencies:
+ - role: dmz_nginx
diff --git a/roles/dmz_motion_front/tasks/main.yml b/roles/dmz_motion_front/tasks/main.yml
new file mode 100644
index 0000000..68ee7e8
--- /dev/null
+++ b/roles/dmz_motion_front/tasks/main.yml
@@ -0,0 +1,56 @@
+---
+# The home-server project produces a multi-purpose setup using Ansible.
+# Copyright © 2018 Y. Gablin, under the GPL-3.0-or-later license.
+# Full licensing information in the LICENSE file, or gnu.org/licences/gpl-3.0.txt if the file is missing.
+
+- name: create a directory for the Motion web page
+ file:
+ name: /srv/http/motion
+ state: directory
+ mode: 0750
+ owner: root
+ group: http
+
+- name: send the feedback and control web page for Motion
+ template:
+ src: templates/index.html.j2
+ dest: /srv/http/motion/index.html
+ mode: 0640
+ owner: root
+ group: http
+
+- name: configure nginx for Motion
+ copy:
+ content: |
+ location {{http_pfx_motion}}/ {
+ alias /srv/http/motion/;
+ index index.html;
+ }
+ location {{http_pfx_motion}}/control/ {
+ proxy_pass http://unix:/run/shared_sockets/motion_control.socket:/;
+ proxy_buffering off;
+ proxy_cache off;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ }
+ location {{http_pfx_motion}}/camera/ {
+ proxy_pass http://unix:/run/shared_sockets/motion_stream.socket:/;
+ proxy_buffering off;
+ proxy_cache off;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ }
+ dest: /etc/nginx/inc.d/motion.https.inc
+ mode: 0440
+ owner: http
+ group: http
+ notify:
+ - restart nginx.service
+
+### LOCAL COMMIT ⇒ ###
+- name: commit local changes
+ include_role: name=etckeeper.inc allow_duplicates=true tasks_from=local.yml
+ vars:
+ msg: Gitea
+### ⇐ LOCAL COMMIT ###
+- meta: flush_handlers
diff --git a/roles/dmz_motion_front/templates/index.html.j2 b/roles/dmz_motion_front/templates/index.html.j2
new file mode 100644
index 0000000..db4b813
--- /dev/null
+++ b/roles/dmz_motion_front/templates/index.html.j2
@@ -0,0 +1,103 @@
+
+
+
+
+ {{motion_web_title}}
+
+
+
+
+ {{motion_web_title}}
+{% for camera in (motion_cameras | from_json) %}
+
+{% endfor %}
+
+
+
+
+
+
+
+
+
+
+
diff --git a/roles/front_run/meta.OK/main.yml b/roles/front_run/meta.OK/main.yml
index bbfb196..5bed625 100644
--- a/roles/front_run/meta.OK/main.yml
+++ b/roles/front_run/meta.OK/main.yml
@@ -8,6 +8,7 @@ dependencies:
- role: dovecot
- role: front
- role: ihmgit_back
+ - role: motion_back
- role: movim_back
- role: nextcloud_back
- role: postgresql
diff --git a/roles/motion_back/files/example_mask_640_360.pgm b/roles/motion_back/files/example_mask_640_360.pgm
new file mode 100644
index 0000000..9b90e23
Binary files /dev/null and b/roles/motion_back/files/example_mask_640_360.pgm differ
diff --git a/roles/motion_back/handlers/main.yml b/roles/motion_back/handlers/main.yml
new file mode 100644
index 0000000..a92a1dc
--- /dev/null
+++ b/roles/motion_back/handlers/main.yml
@@ -0,0 +1,22 @@
+---
+# The home-server project produces a multi-purpose setup using Ansible.
+# Copyright © 2018 Y. Gablin, under the GPL-3.0-or-later license.
+# Full licensing information in the LICENSE file, or gnu.org/licences/gpl-3.0.txt if the file is missing.
+
+- name: restart motion.service
+ systemd:
+ daemon_reload: true
+ name: motion.service
+ state: restarted
+
+- name: restart socat-unix-to-tcp4@-run-shared_sockets-motion_control.socket\x3alocalhost\x3a1080.service
+ systemd:
+ daemon_reload: true
+ name: socat-unix-to-tcp4@-run-shared_sockets-motion_control.socket\x3alocalhost\x3a1080.service
+ state: restarted
+
+- name: restart socat-unix-to-tcp4@-run-shared_sockets-motion_stream.socket\x3alocalhost\x3a1081.service
+ systemd:
+ daemon_reload: true
+ name: socat-unix-to-tcp4@-run-shared_sockets-motion_stream.socket\x3alocalhost\x3a1081.service
+ state: restarted
diff --git a/roles/motion_back/meta.OK/main.yml b/roles/motion_back/meta.OK/main.yml
new file mode 100644
index 0000000..38034be
--- /dev/null
+++ b/roles/motion_back/meta.OK/main.yml
@@ -0,0 +1,8 @@
+---
+# The home-server project produces a multi-purpose setup using Ansible.
+# Copyright © 2018 Y. Gablin, under the GPL-3.0-or-later license.
+# Full licensing information in the LICENSE file, or gnu.org/licences/gpl-3.0.txt if the file is missing.
+
+dependencies:
+ - role: cleanupdate
+ - role: sockets
diff --git a/roles/motion_back/tasks/main.yml b/roles/motion_back/tasks/main.yml
new file mode 100644
index 0000000..900caf8
--- /dev/null
+++ b/roles/motion_back/tasks/main.yml
@@ -0,0 +1,251 @@
+---
+# The home-server project produces a multi-purpose setup using Ansible.
+# Copyright © 2018 Y. Gablin, under the GPL-3.0-or-later license.
+# Full licensing information in the LICENSE file, or gnu.org/licences/gpl-3.0.txt if the file is missing.
+
+### UPSTREAM BEGIN ⇒ ###
+- name: pull prerequisites from upstream
+ include_role: name=etckeeper.inc allow_duplicates=true tasks_from=upstream.yml
+ vars:
+ msg: motion
+### ⇐ UPSTREAM BEGIN ###
+
+- name: install software
+ package:
+ name: "{{item}}"
+ state: present
+ with_items:
+ - curl
+ - motion
+ - 's-nail'
+ - socat
+
+### UPSTREAM END ⇒ ###
+- name: merge upstream
+ include_role: name=etckeeper.inc allow_duplicates=true tasks_from=merge.yml
+ vars:
+ msg: motion
+### ⇐ UPSTREAM END ###
+
+- name: send the script for Motion to send emails
+ template:
+ src: templates/email.sh.j2
+ dest: /etc/motion/email.sh
+ owner: root
+ group: motion
+ mode: 0750
+ notify:
+ - restart motion.service
+
+- name: send the script for Motion to upload files
+ template:
+ src: templates/upload.sh.j2
+ dest: /etc/motion/upload.sh
+ owner: root
+ group: motion
+ mode: 0750
+ notify:
+ - restart motion.service
+
+- name: send main Motion configuration
+ copy:
+ content: |
+ target_dir {{motion_data}}
+ on_event_end /etc/motion/email.sh %$ %v %Y-%m-%d %H:%M:%S
+ on_picture_save /etc/motion/upload.sh "%f"
+ minimum_motion_frames 5
+ event_gap 10
+ picture_output on
+ picture_quality 50
+ picture_filename %$-%v-%Y%m%d%H%M%S-%q@%K_%L
+ movie_output off
+ webcontrol_port 1080
+ webcontrol_localhost on
+ webcontrol_interface 1
+ webcontrol_parms 1
+ stream_port 1081
+ stream_localhost on
+ stream_preview_method 4
+ stream_quality 20
+ camera_dir /etc/motion/camera.d
+ dest: /etc/motion/motion.conf
+ owner: root
+ group: motion
+ mode: 0640
+ notify:
+ - restart motion.service
+
+- name: create the directory for Motion cameras
+ file:
+ name: /etc/motion/camera.d
+ state: directory
+ owner: root
+ group: motion
+ mode: 0750
+
+- name: send mask-files for Motion cameras
+ copy:
+ src: files/{{item.mask_file}}
+ dest: /etc/motion/camera.d/{{item.mask_file}}
+ owner: root
+ group: motion
+ mode: 0640
+ with_items: "{{motion_cameras}}"
+ when:
+ - (item.mask_file != None)
+ notify:
+ - restart motion.service
+
+- name: send Motion cameras configuration
+ copy:
+ content: |
+ camera_id {{item.id}}
+ camera_name {{item.name}}
+ netcam_url {{item.url}}
+ {{ ('mask_file /etc/motion/camera.d/' + item.mask_file) if item.mask_file != None else '' }}
+ width {{item.width}}
+ height {{item.height}}
+ framerate {{item.framerate}}
+ text_right %q (%ix%J+%K+%L)
+ auto_brightness 0
+ noise_tune on
+ lightswitch_percent 40
+ lightswitch_frames 15
+ dest: /etc/motion/camera.d/camera_{{item.id}}.conf
+ owner: root
+ group: motion
+ mode: 0640
+ with_items: "{{motion_cameras}}"
+ notify:
+ - restart motion.service
+
+- name: identify all Motion cameras configured on the server
+ find:
+ paths: [ '/etc/motion/camera.d' ]
+ patterns: [ 'camera_*.conf' ]
+ register: existing_cameras
+ changed_when: false
+
+- name: only keep basenames of configured Motion cameras
+ set_fact:
+ existing_cameras: "{{ existing_cameras.files | map(attribute='path') | map('basename') | list }}"
+ changed_when: false
+
+- name: filter out up-to-date Motion cameras
+ set_fact:
+ existing_cameras: "{{ existing_cameras | reject('contains', 'camera_' + (item.id | string) + '.conf') | list }}"
+ with_items: "{{ motion_cameras }}"
+ changed_when: false
+
+- name: delete old Motion cameras
+ file:
+ path: /etc/motion/camera.d/{{item}}
+ state: absent
+ with_items: "{{ existing_cameras }}"
+ notify:
+ - restart motion.service
+
+- name: ensure ownership of the Motion data directory
+ file:
+ path: "{{motion_data}}"
+ state: directory
+ owner: motion
+ recurse: true
+
+- name: prepare override of Motion launch parameters
+ file:
+ name: /etc/systemd/system/motion.service.d
+ state: directory
+
+- name: override Motion launch parameters
+ copy:
+ content: |
+ [Unit]
+ Description=Motion daemon, paused
+ [Service]
+ ExecStart=
+ ExecStart=/usr/bin/motion -n -m
+ dest: /etc/systemd/system/motion.service.d/paused-mode.conf
+ mode: 0644
+ notify:
+ - restart motion.service
+
+- name: create a generic service for socat-based port-forwarding
+ copy:
+ content: |
+ [Unit]
+ Description=socat-based Unix domain socket to IPv4/TCP forwarding
+ After=network-online.target
+ Wants=network-online.target
+ [Service]
+ ExecStartPre=/usr/bin/sh -c 'rm -f "$${0%%%%:*}"' "%I"
+ ExecStart=/usr/bin/sh -c 'exec /usr/bin/socat -d UNIX-LISTEN:"$${0%%%%:*}",fork,mode=0666 TCP4:$${0#*:}' "%I"
+ PrivateDevices=yes
+ ProtectSystem=full
+ NoNewPrivileges=yes
+ ReadWritePaths=/run /tmp
+ dest: /etc/systemd/system/socat-unix-to-tcp4@.service
+ mode: 0644
+ notify:
+ - restart socat-unix-to-tcp4@-run-shared_sockets-motion_control.socket\x3alocalhost\x3a1080.service
+ - restart socat-unix-to-tcp4@-run-shared_sockets-motion_stream.socket\x3alocalhost\x3a1081.service
+
+- name: prepare instanciation of socat-based port-forwarding for Motion control
+ file:
+ name: /etc/systemd/system/socat-unix-to-tcp4@-run-shared_sockets-motion_control.socket\x3alocalhost\x3a1080.service.d
+ state: directory
+
+- name: instanciate socat-based port-forwarding for Motion control
+ copy:
+ content: |
+ [Unit]
+ Description=socat-based Unix–TCP forwarding of Motion control
+ After=motion.service
+ Wants=motion.service
+ dest: /etc/systemd/system/socat-unix-to-tcp4@-run-shared_sockets-motion_control.socket\x3alocalhost\x3a1080.service.d/dependency.conf
+ mode: 0644
+ notify:
+ - restart socat-unix-to-tcp4@-run-shared_sockets-motion_control.socket\x3alocalhost\x3a1080.service
+
+- name: prepare instanciation of socat-based port-forwarding for Motion stream
+ file:
+ name: /etc/systemd/system/socat-unix-to-tcp4@-run-shared_sockets-motion_stream.socket\x3alocalhost\x3a1081.service.d
+ state: directory
+
+- name: instanciate socat-based port-forwarding for Motion stream
+ copy:
+ content: |
+ [Unit]
+ Description=socat-based Unix–TCP forwarding of Motion stream
+ After=motion.service
+ Wants=motion.service
+ dest: /etc/systemd/system/socat-unix-to-tcp4@-run-shared_sockets-motion_stream.socket\x3alocalhost\x3a1081.service.d/dependency.conf
+ mode: 0644
+ notify:
+ - restart socat-unix-to-tcp4@-run-shared_sockets-motion_stream.socket\x3alocalhost\x3a1081.service
+
+- name: enable Motion
+ systemd:
+ daemon_reload: true
+ name: motion.service
+ enabled: true
+
+- name: enable unix-to-tcp forwarding for Motion control
+ systemd:
+ daemon_reload: true
+ name: socat-unix-to-tcp4@-run-shared_sockets-motion_control.socket\x3alocalhost\x3a1080.service
+ enabled: true
+
+- name: enable unix-to-tcp forwarding for Motion stream
+ systemd:
+ daemon_reload: true
+ name: socat-unix-to-tcp4@-run-shared_sockets-motion_stream.socket\x3alocalhost\x3a1081.service
+ enabled: true
+
+### LOCAL COMMIT ⇒ ###
+- name: commit local changes
+ include_role: name=etckeeper.inc allow_duplicates=true tasks_from=local.yml
+ vars:
+ msg: motion
+### ⇐ LOCAL COMMIT ###
+- meta: flush_handlers
diff --git a/roles/motion_back/templates/email.sh.j2 b/roles/motion_back/templates/email.sh.j2
new file mode 100755
index 0000000..cf33abd
--- /dev/null
+++ b/roles/motion_back/templates/email.sh.j2
@@ -0,0 +1,9 @@
+#!/bin/bash
+# $1: camera
+# $2: event number
+# $3: ISO date
+# $4: ISO time
+
+printf 'Camera: %s\nEvent: %s\nDate: %s %s\n\nCloud: %s' \
+ "$1" "$2" "$3" "$4" '{{motion_cloud_url}}' \
+| mail -s 'Motion event' {{motion_email_recipient}}
diff --git a/roles/motion_back/templates/upload.sh.j2 b/roles/motion_back/templates/upload.sh.j2
new file mode 100755
index 0000000..fa46ea6
--- /dev/null
+++ b/roles/motion_back/templates/upload.sh.j2
@@ -0,0 +1,40 @@
+#!/bin/bash
+# $1: file to upload
+
+BASE_URL=https://www.mediafire.com/api
+TOKEN_FILE=/var/lib/motion/token
+LOGIN='{{motion_cloud_login}}'
+PASSWORD='{{motion_cloud_password}}'
+
+# Plowshare App ID & API key
+APP_ID={{motion_cloud_id}}
+API_KEY='{{motion_cloud_key}}'
+
+token="$(find "$TOKEN_FILE" -mmin -9 -exec cat {} \; 2>/dev/null)"
+set -e
+
+f="$1"
+file_size="$(stat -L --printf=%s "$f")"
+file_name="$(basename "$f")"
+
+if [ -z "$token" ]; then
+ token_json="$(curl \
+ -d "email=$LOGIN" --data-urlencode "password=$PASSWORD" \
+ -d "application_id=$APP_ID" \
+ -d "signature=$(printf '%s' "$LOGIN$PASSWORD$APP_ID$API_KEY" | sha1sum | head -c40)" \
+ -d 'version=1' -d 'response_format=json' \
+ "$BASE_URL/user/get_session_token.php" \
+ | tr -d '\r\n ')"
+
+ grep -qF '"result":"Success"' <<<"$token_json"
+
+ token="$(sed -rn 's/.*"session_token":"(([^"]|\\")*)".*/\1/p' <<<"$token_json" \
+ | sed 's/\\\(.\)/\1/g')"
+
+ printf '%s' "$token" >"$TOKEN_FILE"
+fi
+
+curl \
+ -F "Filedata=@$f;filename=$file_name" \
+ -H "x-filename: $file_name" -H "x-filesize: $file_size" \
+ "$BASE_URL/upload/simple.php?session_token=${token}&path=/Camera&action_on_duplicate=keep&response_format=json"
diff --git a/roles/ssowat/templates/conf.json.j2 b/roles/ssowat/templates/conf.json.j2
index 934295d..142a58e 100644
--- a/roles/ssowat/templates/conf.json.j2
+++ b/roles/ssowat/templates/conf.json.j2
@@ -47,11 +47,13 @@
},
"you": {
"allow": {
+ "{{net_soa}}{{http_pfx_motion}}/": "Surveillance",
"{{net_soa}}{{http_pfx_transmission}}": "BitTorrent"
}
},
"me": {
"allow": {
+ "{{net_soa}}{{http_pfx_motion}}/": "Surveillance",
"{{net_soa}}{{http_pfx_movim}}/": "Social",
"{{net_soa}}{{http_pfx_transmission}}": "BitTorrent",
"{{net_soa}}{{http_pfx_wallabag}}/": "Read later"
diff --git a/site.yml b/site.yml
index de991eb..1136c84 100644
--- a/site.yml
+++ b/site.yml
@@ -33,6 +33,7 @@
- ssh
- dovecot
- mediaplayer
+ - motion_back
- front_run
- acme_back
- nextcloud_davfs
@@ -61,6 +62,7 @@
- dmz_dotclear_front
- dmz_ihmldap
- dmz_prosody_front
+ - dmz_motion_front
# - dmz_wallabag_front
- acme_front
- privatebin