pythonでyeelightのWorking with Flowを使ってみた

## Working with Flow
[python-yeelight](https://yeelight.readthedocs.io/en/latest/flow.html)のドキュメントを読んでいると、あらかじめ電球の遷移状態を設定しているFlowというモードがあるそうです。
>“Flow” is a special mode the bulb can be set to, which is basically a list of transitions to perform in succession. For example, a flow can be a constant cycling of colors from one to the next, until it is stopped, or it can be a quick blink of a certain color

久しぶりにyeelightを使ってみたかったので、"Flow"の動作を確認できる環境を作ってみました。

## 環境
Python version:3.9.7
OS: windows 10.0

### yeelightのIPアドレスの検出
以前、Yeelightに関する記事を書いたのですが、IPアドレスの取得について省略して記載したので、はまってしまいました(汗)
今回は、反省を踏まえて、詳細に書いておきます。スマホでYeelightをセットアップし、「LAN Control」を有効化します。セットアップ方法については、[こちら](https://japan.yeelight.com/faq/yeelight-app-2.html)に沿って設定しました。その後、下記のプログラムを実行すると、出力結果にIPアドレスが出てきます。('ip': 'xxx.xxx.xx.xxx'の部分)

yeelight.discover_bulbs()では、デバイスのネットワークと機能を確認することができます。

```discover.py
import yeelight
yeelight.discover_bulbs()
```

出力結果
```
[{'ip': 'xxx.xxx.xx.xxx', 'port': 55443, 'capabilities': {'id': '0x0000000002dfb19a', 'model': 'color4', 'fw_ver': '39', 'support': 'get_prop set_default set_power toggle set_bright set_scene cron_add cron_get cron_del start_cf stop_cf set_ct_abx adjust_ct set_name set_adjust adjust_bright adjust_color set_rgb set_hsv set_music udp_sess_new udp_sess_keep_alive udp_chroma_sess_new', 'power': 'off', 'bright': '1', 'color_mode': '1', 'ct': '4000', 'rgb': '9685622', 'hue': '99', 'sat': '41', 'name': ''}}]
```


### プログラム
guiで操作したかったので、tkinterを使っています。Tkinterの説明については、次の見出しで説明します。ここでは、yeelightに関係するブブについて説明します。```yeelight.Bulb("IPアドレス")```は、上記で確認したIPアドレスを入力してください。```self.bulb.turn_on(effect="smooth")```では、lightをonにしています。effectは、suddenとsmoothが設定できます。smoothにすると、徐々にライトが光り始めます。詳細は、こちらの[ドキュメント](https://yeelight.readthedocs.io/_/downloads/en/stable/pdf/)を確認してください。
turn_offも同様にlightをoffにしています。

```flow = Flow(count=0, transitions=disco())```では、ライブラリであらかじめ設定されている条件を読み込んで、```self.bulb.start_flow(flow)```で照明の色を変化が開始します。例えば、transitionsにdisco()を設定すると、ディスコっぽい照明の色で変化していきます。countは、設定されている色の変化のflowを繰り返す操作になります。指定回数終わると、デフォルトの光に戻ります。ただし、0回だと設定を解除するまで永遠に変化します。```self.bulb.stop_flow()```は、色の変化途中の状態でストップすることができます。
プログラムは、[github](https://github.com/yutti/study/blob/main/yeelight_flow/run.py)に置いてます。

```run.py
import time
import yeelight
from yeelight import *
import tkinter as tk
from tkinter import ttk
from yeelight.transitions import *
from yeelight import Flow


class gui:
    def __init__(self, main_window):

        # Variable setting
        self.bulb = yeelight.Bulb("IPアドレス")  # Set up IP address for yeelight.
        self.function_btn = [
            "alarm",
            "christmas",
            "disco",
            "lsd",
            "police",
            "police2",
            "random_loop",
            "rgb",
            "slowdown",
            "strobe",
            "strobe_color",
            "temp",
        ]

        # Main window
        self.main_window = main_window
        self.main_window.geometry("800x400")
        self.main_window.title("Yeelight operation v0.10")

        self.label_grid(self.main_window, "Light", 0, 0)
        self.btn_grid(self.main_window, "On", self.turn_on_light, 0, 1, tk.SE)
        self.btn_grid(self.main_window, "Off", self.turn_off_light, 0, 2, tk.SE)

        self.label_grid(self.main_window, "Transitions", 1, 0)

        self.func_combobox = ttk.Combobox(
            self.main_window,
            text="combo_file",
            state="readonly",
            value=self.function_btn,
            width=30,
        )
        self.func_combobox.set(self.function_btn[0])
        self.func_combobox.bind("<<ComboboxSelected>>", self.effect_event)
        self.func_combobox.grid(row=1, column=1, columnspan=3)

        self.label_grid(self.main_window, "Flow", 2, 0)
        self.btn_grid(self.main_window, "Start", self.start_flow, 2, 1, tk.SE)
        self.btn_grid(self.main_window, "Stop", self.stop_flow, 2, 2, tk.SE)
        self.btn_grid(self.main_window, "Reset", self.reset_flow, 2, 3, tk.SE)
        self.btn_grid(self.main_window, "Exit", self.close_window, 3, 3, tk.SE)

    def btn_grid(self, set_frame, btn_name, act_command, r_num, c_num, stk):
        button = tk.Button(set_frame, text=btn_name, width=10, command=act_command)
        return button.grid(row=r_num, column=c_num, sticky=stk, padx=10, pady=10)

    def label_grid(self, set_frame, title, r_num, c_num):
        label = tk.Label(set_frame, text=title)
        return label.grid(row=r_num, column=c_num, sticky=tk.W, padx=10, pady=10)

    def turn_on_light(self):
        self.bulb.turn_on(effect="smooth")

    def turn_off_light(self):
        self.bulb.turn_off(effect="smooth")

    def effect_event(self, arg):
        self.transition = self.func_combobox.get()

    def start_flow(self):

        func_name = self.transition

        if func_name == "alarm":
            flow = Flow(count=0, transitions=alarm())  # Cycle forever.

        elif func_name == "christmas":
            flow = Flow(count=0, transitions=christmas())  # Cycle forever.

        elif func_name == "disco":
            flow = Flow(count=0, transitions=disco())  # Cycle forever.

        elif func_name == "lsd":
            flow = Flow(count=0, transitions=lsd())  # Cycle forever.

        elif func_name == "police":
            flow = Flow(count=0, transitions=police())  # Cycle forever.

        elif func_name == "police2":
            flow = Flow(count=0, transitions=police2())  # Cycle forever.

        elif func_name == "random_loop":
            flow = Flow(count=0, transitions=random_loop())  # Cycle forever.

        elif func_name == "rgb":
            flow = Flow(count=0, transitions=rgb())  # Cycle forever.

        elif func_name == "slowdown":
            flow = Flow(count=0, transitions=slowdown())  # Cycle forever.

        elif func_name == "strobe":
            flow = Flow(count=0, transitions=strobe())  # Cycle forever.

        elif func_name == "strobe_color":
            flow = Flow(count=0, transitions=strobe_color())  # Cycle forever.
        elif func_name == "temp":
            flow = Flow(count=0, transitions=temp())  # Cycle forever.

        self.bulb.start_flow(flow)

    def stop_flow(self):
        self.bulb.stop_flow()

    def reset_flow(self):
        flow = Flow(count=1, transitions=pulse(red=255, green=255, blue=255))
        self.bulb.start_flow(flow)

    def close_window(self):
        self.main_window.destroy()
        # self.main_window.quit()


def main():

    main_window = tk.Tk()
    gui(main_window)
    main_window.mainloop()


if __name__ == "__main__":
    main()

```

### TKinter
フレームは、下記のようにmain_windowにラベルやボタンを配置するようにしました。

####　フレームとGUI
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176158/889999af-49fe-3b74-d34c-7a67d2605288.png)

1番上のLightでは、ライトのon/offを操作します。
2番目でtransitionsに設定する照明のモードをComboboxで選択できるようにしています。
3番目は、2番で設定した照明モードを開始、停止、リセットすることができます。
一番下のExitは、GUIを立ち下げます。