2017年3月19日日曜日

Raspberry Pi の autofs で NAS のバックアップ

自宅の全てのデータを NAS に保存しています。
NAS は RAID でミラーリングしているとは言え、飛ぶときはミラーもろとも飛ぶので
2台体制で定期的にコピーするようにしています。

2台のメーカーが違っていたり、特定のフォルダだけコピーしたいようなケースでは
NAS が持っているネットワークバックアップ機能では対応できないことがあります。

そこで、我が家では Raspberry Pi で NAS 間のデータバックアップを動かしています。

滅多に変更しないもので、毎回やり方を忘れがちなので備忘録としてメモしておきます。

バックアップの前提

  • NAS2台ともWindowsファイル共有。
  • いつも1台(稼働系)に書き込み。もう1台(冗長系)はバックアップ専用。
  • 冗長系が壊れたら、新しく購入したNASを稼働系にして、元の稼働系を冗長系に置き換える。
  • 稼働系が壊れたら、新しく購入したNASを稼働系にして、冗長系から書き戻す。
    (常に冗長系を旧機種にするため。)
  • NASを再起動しても Raspberry Pi のバックアップ機能には影響がないようにしたい。


IP アドレスの設定

NAS2台には固定IPを割り当てます。
DHCPでも何とかなりそうな気はしますが、何かの拍子に稼働系と冗長系が
入れ替わってバックアップされると悲惨なので。

固定IPの設定方法はNASやルータの設定次第なので省略。

今回は、次のように設定したものとして説明します。
コマンドのオプション等は適宜読み替えてください。
  • 稼働系IPアドレス: 192.168.1.1
  • 稼働系ホスト名: active_nas
  • 冗長系IPアドレス: 192.168.1.2
  • 冗長系ホスト名: standby_nas


Raspberry Pi 上でのホスト名設定

NAS2台のIPアドレスにRaspberry Pi上で名前を付けます。
Raspberry Pi に SSH で接続して次のコマンドを実行。
pi@raspberrypi ~ $ sudo -s
root@raspberrypi /home/pi $ cp /etc/hosts /etc/hosts.`date +%Y%m%d`
root@raspberrypi /home/pi $ echo '192.168.1.1    active_nas' >> /etc/hosts
root@raspberrypi /home/pi $ echo '192.168.1.2    standby_nas' >> /etc/hosts
root@raspberrypi /home/pi $ cat /etc/hosts
127.0.0.1 localhost
::1  localhost ip6-localhost ip6-loopback
fe00::0  ip6-localnet
ff00::0  ip6-mcastprefix
ff02::1  ip6-allnodes
ff02::2  ip6-allrouters

127.0.1.1 raspberrypi
192.168.1.1 active_nas
192.168.1.2 standby_nas


autofs を設定

Raspberry Pi で NAS の領域をマウントするのですが、
普通に smbmount してしまうと、NAS を再起動した時に再マウントが必要になります。

そこで、autofs を使って必要な時にだけ自動マウントし、NAS の再起動の影響を回避します。
また、autofs なら NAS が故障してマウント異常になっても大丈夫です。

まずは autofs と smbmount に必要なパッケージのインストール。
root@raspberrypi /home/pi $ apt-get install autofs smbclient

次に、autofs でマウントできるように設定します。
root@raspberrypi /home/pi $ cp /etc/auto.master /etc/auto.master.`date +%Y%m%d`
root@raspberrypi /home/pi $ echo '/smb    /etc/auto.smb' >> /etc/auto.master
root@raspberrypi /home/pi $ mkdir /smb
root@raspberrypi /home/pi $ mkdir /etc/creds
root@raspberrypi /home/pi $ echo 'username=USER_NAME
password=PASSWORD' > /etc/creds/active_nas
root@raspberrypi /home/pi $ chmod 600 /etc/creds/active_nas
root@raspberrypi /home/pi $ echo 'username=USER_NAME
password=PASSWORD' > /etc/creds/standby_nas
root@raspberrypi /home/pi $ chmod 600 /etc/creds/standby_nas
root@raspberrypi /home/pi $ service autofs restart

