ラズパイで監視カメラを作ったときの備忘録

無人部屋に監視カメラが必要だったので作ったときの備忘録。
モチベーションは外付けのモニターとキーボードを使わないこと

# 使ったもの
だいたい次のものを使用した。

- Mac
- Raspberry Pi 3 Model B
- Raspberry Piの電源
- Thunderbolt Ethernetアダプタ
- MicroSD カード 16 GB
- Logitech WebCam(USB)
- Buffaloの無線LAN子機

# Raspbian(OS)のインスコ

```shell-session
$ # 最新のRASPBIANを取得
$wget https://downloads.raspberrypi.org/raspbian_latest
--2017-09-12 20:02:28--  https://downloads.raspberrypi.org/raspbian_latest
Resolving downloads.raspberrypi.org... 93.93.135.188, 93.93.128.211, 93.93.128.230, ...
Connecting to downloads.raspberrypi.org|93.93.135.188|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://downloads.raspberrypi.org/raspbian/images/raspbian-2017-09-08/2017-09-07-raspbian-stretch.zip [following]
--2017-09-12 20:02:31--  https://downloads.raspberrypi.org/raspbian/images/raspbian-2017-09-08/2017-09-07-raspbian-stretch.zip
Connecting to downloads.raspberrypi.org|93.93.135.188|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: http://director.downloads.raspberrypi.org/raspbian/images/raspbian-2017-09-08/2017-09-07-raspbian-stretch.zip [following]
--2017-09-12 20:02:32--  http://director.downloads.raspberrypi.org/raspbian/images/raspbian-2017-09-08/2017-09-07-raspbian-stretch.zip
Resolving director.downloads.raspberrypi.org... 93.93.130.214, 93.93.130.104, 93.93.128.133, ...
Connecting to director.downloads.raspberrypi.org|93.93.130.214|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1757290390 (1.6G) [application/zip]
Saving to: 'raspbian_latest'

raspbian_latest                               100%[==============================================================================================>]   1.64G   271KB/s    in 2h 4m

2017-09-12 22:06:45 (230 KB/s) - 'raspbian_latest' saved [1757290390/1757290390]

wget https://downloads.raspberrypi.org/raspbian_latest  16.39s user 71.27s system 1% cpu 2:04:16.75 total

$ # SHA1でファイルを確認 
$openssl sha1 raspbian_latest
SHA1(raspbian_latest)= c35688583510fc93c5deac637976b7a5c9c55689
openssl sha1 raspbian_latest  3.70s user 0.46s system 92% cpu 4.478 total

$ # 解凍
$unzip raspbian_latest
Archive:  raspbian_latest
  inflating: 2017-09-07-raspbian-stretch.img
unzip raspbian_latest  32.40s user 4.09s system 87% cpu 41.859 total

$ # ファイルの確認
$ ls -al 
total 13033808
drwxr-xr-x   4 os10  staff         136  9 12 22:38 .
drwxr-xr-x  12 os10  staff         408  9 12 20:02 ..
-rw-r--r--   1 os10  staff  4916019200  9  8 01:23 2017-09-07-raspbian-stretch.img
-rw-r--r--   1 os10  staff  1757290390  9  8 01:30 raspbian_latest
```

# SDカードのフォーマットとRaspbianのコピー

