学生証で行う入退室管理システム【関数】

# はじめに
近畿大学ロボット研究会の部室にFelica(学生証)を用いた入退室管理システムを作成しました。今回はプログラムの紹介をします。（これを作ったころはchatGPTがなく、無駄な関数もあります）

# 入退室管理システムについて
入退室管理システムの全体像や動作のようすは以下のブログにまとまっています。

https://qiita.com/keigo1110/items/f7273980e7b0bb2dd39c

また、入退室管理システムの全体のプログラムは以下のブログにまとまっています。参考にしてください。

https://qiita.com/keigo1110/items/1ab595b48bd03734069b


## 関数
以下にプログラムの中で用いた関数をまとめています。

### 時間計算(cal_time)
```python
def cal_time(specific_time):
    day = int(specific_time // 86400) #日数の算出
    time_left = specific_time - 86400 * day #日数を除いた残り時間
    hour = int(time_left // 3600) #時間の算出
    time_left2 = time_left - 3600 * hour #時間を除いた残り時間
    minutes = int(time_left2) // 60 #分の算出
    time_left3 = time_left2 - 60 * minutes #分を除いた残り時間
    second = int(time_left3 // 1) #残りが秒になる
    return day, hour, minutes, second #日、時間、分、秒、を返す
```
UNIX時間を取得するという変態プレイをしているので、この関数が必要です。そのまま日付など取得しても構いません。

### 音を鳴らす(name_call, guest_call, error_call, arere_call, mp3)
```python
'''音関係'''
#名前を呼ぶ
def name_call(line, word):
    speak = get_info("C", line)
    call_word = speak +"さん" + word
    tts = gTTS(text= call_word, lang = "ja")
    tts.save('voice.mp3') #保存
    mp3('voice.mp3') #再生

#名前を呼ぶ（ゲスト用）
def guest_call(name, word):
    call_word = name +"さん" + word
    tts = gTTS(text= call_word, lang = "ja")
    tts.save('guest.mp3') #保存
    mp3('guest.mp3') #再生

#エラー用音楽
def error_call():
    mp3('piropiro.mp3') #エラー音楽

#あれれ音楽
def arere_call():
    mp3('arere.mp3') #入室時間短いときに流す音楽

#音声流すためのセット
def mp3(file_name):
    mixer.init()
    mixer.music.load(file_name)
    mixer.music.play()
    time.sleep(2)
```
学生証からうまく名前を取り出せなかったので、学生証の番号からエクセルファイルで関連付けられている名前を取り出して発声するようにしています。
ゲストの場合は番号を読みます。

音楽は、エラーと入室時間短い場合のものを用意しています。mp3の関数があれば他の役割をもった音楽呼び出しが可能です。

### discord(discord_notify)
```python
'''discordの処理'''
def discord_notify(url, message):
    """
    Discord send message.

    Args:
        url (str): discord webhook url.
        message (str): message.
    """
    if url:
        requests.post(url,data={'content': message})
```
discordにメッセージを送信します。
直前まででmessageに送りたい内容を格納しておけば大丈夫です。


### エクセル操作1(excel_file_read, row_clear, overwrite)
```python
'''エクセル関数'''
#エクセルのファイルを読み込む
def excel_file_read(file_name, sheet_name):
    filename = file_name
    wb = openpyxl.load_workbook(filename)
    ws = wb[sheet_name]
    return wb, ws

#セルの特定の行をクリア
def row_clear(line):
    wb, ws = excel_file_read(filename, sheetname)
    ws.delete_rows(line)
    wb.save("club.xlsx")

#上書きする
def overwrite(column, line, inout):
    wb, ws = excel_file_read(filename, sheetname)
    '''シート内のA1セルに文字列を入力'''
    cell = column + line
    ws[cell] = inout
    #saveメソッドで同じ名前で上書き保存
    wb.save("club.xlsx")
```
上書きのときはファイルを保存するまでがワンセットです。
関数にしておけば忘れることないです。

### エクセル操作2(sum_column, get_info, guest_in)
```py
#特定の列の特定の文字の数を数える
def sum_column(column, keyword):
    wb, ws = excel_file_read(filename, sheetname)
    result = 0
    for cell in column:
        # セルのデータを文字列に変換
        try:
            value = str(cell.value)
        # 文字列に変換できないデータはスキップ
        except:
            continue
        # キーワードに一致するセルの番地を取得
        if value == keyword:
            result += 1
    return result

#データを取得する
def get_info(specific_column, line):
    wb, ws = excel_file_read(filename, sheetname)
    student_information = specific_column + line
    info = ws[student_information].value
    info_str = str(info)
    return info_str

#ゲストを追加して上書きする
def guest_in(sid):
    wb, ws = excel_file_read(filename, sheetname)
    '''シート内のA列セルに文字列を入力'''
    str_sid = str(sid)
    do_check = 0
    for row in range(101, 200):
        if do_check == 1:
            break
        str_row = str(row)
        if ws['A' + str_row].value == None:
            ws['A' + str_row] = str_sid
            ws['B' + str_row] = 'ゲスト' + str_sid
            ws['C' + str_row] = 'ゲスト' + str_sid[0:2] + 'の' + str_sid[7:10] + '番'
            ws['D' + str_row] = '1'
            do_check = 1
    #saveメソッドで同じ名前で上書き保存
    wb.save("club.xlsx")
    '''エクセルに書き込んだのはすぐ使えないから処理用に準備'''
    make_name = 'ゲスト' + str_sid
    make_call_name = 'ゲスト' + str_sid[0:2] + 'の' + str_sid[7:10] + '番'
    return make_name, make_call_name
```
こちらもゲストの上書きは保存をします。

### エクセル操作3(excel_student_column, search_column)
```py
#学籍番号と一致する行番号を返す
def excel_student_column(sid):
    wb, ws = excel_file_read(filename, sheetname)
    '''学籍番号の列から何行目にあるのか検索する'''
    str_sid = str(sid)
    result = search_column(ws['A'], str_sid)
    if result == 0:
        str_result = '00'
    else:
        str_result = str(result)
    student_num = str_result[1:]
    return student_num

# 特定の列を検索
def search_column(column, keyword):
    result = 0
    for cell in column:
        # セルのデータを文字列に変換
        try:
            value = str(cell.value)
        # 文字列に変換できないデータはスキップ
        except:
            continue
        # キーワードに一致するセルの番地を取得
        if value == keyword:
            cell_address = openpyxl.utils.get_column_letter(cell.column) +  str(cell.row)
            result = cell_address
    return result
```

### インターネット接続(net_connect)
```python
'''インターネット接続処理'''
def net_connect():
    webbrowser.open("ログインするサイトのURL") #必要なら記入
    #以下は
    time.sleep(5)

    pyautogui.press("tab")
    time.sleep(1)
    pyautogui.write('学籍番号')

    pyautogui.press("tab")
    time.sleep(1)
    pyautogui.write('パスワード')

    time.sleep(1)

    pyautogui.press("tab")
    pyautogui.press("enter")
    time.sleep(5)
```
ここはchromeドライバがうまく使えなかったので、pyautoguiで画面を直接操作しています。

# おわりに
部品として他のプロジェクトにも使えそうです。