読者です 読者をやめる 読者になる 読者になる

DragonBoard 410c(Debian)でNode.jsとPhantom.jsを使えるようにする

DragonBoard 410c(Debian)でNode.jsとPhantom.jsを使えるようにする

※ 結論をお急ぎの方は「まとめ」まで読み飛ばしてください。

先日、「DragonBoard+IoTアプリコンテスト meet up!」というイベントに参加してきました。

algyan.connpass.com

f:id:ueponx:20170521105631j:plain

DragonBoard410cはAndroidLinux、Windows10IoTCoreが動作する素敵系ボードというとだったので、ぜひ触ってみたいと思いました。ハンズオンでは各OSの動作を確認でき、作品制作・発表は必須ということでしたが、ボードがいただけることだったので大満足のイベントです。

f:id:ueponx:20170521105710j:plain

f:id:ueponx:20170521105722j:plain

f:id:ueponx:20170521105729j:plain

自分も、最近はRaspberryPiばかりだったので、いままで作っていたものを移植してみたいなと思っていたのでいい機会でした。

家に持ち帰り、Debianをインストールしようとすると最新版(2017.05.12)が出ているということでしたので17.04をダンロードし、SDカードに書き込んでインストールしました。インストール手順は以下のリンクでOK

Documentation - 96Boards

インストールが完了するとXが起動します。ダウンロード、SDカード作成、インストールまでいれても30分程度で完了するお手軽さがあります。

ネットワーク(WiFi)、キーボード、ロケールタイムゾーンなどを設定すればほぼLinuxとして使えます。

パッケージマネージャーはaptなので定番のコマンドを打ち込みます。

$ sudo apt-get update
$ sudo apt-get upgrade

これで一応OKかと思います。

自分が使いたいのはNode.jsとPhantom.jsなので確認をしてみます。Node.jsは4系がすでにインストールされていたので、少し古いですが、Raspbianにのデフォルト比べればよっぽどいいかとおもいますので、このままにしました。ただ、nodeコマンドではなく、nodejsコマンドになっているので注意(Debianでは恒例?)なのと、npmコマンドはないので新規で入れる必要があります。ただ、apt-get経由ではインストールされないようです。(なぜ?)

以上の点を踏まえて、作業を行います。

$ sudo apt-get install -y nodejs nodejs-legacy
$ wget http://www.npmjs.org/install.sh --no-check-certificate
$ sudo sh install.sh

簡単に説明をすると…

$ sudo apt-get install -y nodejs nodejs-legacy

nodejsコマンドをnodeに変更する処理を行うものです。(Debian系あるあるらしい。)

$ wget http://www.npmjs.org/install.sh --no-check-certificate
$ sudo sh install.sh

こちらの2行で、手動でnpmをインストールします。インストールのshをダウンロードして、実行することになります。

あとは、Phantom.jsのインストールになります。Node.jsのバージョンが微妙かなとなんとなく思い、npmでインストールしようかなと思って以下のように打ち込むと

$ sudo npm install -g phantomjs

エラー発生

ではということで以下を参考に

Build | PhantomJS

ソースからインストールしてみようとしてみたのですが、

$ sudo apt-get install build-essential g++ flex bison gperf ruby perl libsqlite3-dev libfontconfig1-dev libicu-dev libfreetype6 libssl-dev libpng-dev libjpeg-dev python libx11-dev libxext-dev
$ git clone git://github.com/ariya/phantomjs.git
$ cd phantomjs
$ git checkout 2.1.1
$ git submodule init
$ git submodule update
$ python build.py

ビルドをしていると何故か、コンソールが落ちるという現象が発生。(teratermで接続して作業を行っていました。)何回やっても同じ状況になってしまうので、無理ゲーあるいは、負け確定イベントバトルなのかと思っていたら、どうもビルドが落ちているのではなく、OSが数分に一度リブートしている動きをしていました。その後、OSは起動して、数分経つとリブートするループへ。\(^o^)/オワタ

ここまで2日ほど費やしてしまったのですが、aptでパッケージってなかったか?ということを思い出し、試しにやってみました。

$ sudo apt-get install -y phantomjs

あるじゃん。/(^o^)\ナンテコッタイ

とりあえず、数分ごとにリブートはしますが、短時間ならなんとかなる!(無理ゲー臭が漂いますが、なんだかウルトラマンみたいで燃えるシチュエーションだなと思ってきた)

phantom.jsも無事インストールできたので実行してみます。

$ phantomjs
QXcbConnection: Could not connect to display 
PhantomJS has crashed. Please read the bug reporting guide at
<http://phantomjs.org/bug-reporting.html> and file a bug report.
Aborted (core dumped)

んが、core dump。\(^o^)/オワタ

気を取り直して、エラーメッセージを確認します。QXcbConnection: Could not connect to displayとなっているのでdisplay関係のエラー、もしかしたらと思って、X側のコンソールで

$ phantomjs --version
2.1.1
$ phantomjs 
phantomjs>

対話側コンソールが無事に起動しました。原因は(teratermなどの)リモートターミナルで起動していたためのようです。とはいっても、コンソールから動かせないと電子工作系では厳しいことが多いのでなんとかしたいところです。

そこでエラーメッセージからググってみると こんなissuesページがGithubにありました。

github.com

I was able to get phantomjs to start working again by installing xvfb and creating the following script in /etc/profile.d/aliases.sh to ensure the alias takes effect system-wide:

なんとなくxvfbが必要のような記述です。xvfbは仮想フレームバッファのようなので、コンソールからこれを使えば仮想的にディスプレイと接続した状況になるようです。 このissuesの解決方法をつかうことにしました。

$ sudo apt-get install -y xvfb
$ sudo vi /etc/profile.d/aliases.sh

【/etc/profile.d/aliases.sh】を編集

#!/bin/bash
alias phantomjs="xvfb-run phantomjs"
$ source /etc/profile

この作業を簡単にいうと、ログイン時のデフォルトのalias設定にphantomjs="xvfb-run phantomjs"を追加し、設定を読み直したということになります。

phantomjsコマンドのAliasを、phantomjsを起動時に事前にxvfbを起動するというものにしています。

$ /usr/bin/phantomjs
/usr/bin/phantomjs 
QXcbConnection: Could not connect to display 
PhantomJS has crashed. Please read the bug reporting guide at
<http://phantomjs.org/bug-reporting.html> and file a bug report.
Aborted (core dumped)

$ phantomjs --version
2.1.1
$ phantomjs 
phantomjs>

前半部はalias経由しないで実行した場合、後半はalias経由で起動した場合。コンソールでも無事に動作できました。

まとめ

手順1: パッケージインストー

npmがインストールされていない場合

$ sudo apt-get install -y nodejs nodejs-legacy
$ wget http://www.npmjs.org/install.sh --no-check-certificate
$ sudo sh install.sh
$ sudo apt-get install -y xvfb phantomjs