```shell-session
$ # ※先にSDカードをマウントする
$ diskutil list
...
/dev/disk2 (internal, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     FDisk_partition_scheme                        *15.8 GB    disk2
   1:             Windows_FAT_32 NO NAME                 15.8 GB    disk2s1

$ # SDカードをフォーマット
$ diskutil eraseDisk FAT32 RPI /dev/disk2
Started erase on disk2
Unmounting disk
Creating the partition map
Waiting for partitions to activate
Formatting disk2s2 as MS-DOS (FAT32) with name RPI
512 bytes per physical sector
/dev/rdisk2s2: 30487440 sectors in 1905465 FAT32 clusters (8192 bytes/cluster)
bps=512 spc=16 res=32 nft=2 mid=0xf8 spt=32 hds=255 hid=411648 drv=0x80 bsec=30517248 bspf=14887 rdcl=2 infs=1 bkbs=6
Mounting disk
Finished erase on disk2

$ # SDカードをアンマウント
$ diskutil unmountDisk /dev/disk2
Unmount of all volumes on disk2 was successful

$ sudo dd bs=16m if=2017-09-07-raspbian-stretch.img of=/dev/rdisk2
$ # デバイス名にrを付けつと10倍ぐらい早い。進捗はCtrl+tで確認する。
$ # Imageの容量は5GBで6MB/secの速度だったので、だいたい10minぐらい。
load: 2.00  cmd: dd 73563 uninterruptible 0.00u 0.04s
3+0 records in
2+0 records out
33554432 bytes transferred in 5.498053 secs (6102966 bytes/sec)
load: 2.00  cmd: dd 73563 uninterruptible 0.00u 0.07s
...
4916019200 bytes transferred in 461.069118 secs (10662217 bytes/sec)
sudo dd bs=16m if=2017-09-07-raspbian-stretch.img of=/dev/rdisk2  0.01s user 3.18s system 0% cpu 7:43.63 total
```

# SSHの有効化
どうやら最近は初期状態で無効化されているらしいため

```shell-session
$ cd /Volumes
Macintosh HD boot
$ ls -al 
total 12
drwxr-xr-x@  4 root  wheel   136  9 13 00:54 .
drwxr-xr-x  34 root  wheel  1224  8 13 16:54 ..
lrwxr-xr-x   1 root  wheel     1  8 12 21:44 Macintosh HD -> /
drwxrwxrwx@  1 os10  staff  2048  9 13 00:54 boot

$ touch ./boot/ssh
$ # bootフォルダにsshという空ファイルを作成すれば良いらしい

$ diskutil unmountDisk /dev/disk2
Unmount of all volumes on disk2 was successful
```

# ラズパイをMacに接続する
次の手順でMacのNetworkのSharingの設定をする
1. System Preference > Sharing を開く
2. Internet Sharing(Service)のチェックボックスを活性化する
3. To computers usingのThunderbolt Ethernet(Ports)のチェックボックスを活性化する
4. ラズパイを起動してMacとLANケーブルで接続する

# ラズパイにSSHで接続

```shell-session
$ # ネットワークのインターフェイスを確認(bridge***オプションがEthernetのインターフェイス)
$ ifconfig
...
bridge100: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
        options=3<RXCSUM,TXCSUM>
        ether a6:5e:60:ab:ad:64
        inet 192.168.2.1 netmask 0xffffff00 broadcast 192.168.2.255
        inet6 fe80::a45e:60ff:feab:ad64%bridge100 prefixlen 64 scopeid 0x10
        Configuration:
                id 0:0:0:0:0:0 priority 0 hellotime 0 fwddelay 0
                maxage 0 holdcnt 0 proto stp maxaddr 100 timeout 1200
                root id 0:0:0:0:0:0 priority 0 ifcost 0 port 0
                ipfilter disabled flags 0x2
        member: en6 flags=3<LEARNING,DISCOVER>
                ifmaxaddr 0 port 15 priority 0 path cost 0
        nd6 options=201<PERFORMNUD,DAD>
        media: autoselect
        status: active
$ # inetがIPv4なのでThunderboltのI/Fは次のようになる
$ # - IPアドレス: 192.168.2.1
$ # - サブネットマスク: 255.255.255.0(/24)
$ # - ブロードキャストアドレス: 192.168.2.255
$ # なので対象のIPアドレスは19.168.2.2~244の範囲となる

$ # ネットワークに存在するホスト一覧を取得する
$ nmap -n -sP 192.168.2.1/24
Starting Nmap 6.47 ( http://nmap.org ) at 2017-09-13 02:37 PHT
Strange error from connect (65):No route to host
Nmap scan report for 192.168.2.1
Host is up (0.0058s latency).
Nmap scan report for 192.168.2.3
Host is up (0.0052s latency).
Nmap done: 256 IP addresses (2 hosts up) scanned in 0.03 seconds
$ # このIPアドレス(192.168.2.3)がそれっぽい

$ # SSH接続
$ ssh pi@192.168.2.3  # pi@raspberrypi.local でもOK
pi@192.168.2.3's password: # PWはraspberry
$ # NOTE: REMOTE HOST IDENTIFICATION HAS CHANGEDの場合は次のコマンドでフィンガープリントを削除する
$ # ssh-keygen -R 192.168.2.3
```

