ひこぽんのーと

覚書と雑記です。

Arch Linuxのインストール手順のこと その1

Install Arch Linux

Ubuntu Mate 18.04がいまいちだったのでArch Linuxに入れ替えた。
Arch Linux公式サイトにはインストール手順やドキュメントが充実しているので、
基本は手順通りに行えば良いのだが、それでも迷うところがちらほらあった。
念のために、以下に手順を残す。
今回はBIOSモード、MBRGRUBをインストールするレガシーなパターンです。

インストールメディアの準備

公式サイトからインストールイメージをダウンロード。
Ubuntuのディスクイメージライターを使って、USBメモリにレストアした。

パーティション

UbuntuのLive CDで予め作成した。
とはいえ、LVMを使うのでGUI操作よりコンソール操作が多かった。

バイス マウントポイント フォーマット サイズ 用途
/dev/mapper/mate--vg-lvswap - SWAP 16G スワップ
/dev/mapper/mate--vg-lvroot / ext4 100G ルート領域
/dev/sdb1 /boot ext2(boot ON) 1G ブート領域
/dev/mapper/mate--vg-lvfile /usr/files/ ext4 残り全部 ユーザデータ用

nagamitsu1976.hatenadiary.jp

インストールの準備

PCをUSBブートしてArch Linuxインストールメディアを起動。
メニューからインストーラーを起動。

キーボードレイアウトの設定
$ loadkeys jp106
パーティションの確認

インストールするディスクのデバイス名を確認する。

$ fdisk -l
ルートパーティションのマウント
$ mount /dev/mapper/mate--vg-lvroot /mnt
マウントポイントを作成
$ mkdir /mnt/boot 
$ mkdir -p /mnt/usr/files
残りパーティションのマウント
$ mount /dev/sdb1 /mnt/boot
$ mount /dev/mapper/mate--vg-lvfile /mnt/usr/files
スワップ有効化
$ swapon /dev/mapper/mate--vg-lvswap
ネット接続の確認

wifi接続の場合、接続設定を行う必要があるので、
有線接続での作業が楽です。
wifi設定はOSインストール後なら、NetworkManagerを使うなりなんなりで、
手軽にできるからです。

$ ping www.google.com
システムクロックの変更
$ timedatectl set-ntp true

OSのインストール

ミラーの選択

mirrorlistファイルを開いてリストから国内のサーバーを検索する。
見つかった国内サーバーのURLをファイルの上位にカット&ペーストする。
国内のサーバーもいくつかあるので、
どんな順番にするかは下のページを見ると参考になる。
https://www.archlinux.jp/mirrors/status/

とはいえ、Jaist筑波大学のサイトを上位にすればいいと思う。

$ nano /etc/pacman.d/mirrorlist
ベースシステムのインストール
### $ pacstrap /mnt base base-devel [old] ###
$ pacstrap /mnt base linux linux-firmware
fstabの生成
$ genfstab -U /mnt >> /mnt/etc/fstab

システム設定

以降は、システムの基本設定を行う。
タイムゾーンロケール、ホスト名などなど。

ルートディレクトリ変更

インストールしたベースシステムにルートを変更する。

$ arch-chroot /mnt
タイムゾーン設定
$ ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
$ hwclock --systohc --utc
ロケール設定

/etc/locale.genを編集してからlocale-genを設定する。
有効にするのはen_US.UTF-8 UTF-8とja_JP.UTF-8 UTF-8でOK

$ nano /etc/locale.gen
$ locale-gen

/etc/locale.confにロケールを定義する

$ echo LANG=ja_JP.UTF-8 > /etc/locale.conf
キーマップの設定
$ echo KEYMAP=jp106 > /etc/vconsole.conf
ホスト名の設定
$ echo myhostname > /etc/hostname
$ nano /etc/hosts

同じ名前を/etc/hostsにも記載。

127.0.0.1	localhost
::1		localhost
127.0.1.1	myhostname.localdomain	myhostname
ネットワーク設定

