UPSを自作する【Anker】

前回の投稿から2年近く時が経ってしまいました。
私のモチベーション維持のために、**読んだらいいねをお願いします！**

# 何をやったか・工夫した点
* この記事を見れば汎用ポータブル電源からUPSを作れます。
* Ankerのポータブル電源をUPSとして使い、停電時に自動シャットダウン機能を追加してUPSを自作した。
* 専用のUPSを使わなくても安価で高性能なUPSを自作することができた。
* 停電監視用でUSB電源を取り出し、減圧した上でRaspberryPiに監視させた

# はじめに
3年前に[SIer営業1年目がDockerを使ってファイルサーバを構築してみた](https://qiita.com/tororu/items/5166378dfb6ae64102ee)という記事を投稿し、自宅にファイルサーバがあるという満足感に浸ることができました。
しかし、

* それなりに電気代を食うので、使うときにつけて夜にシャットダウンする、みたいな運用をしているため使いたいときにすぐ使えない
* 無駄に拡張性を考慮してでかいケースを買ってしまったので、邪魔。

ということがあり、ちょっとずつストレスが溜まってきたので、いっそのこと製品にしてしまおう、ということで、ファイルサーバをQNAPに移行しました！
結果的に大正解で、電気代も80W→30W程度まで減らすことができ、常時起動でストレスフリー＆スペースを大幅に削減することができました。
ここで気になるのは停電。**めんどくさがりや＆ズボラというエンジニア適正100%**な私は便利な家電が大好きなのです。
そのため、極稀にブレーカーを落とすことがあり、停電でNASやHDDが壊れてデータがなくなると困る！ということでUPSを導入しようと思いました。
・・・が、個人で買うにちょっと躊躇する値段（安くても１万弱、高いと数万）、、、
ということで探していると、Ankerから[素晴らしい製品](https://www.ankerjapan.com/products/a1720)が出ていました。

ポイントはここ！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111324/d3acc8e6-13fe-5376-2b84-48f6246bb151.png)



なんと、パススルーに対応し、125WまでであればUPSとして使えます。
なので、普段はUPSとして使い、キャンプ等に行くときはポータプル電源として使える2way方式が可能！
~~（キャンプ行ったことないけど）~~
一般的なUPSであれば、停電を検知した場合には製品にシャットダウンコマンドを送り、自動的にシャットダウンされるような仕組みがありますが、この製品にはそのような機能はありません。
自宅にいるときに停電が起きればよいのですが、外出中に停電した場合は充電がどんどんなくなり、力尽きるという**時間差停電が起こるだけ**です。

なので、停電した場合にQNAPにシャットダウンコマンドを送り、安全にQNAPを停止する仕組みを作ります。


# 準備するもの
本システムの構築にあたり、以下の製品を使用しています。
また、RaspberryPiとQNAPは同一ネットワーク上に存在することを前提としています。

| 使用した製品 | 用途 |
|:-:|:-:|
| Raspberry Pi 3  | シャットダウンコマンドの発出用|
| QNAP TS-251D | いわずもがな |


本システムは電子回路の製作があるので、以下の製品を使っています。

| 部品名 | 型番 | 用途 |
|:-:|:-:|:-:|
| 三端子レギュレータ一式  | TA48033S  | 5V→3.3Vの減圧  |
| USB電源アダプタ  | 100均で適当なやつ  | 停電検知用  |
| USBケーブル  | 家に転がってたやつ  | 停電検知用  |
| ブレッドボード  | 家に転がってたやつ  | 配線用  |
| ジャンパ線 | 家に転がってたやつ  | 配線用  |





# 仕組み
今回やりたいことは以下のとおりです。
USB電源から停電状況を監視し、停電を検出したらネットワーク越しにshutdownコマンドを発出し、QNAPをシャットダウンさせます。
QNAPをシャットダウンしている間はAnkerポータブル電源が電源を供給し続けるので、安全にシャットダウンすることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111324/5abe018d-87b1-20c4-7ede-d859c622286f.png)



## ①停電の検出
今回使用したAnkerの製品は最大入力が125W（電源+USBC）のため、それ以内に収めないと入力電力＜出力電力となり、UPSの役割を果たせないので、UPS配下につなぐ製品の合計ワット数は125W以内に収めてください。
また、今回はsshによりシャットダウンを行うため、ネットワークが切断されるとシャットダウンコマンドを発出できません。
なので、ルーターやスイッチ等のNW機器類も保護するようにしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111324/c91287dd-7763-dff2-88d5-8469ac8070a3.png)

USBケーブルは以下の様に4本の線が入っていて、

* １と４が電源ケーブル
* ２と３が通信用ケーブル（今回不使用）

今回は電源を監視するので、１と４の電源ケーブルを使います。
今回使ったUSBアダプタは5Vなので、１－４間の電圧5Vとなります。そのままではラズパイに繋げないので、三端子レギュレータで減圧しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111324/e68c3d42-43fc-d7f6-7b83-b600cb56ad98.png)

