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" : ""
}

]
}

 

 

MediaInfoのコンパイルエラー

gentooをアップデートしていると、時々思わぬエラーで躓きます。

今回はMediaInfoがemergeに失敗しました。

 

/usr/lib/gcc/x86_64-pc-linux-gnu/5.4.0/../../../../lib64/libmediainfo.so: undefined reference to `ZenLib::Ztring::FindAndReplace(std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > const&, std::__cxx11::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> > const&, unsigned long, ZenLib::ztring_t)'
collect2: error: ld returned 1 exit status
make: *** [Makefile:414: mediainfo] エラー 1
 * ERROR: media-video/mediainfo-0.7.96::gentoo failed (compile phase):
 *   emake failed
 *
 * If you need support, post the output of `emerge --info '=media-video/mediainfo-0.7.96::gentoo'`,
 * the complete build log and the output of `emerge -pqv '=media-video/mediainfo-0.7.96::gentoo'`.
 * The complete build log is located at '/var/tmp/portage/media-video/mediainfo-0.7.96/temp/build.log'.
 * The ebuild environment file is located at '/var/tmp/portage/media-video/mediainfo-0.7.96/temp/environment'.
 * Working directory: '/var/tmp/portage/media-video/mediainfo-0.7.96/work/MediaInfo/Project/GNU/CLI'
 * S: '/var/tmp/portage/media-video/mediainfo-0.7.96/work/MediaInfo'

 

この、"collect2: error: ld returned 1 exit status"というのは、ほとんどの場合、そんな関数ねえよ!っていうエラーだそうで、どんな関数かは、その前の行を見ると、"undefined reference to `ZenLib::Ztring(以下略)"と書いてあるので、Zenlibという関数がないよ、ということだそうです。

 

で、自分でコードを書いたのなら、「あー、関数のスペルミスか」となりますが、emergeなのでそんなはずはありません。

google先生に聞いてみると、gccのバージョン違いで関数が見つからない場合があるようです。

 

gentoo ~ # emerge -p libzen

These are the packages that would be merged, in order:

Calculating dependencies... done!
[ebuild R ] media-libs/libzen-0.4.35

 

やはりありました!

これをemergeし直してから、MediaInfoをemerge -uするとすんなり通りました。

 

エラー文はよく読んでみるものですね。

Gentooのclamavでclamav-unofficial-sigsを使う

普通に

 

gentoo ~ # emerge clamav-unofficial-sigs

 

と、してインストールすると、現時点ではマトモに使えない3.7.2が落ちてくる。

これでは使えないので、test版を使うことに。

うちは64bit環境なので、

 

gentoo ~ # nano /etc/portage//package.accept_keywords

で、つぎの一行を追加

 

app-antivirus/clamav-unofficial-sigs ~amd64

 

そして、~amd64のテスト版を、バージョンまでしっかりとしていてemerge

 

gentoo ~ # emerge =app-antivirus/clamav-unofficial-sigs-5.6.1

 

続いてclamavアカウントに関する設定。

clamavアカウントがbashを利用できるように設定します。

 

gentoo ~ # usermod -s /bin/bash clamav

 

そして、アカウントをロック

gentoo ~ # passwd -l clamav

 

つづいて、設定ファイルを1カ所だけ変更。コメントアウトをハズします。

 

gentoo ~ # nano /etc/clamav-unofficial-sigs/user.conf

 

user_configuration_complete="yes"

 

最後に、ログのディレクトリを作成します。

 

gentoo ~ # mkdir /var/log/clamav-unofficial-sigs

gentoo ~ # chown clamav:root /var/log/clamav-unofficial-sigs

 

では、手動で実行します。

 

gentoo ~ # su clamav -c /usr/sbin/clamav-unofficial-sigs.sh

################################################################################
eXtremeSHOK.com ClamAV Unofficial Signature Updater
Version: v5.6.1 (2017-03-18)
Required Configuration Version: v72
Copyright (c) Adrian Jon Kriel :: admin@extremeshok.com
################################################################################

(以下、出力省略)

 

あとは、上記コマンドをcronに入れるだけですね。

 

GentooでPerlのコンフリクト

Perlのバージョンが古く、emerge -u worldでアップデートしようにもいろいろなPerlのモジュールがコンフリクトしてアップデートされないとき、

 