# VNCを使う
VNCを使う理由はキャプチャした画像の確認をするため

- Raspberry側の設定

    ```shell-session
    $ # raspberryにVNCを入れる
    $ sudo apt-get update
    $ sudo apt-get install tightvncserver
    $ tightvncserver # VNCサーバーを起動
    # PWの設定
    ```

- Mac側の設定
  - Finderを起動
  - Go > Connect to Server
  - Server Address: vnc://raspberrypi.local:5901
  - GUIが表示されればOK

# Wifiの設定
- Buffaloの無線LAN子機をラズパイに刺す
- GUIでWifiの設定を行なう
  - CUIからwpa-supplicant.confでやってもよい
- Wifi設定後はThunderbolt Ethernetアダプタを使用しない

# カメラの設定

```shell-session
$ # USBカメラをラズパイに接続する
$ lsusb
Bus 001 Device 004: ID 0411:01a2 BUFFALO INC. (formerly MelCo., Inc.) WLI-UC-GNM Wireless LAN Adapter [Ralink RT8070]
Bus 001 Device 005: ID 046d:0826 Logitech, Inc. HD Webcam C525
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp. SMC9514 Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
$ # LogitechのWebcamが認識されている

$ # キャプチャソフトをインスコ
$ sudo apt install fswebcam
...
Unpacking fswebcam (20140113-1) ...
Setting up fswebcam (20140113-1) ...
Processing triggers for man-db (2.7.6.1-2) ...

$ # 撮影テスト
$ pwd
/home/pi
$ fswebcam -r 640x480 -F 1 -S 100 ./test.jpg # -Fはフレーム, -Sは露光
--- Opening /dev/video0...
Trying source module v4l2...
/dev/video0 opened.
No input was specified, using the first.
Adjusting resolution from 384x288 to 352x288.
--- Capturing frame...
Captured frame in 0.00 seconds.
--- Processing captured image...
Fontconfig warning: ignoring UTF-8: not a valid region tag
Writing JPEG image to 'test.jpg'.
$ # /home/pi/test.jpg に画像が保存されるのでVNCで確認する

$ # カメラのパラメータの調節ソフト
$ sudo apt install guvcview
$ # Menu > Sound & Video > guvcview を起動
```

# モーションセンサーの設定
```bash
$ sudo apt-get install -y motion

$ # 撮影テスト
$ sudo motion -c /etc/motion/motion.conf
$ # /var/lib/motion/ に保存される。GUIでチェックする

$ # 設定ファイル更新(以下の様に)
$ sudo vi /etc/motion/motion.conf
# Motionをサービスとして実行
daemon on
# 動画機能OFF
ffmpeg_output_movies off
# 写真のサイズ
width 640
height 480
# 動体検知のしきい値
threshold 3000 
gap 100
# 画像について
locate_motion_mode on # 動体検知箇所をかこう
text_double on # テキスト大きく

$ sudo vi /etc/default/motion
# スタートアップの時にデーモンとして動かす 
start_motion_daemon=yes 
```

# Slackで通知

次を事前に行なう

- Slack登録
- Slack Appを作成
- 次の2点を有効化する  
　1. Add features and functionality(Bot)  
　2. Install your app to your workspace(対象のTeam)  
- Botを対象のチャンネルにインバイトする

## Pythonの依存モジュールのインスコ