baseシステムではdhcpcdを使い、
あとでNetworkManagerをインストールして使う算段なので、
ここではdhcpcdを有効化する。

$ systemctl enable dhcpcd@[network-interface-name].service
もしくは
$ systemctl enable dhcpcd

インターフェイス名を確認するには、ip link*1を使う。

initramfsの生成

lvmを使っている場合(ルートパーティションが論理ボリュームの場合)
/etc/mkinitcpio.confを編集する。

$ nano /etc/mkinitcpio.conf
……
# HOOKSの行に[lvm2]を追加する。
HOOKS=(base udev autodetect modconf block lvm2 filesystems keyboard fsck)
……
# mkinitcpio -p linux
rootパスワード設定
$ passwd

ブートローダーの設定

最初に書いた通り、ここではBIOSモードでMBRGRUBをインストールする。

exFatNTFSのサポート

Windowsとのデュアルブートのために、exFatNTFSを扱えるようにする。
デュアルブートでなくても入れておいたほうが無難か。

$ pacman -S exfat-utils ntfs-3g
GRUBのインストール

grub-installでMBRに書き込むデバイスを間違えないように注意する。
ここでWindowsのインストール先ディスクに書いてしまったら……*2

$ pacman -S os-prober grub
$ grub-install --target=i386-pc /dev/sdb
$ grub-mkconfig -o /boot/grub/grub.cfg
マイクロコードアップデート設定

Intel製CPUを使っている場合は、更にintel-ucodeパッケージをインストールする。
amd製CPUだったらamd-ucodeパッケージをインストールする。

インストール後、再度、grub-mkconfigを行う。

$ pacman -S intel-ucode
$ grub-mkconfig -o /boot/grub/grub.cfg

再起動

exitで一旦抜けたあと、
ルートパーティションをアンマウントし再起動する。
ブート前にインストールメディアを抜いておくのを忘れずに。

$ exit
$ umount -R /mnt
$ reboot

Congraturations!

ディスクから起動するとGRUBが立ち上がり、
Linuxが起動すれば、インストール成功。
これでCUILinuxが使えます。
おつかれさまでした。

……って、ここで投げ出されてもツラい。
というわけで、その2へ続く。

*1:ifconfigを含むはnet-toolsはもう過去のものになってるようだ。

*2:Windowsブートローダーが壊れます。

Raspberry PiでDNLA Music Serverから曲を取得して再生するのこと。

うちの環境にはBuffaloのLinkStationというNASがあって、
こいつがDNLA Media Serverの機能を持っているので、
ミュージックライブラリとして使っていた。
VLCにはUPnP機能があったので、これで再生していた。
しかし、再生するにはパソコンを立ちあげなければいけない。
スマホにもUPnPメディアクライアントはあるけれど、
再生にはスマホを使わないといけない。

というわけで、
サーバーとして24h稼働しているRaspberry Pi
このような音楽の再生ができないかと考えた。

調査の結果、以下のことがわかった。

  • DNLAはUPnPの仕様に基づいて作られている。
  • UPnP Media Serverのコンテンツを再生するには、Media Rendererの実装が必要である。
  • Media ServerとMedia Rendererの操作を行うためにクライアントが必要。
    操作のための通信方式がSSPDだったり、SOAPだったりする。

ここまでわかるまで、SSPDやらSOAPやらを叩いて時間を使ってしまった。

これを踏まえて現状を見ると、以下が見えてきた。

  • Media Serverはある。→ LinkStation
  • Media Rendererはない。→ Raspberry Piに構築。
  • Media Clientはない。→ さしあたり、Androidの『BubbleUPnP』が使えそう。

と、こんなことをすでにやっている人がおり、
下記の記述を参考にRaspberry PiにMedia Rendererを構築してみた。

Playing music on a Raspberry Pi using UPnP and DLNA (revisited)

ここの例にあるように、Raspberry PiにGMediaRenderをインストールした。
自動起動については、init.dではなく、systemdを使った。