ここで「USER_NAME」と「PASSWORD」はNASのフォルダにアクセスするユーザ名とパスワードです。
2台のNASでアカウント情報が異なっている場合はそれぞれのアカウントを記入します。
/etc/creds フォルダにアカウント情報を書いたファイルを入れて、ファイル名をホスト名にしておくと、
autofs がマウント時に自動的に参照してくれます。
パーミッションは600(オーナーだけが読み書き可能)で。

ここまで出来たら、一般ユーザでもNASのデータにアクセスできるはずです。
例えば、I-O Data の LANDISK なら、次のようにになると思います。

root@raspberrypi /home/pi $ exit
pi@raspberrypi ~ $ ls /smb/active_nas
contents  disk  itunes
pi@raspberrypi ~ $ ls /smb/active_nas/disk
TrashBox quickcopy
pi@raspberrypi ~ $ ls /smb/standby_nas
contents  disk  itunes
pi@raspberrypi ~ $ ls /smb/standby_nas/disk
TrashBox quickcopy
pi@raspberrypi ~ $ df
Filesystem      1K-blocks      Used  Available Use% Mounted on
/dev/root        15021296   2428732   11949656  17% /
devtmpfs           437048         0     437048   0% /dev
tmpfs              441384         0     441384   0% /dev/shm
tmpfs              441384     11556     429828   3% /run
tmpfs                5120         4       5116   1% /run/lock
tmpfs              441384         0     441384   0% /sys/fs/cgroup
/dev/mmcblk0p1      61384     21368      40016  35% /boot
//active_nas/disk   1949057984 846123472 1102934512  44% /smb/active_nas/disk
//standby_nas/disk      972305984 839236008  133069976  87% /smb/standby_nas/disk

しばらくしてから再度 df すると NAS のマウントが外れているはずです。


バックアップする

rsync でバックアップします。
コピー元とコピー先を間違うと大変なことになるので、ひとまず dry run で試します。
pi@raspberry ~$ /usr/bin/rsync -n -rltv --max-size=100m --size-only /smb/active_nas/disk/ /smb/standby_nas/disk/

巨大なNASの場合、差分チェックの時間が馬鹿にならないので
ひとまず「--size-only」オプションでサイズ違いのファイルだけを対象にします。
出力を確認して、期待通りであれば「-n」オプションを外して実際にバックアップを実行。
ただし、まだ怖いのでファイル削除はしません。差分の追記だけ。かつ、100MBだけ。

pi@raspberry ~$ /usr/bin/rsync -rltv --max-size=100m --size-only /smb/active_nas/disk/ /smb/standby_nas/disk/

実行後、ログに出ているファイルが正しくコピーされていることを確認します。
問題なければ、全ファイルをバックアップし、稼働系で削除されたものは冗長系からも削除します。
pi@raspberry ~$ /usr/bin/rsync -rltv --delete /smb/active_nas/disk/ /smb/standby_nas/disk/


バックアップを定期実行

先ほどのコマンドをスクリプトにして crontab で週に一度実行します。
pi@raspberry ~$ cat rsync.sh
#!/bin/sh

echo '/usr/bin/rsync -rltv --delete $1 $2
pi@raspberry ~$ crontab -e
15 05 * * 1 /root/bin/rsync.sh /smb/active_nas/disk/ /smb/standby_nas/disk/

ただし、このコマンドには1つ致命的な問題があります。
万が一、稼働系のNASが故障して空のフォルダが出来上がってしまった場合、
空のフォルダをそのままバックアップして全データが消えます。
そこで、異常な状態だったらファイル削除しないなどの対策を行います。
対策後のスクリプトはこんな感じです。
#!/bin/bash

THRES=-10
SRC=$1
DST=$2

/bin/ls $SRC
/bin/ls $DST

# コピー元フォルダがなければ異常終了
if [ ! -d $SRC ]
then
  echo "$SRC Not Found" >&2
  exit 1
fi

# コピー先フォルダがなければ異常終了
if [ ! -d $DST ]
then
  echo "$DST Not Found" >&2
  exit 1
fi

# リストア中に「/tmp/restore」というファイルを置いておくと、
# cron でのバックアップ実行をスキップする。
if [ -f /tmp/restore ]
then
  echo "Restoring" >&2
  exit 1
fi