npmがインストールされている場合

$ sudo apt-get install -y nodejs nodejs-legacy
$ sudo apt-get install -y xvfb phantomjs

手順2: phantomjsの設定変更

$ sudo vi /etc/profile.d/aliases.sh

【/etc/profile.d/aliases.sh】を編集し保存

#!/bin/bash
alias phantomjs="xvfb-run phantomjs"
$ source /etc/profile

終わりに

一応、DragonBoard 410cの環境にもNode.jsとPhantom.jsが動作するようになりました。でも、Debianが再起動するのは直ってません。これからどうすれば…。

LoLin製のNodeMCUでMicroPythonのインストールをしてみる

LoLin製のNodeMCUでMicroPythonのインストールをしてみる

前回設定したLoLin製のNodeMCUですが、Arduinoで使用するのはまあ普通かなと思ったので、 少し気になっていたMicroPythonのインストールをして使えるようにしたいと思います。

参考にしたのはこちらになります。ありがとうございます。

ken5owata.hatenablog.com

準備を行う。

基本的な流れとしては

  1. ハードウエアの認識(USBで一度接続できていれば不要)
  2. MicroPythonのファームウエアをダウンロード
  3. ファームウエア書き込みツール(Flash Download Tools)をダウンロード・インストー
  4. ファームウエアの書き込み
  5. MicroPythonの動作テスト

このようになると思います。

最初のハードウエアの認識に関してですが、Window10では特にドライバのインストールを行わなくても認識されますので必要はないかと思いますが、認識されない場合には前回のエントリを参考にしてドライバのインストールを行ってください。

uepon.hatenadiary.com

MicroPythonのファームウエアをダウンロード

下記のサイトからMicroPythonのファームウエアをダウンロードします。

micropython.org

キャプチャ画面は2017/05/20現在

f:id:ueponx:20170520090528p:plain

ページの下の方、Firmware for ESP8266 boardsの項目まで行きます。

f:id:ueponx:20170520090930p:plain

この中から今回は esp8266-20170108-v1.8.7.bin (elf, map) (latest)をダウンロードすることにしました。

ファームウエア書き込みツール(Flash Download Tools)をダウンロード・インストー

ファームウエアをダウンロードしたら書き込みツールで書き込みツールを準備します。 自分はWindowsなのでFlash Download Toolsを使用します。

