一眼レフで撮った写真をGoogle Photosに自動アップロード その1 PQI AirCardの固定IP化

私は10年前に購入したCanon EOS 40Dを今も現役で使い続けています。

f:id:naoyukinagano:20171031211751j:plain

 

しかし、このEOS 40Dは、当然Wi-Fiには対応しておらず、さらに記録媒体はコンパクトフラッシュという有様。

Wi-Fiに公式対応するためには、WFT-E3が必要になりますが、これがお高い!

 

スタパ齋藤の「週刊スタパトロニクスmobile」 サクッと無線接続!!EOS 40D用ワイヤレストランスミッター「WFT-E3」

 

で、かなり前からPQI AirCardにmicroSDを入れ、SDカードーコンパクトフラッシュアダプターというものを噛まして使っていました。

f:id:naoyukinagano:20171031211815j:plain

 

室内では家庭内LANのWiFiに、屋外では主にiPadテザリングを掛け、ShutterSnitchというアプリでJPEGだけ吸い出して大画面プレビューとしていました。

これはこれで便利でしたが、この変換、書き込みが遅いため、連射を多用する野鳥撮影には向いていなかったため、最近は通常のコンパクトフラッシュに戻し、どうしてもiPadに吸い出す場合はLightning USBカメラアダプタ+モバイルバッテリー、そしてコンパクトフラッシュリーダーライターを使って読み出していました。

ちなみに、iPad Pro 9.7 32GB + Lightning USB 3カメラアダプタ + エレコムMRS-MB07 + ANKER PowerCore Speed 10000 QC で稼働しております。 モバイルバッテリが5V 2.4Aを給電できないと、iPadはリーダーライタを認識できません。これはリーダーライタのせいではありません。

 

 

 

 

 

 

さて、話がそれましたが、そうなるとPQI AirCardが外出先では使われなくなります。

そこで、家庭内利用かつイエネコ撮影用に限定し、撮影されたそばからGoogle Photosにアップロードし、Google Photosではアルバム単位や一枚ごとに共有できるようにしました。

Googleドライブにアップロードして、Photosと共有するパターンはよく見かけますが、2048px以内なら容量にカウントされないPhotosに直接アップロードします。

 

前提として、私はプログラムが書けないサーバー管理者ですので、Linuxサーバー上で様々なソフトウェアをシェルスクリプトで組み合わせるという方法で達成します。

 

まずは、PQI AirCardのIPアドレスを固定化します。

PQI AirCaedに挿入するmicroSDカード直下にautorun.shというファイルを置くと、AirCardの起動時に自動実行してくれるのですが、これを利用して、宅内のWi-FiWi-Fi子機として接続しつつ、IPアドレスを固定化します。

参考にしたのはこのサイトです。

oichinote.com

Perlを書けるのがうらやましい・・・。

リンク先のパターンでは、PQI AirCard内のLinuxコマンド、/usr/bin/w2でWiFi接続とDHCPによるIPアドレス取得までやってしまい、DHCPで取得したIPアドレスの第4ブロックだけを91に書き換えるという動作を行っています。

私の家ではクラスCプライベートアドレスの192.168.0.0/24の中からDHCPを割り当てます。なので、192.168.0.91となります。

しかし、これをそのまま使おうとしたのですが、私のAirCardは最後にWebサーバー上のCGIに自身のIPアドレスをPOSTし、メールでスマホに報告させるスクリプトがautorun.shの最後に記述されています。

これが動かないのです。

しかし、192.168.0.91にpingもhttpもftpも通る。なぜ?

突き当たったのは、/usr/bin/w2だとデフォルトゲートウェイDHCPで設定されるのですが、その後にifconfigを実行すると、デフォルトゲートウェイが消去されることがわかりました。

PQI SAirCardにはrouteコマンドも用意されているので、route add default gw 192.168.0.xxxで設定されますが、なんせプログラムが書けないので、ifconfigする前にゲートウェイIPアドレスを取得して変数に代入するやり方がわからないのです。

だれか教えてプリーズ!

で、苦肉の策、デフォルトゲートウェイIPアドレスの最終ブロックが1であると決め打ちしてroute add default gwコマンド実行させます。

 

こんな感じになりました。私の場合は91から160に変更しています。

 #!/bin/sh
sleep 5
/usr/bin/w2

# sleep disable
kcard_cmd -s 0

sleep 1

script=`cat <<'EOF'
my $ifname;
my @ipadr;
my $pqi='160';

open (my $fh, '-|', qw/ifconfig/) or die $!;
while (my $line = <$fh>) {
$ifname = $1 if ($line =~ /^(\w+)/);
@ipadr = ($1, $2, $3, $4) if ($line =~ /inet\s+.*?(\d+)\.(\d+)\.(\d+)\.(\d+)/);
if ($ifname and @ipadr and ($ipadr[0] == 192) and ($ipadr[1] == 168)) {
system "ifconfig $ifname $ipadr[0].$ipadr[1].$ipadr[2].$pqi";
system "route add default gw $ipadr[0].$ipadr[1].$ipadr[2].1";
last;
}
}
close ($fh);

EOF
`

