絖綛 N@i.jp  昨日:00036563
 今日:00026423
 総計:00077300
keywords
管理者専用
  Post   Add link   Control Panel 































新しいトピック
最新:04/16 19:55


新しいコメント
最新:07/28 16:47






管理人へMAIL

プライバシーポリシー

Raspberry Pi から IRKitを操作するための第一歩

Python3 で IRKitを操作するプログラムに挑戦中


 勉強を兼ねて Raspberry Pi から IRKitを操作するプログラムを Python3で作ってみようと思っています。とは言え、既に先人達が色々作ってくれていますから、それらを殆ど丸パクリした感もありますが・・・

 第一歩は無線LANに繋がっている IRKitデバイスを Bonjour(ボンジュール)で見つけ出すことからです。手順は以下のようになります。

  1. libdnssdをインストールする
  2. Python3用の pybonjourモジュールをインストールする
  3. pybonjour の Exampleプログラムを流用して IRKitデバイスのIPアドレスを求めるプログラムを作る

1. libdnssdをインストールする

 ウチの Raspberry Pi2 には Avahi(オープンソースによる Bonjour)がインストール済みなのですが、libdnssdライブラリは別途インストールする必要があるようなので、先ずはこれをインストールしました。

$ sudo apt-get install libavahi-compat-libdnssd-dev
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
以下の特別パッケージがインストールされます:
  libavahi-client-dev libavahi-common-dev libavahi-compat-libdnssd1 libdbus-1-dev
以下のパッケージが新たにインストールされます:
  libavahi-client-dev libavahi-common-dev libavahi-compat-libdnssd-dev libavahi-compat-libdnssd1 libdbus-1-dev
〜略〜
libavahi-compat-libdnssd1:armhf (0.6.31-2) を設定しています ...
libavahi-common-dev (0.6.31-2) を設定しています ...
libdbus-1-dev (1.6.8-1+deb7u6) を設定しています ...
libavahi-client-dev (0.6.31-2) を設定しています ...
libavahi-compat-libdnssd-dev (0.6.31-2) を設定しています ...

2. Python3用の pybonjourモジュールをインストールする

 Pythonから Bonjourを扱えるようにするための pybonjour というモジュールをインストールします。実はここで Python2系用の pybonjourをインストールするという失敗をやらかしてしまったので、その時の様子を備忘録として書いておこうと思います。
 Pythonの Bonjour実装をググったところ、最初に見つかったのがここでした。実はこれは Python2系用なのですが、その時には気付かなかったのでした。

$ git clone https://github.com/nickstenning/pybonjour.git
Cloning into 'pybonjour'...
remote: Counting objects: 162, done.
remote: Total 162 (delta 0), reused 0 (delta 0), pack-reused 162
Receiving objects: 100% (162/162), 184.05 KiB, done.
Resolving deltas: 100% (77/77), done.
$ cd pybonjour
$ sudo python3 setup.py install
Traceback (most recent call last):
  File "setup.py", line 32, in 
    import pybonjour
  File "/home/nai/work/pybonjour/pybonjour/pybonjour.py", line 823, in 
    _create_function_bindings()
  File "/home/nai/work/pybonjour/pybonjour/pybonjour.py", line 806, in _create_function_bindings
    for name, (restype, errcheck, outparam, argtypes) in specs.iteritems():
AttributeError: 'dict' object has no attribute 'iteritems'

と言う具合に、モジュールをダウンロードしてインストールしようとしたところエラーが出て失敗してしまいました。エラーの内容は 'dict'(辞書)オブジェクトの属性には 'iteritems' が無いよ!と言うもの。これについて調べたところ、Python2系と3系の非互換で、Python3では dict.iterkeys(), dict.itervalues(), dict.iteritems() メソッドが廃止されたとのこと。これらの代わりに dict.keys(), dict.values(), dict.items() を使えば良いらしい。今回エラーが出ているのは dict.iteritems() メソッドだけど、厳密に言えば Python2 の dict.iteritems() メソッドは辞書オブジェクト要素のイテレータ(反復子)を返すのに対し、Python3 の dict.items() メソッドはview(ビュー)と呼ばれる軽量なコンテナーオブジェクトを返すとの事。viewはイテレータのようにも振舞うので、単純に dict.iteritems() → dict.iterms() に変えても殆どの場合問題にはならないと言う。ナルホド、良く分からん(^^;)。
 とにかく単純にエラーになっている iteritems を items に書き換えてみた(問題の箇所は "pybonjour.py" ファイルの 806行目と 1944行目)ところ、

$ sudo python3 setup.py install
running install
running build
running build_py
running install_lib
copying build/lib/pybonjour.py -> /usr/local/lib/python3.2/dist-packages
byte-compiling /usr/local/lib/python3.2/dist-packages/pybonjour.py to pybonjour.cpython-32.pyc
running install_egg_info
Writing /usr/local/lib/python3.2/dist-packages/pybonjour-1.1.1.egg-info

インストールできてしまいました。ところが、その後よく探してみたらPython3用の pybonjourがちゃんとある事が分かりました。と言うことで、入れ替えるため先にインストールした pybonjourをアンインストールします。アンインストールするためには、もう一度インストールを行ってインストールされたファイルを記録する必要があるそうで、ちょっと面倒臭い。