MacLinuxではesptoolというものを使うらしいです(https://espressif.com/en/support/download/other-tools

espressif.com

キャプチャ画面は2017/05/20現在

f:id:ueponx:20170520084534p:plain

f:id:ueponx:20170520084549p:plain

インストーラー付きが良ければこちら Flash Download Tools V3.4.4 (ESP8266 & ESP32)

ZIPファイルが良ければこちら Flash Download Tools V3.4.1 (ESP8266 & ESP32)

自分はZIP版が良かったのでそちらをダウンロードしています。 ZIPファイルを展開してフォルダを確認し、サブフォルダのなかみを確認すると

f:id:ueponx:20170520160718p:plain

このようにファイルがみえます。 この中のESPFlashDownloadTool_v3.4.1.exeこれを実行することになります。

ファームウエアの書き込み

ESPFlashDownloadTool_v3.4.1.exeこれを実行するとこのような画面になります。

f:id:ueponx:20170520085516p:plain

CLIツールのGUIラッパーのようですのでコンソールウインドウも開きます。

画面の中から【ESP8266 DownloadTool】ボタンをクリックします。 DOWNLOADツールの設定画面が開きます。

f:id:ueponx:20170520085829p:plain

以下の設定を変更します。

  • ダウンロードしたファームウエア(保存パス\esp8266-20170108-v1.8.7.bin)
  • 書き込みのアドレス(0x00000)
  • ファームウエアのファイル名の前のチェックボックス
  • SPI SPEED(40MHz → 80MHz)
  • FLASH SIZE(4Mbit → 32Mbit)
  • COM(認識しているNodeMCUのUSBのCOMポート) *BAUD(230400→1152000)

設定すると以下のような画面になると思います。(画面は【START】ボタンを押したあとなので少し異なります。)

f:id:ueponx:20170520160831p:plain

設定変更後は【START】ボタンをクリックして書き込みを行います。ダウンロード中はステータスが【IDLE】から【Download】に変更となり、DETECTED INFOやMACの表示が行われます。

f:id:ueponx:20170520160954p:plain

無事に終了するとステータスは【Download】から【FINISH】に変更されます。

MicroPythonの動作テスト

書き込み成功したら、改めてTeratermなどで接続すると対話形式でmicropythonを無事に実行できます。 ※シリアルのスピードは1152000bpsなどに合わせてください。

f:id:ueponx:20170520091846p:plain

拡大すると

f:id:ueponx:20170520161343p:plain

最初は文字化けしたテキストがでますが、無事にコンソール上MicroPython v1.8.7-7…と表示されています。(Could not open file ‘main.py’ for readingというエラーメッセージが気になるのですが、動作するようです。)

f:id:ueponx:20170520094258p:plain

拡大すると

f:id:ueponx:20170520161531p:plain

参考にしたブログのサンプルコードを打ち込んでみるとエラーはでないので、動作も大丈夫そうです。そろそろLチカも確認したいので、後日確認して、更新しておきたいと思います。

おわりに

MicroPythonも使用できるようになりました。小さなケースにいれておいて、出先でpythonを楽しむといった使い方もできそうです。 そういえば、対話型以外はどうするのでしょうか。そのあたりは調べておこうかなと考えています。

そういえばMicoroRubyっていうのも気になりますね。MicroRuby

aitendoで購入したLoLin製のNodeMCUを使ってみる

aitendoで購入したLoLin製のNodeMCUを使ってみる

以前、秋葉原に行ったときにaitendoさんでESP8266モジュールのついたLoLin製のNodeMCUを購入したのですが一度も使わずに片付けていました。 そのころはほとんど開発用のボードはなかったので結構いいなと思っての購入でした。 aitendoさんのページでは以下になります。

www.aitendo.com

今であれば下記のボードのほうがお安いのでいいのかなと思いますが。

www.aitendo.com

所詮、技適はないモジュール搭載品なので今となってはあまり魅力はないかなと思います。 とはいえ、もったいないので無線機能を使わず、Arduinoなどとして使用したいと思います。

ハードウエアを認識する。

ハードウエアとしてはNodeMCU DEVKITと呼ばれるボードのようでした。

https://en.wikipedia.org/wiki/NodeMCUen.wikipedia.org

frightanic.com

基本的にはPCとUSBで接続し、シリアルドライバをインストールしてボードの認識ができれば問題ありません。

USBシリアル変換にCH340チップを使用しているようなので、接続して新しいデバイスとして認識できなかった場合には

www.wch.cn

www.wch.cn

このあたりからドライバを入手してインストールを行ってください。

認識できれば、デバイスマネージャから下記のように認識されます。(USB-SERIAL CH340)

f:id:ueponx:20170513020625j:plain

また、Teratermの接続ダイアログのシリアルポートにも表示されます。

f:id:ueponx:20170513015514j:plain

ArduinoIDEの設定を行い、スケッチを書き込む

シリアルの準備ができたので後はArduinoIDEのボード設定を整えてスケッチを書き込んでいきます。

f:id:ueponx:20170513020345j:plain

ボード設定に関してはESP8266の設定を事前に読み込ませます。

その後、NodeMCU 1.0(ESP-12E Module)を選択します。その他の設定に関してはデフォルトで大丈夫でした。(NodeMCU 1.0(ESP-12E Module)の設定でも問題なく書き込めていました。)

IDEのウインドウの右下に以下のような以下のような表示が出ていました。

f:id:ueponx:20170513021119j:plain

その後、スケッチの書き込みを行うと、かなり時間はかかりますが問題なく書き込めました。本当はLチカをやりたかったのですが、オンボードのLEDがどのPINに接続されているかがわからなかったので、シリアルポートのテストするスケッチで代用しました。(M8266D30MCU2102の方はPIN=16にオンボードLEDが接続さてれているようです)

書き込みが終わると無事に【ボードへの書き込みが完了しました。】と表示されます。

f:id:ueponx:20170513021528j:plain

void setup() {
  // put your setup code here, to run once:
  pinMode(16, OUTPUT);
  Serial.begin(9600);
  Serial.println("Start!");
}

void loop() {
  // put your main code here, to run repeatedly:
  Serial.println("HIGH");
  delay(1000);
  Serial.println("LOW");
  delay(1000);
}

実際にArduinoIDEのシリアルモニタで動作を確認すると

f:id:ueponx:20170513021733j:plain

ちゃんと1秒毎にHIGHとLOWの表示が行われていました。

終わりに

もうArduinoは純正であることに拘らなければ、300円程度で変えてしまうのであんまり意味がないかもしれませんが、折角、無駄にするのも何だったので使ってみました。可能ならMicroPythonなどにも挑戦したいです。

RaspberryPiでPechatを使用してみる【失敗?】

RaspberryPiでPechatを使用してみる

pechat.jp

(注)今回のエントリーは失敗の記録になります。ただ、デバイスとしては使用できています。最後の方だけみてもらえればいいかなと思います。

以前のエントリーにも書いたダブルドライバーをRaspberryPiでの実現に向けた企画の第2段です。前回はUSBを挿入すると音がなるところまでを実現しました。しかし、RaspberryPiをバックルに入れて更にスピーカーを接続するとなるとかなり本体のサイズが大きくなることが予想されます。また、スピーカーの電源まで考えるとかなり苦労しそうな感じです。 そこで音声デバイスBluetoothスピーカーの使用を考えてみることにしました。

ネットを調べてみると

サイズも小さく電源が内蔵されているのがかなり助かりそうなデバイスです。

【 主な仕様 】

通信方式:Bluetooth 見通し送信距離:約10m(使用環境による) 電源:3.7V リチウムイオンポリマー二次電池 充電時間:約3時間 連続使用時間:約1.2時間 外形寸法:直径45mm 奥行き21mm(取り付け部含む) 重量:20g 付属品:充電ケーブル 対応OS:iOS9.0以上/Android5.0以上

対応OSはiOS9.0以上/Android5.0以上となっていますが、基本的にはBluetoothスピーカーなので使えないことはないでしょうw。

RaspberryPiでBluetoothスピーカーを使う

参考にしたのは下記になります。 qiita.com

まずはBluetoothドングルをRaspberryPiに接続します。 使用したドングルは以下になります。

ドングルをさしてlsusbコマンドを実行すると

【ドングルを挿す前】

$ lsusb
Bus 001 Device 005: ID 045e:075d Microsoft Corp. LifeCam Cinema
Bus 001 Device 004: ID 0411:01ee BUFFALO INC. (formerly MelCo., Inc.) WLI-UC-GNM2 Wireless LAN Adapter [Ralink RT3070]
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

【ドングルを挿した後】

$ lsusb
Bus 001 Device 006: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
Bus 001 Device 005: ID 045e:075d Microsoft Corp. LifeCam Cinema
Bus 001 Device 004: ID 0411:01ee BUFFALO INC. (formerly MelCo., Inc.) WLI-UC-GNM2 Wireless LAN Adapter [Ralink RT3070]
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Bus 001 Device 006: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)が認識されたドングルになります。

ソフトウエアの確認

音声の出力に関してはPulseAudioを使用します。

PulseAudio

正確にはPulseAudioからBluetoothを経由して音声の出力を行うことになりますのでpulseaudio-module-bluetoothもインストールします。

ただ、最近のRasbianにはインストール済みであることが多いです。今回のバージョン情報は以下のような感じです。

$ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 8.0 (jessie)
Release:        8.0
Codename:       jessie

念のためパッケージの確認すると

$ dpkg -l | grep pulse
ii  libpulse0:armhf                       5.0-13                                    armhf        PulseAudio client libraries
ii  libpulsedsp:armhf                     5.0-13                                    armhf        PulseAudio OSS pre-load library
ii  pulseaudio                            5.0-13                                    armhf        PulseAudio sound server
ii  pulseaudio-module-bluetooth           5.0-13                                    armhf        Bluetooth module for PulseAudio sound server
ii  pulseaudio-module-x11                 5.0-13                                    armhf        X11 module for PulseAudio sound server
ii  pulseaudio-utils                      5.0-13 

インストールが必要なパッケージはほぼ入っています。この状態のインストール作業をすると

$ sudo apt-get install pulseaudio-module-bluetooth
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
pulseaudio-module-bluetooth はすでに最新版です。
以下のパッケージが自動でインストールされましたが、もう必要とされていません:
  ax25-node libax25 libllvm3.7 openbsd-inetd
これを削除するには 'apt-get autoremove' を利用してください。
アップグレード: 0 個、新規インストール: 0 個、削除: 0 個、保留: 161 個。

最新の状態なのでインストールのやり直しはありません。(心配ならapt-get upgradeするのがいいと思います。)

Bluetoothの状態を確認する

bluetoothctlコマンドを使用すればBluetoothのペアリングなどを操作する事ができますので、設定の前に確認してみます。

