前回の記録: Siriで赤外線リモコン操作を実現する
Raspberry PiはUSB接続のWi-Fiドングルで無線通信出来ていたが,ArduinoはEthernetシールドにLANケーブルを接続していた. このLANケーブルが足かせとなり,Arduinoを好きな位置に置くことが出来なかった. そこで今回,Raspberry PiとArduino間通信にXBeeを用いることで双方の無線化を実現. 電源さえ取れればArduinoを好みの場所に置くことが出来るようになった.
目指すところ
前回の記録"Siriで赤外線リモコン操作を実現する"では部屋のペンダントライトをSiriで操作するまでを記録した. そこではRaspberry PiとArduino間の通信にHTTPを利用していたため,無線機能の無いArduinoにはLANケーブルの接続が必要だった. 手元には以前遊んでそのままになっていたXBeeが2台. このXBee2台を有効活用すべく,Raspberry PiとArduino間通信をHTTPからZigBeeへ切り替えた. ここにはその道筋を記す.
使用機器
- XBee S2 (https://www.switch-science.com/catalog/224/)
- XBee Explorer USB (https://www.sparkfun.com/products/11812)
- Seeed XBee Shield (http://www.seeedstudio.com/wiki/XBee_Shield_V2.0)
XBeeのセットアップ
XBeeのセットアップに関しては次の記録を参照.
XBeeに触る
上の記録では2台のXBeeがペア(1対1)通信を行えるようセットアップする方法を紹介している. セットアップ後はXBeeをシリアルケーブルと同等に扱うことが出来るようになる.
つまり,無線通信のプロトコルどうこうといった部分を気にせず,いつも通りSerial通信をするだけでXBeeが勝手に無線通信し合ってくれるようになるのだ.
Raspberry Piのセットアップ
セットアップ済みXBeeを載せたXBee USB ExplorerをUSBケーブルでRaspberry Piへ接続.
それではお手持ちのPCからRaspberry PiへSSH接続.
文字を送信するPythonスクリプトはこれで完成. 次は受け手となるArduinoのセットアップ.
ssh ユーザ名@ホスト名.local
SSH接続したら,Raspberry Piに次のコマンドを入力.
lsusb
USB接続されている機器一覧が表示される. その中に
...
Future Technology International, ~ Ltd Serial (UART) ...
...
という表示があればそれがXBee USB Explorer. きちんと認識されていることが分かる. さて,久しぶりのRaspberry Pi(Arch Linux)なので一応パッケージを更新.
sudo pacman -Syu
更新を終えたら,Pythonでシリアル通信を実現するライブラリ"pySerial"をインストール
sudo pacman -S python-pyserial
これでPythonを使ってシリアル通信を行う事が出来るようになった. XBeeが繋がっているので,シリアル通信=無線通信(ZigBee)ということになる. さて,簡単な文字のやり取りでON/OFF制御ができれば良いので,ここでは文字Tを送ったらON,Fを送ったらOFF,Sを送ったら現在の状態を返してもらう,という仕様にしよう. ここで返してもらう"状態"とはライトがONならば1,OFFならば0の整数とする.
nano -w send_ascii.py
send_ascii.pyという名前のプログラムを作る. これはASCII文字をシリアル出力する簡単なPythonスクリプトだ.
send_ascii.py
import sys
import serial
if len(sys.argv) == 1:
sys.exit()
ser = serial.Serial('/dev/ttyUSB0')
ser.write(sys.argv[1].encode('utf-8'))
if sys.argv[1] == 'S':
res = ord(ser.read())
if res == 1:
print(res)
ser.close()
例えばASCII文字のTを送りたい場合は次のようにする.
python send_ascii.py T
引数の文字Tがシリアルポート/dev/ttyUSB0に送信される. つまり,XBeeに文字Tが流れ,無線として飛び,もう一方のXBeeに渡る仕組み.
スクリプトについて少し解説
serial.Serial()がシリアル通信を始める合図. 引数にポートとボーレートを渡す. ここでは/dev/ttyUSB0というポート名が"XBee USB Explorer"を指す. ボーレートは省略すると9600bpsとなる(Arduinoも同じボーレートなので都合が良い). 指定したポートへデータを送信する時はwrite()を使う. 指定したポートからデータを受信する時はread()を使う. やっていることはシンプルで,受け取った引数sys.argv[1]をUTF-8でエンコードして送信,もし引数がSだった場合,相手の返答(状態)を受け取る必要があるのでread()で受信をしている. Arduinoから受け取った値はASCIIコードなのでord()で整数(0か1)へと変換. 1(ON)ならば"1"と表示,0(OFF)ならば何も表示しないようにしてある(この挙動が後々役立つ). 最後はclose()で開いたポートを閉じる.Arduinoのセットアップ
ArduinoにXBeeの付いたXBeeシールド(私はSeeedのXBee Shieldを使っている)を載せる.
シールド上のジャンパピンは2つとも外す.
下のスケッチをアップロードしよう.
アップロードが完了したらジャンパピンを次のように接続する.
さて,お次は赤外線LED(IR-LED)の接続.
回路はとてもシンプル. ArduinoのD3ピンとGNDの間に抵抗とIR-LEDを直列につなぐだけ.
これでArduinoのセットアップは完了.
HomebridgeXBeeController.ino
#include <SPI.h>
#include <IRremote.h>
IRsend irsend;
int state = 0;
unsigned int light_on[] = {/* ONコマンド */};
unsigned int light_off[] = {/* OFFコマンド */};
void setup() {
Serial.begin(9600);
}
void loop() {
if (Serial.available() > 0) {
char c = Serial.read();
if (c == 'T') {
irsend.sendRaw(light_on, sizeof(light_on)/sizeof(light_on[0]), 38);
state = 1;
}
else if (c == 'F') {
irsend.sendRaw(light_off, sizeof(light_off)/sizeof(light_off[0]), 38);
state = 0;
}
else if (c == 'S') {
Serial.write(state);
}
}
}
/* ONコマンド */と/* OFFコマンド */の部分には赤外線コード(RAWデータ)を配列の形で書き込む(詳細はこちら"赤外線コードの送信 - 再現"の項).
スケッチについて少し解説
Serial.begin()でシリアル通信がはじまる. 引数にはボーレートを. Pythonスクリプトと同じ9600bpsを渡している. Serial.available()でデータを受信したかどうかが分かる. つまりXBeeからデータが来ていれば,if文の中に入る. Serial.read()で受信したデータを読む. 受信したデータがTならばON信号をirsend.sendRaw()で送信する. この函数はArduinoのD3ピンに繋がったIR-LEDを光らせる. Fが来たらOFF信号を,Sが来たらライトの状態stateをSerial.write()でRaspberry Piへ送信している.合わせてテスト
Raspberry Piで次のコマンドを実行しよう.
部屋のライトが点灯したら,ライトの状態を取得してみよう.
python send_ascii.py T
これで文字TがXBeeを通ってArduinoへと送信されるはず. この文字を受信したArduinoはIR-LEDからON信号を送信するので,部屋のライトが点灯する.
エラーになった場合
上のコマンドを実行してPermission deniedエラーが出力された場合について.
Traceback (most recent call last):
File "/usr/lib/python3.5/site-packages/serial/serialposix.py", line 265, in open
self.fd = os.open(self.portstr, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK)
PermissionError: [Errno 13] Permission denied: '/dev/ttyUSB0'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "xbee_test.py", line 3, in <module>
s = serial.Serial('/dev/ttyUSB0', 9600)
File "/usr/lib/python3.5/site-packages/serial/serialutil.py", line 236, in __init__
self.open()
File "/usr/lib/python3.5/site-packages/serial/serialposix.py", line 268, in open
raise SerialException(msg.errno, "could not open port {}: {}".format(self._port, msg))
serial.serialutil.SerialException: [Errno 13] could not open port /dev/ttyUSB0: [Errno 13] Permission denied: '/dev/ttyUSB0'
現在ログイン中のユーザーにUSBポート/dev/ttyUSB0を操作する権限を与えれば解決する.
ls -l /dev/ttyUSB0
とすると該当USBポートの権限について表示される.
crw-rw---- 1 root uucp 188, 0 Dec 10 10:12 /dev/ttyUSB0
見るとrootとuucpグループに操作の権限がある. 自分をuucpグループに追加すればPermissionうんぬん言われないはず.
sudo gpasswd -a $(whoami) uucp
これでログイン中のユーザー(自分)をuucpグループに追加できた. ユーザー情報を更新するには再ログインする必要がある. 一旦ログアウトしよう.
logout
そして,SSHで再接続(再ログイン)する. その後,再び
python xbee_on.py T
でエラー無く動くはず.
python send_ascii.py S
ON状態なので1が返ってくるはずだ. 次のコマンドでライトを消灯できる.
python send_ascii.py F
再び文字Sを送って状態を取得してみよう. 今度はOFFなので0が返ってくるはず. 何も表示されなければ正常だ. ここまで上手く行っていれば,後はHomebridgeに追加するだけで目標達成だ.
Homebridgeへの追加
今回はコマンドでON/OFF制御できるHomebridgeのプラグイン"homebridge-cmdswitch2"をインストールした(この記事を参考: npmでパッケージをインストールする).
homebridge-httpと違い,accessoriesではなくplatforms内に設定を書く点に注意. そしてこのプラグインはstatus_cmdを実行した時に何か出力があればON,何も出力が無ければOFFだと認識するようになっている. send_ascii.pyも1が返ってきた時にのみ出力するようになっているので,都合が良い. configを編集し終えたらCtrl+x,y,Enterで保存. Homebridgeを再起動させよう.
npm install -g homebridge-cmdswitch2
さて,Homebridgeのconfigを編集しよう.
nano /var/homebridge/config.json
次の例を参考にファイルを編集しよう.
/var/homebridge/config.json
{ "bridge": { "name": "Homebridge", "username": "CC:22:3D:E3:CE:30", "port": 51826, "pin": "031-45-154" }, "description": "This is an example configuration file with one fake accessor$ "platforms": [{ "platform": "cmdSwitch2", "name": "CMD Switch", "switches": [{ "name": "Light", "on_cmd": "python ~/send_ascii.py T", "off_cmd": "python ~/send_ascii.py F", "status_cmd": "python ~/send_ascii.py S" }] }] }
sudo systemctl restart homebridge
試しにHomeアプリを開きライトが正常に動作しているか確認,ちゃんとON/OFF操作も出来るか確かめてみよう. HTTPの時より反応速度はやや遅い印象だが,置き場所のシビアな赤外線LEDを載せたArduinoを比較的自由な位置に置くことが出来るようになったので利便性が増した. 目標達成だ!
参考元
8872662773723104100
https://www.storange.jp/2017/02/homebridgearduinoxbee.html
https://www.storange.jp/2017/02/homebridgearduinoxbee.html
HomebridgeとArduinoをXBeeでつなぐ
2017-02-28T22:25:00+09:00
https://www.storange.jp/2017/02/homebridgearduinoxbee.html
Hideyuki Tabata
Hideyuki Tabata
200
200
72
72