はじめに
- Raspberry piのGPIOにタクトボタン3個を接続し、Volume Up、Down、Mute、Shutdown、Reset(電源ON)の機能を割り当てます。GPIOのライブラリはgpiozeroを使用します。gpiozeroは、長押、短押制御が簡単に実装できるのでオススメです。
- gpiozeroには、タクトボタンをシミュレートするMock PinsというAPIがあります。タクトボタンがない方も今回のコードを確認できるようにこのAPIの使用方法も記載しました。
- 以前投稿した「gpiozeroのAPIでボタンの長押、短押をシンプルにコーディングする。」 も参考になると思いますので合わせてご覧ください。
1. スイッチ接続方法
-
Mute、Shutdown、Reset用:btn_3 -> GPIO3
(ResetボタンはGPIO3に接続する必要があります。)
GPIO3をGroundに落とすことでOSを起動することができます。電源の抜き差しが不要になり便利です。 -
Volume Up : btn_5 -> GPIO5(他のGPIOでも問題ありません。)
-
Volume Down : btn_11 -> GPIO11(他のGPIOでも問題ありません。)
-
各スイッチのマイナス側はGPIOのGroundにつないでください。私は9番pinに接続しています。
2. スクリプト
- 長押、短押のときに呼び出す関数を作成し、さらに関数内でpin番号毎の処理を記載しています。
- sudo amixer scontrols コマンドで表示されたcontrolを指定するようにしてください。今回は3B+を使用していますが私の環境では「Headphone」と表示されました。以前、Pi Zeroで実装した時は、「PCM」でした。HDMIを出力先にしている場合は他のcontrolの指定が必要かもしれません。
- コマンドをsudoで起動していますがこれは自動起動する際、rootユーザで起動することになるのでそれを考慮したものです。ちなみにpiユーザでコマンドを実行すると「Master」が表示されます。「Master」を指定する場合は、「amixer sset Master 10%+」のように%で制御する必要があります。rootユーザの時と制御方法が異なるのでpiユーザのコマンド実行は問題なく実行できるものの、自動起動にするとうまくいかなくてずいぶん時間を使いました。なぜ制御方法が異なるのか?理由についてまだ解明できていません。ご存知の方いらっしゃったらコメントください。
- Muteボタンはtoggle型です。ボタンを押す毎にMute、Mute解除になります。
- Muteボタン長押の時には、shutdownするようにコマンドを記載しました。shutdown状態でこの同じMuteボタンを押すとOSが起動します。Reset処理はgpiozeroの機能ではなくRaspberry Piの仕様です。Reset(電源ON)ボタンだけ実装したい場合はプログラム無しでただGPIO3とGroundにスイッチをつなぐだけで大丈夫です。
#!/usr/bin/python3
# coding:utf-8
import subprocess
from gpiozero import Button
from signal import pause
Button.was_held = False
def held(btn):
btn.was_held = True
print("button", btn.pin.number, "長押検知")
# Shutdown
if btn.pin.number == 3:
subprocess.run('sudo poweroff', shell=True)
def released(btn):
if not btn.was_held:
print("button", btn.pin.number, "短押検知")
if btn.pin.number == 5:
# sudo amixer scontrols コマンドで表示されたcontrolを指定してください
subprocess.run('sudo amixer sset Headphone 4db+', shell=True)
elif btn.pin.number == 11:
subprocess.run('sudo amixer sset Headphone 4db-', shell=True)
elif btn.pin.number == 3:
# toggle 指定するとボタンを押す毎にMute、Mute解除が可能になります。
subprocess.run('sudo amixer sset Headphone toggle', shell=True)
btn.was_held = False
btn_3 = Button(3)
btn_11 = Button(11)
btn_5 = Button(5)
btn_3.when_held = held
btn_3.when_released = released
btn_11.when_released = released
btn_5.when_released = released
pause()
3. 動作確認
3.1タクトボタンを接続して確認する場合
$ python3 pyhome/gpio_3button_sample.py
# button11を短押したとき Volume Down
button 11 短押検知
Simple mixer control 'Headphone',0
Capabilities: pvolume pvolume-joined pswitch pswitch-joined
Playback channels: Mono
Limits: Playback -10239 - 400
Mono: Playback -2208 [75%] [-22.08dB] [on]
# button5を短押したとき Volume Up
button 5 短押検知
Simple mixer control 'Headphone',0
Capabilities: pvolume pvolume-joined pswitch pswitch-joined
Playback channels: Mono
Limits: Playback -10239 - 400
Mono: Playback -1808 [79%] [-18.08dB] [on]
# 状態が[on]の時にbutton3を短押したとき Mute
button 3 短押検知
Simple mixer control 'Headphone',0
Capabilities: pvolume pvolume-joined pswitch pswitch-joined
Playback channels: Mono
Limits: Playback -10239 - 400
Mono: Playback -1808 [79%] [-18.08dB] [off]
# 状態が[off]の時にbutton3を短押したとき Mute解除
button 3 短押検知
Simple mixer control 'Headphone',0
Capabilities: pvolume pvolume-joined pswitch pswitch-joined
Playback channels: Mono
Limits: Playback -10239 - 400
Mono: Playback -1808 [79%] [-18.08dB] [on]
# button3を長押したとき shutdown
3.2 Mock Pinsで確認する場合
- Mock pinsというAPIを使えば物理スイッチがなくてもスイッチ動作をシミュレートすることができます。
- スクリプト pyhome/gpio_3button_sample.py に Mock pinsを使うための宣言を追加します。
- 対話型実行環境として Ipythonを使用します。
$ python3 -m IPython
Python 3.7.3 (default, Jul 25 2020, 13:03:44)
Type "copyright", "credits" or "license" for more information.
IPython 5.8.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]:
- IPythonのプロンプトが表示されたら以下ソースをペーストします。
import subprocess
from gpiozero import Button
from signal import pause
### Mock pinsを使用するために追加するコード ###
from gpiozero.pins.mock import MockFactory
from gpiozero import Device
Device.pin_factory = MockFactory()
############################################
Button.was_held = False
def held(btn):
btn.was_held = True
print("button", btn.pin.number, "長押検知")
# Shutdown
if btn.pin.number == 3:
subprocess.run('sudo poweroff', shell=True)
def released(btn):
if not btn.was_held:
print("button", btn.pin.number, "短押検知")
if btn.pin.number == 5:
subprocess.run('sudo amixer sset Headphone 4db+', shell=True)
elif btn.pin.number == 11:
subprocess.run('sudo amixer sset Headphone 4db-', shell=True)
elif btn.pin.number == 3:
subprocess.run('sudo amixer sset Headphone toggle', shell=True)
btn.was_held = False
btn_3 = Button(3)
btn_11 = Button(11)
btn_5 = Button(5)
btn_3.when_held = held
btn_3.when_released = released
btn_11.when_released = released
btn_5.when_released = released
### Mock pinsを使用するために除外するコード ###
# pause()
############################################
- 続いてIPythonのコンソールにbuttonの短押と長押しをシミュレートするコマンドを入力します。
短押:btn.pin.drive_low();btn.pin.drive_high()
長押:btn.pin.drive_low()
ボタンを元に戻す:btn.pin.drive_high()
短押は押し込んですぐ離すlow(押す)->high(離す)
長押は押したままlow(押す)
メソッドがタクトボタンの動きと連動してるのでわかりやすいと思います。
# button3 短押シミュレート Mute
In [2]: btn_3.pin.drive_low();btn_3.pin.drive_high()
button 3 短押検知
Simple mixer control 'Headphone',0
Capabilities: pvolume pvolume-joined pswitch pswitch-joined
Playback channels: Mono
Limits: Playback -10239 - 400
Mono: Playback 0 [96%] [0.00dB] [off]
# button3 短押シミュレート Mute解除
In [3]: btn_3.pin.drive_low();btn_3.pin.drive_high()
button 3 短押検知
Simple mixer control 'Headphone',0
Capabilities: pvolume pvolume-joined pswitch pswitch-joined
Playback channels: Mono
Limits: Playback -10239 - 400
Mono: Playback 0 [96%] [0.00dB] [on]
# button11 短押シミュレート Volume Down
In [4]: btn_11.pin.drive_low();btn_11.pin.drive_high()
button 11 短押検知
Simple mixer control 'Headphone',0
Capabilities: pvolume pvolume-joined pswitch pswitch-joined
Playback channels: Mono
Limits: Playback -10239 - 400
Mono: Playback -400 [92%] [-4.00dB] [on]
# button5 短押シミュレートVolume Up
In [5]: btn_5.pin.drive_low();btn_5.pin.drive_high()
button 5 短押検知
Simple mixer control 'Headphone',0
Capabilities: pvolume pvolume-joined pswitch pswitch-joined
Playback channels: Mono
Limits: Playback -10239 - 400
Mono: Playback 0 [96%] [0.00dB] [on]
# button3を元に戻す
In [6]: btn_3.pin.drive_high()
# button3 長押シミュレート shutdown
In [7]: btn_3.pin.drive_low()
4. 自動起動設定
# スクリプトに実行権を付与する
$ chmod +x pyhome/gpio_3button_sample.py
# 自動起動用サービスファイルを作成する
sudo vi /etc/systemd/system/gpio_3button_sample.service
[Unit]
Description=Pi Zero Gpio Service Daemon
[Service]
ExecStart =/home/pi/pyhome/gpio_3button_sample.py
Restart=always
Type=simple
[Install]
WantedBy=multi-user.target
# サービス自動起動を有効にする
$ sudo systemctl enable gpio_3button_sample
# サービスを起動する
$ sudo systemctl start gpio_3button_sample
# サービスの状態を確認する
$ sudo systemctl status gpio_3button_sample
● gpio_3button_sample.service - Pi Zero Gpio Service Daemon
Loaded: loaded (/etc/systemd/system/gpio_3button_sample.service; enabled; vendor preset: enabled)
Active: active (running)
おわりに
Raspberry Piにスイッチつけたりスピーカつけたりするとぐっと使いやすくなると感じています。マウスやキーボードで操作するのとは違ったダイレクトな操作性は気持が良いです。
この記事が何かのお役にたてれば幸いです。
では、すてきなRaspberry Pi Lifeを!