$ sudo bluetoothctl -a
[NEW] Controller 00:1B:DC:06:XX:XX raspberrypi [default]
[NEW] Device CC:30:80:00:XX:XX Pechat-00F8A1
Agent registered
[bluetooth]# scan on
Discovery started
Discovery started
[CHG] Controller 00:1B:DC:06:XX:XX Discovering: yes
[NEW] Device CC:30:80:00:XX:XX Pechat-00F8A1
[CHG] Device 75:66:AC:C7:XX:XX RSSI: -75
[CHG] Device CC:30:80:00:XX:XX RSSI: -57
[DEL] Device 75:66:AC:C7:XX:XX 75-66-AC-C7-90-25
[DEL] Device CC:30:80:00:XX:XX Pechat-00F8A1
[NEW] Device 75:66:AC:C7:XX:XX 75-66-AC-C7-90-25
[CHG] Device 3C:77:E6:03:54:C9 UUIDs:
        00001200-0000-1000-8000-00805f9b34fb
[NEW] Device CC:30:80:00:XX:XX Pechat-00F8A1
[bluetooth]# pair 00:1B:DC:06:XX:XX
Device 00:1B:DC:06:XX:XX not available
[bluetooth]# connect 00:1B:DC:06:XX:XX
Device 00:1B:DC:06:XX:XX not available
[bluetooth]# quit
Agent unregistered
[DEL] Controller 00:1B:DC:06:XX:XX raspberrypi [default]

あれ?うまくペアリングができないようです。 正常であれば、pairconnectのコマンドでデバイスMAC指定すれば行けるようなんですが…不吉な予感です。 念のためにsyslogを確認すると

$ tail /var/log/syslog
(略)
May  4 14:57:55 raspberrypi bluetoothd[435]: a2dp-sink profile connect failed for CC:30:80:00:XX:XX: Protocol not available

となっていました。プロファイルが違うということのようです。 設定をちゃんと行えればいいのかなと思いましたのでそのまま作業は続行します。

ソフトウエアの設定

あとは参考にしたブログの通り作業を行っていきます。

/etc/systemd/system/pulseaudio.serviceファイルを作成

$ sudo vim /etc/systemd/system/pulseaudio.service

【/etc/systemd/system/pulseaudio.service】

[Unit]
Description=Pulse Audio

[Service]
Type=simple
ExecStart=/usr/bin/pulseaudio --system --disallow-exit --disable-shm

[Install]
WantedBy=multi-user.target

/etc/dbus-1/system.d/pulseaudio-bluetooth.confファイルを作成

$ sudo vim /etc/dbus-1/system.d/pulseaudio-bluetooth.conf

【/etc/dbus-1/system.d/pulseaudio-bluetooth.conf】

<busconfig>

  <policy user="pulse">
    <allow send_destination="org.bluez"/> 
  </policy>

</busconfig>

pulseaudioサービスの設定

サービスのスタートと自動起動の設定を行います。

$ sudo systemctl start pulseaudio.service
$ sudo systemctl enable pulseaudio.service

これで完了です。 あとは先程と同じくBluetoothの状態の確認をします。

再度、Bluetoothの状態を確認する

今度はうまくconnect

$ sudo bluetoothctl -a
[NEW] Controller 00:1B:DC:06:XX:XX raspberrypi [default]
Agent registered
[bluetooth]# scan on
Discovery started
[CHG] Controller 00:1B:DC:06:XX:XX Discovering: yes
[NEW] Device CC:30:80:00:XX:XX Pechat-00F8A1
[bluetooth]# pair CC:30:80:00:XX:XX
Attempting to pair with CC:30:80:00:XX:XX
[CHG] Device CC:30:80:00:F8:A1 Connected: yes
[CHG] Device CC:30:80:00:F8:A1 UUIDs:
        00001101-0000-1000-8000-00805f9b34XX
        0000110b-0000-1000-8000-00805f9b34XX
        0000111e-0000-1000-8000-00805f9b34XX
        00001200-0000-1000-8000-00805f9b34XX
[CHG] Device CC:30:80:00:XX:XX Paired: yes
Pairing successful
[CHG] Device CC:30:80:00:XX:XX Connected: no
[bluetooth]# scan off
[CHG] Device CC:30:80:00:XX:XX RSSI is nil
Discovery stopped
[CHG] Controller 00:1B:DC:06:XX:XX Discovering: no
[bluetooth]# connect CC:30:80:00:XX:XX
Attempting to connect to CC:30:80:00:XX:XX
[CHG] Device CC:30:80:00:XX:XX Connected: yes
Connection successful
[bluetooth]# quit
Agent unregistered
[DEL] Controller 00:1B:DC:06:XX:XX raspberrypi [default]

一応、うまく認識ができたようです。

音声を出力してみる

$ aplay ./sample.wav
ALSA lib pulse.c:243:(pulse_connect) PulseAudio: Unable to connect: アクセス拒否

aplay: main:722: audio open error: 接続を拒否されました

オゥフ…

そういえば?

Xの画面上にもBluetoothの設定のアプリケーションがあったよな気がしますのでそれも確認してみます。

Xの画面上の右上の部分にそれはあります。

f:id:ueponx:20170504153005j:plain

このBTのマークがそれになります。

f:id:ueponx:20170504153037j:plain

マウスで左クリックをすると接続されているBluetoothバイスが表示されます。この表示ではPechatも認識されている様です。

続いて、その2つ隣の音声アイコンを右クリックし音声出力の状況を確認します。

f:id:ueponx:20170504153521j:plain

正常ならばこの状態で出力するデバイスにチェックが入っているのですが、チェックがありません。これが原因ということなのでしょうか。一応Pechatのところでクリックしてみると、一瞬ダイアログが表示されているようです。

$ aplay sample.wav
再生中 WAVE 'sample.wav' : Signed 16 bit Little Endian, レート 44100 Hz, ステレオ

音声はなりませんが、エラーはなくなりました。うーん…。

どうしようもないので今回は設定を元に戻してみます。

$ sudo systemctl stop pulseaudio.service
$ sudo systemctl disable pulseaudio.service

気を取り直してX側から設定を行います。

まずはBTのアイコンをマウスで左クリックしてメニューを開きます。

f:id:ueponx:20170504192450j:plain

その中から【Add Device】を選択します。すると認識されているデバイス一覧のダイアログが開きます。

f:id:ueponx:20170504191552j:plain

一覧の中から【Pechat】のデバイスを選択し【Pair】ボタンをクリックします。

f:id:ueponx:20170504191553j:plain

うまく行けば、ペアリング成功の旨を表すダイアログが表示されます。(ここでaudioメニューから出力するデバイスを選んでねというメッセージがでます。BTの設定ではないのが謎です。)

f:id:ueponx:20170504191554j:plain

もう一度BTアイコンを左クリックしてみるとPechatがメニュー上に現れます。選択してみると

f:id:ueponx:20170504191555j:plain

【connect】がでてくるのですが、選択してもコネクションが失敗するメッセージダイアログが表示されるだけです。

f:id:ueponx:20170504191556j:plain

次はオーディオメニューを確認してみると、ちゃんとメニューには出力対象のデバイスにチェックがついています。また、こちらにもPechatが表示されています。