$ sudo python3 setup.py install --record files.txt
running install
running build
running build_py
running install_lib
running install_egg_info
Removing /usr/local/lib/python3.2/dist-packages/pybonjour-1.1.1.egg-info
Writing /usr/local/lib/python3.2/dist-packages/pybonjour-1.1.1.egg-info
writing list of installed files to 'files.txt'
$ su
# cat files.txt | xargs rm -rvf
`/usr/local/lib/python3.2/dist-packages/pybonjour.py' を削除しました
`/usr/local/lib/python3.2/dist-packages/__pycache__/pybonjour.cpython-32.pyc' を削除しました
`/usr/local/lib/python3.2/dist-packages/pybonjour-1.1.1.egg-info' を削除しました
# exit
$ cd ..
$ rm -rf pybonjour

 その後、Python3用の pybonjourをインストールします。

$ git clone https://github.com/depl0y/pybonjour-python3.git
Cloning into 'pybonjour-python3'...
remote: Counting objects: 16, done.
remote: Total 16 (delta 0), reused 0 (delta 0), pack-reused 16
Unpacking objects: 100% (16/16), done.
$ cd pybonjour-python3
$ sudo python3 setup.py install
running install
running build
running build_py
running install_lib
copying build/lib/pybonjour.py -> /usr/local/lib/python3.2/dist-packages
byte-compiling /usr/local/lib/python3.2/dist-packages/pybonjour.py to pybonjour.cpython-32.pyc
running install_egg_info
Writing /usr/local/lib/python3.2/dist-packages/pybonjour-1.1.1.egg-info

 今度はエラーが起きることなくインストールできました。

3. pybonjour の Exampleプログラムを流用して IRKitデバイスのIPアドレスを求めるプログラムを作る

 上でダウンロードした pybonjour-python3 配下にある examplesディレクトリ内にサンプルプログラムがあります。3本あるサンプルプログラムのうち "browse_and_resolve.py" を流用して IRKitの IPアドレスを求めるプログラムを作りました。しかし、サンプルプログラムは print が関数ではないところを見ると Python2系用みたいですね。まぁ print以外は Python3でも問題ないようですけど。
 参考にさせてもらったのが こちらの "resolve.py" です。ウチの環境では、このプログラムのままでは IRKitを見つけてくれませんでしたので、少々手直ししたり単純化したりしました。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import select
import sys
import pybonjour
from socket import gethostbyname

regtype  = '_irkit._tcp'
timeout  = 5
resolved = []
irkits = []

def resolve_callback(sdRef, flags, interfaceIndex, errorCode, fullname,
                     hosttarget, port, txtRecord):
    if errorCode == pybonjour.kDNSServiceErr_NoError:
        irkits.append((hosttarget, port))
        resolved.append(True)


def browse_callback(sdRef, flags, interfaceIndex, errorCode, serviceName,
                    regtype, replyDomain):
    if errorCode != pybonjour.kDNSServiceErr_NoError:
        return
    if not (flags & pybonjour.kDNSServiceFlagsAdd):
        print('Service removed', file=sys.stderr)
        return

    with pybonjour.DNSServiceResolve(0,
                                     interfaceIndex,
                                     serviceName,
                                     regtype,
                                     replyDomain,
                                     resolve_callback) as resolve_sdRef:
        while not resolved:
            ready = select.select([resolve_sdRef], [], [], timeout)
            if resolve_sdRef not in ready[0]:
                print('Resolve timed out', file=sys.stderr)
                break
            pybonjour.DNSServiceProcessResult(resolve_sdRef)
        else:
            resolved.pop()


def resolve_irkits():
    with pybonjour.DNSServiceBrowse(regtype = regtype,
                                    callBack = browse_callback) as browse_sdRef:
        while True:
            ready = select.select([browse_sdRef], [], [], timeout)
            if browse_sdRef in ready[0]:
                pybonjour.DNSServiceProcessResult(browse_sdRef)
            else:
                break

if __name__ == '__main__':
    resolve_irkits()
    for irkit in irkits:
        print('hosttarget={0}
IPaddress={1}
port={2}'.format(irkit[0], gethostbyname(irkit[0]), irkit[1]))

 殆ど変わってませんけどね。変えた所は主に resolve_irkits関数の中で、"browse_and_resolve.py"サンプルプログラムと同様に selectしながらループさせてます。こうしないとうまく IRKitを見つけてくれないようです。サンプルプログラムでは^Cで打ち切るまで無限ループさせていたところを、応答が帰って来なくなったらループを抜けるようにしました(したつもり ^^;)。
 これを実行した結果が以下です。

$ ./resolve_irkit.py
hosttarget=irkit648a.local.
IPaddress=192.168.0.6
port=80

 これで無線LANに繋がっている IRKitのIPアドレスを求めることができるようになりました。次のステップは IRKit のAPI(HTMLコマンド)でリモコン信号のやり取りができるようにすることですけど、このペースだといつになるかなぁ・・・


< 過去の記事 [ 8月の 全てのカテゴリ リスト ] 新しい記事 >

2015 calendar
8月
1
2345678
9101112131415
16171819202122
23242526272829
3031


掲示板
最新:08/15 17:19


GsBlog was developed by GUSTAV, Copyright(C) 2003, Web Application Factory All Rights Reserved.