perl -e "$script"

 

この後、ifconfigの内容をWebサーバーのCGIにPOSTするスクリプトが続いています。

これはPQI AirCardをいじり倒しているひとりブログさんが、ツイッターにメンションしているものを、メールで飛ばすように変えたものです。

hitoriblog.com

autorun.shの最後のほうに次のように記述しました。

sleep 1


ip=`ifconfig mlan0 | grep inet`

wget -O - --post-data="${ip}" http://foo/bar/mail.cgi

 

CGIはPOSTされたIPアドレスをメールで報告するだけです。

サーバーに設置してあるmail.cgiはこんな感じ。どこから持ってきたのかしら?

#!/usr/bin/env perl

use URI::Escape;
read (STDIN, $inputescaped, $ENV{'CONTENT_LENGTH'});
$input = uri_unescape($inputescaped);

$sendmail = '/usr/sbin/sendmail'; # sendmailコマンドパス
$from = 'foo@bar.com'; # 送信元メールアドレス
$to = '1hoge@docomo.ne.jp'; # あて先メールアドレス
#$cc = 'hage@example.com'; # Ccのあて先メールアドレス
$subject = 'PQIAirCard'; # メールの件名
#$msg = 'body'; # メールの本文(ヒアドキュメントで変数に代入)

# robot対策

if ($input =~ m/inet/ ) {

$input =~ s/ //g; # 空白2文字分を削除

# sendmail コマンド起動
open(SDML,"| $sendmail -t -i") || die 'sendmail error';

# メールヘッダ出力
print SDML "From: $from\n";
print SDML "To: $to\n";
#print SDML "Cc: $cc\n";
print SDML "Subject: $subject\n";
print SDML "Content-Transfer-Encoding: 7bit\n";
print SDML "Content-Type: text/plain;\n\n";

# メール本文出力
print SDML "$input";

# sendmail コマンド閉じる
close(SDML);
}

print "OK";
exit; 

 

これで、カメラの電源投入後にスマホにメールが届けば成功です。

Raspberry Piのメディアレンダー化作戦 DLNA編

Raspberry Pi 2 Model Bのメディアレンダー化作戦。次はDLNAのレンダラーです。

Raspbian Stretch Liteですので、動画はレンダーしません。

LinuxはシンプルにCLI派です。

f:id:naoyukinagano:20171030225612j:plain

 

さて、RaspbianのDLNAレンダーですが、Gstreamerを利用したGmediarenderで構築します。

よくGmediarendererと記載されているサイトがありますが、Raspbian Stretchにはgmediarenderというパッケージがありますので、それを使います。

パッケージが用意されているなんて、さすが最新OS

なので、こちらも依存関係含めてパッケージを入れるだけ。

 root@raspberrypi:~# apt-get install libupnp-dev libgstreamer1.0-dev gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-alsa gmediarender

 

さて、ハマったのが起動。

普通なら

 root@raspberrypi:~# systemctl enable gmediarender

で、自動起動の登録、

root@raspberrypi:~# systemctl start gmediarender

で起動するはずですが、ps -eでもgmediarenderというプロセスは見つからず。

 

起動スクリプトが/etc/init.d/gmediarenderに入っているので見てみると、

[ "x$ENABLED" = "x1" ] || exit 0

こんな一行が。

$ENABLEDってどこに定義してあるんだろうとスクリプトを見ても、見当たりません。

ようやく探し当てたのが、/etc/default/gmediarenderというファイル。

というやらこいつが設定ファイルだったようです。

 

設定ファイル/etc/default/gmediarenderの中の

ENABLED=1

UPNP_DEVICE_NAME="$(hostname)"

INITIAL_VOLUME_DB=0.0

ALSA_DEVICE="hw:1,0"

DAEMON_EXTRA_ARGS="--logfile /var/log/gmediarender.log"

という5項目を設定しました。

ENABLEDがコメントアウトしてあったので起動しなかったんですね。

UPNP_DEVICE_NAMEは、DLNAのコントローラに通知する名前なので、よさげなものをつけて下さい。私はホスト名で。

INITIAL_VOLUME_DBは音量をdbで指定します。0は音量最高。こうしないと出力が小さくなりますので。

ALSA_DEVICEはサウンドデバイスの設定です。aplay -lで出てくるデバイスを指定できます。shairport-syncで指定したoutput_device=と同じ、USB Audioを指定しています。

DAEMON_EXTRA_ARGSは他に定義したい起動オプションを記載するようです。とりあえずログ指定を。

 

ではようやく起動です。

root@raspberrypi:~# systemctl start gmediarender

 

Windows10から見えるようになりました。

f:id:naoyukinagano:20171031003814p:plain

Raspberry Piのメディアレンダー化作戦 AirPlay編

今年で67になる母は、つい先日までイナカの実家で一人暮らしをしていました。