f:id:ueponx:20170504191557j:plain

先程のメッセージにもあった通りこちらでデバイス選択をしてみます。

f:id:ueponx:20170504191558j:plain

接続処理を行い…

f:id:ueponx:20170504191559j:plain

接続に成功した様です。

f:id:ueponx:20170504191600j:plain

処理がうまく行ったら、音声を鳴らしてみます。

$ aplay sample.wav
再生中 WAVE 'sample.wav' : Signed 16 bit Little Endian, レート 44100 Hz, ステレオ

文字だけではわかりませんが、うまく出力できました。コマンドラインではうまくできませんでしたがXからの設定ではうまく行ったようです。

終わりに

一応、デバイスとしては使用できるようにはなりました。現時点での難点はコマンドラインでの設定変更ができない点です。とはいえ、Pechatは非常にコンパクトで音声を鳴らすことのできるデバイスなので、今後比較的に利用ができそうなスピーカーデバイスではないでしょうか。

えーマジifconfig!!ifconfigが許されるのはオッサンだけだよね!(ifconfigからipコマンドへの移行)

えーマジifconfig!!ifconfigが許されるのはオッサンだけだよね!

また、自戒の念を込めたクソネタです。

ネットで少し前にLinux界隈でIPアドレスを調べたりするときに、ifconfigコマンドは過去のもの(Deprecated)となりipコマンドが推奨されるという記事がでていました。

【参考】 understeer.hatenablog.com

net-toolsパッケージのメンテナンスが行われていないので推奨されないということのようです。 このパッケージに含まれるコマンドはarp, ifconfig, iptunnel, iwconfig, nameif, netstat, route になるそうです。

個人的にはネットワーク関連のコマンドはそうそう打つ人間ではないのですが、ifconfigrouteぐらいは使用するので結構衝撃的な記事でした。

そして、…月日は流れます。

ふと、ネットワーク関連のコマンドを打とうとしたときに/sbin/ifconf...と打っている自分がいました。頭ではわかっているのですが、体が覚えてしまっています。 そこで反省を込めてブログエントリとして推奨コマンドをまとめたいと思いました。そして、古いコマンドはもう使わない決意をします。

コマンド対比表

今後推奨されないコマンド(Deprecated) 代替のコマンド(Replacement)
arp ip n
ifconfig ip a
iptunnel ip tunnel
iwconfig iw
nameif ip link
netstat ss
route ip r

netstatコマンドのssが少し違うので注意かなと思いました。

【参考】 Deprecated Linux networking commands and their replacementsdougvitale.wordpress.com

おわりに

使わない宣言したけど大丈夫だろうか

PC版 Rasbian Pixcelにnode.jsをインストールする

PC版 Rasbian Pixcelにnode.jsをインストールする

勉強会でUbuntu系のOSをつかってNode.jsを触る必要があったので、以前設定していたPC版Rasbian Pixelを使用しようと思いました。

ご存知の通りUbuntuベースのデフォルトのNode.jsのバージョンは古いので何とかしなければなりません。RaspberryPiでNode.jsのインストールの関連を何回かやっていたのですが、PC版では初めてということでインストールのメモ。ソースから入れると厳しいのでググるとよく出てくるn packageを使用します。

github.com

インストール手順

n packageをインストールするにもNode.jsが必要なので以下の手順をとります。

  1. デフォルトのNode.jsパッケージとnpm(何れも古いもの)をインストール
  2. 古いnpmを使用してn packageをインストール-gでインストール
  3. n packageを使用して比較的新しいNode.jsをインストール(LTSかStableか)
  4. 最初に入れたデフォルトパッケージのNode.jsとnpmを削除

デフォルトのNode.jsパッケージとnpm(何れも古いもの)をインストール

他と同様にapt-getを使用してインストールを行います。

$ sudo apt-get install -y nodejs npm

デフォルトのパッケージではコマンドがnodeではなくnodejsになっていました。 バージョンを確認します。

$ nodejs -v
v0.10.29
$ npm -v
1.4.21

古いnpmを使用してn packageをインストール-gでインストール

つづいて、n packageをインストールします。

$ sudo npm cache clean
$ sudo npm install n -g

一行目のキャッシュクリアはインストール時にキャッシュが悪さをすることがあるようなので対策になります。

【参考】 qiita.com

n packageを使用して比較的新しいNode.jsをインストール(LTSかStableか)

n packageがインストールできたので、これを使用して新しいバージョンのNode.jsをインストールします。

stableをインストールする場合は以下で

$ sudo n stable

LTSをインストールする場合は以下で

$ sudo n lts

インストールされたnodeをデフォルトとして使用できるように、シンボリックリンクで入れ替えておきます。

$ sudo ln -sf /usr/local/bin/node /usr/bin/node

-fは強制処理フラグです。

処理が終わったらバージョンの確認になります。少数点以下のバージョンでなければ問題ないでしょう。最近のパッケージでは4以上対応になっているものが多いようです。 自分はstableでインストールしたので以下の様になりました。(2017/04/25現在)

$ node -v
v7.8.0
$ npm -v
4.2.0

最初に入れたデフォルトパッケージのNode.jsとnpmを削除

最初にパッケージでいれたNode.jsとnpmは不要になるのでパッケージから削除します。

$ sudo apt-get purge -y nodejs npm

これで終了です。

おわりに

単なる備忘録になってしまいました。ただ、n packageがあればバージョンを簡単に変更できるのでこちらの方が簡単に管理できそうです。 思いなおしてみるとRaspberryPi側もn packageを使ったほうが良かったのかなと思いました。

RaspberryPiでUSBメモリを挿したことをユーザプログラムから認識する

RaspberryPiでUSBメモリを指したことを確認する

つい先日名古屋ではこういうイベントがありました。

geekbar.doorkeeper.jp

発表もいろいろあったので自分ももう少し作品作りをしなければという気持ちになりました。ということで次回のイベント(?)に向けて自分も作ってみることにしました。(過去の焼き直しではありますが)

今回のエントリーでは、仮面ライダーWのダブルドライバーをRaspberryPiで実現に向けたものにしようと思います。昔作ったものはPCベースだったため、ベルト化(小型化)が難しかったのですが、今回はRaspberryPiでの実装ですのでバックル化も可能になると思います。最終ターゲットは腰に巻けるようにすることになります。

Wドライバーは以下のようなものです。

Amazon CAPTCHA

簡単にいうとUSBメモリを挿し、挿したものの種類を判別して音を鳴らすというものになります。Windows版については以下を参照してください。該当の組み合わせであれば変身音がなるというものです。

www.slideshare.net

USBメモリを抜き差しを検出する。

ネットを色々と調べてみるとLinuxではudevを使用することでデバイスの接続を確認することができるようです。

itpro.nikkeibp.co.jp

これによれば