スマホにインストールしてあるBubleUPnPのレンダラーを
Raspberry Pi上のレンダラーとすることで、
Raspberry Piから音を出すことができた。

しかし、Clientは自作したいな。
現状、スマホからしか操作できないのは不便だ。

参考文献:
http://blog.scphillips.com/posts/2013/07/playing-music-on-a-raspberry-pi-using-upnp-and-dlna-revisited
https://openconnectivity.org/developer/specifications/upnp-resources/upnp
http://www.upnp.org/specs/av/UPnP-av-AVArchitecture-v1.pdf.

Raspberry Piでラジオを鳴らすのこと

Raspberry Piにスピーカーをつけてラジオを鳴らす方法についてのメモ。
おおまかな仕掛けとしては、
Radikoのswfプレイヤーからストリーミングデータをぶっこ抜いて
メディアプレイヤーで再生する方式の模様。
(だから、いつまで使えるかわからんね)

音声を再生するアプリの導入*1

sudo apt-get install mplayer

ストリーミング関係のアプリの導入

sudo apt-get install rtmpdump swftools libxml2-utils

音声出力先の設定

デフォルトではイヤホンジャックかHDMIか自動判定となっている。
HDMIなり、イヤホンジャックなりどちらか固定としたい場合は
rasp-configから設定可能。
設定メニューの[Advance Options] -> [Audio]と追っていき、
[Auto], [Force 3.5mm ('Headphone') jack], [Force HDMI]から選択する。

sudo rasp-config

音量の設定

画面からできるけど、コマンドでやる場合。
下記でコマンドで現在の値を知る。

sudo amixir -M

Simple mixer control 'PCM',0
  Capabilities: pvolume pvolume-joined pswitch pswitch-joined
  Playback channels: Mono
  Limits: Playback -10239 - 400
  Mono: Playback 400 [100%] [4.00dB] [on]

下記、コマンドで設定する。

sudo amixir sset PCM 100%

radikoを再生するスクリプトの取得

スクリプトをここから取得
play_nhk-radio.sh · GitHub

play_radiko.sh スクリプトの修正

radiko側の状態が変わっているのだろうが、
再生で使用するplay_radiko.shはそのままだと動かない。
以下の箇所を修正する。

修正前 修正後
28 playerurl=http://radiko.jp/player/swf/player_3.0.0.01.swf playerurl=http://radiko.jp/apps/js/flash/myplayer-release.swf
53 swfextract -b 14 $playerfile -o $keyfile swfextract -b 12 $playerfile -o $keyfile
70 --header="X-Radiko-App: pc_1" \ --header="X-Radiko-App: pc_ts" \
71 --header="X-Radiko-App-Version: 2.0.1" \ --header="X-Radiko-App-Version: 4.0.1" \
108 --header="X-Radiko-App: pc_1" \ --header="X-Radiko-App: pc_ts" \
109 --header="X-Radiko-App-Version: 2.0.1" \ --header="X-Radiko-App-Version: 4.0.1" \
111 --header="X-Radiko-Authtoken: ${authtoken}" \ --header="X-Radiko-AuthToken: ${authtoken}" \
112 --header="X-Radiko-Partialkey: ${partialkey}" \ --header="X-Radiko-PartialKey: ${partialkey}" \

*1:mplayerよりvlcのコンソール版cvlcの方が安定している気がする。mplayerだとsignal 13(パイプ破壊)が結構出た。

Raspberry pi Model BでGW-900Dを使うのこと

RaspbianにはPlanexの無線Lan子機 GW-900Dのドライバは用意されていない。
幸いドライバはrtl8812auのオープンソースドライバが利用でき、
ビルドさえすればLinuxでも動作する。

Web上にはこの手の手順がかなりあるものの、
持っているRaspberry piが初期型のためか、
導入にかなり手こずったので自分なりの手順を書いておく。
以下の手順では有線Lanでインターネットに接続している事が前提となる。

rtl8812auドライバのインストール

