標準入力とsystemdはうまくいかない

研究室では自作スマートロックを使っているが問題がある。

今の所、学生証であけるシステムになっているがトイレとかにいくとき学生証を研究室に忘れることとか起きそう。これが起きるとオートロックだから忘れると締め出される。中に人がいればいいが夜遅くとかだと悲惨な結末になる。ということでなにも必要なく(パスワードを覚えればいい)開けられるシステムがほしいなあということでキーボードでパスワードを入力するシステムをつくりたくなった。

ラズパイでスマートロックは作っていてパッケージが便利なので基本pythonでプログラミングしている。

最初は

まあ input()で入力受け取ってそれがパスワードと一致するかどうかでいいでしょ。

と高をくくっていた。実際にこれで動くからはい、これで解決~と思っていた。しかしながらプログラムの実行と実際のシステムに実装するのとでは同じではないことを改めて感じた。

システム的に毎日深夜に再起動して再起動時にプログラムが実行するようにするが定番のsystemdを使うことにした。もともとのsystemdが使われていたのでそこに少し加えればいいだろうと思っていた。

しかしながらsystemdでの起動はコンソールでの実行と異なるため標準入力を受け取らない。そのためにsystemdでは起動することすらできずエラーがでてくる。(エラーメッセージ忘れた)

ということでcronを使ってみようかと思ったがこちらも標準入力は受け取らない。

考え方を変えて標準入力以外でキーボードの入力を受け取る方法を考えてchatgptと相談したらevdevというパッケージを教えてもらえました。このパッケージは標準入力を取るのではなく「このキーが押されました」っていうのを取得するパッケージっぽい。つまりcapslockが無意味。ということでこちらのサイトを参考にパスワードを取得するスクリプトを次みたいに書いた。

import evdev
from evdev import categorize, ecodes
import sys
import time
from datetime import datetime

device_path = "/dev/input/event0"

device = evdev.InputDevice(device_path)

keys = []

while True:
    for event in device.read_loop():
        if event.type == evdev.ecodes.EV_KEY:
            key_code = event.code
            key_value = event.value

            if key_value == 1:
                key_string = evdev.ecodes.KEY[key_code]
                if key_string == 'KEY_ENTER':
                    break

                else:
                    key_string = key_string[4:5]
                    keys.append(key_string)
    
    password = "".join(keys)
    keys = []
    if password == "PASSWORD":
        print ('welcome!')
    else: 
        print("not correct")

device_pathはキーボードを指定してる。こちらのサイトを参考に調べた。それをdeeviceに指定。keysはキーボードの入力を保管するリスト。

while Trueでつねにキーボードの入力を受け取る。

event.typeとかはよくわからんけどとりあえずキーボードの入力をうけとるためのコードらしい。

key_value == 1でキーが押されてることを検出してそれがエンターキーだったら入力をリセット。(標準入力ではないのでエンターで改行とかではなくエンターキーを押した、という入力を受け取るためこういう書き方)

KEY_○はevdevでの出力形式らしく○にはキーの名前が入る。ただこれだと文字として扱いづらいのでkey_string[4:5]でキーの文字部分のみとってくる。それでkey[]リストに加えていきその後のjoinで文字に結合してる。

print(“welcom!")の部分にサーボモータを動かすプログラムとか書けばいいんじゃないでしょうか。私はそれでやって今の所正常に動作しています。

ということでsystemdで標準入力を動かすのは結構面倒。今回はとりあえずevdevで回避したけどそのうち標準入力が必要になりそうで怖い。