udev(userspace device management)とは,カーネルがパソコンへの接続を検出したデバイスに対して,動的に「デバイス・ファイル」を作成して割り当てるための仕組みです。 Linuxは,システムに存在するあらゆるリソースをファイルとして扱うという特徴を持っています。

事前にlsusbを使用してみる

とりあえずudevを使用する前に、接続しようとする、USBメモリの認識を確認しておきます。USBの接続状況を確認するのは恒例のlsusbコマンドになります。

【接続前の状態】

$ lsusb
Bus 001 Device 005: ID 045e:075d Microsoft Corp. LifeCam Cinema
Bus 001 Device 004: ID 0411:01ee BUFFALO INC. (formerly MelCo., Inc.) WLI-UC-GNM2 Wireless LAN Adapter [Ralink RT3070]
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

【接続後の状態】

$ lsusb
Bus 001 Device 006: ID 090c:1000 Silicon Motion, Inc. - Taiwan (formerly Feiya Technology Corp.) Flash Drive
Bus 001 Device 005: ID 045e:075d Microsoft Corp. LifeCam Cinema
Bus 001 Device 004: ID 0411:01ee BUFFALO INC. (formerly MelCo., Inc.) WLI-UC-GNM2 Wireless LAN Adapter [Ralink RT3070]
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

以下のエントリーが追加されたUSBメモリの情報になります。

Bus 001 Device 006: ID 090c:1000 Silicon Motion, Inc. - Taiwan (formerly Feiya Technology Corp.) Flash Drive

IDの後につづいている値がVenderIDとProductID(ModelID)になります。もう少し固有の値がほしいのですが、このコマンドではここまでしか表示できませんでした。(後からわかったのですが-vで詳細がでますので、それで詳細をみてもいいかもしれません。)

lsusbコマンドでは認識されたUSBデバイスの状況のみが確認できるため、抜き差しのタイミングでの検知はできません。

udevを使用してみる

次にudevのコマンドインターフェースであるudevadmを使ってUSBデバイスの挿抜状態をモニタリングしてみたいと思います。

udevadmのモニタリングモードでは、KERNEL側の情報とUDEV側の情報をモニタリングできます。イベントとしては接続時のaddイベント、取り外し時のremoveイベントなどが見れます。このあたりはデバイスのクラスに依存するのでその他もありますが、詳細はドキュメントに記載されています。

実際に実行してみます。

$ udevadm monitor
monitor will print the received events for:
UDEV - the event which udev sends out after rule processing
KERNEL - the kernel uevent

KERNEL[1219.983660] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4 (usb)
KERNEL[1219.986476] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0 (usb)
KERNEL[1219.997083] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0 (scsi)
KERNEL[1219.997701] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/scsi_host/host0 (scsi_host)
UDEV  [1220.020340] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4 (usb)
UDEV  [1220.027171] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0 (usb)
UDEV  [1220.031344] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0 (scsi)
UDEV  [1220.035723] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/scsi_host/host0 (scsi_host)
KERNEL[1221.487617] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0 (scsi)
KERNEL[1221.487880] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0 (scsi)
KERNEL[1221.488153] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/scsi_disk/0:0:0:0 (scsi_disk)
KERNEL[1221.488541] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/scsi_device/0:0:0:0 (scsi_device)
KERNEL[1221.490362] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/bsg/0:0:0:0 (bsg)
UDEV  [1221.491079] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0 (scsi)
KERNEL[1221.493208] add      /devices/virtual/bdi/8:0 (bdi)
UDEV  [1221.496802] add      /devices/virtual/bdi/8:0 (bdi)
KERNEL[1221.504379] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/block/sda (block)
KERNEL[1221.505020] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda1 (block)
UDEV  [1221.505249] add      /module/sg (module)
KERNEL[1221.505405] add      /module/sg (module)
UDEV  [1221.505879] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0 (scsi)
KERNEL[1221.506146] add      /class/scsi_generic (class)
KERNEL[1221.506620] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/scsi_generic/sg0 (scsi_generic)
UDEV  [1221.507040] add      /class/scsi_generic (class)
UDEV  [1221.512906] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/scsi_device/0:0:0:0 (scsi_device)
UDEV  [1221.513143] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/scsi_disk/0:0:0:0 (scsi_disk)
UDEV  [1221.516441] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/bsg/0:0:0:0 (bsg)
UDEV  [1221.525971] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/scsi_generic/sg0 (scsi_generic)
UDEV  [1221.589504] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/block/sda (block)
UDEV  [1221.663788] add      /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda1 (block)
KERNEL[1242.032388] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/bsg/0:0:0:0 (bsg)
KERNEL[1242.032573] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/scsi_generic/sg0 (scsi_generic)
KERNEL[1242.032678] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/scsi_device/0:0:0:0 (scsi_device)
KERNEL[1242.040388] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/scsi_disk/0:0:0:0 (scsi_disk)
UDEV  [1242.040618] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/bsg/0:0:0:0 (bsg)
KERNEL[1242.040797] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda1 (block)
KERNEL[1242.040961] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/block/sda (block)
KERNEL[1242.041102] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0 (scsi)
UDEV  [1242.047234] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/scsi_generic/sg0 (scsi_generic)
UDEV  [1242.049023] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/block/sda/sda1 (block)
UDEV  [1242.051848] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/scsi_device/0:0:0:0 (scsi_device)
UDEV  [1242.053386] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/scsi_disk/0:0:0:0 (scsi_disk)
UDEV  [1242.063650] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0/block/sda (block)
UDEV  [1242.070194] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0/0:0:0:0 (scsi)
KERNEL[1242.074278] remove   /devices/virtual/bdi/8:0 (bdi)
KERNEL[1242.074545] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0 (scsi)
KERNEL[1242.075798] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/scsi_host/host0 (scsi_host)
UDEV  [1242.076003] remove   /devices/virtual/bdi/8:0 (bdi)
KERNEL[1242.076136] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0 (scsi)
KERNEL[1242.076318] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0 (usb)
UDEV  [1242.078805] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/target0:0:0 (scsi)
UDEV  [1242.079279] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0/scsi_host/host0 (scsi_host)
KERNEL[1242.079514] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4 (usb)
UDEV  [1242.085069] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0/host0 (scsi)
UDEV  [1242.089120] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4/1-1.4:1.0 (usb)
UDEV  [1242.099753] remove   /devices/platform/soc/3f980000.usb/usb1/1-1/1-1.4 (usb)
KERNEL[1246.060791] add      /devices/w1_bus_master1/00-980000000000 (w1)
UDEV  [1246.064646] add      /devices/w1_bus_master1/00-980000000000 (w1)

一応、これでUSBメモリを挿抜ときの状態を確認できるようです。これをユーザープログラム上から検出できれば目的はほぼ達成となります。

udevでデバイスの挿抜状態を検出する方法としては、pythonpyudevというモジュールがあるのでこれを使用することにします。