Raspbianをインストールする

手っ取り早くNOOBSでインストールした。(JESSIE)

OSの最新化

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

rootパスワードの設定

$ sudo passwd root

ドライバのビルドに必要なもののインストール

rpi-sourceのインストール

Raspbianのソースを取得するためにこのツールをインストールする
$ sudo wget https://raw.githubusercontent.com/notro/rpi-source/master/rpi-source -O /usr/bin/rpi-source

rpi-sourceの実行で必要なもののインストール

sudo apt-get install bc
sudo apt-get install libncurses5-dev

rpi-sourceの実行(カーネルソースのダウンロード)

$ sudo chmod +x /usr/bin/rpi-source
$ sudo /usr/bin/rpi-source -q --tag-update
$ sudo rpi-source --skip-gcc (gccのバージョンで弾かれたため)

/usr/srcにリンクを貼る

ln -s /root/linux-XXXXXX /usr/src/`uname -r`

rtl8812auドライバのダウンロード

保存場所へ適時移動してからダウンロードを実行
git clone https://github.com/gnab/rtl8812au.git

ドライバのビルド

ダウンロードしたドライバのディレクトリに移動
Makefileの編集。

ターゲットプラットフォームをPCからARM RPIに変更する。
...
CONFIG_PLATFORM_I386_PC = n
...
CONFIG_PLATFORM_ARM_RPI = y
...

ビルド

変更後、ビルド。
make

ドライバファイルの設置&カーネルモジュールの依存情報の更新

cp 8812au.ko /lib/modules/$(uname -r)/kernel/drivers/net/wireless
depmod

再起動

sudo reboot

まだまだこれから

dmesg でドライバがロードされているか確認。

ネットワークインターフェイス名の固定化

なんだか知らないがネットワークインターフェイス名(eth0とかのアレ)が、
再起動するたびにコロコロ変更されるので、これを固定化する。

ネットワークインターフェイス名の調査

ifconfigとiwconfigを使って、現在のネットワークインターフェイス名を調べる。

MACアドレスNICのドライバ名の調査。

MACアドレスはifconfigで表示される、etherの値。
NICのドライバ名はethtoolで調べることができる。
ethtool -i ネットワークインターフェイス

ネットワークインターフェイス名の設定

/etc/udev/rule.d/70-persistent-net.rules を作成
ファイルに以下の要領で定義を追加する。
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="(ドライバ名)", ATTR{address}=="AA:BB:CC:DD:EE:FF(MACアドレス)", NAME="eth0(インターフェイス名)"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="(ドライバ名)", ATTR{address}=="AA:BB:CC:DD:EE:FF(MACアドレス)", NAME="wlan0(インターフェイス名)"

書式はここ参照。
NIC の名前(eth0, eth1, wlan0, ath0,...)を変更

再起動

sudo reboot

ifconfigで確認

ネットワークンターフェイス名が指定通りならOK。

wifiの有効化

アクセスポイントのscan

sudo iwlist wlan0 scan

wpa_supplicant.confの設定

sudo wpa_passphrase (SSID) (パスワード(平文)) >> /etc/wpa_supplicant/wpa_supplicant.conf

wpa_supplicantの起動

sudo wpa_supplicant -Dwext -iwlan0 -c/etc/wpa_supplicant/wpa_supplicant.conf

接続の確認

ifconfigでIPアドレスが割り当てられていることを確認

wifi自動起動

システム起動時にwlan0が有効になるようにsystemdに設定する。

# systemctl enable wpa_supplicant@wlan0(インターフェイス名)
Created symlink /etc/systemd/system/multi-user.target.wants/wpa_supplicant@wlan0.service → /lib/systemd/system/wpa_supplicant@.service.

wlan0用のwpa_supplicant.confを作成する。

sudo cp /etc/wpa_supplicant/wpa_supplicant.conf /etc/wpa_supplicant/wpa_supplicant-wlan0.conf

再起動

ifconfigでwifiが自動接続されていることを確認する。