そんな67の母は私のすすめで2015年9月にDENONのネットワークオーディオRCD-N9を購入。

CDとラジオ、そして海外のネットラジオを楽しんでいました。

(購入当初はらくスマのdヒッツをBluetooth経由で聞いていましたが、Bluetoothが面倒なのか、dヒッツが高かったのか、聞くのをやめてしまいました。)

 

そこで、よかれと思いRaspberry Pi 2 Model Bを調達し、OpenMediaValueをインストールして、手持ちのCDを全てリッピングして保存、リッピングのやり方も解説して置いていきましたが、こちらも使われずにいたようです。

 

CDで聞けるなら、CDを入れ替えた方がいいようです。

 

そこで、弟夫婦との同居を機に、Raspberry Piを引き上げてきました。

そのRasoberry Piに第二の人生を送ってもらおうと、寝室のメディアレンダーとして活躍してもらうこととしました。

忘れないうちにインストール記録です。

 

OSはRaspbian Stretch Liteを、NOOBSを使わずに、イメージを直接SDに焼いて起動し、有線イーサを使ってdhcpcd.confで固定IPにすること、自分の持っている秘密鍵SSH接続できるようにすること、デフォルトのpiユーザーをsudo出来ないようにすること、sudoにパスワードが必要になるようにすること、自分がrootにsu(Switch User)できるように設定しました。

このあたりは難しくないので他に譲ります。

そして、sudoは面倒なので、rootで作業してしまいます。(よい子はまねしちゃだめ)

 

ケースから出しているので、こんな感じです。

f:id:naoyukinagano:20171030225137j:plain

 

Raspberry Piのデフォルトアナログ音声出力は音の悪さに定評がありますので(笑)、USB Audioに変えます。

 

たまたま以前まで使っていたBEHRINGER UCA202 U-CONTROLが手元にあったので、こちらを使います。

中身はTI PCM 2902のようです。たいへん素直なデバイスです。

せっかくデジタルOPT出力があるので、MARANTZのNA7004に入力して音出しを試みます。

f:id:naoyukinagano:20171030225612j:plain

NA7004って既にレンダラーじゃん!っていうツッコミはなしでお願いします。

完成したら別の部屋で使いますので・・・。

 

まずはAirPlayのレンダラーになっていただきます。

shairportの後継、shairport-syncを使います。(後継と言っても派生のようですが)

 

さて、githubからshairport-syncをgitしてautoconfしてmake・・・とおもったら、stretchはもうパッケージが準備されています。

さすが最新OS!

root@raspberrypi:# apt-get install shairport-sync

さて、設定しましょう。

たぶん、shairport-syncを動かすためのユーザーが必要でしょうから、作ります。

 root@raspberrypi:# groupadd -r shairport-sync

 root@raspberrypi:# useradd -r -M -g shairport-sync -s /usr/bin/nologin -G audio shairport-sync

デフォルトのアナログやHDMI出力から音を出すわけではないので、出力先を確認しておきましょう。

再生ソフトaplayの機能を借りて、再生デバイスの一覧を出してもらいます。

root@raspberrypi:~# aplay -l
**** ハードウェアデバイス PLAYBACK のリスト ****
カード 0: ALSA [bcm2835 ALSA], デバイス 0: bcm2835 ALSA [bcm2835 ALSA]
サブデバイス: 8/8
サブデバイス #0: subdevice #0
サブデバイス #1: subdevice #1
サブデバイス #2: subdevice #2
サブデバイス #3: subdevice #3
サブデバイス #4: subdevice #4
サブデバイス #5: subdevice #5
サブデバイス #6: subdevice #6
サブデバイス #7: subdevice #7
カード 0: ALSA [bcm2835 ALSA], デバイス 1: bcm2835 ALSA [bcm2835 IEC958/HDMI]
サブデバイス: 1/1
サブデバイス #0: subdevice #0
カード 1: CODEC [USB Audio CODEC], デバイス 0: USB Audio [USB Audio]
サブデバイス: 0/1
サブデバイス #0: subdevice #0

USBはカード1のサブデバイス0なので、hw:1,0かplughw:1,0のどちらかを指定することとなります。

 

shairport-syncのコンフィグはお行儀悪く、/etcの直下にshairport-sync.confがあります。

 root@raspberrypi:~# nano /etc/shairport-sync.conf

 

 general =