# マウントした領域のサイズを確認する。
srcsize=`/bin/df $SRC | /bin/grep / | /usr/bin/awk '{print $3}'`
dstsize=`/bin/df $DST | /bin/grep / | /usr/bin/awk '{print $3}'`
let diff=(${srcsize}-${dstsize})/1048576
if [ $diff -lt $THRES ]
then
  # コピー元のディスクサイズが極端に小さかったら以上終了。
  echo "Source data size is too small" >&2
  exit 1
elif [ $diff -lt 0 ]
then
  # コピー元のディスクサイズの方が小さかったら、ファイル削除しない。
  echo "Sync without delete" >&2
  /usr/bin/rsync -rltv $SRC $DST
else
  /usr/bin/rsync -rltv --delete $SRC $DST
  echo 2
fi


これで多少の障害があってもそこそこ安全にバックアップできるようになりました。

2017年3月12日日曜日

3Dプリンタを温度監視する

以前書いた、Raspberry Pi で3Dプリンタを無線化する方法の続きです。
Web カメラでリモートから監視できるようになったので、クローゼットの棚を3Dプリンタ専用にしてみました。


クローゼットに押し込んで静かになったのは良いのですが、
ちょっと怖いので遠隔監視を強化します。

材料

フィラメントホルダーは amazon で売っていたこれです。 家具の転倒防止用に縦に使うための突っ張り棒を横にして使いました。 通常の突っ張り棒の場合、細すぎてリールの回転が引っかかってしまいます。


カメラは中国製の怪しい暗視カメラです。
リンク先のカメラが私が購入した時のものから変わっているようです。
中華暗視カメラは結構トラブルが多いようなので、購入の際は失敗覚悟で。
赤外線LEDが点灯しないとか、普通のLEDだったとか。
私が購入したものも、ボリュームダイヤルが光量調整ではなくてON/OFFのみでした。
ダイヤル回したら ON というオシャレなユーザインターフェイス。

OctoPrint で映像監視する方法は以前に書いた記事をご参照ください。


温度監視のために温度センサ DS18B20 モジュールを使います。
実はもらいもののセンサー20種セットに偶然入っていました。

DS18B20 センサ単体でも良いのですが、
モジュールにはプルアップ抵抗が内蔵されていて接続が楽です。
ただし、センサ単体とモジュールではピン配列が異なるので要注意。


当然ですが Raspberry Pi。


Raspberry Pi を温度監視

熱暴走を避けるため、Raspberry Pi のCPU温度を監視します。
と言っても、OctoPrint の Plugin を有効にするだけです。
OctoPrint の画面で「Settings」から「Plugin Manager」を開きます。
「Navbar Temperature Plugin」を有効にして再起動すればOK。


室温を温度監視

M3D The Micro はヒートベッドが無いので室温が下がりすぎると造形物が歪みます。
かと言って上げすぎると Raspberry Pi が熱暴走します。
そこで、画面上に室温を表示するようにしました。
(適当な理由を付けていますが、ただ単にやってみたかっただけ。)

まず、OctoPrint の Plugin Manager で「Room Temperature Plugin」を有効にします。
Room Temperature Plugin の説明には
  「with a DS18b20 sensor connected on Pin n°4」
  (4番ピンにつないだDS18b20センサ)
と書かれているのですが、4番ピンってどこなのかと。

正解はRaspberry Pi の公式サイトに書いてあります
ピン番号は端から連番ではありません。
4番はたまたま4番目にありますが。

DS18B20 モジュールは DS18B20 センサ本体とはピン配置が異なります。
この写真のモジュールの場合は「S」がセンサピンです。
DS18B20 センサ単体の場合は真ん中のピンがセンサピン。
これをRaspberry Piの4番に繋ぎます。

写真の「-」は GND ピンのようです。
センサ単体の場合は平らな面(ラベルの面)を自分側に向けて左側が GND。
これを Raspberry Pi の Ground ピンに繋ぎます。

消去法で残る、真ん中のピンが VCC です。
DS18B20 の仕様は 3.0〜5.5V なので 3.3V でも 5.0V でもどちらでも良さそうですが、
大抵の説明では 3.3V に繋いでいるようです。

接続してから Raspberry Pi を起動すると、数秒おきにモジュールの LED が点滅します。
おそらく点滅のタイミングで温度測定しているんだと思います。
OctPrint への表示は測定後に反映されるので、あまり頻繁に温度が更新されるわけではなさそうです。