IPアドレス固定設定

検索すると/etc/network/interfacesを編集するってのがよく見つかるけれど、
その方法はもう古い。
JESSIEでは/etc/dhcpcd.confに設定を記述する方式に変わっている。
ちなみにUbuntu 16.04だったらnmtuiを使って設定する。

/etc/dhcpcd.confを編集する。

interface eth0
static ip_address=192.168.10.32/24
static routers=192.168.10.1
static domain_name_servers=192.168.10.1

interface wlan0
static ip_address=192.168.10.33/24
static routers=192.168.10.1
static domain_name_servers=192.168.10.1

Djangoをやってみよう。 その8-管理サイトでの操作-

その7のつづき。

その6で作ったWarshipモデルを管理画面に登録してみる。
nagamitsu1976.hatenadiary.jp

作成したモデルを管理画面に登録するには、
アプリケーションディレクトリ配下にあるadmin.pyにモデル管理クラスを作成する必要がある。
warship/admin.pyを開いて下記を追加する。

from django.contrib import admin
from warship.models import ShipClass, Warship
# Register your models here.


class ShipClassAdmin(admin.ModelAdmin):
    fields = [u"name"]


class WarshipAdmin(admin.ModelAdmin):
    fields = [ u"ship_class", u"name"]
    list_display = [u"ship_class", u"name"]


admin.site.register(ShipClass, ShipClassAdmin)
admin.site.register(Warship, WarshipAdmin)

ここではAdminクラスのメンバにfieldsとlist_displayを定義した。

fieldsについてはモデルの編集画面に表示したい項目をリストで定義している。
つまり、ShipClassは"name"をWarshipは"ship_class"と"name"を表示したい、
ということになる。

list_displayについては、モデルの一覧画面で表示したい項目を定義していて、
ここでは仮にWarshipだけ"ship_class"と"name"を定義してみた。

最後に、admin.site.registerを使って管理画面にモデルと管理モデルのひも付けを行って
処理は完了。
サーバを再起動して管理画面を表示しなおしてみると、項目が増えているのがわかる。

f:id:nagamitsu1976:20170623151530p:plain

Warshipをクリックして一覧を表示してみると、
list_displayで定義した項目が表示されるのがわかる。
f:id:nagamitsu1976:20170623151902p:plain

一方、前画面に戻ってShipClassを開いてみると。。。
項目がnameになっておらず、__str__()の値がそのまま表示される。
f:id:nagamitsu1976:20170623152055p:plain

「ADD Ship class」ボタンを押して、編集画面を見てみる。
こちらはfieldsに定義したnameが表示される。
f:id:nagamitsu1976:20170623152252p:plain

ついでに「軽巡」を入力してSAVEボタンを押してみる。
正しく追加できているのがわかる。
f:id:nagamitsu1976:20170623152527p:plain
f:id:nagamitsu1976:20170623152536p:plain

同じように、Warshipの追加ボタンを押して、
編集画面を確認してみる。
項目の順序もfieldsの順番で表示されている。
f:id:nagamitsu1976:20170623154729p:plain

ついでに登録も試してみる。
f:id:nagamitsu1976:20170623154656p:plain
f:id:nagamitsu1976:20170623153040p:plain

とまぁ、こんな感じで簡単にモデルの登録、編集画面ができたとさ。
使い方としてはマスタ編集画面だとかになるんだろうか。
製造時のデバッグデータ、試験データ作成にもいいかも。
なんせ、低コストだし。

といったところで、次回へ続く。

Djangoをやってみよう。 その7-管理サイト-

その6のつづき。

Apache TomcatにWebアプリケーションを登録する時、
管理画面を使ってデプロイすることができる。
これと似たようなもので、Djangoにも管理画面がある。
管理画面を使うには管理者ユーザを作成する必要がある。

と、その前に以下のコマンドを実行して管理画面等、基本機能を使用可能状態にする。
管理テーブルなんかが作られるため、プロジェクト作成後にやってしまえばよかった。

 python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions, warship
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying sessions.0001_initial... OK

