Raspberry Pi 覚え書き

小型PC、ラズベリーパイ3を使って遊んだプロセスを記録するページ

Contents

1.Raspberry Pi 3でNAS-ファイルサーバーを作る
2.WindowsPCとファイル共有する
3.Raspberry Pi 3にポータブルSSDをつなぐ
4.Raspberry Pi 3に3.5インチタッチパネルをつなぐ
5.Raspberry Pi 3でAmazon Echoを作る
6.MP3を再生する
7.Python-Pygameを使ってみる
8.WindowsにPython-Pygame開発環境を構築する
9.Python-Pygameで漢字を扱う
10.Tkinterを使ってみる
11.pyaudioを使ってみる
12.TkinterでJPEG画像を表示する
13.Tkinter.Canvasを使ってみる
14.Tkinter.Canvasを使って電卓を作る
15.Orange Pi ZeroをWiFiに接続する
16.Raspberry Pi Zero WHを使う
17.Raspberry Pi 3にローカルWebサーバーを構築する
18.リネームアプリを作る

1.Raspberry Pi 3でNAS-ファイルサーバーを作る

1.1.Raspbain Stretch with Dasktopをインストールする

Windows10-PCを使ってラズベリーパイを設定する手順を解説する。
用意するもの
・SD Formatter 5.0
   https://www.sdcard.org/jp/index.html
SDメモリーカードフォーマッター5.0アソシエーションのページ、ダウンロードのタブの次、SDメモリーカードフォーマッターWindows用のボタンを押す。「同意します」ボタンを押すとインストーラのダウンロード開始。
・Win32 Disk Imager 1.0
   https://ja.osdn.net/projects/sfnet_win32diskimager/
ダウンロードファイル一覧のボタンの先、win32diskimager-1.0.0-install.exeを選んでインストーラをダウンロードする。窓の杜からも入手できる。窓の杜で"Win32 Disk Imager"を検索すれば見つけられるだろう。

以上の2つのフリーソフトをあらかじめWindowPCにインストールしておく。

ラズベリーパイ公式サイト>DOWNLOADS>RASPBIANのページ*から
RASPBIAN STRETCH WITH DESKTOP-"2017-11-29-raspbian-stretch.zip"をダウンロード。
ZIP形式になっているので解凍してイメージファイル"2017-11-29-raspbian-stretch.img"を取り出す。
*https://www.raspberrypi.org/downloads/raspbian/
※このページ執筆時点の最新RASPBIANが"2017-11-29-raspbian-stretch.zip"であった。
※torrent形式かzip形式どちらかを選ぶことができる。torrentユーザーならtorrent経由でダウンロードした方が速い。torrentを持っていない/何のことかわからない人はzip形式をダウンロードすべし。

■MicroSDカードをフォーマットする
PCにMicroSDカードをセットし、SD Formatter 5.0を開く。
"カードの選択"でドライブを間違えないように。"クイックフォーマット"も可能だが、トラブルを未然に防ぎたいのなら"上書きフォーマット"を選択する。"ボリュームラベル"は空欄でもよい。
※MicroSDカードは16GB以上を推奨する。
※MicroSDカードとラズベリーパイには相性がある。詳しくは下記のサイト参照。
*http://elinux.org/RPi_SD_cards

■MicroSDカードにイメージファイルを展開する
Win32 Disk Imager 1.0を開く。
"Image File"は"2017-11-29-raspbian-stretch.img"を選択、"Device"でMicroSDカードが挿入されているドライブを選択したのち、"Write"を押す。

イメージファイルを展開したMicroSDカードをラズベリーパイに挿し、電源を入れる。問題なければ、RASPBIAN STRETCH WITH DESKTOPのデスクトップ画面が表示されるはずである。

■RASPBIAN STRETCH WITH DESKTOPの初期設定をする
メニューバー>Preferences>Raspberry Pi Cofigurationを開く。
"Interfaces"のタブの下、SSHがDisabeleになっているのでEnableをオンにする。以後、リブートのたびにパスワード変更を促す警告メッセージが出る。パスワードを変更するかしないかはご自身の判断で。
→SSHで接続しないのなら、当然Enableにする必要はない。後述するTera TermでラズベリーパイにアクセスするためにはSSHをオンにする必要がある。しかし、SSHをオンにしなくてもWindows標準のリモートデスクトップ接続を使ってアクセスすることができる。
"Lacarization"のタブの下、"Local"の"Language"を"ja(Japanese)"に、"Country"を"JA(Japan)"に、
"Timezone"を"Japan"に、"Keyboard"を"Japanese(PC-98xx Series)"に、
"WiFi Country"を"JP Japan"に設定。
※Timezoneを変更してもすぐに時計はアジャストされない。
※"Local"をデフォルトのままにしておくとメニューが日本語化されない。英語のメニューがお好きならここはそのまま。最低限"Keyboard"だけは"Japanese(PC-98xx Series)"に変えておいたほうがいいと思う。

■WiFiの設定をする
画面右上、メニューバーの中、Bluetoothの右の記号をクリック。
自宅のWiFiのSSIDを選んで"Pre Shared key"にパスワードを入力。
すぐにSSIDが表示されないときは、いったん"Turn off Wi-Fi"を選んだのち、再び"Turn On Wi-Fi"を選ぶと表示が正常化される。

■とりあえずアップデートする
以下の日本語IMEをはじめ、いくつかのアプリをインストールする時は事前にOSをアップデートしておいた方がいい。インストールに失敗しないためのおまじないだ。
左から4つ目のアイコン"LXTerminal"ターミナルを開いて以下を入力。
$ sudo apt update
※apt-getコマンドじゃなくてaptだけでもいいみたい。

■心配ならアップグレードもしてみる
$ sudo apt upgrade

最新のRASPBIAN STRETCH WITH DESKTOPは日本語フォントを内蔵しているので、別途日本語フォントをインストールする必要はない。しかし、日本語入力メソッドをインストールしないと日本語の入力ができない。

■日本語入力メソッドをインストールする
uim uim-mozcは2018-06-27 Raspbianとの相性がよくないようだ。2枚目のターミナルが開かない、Sambaが起動しないなどのトラブルを確認した。
mozcをインストールする。ターミナルを開いて以下を入力。
$ sudo apt install uim uim-mozc
途中、続行しますか?[Y/n]が出たらyを押してEnter。

※"Language"が"en(English)"のままだと日本語入力できない。
再起動後にmozcが有効になる。
ちなみに再起動は
$ reboot
あるいは

$ sudo reboot
※SSHによるリモート接続からリブートを実行するときはsudoから書き始めないといけないようだ。

■ディスプレイ解像度を設定する
私のモニタはHDMI-1920 x 1080(スピーカ付き)だが、デフォルトでは画面いっぱいに表示されず黒い非表示領域が残る。そこでディスプレイ解像度を設定して表示領域をモニタにフィットさせる。
ターミナルを開いて以下を入力。
$ sudo nano /boot/config.txt
長い文字列が表示されるが、ずーっと下まで送って、最後の行に以下のコマンドを追記する。
hdmi_drive=2
hdmi_group=2 # DMT
hdmi_mode=82 # 1080p 60Hz
その後、Ctrl+O(上書き)を押す。Config.txtを上書きするか尋ねてくるのでEnterを押す。
Ctrl+Xを押して完了。
→hdmi_drive=2でスピーカ付きHDMIモニタから音が出るようになる。
→#に続く文字はコメントなので省略可。
→hdmi_mode=82は1920x1080/60Hzディスプレイに対応した設定である。それ以外の解像度の設定については以下のページを参照。
https://www.raspberrypi.org/documentation/configuration/config-txt/video.md
※メニューバー>Preferences>Raspberry Pi Cofiguration>Systemタブの下に"Set Resolution"ボタンがあるが、この中に"DMT mode 82 1920x1080 60Hz 16:9"が見当たらないので、/boot/config.txtを直接編集する。

以上で汎用PCとしての体裁が整った。

1.2.HDDをマウントしてファイルサーバーにする

■ntfs-3gをインストール
NTFS形式のHDDをマウントするためにntfs-3gをインストールする。
ターミナルを開いて以下を入力。
$ sudo apt install ntfs-3g
そしてリブート

■HDDを接続する
今回はSeagate(3TB)HDDを用意した。これをUSBでラズベリーパイに接続する。
ターミナルを開いてdf(disk filesystem)コマンドを入力。
$ df
以下のような文字列が表示される。
ファイルシス       1K-ブロック         使用          使用可 使用% マウント位置
/dev/root            29320680  3822304     23985904  14% /
devtmpfs                469688             0         469688   0% /dev
tmpfs                     474004             0         474004   0% /dev/shm
tmpfs                     474004      12596         461408   3% /run
tmpfs                         5120             4            5116   1% /run/lock
tmpfs                     474004             0          474004  0% /sys/fs/cgroup
/dev/mmcblk0p6       64366      19974           44392 32% /boot
/dev/sda2          930134012    290184    929843828  1% /media/pi/Seagate
tmpfs                       94804            0            94804   0% /run/user/1000

Seagate HDDのデバイスネームとして/dev/sda2が与えられている。
Seagate HDDは臨時に/media/piディレクトリにマウントされている。
以上を確認。※デバイスネームはシステムが勝手に割り当てるもので状況により変わる。
$ df -h
と入力するともう少しわかりやすい単位で表示してくれる。

■新規にディレクトリ(フォルダ)を作る
ターミナルを開いて以下を入力。
$ sudo mkdir /mnt/usbhdd
mkdir(make directory)コマンドでmntフォルダの下にusbhddフォルダを作成した。

■HDDのマウント位置を変える
/media/piにマウントしたままでは以下の設定ができないのでマウント位置を変える。
ターミナルを開いて以下を入力。/dev/sda2をいったんアンマウントする。
$ sudo umount /dev/sda2
次に以下を入力。
$ sudo mount -t auto /dev/sda2 /mnt/usbhdd
これで先ほど作成した/mnt/usbhdd直下にマウントされる。