pyudevとは

pyudev – pure Python libudev binding

https://pyudev.readthedocs.io/en/latest/

libudevの情報をpythonで取得できるようにしたモジュールになります。

pyudevをインストールする

パッケージのインストール方法に従ってモジュールのインストールをしてみます。

$ pip install pyudev
Downloading/unpacking pyudev
  Downloading pyudev-0.21.0.tar.gz (89kB): 89kB downloaded
  Running setup.py (path:/tmp/pip-build-jZcUeV/pyudev/setup.py) egg_info for package pyudev

    warning: no previously-included files matching '*.py' found under directory 'tests/.hypothesis'
    warning: no files found matching '*.c' under directory 'reproducers'
    warning: no files found matching '*.py' under directory 'reproducers'
Requirement already satisfied (use --upgrade to upgrade): six in /usr/lib/python2.7/dist-packages (from pyudev)
Installing collected packages: pyudev
  Running setup.py install for pyudev
    error: could not create '/usr/local/lib/python2.7/dist-packages/pyudev': Permission denied
    Complete output from command /usr/bin/python -c "import setuptools, tokenize;__file__='/tmp/pip-build-jZcUeV/pyudev/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /tmp/pip-24vQet-record/install-record.txt --single-version-externally-managed --compile:
    running install

running build

running build_py

creating build

creating build/lib.linux-armv7l-2.7

creating build/lib.linux-armv7l-2.7/pyudev

copying src/pyudev/_qt_base.py -> build/lib.linux-armv7l-2.7/pyudev

copying src/pyudev/pyqt4.py -> build/lib.linux-armv7l-2.7/pyudev

copying src/pyudev/version.py -> build/lib.linux-armv7l-2.7/pyudev

copying src/pyudev/core.py -> build/lib.linux-armv7l-2.7/pyudev

copying src/pyudev/__init__.py -> build/lib.linux-armv7l-2.7/pyudev

copying src/pyudev/_util.py -> build/lib.linux-armv7l-2.7/pyudev

copying src/pyudev/discover.py -> build/lib.linux-armv7l-2.7/pyudev

copying src/pyudev/glib.py -> build/lib.linux-armv7l-2.7/pyudev

copying src/pyudev/_compat.py -> build/lib.linux-armv7l-2.7/pyudev

copying src/pyudev/pyqt5.py -> build/lib.linux-armv7l-2.7/pyudev

copying src/pyudev/monitor.py -> build/lib.linux-armv7l-2.7/pyudev

copying src/pyudev/wx.py -> build/lib.linux-armv7l-2.7/pyudev

copying src/pyudev/pyside.py -> build/lib.linux-armv7l-2.7/pyudev

creating build/lib.linux-armv7l-2.7/pyudev/device

copying src/pyudev/device/_device.py -> build/lib.linux-armv7l-2.7/pyudev/device

copying src/pyudev/device/_errors.py -> build/lib.linux-armv7l-2.7/pyudev/device

copying src/pyudev/device/__init__.py -> build/lib.linux-armv7l-2.7/pyudev/device

creating build/lib.linux-armv7l-2.7/pyudev/_ctypeslib

copying src/pyudev/_ctypeslib/libc.py -> build/lib.linux-armv7l-2.7/pyudev/_ctypeslib

copying src/pyudev/_ctypeslib/libudev.py -> build/lib.linux-armv7l-2.7/pyudev/_ctypeslib

copying src/pyudev/_ctypeslib/_errorcheckers.py -> build/lib.linux-armv7l-2.7/pyudev/_ctypeslib

copying src/pyudev/_ctypeslib/__init__.py -> build/lib.linux-armv7l-2.7/pyudev/_ctypeslib

copying src/pyudev/_ctypeslib/utils.py -> build/lib.linux-armv7l-2.7/pyudev/_ctypeslib

creating build/lib.linux-armv7l-2.7/pyudev/_os

copying src/pyudev/_os/pipe.py -> build/lib.linux-armv7l-2.7/pyudev/_os

copying src/pyudev/_os/poll.py -> build/lib.linux-armv7l-2.7/pyudev/_os

copying src/pyudev/_os/__init__.py -> build/lib.linux-armv7l-2.7/pyudev/_os

running install_lib

creating /usr/local/lib/python2.7/dist-packages/pyudev

error: could not create '/usr/local/lib/python2.7/dist-packages/pyudev': Permission denied

----------------------------------------
Cleaning up...
Command /usr/bin/python -c "import setuptools, tokenize;__file__='/tmp/pip-build-jZcUeV/pyudev/setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n', '\n'), __file__, 'exec'))" install --record /tmp/pip-24vQet-record/install-record.txt --single-version-externally-managed --compile failed with error code 1 in /tmp/pip-build-jZcUeV/pyudev
Storing debug log for failure in /home/pi/.pip/pip.log

あれ?エラーです。内容としてはディレクトリが作成できない感じのメッセージなので、一般ユーザでは権限がないからなのかなと思います。 sudoつきでpipを行えば大丈夫そうなんですが、今回はapt-getでインストールしてみることにします。

一応、パッケージがあるか確認してみます。

$ apt-cache search pyudev
python-pyudev - Python bindings for libudev
python3-pyudev - Python3 bindings for libudev

aptのパッケージではVersion2系と3系があるようですので、今回は2系を入れます。(そろそろ3への以降も考えたいですが。)

$ sudo apt-get install python-pyudev
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
以下のパッケージが自動でインストールされましたが、もう必要とされていません:
  ax25-node libax25 libllvm3.7 openbsd-inetd
これを削除するには 'apt-get autoremove' を利用してください。
提案パッケージ:
  python-qt4 python-pyside.qtcore
以下のパッケージが新たにインストールされます:
  python-pyudev
アップグレード: 0 個、新規インストール: 1 個、削除: 0 個、保留: 161 個。
31.6 kB のアーカイブを取得する必要があります。
この操作後に追加で 193 kB のディスク容量が消費されます。
取得:1 http://mirrordirector.raspbian.org/raspbian/ jessie/main python-pyudev all 0.16.1-2 [31.6 kB]
31.6 kB を 1秒 で取得しました (29.4 kB/s)
以前に未選択のパッケージ python-pyudev を選択しています。
(データベースを読み込んでいます ... 現在 130447 個のファイルとディレクトリがインストールされています。)
.../python-pyudev_0.16.1-2_all.deb を展開する準備をしています ...
python-pyudev (0.16.1-2) を展開しています...
python-pyudev (0.16.1-2) を設定しています ...

無事にインストールできました。

念のためテストしてみると…

$ python
Python 2.7.9 (default, Sep 17 2016, 20:26:04)
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyudev
>>>

エラーがでていないのでインストールは無事に終わったようです。 ドキュメントに出ているサンプルを実行させてみます。

