RaspberryPi 4B でZoneMinderを使用する Part1…目標設定と環境の準備

# Raspberry PIにZoneMinderを導入する

## この記事がおすすめの人
* 家に複数のネットワークカメラがあり、一元管理したい
* RaspberryPIを衝動買いしたがイマイチ使い道がない
* 24時間、WindowsPCなどを稼働させておくのが嫌
* PCの基本操作はできるが、linuxについてはほとんど何も知らない。（リモートでログインし、ファイル編集できる程度）


# 全体の目次
[目標の設定と環境の準備](https://qiita.com/BUBUBB/items/b7f3eb0e16a1c1a938b2)
[ZoneMinderのインストール](https://qiita.com/BUBUBB/items/bdf6df6b1d0ee1e14bc0)
[ZoneMinderの全般設定](https://qiita.com/BUBUBB/items/9de905615f389fd9ed50)
[カメラの登録](https://qiita.com/BUBUBB/items/f9415bc8bc526d0d84a5)
[パフォーマンスの調整](https://qiita.com/BUBUBB/items/9f98c91479a2ab6d8c0c)
[アクセスのブロック](https://qiita.com/BUBUBB/items/dbc7d59065484cd32476)
[外部からのアクセス](https://qiita.com/BUBUBB/items/99174603530094e5f746)
[ZmNinjyaの使用（未)]()


## このページでやること

このページでは、現状の把握と、最終的な目標、優先度を決める。
さらにハードウェアとソフトウェアの基本的なインストールをおこなう。このページでは、目標の実現に特化した操作は含まれない。


# 目次
[目的](#目的)
[現状の認識](#現状の認識)
　[現状](#現状)
　[目標](#目標)
　[優先度](#優先度)
[ZoneMinder以外の選択肢](#zoneminder以外の選択肢)
[使用する機器](#使用する機器)
[環境の設定](#環境の設定)
　[OSのインストール](#osのインストール)
　[SSDの接続とフォーマット](#SDの接続とフォーマット)
　[マウントポイントの作成](#マウントポイントの作成)

# 目的

自宅のネットワークカメラが増えてきたが、メーカーが異なるためビュアーが複数になってしまい面倒くさくなってきた。また、一部のネットワークカメラは、中国のサーバーを経由しているため、セキュリティ上も不安になってきた。
さらに、面白そうだと思って買ったはずのRaspberry Piも使い道が見つからぬまま放置されている。
こうなると、もはや何かせざるを得なくなり、重い腰を上げることになった。

自分用のメモを兼ねて、記録に残すことにした。

# 現状の認識

## 現状
現在は、すべてのネットワークカメラが独立しており、ルータのアドレス変換とスマホなどの端末でカメラの画像を参照している。
<img width="400" alt="1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2096509/2c7a3eab-9e54-57fc-d9aa-948e244b3968.png"> 

ネットワークカメラに対して、次の2つの方法でアクセスしている。

1. ルーターがアドレス/ポート変換を行って外部に公開したポートに、スマートフォンなどから直接接続する。ソフトウェアには [IPCam Viewer Pro]("https://play.google.com/store/apps/details?id=com.rcreations.WebCamViewerPaid&hl=ja&gl=US")を使用している。
1. 各カメラメーカ製のアプリを使用してカメラにアクセスする。アクセスの経路は不明だが、おそらく中国に存在するサーバーを経由したアクセスになっていると思われる。


## 目標
最終的に目標とするのは、次のような接続形態としたい。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2096509/f84654a6-9d33-34c0-6824-ef0e3016353e.png)

自宅内ネットワークにあるカメラーサーバ（ZoneMinder）が、複数のカメラの情報を集めてWebとして外部に公開する、ルーターは唯一のポートを外部に公開し、アドレス変換を行う。同時に、ルータのFirewall機能を使用して、Tapo/Imouが行う外部アクセスを遮断する。

現在使用しているカメラ（最も古いものは2018年春購入）は、すべてRTSPに対応していることが確認できた。事実上、RTSPに対応していないカメラは今市場で新品を買うことが出来ないと思われるので、RTSPを前提としてもかまわない。




## 優先度
実現するにあたり考えた優先度は次の通り

1. 使用時に中国のサーバーなどと通信しない。
1. 使うのはRaspberry Pi 4Bと、余ったSSDなど安価に構築できる。
1. ファンレスのRaspberry piでも夏場の運用時に温度が50℃を超えない。
1. 可能な限りオープンソース製品を使用する。
1. モーションを検出して画像が録画でき、ブラウザから確認できる
1. モーションの誤検出よりも、検出漏れが無いことを重視する


# ZoneMinder以外の選択肢
カメラサーバーでは、ほかのいくつかの製品を軽く評価した。

+ [Shinobi](https://shinobi.video/)。モーション検知の性能が今一つだった。設定可能かもしれないが、少々わかりにくくかった。長時間運用しているとハングしていることが数回あった。Raspberry pi用のDocker Imageが公式になく若干不安が残った。（icebrian/shinobi-image:1.0 が有志？により公開されており、問題なく動作した。）　スマホ版のクライアントは存在しなかった。　一方、GUIは洗練されており、スマホで見たときも専用アプリと遜色ない。実行速度は非常に高速で軽い。ZoneMinderと最後まで迷ったが、安定性を考えて今回は見送った。Dockerを使用せずにインストールして再テストする価値があると感じた。
+ [iSpy](https://www.ispyconnect.com/)　.NET で書かれておりインストールが若干面倒。全体的に重く、Raspberry pi での常時運用に適さないと判断した。Winodws版もあり、こちらは高機能で使いやすそうだった。UPNPにより、ルーターのポートフォワーディング設定が不要。　機能的には一番高性能だったのではないか？
+ [ZoneMinder](https://zoneminder.com/)。全体的にバランスが取れた性能で、設定も容易。ユーザーが多く日本語の情報も十分。クライアントはZmNinjaがAndroid/iPhone向けにリリースされている。ONVIFの対応が無い（あるのかもしれないがわからなかった）ので、カメラを動かすことはできない。画像解像度を高くするとCPU資源を多く消費する。

この中でZoneMinderを使用することにした。精細な画像の記録は、カメラそれぞれに挿入したmicroSDに任せて、ZoneMinderは低解像度の画像で現在の状態を確認することと、モーションを記録し簡単に参照して必要に応じてカメラのSDカードを見る、と言う形で使用する。


# 使用する機器
Raspberry Pi 4 Model B / 8GB (4GBytesでも十分）
メーカー不詳USB SSD (128GBytes)
RTSP対応のカメラ：Tapo C-100、C-200、Imou ‎‎IPC-C26EP、Ctronics ‎CTPT-90C1080P

Raspberry piには、Raspberry PI OSを導入しておく。起動時は、GUIではなくCUIで起動するようにしておく方が良い。（CPU負荷が高いので）
ffmpegなどのパッケージの関係上、Liteではないほうが良いらしい。

この手順では、次のバージョンを使用した。

```
pi@raspberrypi:~ $ uname -a
Linux raspberrypi 5.10.63+ #1459 Wed Oct 6 16:40:27 BST 2021 armv6l GNU/Linux
```

# 環境の設定

## OSのインストール
(https://www.raspberrypi.com/software/) から、Raspberry Pi Imagerをダウンロードしてインストールする。Recomendedの32bit版で動作するが、64bit版でも動作した。

インストールが終わったら、基本的な設定を行っておく。最低限、ネットワークの設定と SSL の設定が必要。


# SSDの接続とフォーマット

ZoneMinderが、カメラの録画を保存するためのデバイスを準備する。標準で本体に装着したmicroSDが使用されるが、microSDのままだと容量的に不足すること、速度が遅いこと、書き換え回数に制限があることを考え、USB接続のSSDを接続、マウントしておく。

まず、USB接続したSSDがどのように認識されているかを確認する。　Disk /dev/sda:などから、デバイスが /dev/sdaとして認識されていることを確認する。

```
$ sudo fdisk -l
　：
Disk /dev/sda: 29 GiB, 31142707200 bytes, 60825600 sectors
Disk model: FLASH DRIVE
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x8f599e6c

Device     Boot Start      End  Sectors Size Id Type
/dev/sda1  *     2048 60825599 60823552  29G  c W95 FAT32 (LBA)
```
最後の/dev/sda1  *     2048 60825599 60823552  29G  c W95 FAT32 (LBA)などの行があれば、すでにパーティションが存在するので既存のパーティションを表示し、すべて削除する

```
$ sudo fdisk /dev/sda
Welcome to fdisk (util-linux 2.33.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

Command (m for help): p   （現在のパーティションを表示）
Disk /dev/sda: 29 GiB, 31142707200 bytes, 60825600 sectors
Disk model: FLASH DRIVE
：
Device     Boot Start      End  Sectors Size Id Type
/dev/sda1  *     2048 60825599 60823552  29G  c W95 FAT32 (LBA)

Command (m for help): d
Selected partition 1
Partition 1 has been deleted.

Command (m for help):
```

パーティションを削除したら、新しいパーティションを作成する。基本的にはすべてデフォルトで良い。

```
Command (m for help): n　（パーティション作成）
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-60825599, default 2048): 2048
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-60825599, default 60825599): 60825599

Created a new partition 1 of type 'Linux' and of size 29 GiB.
Partition #1 contains a vfat signature.
Do you want to remove the signature? [Y]es/[N]o: Y
The signature will be removed by a write command.
```

今まで行った操作を実際にSSDに反映する

```
Command (m for help): w　（書き込み）
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
```

パーティションが作成されたかを確認

```
$ sudo fdisk -l
　：
Device     Boot Start      End  Sectors Size Id Type
/dev/sda1        2048 60825599 60823552  29G 83 Linux
```

パーティションをext4形式でフォーマット

```
$ sudo mkfs.ext4 /dev/sda1
mke2fs 1.44.5 (15-Dec-2018)
Creating filesystem with 7602944 4k blocks and 1901280 inodes
　　：
Writing inode tables: done
Creating journal (32768 blocks):
done
Writing superblocks and filesystem accounting information:
done
```

## マウントポイントの作成

マウントポイントを作成し、接続したSSDをマウントする。マウントされたこと、書き込みできることも確認しておく。確認が終わったら、マウントを解除して解除されたことも確認しておく。

```
#/SSD1をマウント先としてディレクトリを作成
$ sudo mkdir /SSD1

#/SSD1の所有者をpi:piに変更しておく
$ sudo chown -hR pi:pi /SSD1

#/dev/sda1を /SSD1にマウント
$ sudo mount -t ext4 /dev/sda1 /SSD1

#　正常にマウントされたかを確認
$ df -h | grep SSD
/dev/sda1         29G   45M   27G    1% /SSD1

#ファイルが書き込めるかを確認
$ touch /SSD1/hoge.txt
$ ls /SSD1/hoge.txt
/SSD1/hoge.txt

#fstabの設定のため、一旦マウントを解除しておく
$ sudo umount /SSD1

#マウントが解除されたことを確認。（さっき作成したファイルがあるかを使って確認。 df -hなどでも良い）
$ ls /SSD1/hoge.txt
ls: '/SSD1/hoge.txt' にアクセスできません: そのようなファイルやディレクトリはありません
```

ディスクのUUIDを求め、そのIDを /etc/fstabの末尾に追加する。今回の例では、sda1なので、そのデバイスのUUIDを使用する。編集が終わったら、正常にマウントできるかを確認する。


```
# lsblkを使って、接続したデバイスのUUIDを求めておく
$ lsblk -f
NAME        FSTYPE LABEL  UUID                                 FSAVAIL FSUSE% MOUNTPOINT
sda
 +--sda1      ext4          b7f93654-7e85-4a43-8d25-fb5f66280eef  (←　これが SSD1のUUID)
mmcblk0
 +-- mmcblk0p1 vfat   boot   xxxx-xxxx                               204M    19% /boot
 +-- mmcblk0p2 ext4   rootfs xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx   23.1G    14% /   

# /etc/fstabを編集し、ファイルの最後にUUIDとマウント先を追加
$ nano  /etc/fstab
proc            /proc           proc    defaults          0       0
PARTUUID=6252fb91-01  /boot           vfat    defaults          0       2
PARTUUID=6252fb91-02  /               ext4    defaults,noatime  0       1
# a swapfile is not a swap partition, no line here
#   use  dphys-swapfile swap[on|off]  for that
UUID=87b585d1-84c3-486a-8f3d-77cf16f84f30 /SSD1 ext4 defaults,nofail 0 0

#/SSD1がマウントされていないことを確認
$ ls -a /SSD1
.  ..

#/etc/fstabの内容でマウント
$ sudo mount -a

#マウントされたことを確認
$ ls -a /SSD1
.  ..  hoge.txt  lost+found
```

ZoneMinderの画像保存用のディレクトリを作成しておく

```
$ mkdir /SSD1/zm

$ sudo chown www-data:www-data /SSD1/zm
$ sudo chmod 777 /SSD1/zm

$ ls /SSD1
hoge.txt  lost+found  zm
```