USBリレーで遊んでみる Linux編
本稿では、LinuxからUSBリレーの制御を行います。USBリレーは、独立した端点のON/OFFをUSB接続したホストから制御できるデバイスで、ここではネット通販などで安価に購入できるものを使用しています。
2019-09-30
1. はじめに
2. USBリレー
3. 制御
・
シリアルポートエミュレーション
・
/dev/hidraw
4. 実践例
5. まとめ
ときに特定のデバイスのON/OFFをパソコン上から制御したい場合があります。例えば、携帯機器の過充電を避けるため一定時間だけ充電を実行したいというような場合やUSB機器等の強制リセットを実行したい場合などです。最近ではスマフォから制御するスマートコンセントなどが市販されているようですが、それではパソコンから制御するのは簡単ではないので、ここではUSBリレーを使ってパソコン上から電源のON/OFFを制御する方法について考察します。
最初に、本稿で扱ういくつかのUSBリレーについて述べ、その後、それらのドライバおよび制御法について検証し、最後に実践例を紹介します。
実行環境は、Vine Linux 6.5 x86_64 (kernel 4.4.110-2vl6)、および、Open SUSE 15.1 (kernel 4.12.14-lp151.28.16-default)です。
USBリレーはネット通販で簡単に買える物を想定しています。実際に売られている物には概ね三種類あり、シリアルポートエミュレーションで動作するもの、/dev/hidrawで動作するもの、ビットバンモードで動作するもの、となっています。ここでは、シリアルポートエミュレーションで動作するものと/dev/hidrawで動作するものについて紹介します。ビットバンモードで動作するものは直接的にアプリなどを書く場合には有利ですが、現状、とりあえず動作させるという使い方には不向きだと思います。
手元にあるUSBリレーはすべてamazonで購入しました。単接点のものは500円〜1,000円程度で、シリアルポートエミュレーションのものの方がエミュレーションの分いくらか割高ですが、値段は発送地の違いの方が影響します。日本の業者経由ならば割高なだけにすぐ届きますが、中国(原産地)発送の場合は安価ではあるものの、いつ品物が届くのか見当がつきません。
本稿で取り上げる現物は以下の二種になります。価格は税込、amazonで購入当時(2019年4月)のものです。
SODIAL HW667シリアルポート制御リレーモジュール 585円
画像はケースに収まったもの。USB Type Aコネクタのオスがケースの外側に出ています。USB接続が確立すると赤のPWR LEDが点灯し、リレーの接点がONになると赤のSTATUS LEDが点灯します。
SODIAL(R)5V USBリレー1チャンネルプログラマブルコンピュータ制御 スマートホーム 489円
こちらは、kernel標準のhidドライバで動作するUSBリレーで、USB Type Bのメスがコネクタとしてついています。USB接続が確立すると赤のPWR LEDが点灯し、リレーの端点がONになると緑のSTATUS LEDが点灯します。
両者を比較した場合、後者の方がエミュレーションという回りくどいことをしておらず、二色のLEDで視認性もよく、専用ツールでステイタス情報を取得できるなど、専用ツールを用意する手間を差し引いても単純にUSBリレーとして使いやすいのですが、実際に使ってみると反応しなくなることがたまにあり、やや信頼性には欠ける印象です。
なお、USBリレーに限らず、一般的なリレーでは一つの接点に3つの端子(COM, NC, NO)があり、通常はCOMとNOを用います。COMとNCを用いると接点の動作が逆(ONで断線、OFFで通電)になりますので工作の際は注意する必要があります。
・シリアルポートエミュレーション
このタイプのUSBリレーをUSBポートに接続するとシリアルポート(/dev/ttyUSB0)が見えるようになります。ON/OFFの制御はこのデバイスファイルへの書き込みによって行います。当然ながら利用者はデバイスファイルへの書き込み権限が必要です。
echo -ne "\xa0\x01\x01\xa2" >/dev/ttyUSB0 #ON
echo -ne "\xa0\x01\x00\xa1" >/dev/ttyUSB0 #OFF
最初の0xa0は制御コードであることを示すヘッダーです。二番目の値はそのUSBリレーが持つどの接点を制御したいのかを識別するためのインデックスナンバーで、本稿で扱っているUSBリレーの接点は一つだけなので0x01になっています。三番目の値は、0x00でOFF、0x01でONになります。最後の値はこれまでの三値を足したものでいわゆるチェックサムです。
なお、制御コードをechoで書き込んでもechoが戻って来ずにストールする場合があります。この場合はドライバモジュールの再読み込みで問題解決します。ch341とusbserialを、一旦、rmmodし、再度、modprobeしてください。sttyで確認した時、下記のようになっていれば正常に動作するはずです。異常時にはspeedが115200 baudになっています。一度、正常に認識されると以後は大丈夫のようです。
# stty -F /dev/ttyUSB0
speed 9600 baud; line = 0;
-brkint -imaxbel
・/dev/hidraw
ここまでこのタイプのUSBリレーを/dev/hidrawで動作するものと分類してきましたが、実際の制御では/dev/hidrawを意識することは、ほぼ、ありません。なぜならこのUSBリレーでは専用のコマンドラインツールを使用するため、/dev/hidrawはユーザー側からは隠蔽されてしまうからです。というわけで、まず、そのコマンドラインツールを作る必要があります。使用しているディストリビューションに用意されているのであればそれを利用するだけなのですが、残念ながら手元の環境にはなかったのでここでは自力で用意することとします。
このリレーを制御するツールは複数ありますが、ここではhidusb-relay-cmd(usb-relay-hid)を使用します。これを選んだ最大の理由はhidapiを使っていないことです。hidapiはUSBのHID用ライブラリでスタンダードなもののようなのですが、Vineにはインストールできませんでした。
hidusb-relay-cmdの作成にはlibusbが必要なので適宜インストールして下さい。その後、下記を実行します。
$ git clone https://github.com/pavel-a/usb-relay-hid
$ cd usb-relay-hid/commandline/makemake/
$ make all
$ sudo /bin/cp hidusb-relay-cmd /usr/local/bin
参考までに上記を実行するrpmも作ってみました(
usb-relay-hid-1.4-0pe4.src.rpm)。このsrc.rpmはソースファイルを、ビルド実行時、動的にダウンロードするようになっており、パッケージに含まれているソースファイルはダミーの空ファイルです。
使用法は以下のようにON/OFFします。デフォルトでは実行はrootのみに限られます。
# hidusb-relay-cmd on 1
# hidusb-relay-cmd off 1
本稿で扱っているリレーは一つなので上記ではリレーを特定していません。数字の1は、そのリレーが持つどの接点を制御するかを示しています。これもこの例では一つしかないので単純に1になっています。リレーが複数ある場合には、まず、下記のように情報を得、
# hidusb-relay-cmd enum
Board ID=[959BI] State: R1=ON
Board ID=[BITFT] State: R1=OFF R2=OFF
IDを指定してON/OFFを実行します。
# hidusb-relay-cmd ID=BITFT on 2
上記の場合は、BITFTというIDを持つリレーの二番目の接点をONにする、という意味になります。
ここまでのコマンドはすべてrootで実行したという前提ですが、一般ユーザでhidusb-relay-cmdを実行するには多少の工夫が必要です。一番簡単なのはステッキービットを立ててしまうことです。
# chmod 4755 /usr/bin/hidusb-relay-cmd
ステッキービットはセキュリテイー的に推奨されないのでsudoとかも考えられますが、usb-relay-hidのREADMEでは、udevでのパーミッション制御を推奨しているようです。
SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05df", MODE:="0666"
上記のような設定を99-usb-relay.rulesのようなファイルに書いて/etc/udev/rules.d/に設置します。idVendorおよびidProductの値は個別の環境に合わせて下さい。この設定は再起動するか、「udevadm control -R」で有効になります。udevadmで有効化する場合は現状のデバイスには効果がないので設定を反映するためには該当のデバイスを挿し直す必要があります。
USBリレーを使いたいと思った最初の動機はモバイルルータの電源管理です。現在、MVNOのデータプランでは最安月額500円程度でインターネットへの常時接続が可能で、これを利用して遠隔地にあるサーバの緊急管理回線を確保しようと考えました。この時、意外に問題になるのがモバイルルータを常時稼動させることです。電源アダプタを接続したままにすると過充電となり、バッテリーの寿命が縮むだけならまだしも発火の危険性も生じます。そこで、モバイルルータのバッテリー残量が一定値になったら一定時間充電するような機構が求められました。
システムは以下のような構成で、EPSON NP11は食パン程度の大きさのいわゆるネットトップ機です。on boardのNICでローカルのメインネットワークに接続し、USB無線LANでモバイルルータと接続しています。このモバイルルータにはイオンモバイルTYPE2のSIMが搭載されており、グローバルIPでインターネットと接続しています。また、USBカメラでは実家の外観を常時録画しています。
機体 | EPSON NP11 |
CPU | Intel(R) Atom(TM) CPU 230 @ 1.60GHz |
Memory | 2GB |
HDD | Hitachi HTS543216L9A300 320GB |
on board Network | Realtek RTL8168 PCIe Gigabit ethernet Contoller |
USB WLAN adaptor | MediaTek MT7610U |
USB Camera | Microsoft LifeCam HD-6000 |
USB Ext. HDD | 1TB |
USB Relay | SODIAL HW667 |
OS | Vine Linux 6.5 |
Mobile Router | Freetel FTW141A aria |
この機体におけるモバイルルータの電源管理は、5分毎にモバイルルータの管理ページにアクセスし、バッテリーの状態を確認、一定値を下回ると2時間の充電を実行するようになっています。この充電のON/OFFをUSBリレーが担っています。このUSBリレーの接点にはUSBの4本あるラインの内の電源線(赤)が割り込んでおり、モバイルルータ電源供給用のUSBマイクロBオスコネクタへと接続されています。実運用中のスクリプトが以下です。
aria_charge.sh
画像の白いケーブルが電源供給用のUSBケーブルです。ケース左側から入力(USBタイプAオスをUSBポートに接続)し、右側の先端はUSBマイクロBのオスになっており、これがモバイルルータに接続されています。
この構成で実際に半年ほど運用してみたところ、このモバイルルータ(Freetel FTW141A aria)では安定性に難があり、連続稼働では2週間ほどでインターネットに接続できなくなります。再起動すれば復旧しますが、安定性が重視される緊急用途での使用には疑問符がつきます。結局、電源管理にリソースを割くよりも据え置き型のSIMフリールータで運用するのがベストという結論になりました。ただ、据え置き型のSIMフリールータには選択肢がほとんどないため他の解決法はないのかと試行錯誤したのが今回の案件なのでした。現在、据え置き型SIMフリールータ(NECプラットホームズ Aterm PA-HT100LN-SW)に移行するため試験運用を実施しています。
USBリレーは単にON/OFFを制御できるだけの瑣末なデバイスですが、使い方によってはいろいろなことができます。もっとも、本当に使いこなすには工作のスキルを問われることにもなるのであまり工作の得意でない身にとっては少し荷が重いです。以前、パラレルポートの出力を利用してシリコンリレーをON/OFFするデバイスを作ったことがあるのですが、100Vを制御するそのデバイスを遠隔地に置く自信がなく、作っただけで終わったことがありました。
今後の課題としては電源管理だけでなく、USB機器の物理的挿抜にも使ってみたいと思っています。いや、それは当該のUSB機器が不具合を起こすという前提なのでホントはそんなことはしたくないのですが、最近買った某USB機器が少し不安定な上、不具合を起こした場合、挿し直さないと復旧しないということがあってどうしたものかと思案中です。