停電を検知するために、ラズパイへコンセントの電源を直接入力します。
ただし、ラズパイのGPIOの入力は3.3Vなので、USB電源アダプタを使用して100V→5V、三端子レギュレータを使って5V→3.3Vに減圧しています。
今回はGPIO23番を使用しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111324/d2e00ede-284b-b40e-db77-686d06c559fc.png)

最終的に以下のような配線となりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/111324/d81d1f80-04a6-31a2-4d9a-148ace16a543.png)


停電を検知するプログラムは以下の通りです。
今回はGPIO23番を使用していますが、適宜読み替えてください。
また、必要なモジュールはインストールしてください。
1秒毎に電源の状態を監視し、60秒間GPIO23がOFF（=1分間停電状態が続いた）場合にはシャットダウンを発出するシェルスクリプト（qnap-shutdown.sh）が動く仕組みになっています。

```power-outage.py
#必要なモジュールをインポート
import RPi.GPIO as GPIO             #GPIO用のモジュールをインポート
import time                         #時間制御用のモジュールをインポート
import sys                          #sysモジュールをインポート
import subprocess                   #シェルスクリプト呼び出し用

#ポート番号の定義
Sw_pin = 23                         #変数"Sw_pin"に23を格納

#GPIOの設定
GPIO.setmode(GPIO.BCM)              #GPIOのモードを"GPIO.BCM"に設定
#GPIO23を入力モードに設定してプルダウン抵抗を有効にする
GPIO.setup(Sw_pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

SHELL_PATH = "${HOME}/qnap-shutdown/qnap-shutdown.sh"
TIME_OF_POWER_OUTAGE = 60


powerOutageTime = 0

#while文で無限ループ
#GPIO23の入力を読み取る
while True:
    if powerOutageTime >= TIME_OF_POWER_OUTAGE:            #1分超えた場合はシャットダウンコマンドの実行
        subprocess.call( ["bash",SHELL_PATH] )
        powerOutageTime = 0

    if GPIO.input(Sw_pin) == 1:         #GPIO23が「ONで"1"」「OFFで"0"」
        powerOutageTime = 0
    else:
        powerOutageTime += 1

   time.sleep(1)                       #1秒間待つ
```

## ②シャットダウンコマンドを発出する
上記で1分間入力がなかった場合停電したと見なし、以下のシャットダウンシェルを動かします。
ここは各環境によると思うので、適宜読み替えてください。
私はQNAPに公開鍵でsshできる設定にしています。
（公開鍵だけで入る方法はQNAPを再起動すると初期化される→今後の課題）

```qnap-shutdown.sh
#!/bin/bash

password="PASSWORD"      #ここは各環境に合わせてください。
username="USERNAME" #ここは各環境に合わせてください。
host="HOST"  #ここは各環境に合わせてください。
port="PORT"  #ここは各環境に合わせてください。

expect -c "
        spawn ssh ${username}@${host} -p ${port} -i ${HOME}/.ssh/id_rsa
        expect \"ゆーざねーむ@ほすとめい's password:\"      #ここは各環境に合わせてください。
        send \"${password}\n\"
        expect \"~]\"
        send \"sudo poweroff\n\"  #シャットダウンコマンドの発出
        expect \"Password:\"
        send \"${password}\n\"
        expect \"~]\"
        send \"exit\n\"
        expect \"~]\"
```




# 終わりに
データがなくなるのは一瞬です。
QNAPでRAID構築＆バックアップをしていても、停電で同時に消えてしまう可能性もあります。
仮に消えなかったとしても、製品やHDDに大きな負荷がかかることは間違いありません。
よって、可能な限り安全に運用できる環境を整え、安心して運用していきましょう。

# 今後の課題
* シェルスクリプト内にパスワードが平文で入っている→公開鍵だけで入れるようにしたい
* QNAP等の製品を安全にシャットダウンする仕組みとしてNUTという規格があるらしい

# 参考文献
[【ラズパイ電子工作】スイッチのON／OFF状態を読み取る方法](https://denkisekkeijin.com/raspberrypi/pi-sw/#4_%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0Python)
[Raspberry Piでスイッチ入力](https://monomonotech.jp/kurage/raspberrypi/tact_switch.html)
[低損失三端子レギュレーター](https://akizukidenshi.com/catalog/g/gI-00534/)
[Raspberry Pi と BY50S と Ready NAS の連携](https://catoocraft.com/dblog/?p=82)
[Raspberry Pi にNUTをセットアップする](https://goodjobnahibi.blogspot.com/2018/03/raspberry-pi-nut.html)
[NUT(Network UPS Tools)のmaster・slaveモードでの設定](https://ameblo.jp/p630/entry-12333636345.html)
[QNAP TS-251+ の設定（UPSおよび他NASとの連携）](https://blog.mori-soft.com/entry/2017/02/24/113915)