StreamDeckっぽいものを作る_3_メイン部分

デバッグ版だけどとりあえず上げとく。いつか書き直す。

基本的にはコントローラー端末からコマンドデータを待ち、それに合わせて各処理をやっていくという構成になる。大きくはコントローラー端末とやり取りする部分とコマンドデータを解析して処理していく部分に分かれる。
コマンドデータはUDPにて送られてくるので受信待ちはスレッドにして、受信次第データを解析側にデータキューで渡してやる

コントローラー端末とやり取りをするクラス
```
#   コントローラークラス
class ControlerSocket(threading.Thread):
    #   コンストラクタ
    def __init__(self):
        threading.Thread.__init__(self)

        srcIP = ""                                          #   受信元IP(""でどこからでも可)
        srcPort = STREAMDECKLIKESERVER_PORT                 #   受信元ポート番号
        self.SrcAddr = (srcIP, srcPort)                     #   アドレスをtupleに格納
        self.BUFSIZE = 1024                                 #   バッファサイズ指定
        self.udpServSock = socket(AF_INET, SOCK_DGRAM)      #   AF_INET(IPv4), SOCK_DGRAM(UDP)ソケット作成
        self.udpServSock.bind(self.SrcAddr)                 #   受信元アドレスでバインド

        self.recQueue = queue.Queue()   #   受信データ用キューの生成

        #UDP通信はopen()いらない？

    #   デストラクタ
    def __del__():
        #UDP通信はclose()いらない？
        print("dest")

    def run(self):
        self.__recv()
        
    def send(self, data, DstAddr):
        data = data.encode('utf-8')                 #   byte型に変換
        self.udpServSock.sendto(data, DstAddr)      #   宛先アドレスに送信

    #   受信
    def __recv(self):
        while True:
            try:
                (data, addr) = self.udpServSock.recvfrom(self.BUFSIZE)
            except timeout:
                print("ex")
                continue
            if addr != 0:
                print(type(data))
                str_data = data.decode('utf-8') #データをstr型に変換
                fromip = FROMIPADDRESS + ":" + str(addr[0]) #   返信先IPアドレスをコマンドフォーマットに変換
                formport = FROMPORTADDRESS + ":" + str(addr[1]) #   返信先ポートをコマンドフォーマットに変換
                self.recQueue.put(fromip + "," + formport + "," + str_data) #   受信データをキューに格納
                print(f"get massage from {addr} --> {str_data} ")   #   受信情報表示
                
            if str_data == "end":                       #   プログラム終了
                break
```

こっちがメイン部分のコマンド解析と各種処理を行う部分
UDP受信はコントローラークラスが担当していてデータはデータキューで送られてくるのでデータキューが来たら解析して該当処理を行うだけ
```
#   メイン
def main():
    global obsws
    global dicFunction

    #コマンドと関数の紐づけ
    it = iter(COMMANDS)
    for cmd,func in zip(it,it):
        dicFunction[cmd] = func

    #コントローラー(esp32予定)受信用ソケット
    thcs = ControlerSocket()     #   クラス呼び出し
    thcs.setDaemon(True)         #  デーモンスレッドにする（joinにする方が今回は良いと思うが面倒なのでとりあえずデーモン。いつか直す
    thcs.start()                 #   スレッドとして実行

    #データ待ちループ
    while True:
        recdata = thcs.recQueue.get()   #   受信データの取り出し(データが来るまで待ち)
        dicobscommand = CommandSlpit(recdata)   #  受信データのコマンドとパラメタに分割
        try:
            result = CommandExecute(dicobscommand)
            if result is not None :
                print("return data")
                DstAddr = (dicobscommand[FROMIPADDRESS], STREAMDECKLIKECLIANT_PORT)     #   アドレスをtupleに格納

                thcs.send(str(result), DstAddr)
                
        except KeyboardInterrupt:
            pass

    obsws.Close()  #

    print("enddd")
#   コマンドごとに登録したメソッドを実行
#   diccmd：分割したコマンド辞書
def CommandExecute(diccmd):
    result = dicFunction[diccmd["cmd"]](diccmd)
    return result
    print("exe")

```
コマンド名を元に実行するメソッドを配列として作成(ここでは辞書配列を使っている)しておくことによって後々のメンテナンス性が楽になる。
```
コマンド文字列,実行するメソッド
```
で登録していけば後は勝手にうまくやってくれる。
```
    #コマンドと関数の紐づけ
    it = iter(COMMANDS)
    for cmd,func in zip(it,it):
        dicFunction[cmd] = func

#   コマンド登録用リスト
COMMANDS = [
    OBSSCENECHANGE, obsws.OBSSceneChange   #   OBSアクティブシーン変更
    ,OBSTEXTCHANGE, obsws.OBSTextChange    #   OBSテキストグリッド変更
]
```
解析部分
StreamDeckっぽいものを作る_1で決めたコマンドデータフォーマットの先頭にipとポートが付け加えられて送られてくるのでそれを分離して、パラメタとして格納していく。
基本的には「:」と「,」で分けられているだけ。
```
#コマンドの分離(コマンド種別とコマンドパラメタに分離)
#data：1文コマンドの文字列
#result：分離したコマンド辞書
def CommandSlpit(data):
    result = {} #   空の辞書作成
    datasplit  = str(data).split(',')   #   1コマンド分に分割

    #   1コマンド分を辞書登録
    for d in datasplit:
        obsdic = d.split(":")   #   コマンド種別とコマンドパラメタ値に分割
        result[obsdic[0]] = obsdic[1]   #   辞書に追加

    return result
```