gentoo ~ # emerge --with-bdeps=y --backtrack=1000 --nodeps perl

 

 で、perl本体だけをバージョンアップし、さらに、

 

gentoo ~ # perl-cleaner --al

 

 で、perlのモジュールをすべてバージョンが一致したものに変えてくれる。

 

 それからemerge -u worldとか-uDNとかやるといいカンジ。

ディスククローンで複製したWindows7で起動時に0x0000007Bエラー

会社で異動があり、移動先でPCがあたる。

このPC、今時500GBのHDDだ。

WD BlueでAFT仕様。

ここ数年、異動してPCがあたる度に、SSDにディスククローンをして、SSDで利用していた。

なにしろ、セキュリティに厳しい会社なので、あちこちWindows標準のEFSで暗号化がかけられ、さらに、MS-OfficeやPDFなどは、社内からしか開けないような独自の暗号化も掛けている。

ただでさえアクセスが遅いHDDをSSDに載せ替えるだけでも、体感的にだいぶ早くなる。

で、今までAOMEI Backupperでライブクローンをすれば、差し替えるだけですんなり起動していたのだが、今回に限っては「Windowsを起動しています」の画面で再起動を繰り返す。

元のハードディスクにつなぎ替え、通常に起動して、システムエラー発生時「自動的に再起動する」をOFFにした。

 

Windows 7でシステムエラー発生時に自動で再起動しないよう設定する方法

121ware.com > サービス&サポート > Q&A > Q&A番号 013044

 

で、再度クローンしてSSDから起動。

すると、STOP 0x0000007Bと表示された。

このエラーでググっても、ディスク自体が悪いのでCHKDSKしろとか、MBRが壊れているのでbootsectでMBRを書き直せとか出てきますが、どれをやってもエラーは解決せず。

HDDから起動し、SSDをDドライブとして使ってみても、何ら問題なくSSDは使える。

HDDがAFTで物理セクタが4K、SSDが512バイトだから、セクタアライメントのせいか?と思ったけど、どうやらそうではなさそう。

AOMEIが悪いのかと、EASEUS TodoBackupを使ってみるも、症状は同じ。

万事休す。

 

と、英語でWindows7 Clone 0x0000007Bでググると、ありました!

マイクロソフトはもちろん、Acronis、Veritas、Citrixといった、有名どころのバックアップソフトの会社や仮想化ソフトの会社はしっかりと自体を把握しておりました。

 

"Stop 0x0000007B" error after you use a Group Policy setting to prevent the installation of devices in Windows 7 or Windows Server 2008 R2

https://support.microsoft.com/ja-jp/help/2773300/stop-0x0000007b-error-after-you-use-a-group-policy-setting-to-prevent

 

これによれば、グループポリシーエディタで他のデバイスIDやリムーバブルディスクのインストールを防止する設定を入れた場合、クローン後のデバイスからは起動できなくなっているようです。

それがわかるのは、次のレジストリの値が1になっている場合だそうです。

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\PnP\DisableCDDB

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\PnP\DontStartRawDevices

 

で、元のHDDを接続し、起動してregeditで確認してみると、ビンゴ!

両方ともに1になっていました。

これを0に書き換え、念のためControlSet001なども書き換えておきました。

そして、再起動など一切せずにAOMEI Backupperを使ってディスククローン。(再起動するとまた1に戻ります。)

クローンされたSSDにつなぎ直して起動。

 

ちゃんと起動しましたとさ。

 

もしかすると富士通ソフトウェア製のSystemwalker Desktop Keeperがインストールされているので、こいつが起動時(もしくは終了時)に、レジストリの値を書き換えているのかもしれません。

 

なお、元のディスクがもう手元にない場合、Windows PEやインストールディスクを使用して、コマンドプロンプトからRegeditを起動し、\Windows\System32\config\SYSTEM のレジストリハイブを読み込んで、上記の値を直すそうですが、私はこの方法は試していないため、他に譲ります。

 

参考 インストールディスクやWindows PEから、起動できないWindowsディスクのレジストリを直す。

レジストリの修正 - PCと解

 

とりあえず、この件に関する日本語解説がなかったので、備忘録として。