最終的に OctPrint のヘッダ部分はこんな感じになります。


これで、クローゼットをわざわざ見に行かなくても、
外からタブレット等で温度とプリント状態を見ることができます。
とは言え、監視だけ(制御なし)なのでプリント成功率が上がる訳ではないですが。

2017年1月29日日曜日

iOSアプリにシェアボタンを付ける

iOS アプリ「わたしのほんやさん」をバージョンアップしました。
今回、お気に入りの本を Twitter や Facebook でシェアできるボタンを追加しています。

シェアボタンの作成は非常に簡単です。
ただし、シェア先のサービスでの表示は結構バラバラ。。。

ボタンを配置する


まず、ユーザがタップするためのボタンを配置します。

  1. Storyboard の右下からUIButtonをドラッグしてViewの上にドロップ。
  2. ウインドウ右上の「8」のようなアイコンをクリックし、ViewController のソースを開く。もし他のファイルが開かれてしまったら、図の (2) のところから正しいファイルを選択。
  3. 先ほどドロップしたUIButtonを右クリックのドラッグでViewControllerにドロップ。UIButtonへの参照をメンバ変数として登録する。
  4. UIButtonを右クリックし「Touch Down」をドラッグしてViewControllerにドロップ。タップアクションを IBAction の関数として登録する。


シェアの動作を実装する

2017年1月21日土曜日

iOS アプリに Swift Realm を導入する

アプリ開発系の話が続きますが、書いておかないと忘れてしまうので。

今回はiOS アプリで Swift Realm を導入する方法です。



Swift Realmって何?


Realm は組み込み用DB(データベース)です。

iOS と android のどちらでも使えます。

iOS には Objective C 版と Swift 版があり、Swift 版が Swift Realm。



ただし、DBと言ってもSQL文などの高度な検索言語は使えません。

その代わり、クラスのメンバ変数がそのままDBカラムになっていたり、

オブジェクトがDBのレコードを表してしていたりします。

そのため、クラス定義でDBスキーマを定義し、

オブジェクト操作がレコード操作になるなど、

データベースの知識がなくても組み込みDBを扱うことができます。



ここまでで「は?宇宙語?」と思った方は気にせず先に進んでください。



2017年1月19日木曜日

オンライン少額決済サービス

ちょっと訳あって500円程度のものを短期間かつ散発的にオンラインで販売する方法を調べています。
多少手作業を挟んでも構わないので、顧客管理などはどうとでもなるのですがやはり最大の難関は決済手段。

一番確実なのは銀行振込ですがやはり手数料と入金確認がネックですね。
いくつか決済手段を調べたので備忘録として残しておきます。

前提条件


いまのところ、次のような用途を想定しています。

  • 単価は500円程度。高くても1000円まで。

  • 1ヶ月程度の期間限定で年に1、2回程度の開設。

  • 販売数は数十件から多くても500件程度。

  • 1ヶ月で数十件とは言え、1件ずつ振込確認するのは不可能。

  • 単価500円が数十件なのでせいぜい数万円程度の売り上げ。

  • 他人のWebサイトを使うためシステム開発は不可。
    せいぜいブログかfacebookでサイト構築する程度。

  • 購入者はさほどネットに詳しくなく、普通にスマホでLINE, Facebookを使う程度。

2016年12月27日火曜日

小学生レベルの工作をホバークラフトにする

小学生がよく作るようなストローで出来たホバークラフトを走らせてみます。
材料は前回分解したラジコンヘリの部品。

出来上がるとこんな感じ。


アップだとこんな感じ。
videocopter_2-1.png

作り方は超テキトーですが、強いて言えば次の通り。

豆ドローンからラジコン部品を流用


AIRHOGS のビデオコプターは不自然なほどの低価格な上、
手のひらサイズでカメラを搭載しています。
以前は2,000円を切っていたのですが
やはり不自然だったようで徐々に値上がりしているようですが。。。

ちなみに、新品でも飛ばなかったり、2、3回飛んだと思ったら
ダメになったり、やはりと言うか何と言うか、コメントの難しい品質です。

そんな何とも微妙な商品ですが、部品取りとして考えると素晴らしいコスパ。
秋葉原でこれだけの部品をバラで集めようと思うとかなり骨が折れるのではないでしょうか。

と言うわけで、とっとと分解します。