以下のサンプルは認識されているデバイスの一覧を表示させるものになります。

【sample.py】

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import pyudev
context = pyudev.Context()
for device in context.list_devices():
    print(device)

では、実行してみます。

$ python sample.py
Device(u'/sys/devices/armv7_cortex_a7')
Device(u'/sys/devices/breakpoint')
Device(u'/sys/devices/platform/alarmtimer')
Device(u'/sys/devices/platform/clocks')
Device(u'/sys/devices/platform/clocks/clocks:clock@0')
Device(u'/sys/devices/platform/clocks/clocks:clock@1')
Device(u'/sys/devices/platform/clocks/clocks:clock@2')
Device(u'/sys/devices/platform/clocks/clocks:clock@3')
Device(u'/sys/devices/platform/clocks/clocks:clock@4')
Device(u'/sys/devices/platform/clocks/clocks:clock@5')
Device(u'/sys/devices/platform/clocks/clocks:clock@6')
Device(u'/sys/devices/platform/lirc_rpi')
(略)

udevで認識されているデバイスが大量に出てきます。 あとは、USBメモリを指したことがモニタできれば次のステップにすすめます。 udevadmのモニタ機能と同じものができればよいということになります。

メモリの細かい判別を行うために必要なパラメータとしては

  • Action(挿した抜いたなどのイベントの種類)
  • ID_MODEL_ID(デバイスのModelID)
  • ID_MODEL_FROM_DATABASE(ModelIDから得られる製品のモデル名)
  • ID_VENDOR_ID(デバイスのVentorID)
  • ID_VENDOR_FROM_DATABASE(VentorIDから得られるベンダー(会社)名)
  • ID_SERIAL_SHORT(製品の固有値の短縮形式)
  • ID_SERIAL(製品の固有値 短縮形にメーカー名、モデル名などが入っていることがあります)

以上だと思います。 ではモニタリングを行うプログラムは以下のようになります。

【pyudev_event.py】

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import pyudev

context = pyudev.Context()
monitor = pyudev.Monitor.from_netlink(context)
monitor.filter_by(subsystem='usb')
monitor.start()

for device in iter(monitor.poll, None):
  print(device.action)
  print('MODEL  : {0} -> {1}'.format(device.get('ID_MODEL_ID'), device.get('ID_MODEL_FROM_DATABASE')))
  print('VENDOR : {0} -> {1}'.format(device.get('ID_VENDOR_ID'), device.get('ID_VENDOR_FROM_DATABASE')))
  print('SERIAL : {0} -> {1}'.format(device.get('ID_SERIAL_SHORT'), device.get('ID_SERIAL')))
  print('---')

pyudevのMonitorオブジェクトを生成し、Contextを監視する様にしたのがサンプルとの大きな違いです。pyudev.Monitor.from_netlink(context) と実行しているnetlinkに関してですがman pageによれば

netlink はカーネルモジュールとユーザー空間のプロセス間で 情報をやりとりするために用いられる。

とのことですので、pyudevはこれを経由して動的にデバイス情報を得ていることになります。

実行して、USBメモリを何本か挿抜してみます。(面倒なのでシリアル値はそのままにしました…)

$ python pyudev_event.py
add
ID_MODEL : 0098 -> None
ID_VENDOR : 0411 -> BUFFALO INC. (formerly MelCo., Inc.)
SERIAL : A000000000095409 -> BUFFALO_SiliconHardDisk_A000000000095409
---
add
ID_MODEL : None -> None
ID_VENDOR : None -> BUFFALO INC. (formerly MelCo., Inc.)
SERIAL : None -> None
---
remove
ID_MODEL : None -> None
ID_VENDOR : None -> BUFFALO INC. (formerly MelCo., Inc.)
SERIAL : None -> None
---
remove
ID_MODEL : 0098 -> None
ID_VENDOR : 0411 -> BUFFALO INC. (formerly MelCo., Inc.)
SERIAL : A000000000095409 -> BUFFALO_SiliconHardDisk_A000000000095409
---
add
ID_MODEL : 1000 -> Flash Drive
ID_VENDOR : 090c -> Silicon Motion, Inc. - Taiwan (formerly Feiya Technology Corp.)
SERIAL : None -> SMI_Corporation_USB_DISK
---
add
ID_MODEL : None -> Flash Drive
ID_VENDOR : None -> Silicon Motion, Inc. - Taiwan (formerly Feiya Technology Corp.)
SERIAL : None -> None
---
remove
ID_MODEL : None -> Flash Drive
ID_VENDOR : None -> Silicon Motion, Inc. - Taiwan (formerly Feiya Technology Corp.)
SERIAL : None -> None
---
remove
ID_MODEL : 1000 -> Flash Drive
ID_VENDOR : 090c -> Silicon Motion, Inc. - Taiwan (formerly Feiya Technology Corp.)
SERIAL : None -> SMI_Corporation_USB_DISK
---
add
ID_MODEL : 5583 -> None
ID_VENDOR : 0781 -> SanDisk Corp.
SERIAL : 4C531001520507123272 -> SanDisk_Ultra_Fit_4C531001520507123272
---
add
ID_MODEL : None -> None
ID_VENDOR : None -> SanDisk Corp.
SERIAL : None -> None
---
remove
ID_MODEL : None -> None
ID_VENDOR : None -> SanDisk Corp.
SERIAL : None -> None
---
remove
ID_MODEL : 5583 -> None
ID_VENDOR : 0781 -> SanDisk Corp.
SERIAL : 4C531001520507123272 -> SanDisk_Ultra_Fit_4C531001520507123272
---
^CTraceback (most recent call last):
  File "pyudev_sample.py", line 8, in <module>
    for device in iter(monitor.poll, None):
  File "/usr/lib/python2.7/dist-packages/pyudev/monitor.py", line 340, in poll
    rlist, _, _ = select.select([self], [], [], timeout)
KeyboardInterrupt

今回の例では3メーカーのUSBメモリを挿してみたのですが、一回抜き差しをするごとに2回のイベントが表示されていました。また、USBメモリ固有値であるとされるID_SERIAL_SHORT'ID_SERIALが必ずしも入っていないことがわかりました。このあたりはメーカーのポリシーなのかもしれません。(価格が安いからとかそういう感じでもないようでした)

方針としては、値が取得できるときには判別にそれを使用し、無いときにはVenderIDとModelIDを使うことで代用したいと思います。

これでUSBの挿抜の認識の準備はできました。あともう少しですが今回はここまでにします。

おわりに

udevをつかったデバイス検出の部分と、pythonからのudev情報の呼び出し部分を作成の実験を行ってみました。後もう少しですが、次は組み合わせと音を鳴らす部分の処理を追加してプロトタイプを仕上げたいと思います。

やっているうちにもっと違う方法もあるのかなと思い始めたのですが、気が向いたらそれも試したいと考えています。