0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

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

Last updated at Posted at 2023-02-20

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

基本的にはコントローラー端末からコマンドデータを待ち、それに合わせて各処理をやっていくという構成になる。大きくはコントローラー端末とやり取りする部分とコマンドデータを解析して処理していく部分に分かれる。
コマンドデータは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
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?