```shell-session
$ sudo pip install slacker
pi@raspberrypi:~/slack $ sudo pip install slacker

Collecting slacker
  Downloading slacker-0.9.60.tar.gz
Requirement already satisfied: requests>=2.2.1 in /usr/lib/python2.7/dist-packages (from slacker)
Building wheels for collected packages: slacker
  Running setup.py bdist_wheel for slacker ... done
  Stored in directory: /root/.cache/pip/wheels/57/61/2c/99406ad2141fdf3ede576acedad209a3b63b9674af56bbfa19
Successfully built slacker
Installing collected packages: slacker
Successfully installed slacker-0.9.60
```

## メッセージ投稿テスト
```pycon
$ python
Python 2.7.9 (default, Mar  8 2015, 00:52:26)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from slacker import Slacker
>>> token = "HOGEHOGE" # OAuth Tokens for Your Team >  Bot User OAuth Access Token
>>> slk = Slacker(token)
>>> cn = "C71DQB3MG" # チャンネル名はエンコード済みのもの。slackのURLを見れば分かる
>>> msg = 'APIだよ' 
>>> slk.chat.post_message(cn, msg)
<slacker.Response object at 0xb64aca50>
```

## 画像のアップロードテスト
```pycon
$ python
Python 2.7.9 (default, Mar  8 2015, 00:52:26)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from slacker import Slacker
>>> token = "HOGEHOGE" # OAuth Tokens for Your Team >  Bot User OAuth Access Token
>>> slk = Slacker(token)
>>> cn = "C71DQB3MG"
>>> fn = '/home/pi/hoge.jpg'
>>> comment = "test"
>>> slk.files.upload(fn, channels=[cn], initial_comment=comment) # 画像を投稿
 <slacker.Response object at 0xb64aca50>
```

# Motionで自動画像投稿
Motionの設定で画像をSaveするたびにスクリプトをフックさせる

```shell-session
$ sudo vi /etc/motion/motion.conf
# confからsave時にスクリプトをフックできる
on_picture_save python /home/pi/slack/bot.py %f # %f=画像のファイル名

$ cd /home/pi
$ mkdir slack
$ cd slack
$ vi bot.py # 後述のスクリプト作成
$ chmod a+x /home/pi/slack/bot.py # 実行権限付与
$ python ./bot.py /home/pi/test.jpg # テスト
```


```bot.py
# -*- coding: utf-8 -*-
import sys
from slacker import Slacker
from datetime import datetime

class Slack(object):

    __slacker = None

    def __init__(self, token):
        self.__slacker = Slacker(token)

    def post_to_file(self, file_path, encoded_ch_name):
        now = datetime.now()
        comment = "Uploaded At: " + now.strftime('%Y-%m-%d %H:%M:%S') + '(UTC)'
        print("Sending a picture")
        self.__slacker.files.upload(file_path, channels=[encoded_ch_name], initial_comment=comment)
        print("Done")

if __name__ == "__main__":

    param = sys.argv
    file_path = param[1]

    token = "" # Bot User OAuth Access Token
    slack = Slack(token)
    encoded_ch_name = "C71DQB3MG"
    slack.post_to_file(file_path, encoded_ch_name)

```


# Motionをデーモン化