■ラズベリーパイ起動時に自動マウントされるようにする
上記の設定のままでは再起動すると設定がリセットされてしまう。再起動後も自動マウントされるようシステムファイル/etc/fstabに追記する。
ターミナルを開いて以下を入力。
$ sudo nano /etc/fstab
最後の行(# a swapfile is not swap partition,...の前)に以下を追記。
※長い空白はTabキーを入力。
/dev/sda2     /mnt/usbhdd     ntfs-3g     defaults     0     0
その後、Ctrl+O(上書き)を押す。fstabを上書きするか尋ねてくるのでEnterを押す。
Ctrl+Xを押して完了。
※書く場所を間違えると次回の起動でつまずくので注意。

■Sambaをインストールする
ファイルサーバを作成するためのプログラム、sambaをインストールする。
ターミナルを開いて以下を入力。
$ sudo apt install samba

■Sambaの設定をする。
ターミナルを開いて以下を入力。
$ sudo nano /etc/samba/smb.conf
最後の行に以下を追加
[RaspNAS]
comment = USBHDD
path = /mnt/usbhdd
public = Yes
read only = No
writable = Yes
guest ok = Yes
force user = pi

その後、Ctrl+O(上書き)を押す。smb.confを上書きするか尋ねてくるのでEnterを押す。
Ctrl+Xを押して完了。
※[RaspNAS]はWindowsPCで閲覧する時のサーバー名である。任意の文字を名称として設定して差し支えないが、Sambaが予約している単語は避ける。どのような単語が予約されているかはsmb.confを読めばわかる。
※comment =に続く文字はコメント文である。自分のための覚え書きなので何を書いてもよい。
$ reboot
でリブートするとSambaが起動する。
以上で、ファイルサーバ完成。

1.3.ラズベリーパイのローカルIPアドレスを知る

ターミナルを開いて以下を入力。
 $ ifconfig
以下のような文字列が表示される。
eth0 
Link encap:イーサネット ハードウェアアドレス x0:00:xx:00:00:x0
inet6アドレス: xx00::0x00:0xx0:0000:x0xx/64 範囲:リンク
UP BROADCAST MULTICAST MTU:1500 メトリック:1
RXパケット:0 エラー:0 損失:0 オーバラン:0 フレーム:0
TXパケット:0 エラー:0 損失:0 オーバラン:0 キャリア:0
衝突(Collisions):0 TXキュー長:1000
RXバイト:0 (0.0 B) TXバイト:0 (0.0 B)

lo 
Link encap:ローカルループバック
inetアドレス:127.0.0.1 マスク:255.0.0.0
inet6アドレス: ::1/128 範囲:ホスト
UP LOOPBACK RUNNING MTU:65536 メトリック:1
RXパケット:140 エラー:0 損失:0 オーバラン:0 フレーム:0
TXパケット:140 エラー:0 損失:0 オーバラン:0 キャリア:0
衝突(Collisions):0 TXキュー長:0
RXバイト:11712 (11.4 KiB) TXバイト:11712 (11.4 KiB)

wlan0 
Link encap:イーサネット ハードウェアアドレス x0:00:xx:00:x0:x0
inetアドレス:192.168.0.5 ブロードキャスト:192.168.0.255 マスク:255.255.255.0
inet6アドレス: xx00::xx00:xxxx:xx00:x0x0/64 範囲:リンク
UP BROADCAST RUNNING MULTICAST MTU:1500 メトリック:1
RXパケット:599 エラー:0 損失:490 オーバラン:0 フレーム:0
TXパケット:194 エラー:0 損失:0 オーバラン:0 キャリア:0
衝突(Collisions):0 TXキュー長:1000
RXバイト:94274 (92.0 KiB) TXバイト:30525 (29.8 KiB)

→注目すべきはwlan0の2行目、inetアドレス:192.168.0.5 
これがWiFiのローカルIPアドレスである。
192.168.0.Xとなる数列で、末尾の1桁はルータが勝手に割り当てる。

■ラズベリーパイのローカルIPアドレスを知る別の手段。
私のWiFiルータはバッファロー製である。バッファロー製ルータの付属ユーティリティ"エアステーション設定ツール"の管理画面トップページ、"ネットワークサービス一覧を表示"を押すと、ローカルWiFi接続機器の一覧が表示される。そこからラズベリーパイのIPアドレスを知ることもできる。
■iPhoneユーザーならばFingというiPhoneアプリが利用できる。ローカルWiFiをスキャンし、接続しているデバイスとIPアドレスのリストを表示してくれる。
※iOS11よりMACアドレスが読めなくなったとかでFingが使いにくくなった。新規のデバイス名が不明と表示される。何らかのデバイスがIPアドレスを取得したのはわかるがデバイスの詳細はわからない。
■WindowsならAdvanced IP Scannerというフリーソフトが利用可能だ。窓の杜で入手できる。窓の杜ライブラリ>インターネット・セキュリティ>サーバー・ネットワーク>ネットワーク調査*~に分類されている。*https://forest.watch.impress.co.jp/library/nav/genre/inet/servernt_netanlz.html
ローカルネットワーク内のデバイスを検出してリスト化してくれる。
※このフリーソフトを起動するとユーザーフォルダ内にadvanced_ip_scanner_Aliases.bin他3つのジャンクファイルを勝手に保存するところがちょっとうざい。このジャンクファイルはその都度削除しても大丈夫。

■ルータを再起動するとローカルIPアドレスの割り当てがリセットされる。おそらく末尾1桁の数字が変わる。

■WindowsPCからファイルサーバにアクセスする
WindowsPCでエクスプローラを開き、検索窓に"\\192.168.0.5"を入力する。末尾の1桁は環境により変わる。
ネットワーク資格情報の入力欄
ユーザー名:pi
パスワード:raspberry
でアクセス可能。

上記の方法でアクセスすると以後、PCの電源を落とすまでエクスプローラ>ネットワーク経由でもアクセス可能となる。

1.4.ラズベリーパイをリモート接続する

WindowsPC、ラズベリーパイそれぞれに別々のモニタ、キーボード、マウスを用意できればよいが、通常はリモート接続によってひとつのモニタ、キーボード、マウスを共用することになろう。

■ラズベリーパイにSSHでリモート接続する
WindowsPCにTera Termをインストールする。ラズベリーパイ側はSSHをオンにしておく。
Tera Term
https://ja.osdn.net/projects/ttssh2/

Tera Teamを起動し、"ホスト"にローカルIPアドレス"192.168.0.X"を入力。
ユーザ名:pi
パスフレーズ:raspberry
でOKを押す。
ターミナル画面が開き、コマンド入力待ち状態となる。
SSHで開くことができるのはターミナル画面のみである。しかし、この画面からすべてのことが行えるので問題ない。

■ラズベリーパイにリモートデスクトップ接続する(xrdp)
ラズベリーパイにリモートデスクトップ接続する方法は二つある。ひとつはxrdp経由で行うもの。Windows標準のリモートデスクトップ接続になる。Windowsスタート画面、Windowsアクセサリの中にある"リモートデスクトップ接続"で接続できる。後述するVNCとは同時に利用できない。
ラズベリーパイ側の準備。リモートデスクトップ接続を有効にするために以下のふたつのプログラムをインストールする。ターミナルを開いて以下を入力。
$ sudo apt install tightvncserver
$ sudo apt install xrdp
WindowsPC側でリモートデスクトップ接続を起動。
"コンピュータ(C):"にローカルIPアドレス"192.168.0.X"を入力。
USERNAME:pi
PASSWORD:raspberry
でOKを押す。

■ラズベリーパイにリモートデスクトップ接続する(REALVNC)
ラズベリーパイに標準で組み込まれているリモートデスクトップ接続サービスはREALVNC経由によるものだ。そのクライアントソフトVNC ViewerはWindows、Mac、iOS、Andoroid...様々なホストをサポートしている。VNCを利用するためにはメニューバー>Preferences>Raspberry Pi Cofiguration "Interfaces"のタブの下、VNCをオンにする。リブートするとメニューバーにVNCアイコンが現れる。このVNCアイコンをクリックするとラズベリーパイのローカルIPアドレス"192.168.0.X"が表示される。
■WindowPCにVNC Viewerをインストールする。
VNC Viewerのダウンロードページ*にアクセスしてWindouws用VNC Viewerアプリをダウンロードする。
*https://www.realvnc.com/download/viewer/
ダウンロードしたVNC-Viewer-6.0.2-Windows-64bit.exeを好きなフォルダに置いてダブルクリックする。
空白部分で右クリック""New Connection"を選ぶ。"VNC Server"にローカルIPアドレス"192.168.0.X"を記入。"Name"は”RaspberryPi"とでもしておく。"Continue"を押して、USERNAME:pi、PASSWORD:raspberry、"Remember Password"にチェックを入れておく。OKボタンで接続を始める。
※iOSもサポートしているのでiPhoneにVNC Viewerを入れておけば、iPhone からもリモートデスクトップ接続できる。

2.WindowsPCとファイル共有する

2.1.Sambaを使ってWindowsPCとファイル共有する

■ntfs-3gとSambaをインストールする
前述の通り
$ sudo apt install ntfs-3g
$ sudo apt install samba

■Sambaの設定をする
ターミナルを開いて以下を入力。
$ sudo nano /etc/samba/smb.conf
最後の行に以下を追加
[RaspSHARE]
comment = HomePi
path = home/pi
public = Yes
read only = No
writable = Yes
guest ok = Yes
force user = pi

その後、Ctrl+O(上書き)を押す。smb.confを上書きするか尋ねてくるのでEnterを押す。
Ctrl+Xを押して完了。
※[RaspSHARE]はWindowsPCで閲覧する時のサーバー名である。任意の文字を名称として設定して差し支えないが、Sambaが予約している単語は避ける。どのような単語が予約されているかはsmb.confを読めばわかる。
※comment =に続く文字はコメント文である。自分のための覚え書きなので何を書いてもよい。
※前述のファイルサーバ制作の時path =に続く文はpath = /mnt/usbhddで"mnt"の前に"/"があった。しかし今回、"home"の前に"/"はない。結論から言うとこの"/"はあってもなくてもどっちでもいいらしい。

■Sambaを起動する
ターミナルを開いて以下を入力。
$ sudo service samba-ad-dc restart
または、リブート。

■WindowsPCからRaspberry Piにアクセスする
WindowsPCでエクスプローラを開き、検索窓に"\\192.168.0.X"を入力する。末尾の1桁は環境により変わる。
ネットワーク資格情報の入力欄
ユーザー名:pi
パスワード:raspberry
でアクセス可能。

■ファイルサーバとファイル共有を同時に実行する

[RaspNAS]
comment = USBHDD
path = /mnt/usbhdd
public = Yes
read only = No
writable = Yes
guest ok = Yes
force user = pi

[RaspSHARE]
comment = HomePi
path = home/pi
public = Yes
read only = No
writable = Yes
guest ok = Yes
force user = pi

というように前述のファイルサーバの構文に続けて、ファイル共有の構文を書き足すことができる。この場合、WindowsPCから"\\192.168.0.X"にアクセスすると[RaspNAS][RaspSHARE]ふたつのフォルダが見える。

3.Raspberry Pi 3にポータブルSSDをつなぐ

3.1.ポータブルSSD(USB給電タイプ)をつなぐ

Sandisk製外付けポータブルSSDを入手したのでラズベリーパイにつないでみる。USB経由で給電を受けるタイプである。
■USB給電のアンペア数を上げる
ラズベリーパイ側からの出力電流は0.6Aに制限されているらしいので、これを1.2Aに引き上げる。
ターミナルを開いて以下を入力。
$ sudo nano /boot/config.txt
最後の行に以下を追加
safe_mode_gpio=4
その後、Ctrl+O(上書き)を押す。config.txtを上書きするか尋ねてくるのでEnterを押す。
Ctrl+Xを押して完了。

■exFAT形式のドライバをインストールする
Sandiskの外付けSSDはexFATとかいうフォーマット形式らしい。これもそのままではラズベリーパイで扱えないのでドライバをインストールする。
$ sudo apt-get install exfat-fuse
そして再起動。

ラズベリーパイに外付けSSDをつなぐと臨時に/media/piフォルダの中にマウントされる。マウントポイントを変えたい時は上記「HDDをマウントしてファイルサーバーにする」の項を参照。SSDを外す時は必ずデスクトップ画面右上のイジェクトボタンを押してマウントを解除する。安全に取り外すためのおまじない。

4.Raspberry Pi 3に3.5インチタッチパネルをつなぐ

4.1.機器を接続する

ラズベリーパイのGPIOに3.5インチLCDを挿す。挿す場所は取説などに従う。HDMI接続のLCDの場合、二股のHDMI端子が付属するが、まだLCDドライバを入手していないので、今はこれを使わない。ラズベリーパイのHDMI端子には一般のモニタをつなげておく。

4.2.GitHubからドライバを入手し、インストールする

ここ*に行くと最新のタッチパネルディスプレイドライバが入手できるらしい。
*https://github.com/goodtft/LCD-show
このURLを覚える必要はない。「GitHub LCD-show」くらいのキーワードでググればたどりつける。
このページを見れば丁寧にドライバの入手方法が書いてある。以下はその覚え書き。
ターミナルを開いて以下を入力。
$ sudo rm -rf LCD-show
$ git clone https://github.com/goodtft/LCD-show.git
$ chmod -R 755 LCD-show
$ cd LCD-show
$ sudo ./LCD35-show


1行目は先に古いLCD-showフォルダがあった場合、それを消すコマンド。初めてのイントールならばLCD-showフォルダは存在しないはずなので、1行目は省略可。
2行目でドライバを入手。piフォルダにLCD-showフォルダができているはずだ。
3行目でLCD-showフォルダのアクセス権変更
4行目cd(change directory)コマンドでLCD-showフォルダの中に入る。
5行目でシェルスクリプトLCD35-showの実行、自動的に再起動して、3.5インチLCDにデスクトップが表示される。もしあなたのLCDが3.5インチでなく5インチだったら、5行目はsudo ./LCD5-showとなる。詳しくは上記URLを参考にしていただきたい。

■一般のHDMIモニタに戻したい時
ターミナルを開いて以下を入力。
$ cd LCD-show
$ ./LCD-hdmi

■再び3.5インチLCDに戻したい時
ターミナルを開いて以下を入力。
$ cd LCD-show
$ ./LCD35-show

ラズベリーパイゼロWHにElecrowの3.5インチタッチパネルを挿して、GitHubのドライバをインストールしたところ、タッチ動作のX軸とY軸が入れ替わる不具合が生じた。(指を横に動かすとポインタは縦に動く現象)
そこで下記、3.ドライバを直接ダウンロードし、インストールする方法を試したところ不具合は解消した。

4.3.ドライバを直接ダウンロードし、インストールする方法

GitHubから入手した方が楽である。以下の方法はお勧めしない。
■waveshare.com-LCDの記事*にアクセス
*http://www.waveshare.com/wiki/3.5inch_RPi_LCD_(A)
文中のリンクからLCD-show-170703.tar.gzファイルをダウンロードする。リンクをクリックするとダウンロードを開始する。

ダウンロードしたファイルは/home/pi/Downloadsフォルダに保存されているはずである。このフォルダから出して/home/piフォルダに移動する。WindowsPCと同様、右クリックで「切り取り」→「コピー」でファイルを移動できる。
※上記リンクにはLCDパネル設定手順が英文で書いてある。以下はその覚え書き。
※3.5inch_RPi_LCD_(A)と3.5inch_RPi_LCD_(B)がある。(B)を使うと表示がネガポジ反転する。

■初期設定
ターミナルを開いて以下を入力。
$ sudo raspi-config
初期設定画面が開く。
下↓カーソルキーを2回叩いて"3 Boot Options"をハイライトさせてEnter。
"B1 Desktop/CLI"をハイライトさせてEnter。
下↓カーソルキー3回たたいて"B4 Desktop Autologin"をハイライトさせてEnter。
Tabキー2回叩いて"Finish"をハイライトさせてEnter。
"Yes"をハイライトさせてEnter。自動でリブートする。

■tarファイルを解凍(tarファイルはzipのようなもので複数のフォルダ/ファイルをまとめて圧縮している)
ターミナルを開いて以下を入力。
$ tar xvf LCD*.tar.gz
/home/piフォルダの中にLCD-showフォルダが現れる。
※LCD-show-170703.tar.gzをダブルクリック、LCD-showフォルダが見えるのでこれを1回クリックで選択、アクションメニューから[展開]、次に開くダイアログボックスの設定は変えずにそのまま[展開]ボタンを押しても結果は同じ。ターミナルからコマンドを打ちたくない人はこちらの手順で。

■3.5インチタッチパネルディスプレイ用ドライバを起動
ターミナルを開いて以下を入力。
$ cd LCD-show
$ ./LCD35-show

■HDMIに戻したい時
ターミナルを開いて以下を入力。
$ cd LCD-show
$ ./LCD-hdmi

5.Raspberry Pi 3でAmazon Echoを作る

5.1.準備

Amazon EchoはAlexa(アレクサ)と呼びかけると反応する音声コントロールによる人工知能である。開発者向けのボイスサービスサンプルプログラムを使うことで、ラズベリーパイからも利用できる。

まずはラズベリーパイを使用可能な状態にするための最低限の下ごしらえをしておく。
■SDカードをフォーマットし、Rasipbian Jessie with Pixelを書き込む。
■キーボード、マウス、モニタを接続、そしてSDカードをラズベリーパイに挿し、起動する。
■WiFiを使えるようにしておく。
■"Locarization"の設定をしておく。
■OSをアップデートする。心配ならアップグレードもしておく。
■SSH経由でリモート接続するつもりなら、SSHをオンにしておく。
■WindowsPCからリモートデスクトップ接続するつもりならtightvncserverとxrdpもインストールしておく。

以上、詳細は前項に記載済みなのでそちらを参照。
さらに今回はUSBマイクと3.5mmイヤホンジャック入力のスピーカーも接続する。AlexaはUSBスピーカーに対応していない。
※HDMIモニタを接続していると音声出力が自動的にHDMIにセットされる。強制的に3.5mmイヤホンジャックに出力させるには
$ sudo raspi-config
7 Advance Optionsを>A4 Audio>1 Force 3.5mm ('headphone')jackをハイライトさせてTabキー<Ok>を選んでenter。Tabキー2回押して<Finish>選んでenter。

なお、ラズベリーパイでAlexaを利用する手順を詳細に説明するウェブページ*が既にある。私の説明はここに書かれていることとほぼ同じ内容である。
*https://github.com/alexa/alexa-avs-sample-app/wiki/Raspberry-Pi

5.2.Amazon Developerアカウントの登録

開発者向けのウェブサービス、Amazon Developerアカウントを取得し、ラズベリーパイで利用可能なセキュリティIDを発行してもらう。
まずはAmazon Developer Serviceのウェブページ*にアクセスする。
*https://developer.amazon.com/

言語設定から"Japanese(日本語)"も選べるが"English"のままにしておく。"Japanese(日本語)"を選択するとAlexaに関するリンクが非表示になってしまう。
上段のメニュー、Alexa>Alexa Voice Srevice>Stert Buildindのリンクをたどる。
Getting Started with the Alexa Voice Serviceのページ、"Sign up for a free Amazon developer account"のリンク*をクリック。
*https://developer.amazon.com/home.html

Sign Inのページ
■E-mail or mobile numberの欄にEメールアドレス
■初回登録時は◎I am a new costomer.に丸をつけて次へ
1.Profile Infomation-個人情報を偽りなく記入。日本の国番号は+81。
2.App Distribution Agreement-合意して次へ
3.Payments-開発したアプリで金儲けする意思があるか聞いている。両方とも◎No
※次回以降はパスワードを入力して// DEVELOPER CONSOLEポータルサイトにリンクする。

登録が完了すると// DEVELOPER CONSOLE(開発者のためのポータルサイト)にアクセスできるようになる。ここで上段ALEXA>Alexa Voice Service>Get Startedのリンクをだどる
[Register a Product Type]のメニューで"Device"を選択。

Create a new Device Typeのページ
Device Type Info
Company Nameのところにあなたの登録した名前が入っている。
Device Type IDは"my_device"とすること。他の名前では先へ進めない。
Display Nameは"My Device"
次へ

[Security Profile]ドロップダウンリストから"Create a new profile" を選択。
[General]タブ
Security Profile Nameに"Alexa Voice Service Sample App Security Profile"と記入。
Security Profile Descriptionに"Alexa Voice Service Sample App Security Profile Description"と記入。
次へ

・Security Profile ID
・Client ID
・Client Secret
が発行される。このうちClient IDとClient Secretは後々使用するのでコピーしておく。

次に、[Web Settings]タブをクリック。
[Alexa Voice Service Sample App Security Profile]のドロップダウンリストはそのまま
[Edit]をクリック。
Allowed Origins [Add Another]クリック、ブランクに"https://localhost:3000"と記入。
Allowed Return URLs[Add Another]クリック、ブランクに"https://localhost:3000/authresponse"と記入。
次へ

Devise Details
横142x縦130pixels以内のJPEG画像を登録できる。画像はリストに表示される。画像はあってもなくてもよい。
[Category]ドロップダウンリストから"Other" を選択。
Descriptionに"Alexa Voice Service sample app test"と記入。
Do you have plans to make your product available to the general public? ◎Noを選択。
次へ

Amazon Music
Apply for access to Amazon Music?◎Noを選択。
[Submit]をクリック。

Security Profileを有効にする
ここへ行く
https://developer.amazon.com/lwa/sp/overview.html

[Select a Security Profile] ドロップダウンリストから"Alexa Voice Service Sample App Security Profile" を選択。
[Confirm]をクリック。

Consent Privacy Notice URLに"http://example.com"と記入。
[Save]をクリック。

"Show Client ID and Client Secret"のリンクをクリック。
Client ID と Client Secretが表示されていることを確認する。

なお、セキュリティプロファイルを作成する手順を詳細に説明するウェブページ*が既にある。私の説明はここに書かれていることとほぼ同じ内容である。
*https://github.com/alexa/alexa-avs-sample-app/wiki/Create-Security-Profile

5.3.ラズベリーパイのセットアップ

■alexa-avs-sample-appをコピーする
ターミナルを開いて以下を入力。
$ cd Desktop
$ git clone https://github.com/alexa/alexa-avs-sample-app.git
デスクトップに"alexa-avs-sample-app"という名のフォルダが作成されている。このフォルダを開いて内容を確認する。Rasipbian Jessieのファイルマネージャーがファイルの存在に気づいていないことがあるので、フォルダを開いて確かにファイルがあることを確認する。

■alexa-avs-sample-appのインストールスクリプトを編集する
ターミナルを開いて以下を入力。
$ cd ~/Desktop/alexa-avs-sample-app
$ sudo nano automated_install.sh

ProductID=my_device
ClientID=amzn.xxxxx.xxxxxxxxx
ClientSecret=4e8cb14xxxxxxxxxxxxxxxxxxxxxxxxxxxxx6b4f9

Amazonから発行されたClientIDとClientSecretをそれぞれ記入する。
その後、Ctrl+O(上書き)を押す。automated_install.shを上書きするか尋ねてくるのでEnterを押す。
Ctrl+Xを押して完了。

■インストールスクリプトを実行する
ターミナルを開いて以下を入力。
$ cd ~/Desktop/alexa-avs-sample-app
$ . automated_install.sh
これでAlexaインストール完了。

5.4.Alexaの起動

3つのターミナルウィンドウを別々に開いて3つのコマンドを実行する。
■ターミナル1
以下を入力。
$ cd ~/Desktop/alexa-avs-sample-app/samples
$ cd companionService && npm start

■ターミナル2
以下を入力。
$ cd ~/Desktop/alexa-avs-sample-app/samples
$ cd javaclient && mvn exec:exec
Webブラウザを起動する旨の警告と[Yes/No]のボタンが出るので[Yes]をクリック。直後に[OK]ボタンが出るがすぐにこれを押してはいけない。
Webブラウザが起動し、Amazon Developer Serviceにログインする。
JessieではここでしばしばHTTPS警告「この接続ではプライバシーが保護されません」が出ることが確認されている。左下[詳細設定]ボタンを押してこれを回避する。
認証が通ると"device tokens ready"と表示される。ここで先ほどの[OK]ボタンを押す。
[Listen]ボタンが表示される。このボタンを押してAlexaを呼び出すことができる。

■ターミナル3
以下を入力。
$ cd ~/Desktop/alexa-avs-sample-app/samples
$ cd wakeWordAgent/src && ./wakeWordAgent -e sensory
これでWake Wordが使えるようになる。[Listen]ボタンを押さなくても"Alexa"と呼びかけるだけでポン♪という音とともにAlexaを呼び出すことができる。
"Good morning."と呼びかけてみよう。

6.MP3を再生する

6.1.VLCをインストールする

定番のメディアプレイヤー"VLC Media Player"をインストールする。
$ sudo apt-get install vlc
メニューバー、ラズベリーのプルダウンメニューに"Sound & Video"カテゴリが作られる。その中に"VLC Media Player"がある。
"VLC Media Player"を選んで起動する。初期画面はオレンジのパイロン。Media>Open File...のウィンドウから聴きたいmp3ファイルを選ぶ。
※デフォルトのRaspbianにmp3ファイルは存在しない。前述のファイル共有機能等を使ってあらかじめ他所からコピーしておく必要がある。/home/pi/Musicフォルダにでも置いておけばよいだろう。
※/home/pi/python_gameフォルダの中にいくつかのビープ音が収録されている。何でもいいから音を出したい時に便利。音符の形のアイコンなのですぐに見つけられるだろう。

6.2.Bluetoothスピーカーを接続する

音楽をBluetouthスピーカーから流してみる。Bluetouthスピーカーの電源を入れ、どこかのボタン(スピーカーの仕様によるので取説参照)を長押ししてペアリングモードにする。
ラズベリーパイのBluetouthアイコンをクリック。Add Device...のウィンドウからBluetouthデバイス名を選んで"Pair"を押す。
Bluetouthアイコンの2つ右、スピーカアイコンを右クリック。Bluetouthデバイス名を選んでチェックを入れる。これでBluetoothスピーカーから音が出るようになる。
※Bluetoothスピーカーは安定しない。時折音飛び、音切れが発生する。
※ブラウザでYouTubeを開いてミュージックビデオ等を再生しようとするとハングアップする。正直Bluetoothスピーカーは使い物にならない。

6.3.USBスピーカーを接続する

スピーカアイコンを右クリック。Audio Advantage MicroIIを選ぶ。Analogを選べば3.5mmイヤホンジャックから、HDMIを選べばHDMIモニタから、Bluetoothスピーカーを選べばBluetoothスピーカーから、Audio Advantage MicroIIを選べばUSBスピーカーから音が出る仕組み。

7.Python-Pygameを使ってみる

7.1.Pygameについて

Pygameはラズベリーパイにあらかじめインストールされているプログラム言語Pythonのためのモジュールである。ラズベリーのメニューの下、Gameの中にPython Gamesがあり、たくさんのゲームが収録されている。こんな立派なゲームを作ることはできないが、簡単なプログラムなら書けそうなので挑戦してみた。

7.2.Pygameを使ってMP3を再生する

Pythonでmp3を再生するスクリプトを書き、実行する。
まず、/home/piフォルダの中に再生したいmp3ファイルを置いておく。
ターミナルを開いて以下を入力。
$ nano musicplay.py
白紙の画面が表示されるので、下記のスクリプトを記述。
# -*- coding:utf-8 -*-

import pygame.mixer
import time

# mixerモジュールの初期化
pygame.mixer.init()
# 音楽ファイルの読み込み
pygame.mixer.music.load("ファイル名.mp3")
# 音楽再生、および再生回数の設定(-1はループ再生)
pygame.mixer.music.play(-1)
# 60秒間だけ再生
time.sleep(60)
# 再生の終了
pygame.mixer.music.stop()

その後、Ctrl+O(上書き)を押す。musicplay.pyを上書きするか尋ねてくるのでEnterを押す。
Ctrl+Xを押して完了。
/home/piにmusicplay.pyファイルが作成されている。その隣にmp3ファイルが置かれている。
※上記スクリプトの"ファイル名.mp3"の部分には隣に置いてあるmp3ファイル名を書いておく。

ターミナルを開いて以下を入力。
$ python musicplay.py
指定した"ファイル名.mp3"が60秒間だけ再生される。
musicplayというファイル名は私が勝手につけたファイル名である。もちろんこの名前は好き勝手に変更していただいてかまわない。

7.3.Pygameを使ってデジタル時計を作る

Pythonでデジタル時計を表示するスクリプトを書き、実行する。
ターミナルを開いて以下を入力。
$ nano clock.py
白紙の画面が表示されるので、下記のスクリプトを記述。
# -*- coding:utf-8 -*-

import pygame
from pygame.locals import *
import datetime
import sys

# Pygameの初期化
pygame.init()
# 大きさ300*200の画面を生成
screen = pygame.display.set_mode((300, 200))
# タイトルバーに表示する文字
pygame.display.set_caption("clock")
# フォントの設定(25px)
font = pygame.font.Font(None, 25)

# ループを作る
while True:
    # 画面を黒色に塗りつぶし
    screen.fill((0,0,0))
    # 変数clocktimeを定義、現在の年月日時分秒を代入
    clocktime = datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S')
    # アンチエイリアスあり、文字色を白に設定
    text = font.render(clocktime, True, (255,255,255))
    # 文字列の表示位置x方向:75ドット、y方向:85ドット
    screen.blit(text, [75, 85])
    # 画面を更新
    pygame.display.update()

    # イベント待ち受け
    for event in pygame.event.get():
        # 閉じるボタンが押されたら終了
        if event.type is pygame.QUIT:
            # Pygameの終了(画面閉じられる)
            pygame.quit()
            sys.exit()


その後、Ctrl+O(上書き)を押す。clock.pyを上書きするか尋ねてくるのでEnterを押す。
Ctrl+Xを押して完了。
/home/piにclock.pyファイルが作成されている。

ターミナルを開いて以下を入力。
$ python clock.py
デジタル時計が表示される。
もう一度言うがclockというファイル名は私が勝手につけたファイル名である。好き勝手に変更してかまわない。

■Pythonの決まり事
screen =
font =
clocktime =
text =
=(イコール)の前にある文字列はたいてい変数である。変数ということはユーザーが勝手に定義した仮名称のようなもので、これまた勝手に別の文字に置き換えられる。もちろん置き換えたら置き換えたで、その後の行でその変数を引用している箇所が必ずあるので、そこもいっしょに置き換えなければならない。
そうはいっても"font ="や"text ="を別の文字に置き換えたところでわかりづらくなるだけだ。"screen ="もまた慣例的にみんなが使っている変数名にすぎない。人によっては"display ="とか別の言い方に変えているのを見かける。

7.4.python_gamesフォルダについて

/home/piフォルダの中にpython_gamesフォルダがある。この中にはpygameで作られたゲームがスクリプトのまま収められている。例えばpython_gamesフォルダの中のflippy.py(オセロゲーム)をダブルクリックで開くとそのスクリプトを読むことができる。そしてこれを実行して実際にゲームをプレイすることができる。
ゲームをプレイするためにはまずカレントディレクトリをpython_gamesフォルダに移す。

ターミナルを開いて以下を入力。
$ cd python_games
続けてflippy.pyを実行。
$ python flippy.py
これでオセロゲームの盤面が開く。

8.WindowsにPython-Pygame開発環境を構築する

8.1.WindowsにPythonをインストールする

■Pythonの入手
Python.orgのDownloadページ*に行って最新Pythonを入手する。
*https://www.python.org/downloads/
本稿執筆時点の最新バージョンはPython3.6.4であった。"Download Python 3.6.4"のボタンを押すとすぐに32ビット用Python3.6.4実行形式のインストーラがダウンロードされる。これを使ってインストールしてかまわない。"Downloads">"Windows"のタブをたどるとインストーラにも複数の種類があることを知る。
Windows x86-64 xxxxxは64ビット用、Windows x86 xxxxxは32ビット用。私のPCはWindows10の64ビットだが、ここはあえて動作の安定している32ビット用を選ぶ。もちろんここで64ビット用を選んでもかまわない。さらにweb-based、embeddable zip fileなど様々な形態が用意されているが、ここは実行形式:Windows x86 executable installerを選ぶべきである。様々な処理を自動で行ってくれるので楽である。
■Pythonのインストール
Python3.6.4インストーラをダブルクリックして起動。途中□Add Python 3.6 to PATHのチェックボックスが表示されるので、チェックを入れて続行。「環境変数の編集」とか「パスを通す」とか意味不明の手続きを自動で行ってくれる。最後、Disable path length limitの記述のところがボタンになっているのでこれを押し、ファイル名に関する制限項目を解除して完了。
なお、Python-32bit-3.6.4の本体は隠しフォルダの中にインストールされる。
■IDELを試す
IDELはPythonに付属するエディタである。IDELはWindowsメニュー>"最近追加されたもの"の中に入っているはずである。これを起動すると確かにPython3.6.4の記述がある。プロンプトに続けて
print ("Hello World")
と入力。Enterを押してHello Worldが返ってくればインストール成功だ。
FileメニューからNew Fileを選択すると新規pyファイルを作ることができる。そのまま保存すると例の隠しフォルダの中に保存してしまうので、保存先は変えた方がいいだろう。

8.2.WindowsにPygameをインストールする

ラズベリーパイなら最初から入っているが、Windowsの場合、Pygameも自力でインストールしなければならない。
■Pygameの入手
Pygame.orgのページ*に行って最新Pygameを入手する。
*https://www.pygame.org/
ページの中ほどにpygame 1.9.3 released — 16 Jan, 2017の記事がある。Downloads: PyPIのリンクをたどるとインストーラの一覧が表示される。これまたたくさんの種類がある。Windwows用Python-32bit-3.6.1に適合したPygameはpygame-1.9.3-cp36-cp36m-win32.whl (md5)なので、このリンクをクリックしてpygame-1.9.3-cp36-cp36m-win32.whlをダウンロードする。これはwheel形式といって残念ながら実行形式ではない。
Windows用Python拡張パッケージまとめサイト*もある。
*https://www.lfd.uci.edu/~gohlke/pythonlibs/
ここでもpygame-1.9.3-cp36-cp36m-win32.whlを見つけられるだろう。
■Pygameのインストール
pygame-1.9.3-cp36-cp36m-win32.whlファイルをC:\Users\自分の名前のフォルダに置く。エクスプローラーでたどるなら > PC > Windows(C:) > ユーザー > 自分の名前のフォルダの中だ。
よそのチュートリアルでは、この時環境変数にパスが通っているか確認せよと忠告するところもあるがその必要はない。パスは自動で通っているはずだ。
次にスタートメニューを右クリック、Windows PowerShellを起動。管理者でない方を選ぶ。かつてコマンドプロンプトと呼ばれたシェルプログラムはいつの間にかこんな名前に変わっていた。旧コマンドプロンプトもスタートメニューの中をさがせばある。
C:\Users\自分の名前>のプロンプトが表示されているはずである。pygame-1.9.3-cp36-cp36m-win32.whlファイルが別の場所にあるならここからcd(Change Directory)コマンドで.whlファイルが置いてある場所に移動することもできる。
プロンプト(>)に続けて以下を入力。
pip install pygame-1.9.3-cp36-cp36m-win32.whl
これでインストール完了。
■Pygameを用いたプログラムを実行する
前述のclock.pyをC:\Users\自分の名前のフォルダに置く。あるいはIDELで新規pyファイルを作り、前述のスクリプトをコピーし、clock.pyのファイル名でC:\Users\自分の名前のフォルダに保存してもよい。このスクリプトをWindows PowerShellまたはコマンドプロンプトから呼び出して実行する。
スタートメニューを右クリック、Windows PowerShell(管理者でない方)を起動。プロンプトに続けて以下を入力。
python clock.py
これでclock.pyの画面が開く。
■ダブルクリックでpyファイルを実行する
clock.pyファイルをダブルクリックするとそのまま実行する。これは便利。ただし、シェルプログラムの黒い画面が後ろで同時に開いてしまう。これが残念だなと思う方はclock.pywというように拡張子を.pywに変えるとよい。黒い画面を開かなくなる。

8.3.PythonスクリプトをWindows実行形式(.exeファイル)にする

PythonスクリプトをWindows PowerShellから実行できるが、このままではPython-PygameがインストールされたPCでしかプログラムを動かせない。EXEファイルすなわち1個のアプリケーションとして配布でき誰でも実行できるプログラムとしたい。その方法を紹介する。
■cx_Freezeの入手
Pythonスクリプトを実行形式にするアプリはいくつかあるがここではcx_Freezeを使う。
Anthony Tuiningaさんのページ*に行って最新のcx_Freezeを入手する。
*https://github.com/anthony-tuininga
download directly from PyPIのリンクが見つかるだろうか。ここからpython.orgのcx_Freeze保存場所にたどり着くことができる。cx_Freeze-5.1.1-cp36-cp36m-win32.whl (md5)のリンクをクリックしてcx_Freeze-5.1.1-cp36-cp36m-win32.whlをダウンロードする。これはWindwows用Python-32bit-3.6.Xに適合したバージョンとなる。
Windows用Python拡張パッケージまとめサイト*もある。
*https://www.lfd.uci.edu/~gohlke/pythonlibs/
ここでもcx_Freeze-5.1.1-cp36-cp36m-win32.whlを見つけられるだろう。
■cx_Freezeのインストール
cx_Freeze-5.1.1-cp36-cp36m-win32.whlファイルをC:\Users\自分の名前のフォルダに置く。
次にWindows PowerShellを起動。プロンプトに続けて以下を入力。
pip install cx_Freeze-5.1.1-cp36-cp36m-win32.whl
これでインストール完了。
■cx_Freezeの使い方
まずsetup.pyというファイル名のpyファイルを作成、cx_Freezeはこのファイルの中でモジュールとして呼ばれる。さらにこの中にビルドすなわち実行形式に変換するための手順を記述。このpyファイルにbuildという引数を与えて実行すると、exeファイルが組み立てられる仕組み。わかりにくい。
さきほどのclock.pyを例にとって説明する。最終的にclock.pyがclock.exeという名の時計アプリに変換(コンパイル)される。
■setup.pyの記述
IDELで新規pyファイルを作成し、以下を記述。
# coding: utf-8

import sys
from cx_Freeze import setup, Executable

includes = ["pygame", "datetime"]

base = None

if sys.platform == "win32":
   base = "Win32GUI"

exe = Executable(script = 'clock.py', base = base)

setup(name = 'sample',
   version = '0.1',
   description = 'converter',
   executables = [exe])

以上。
4行目includes = ["", "", "", "" ....]で呼び出されるのはclocl.pyに使用したモジュール。clock.pyはPygameとDatetime、sysの3つのモジュールを使用している。使用したモジュールはすべてここに書き出す。ただしsysモジュールとかosモジュールとかは記述不要。
8行目exe = Executable(script = 'clock.py',の行で変換したいpyファイルを記述。
10行目setup(name = 'sample',で名前がsampleのままでいいのか不安になるが、これはこのままでも影響ない。
なお、このsetup.pyの記述はGUIを含むアプリ用である。例えばprint("Hello World")のようなGUIのないアプリの場合、また記述の仕方が少し異なってくるらしい。
■setup.pyの実行
setup.py、clock.pyともにC:\Users\自分の名前のフォルダに置いておく。
次にWindows PowerShellを起動。プロンプトに続けて以下を入力。
python setup.py build
成功すればbuildフォルダができあがる。中にclock.exeと大量の参照ファイルが入っている。この参照ファイルが20MBもある。import pygameというようにざっくりpygameをimportするとpygameのフル機能に対応する参照ファイルが呼び出されるみたいである。
■.exeファイルの配布
大量の参照ファイルを含むbuildフォルダとなってしまったが、clock.exeだけを取り出してダブルクリックしても起動しない。参照ファイルといっしょに配布しなければならない。(全部必要ではないと思うが)これで、pythonを持っていない友人に自作のアプリケーションソフトとして配布することが可能になるが、ひとつ問題点がある。
自作の.exeファイルは他人のPCの下では発行元不明の怪しい実行ファイルとみなされWindowsのセキュリティ機能SmartScreenが発動する。起動しようとすると実行が阻止され「WindowsによってPCが保護されました」画面が表示される。もちろんこれを無視して実行することは可能だが、心臓に悪い。
これを回避するためには専門の機関に連絡して健全な発行元であることを証明するデジタル署名を発行してもらわなければならない。その話はまたPythonとはずいぶん離れた話なので割愛する。

8.4.アイコンを追加する

上記の手順で.exeファイルを作成できるが、完成した.exeファイルにアイコンがない。アイコンを追加する手続きを紹介する。
■PNGファイルを作る
32x32pixelのPNGファイルを作成する。Windows標準-大アイコンは128x128pixelだが、Python で扱えるのは32x32pixelのみである。
■icoファイルに変換する
PNGファイルをicoファイルに変換してくれるWebサービスがいくつかある。ここではアイコンコンバータ*を紹介する。
*http://app.tree-web.net/icon_converter/
JEPG/PNG/GIFファイルをico形式に変換してくれる。ここではとりあえずicon.icoというファイル名で保存し、clock.pyと同じフォルダに置いておく。
■setup.pyの記述
setup.pyを以下のように記述する。icon='icon.ico'が追記されている。
# coding: utf-8

import sys
from cx_Freeze import setup, Executable

includes = ["pygame", "datetime"]

base = None

if sys.platform == "win32":
   base = "Win32GUI"

exe = Executable(script = 'clock.py', base = base, icon='icon.ico')

setup(name = 'sample',
   version = '0.1',
   description = 'converter',
   executables = [exe])

以上。
これでpython setup.py buildを実行すればclock.exeにアイコンが付与される。

9.Python-Pygameで漢字を扱う

9.1.Raspbianで使える日本語フォントを調べる

Pythonで漢字を扱う練習のため、漢字を表示する簡単なアプリを制作してみようと思う。漢字を扱う上で気を付けなければいけないことは以下の2つ。
・日本語のフォントを使用する
・日本語の前にはuの字をつけてunicodeであることを宣言する(Raspbianの場合)

そこでRaspbianにプレインストールされている日本語フォントにどんなものがあるか調べてみる。
ターミナルを開いて以下を入力。
$ python
Pythonが起動し、対話モードになる。プロンプトに続けて以下を入力。
import pygame
pygame.font.get_fonts()
インストール済み使用可能なフォントの一覧を表示する。今回はdroidsansjapaneseを使ってみる。Andoroid端末用日本語フォントらしい。

9.2.新規フォントのインストール

好きなフォントをインストールすることもできる。
メニューバー>Preferences>Add/Remove Softwareを開く。Fontの項目をクリックするとインストール済み/未インストールフォントの一覧を表示する。ここから梅フォント、東風フォントといった有名フリーフォントを追加できる。
もちろんapt-get install...と手入力で好きなフォントパッケージをインストールすることもできる。

9.3.くじびきアプリを作る

漢字利用の例としてくじびきアプリを作ってみる。起動後、画面をクリックするとルーレットがスタートし、1都9県の県名がループする。もう一度クリックすると停止するというシンプルなアプリ。会社などで会議の書記担当をくじ引きで決めるケースもあるだろうと思う。県名のところを人名に書き換えれば、人名ルーレットができあがる。ループの項目の数は増減しても問題ない。
なお、Pythonを覚え始めて半年の初心者が作るプログラムである。プログラムとして不備不適当な箇所があることは承知の上である。とはいえこのレベルのプログラムなら初心者でもサッと書けるところがPythonの魅力だ。

新規.pyファイルを作って以下を入力。(コメントごとコピペしても多分大丈夫。)
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import pygame
from pygame.locals import *
import time
import sys
# Pygameの初期化
pygame.init()
# 大きさ300*200の画面を生成
screen = pygame.display.set_mode((300,200))
# タイトルバーに表示する文字
pygame.display.set_caption('くじびき')
# loopリストを定義、日本語の前にはuをつけてunicodeであることを宣言
loop=[u'茨城',u'栃木',u'群馬',u'埼玉',u'千葉',u'東京',u'神奈川',u'山梨',u'長野',u'新潟']

# 関数main()を定義
def main():
    # 変数nに初期値0を代入
    n = 0
    # 変数xに初期値-1を代入
    x = -1
    # while構文の開始、PygameGUIは必ずwhile構文の形をとる
    while True:
        # 画面色にR,G,B=255,255,255(白)を設定
        screen.fill((255,255,255))
        # fontの定義、プレインストールの日本語フォントdroidsansfallbackを設定、大きさは50pix
        font = pygame.font.SysFont('droidsansfallback',50)
        # loopリストの[n]番目を呼び出してtextオブジェクトを生成、文字色はR,G,B=0,0,0(黒)
        text = font.render(loop[n], True, (0,0,0))
        # text.get_rect()でtextを内包する矩形を取得、変数textrectに代入
        textrect = text.get_rect()
        # textrect(textを内包する矩形)を画面中央にセンタリング
        textrect.center = (300/2),(200/2)
        # 以上はtextの定義、blit()を実行してtextを画面に配置、そして描画
        screen.blit(text, textrect)
        # for構文の開始、イベント待ち受け
        for event in pygame.event.get():
            # 閉じるボタンが押されたら終了、今回はQキー押下でも終了
            if event.type == pygame.QUIT or (event.type == KEYDOWN and event.key == K_q):
                # Pygameの終了
                pygame.quit()
                sys.exit()
            # もしマウスボタンが押されたら変数x(初期値:-1)に-1を乗じる
            if event.type == pygame.MOUSEBUTTONDOWN:
                # 変数xに-1を乗じるたびxの値は+1⇔-1と入れ替わる、これをトグルボタンに利用する
                x = x*-1
        # もしxが+1すなわちx>0の時
        if x>0:
            # nに1を足してインクリメント、loopリストの[n]番目の値が繰り上がる
            n = n+1
            # len(loop)でloopリストの個数を数える、今回の例ではlen(loop)=10になる
            if n >= len(loop):
                # nの値が10に達したら次の値は11でなく0にする、これでループがぐるぐる回る
                n = 0
        # 途中でマウスボタンが押されるとxの値は-1すなわちx<0になる
        if x<0:
            # インクリメントを停止する、ルーレットが止まる
            n = n
        # 画面の再描画、while構文で始めてpygame.display.update()で結ぶのがPygameGUIの基本
        pygame.display.update()
        # ルーレットの速度の調整、毎秒20歯に設定
        pygame.time.Clock().tick(20)

# ここまでの行は関数main()の定義、最後の行で関数main()を実行
main()

以上。

9.4.Windowsにくじびきアプリを移植する

移植というのは大げさだが、このプログラムをWindows用アプリとしてコンパイルすることは簡単だ。ただしWindowsにはdroidsansjapaneseフォントがないのでフォントだけ差し替えなければならない。
そこでWindowsにインストールされている日本語フォントにどんなものがあるか調べてみる。
Windows PowerShellを開いて以下を入力。
python
Pythonが起動し、対話モードになる。プロンプトに続けて以下を入力。
import pygame
pygame.font.get_fonts()
インストール済み使用可能なフォントの一覧を表示する。今回はmeiryomeiryomeiryouimeiryouiitalicを使うことにする。いわゆるメイリオフォントだ。
上記スクリプトの17行目
font = pygame.font.SysFont('droidsansjapanese',50)
これを以下の文章に差し替える。
font = pygame.font.SysFont('meiryomeiryomeiryouimeiryouiitalic',50)
これでWindows上でも漢字で表示される。なお、漢字の前に追記していたuの字はWindows環境の場合、あってもなくてもどっちでもいい。
一応、差し替え後のスクリプト全文を掲載する。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import pygame
from pygame.locals import *
import time
import sys
pygame.init()
screen = pygame.display.set_mode((300,200))
pygame.display.set_caption('くじびき')
clock = pygame.time.Clock()
loop=['茨城','栃木','群馬','埼玉','千葉','東京','神奈川','山梨','長野','新潟']

def main():
    n = 0
    x = -1
    while True:
        screen.fill((255,255,255))
        font = pygame.font.SysFont('meiryomeiryomeiryouimeiryouiitalic',50)
        text = font.render(loop[n], True, (0,0,0))
        textrect = text.get_rect()
        textrect.center = (300/2),(200/2)
        screen.blit(text, textrect)
        for event in pygame.event.get():
            if event.type == pygame.QUIT or (event.type == KEYDOWN and event.key == K_q):
                pygame.quit()
                sys.exit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                x = x*-1
        if x>0:
            n = n+1
            if n >= len(loop):
                n = 0
        if x<0:
            n = n
        pygame.display.update()
        clock.tick(20)

main()

以上。
前述の手続きに従ってビルドすればWindows用.exeファイルに変換される。

9.5.外部ファイルにリストを置く

上記のプログラムだと、人名/県名を入れ替えるたびにスクリプトから書き直さなければならない。たいしたプログラムではないが、外部のテキストファイルにリストを記述し、それを利用するパターンで書き直してみた。
まず「名前リスト.txt」というテキストファイルを用意し、
茨城,栃木,群馬,埼玉,千葉,東京,神奈川,山梨,長野,新潟
というようにカンマ区切りでルーレットの項目を記述する。
その上でスクリプトを以下のように修正。Windowsは2バイト文字に対する制限がゆるゆるなのでファイル名にも普通に漢字ひらがなが使える。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import pygame
from pygame.locals import *
import time
import sys
import os
pygame.init()
screen = pygame.display.set_mode((300,200))
pygame.display.set_caption('くじびき')
clock = pygame.time.Clock()

# 名前リスト.txtを開いて中身を変数namesに転記
names = open('名前リスト.txt','r')
# for構文でnamesの項目をひとつひとつ読み出す
for name in names:
    # カンマ区切りで分割してloopリストに取り込む。
    loop = name.split(',')

def main():
    n = 0
    x = -1
    while True:
        screen.fill((255,255,255))
        font = pygame.font.SysFont('meiryomeiryomeiryouimeiryouiitalic',50)
        text = font.render(loop[n], True, (0,0,0))
        textrect = text.get_rect()
        textrect.center = (300/2),(200/2)
        screen.blit(text, textrect)
        for event in pygame.event.get():
            if event.type == pygame.QUIT or (event.type == KEYDOWN and event.key == K_q):
                names.close()
                pygame.quit()
                sys.exit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                x = x*-1
        if x>0:
            n = n+1
            if n >= len(loop):
                n = 0
        if x<0:
            n = n
        pygame.display.update()
        clock.tick(20)

main()

以上。
前述の手続きに従ってビルドすればWindows用.exeファイルに変換される。完成した.exeファイルの隣に名前リスト.txtを置くのを忘れずに。

10.Tkinterを使ってみる

10.1.Tkinterを使ってデジタル時計を作る

以前Pygameを使ってデジタル時計を作った。しかし実際に動かしてみると発熱が大きい。PygameモジュールはCPUへの負荷が大きいらしくCPU占有率もすぐに80%を超える。やはりPygameはゲーム用モジュールなのか。そこで動作の軽そうなもうひとつのGUI用モジュール、Tkinterを使ってデジタル時計を作り直してみた。以下にサンプルスクリプトを掲載する。素人が書くスクリプトである。おそらく冗長でお手本としては不適切だと思う。

新規pyファイルを作り、以下を記述する。
# -*- coding:utf-8 -*-

#Tkinterとdatetimeをインポートする
import Tkinter
import datetime

#メイン画面rootを生成、フォントサイズを12ポイントに設定
root = Tkinter.Tk()
root.option_add('*font','12')

#ラベルを生成、textに現在の年月日時分秒を代入、pack()で画面に配置
label = Tkinter.Label(text=datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'))
label.pack()

#関数timecount()を定義
def timecount():
    #Tkinterは勝手に画面を更新してくれないのでroot.after()で強制的に画面更新
    root.after(1000,timecount)
    #1000ミリ秒(1秒)ごとにtextの中の年月日時分秒を書き換え
    label.configure(text=datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'))

#関数timecount()を実行
timecount()
#root = Tkinter.Tk()で始めてroot.mainloop()で結ぶのがTkinterGUIの基本
root.mainloop()
exit()

pyファイルに名前をつけて保存する。tkclock.pyとでもしておこうか。

■Pythonの決まり事
Pygameの項でも書いたが
root =
label =
のように=(イコール)の前にある文字列はたいてい変数だ。これはユーザーが勝手に定義しているもので別の文字列に差し替え可能だ。ややこしい言い方をすると変数にクラスを代入してインスタンス化している作業ということになるらしい。とにかくただの変数なのでrootという言い方が気に入らなければ別の言い方に変更してかまわない。

10.2.TkinterとPygameを使って音楽再生アプリを作る

mp3ファイルを再生するためにはPygame.mixerを使わなければならない。以前Pygameを使ってmp3ファイルを再生したが、今回はそのGUIをTkinterで作る。PlayボタンとStopボタンを備えたGUIとする。
新規pyファイルを作り、以下を記述する。
# -*- coding:utf-8 -*-

#TkinterとPygame.mixerをインポートする
import Tkinter
import pygame.mixer

root = Tkinter.Tk()
root.option_add('*font','12')

#関数play()を定義
def play():
    #mixerモジュールの初期化
    pygame.mixer.init()
    #音楽ファイルの読み込み
    pygame.mixer.music.load("ファイル名.mp3")
    #音楽再生
    pygame.mixer.music.play(1)

#関数stop()を定義
def stop():
    #再生の終了
    pygame.mixer.music.stop()

#Playボタンを生成、コマンドに関数playを割り当て、pack()で画面配置
button = Tkinter.Button(text='Play',command=play)
button.pack()
#Stopボタンを生成、コマンドに関数stopを割り当て、pack()で画面配置
button = Tkinter.Button(text='Stop',command=stop)
button.pack()

root.mainloop()
exit()

pyファイルに名前をつけて保存する。playmp3.pyとでもしておこうか。
playmp3.pyと同じ場所にmp3ファイルも置いておく。
$ python playmp3.py
で起動すると、PlayボタンとStopボタンだけの画面が現れる。Playボタンを押せば音楽を再生し、Stopボタンを押せば音楽を終了する。

10.3.上記ふたつのスクリプトを合体させて目覚まし時計を作る

新規pyファイルを作り、以下を記述する。
# -*- coding:utf-8 -*-

#TkinterとdatetimeとPygame.mixerをインポートする
import tkinter
import datetime
import pygame.mixer

#メイン画面rootを生成、フォントサイズを12ポイントに設定
root = tkinter.Tk()
root.option_add('*font','12')

#関数play()を定義
def play():
    #mixerモジュールの初期化
    pygame.mixer.init()
    #音楽ファイルの読み込み
    pygame.mixer.music.load("ファイル名.mp3")
    #音楽再生
    pygame.mixer.music.play(1)

#関数stop()を定義
def stop():
    #再生の終了
    pygame.mixer.music.stop()

#ラベルを生成、textに現在の年月日時分秒を代入、pack()で画面に配置
label = tkinter.Label(text=datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'))
label.pack()
#Playボタンを生成、コマンドに関数playを割り当て、pack()で画面配置
button = tkinter.Button(text='Play',command=play)
button.pack()
#Stopボタンを生成、コマンドに関数stopを割り当て、pack()で画面配置
button = tkinter.Button(text='Stop',command=stop)
button.pack()

#関数timecount()を定義
def timecount():
    #Tkinterは勝手に画面を更新してくれないのでroot.after()で強制的に画面更新
    root.after(1000,timecount)
    #1000ミリ秒(1秒)ごとにtextの中の年月日時分秒を書き換え
    label.configure(text=datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'))
    #if構文、もし現在時刻が06時00分00秒なら関数play()を実行して音楽再生
    if datetime.datetime.now().strftime('%H%M%S') == '060000':
        play()

#関数timecount()を実行
timecount()
#root = tkinter.Tk()で始めてroot.mainloop()で結ぶのがTkinterGUIの基本
root.mainloop()
exit()

pyファイルに名前をつけて保存する。今回はmezamashi.pyとする。
if構文に続く'060000'=06時00分00秒の値を書き換えれば目覚まし時刻のセットができる。時刻セットのためにはスクリプトから書き直さなければならないが、まあ最初はこんなもんから。
今回はPython3の記法に従って記述してみた。すなわちTkinterでなくtkinterと小文字で書き出してみた。ラズベリーパイでこれを実行する際は
$ python3 mezamashi.py
と、あえてpython3であることを指定しないとうまく動かない。さきほど、WindowsPCにはPython3.6.4をインストールした。なのでWindowsPC上ではPython3に従った記法でないとうまく動かない。しかし、WindowsPCで上記pyファイルを実行する時は、コマンドプロンプトに
python mezamashi.py
と打ち込む。"3"はいらない。

10.4.ttkを使ってみる

ttkはTkinterの機能を拡張するモジュールだ。Pythonのパッケージに最初から含まれているものなので、後から何かをインストールすることなく、だたimportで呼び出すだけですぐに使える。しかし、その呼び出し方がPython3とPython2で異なるのでややこしい。

■Python3でのttkの呼び出し方
import tkinter
from tkinter import ttk

■Python2でのttkの呼び出し方
import Tkinter
import ttk

なぜ異なるのか。Tkinteおよびttkのモジュールとしての作りこみに起因するらしい。詳しいことはわからない。(理解できない)
ttkを使ってみることに意義はある。Notebookというウィジェットを使うとタブつきのウィンドウを生成できるのである。先ほどの目覚まし時計アプリにttk.Notebookを追記して、アラーム時刻をセットするウィンドウを追加する。

# -*- coding:utf-8 -*-

import tkinter
from tkinter import ttk
import datetime
import pygame.mixer

#まずはalarmtimeという変数を用意する
alarmtime = "060000"

root = tkinter.Tk()
root.option_add('*font','12')

#ttk.Notebookを使ってタブ1とタブ2を作る
note = ttk.Notebook(root)
tab1 = ttk.Frame(note)
tab2 = ttk.Frame(note)
note.add(tab1,text="Alarm Clock")
note.add(tab2,text="Set Alarm")
note.pack()

def play():
    pygame.mixer.init()
    pygame.mixer.music.load("ファイル名.mp3")
    pygame.mixer.music.play(1)

def stop():
    pygame.mixer.music.stop()

label = tkinter.Label(tab1,text=datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'))
label.pack()
button = tkinter.Button(tab1,text='Play',command=play)
button.pack()
button = tkinter.Button(tab1,text='Stop',command=stop)
button.pack()

#タブ2にエントリー(1行入力ボックス)を置く
EditBox = tkinter.Entry(tab2)
EditBox.insert(tkinter.END,alarmtime)
EditBox.pack()

def timecount():
    root.after(1000,timecount)
    label.configure(text=datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'))
    #エントリーの6桁の数字を取得してアラーム時刻を設定する
    alarmtime = EditBox.get()
    if datetime.datetime.now().strftime('%H%M%S') == alarmtime:
        play()

timecount()
root.mainloop()
exit()

10.5.threadを使ってみる

この目覚まし時計を改良して、鳴り始めは小さな音で演奏し、徐々に音量が大きくなる仕様に変更したい。そこで関数tone()を定義し、10秒ごとに段々音量が大きくなる仕組みを追記した。18段階、3分で最大音量に達する。
def tone():
    global volume_up
    for i in range(18):
        i+=1
        if volume_up is False:
            break
        else:
            pygame.mixer.music.set_volume(i/18)
            time.sleep(10)
Stopボタンが押されるとグローバル変数volume_upがFalseになり、for文を抜ける→演奏をストップする という仕組みとする予定だったが、for文実行中はパソコン自体がビジーになり、マウス入力すら受け付けないことを知った。これではStopボタンを押せない。for文を止めるボタンを作りたい。
そこでthreadというライブラリを使ってみる。マルチスレッド(並列処理)を実現するものだ。for文の処理を本体と並行して走るマルチスレッドとすることで、for文実行中もStopボタンが有効になる。
前述のプログラムを以下のように書き換えた。

# -*- coding:utf-8 -*-

import tkinter
from tkinter import ttk
import datetime
import pygame.mixer
import threading
import time

alarmtime = "060000"
#グローバル変数volume_upを設定
volume_up = False


root = tkinter.Tk()
root.option_add('*font','12')

note = ttk.Notebook(root)
tab1 = ttk.Frame(note)
tab2 = ttk.Frame(note)
note.add(tab1,text="Alarm Clock")
note.add(tab2,text="Set Alarm")
note.pack()


def play():
    global volume_up
    pygame.mixer.init()
    pygame.mixer.music.load("ファイル名.mp3")
    pygame.mixer.music.play(1)
    volume_up = True
    #tone()関数を並列して走るマルチスレッドとして実行する

    thread = threading.Thread(target=tone)
    thread.start()


def tone():
    global volume_up
    for i in range(18):
        i+=1
        if volume_up is False:
            break
        else:
            pygame.mixer.music.set_volume(i/18)
            time.sleep(10)

def stop():
    global volume_up
    volume_up = False
    pygame.mixer.music.stop()

label = tkinter.Label(tab1,text=datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'))
label.pack()
button = tkinter.Button(tab1,text='Play',command=play)
button.pack()
button = tkinter.Button(tab1,text='Stop',command=stop)
button.pack()

EditBox = tkinter.Entry(tab2)
EditBox.insert(tkinter.END,alarmtime)
EditBox.pack()

def timecount():
root.after(1000,timecount)
label.configure(text=datetime.datetime.now().strftime('%Y/%m/%d %H:%M:%S'))
alarmtime = EditBox.get()
if datetime.datetime.now().strftime('%H%M%S') == alarmtime:
play()

timecount()
root.mainloop()
exit()

これで徐々に音量を上げる優しい目覚まし時計が完成した。演奏時間が3分未満の曲の場合、最大音量に達する前に演奏が終了するので注意。

11.pyaudioを使ってみる

11.1.pyaudioをインストールする

ターミナルを開いて
sudo apt install python-pyaudio
と入力。

11.2.録音アプリを作る

新規pyファイルを作成し、以下を記述。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import pyaudio
import wave
import Tkinter

CHUNK = 512
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 44100
RECORD_SECONDS = 10
WAVE_OUTPUT_FILENAME = "output.wav"

root = Tkinter.Tk()
root.option_add('*font','12')

p = pyaudio.PyAudio()

def record():
    stream = p.open(format=FORMAT,
                                channels=CHANNELS,
                                rate=RATE,
                                input=True,
                                frames_per_buffer=CHUNK)

    print("* recording")

    frames = []

    for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
         data = stream.read(CHUNK)
         frames.append(data)

    print("* done recording")

    stream.stop_stream()
    stream.close()
    p.terminate()

    wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
    wf.setnchannels(CHANNELS)
    wf.setsampwidth(p.get_sample_size(FORMAT))
    wf.setframerate(RATE)
    wf.writeframes(b''.join(frames))
    wf.close()

button = Tkinter.Button(text='Record',command=record)
button.pack()

root.mainloop()
exit()

pyファイルに名前をつけて保存する。record.pyとでもしておこうか。
$ python record.py
で起動すると"Record"と書かれたボタンが現れる。これを押すと10秒間マイクの音を録音する。録音された音は"output.wav"という音声ファイルとして書き出される。
RECORD_SECONDS = 10の値を書き換えることで録音時間を変更できる。
自分で書いたように語るがpyaudio公式Webページ*のコードサンプルを改造しTkinterでボタンをくっつけただけである。
*https://people.csail.mit.edu/hubert/pyaudio/

12.TkinterでJPEG画像を表示する

12.1.Python Imaging Library(PIL)をインストールする

TkinterにはGIF画像を表示する機能がある。しかし、そのままではJPEG画像を扱えない。TkinterでJPEG画像を表示できるようにするためPython Imaging Library(PIL)をインストールする。
ターミナルを開いて以下を入力。
$ sudo apt install python-pil.imageTk
※新たなプログラムをインストールする時はその直前にsudo apt updateでアップデートをしておくクセをつけておいた方がよい。
これでImageTk.PhotoImageコマンドが使えるようになった。

■Python3用PIL
以下のように入力するとPython3用PILもインストールできる。
$ sudo apt install python3-pil.imageTk

12.2.JPEG画像を表示するスクリプトを書く

新規pyファイルを作成し、以下を記述。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import Tkinter
from PIL import ImageTk, Image

#開始の決まり文句
root = Tkinter.Tk()

#画像をロード、インスタンス化して変数imgに代入
image = Image.open("yourfile.jpg")
img = ImageTk.PhotoImage(image)

#imgをラベルに添付、pack()で画面に配置
label = Tkinter.Label(root, image = img)
label.pack()

#結びの決まり文句
root.mainloop()

以上。
yourfile.jpgはもちろんあなたのjpg画像のファイル名に書き換える。

12.3.画面サイズを指定し、その中央にJPEG画像を置く

画面サイズを指定し、その中央にJPEG画像を配置するパターンで書いてみた。root.geometry("600x400")で画面サイズを600x400にしている。さらにタイトルも記入する。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import Tkinter
from PIL import ImageTk, Image

root = Tkinter.Tk()
root.title("Image")
root.geometry("600x400")

image = Image.open("yourfile.jpg")
img = ImageTk.PhotoImage(image)
label = Tkinter.Label(root, image = img)
label.pack(side = "bottom", fill = "both", expand = "yes")

root.mainloop()

以上。

12.4.画面枠いっぱいに広げる

画面枠いっぱいに背景を広げ、その中央にJPEG画像を配置するパターンで書いてみた。PowerPointのスライドショーのようにタイトルバーも消してしまう。タイトルバーが消えてしまうと[閉じる]ボタンも消えてしまうため、プログラムを終了できない。終了するためにはラズベリーパイの電源を抜くより方法がなくなる。それではまずいので、[Exit](終了)ボタンをつける。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import Tkinter
from PIL import ImageTk, Image

root = Tkinter.Tk()
sw, sh = root.winfo_screenwidth(), root.winfo_screenheight()
root.overrideredirect(1)
root.geometry("{0}x{1}+0+0".format(sw,sh))

image = Image.open("yourfile.jpg")
img = ImageTk.PhotoImage(image)
label = Tkinter.Label(root, image = img)
label.pack(side = "bottom", fill = "both", expand = "yes")

button = Tkinter.Button(text='Exit',command=root.destroy)
button.place(x=0,y=0)

root.mainloop()

以上。
※button.place(x=0,y=0)で[Exit]ボタンを左上角に配置している。(x=0,y=0)の値を書き換えれば好きな位置に再配置できる。

12.5.文字の省略

import Tkinter
でなく
from Tkinter import*
と書き出すことで、以下Tkinterの文字を省略できる。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from Tkinter import*
from PIL import ImageTk, Image

root = Tk()
image = Image.open("yourfile.jpg")
img = ImageTk.PhotoImage(image)

label = Label(root, image = img)
label.pack()

root.mainloop()

12.6.Tkinterを使ってGIF画像を表示する

最後にTkinterを使ってGIF画像を表示する演習をしてみる。TkinterにはもともとGIF画像を扱う機能が備わっている。なのでPILや後述するCanvasを使わなくてもGIF画像を表示できる。
import Tkinter

root = Tkinter.Tk()
img = Tkinter.PhotoImage(file = 'yourfile.gif')
label = Tkinter.Label(root, image = img)
label.pack()

root.mainloop()

12.7.Tkinterのスクリプトをオブジェクト指向で書いてみる

TkinterでGIF画像を表示するスクリプトは上記の通り、たった6行で書けてしまう。今度はこの6行をオブジェクト指向で書き直したらどうなるかという演習。3通りの書き方ができてしまうらしい。自分で書いたように語るがStack Overflowからのコピペである。
■初期化メソッドのみのパターン
import Tkinter

class MyCustomWindow(Tkinter.Frame):
    def __init__(self, parent):
        Tkinter.Frame.__init__(self, parent)
        Tkinter.Label(self, image=img).pack()
        self.pack()

root = Tkinter.Tk()
img = Tkinter.PhotoImage(file='yourfile.gif')
MyCustomWindow(root)
root.mainloop()

■初期化メソッドの中で画像読み込み
import Tkinter

class MyCustomWindow(Tkinter.Frame):
    def __init__(self, parent):
        Tkinter.Frame.__init__(self, parent)
        self.img = Tkinter.PhotoImage(file='yourfile.gif')
        Tkinter.Label(self, image=self.img).pack()
        self.pack()

def main():
    root = Tkinter.Tk()
    MyCustomWindow(root)
    root.mainloop()

if __name__ == "__main__":
    main()

■main()の中で画像読み込み
import Tkinter

class MyCustomWindow(Tkinter.Frame):
    def __init__(self, parent):
        Tkinter.Frame.__init__(self, parent)
        Tkinter.Label(self, image=img).pack()
        self.pack()

def main():
    root = Tkinter.Tk()
    global img
    img = Tkinter.PhotoImage(file='yourfile.gif')
    MyCustomWindow(root)
    root.mainloop()

if __name__ == "__main__":
    main()

12.8.WindowsにPython Imaging Library(PIL)をインストールする

前述のWindows用Python拡張パッケージまとめサイト*でPILをダウンロードできる。
*https://www.lfd.uci.edu/~gohlke/pythonlibs/
Pillowなどという名前で呼ばれている。Python3.6(32ビット)用Pillow(PIL)はPillow‑4.3.0‑cp36‑cp36m‑win32.whlである。自分の環境にあった.whlファイルをダウンロードし、インストールする。.whlファイルのインストールの仕方は前述、Pygameの項参照。

12.9.Windows上でスクリプトを実行する

Windowsで上記スクリプトを記述、実行するにあたって、ひとつ注意点がある。私のWindowsの中のPythonはPython3なのでPython3系の記法に書き換えなければならない。要するにTkinterはtkinterと小文字に書き換えなければならない。

13.Tkinter.Canvasを使ってみる

13.1.Tkinter.Canvasを使って、画像をマウスドラッグで動かす

Tkinter.CanvasはGUI画面上に円、三角、四角を描くためのキャンバスとなる画面要素(ウィジェット)の一種だ。Tkinter.Canvasの中で使えるコマンド(メソッド)は実に多種で全部説明できないし、まったく理解できない。詳しくはここ*を見るといいだろう。
*http://effbot.org/tkinterbook/canvas.htm
私はJPEG画像またはPNG画像をアイコンに見立て、そのアイコンをマウスクリックすると何らかの反応を得られたリ、そのアイコン自体をマウスドラッグで移動できたり、というような一般的なGUIのデモ画面を構築したいだけだ。そのためには.Tkinter.Canvasと前述のPython Imaging Library(PIL)の力を借りる必要があった。

13.2.画像をマウスドラッグで動かすスクリプトを書く

新規pyファイルを作成し、以下を記述。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import Tkinter
from PIL import ImageTk, Image

#400x300のキャンバスを生成
root = Tkinter.Tk()
canvas = Tkinter.Canvas(width=400, height=300)
canvas.pack(fill="both", expand=True)

#3つの変数を初期化
item_ID=None
current_x=0
current_y=0

#たい焼きの画像(アイコン)をロード、キャンバスに配置
image1 = Image.open("taiyaki.png")
img1 = ImageTk.PhotoImage(image1)
canvas.create_image(100,150, image=img1, tags="icon")

#桜餅の画像(アイコン)をロード、キャンバスに配置
image2 = Image.open("sakuramochi.png")
img2 = ImageTk.PhotoImage(image2)
canvas.create_image(300, 150, image=img2, tags="icon")

#アイコンをマウスプレスした時の処理、アイコンのIDを取得、マウスの現在位置座標取得
def on_icon_press(event):
    global item_ID
    global current_x
    global current_y
    item_ID = canvas.find_closest(event.x, event.y)[0]
    current_x = event.x
    current_y = event.y

#アイコンを離した時の処理、3つの変数を初期化
def on_icon_release(event):
    global item_ID
    global current_x
    global current_y
    item_ID = None
    current_x = 0
    current_y = 0

#マウスドラッグした時の処理、マウスの移動量とアイコンの位置座標を同期
def on_icon_motion(event):
    global item_ID
    global current_x
    global current_y
    delta_x = event.x - current_x
    delta_y = event.y - current_y
    canvas.move(item_ID, delta_x, delta_y)
    current_x = event.x
    current_y = event.y

#3種類のイベントと3種類の関数をバインド(関連付け)
canvas.tag_bind("icon", "<ButtonPress-1>", on_icon_press)
canvas.tag_bind("icon", "<ButtonRelease-1>", on_icon_release)
canvas.tag_bind("icon", "<B1-Motion>", on_icon_motion)

#結びの決まり文句
root.mainloop()

以上。
アイコン画像に見立てたのは「いらすとや」から引用したたい焼きと桜餅のPNG画像。PILをインポートすればJPEG画像のほかにPNG画像も利用可能だ。PNG画像ならば透明色を設定でき、背景を透過させられる。
canvas.create_image(...の次に来るのは画像の座標だが、画像の中央点の位置を指定する。左上ではない。
さて、とりあえずスクリプトは書けたが、item_ID、current_x、current_yの3つの変数を3回グローバル変数として宣言するのはいかにもやぼったい。そこでもっとスマートな記述をしている他人のスクリプトをまねてみた。

13.3.画像をマウスドラッグで動かすスクリプトを書く(その2)

上記スクリプトを以下の通り修正。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import Tkinter
from PIL import ImageTk, Image

root = Tkinter.Tk()
canvas = Tkinter.Canvas(width=400, height=300)
canvas.pack(fill="both", expand=True)

image1 = Image.open("taiyaki.png")
img1 = ImageTk.PhotoImage(image1)
canvas.create_image(100, 150, image=img1, tags="icon")

image2 = Image.open("sakuramochi.png")
img2 = ImageTk.PhotoImage(image2)
canvas.create_image(300, 150, image=img2, tags="icon")

def on_icon_press(event):
    current["item_ID"] = canvas.find_closest(event.x, event.y)[0]
    current["x"] = event.x
    current["y"] = event.y

def on_icon_release(event):
    current["item_ID"] = None
    current["x"] = 0
    current["y"] = 0

def on_icon_motion(event):
    delta_x = event.x - current["x"]
    delta_y = event.y - current["y"]
    canvas.move(current["item_ID"], delta_x, delta_y)
    current["x"] = event.x
    current["y"] = event.y

current = {"x": 0, "y": 0, "item_ID": None}

canvas.tag_bind("icon", "<ButtonPress-1>", on_icon_press)
canvas.tag_bind("icon", "<ButtonRelease-1>", on_icon_release)
canvas.tag_bind("icon", "<B1-Motion>", on_icon_motion)

root.mainloop()

以上。
3つの変数をディクショナリにまとめた。こういう使い方ができるのか。

14.Tkinter.Canvasを使って電卓を作る

14.1.電卓の背景画像を作る

Python-Tkinterを用いて電卓を作る演習は他の人が色々やっている。同じものを作るのでは能がない。私は背景画像をGUIに見立て、そこに透明なボタンを配置したいと考えた。背景画像を差し替えればまるでスキンを入れ替えるようにGUIのイメージを変えられる。まずは240x320のJPEG画像を用意した。これをbg.jpgという名で保存し、スクリプトから呼び出すようにした。
本来のTkinterにボタンを透明化するオプションは備わっていない。そこで(event.x, event,y)からマウスクリックした座標を取り出し、それがある領域(x1, y1, x2, y2)内にある時、特定のボタンが押されたと認識するプログラムとした。
結果としてTkinterの演習でありながら、Button()もLabel()も使わないプログラムとなった。
■bg.jpg

14.2.電卓のスクリプトを書く

スクリプトは以下の通り。たくさんのif構文で複雑に条件分岐する内容となった。多分お手本としては不適切だと思う。いいじゃないかしろうとだもの。

#!/usr/bin/env python
# -*- coding: utf8 -*-
from tkinter import*
from PIL import ImageTk, Image

def calc(event):
    global buff
    if 80<event.y<=140:
        if 0<event.x<=60: #7
            if buff[0]=='=' or buff==['0']:
                buff=['7']
            else:
                buff.append('7')
        if 60<event.x<=120: #8
            if buff[0]=='=' or buff==['0']:
                buff=['8']
            else:
                buff.append('8')
        if 120<event.x<=180: #9
            if buff[0]=='=' or buff==['0']:
                buff=['9']
            else:
                buff.append('9')
        if 180<event.x<=240: #/
            if buff[-1] in ('+','-','*','/'):
                buff[-1]='/'
            elif buff[0]=='=':
                buff.pop(0)
                buff.append('/')
            else:
                buff.append('/')
    if 140<event.y<=200:
        if 0<event.x<=60: #4
            if buff[0]=='=' or buff==['0']:
                buff=['4']
            else:
                buff.append('4')
        if 60<event.x<=120: #5
            if buff[0]=='=' or buff==['0']:
                buff=['5']
            else:
                buff.append('5')
        if 120<event.x<=180: #6
            if buff[0]=='=' or buff==['0']:
                buff=['6']
            else:
                buff.append('6')
        if 180<event.x<=240: #*
            if buff[-1] in ('+','-','*','/'):
                buff[-1]='*'
            elif buff[0]=='=':
                buff.pop(0)
                buff.append('*')
            else:
                buff.append('*')
    if 200<event.y<=260:
        if 0<event.x<=60: #1
            if buff[0]=='=' or buff==['0']:
                buff=['1']
            else:
                buff.append('1')
        if 60<event.x<=120: #2
            if buff[0]=='=' or buff==['0']:
                buff=['2']
            else:
                buff.append('2')
        if 120<event.x<=180: #3
            if buff[0]=='=' or buff==['0']:
                buff=['3']
            else:
                buff.append('3')
        if 180<event.x<=240: #-
            if buff[-1] in ('+','-','*','/'):
                buff[-1]='-'
            elif buff[0]=='=':
                buff.pop(0)
                buff.append('-')
            else:
                buff.append('-')
    if 260<event.y<=320:
        if 0<event.x<=60: #0
            if buff[0]=='=' or buff==['0']:
                buff=['0']
            elif buff[-1]=='/':
                pass
            else:
                buff.append('0')
        if 60<event.x<=120: #C
            buff = ['0']
        if 120<event.x<=180: #=
            if buff[-1] in ('+','-','*','/'):
                pass
            elif buff[0]=='=':
                pass
            else:
                ans=eval(''.join(buff))
                buff=['=']
                buff.append(str(ans))
        if 180<event.x<=240: #+
            if buff[-1] in ('+','-','*','/'):
                buff[-1]='+'
            elif buff[0]=='=':
                buff.pop(0)
                buff.append('+')
            else:
                buff.append('+')
    else:
        pass
    display = ''.join(buff)
    canvas.itemconfig(item,text=display)

root = Tk()
buff = ['0']
display = ''.join(buff)
canvas = Canvas(width=240,height=320)
image = Image.open("bg.jpg")
img = ImageTk.PhotoImage(image)
canvas.create_image(120,160,image=img)
canvas.bind("<ButtonPress-1>",calc)
item = canvas.create_text(20,20,text=display,font=('',24),fill='black',anchor=NW)

canvas.pack()
root.mainloop()

今回はfrom tkinter import*という書き出しで始めて見た。スクリプト本文中からtkinterの文字を省略できる。しかもtkinterは小文字である。Python3の記法に従った。

15.Orange Pi ZeroをWiFiに接続する

ラズベリーパイゼロがいつまでたっても買えないので勢いでオレンジパイゼロを買ってみた。同じようなもんだろと思ったが全然違った。私と同様興味本位でうっかり買ってしまった人のためにオレンジパイゼロを起動するまでの顛末を記述する。
なお、私が買ったのはOrange Pi Zero 512MBメモリモデルだ。オレンジパイゼロにはたくさんの種類があり、Orange Pi Zero 2+ H5とか拡張ボード付きタイプとか色々あるが、私が買ったのは無印のオレンジパイゼロだ。

15.1.Armbianをインストールする

オレンジパイゼロではUbuntuやAndroidが扱えると公式マニュアルには書いてあるがそれは幻想ではなかろうか。事実上使えるのはArmbianというOSだけだ。これはGUIがない。初心者には敷居が高い。
■用意するもの
・圧縮解凍ソフト7-ZIP
窓の杜*で入手できる。「圧縮・解凍」ライブラリのトップで紹介されている。圧縮・解凍を行うフリーソフト。オレンジパイゼロ用OS「Armbian」が7-ZIPで圧縮されているため、解凍にはこのソフトが必須となる。
*https://forest.watch.impress.co.jp/library/nav/genre/arc/archive_archiver.html
・SSH接続ソフトTera Term
https://ja.osdn.net/projects/ttssh2/

■Armbianを入手する
ここ*に行ってオレンジパイゼロ用Armbianのイメージファイルを入手する。
*https://www.armbian.com/orange-pi-zero/
Ubuntu server - legacy kanelのボタンをクリック。7zファイルのダウンロードが始まる。完了までに10分ほど時間がかかる。2017年10月29日時点、"Armbian_5.30_Orangepizero_Ubuntu_xenial_default_3.4.113.7z"というファイルが入手できる。Armbianはバージョンによって振る舞いが違うので注意されたい。
7-ZIPがインストールされていれば、圧縮ファイルを右クリックした時7-Zipのサブメニューが表示されるはずだ。7-Zipのサブメニューから「ここに展開」を選ぶ。同じフォルダに7zファイルが解凍され複数のファイルが展開されるが、必要なのは"Armbian_5.30_Orangepizero_Ubuntu_xenial_default_3.4.113"ディスクイメージファイルだけだ。
このディスクイメージファイルをWin32 Disk Imager 0.9.5を使ってMicroSDカードに展開する。私は16GBのMicroSDカードしか持っていないので16GBのカードを使用したが4GB以上なら大丈夫な気がする。(確認はしていない)
Armbianのディスクイメージを展開したMicroSDカードをオレンジパイゼロに挿す。さらに有線LANコネクタを接続、そして電源ON。1分ほどするとArmbianの初期動作が完了し、SSHで接続可能となる。
ここで問題。どうやってオレンジパイゼロのIPアドレスを知ることができようか。そこで前述の「ラズベリーパイのローカルIPアドレスを知る」の項を参照。2通りの手段がある。
・バッファロー製ルータを使用している場合。付属ユーティリティ"エアステーション設定ツール"の管理画面トップページ、"ネットワークサービス一覧を表示"を開くとLAN内のデバイス一覧を表示する。ここから新規に追加されたデバイスを探る。
・Windouwsの場合、Advanced IP Scannerというフリーソフトが利用可能だ。LANに接続するデバイスを検出し一覧表示する。ここから新規に追加されたデバイスを探る。

■SSH接続ソフト"Tera Term"を使う
Tera Teamを起動し、"ホスト"にローカルIPアドレス"192.168.0.X"を入力。
ユーザ名:root
パスフレーズ:1234
でOKを押す。
※バッファロー製ルータを使用の場合、IPアドレスは192.168.0.Xという数列になる。

以下のような起動画面が表示される。

You are required to change your password immediately (root enforced)
___ ____ _ _____
/ _ \ _ __ __ _ _ __ __ _ ___ | _ \(_) |__ /___ _ __ ___
| | | | '__/ _` | '_ \ / _` |/ _ \ | |_) | | / // _ \ '__/ _ \
| |_| | | | (_| | | | | (_| | __/ | __/| | / /| __/ | | (_) |
\___/|_| \__,_|_| |_|\__, |\___| |_| |_| /____\___|_| \___/
|___/崩れているが本当はASCII文字でOrangePiZeroと書かれている

Welcome to ARMBIAN 5.30 stable Ubuntu 16.04.2 LTS 3.4.113-sun8i
System load: 0.25 0.32 0.16 Up time: 5 min
Memory usage: 6 % of 494MB IP: 192.168.0.X
CPU temp: 47°C
Usage of /: 9% of 15G

[ General system configuration: armbian-config ]
Changing password for root.
(current) UNIX password:
現在のパスワード"1234"を入力してEnterを押す。カーソルは動かない
Enter new UNIX password:
新しいパスワードを入力。私は"orangepi"とした。Enterを押す。カーソルは動かない。
Retype new UNIX password:
もう一度新しいパスワードを入力。Enterを押す。カーソルは動かない。


Thank you for choosing Armbian! Support: www.armbian.com

Creating a new user account. Press <Ctrl-C> to abort

Please provide a username (eg. your forename): orangepi
新しいユーザーネームを入力。私は"orangepi"とした。Enterを押す。
Trying to add user orangepi
Adding user `orangepi' ...
Adding new group `orangepi' (1000) ...
Adding new user `orangepi' (1000) with group `orangepi' ...
Creating home directory `/home/orangepi' ...
Copying files from `/etc/skel' ...
Enter new UNIX password:
パスワードを入力。Enterを押す。カーソルは動かない。
Retype new UNIX password:
もう一度パスワードを入力。Enterを押す。カーソルは動かない。
passwd: password updated successfully
Changing the user information for orangepi
Enter the new value, or press ENTER for the default
Full Name []: Enterを押す。
Room Number []: Enterを押す。
Work Phone []: Enterを押す。
Home Phone []: Enterを押す。
Other []: Enterを押す。
Is the information correct? [Y/n]  yを押す。

Dear orangepi, your account orangepi has been created and is sudo enabled.
Please use this account for your daily work from now on.

root@orangepizero:~#
これで初回の手続き完了。
sudo apt-get updateしてみるもよし。sudo shutdown -h nowでいきなりシャットダウンするもよし。

15.2.WiFiの設定をする

日本の技適を通過していないのでWiFiの利用は自己責任になる。
プロンプトに続けて以下を入力。
nmtui
Networkmanagerの画面を開く
↓下矢印キーを叩いてActivate a coonectionを選択、Enterを押す。
ネットワークの一覧が表示されるので自宅のルータを選んで、Enterを押す。
パスワード入力画面が表示されるのでパスワードを入力、Enterを押す。
上下左右キーで<OK><Quit>を選んでEnterを押す。画面を抜ける。
■新しいIPアドレスを知る
有線LAN接続時とは異なる新しいIPアドレスが割り当てられる。新しいIPアドレスを知るには前述の「ラズベリーパイのローカルIPアドレスを知る」の項を参照。
ifconfig
を入力して、wlan0の数行下の数列を確認する。

16.Raspberry Pi Zero WHを使う

16.1.Rasupbian Stretch Liteをインストールする

Raspberry Pi Zero WHを入手したので起動するまでの顛末を記録する。Raspberry Pi Zero / Raspberry Pi Zero WHはMini HDMIx1、Micro USB タイプBメスx2という構成となっている。変換ケーブルなしにはHDMIモニタもキーボード/マウスも接続できない。しかし、後述する方法は最初からSSHによるリモート接続を行うので、モニタ、マウス、キーボードを直結する必要はない。Micro USB タイプBの電源用ケーブルさえあればいい。
Raspberry Pi Zero WHの場合、ふたつ並んだMicro USB端子のうち、外側が電源用端子で内側がUSB機器接続用端子とされている。

用意するもの
・SD Formatter 5.0
https://www.sdcard.org/jp/index.html
・Win32 Disk Imager 1.0
https://ja.osdn.net/projects/sfnet_win32diskimager/

手順は前項「Raspbian Stretch with Desktopをインストールする」を参照。RASPBIAN STRETCH WITH DESKTOP-"2017-11-29-raspbian-stretch.zip"でなくRASPBIAN STRETCH LITE"2017-11-29-raspbian-stretch-lite.zip"の方をダウンロードする。
Raspberry Pi ZeroにRasupbian Stretch with Desktopが入らないわけではなかろうが、なぜかみんなPi ZeroにはRasupbian Stretch Liteをインストールしたがるようだ。
■MicroSDカードをフォーマットする
SD Formatter 5.0を使って、MicroSDカードをフォーマットする。手順は前項の通り。
■MicroSDカードにイメージファイルを展開する
Win32 Disk Imager 1.0を使って、"2017-11-29-raspbian-stretch-lite.img"をMicroSDカードに展開する。手順は前項の通り。

OSをインストールしたMicroSDカードをRaspberry Pi Zero WHにすぐ挿したいところだが、その前に下ごしらえがある。

16.2.SSHを使えるようにする

OSをインストールしたMicroSDカードをWindowsエクスプローラーで開いてみる。bootという名のディレクトリとなっている。この中にSSHという名の空ファイルを作る。
まず、エクスプローラー;[表示]タブの中、□ファイル名拡張子にチェックを入れる。拡張子って何?って人はいるまいな。Windowsの基本から勉強したまえ。
この状態でbootフォルダの中で右クリック、[新規作成>]から何かファイルを作る。例えばテキストドキュメントを選んでみる。「新しいテキストドキュメント.txt」が作られる。ファイル名を「SSH.txt」としたのち、「.txt」を消す。「SSH」という名の拡張子のないファイルが出来上がる。不思議なことにこれでSSHが使えるようになる。

16.3.WiFiを使えるようにする

WiFi設定も事前の下ごしらえでプリセットできる。起動時に自動でWiFi接続する設定ファイルを仕込んでおくだけでいい。
まずIDLEを起動する。IDLEはWindows用Pythonに付属するエディタだ。まだPythonをインストールしていないのであれば前項「WindowsにPythonをインストールする」を参照してインストールしておく。
IDLEの場所を覚えているだろうか。スタートメニュー[P]の項目、Python3.6の中にある。
IDLE起動後、FileメニューからNew Fileを選ぶ。開かれた白紙画面に以下を入力。

country=JP
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
network={
                ssid="xxxxxxxx"
                psk="yyyyyyyy"
}

以上。

ssid="xxxxxxxx"のところにSSIDを記入する。psk="yyyyyyyy"のところにパスワードを記入する。SSIDって何?って人はいるまいな。WiFiの基本から勉強したまえ。

上記を記述後、ファイル名をwpa_supplicant.confとして保存する。Fileメニュー→Saveを選ぶ。続くダイアログに[ファイル名]wpa_supplicant.conf、[ファイルの種類]All files(*.*)とする。そのまま保存すると隠しフォルダの中に保存してしまうので、保存場所は変えたほうがいいだろう。デスクトップにでも保存しておいて、後でbootフォルダの中にコピーする。
さて、SSHファイルとwpa_supplicant.confファイルをbootフォルダの中に作ったら下ごしらえ完了。MicroSDカードを抜いてRaspberry Pi Zeroに挿す。電源ケーブルを挿して起動処理が完了するまで1分程度かかる。ゆっくり待ってSSHを起動しよう。

16.4.SSHで接続する

前項「1.4.ラズベリーパイをリモート接続する」を参照。Pi ZeroのローカルIPアドレスを知る手段は前項「1.3.ラズベリーパイのローカルIPアドレスを知る」を参照。
無事、Pi Zeroを起動できたが、GUIのないOSはつまらんな。

16.5.初期設定をする

ターミナルを開いて以下を入力。
$ sudo raspi-config
初期設定画面が開く。
下↓カーソルキーを3回叩いて"4 Localisation Options"をハイライトさせてEnter。またはTabキーを1回叩いて<Select>をハイライトさせてEnter。
"I1 Change Locals"をハイライトさせてEnter。次の画面が出てくるまでちょっと間がある。
下↓カーソルキー押し続け"[ ] ja_JP.UTF-8 UTF-8"をハイライトさせてスペースキー押下。[ ]にアスタリスク[*]を入れてEnter。続く画面で"ja_JP.UTF-8"をセレクトしEnter。
同様に"I2 Change Timezone"をAsia→Tokyoに。"I4 Change Wi-fi Country"を"JP Japan"にセットしてEnter。最後にトップ画面でTabキー2回叩いて<Finish>をハイライトさせてEnter。
確認画面で"Yes"をハイライトさせてEnter。自動でリブートする。

16.6.GUI環境を構築する

最初からRasupbian Stretch with Desktopを入れれば済むことだが、Raspbian Stretch Liteの上にGUI環境を構築していこうと思う。
まず新たなプログラムをインストールする前にupdateとupgradeを済ませておく。
$ sudo apt update
$ sudo apt upgrade
次に日本語フォントをインストール。
$ sudo apt install fonts-vlgothic
そしてGUI環境をインストール。
$ sudo apt install raspberrypi-ui-mods
最後にVNCをインストールして、WindowsPCからVNCでリモート接続できるようにしておこうと思う。
再び初期設定画面を開く。
$ sudo raspi-config
下↓カーソルキーを4回叩いて"5 Internet Options"をハイライトさせてEnter。"P3 VNC"を選んでEnter。続く画面で<Ok>をハイライトさせてEnter。確認画面で"Yes"をハイライトさせてEnter。自動でVNCのインストールが始まる。
$ sudo apt install tightvncserver
と入力して手動でVNCをインストールする方がたやすいかもしれない。インストール後は再起動する。

16.7.WindowsPCからVNC経由でリモート接続する

WindowsのVNCを開く。RealVNCをインストールしていない人は前項「ラズベリーパイをリモート接続する」を参照。WindowPCにVNC Viewerをインストールする手順を記述している。
WindowsのVNCを開いたら空白部分で右クリック。"New Connection"を選ぶ。"VNC Server"にローカルIPアドレス"192.168.0.X"を記入。"Name"はご自由に。"Continue"を押して、USERNAME:pi、PASSWORD:raspberry、"Remember Password"にチェックを入れ、OKボタンで接続を始める。おなじみのデスクトップ画面が表示される。起動時はUSERNAME:pi、PASSWORD:raspberryを記入させられる。

16.8.画面サイズを修正する

WindowsのVNC Viewerから接続すると初期状態では画面サイズが656x416となっており、極めて小さい。これを修正する。ラズベリーパイメニューからターミナルを開いて以下を入力。
$ sudo nano /boot/config.txt
長い文字列が表示されるが、ずーっと下まで送って、最後の行に以下のコマンドを追記する。
hdmi_ignore_edid=0xa5000080
hdmi_group=2
hdmi_mode=47
その後、Ctrl+O(上書き)を押す。Config.txtを上書きするか尋ねてくるのでEnterを押す。
Ctrl+Xを押して完了。
→hdmi_mode=47は1440x900/60HzでRaspbianのデフォルトとなっている解像度である。それ以外の解像度の設定については以下のページを参照。
https://www.raspberrypi.org/documentation/configuration/config-txt/video.md

16.9.TkinterとPygameをインストールする

Raspbian Stretch with Desktopなら最初から入っているTkinterとPygameもStretch Liteには付属しないようだ。
ターミナルを開いて以下を入力。Python2用とPython3用それぞれインストールする。
$ sudo apt install python-tk
$ sudo apt install python3-tk
$ sudo apt install python-pygame
$ sudo apt install python3-pygame
ここまでするのならいよいよ最初からRaspbian Stretch with Desktopを入れていた方がよさそうだ。

16.10.スクリーンセーバーを無効にする

こうしてインストールしたGUI付きRaspbianにはどういうわけがスクリーンセーバーが付属していてデフォルトでONになっている。眺めているのは楽しいが、無駄機能なのでOFFにする。ラズベリーパイメニューから設定>スクリーンセーバーを選ぶ。モード→[セーバーを無効にする]を選ぶ。

17.Raspberry Pi 3にローカルWebサーバーを構築する

17.1.ラズベリーパイにLAMP環境を構築する

Pythonを一通り習得したので今度はPHPを学習しようと思う。そこでPHPの学習環境となるLAMP環境をラズベリーパイに構築する。

■LAMP環境をインストールする
Apach、PHP、MySQL、phpMyAdminをまとめてインストールする。
$ sudo apt-get install apache2 php mysql-server phpmyadmin
途中phpMyAdminで使用するWebサーバをapache2とするかlighttpdとするか聞いてくる。apache2が選択されているのでそのままEnter。あるいはTabキーで<了解>を選択してEnter.
途中phpmyadmin のデータベースを dbconfig-common で設定しますか?と聞いてくる。<はい>を選択してEnter。
途中phpMyAdminのパスワードを聞いてくる。任意のパスワードを設定してEnter。
これで完了。
WindowsPCのWebブラウザからラズベリーパイのIPアドレスにアクセスしてみる。
http://192.168.0.X ※IPアドレスの値は環境により変わる。
「It works」のページが表示されたらOK。
この「It works」ページの本体となるHTMLファイルは/var/www/html/の中にある。

■PHPの動作確認をする
ターミナルを開いて以下を入力。
$ sudo nano /var/www/html/phpinfo.php
空のファイルに以下のテキストを記述して保存。
<?php phpinfo(); ?>

WindowsPC側のブラウザにて以下のURLにアクセス。
http://192.168.0.x/phpinfo.php
紫色のPHP情報画面が表示されたらOK。

■varフォルダを書き込み可能にする
そのままでは/var/www/html/フォルダの中身をいじることができない。それでは不便なので自由自在にフォルダの中身をいじれるようにしたい。
ターミナルを開いて以下を入力。
sudo chmod -R 777 /var/www/
これでvar/www/フォルダ以下をいじれる。
なお、後から追加したファイル/フォルダに対しては777のパーミッションすなわちすべてのユーザーが自由に読み書き実行できる権限が適用されない。var/www/フォルダ以下のディレクトリに後からファイル/フォルダを追加したらその都度sudo chmod -R 777 /var/www/を実行する。

17.2.MySQLを使う

ターミナルを開いて以下を入力。
$ sudo nano /etc/mysql/my.cnf

[client-server]の下に以下の一文を挿入。文字コードをUTF-8に設定する。
default-character-set=utf8mb4
その後、Ctrl+O(上書き)を押す。上書きするか尋ねてくるのでEnterを押す。
Ctrl+Xを押して完了。

ターミナルを開いて以下を入力。
$ sudo mysql
以下の応答があれば成功。
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 15
Server version: 10.1.23-MariaDB-9+deb9u1 Raspbian 9.0

Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]>

MariaDBはMySQLの非商用互換データベースだ。それはともかくMariaDBがコマンド待ち受け状態で止まっている。とりあえずexit;コマンドで脱出。

MariaDB [(none)]> exit;

Bye
が返ってくる。

17.3.データベースを作成する

では以下のようなデータベースを作成してみる。
データベース名:hoge_db1
データベースのパスワード:2018hogePW

データベースにテーブルを配置する。テーブルとはExcel表のようなもので、テーブルの集まりがデータベースである。1個のデータベースの中にいくつでもテーブルを配置できる。ここでは特定のユーザーに対する特定のパスワードを記録するテーブルを用意する。パスワードはsha1形式で暗号化する。
テーブル名:members、ユーザー名:000member、パスワード:pokopen
                      
id                         name               password
Auto Increment     000member      pokopen 

こんなイメージのテーブルを作成してみる。
SQL構文ではコマンドの末尾に必ず ; を入力する。

ターミナルを開いて以下を入力。
$ sudo mysql
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 15
Server version: 10.1.23-MariaDB-9+deb9u1 Raspbian 9.0

Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> CREATE DATABASE hoge_db1;
Query OK, 1 row affected (0.00 sec)
MariaDB [(none)]> USE hoge_db1;
Database changed
MariaDB [hoge_db1]> CREATE TABLE members
-> (
-> id INT(11) NOT NULL AUTO_INCREMENT,
-> name VARCHAR(255) NOT NULL,
-> password VARCHAR(255) NOT NULL,
-> PRIMARY KEY (id)
-> );
Query OK, 0 rows affected (2.80 sec)
MariaDB [hoge_db1]> INSERT INTO members (name, password) VALUES
-> ('000member', sha1('pokopen'));
Query OK, 1 row affected (0.04 sec)
MariaDB [hoge_db1]> GRANT ALL ON hoge_db1.* to 'hoge_db1'@'localhost'
-> IDENTIFIED BY '2018hogePW';
Query OK, 0 rows affected (0.02 sec)
MariaDB [hoge_db1]> FLUSH PRIVILEGES;
Query OK, 0 rows affected (1.22 sec)
MariaDB [hoge_db1]> exit;
Bye

INSERT構文でnameとpasswordをどんどん追記していけば、複数のユーザー名とパスワードを管理するデータベースとなる。

17.4.Apache設定ファイルを編集する

画像をアップロードして一覧表示するWebサイトをローカルに構築する予定だ。しかし、その前にApache設定ファイルを修正する必要がありそうだ。デフォルトの設定を前述のPHP情報画面から確認できる。それによるとアップロード可能なファイルサイズは上限2MBにセットされているらしい。今時2MBでは到底足りない。そこでApache設定ファイルを編集してアップロード可能なファイルサイズの上限を増やす。
ターミナルを開いて以下を入力。
$ sudo nano /etc/apache2/apache2.conf
最後の行に以下を入力。赤字のところは好きな値をセットしてよい。
<Directory "/var/www">
php_value max_execution_time 100
php_value memory_limit 256M
php_value post_max_size 28M
php_value upload_max_filesize 25M
</Directory>

その後、Ctrl+O(上書き)を押す。apache2.confを上書きするか尋ねてくるのでEnterを押す。
Ctrl+Xを押して完了。そしてリブート。

■Apache設定変更を確認する。
WindowsPC側のブラウザにて先ほどのphpinfo.phpにアクセス
http://192.168.0.x/phpinfo.php

左側Local Valueと右側Master Valueの値を比べてみる。
max_execution_time
memory_limit
post_max_size
upload_max_filesize
の各項目がLocalでは修正されていることがわかるだろう。

17.5.画像アップロード用Webページを作る

前述の通り、var/www/html/フォルダの中に置いたファイルがWindowsPC側のブラウザから閲覧可能となる。ここにindex.htmlまたはindex.phpという名のファイルを置き、WindowsPC側のブラウザからラズベリーパイのローカルIPアドレスhttp://192.168.0.Xにアクセスすればindexファイルの中身が表示される仕組み。

■画像アップロード用ページを作る
var/www/html/フォルダの中に新規「空のファイル」を作り、以下を記述する。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">

<title>Upload</title>
</head>
<body>
<form action="index.php" method="post" enctype="multipart/form-data">
<input type="file" name="fname">
<input type="submit" value="アップロード">
</form>
</body>
</html>

<?php
$temporaryname = $_FILES['fname']['tmp_name'];
$originalname = $_FILES['fname']['name'];
if (is_uploaded_file($temporaryname)){
    if(move_uploaded_file($temporaryname, './' . $originalname)){
    echo $originalname . "をアップロードしました。";
    }
}
?>

ファイル名を"index.php"として保存する。保存の際のオプションとして文字コードは"UTF-8"、改行コードは"CR+LF"としておく。
これで必要最低限の画像アップロード用ページが完成する。WindowsPC側のブラウザからhttp://192.168.0.Xにアクセスし、指示に従い画像を選択→アップロードすれば、var/www/html/フォルダの中に画像ファイルが次々転送されていく。フリーのGalleryページ用PHPファイルを転記すれば画像アップロード兼ギャラリーページを作成することも可能だろう。
画像アップロードと書いたが実は画像以外のファイルでも何でも選べば転送できてしまう。画像だけに限定したいのなら、もう1段if構文を重ねて、JPGファイル以外をふるい落とす仕組みが必要だろう。
何でも転送できるが唯一、自分と同名"index.php"という名のファイルだけは転送できない。当たり前だ。"index.php"という名のファイルを転送したかったら、アップロード用ファイルの方の名前をhogehoge.phpとか別の名前にしておけばよい。その際、8行目<form action="index.php" ~<form action="hogehoge.php" ~に変えておく。そしてWindowsPC側のブラウザからhttp://192.168.0.X/hogehoge.phpにアクセスすればよい。
よく考えたらSambaなんかインストールしなくてもこれでファイル共有というかファイル転送の仕組みが構築できたことになる。

17.6."選択されていません"を消す

<input type="file"~という通常のファイル選択フォームで書き出すと、"ファイル選択/選択されていません"といったボタン/ラベルが表示され、アップロードの手順が2ボタンに分かれる。"ファイル選択/選択されていません"を消して、1ボタンでアップロードを完了したい。
前述のPHPファイルを下記のように修正する。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Upload</title>

<style>
.uploadbtn {
background-color: #ff7f50;
padding: 6px;
border-radius: 8px;
font-weight: bold;
cursor: pointer;
cursor: hand;
}

.uploadbtn:hover {
background-color: #ff0000;
border:2px solid #ff0000;
}
</style>

</head>
<body>
<div align="center">
<p></p>
<form action="index.php" method="post" enctype="multipart/form-data">
<label for="filename">
<span class="uploadbtn">アップロード</span>
<input type="file" name="fname" style="display:none;" onchange="this.form.submit()" id="filename">

</label>
</form>
</div>
</body>
</html>

<?php
$temporaryname = $_FILES['fname']['tmp_name'];
$originalname = $_FILES['fname']['name'];
if (is_uploaded_file($temporaryname)){
    if(move_uploaded_file($temporaryname,'./'.$originalname)){
   echo $originalname."をアップロードしました。";
    }
}
?>

<style></style>でスタイルシートを追記してアップロードボタンを修飾した。

18.リネームアプリを作る

18.1.EXIF情報から撮影日を取得する

わけあって他人からもらった大量の写真ファイルを管理することとなった。他人からもらう写真ファイルにはIMG_8984.JPGだのDSC07891.JPGだのメーカーごとに異なるファイル名がつく。このままでは管理しづらいので撮影日順にソートしやすいよう先頭に撮影日がつくファイル名にリネームしたい。窓の杜あたりに行けばそんなフリーソフトなどごまんとありそうだが、それを自分で作ってみる。
まず、EXIF情報から撮影日を取得するスクリプトを書く。PILをインポートするとEXIF情報が扱えるみたいだ。

EXIF情報から撮影日を取得するだけのスクリプト。これを記述しgetexif.pyなどというファイル名で保存しておく。getexif.pyの隣にターゲットファイルとなる"MyImageFile.JPG"を置いておいて、このスクリプトを実行すれば"MyImageFile.JPG"の撮影日情報をprintして返す。さらに撮影年月日を8桁の数列「20180814」として返す。

# -*- coding:utf-8 -*-
import os
from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS

#ファイル名とexif情報属性名を引数にとる関数を定義
def get_exif(file,field):

    #imageオブジェクトからexif情報を抽出
    img = Image.open(file)
    exif = img._getexif()
    #exif_dataリストを生成
    exif_data = []

    for id, value in exif.items():
        if TAGS.get(id) == field:
            tag = TAGS.get(id, id),value
            exif_data.extend(tag)
    #引数に与えられた属性名から値を返す
    return exif_data

#ターゲットとなる画像ファイル、ここではMyImageFile.JPGを設定
f = "MyImageFile.JPG"
#DateTimeOriginal属性の値を取得してprint
var=get_exif(f,"DateTimeOriginal")
print (var)
#上記の値を整形して年月日を示す8桁数列としてprint
fdate = var[1].replace(":", "")[:8]
print (fdate)

18.2.連番を追記するリネームアプリを作る

目標とするアプリのもうひとつの機能はファイル名の末尾に3桁の連番をつけるもの。ターゲットフォルダ内の複数のJPGファイルに対して適当なファイル名と連番を付与するスクリプト。これを記述してrenamefiles.pyなどというファイル名で保存しておく。renamefiles.pyの隣にターゲットフォルダとなる"Rename"フォルダを置いておく。このスクリプトを実行すればRenameフォルダの中にある複数のJPGファイルを「_任意のタイトル_001.JPG」というファイル名にリネームする。

# -*- coding:utf-8 -*-
import glob
import os
#/Rename/フォルダ内JPG画像のリストを生成
files = glob.glob('./Rename/*.jpg')

#リネームを実行する関数を定義
def rename_files():

    #enumerate関数で連番を生成してiに代入、初期値は1
    for i, f in enumerate(files,1):
        #リネーム前のファイル名fから拡張子を分離
        ftitle, fext = os.path.splitext(f)
        #[_任意のタイトル_+3桁の連番+拡張子]にリネームして/Rename/フォルダに保存
        os.rename(f, "./Rename/" + "_任意のタイトル_" + '{0:03d}'.format(i) + fext)

rename_files()
exit()

18.3.上記ふたつのスクリプトを合体させてリネームアプリを作る

さらにTkinterを用いてGUIを付与する。一行エントリーに「_任意のタイトル_」の文字をあらかじめ入れておき、これを編集することでタイトルを入れ替えられる仕様とする。もうひとつ一行エントリーを配置し、連番の初期値も変更できる仕様とする。
新規pyファイルを作り、以下を記述する。

# -*- coding:utf-8 -*-
import glob
import os
import tkinter
from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS

#ファイル名とexif情報属性名を引数にとる関数を定義
def get_exif(file,field):

    img = Image.open(file)
    exif = img._getexif()
    exif_data = []

    for id, value in exif.items():
        if TAGS.get(id) == field:
        tag = TAGS.get(id, id),value
        exif_data.extend(tag)
    return exif_data

files = glob.glob('./Rename/*.jpg')

#リネームを実行する関数を定義
def rename_files():

    #EditBox2から連番の初期値を取得
    num = EditBox2.get()

    for i, f in enumerate(files,int(num)):
        ftitle, fext = os.path.splitext(f)
        var=get_exif(f,"DateTimeOriginal")
        fdate = var[1].replace(":", "")[:8]
        #EditBox1から任意のタイトル(ユーザー入力値)を取得
        title = EditBox1.get()
        #[年月日を示す8桁数列+任意のタイトル+3桁の連番+拡張子]にリネーム
        os.rename(f, "./Rename/" + fdate + title + '{0:03d}'.format(i) + fext)
    exit()

#tkinterによるGUI生成
root = tkinter.Tk()
Label = tkinter.Label(text="20180102(撮影日) + 任意のタイトル + 001(連番).JPG")
Label.pack(anchor=tkinter.W, padx=5, pady=5)
EditBox1 = tkinter.Entry(width=50)
EditBox1.insert(tkinter.END,"_任意のタイトル_")
EditBox1.pack(padx=5, pady=5)
Label = tkinter.Label(text="連番の初期値")
Label.pack(side=tkinter.LEFT, padx=5, pady=5)
EditBox2 = tkinter.Entry(width=5)
EditBox2.insert(tkinter.END,"001")
EditBox2.pack(side=tkinter.LEFT, padx=5, pady=5)
Button = tkinter.Button(text='Rename',command=rename_files)
Button.pack(side=tkinter.RIGHT, padx=5, pady=5)
root.mainloop()
exit()