{

で始まる項目を設定していきます。

コメント多過ぎですね(笑)

 

まずは、AirPlayデバイス名を決めるので、name =の前のコメントアウト//を消して、ホスト名をデバイス名にします。

name = "%H"; // This means "Hostname" -- see below. This is the name the service will advertise to iTunes.

soxrを使うと音が良くなると聞いたので、// interpolation = "basic"を下記のように変えます。

interpolation = "soxr"; // aka "stuffing". Default is "basic", alternative is "soxr". Use "soxr" only if you have a reasonably fast processor.

ALSAドライバーを使うので、一応明示しておきます。

output_backend = "alsa";

なんか音が小さいな、と思ったら、ボリュームコントロールが有効でした。無効にします。

ignore_volume_control = "yes";

 

続いて

 alsa =

{

で始まる項目を設定していきます。

USB Audioにアウトプットするので、

output_device = "hw:1,0"; 

mixer_control_name = "PCM";

mixer_device = "default";

に変更します。("hw:1,0"は"plughw:1,0"でもOK。)

 

では、nanoを閉じましょう。ctrl + xでyですね。

 

次に、デーモンを自動起動する設定と、実際に起動するところです。

まずは、raspbian起動時に自動起動するように設定。

root@raspberrypi:~# systemctl enable shairport-sync

では、最後、祈るように起動しましょう。

root@raspberrypi:~# systemctl start shairport-sync

 

なにかいろいろ(最初にgithub版をmakeしたものをインストールしたので、アンインストールしてパッケージをapt-getしたため)やっているうちに、"Failed to attach mixer"と出てきました。

Raspbian自体を再起動するとしっかりと直りました。

このFailed to attach mixerは、ユーザーshairport-syncをグループaudioに入れていないことによって、ミキサーが操作できないために起こるエラーです。

 

さて、iPadから再生してみましょう。

f:id:naoyukinagano:20171031001331j:plain

 

ちゃんと選べて再生できるようになりました!!

寝室のESPEasy in Sonoff常時通電化

以前、SonoffというESP8266が搭載されたオールインワンなIoTリレーデバイスファームウェアをESPeasyに入れ替え、サーバーにHomebrigeをインストールと設定をし、Apple Homekitでコントロールするというのをやりました。

 

gentoolinux.hatenablog.com

gentoolinux.hatenablog.com

このとき、Sonoffのルールに、

On System#Boot do
gpio,12,1
EndOn

と記述し、通電されると約10秒後にSonoffが起動し、まずは通電を開始し、寝室のライトが付くようにしました。

しかし、この10秒が結構待たされます。

嫁にも言われます。

そのうち、帰宅後から就寝まで、つきっぱなしになります。(笑)

 

そこで、リビングの3chリレーと同様、Sonoffを常時通電させ、GPIOに接続した押しボタンスイッチでON/OFF出来るようにします。

 

スイッチに100VのL(ライン)とN(ニュートラル)が来ていれば、そこにSonoffを噛ませ、GPIOを結線するだけで以上終了・・・。だといいのですが、たいていは天井に隠蔽された差し込みコネクタでLだけが分岐され、スイッチにはL側だけが配線されています。

となると、Sonoffを動作させるためにAC100V(もしくはDC5Vですが、これもAC100Vで作る必要があります。)をスイッチ部分まで別途引いてくる必要があります。

 

まずは、天井の通線作業です。

幸いに、寝室スイッチ近くの脱衣場の天井に換気口があり、換気口をとれば腕が入ることと、風呂場の天井に点検口があること、その天井に常時通電の100Vを差し込みコネクタで分岐している部分が手に届きます。

 

VVF1.6を使っての通線作業です。

VVF1.6が堅くて良かった。

点検口から換気口まで約2m弱ですが、届いてくれました。

あとは換気口から手探りで寝室スイッチまでVVFを通線します。

f:id:naoyukinagano:20171004221420j:plain

 

その後、常時通電している差し込みコネクタを1端子多いものに交換し、通線したVVFと結線します。

ちなみに、この作業は有資格者でないとできません。

f:id:naoyukinagano:20171004221515j:plain

 

では、ここからは有資格者じゃなくてもできる改造作業です。

 

まず、寝室の天井ランプに仕込んでいたSonoffを外し、ランプを原状回復させます。

f:id:naoyukinagano:20171004221833j:plain

 

Sonoffにさらなる改造を施します。

通常のSonoffは、Inputの100vをDC変換し自身の動力源としつつ、リレーを介してそのままOutputに渡しています。

しかしながら、先ほど申し上げたように、スイッチには100のL側しか来ていません。

なので、InputとOutputを絶縁した上で、Output側の接点両方をリレーでON/OFF出来るように結線し直さなくてはなりません。

 

まずは、取り出したSonoff基板のN側結線を、基板ごとラジオペンチを使って壊します。

カッターで予め切り込みを入れておくときれいに切れると思います。

赤丸の部分です。

f:id:naoyukinagano:20171004222646j:plain

 

続いて、L側の結線を絶縁です。

結線は裏面と表面両面にパターンがあります。

裏のパターンは次の写真の赤丸のところで、先に半田を吸い取って薄くしてから、カッターでカットします。

円内上部には抵抗の足が、円内右にはリレーの足があります。

f:id:naoyukinagano:20171004223011j:plain

 

表面もL側結線のパターンが走っているので、5VDC変換回路に影響のない、リレーギリギリのところでパターンカットします。

見づらいですが、リレーに沿って、カッターでパターンを削っています。

f:id:naoyukinagano:20171004223533j:plain

 

パターンカットしたら、しっかりとテスターで絶縁されているか確認しましょう。

 

続いて、Output側をリレーにつなぎます。

裏面のパターンが近い部分に、おあつらえ向きに、元々半田が持ってあります。

この間をなるべく太い線で結線します。

電流も多めにがなれるでしょうから、半田も多めに盛っておきましょう。

(写真の青い被服部分は取っ手として使っていたので、半田が終わったらカットしました。)

f:id:naoyukinagano:20171004224042j:plain

 

つづいて、スイッチとなるGPIOの結線ですが、これは以前にピンヘッダーを半田付けしていました。

シリアル通信で使わなかった1本が、実はGPIO14だったのです!

こんな小さくて安いのに、なんて拡張性が高いのでしょう!!

(今、Sonoffをもう一つ買って、温湿度センサーのDHT22をこのGPIO14に結線し、室外温度を計測することを計画中です。)

写真はもうGNDとGPIO14を結線していますが、スイッチがある側から、3.3V,RX,TX,GND,GPIO14です。

このGPIO14とGNDを取り出し、プッシュスイッチに接続し、ショートさせてSwitch Inputとします。

プルアップ抵抗をESP8266内部に持たせるので、抵抗は結線せずに直接プッシュスイッチに接続する予定です。

f:id:naoyukinagano:20171004225226j:plain

 

GPIO14とGNDのケーブルをケースから出します。

f:id:naoyukinagano:20171004225326j:plain

 

ジャンパーケーブルは細いので、そのままでは当然VVF用のスイッチには入りませんから、棒形圧着端子に入れて圧着を掛けます。

私はジャンパ端子ごと圧着しました。その方が抜けにくそうだったので。

 

棒形圧着端子はあ例えばこんな商品です。(太さがこれで適合するのかは保証しません。)

 

こんな感じで圧着しました。

f:id:naoyukinagano:20171004230106j:plain

 

では、これをスイッチがある壁の中に押し込みます。

Sonoffは高さが88mmなので、壁のスイッチの穴は簡単に入りますし、厚さも23mm程度なので、LGSスタッドの主流である45形か50形であれば、フトコロは45mmか50mmですので、余裕で入ります。

VVFが硬いことがここでは難儀しますね。

 

ここからは電気工事士有資格者の作業となります。

通線した100VのLを片切スイッチに、片切スイッチの片方をSonoffのInputのLに。100VのNはそのままSonoffのInputのNに。と、言いたいところですが、私はパイロットランプ付きのスイッチを購入したので、差し込みコネクタで分岐し、片方をパイロットランプ付きスイッチのNに接続しました。

今までのスイッチに付いていた寝室ランプのVVFをSonoffのOutputに接続します。

GPIO14とGNDのケーブルをプッシュスイッチに接続します。

 

接続途中ですが、スイッチの作業中の様子です。

f:id:naoyukinagano:20171004231407j:plain

 

全て結線して壁に押し込んで、スイッチをC形挟み込み金具で壁に固定し、スイッチパネルをつけて完成です。

f:id:naoyukinagano:20171004231515j:plain

 

上がGOIO14とGNDをショートさせるプッシュスイッチ、下がSonoffに電源を供給するパイロットランプ付き片切スイッチです。

Sonoffが暴走して再起動する際は、下のスイッチをOFF/ONすれば良いということになります。

 

ここまでできたら、SonoffのESPEasyの設定を変更します。

 

Sonoffに設定しているIPアドレスにブラウザからアクセスしましょう。

まず、Devicesです。

すでに、前回設置した際に、Task1にGPIO-12としてリレーを割り当て、Task2にGPIO-0として基板上のボタンを割り当て、このボタンでもON/OFF出来るようにしていました。が、前回も今回も、ボタンは押せない場所にあります(笑)。

このGPIO-0をGPIO-14に変更するだけです。

 

以下、ブラウザのキャプチャですが、Task2のEditを押します。(すみません。すでにGPIO-0からGPIO-14に変更した画像です。)

f:id:naoyukinagano:20171004233048p:plain

 

そして、「1st GPIO:」からGPIO-14を選び、念のため「Pull UP:」にチェックが入っていることを確認して「Submit」を押します。(なにせ、プルアップ抵抗をつないでませんからね。Pull UPにチェックしましょう。)

 

Rulesは買えるところがありませんが、一応おさらい。

f:id:naoyukinagano:20171004233427p:plain

 

次のように記載しています。

On System#Boot do
   gpio,12,1
EndOn

On PowerOn Do
   gpio,12,1
EndOn

On PowerOff Do
   gpio,12,0
EndOn

On Button#State Do
   If [Button#State] = 0
     gpio,12,0
     gpio,13,1
   Else
     gpio,12,1
     gpio,13,0
   EndIf
EndOn

 

GPIO-0のときも、GPIO-14の時も、devicesでButtunというデバイス名で定義しているので、特に変更ありませんでした。

 

ちなみに、Homebridgeも変更するところはありません。

これで完成です!

 

寝室ランプがスイッチでも、AppleHomekitでも瞬時に反応し、快適になりました。

 

homebridge-http(github版)のエラー解消

本家npmでインストールできるhomebridge-httpは、スイッチのON/OFF状態を1か0で応答しなければ解釈できませんが、ESPeasyはGPIOのステイタスをJSON形式で返します。

githubに上がっている最新版はJSON形式のステイタスをサポートするのですが、なにやらエラーが起きます。

というところまでが、前回、nodeMCUにESPeasyをインストールして3chリレーを制御し、リビングの3つの照明をコントロールしたという話。

 

gentoolinux.hatenablog.com

本家npm版だと、照明の状態とiOSのホームアプリに表示される状態が一致しません。常にOFFの状態で開始されます。

(でも、何度かタップすれば良かったので、利用自体にはそれほどクリティカルな問題ではありませんでした。)

しかし、なんとも歯がゆい。

 

そこで、github版を、プログラミングが何一つ出来ない私が急ごしらえで直しました。

 

まずは、本家npm版をアンインストールし、github版をインストールします。(念のためキャッシュの削除も)

 

gentoo ~ # npm rm homebridge-http

gentoo ~ # npm cache clean

gentoo ~ # npm install -g git+https://github.com/rudders/homebridge-http#master

 

githhubからインストールする場合は、URLの前にgit+を、最後にブランチを(ここでは#maaster)を記載する必要があります。

 

で、config.jsonは前回書いているので、そのまま起動すると、一応は起動します。

が、iOSのホームアプリを起動すると、

 

ReferenceError: that is not defined 

 

のようなエラーが出ます。

で、本体を直します。

/usr/lib/node_modules/homebridge-http/index.js

の、221行目付近

var customStatusOn = that.status_on;
var customStatusOff = that.status_off;

var customStatusOn = this.status_on;
var customStatusOff = this.status_off;

に、

233行目の

that.log("Status On Get Power State", statusOn);

this.log("Status On Get Power State", statusOn);

とします。

 

次に、

 

ReferenceError: compareStates is not defined

 

というエラーも出ますので、61行目から71行目にある

function compareStates(customStatus, stateData) {
var objectsEqual = true;
for (var param in customStatus) {
if (!stateData.hasOwnProperty(param) || customStatus[param] !== stateData[param]) {
objectsEqual = false;
break;
}
}
// that.log("Equal", objectsEqual);
return objectsEqual;
}

をコピーして、212行目あたりにペーストします。

 

これで、homebrigeを再起動すると、しっかりとJSONでのステイタスを解釈し、比較してスイッチがONなのかOFFなのかを判定し、iOSのホームアプリに返してくれます。

 

githubに不具合報告したいところですが、プログラミングの知識も英語力もないので、報告できません。

だれか、代わりに報告してくれないかなぁ・・・。

 

 

GCC 5系アップデート後のコンパイルエラー

gentooでgriveをemergeしていたら、「定義されていない参照です」と出てエラーで止まってしまいました。

エラーの参照内容を見ると、CppUnit::で始まっている。

ということはこのCppUnitのライブラリでエラーが起きているようです。

ちょっとググると、GCCを5系にアップデートしてから、いつもとはちょっと違う、ちょっとしたライブラリ更新をしなければ、「std::__cxx11」の関数で同様の定義されていない参照のエラーになるらしい。

 

Upgrading from gcc-4.x to gcc-5.x - Gentoo Wiki

 

で、実施するのは、gentoolkit-0.3.1以上の場合は、次のコマンド

 

gentoo ~ # revdep-rebuild --library 'libstdc++.so.6' -- --exclude gcc

 

を、実行すると、だいぶ時間がかかりましたが、ライブラリが更新され、griveもemerge出来るようになりました。

 

node MCUにESP Easyをインストールして3chリレーを制御

以前、Sonoffを使って1chリレーを作成しました。

今回はその3ch版を作ってみました。

しかも、物理的な押しボタンスイッチからもON/OFFできるようにします。

リビングの3つの電気を、壁のスイッチからも、Webからも操作できるようにするためです。

 

ESP Easyに対応するデバイスはいくつかあります。

ESP Hardware - Let's Control It

私はこの中からNode MCU V2を選びました。

 

 

それと、リレーが必要です。

こちらも完成品がありました。

4ch仕様です。 

サインスマート(SainSmart) 4チャンネル 5V リレーモジュールfor Arduino DSP AVR PIC ARM
 

 さがせば日本語の仕様書も出てくるので大変ありがたいです。

USBの5Vで動きます。

ただし、接点がGNDに落ちるとリレーが動作するタイプです。

まぁ、リレーは3接点回路なので、常閉側に負荷回路を接続すると、5V印加で動作するようになります。

(その代わり、常閉なので、Node MCUの電源が落ちると、付加回路がONになりますが・・・。)

 

ESP Easyのインストールは前回実施したのでここでは割愛。

 

まずは、ジャンパーピンでNode MCUとつなぎますが、つないではいけないGPIOがいくつかあります。

この解説が次のリンク

Configuration - Let's Control It

おいおい!使えないGPIO多過ぎじゃねーかよ!

で、当初GPIO15とリレーを結線しましたが、LOW for bootで、かつ、リレーはLOWで動作。大量の電流が流れるせいか、Node MCUが起動しない、という状況が発生します。

なので、シリアル通信に使うGPIO4と5をシリアル通信用とせず、スイッチ用としました。

どうせ、シリアル通信はしません。

 

というわけで、GPIOを次のように使用しました。

 

GPIO-4 : Switch01 →押しボタン1へ

GPIO-5 : Switch02 →押しボタン2へ

GPIO-12 : Switch03 →押しボタン3へ

GPIO-13 : Relay01 →リレーモジュールの1へ

GPIO-14 : Relay02 →リレーモジュールの2へ

GPIO-16 : Relay03 →リレーモジュールの3へ

他に、Node MCUとリレーモジュールとはVCCとGNDを結線します。

Node MCUにはMicroUSBから5Vを給電、リレーモジュールにはNodeMCUからのVCC5V結線で給電です。

 

Node MCUにUSB電源を供給してからブートしてLAN内からアクセスできるようにするまでは、以前のこの記事を参考にしてください。

gentoolinux.hatenablog.com

ESPEasyで、まずはGPIO-4とGPIO-5に割り当てられているシリアルを解放します。

HardwareのページでSDAとSCLのプルダウンから空白を選びます。

Pin modeもボタン類のGPIO-4,5,12はDefaultで。

逆に、リレーのGPIO-13,14,16はOutput Highにしました。が、あんまり意味なさそう・・・。

f:id:naoyukinagano:20170828232439p:plain

 

さて、ESP Easyのデバイス設定です。

まず、スイッチ側ですが、内部のプルアップ抵抗を使い、スイッチが押されるとGPIOがGNDに落ちるて、ESP Easyにスイッチが押されたことが認識されるようにします。

下記のPull Upにチェックを入れ、Switch typeをSwithに、Switch Button TypeをPush Button Active Lowとします。

f:id:naoyukinagano:20170828231426p:plain

 

リレー側ですが、実は、リレーもほぼ同じです。

あ、Swith Button Typeが違うか。

f:id:naoyukinagano:20170828231430p:plain

 

そうそう、IDXはLAN内のESP Easyで一意の番号をつけましょうとのことです。確か・・・。

 

で、ルールを書いていきます。

ESP Easyのデフォルトでは、Ruleは表示されていません。

Tools → AdvancedからRuleにチェックを入れると出てきます。

f:id:naoyukinagano:20170828232131p:plain

 

Ruleに記入したことを解説しながら示します。

 

On System#Boot do
gpio,13,0
gpio,14,0
gpio,16,0
EndOn

まずはboot時、動作確認も込めてリレーがオンになります。

 

on Switch01#State1 do
If [Switch01#State1] = 1
event Switch01On
else
event Switch01Off
endif
endon

on Switch02#State2 do
If [Switch02#State2] = 1
event Switch02On
else
event Switch02Off
endif
endon

on Switch03#State3 do
If [Switch03#State3] = 1
event Switch03On
else
event Switch03Off
endif
endon

ここは、GPIO-4,5,12である、それぞれSwith01から03までのボタンが押され、GNDに落ちたときの動作を記述しています。

まずは、現在ONなのかOFFなのかのステイタスの判定をします。

1がOFF、0がONの状態です。

ステイタスが1なら、eventであるSwitch01Onを実行、それ以外ならSwitch01Offを実行です。

で、そのeventの定義を続けてRuleに記載します。

 

on Switch01On do
inputswitchstate 0,0
gpio,13,0
endon

on Switch01Off do
inputswitchstate 0,1
gpio,13,1
endon

on Switch02On do
inputswitchstate 1,0
gpio,14,0
endon

on Switch02Off do
inputswitchstate 1,1
gpio,14,1
endon


on Switch03On do
inputswitchstate 2,0
gpio,16,0
endon

on Switch03Off do
inputswitchstate 2,1
gpio,16,1
endon

最初の4行を見ましょう。

まず、ここからevent であるSwitch01Onですよという定義です。

inputswitchstateはDeviceにあるValuesを変更する命令です。

inputswitchstate 0,0は、Deviceにかかれた1行目のデバイスのValues(ここではSwitch01)を0にするという意味です。

0が1つめですね。

この命令を入れないと、Valuesが変わらないため、物理スイッチでON/OFFした状態とLAN上でON/OFFした状態が一致しない状況になります。

で、3行目がGPIO-13を0、つまりLOWにしましょうと言うことです。

リレーはLOWでリレーONですから、通電状態になります。

4行目がeventの終了です。

あとは、そのONとOFFパターンとスイッチ3回路で6パターンのイベントが書かれています。

 

このルールが試行錯誤だったので、一番時間かかりました。

 

設定等が終わったら、ケースに収めます。

下駄が高すぎて、NodeMCUはフタが閉まりません(T_T)

f:id:naoyukinagano:20170828231433j:plain

 

一つに収まるちょうど良いケーズがなかったので、リレーモジュールも別体のケースに。

f:id:naoyukinagano:20170828231436j:plain

 

ちなみに、このケースは見えないように壁の中に埋め込みます。

ということは、ケースの高さは壁の中の厚み未満に、横幅はコンセントの穴の幅未満に。今回は2列用のプレートを使うため、穴の幅は約100mm(正確には97mm)。高さもコンセントの穴の高さ未満で、穴の高さは95mmです。

 

あとは壁に埋め込みます。

ここからの作業は有資格者でなければ出来ません。

私はこのようなコンセント作業を自分で出来るよう、第二種電気工事士を持っています。

 

上部の6つスイッチのうちよく使う右3つのスイッチをIOT化します。

拙宅のスイッチはすべて神保電器のJ-WIDEシリーズですが、このシリーズには押しボタンというのがありません。

なので、パナソニックのコスモWIDE21のスクエアタイプに変更しました。

これなら押しボタンが用意されているのです。

f:id:naoyukinagano:20170828231439j:plain

 

仕上がりです。

下のコンセントの横にあるスイッチは、Node MCUに電源を供給するUSB電源のAC側スイッチになっています。

何かあって電源再起動の際も、いちいち壁面を開けずにOFF/ON出来ますし、ステイタスランプも付いていますので、不具合時の切り分けにもなります。

 

我ながらうまく収めました。

f:id:naoyukinagano:20170828231442j:plain

 

で、HomeBridgeにはnpmからhomebridge-httpをインストールします。

 

gentoo # npm install -g homebridge-http

 

config.jsonは、前回のsonoffを含めて下記の通り。

ただし、ESPEasyはGPIOステイタスをJSONで返すのに対し、homebridge-httpの現状版は0か1でステイタスを受け取るような仕様です。

(将来的にはjson対応するようで、githubにはJSON対応の最新版がありました。が、インストールしても正しく動かない・・・)

そうすると、Apple HOMEアプリ上のステイタスの取得に時間がかかったり、正しくなかったりします。

いつかMQTTとかに移行しないとダメなのかしら・・・。

 

{
"bridge": {
"name": "Homebridge",
"username": "00:00:00:00:00:00",
"port": 51826,
"pin": "031-45-154"
},

"description": "dummy",

"accessories": [
{
"accessory": "SonoffBasicESPEasy",
"name": "寝室の電気",
"ip": "192.168.0.151"
},
{
"accessory": "Http",
"name": "SnowBall",
"switchHandling": "yes",
"http_method": "GET",
"on_url": "http://192.168.0.152/control?cmd=event,Switch01On",
"off_url": "http://192.168.0.152/control?cmd=event,Switch01Off",
"status_url": "http://192.168.0.152/control?cmd=status,gpio,13",
"status_on": {
"log": "",
"plugin": 1,
"pin": 13,
"mode": "output",
"state": 0
},
"status_off": {
"log": "",
"plugin": 1,
"pin": 13,
"mode": "output",
"state": 1
},
"service": "Light",
"brightnessHandling": "no",
"brightness_url": "",
"brightnesslvl_url": "",
"sendimmediately": "",
"username" : "",
"password" : ""
},
{
"accessory": "Http",
"name": "PH5 Plus",
"switchHandling": "yes",
"http_method": "GET",
"on_url": "http://192.168.0.152/control?cmd=event,Switch02On",
"off_url": "http://192.168.0.152/control?cmd=event,Switch02Off",
"status_url": "http://192.168.0.152/control?cmd=status,gpio,14",
"status_on": {
"log": "",
"plugin": 1,
"pin": 14,
"mode": "output",
"state": 0
},
"status_off": {
"log": "",
"plugin": 1,
"pin": 14,
"mode": "output",
"state": 1
},
"service": "Light",
"brightnessHandling": "no",
"brightness_url": "",
"brightnesslvl_url": "",
"sendimmediately": "",
"username" : "",
"password" : ""
},
{
"accessory": "Http",
"name": "Spot & Bracket Light",
"switchHandling": "yes",
"http_method": "GET",
"on_url": "http://192.168.0.152/control?cmd=event,Switch03On",
"off_url": "http://192.168.0.152/control?cmd=event,Switch03Off",
"status_url": "http://192.168.0.152/control?cmd=status,gpio,16",
"status_on": {
"log": "",
"plugin": 1,
"pin": 16,
"mode": "output",
"state": 0
},
"status_off": {
"log": "",
"plugin": 1,
"pin": 16,
"mode": "output",
"state": 1
},
"service": "Light",
"brightnessHandling": "no",
"brightness_url": "",
"brightnesslvl_url": "",
"sendimmediately": "",
"username" : "",
"password" : ""
}

]
}