```shell-session
$ # サービスとして有効化
$ sudo systemctl enable motion
$ sudo systemctl list-unit-files -t service # サービス一覧の設定確認
$ sudo systemctl is-enabled motion # motionの設定確認
motion.service is not a native service, redirecting to systemd-sysv-install.
Executing: /lib/systemd/systemd-sysv-install is-enabled motion
enabled
$ # enabledなのでOK

$ # ランレベル変更
$ sudo systemctl set-default multi-user.target # デフォルトのターゲットをマルチユーザーモードに変更(電源入れればMotion有効化)
$ sudo systemctl get-default
multi-user.target

$ # スタートしてサービスの状態確認
$ sudo systemctl start motion
$ sudo service motion status
● motion.service - LSB: Start Motion detection
   Loaded: loaded (/etc/init.d/motion; generated; vendor preset: enabled)
   Active: active (exited) since Wed 2017-09-13 01:19:37 UTC; 5h 51min ago
     Docs: man:systemd-sysv-generator(8)
  Process: 5219 ExecStop=/etc/init.d/motion stop (code=exited, status=0/SUCCESS)
  Process: 5268 ExecStart=/etc/init.d/motion start (code=exited, status=0/SUCCESS)
   CGroup: /system.slice/motion.service

Sep 13 01:19:37 raspberrypi systemd[1]: Starting LSB: Start Motion detection...
Sep 13 01:19:37 raspberrypi motion[5268]: Starting motion detection daemon: motion.
Sep 13 01:19:37 raspberrypi systemd[1]: Started LSB: Start Motion detection.
Sep 13 01:19:38 raspberrypi motion[5274]: [0:motion] [NTC] [ALL] conf_load: Processing thread 0 - config file /etc/motion/motion.conf
Sep 13 01:19:38 raspberrypi motion[5274]: [0:motion] [NTC] [ALL] motion_startup: Motion 4.0 Started
Sep 13 01:19:38 raspberrypi motion[5274]: [0:motion] [ERR] [ALL] myfopen: Error opening file /var/log/motion/motion.log with mode a: Permission denied
Sep 13 01:19:38 raspberrypi motion[5274]: [0:motion] [EMG] [ALL] motion_startup: Exit motion, cannot create log file /var/log/motion/motion.log: Permission denied

$ # motionユーザーのパーミッションがないらしいので変更
$ sudo chown motion:motion /var/run/motion
$ sudo chown motion:motion /var/log/motion/motion.log

$ # 再確認
$ sudo systemctl start motion
$ sudo systemctl status motion
...
Sep 13 07:17:01 raspberrypi systemd[1]: Starting LSB: Start Motion detection...
Sep 13 07:17:02 raspberrypi motion[5860]: Starting motion detection daemon: motion.
Sep 13 07:17:02 raspberrypi systemd[1]: Started LSB: Start Motion detection.
Sep 13 07:17:03 raspberrypi motion[5866]: [0:motion] [NTC] [ALL] conf_load: Processing thread 0 - config file /etc/motion/motion.conf
Sep 13 07:17:03 raspberrypi motion[5866]: [0:motion] [NTC] [ALL] motion_startup: Motion 4.0 Started
$ # 今度はOK

$ # サービスのログを全部見たい場合は
$ sudo journalctl -b | less # 全ログチェック
$ sudo journalctl -u motion | less # モーションのログチェック

$ # その他
$ sudo systemctl stop motion
$ sudo systemctl disable motion
``` 



# 参考文献

http://qiita.com/toshihirock/items/8e7f0887b565defe7989
https://medium.com/@tzhenghao/how-to-ssh-into-your-raspberry-pi-with-a-mac-and-ethernet-cable-636a197d055
http://qiita.com/wf9a5m75/items/6712181de189169eb444
http://www.pawprint.net/designresources/netmask-converter.php
https://vivibit.net/raspbian-enable-ssh/
https://www.raspberrypi.org/forums/viewtopic.php?t=191252
http://daisukekmr.hatenablog.com/entry/2015/01/22/201919
http://qiita.com/kinpira/items/bf1df2c1983ba79ba455
http://a244.hateblo.jp/entry/2016/10/14/053000
http://qiita.com/Go-zen-chu/items/63f65156c748b34e1678
http://safe-linux.homeip.net/web/motion/motion-03.html
https://github.com/yusukeyamatani/slackbot/blob/master/slack_bot.py
https://github.com/os/slacker
https://github.com/Motion-Project/motion/issues/309
https://raspberrypi.stackexchange.com/questions/41342/how-to-start-motion-in-daemon-mode-on-rpi-running-raspbian-jessie
https://raspberrypi.stackexchange.com/questions/43740/how-do-i-change-runlevel-on-model-3