管理テーブルができたら、管理ユーザ作成コマンドを実行する。
初回はコマンドでユーザを作るが、
以降は管理画面から追加できる。

python manage.py createsuperuser
Username (leave blank to use 'nagamitsu'): 
Email address: nagamitsu@foo.bar.com
Password: 
Password (again): 
Superuser created successfully.

ユーザを作成したら、サーバを起動して管理画面を起動してみる。

python manage.py runserver

管理画面のURLはこれだ。
http://127.0.0.1:8000/admin
f:id:nagamitsu1976:20170623144059p:plain
先ほど作ったユーザでログインしてみる。
f:id:nagamitsu1976:20170623144349p:plain
ログイン後、管理メニューのようなものが表示される。

Usersなどをクリックしてみるとわかると思うが、
今のところ、管理ユーザの追加・編集程度しかできないが、
定義を加えることで、
作成したアプリのモデルを管理画面から編集することができるようになる。

といったところで、次回へ続く。

Djangoをやってみよう。 その6-Model/DBの操作-

その5の続き。

まだ画面も何もないので、
コンソールからモデルの操作をやってみる。
実行自体は簡単でpythonの対話モードを使う。
ただし、Djangoの機能だったり、
helloサイト上のクラスを正しく使うには、
ちょっとした手順がある。

python manage.py shell

このコマンドを実行するとhelloサイトの設定が読み込まれた状態で
Pythonの対話モードが起動する。

対話モードに入ったらまず、艦種を登録してみる。

>>> from warship.models import ShipClass
>>> ship_class = ShipClass()
>>> ship_class.name = u'駆逐艦'
>>> ship_class.save()

ShipClassをインポートしたあと、ShipClassのインスタンスを作り、
nameに「駆逐艦」を設定したあと、saveメソッドを呼ぶだけ。
これで、DBに対してInsertが走る。

登録されたかどうか、検索してみる。
とりあえず、全件検索の<モデル>.objects.all()を実行してみる。

>>> ShipClass.objects.all()
<QuerySet [<ShipClass: ShipClass object>]>

なんか帰ってきたがよくわからんね。
チュートリアルでは「モデルに__str__メソッドを追加するのが重要です。」なんて、
あとに書いてある。
こっちも真似してmodels.pyのクラスを以下のように変えてみる。

from django.db import models

# Create your models here.


class ShipClass(models.Model):
    name = models.CharField(max_length=30)

    def __str__(self):
        return self.name

class Warship(models.Model):
    ship_class = models.ForeignKey(ShipClass, on_delete=models.CASCADE)
    name = models.CharField(max_length=30)

    def __str__(self):
        return u"{0} - {1}".format(self.ship_class, self.name)

そしたら、一旦、対話モードを終了し、再度、対話モードで実行しなおして
検索を行ってみる。

>>> ShipClass.objects.all()
<QuerySet [<ShipClass: 駆逐艦>]>

中身が見えるようになったので、登録されていたことが確認できた。
all()は全件検索なので、絞り込みをやってみよう。

>>> ship_class = ShipClass.objects.filter(name=u"駆逐艦")
>>> print(ship_class)
<QuerySet [<ShipClass: 駆逐艦>]>

絞り込みはfilter()。
抽出条件をキーワード引数で指定すると、絞り込みを行ってくれる。

ついでに、もう一回登録をやってみる。
今度は、艦船を登録してみる。

>>> ship_class = ShipClass.objects.filter(name=u"駆逐艦")[0]
>>> from warship.models import Warship
>>> warship = Warship()
>>> warship.ship_class = ship_class
>>> warship.name = u"暁"
>>> warship.save()
>>> Warship.objects.all()
<QuerySet [<Warship: 駆逐艦 - 暁>]>

とまぁ、うまくできているようだ。
データベースを触らずにテーブル作って、データ登録までできるって
なんて楽なんだろう。

といったところで、次回へ続く。