From e02fb8df3c4c79d5a96ad4bd252227aebc8e453f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Wed, 13 Sep 2023 17:28:15 +0200 Subject: [PATCH] Support RGBCT bulbs --- ltctplugin/upk2esphome/gui.py | 7 +- upk2esphome/parts/bulb.py | 93 ++++++--- .../{bulb_cw_pwm.txt => bulb_pwm_ct.txt} | 0 upk2esphome/tests/bulb_pwm_cw.txt | 141 +++++++++++++ upk2esphome/tests/bulb_pwm_rgbct.txt | 185 ++++++++++++++++++ upk2esphome/tests/bulb_pwm_rgbcw.txt | 177 +++++++++++++++++ 6 files changed, 570 insertions(+), 33 deletions(-) rename upk2esphome/tests/{bulb_cw_pwm.txt => bulb_pwm_ct.txt} (100%) create mode 100644 upk2esphome/tests/bulb_pwm_cw.txt create mode 100644 upk2esphome/tests/bulb_pwm_rgbct.txt create mode 100644 upk2esphome/tests/bulb_pwm_rgbcw.txt diff --git a/ltctplugin/upk2esphome/gui.py b/ltctplugin/upk2esphome/gui.py index 726ed63..ed2215c 100644 --- a/ltctplugin/upk2esphome/gui.py +++ b/ltctplugin/upk2esphome/gui.py @@ -2,7 +2,7 @@ import json import os -from logging import debug, error, info, warning +from logging import debug, error, exception, info, warning from os.path import dirname, isfile import wx @@ -11,7 +11,6 @@ from ltchiptool.gui.base.zc import ZeroconfBase from ltchiptool.gui.panels.base import BasePanel from ltchiptool.gui.utils import on_event -from ltchiptool.util.logging import LoggingHandler from zeroconf import IPVersion, ServiceInfo from upk2esphome import Opts, YamlResult, upk2esphome @@ -356,7 +355,7 @@ def OnDoCloudcutterClick(self): self.EnableAll() except Exception as e: self.EnableAll() - LoggingHandler.get().emit_exception(e) + exception(None, exc_info=e) return dialog = wx.SingleChoiceDialog( @@ -377,7 +376,7 @@ def OnDoCloudcutterClick(self): self.EnableAll() except Exception as e: self.EnableAll() - LoggingHandler.get().emit_exception(e) + exception(None, exc_info=e) return self.data = device diff --git a/upk2esphome/parts/bulb.py b/upk2esphome/parts/bulb.py index 19c865c..5a801d7 100644 --- a/upk2esphome/parts/bulb.py +++ b/upk2esphome/parts/bulb.py @@ -5,43 +5,70 @@ from upk2esphome.opts import Opts from upk2esphome.result import YamlResult -colors = ["red", "green", "blue", "cold", "warm"] -platforms = { +COLORS_STD = ["red", "green", "blue", "cold", "warm"] +COLORS_ALL = [*COLORS_STD, "brightness", "temperature"] +EXTRAS_CW = { + "cold_white_color_temperature": "6500 K", + "warm_white_color_temperature": "2700 K", +} +EXTRAS_RGBCW = { + "color_interlock": True, + **EXTRAS_CW, +} + +# { found_colors: (esphome_platform, {color_translation}, {extra_opts}) } +COLOR_PLATFORMS = { + # Red, Green, Blue "rgb": ("rgb", {}, {}), + # Red, Green, Blue, Warm "rgbw": ("rgbw", {"warm": "white"}, {}), + # Red, Green, Blue, Cold "rgbc": ("rgbw", {"cold": "white"}, {}), + # Red, Green, Blue, Cold, Warm "rgbcw": ( "rgbww", {"cold": "cold_white", "warm": "warm_white"}, - { - "color_interlock": True, - "cold_white_color_temperature": "6500 K", - "warm_white_color_temperature": "2700 K", - }, + EXTRAS_RGBCW, ), + # Red, Green, Blue, Brightness, Temperature + "rgbbt": ( + "rgbct", + {"brightness": "white_brightness", "temperature": "color_temperature"}, + EXTRAS_RGBCW, + ), + # Cold, Warm "cw": ( "cwww", {"cold": "cold_white", "warm": "warm_white"}, - { - "cold_white_color_temperature": "6500 K", - "warm_white_color_temperature": "2700 K", - }, + EXTRAS_CW, ), + # Brightness, Temperature + "bt": ( + "color_temperature", + {"temperature": "color_temperature"}, + EXTRAS_CW, + ), + # Cold "c": ("monochromatic", {"cold": "output"}, {}), + # Warm "w": ("monochromatic", {"warm": "output"}, {}), } -cmods = { - "rgbcw": "rgbww", - "rgb": "rgb", - "cw": "cwww", - "c": "monochromatic", - "rgbc": "rgbw", + +# { (cmod, cwtype): esphome_platform } +CMOD_PLATFORM = { + ("rgbcw", 0): "rgbww", + ("rgbcw", 1): "rgbct", + ("rgb", 0): "rgb", + ("cw", 0): "cwww", + ("cw", 1): "color_temperature", + ("c", 0): "monochromatic", + ("rgbc", 0): "rgbw", } -def get_platform(found: set[str]) -> str | None: +def get_platform(found: set[str]): key = sorted(c[0] for c in found) - for name, platform in platforms.items(): + for name, platform in COLOR_PLATFORMS.items(): if sorted(name) == key: return platform return None @@ -49,11 +76,16 @@ def get_platform(found: set[str]) -> str | None: def gen_pwm(yr: YamlResult, config: dict) -> set[str]: found = set() - for color in colors: + is_ct = config.get("cwtype", 0) == 1 + for color in COLORS_STD: pin = config.get(f"{color[0]}_pin", None) inv = config.get(f"{color[0]}_lv", None) == 0 if pin is None: continue + if is_ct and color == "cold": + color = "brightness" + elif is_ct and color == "warm": + color = "temperature" found.add(color) yr.log(f" - color {color}: pin P{pin}, inverted {inv}") @@ -89,7 +121,7 @@ def gen_i2c_sm2235(yr: YamlResult, config: dict): yr.log(f" - white channels power: {cur_white}") found = set() - for color in colors: + for color in COLORS_STD: channel = f"iic{color[0]}" if channel not in config: continue @@ -144,7 +176,7 @@ def gen_i2c_sm2135eh(yr: YamlResult, config: dict): yr.log(f" - white channels current: {cur_white} mA") found = set() - for color in colors: + for color in COLORS_STD: channel = f"iic{color[0]}" if channel not in config: continue @@ -178,7 +210,7 @@ def gen_i2c_bp5758d(yr: YamlResult, config: dict): cur_warm = config.get("dwcur", None) found = set() - for color in colors: + for color in COLORS_STD: channel = f"iic{color[0]}" if channel not in config: continue @@ -223,7 +255,7 @@ def gen_i2c_bp1658cj(yr: YamlResult, config: dict): yr.log(f" - white channels power: {cur_white}") found = set() - for color in colors: + for color in COLORS_STD: channel = f"iic{color[0]}" if channel not in config: continue @@ -279,7 +311,7 @@ def generate(yr: YamlResult, config: ConfigData, opts: Opts): **opts, } # add channels - for color in colors: + for color in COLORS_ALL: if color not in found: continue key = mapping.get(color, color) @@ -287,7 +319,10 @@ def generate(yr: YamlResult, config: ConfigData, opts: Opts): # add light component yr.light(light) # check cmod matching - if "cmod" in config: - cmod = config["cmod"] - if cmods[cmod] != name: - yr.warn(f"Module 'cmod': {cmod} doesn't match platform {name}") + cmod = config.get("cmod", None) + cwtype = config.get("cwtype", 0) + if (cmod, cwtype) in CMOD_PLATFORM: + if CMOD_PLATFORM[cmod, cwtype] != name: + yr.warn( + f"Module cmod:{cmod}/cwtype:{cwtype} doesn't match platform {name}" + ) diff --git a/upk2esphome/tests/bulb_cw_pwm.txt b/upk2esphome/tests/bulb_pwm_ct.txt similarity index 100% rename from upk2esphome/tests/bulb_cw_pwm.txt rename to upk2esphome/tests/bulb_pwm_ct.txt diff --git a/upk2esphome/tests/bulb_pwm_cw.txt b/upk2esphome/tests/bulb_pwm_cw.txt new file mode 100644 index 0000000..7c907e3 --- /dev/null +++ b/upk2esphome/tests/bulb_pwm_cw.txt @@ -0,0 +1,141 @@ +{ + "manufacturer": "Kobi", + "name": "Oprawa Smart LED Moon", + "key": "keytg5kq8gvkv9dh", + "ap_ssid": "SmartLife", + "github_issues": [ + 264 + ], + "image_urls": [ + "https://tuya-cloudcutter.github.io/images/kobi-oprawa-smart-led-moon.jpg" + ], + "profiles": [ + { + "slug": "oem-bk7231s-light-ty-2.9.16-sdk-1.0.8-40.00", + "name": "2.9.16 - BK7231T", + "type": "CLASSIC", + "sub_name": "oem_bk7231s_light_ty", + "icon": "lightbulb-outline" + } + ], + "schemas": { + "0000021ioj": [ + { + "type": "obj", + "mode": "rw", + "property": { + "type": "bool" + }, + "id": 20 + }, + { + "type": "obj", + "mode": "rw", + "property": { + "range": [ + "white", + "colour", + "scene", + "music" + ], + "type": "enum" + }, + "id": 21 + }, + { + "type": "obj", + "mode": "rw", + "property": { + "min": 10, + "max": 1000, + "scale": 0, + "step": 1, + "type": "value" + }, + "id": 22 + }, + { + "type": "obj", + "mode": "rw", + "property": { + "min": 0, + "max": 1000, + "scale": 0, + "step": 1, + "type": "value" + }, + "id": 23 + }, + { + "type": "obj", + "mode": "rw", + "property": { + "type": "string", + "maxlen": 255 + }, + "id": 25 + }, + { + "type": "obj", + "mode": "rw", + "property": { + "min": 0, + "max": 86400, + "scale": 0, + "step": 1, + "type": "value" + }, + "id": 26 + }, + { + "type": "obj", + "mode": "wr", + "property": { + "type": "string", + "maxlen": 255 + }, + "id": 28 + } + ] + }, + "device_configuration": { + "Jsonver": "1.1.8", + "brightmax": 100, + "brightmin": 10, + "c_lv": 1, + "c_pin": 7, + "cagt": 20, + "category": "0502", + "cmod": "cw", + "colormax": 100, + "colormin": 10, + "crc": 100, + "ctrl_lv": 1, + "ctrl_pin": 14, + "cwmaxp": 100, + "cwtype": 0, + "defbright": 50, + "defcolor": "c", + "deftemp": 0, + "dmod": 0, + "module": "WB3L", + "onoffmode": 0, + "pmemory": 1, + "prodagain": 0, + "pwmhz": 1000, + "remdmode": 0, + "rgbt": 0, + "rstbr": 50, + "rstcor": "c", + "rstnum": 3, + "rsttemp": 0, + "title20": 1, + "w_lv": 1, + "w_pin": 6, + "wfcfg": "spcl", + "wfct": 3, + "wt": 20 + }, + "slug": "kobi-oprawa-smart-led-moon", + "image_url": "https://tuya-cloudcutter.github.io/images/thumbs/kobi-oprawa-smart-led-moon.jpg" +} diff --git a/upk2esphome/tests/bulb_pwm_rgbct.txt b/upk2esphome/tests/bulb_pwm_rgbct.txt new file mode 100644 index 0000000..9fc1b6c --- /dev/null +++ b/upk2esphome/tests/bulb_pwm_rgbct.txt @@ -0,0 +1,185 @@ +{ + "manufacturer": "Cree", + "name": "CMPAR38-120W-AL-9ACK RGBCT Bulb 1.0.6", + "key": "key4emr7fgcfvnuh", + "ap_ssid": "SL-CreeLighting", + "github_issues": [], + "image_urls": [ + "https://tuya-cloudcutter.github.io/images/cree-cmpar38-120w-al-9ack-rgbct-bulb-1.0.6.jpg" + ], + "profiles": [ + { + "slug": "oem-bk7231s-light-db-par38-1.0.6-sdk-1.0.3-40.00", + "name": "1.0.6 - BK7231T", + "type": "CLASSIC", + "sub_name": "oem_bk7231s_light_db_par38", + "icon": "memory" + } + ], + "schemas": { + "000001nbvo": [ + { + "type": "obj", + "mode": "rw", + "property": { + "type": "bool" + }, + "id": 20 + }, + { + "type": "obj", + "mode": "rw", + "property": { + "range": [ + "white", + "colour", + "scene", + "music" + ], + "type": "enum" + }, + "id": 21 + }, + { + "type": "obj", + "mode": "rw", + "property": { + "min": 10, + "max": 1000, + "scale": 0, + "step": 1, + "type": "value" + }, + "id": 22 + }, + { + "type": "obj", + "mode": "rw", + "property": { + "min": 0, + "max": 1000, + "scale": 0, + "step": 1, + "type": "value" + }, + "id": 23 + }, + { + "type": "obj", + "mode": "rw", + "property": { + "type": "string", + "maxlen": 255 + }, + "id": 24 + }, + { + "type": "obj", + "mode": "rw", + "property": { + "type": "string", + "maxlen": 255 + }, + "id": 25 + }, + { + "type": "obj", + "mode": "rw", + "property": { + "min": 0, + "max": 86400, + "scale": 0, + "step": 1, + "type": "value" + }, + "id": 26 + }, + { + "type": "obj", + "mode": "wr", + "property": { + "type": "string", + "maxlen": 255 + }, + "id": 27 + }, + { + "type": "obj", + "mode": "wr", + "property": { + "type": "string", + "maxlen": 255 + }, + "id": 28 + }, + { + "mode": "rw", + "id": 30, + "type": "raw" + }, + { + "mode": "rw", + "id": 31, + "type": "raw" + }, + { + "mode": "rw", + "id": 32, + "type": "raw" + }, + { + "type": "obj", + "mode": "rw", + "property": { + "type": "bool" + }, + "id": 41 + }, + { + "mode": "rw", + "id": 210, + "type": "raw" + } + ] + }, + "device_configuration": { + "Jsonver": "1.1.0", + "b_lv": 1, + "b_pin": 26, + "brightmax": 100, + "brightmin": 9, + "c_lv": 1, + "c_pin": 7, + "cmod": "rgbcw", + "colormax": 100, + "colormin": 10, + "cwmaxp": 100, + "cwtype": 1, + "defbright": 100, + "defcolor": "c", + "deftemp": 100, + "dmod": 0, + "g_lv": 1, + "g_pin": 9, + "module": "WB8P", + "onoffmode": 1, + "pairt": 600, + "pmemory": 1, + "pwmhz": 2000, + "r_lv": 1, + "r_pin": 24, + "remdmode": 1, + "rstbr": 50, + "rstcor": "c", + "rstmode": 0, + "rstnum": 4, + "rsttemp": 100, + "title20": 1, + "w_lv": 1, + "w_pin": 8, + "wfcfg": "spcl_auto", + "wfct": 10 + }, + "slug": "cree-cmpar38-120w-al-9ack-rgbct-bulb-1.0.6", + "image_url": "https://tuya-cloudcutter.github.io/images/thumbs/cree-cmpar38-120w-al-9ack-rgbct-bulb-1.0.6.jpg" +} diff --git a/upk2esphome/tests/bulb_pwm_rgbcw.txt b/upk2esphome/tests/bulb_pwm_rgbcw.txt new file mode 100644 index 0000000..f7125a4 --- /dev/null +++ b/upk2esphome/tests/bulb_pwm_rgbcw.txt @@ -0,0 +1,177 @@ +{ + "manufacturer": "Feit", + "name": "OM60-RGBW-CA-AG A19 Bulb v2.9.16", + "key": "keydpkw438xwpdtm", + "ap_ssid": "SmartLife", + "github_issues": [ + 11 + ], + "image_urls": [ + "https://tuya-cloudcutter.github.io/images/feit-om60-rgbw-ca-ag-a19-bulb-v2.9.16.jpg" + ], + "profiles": [ + { + "slug": "oem-bk7231s-light-ty-2.9.16-sdk-1.0.8-40.00", + "name": "2.9.16 - BK7231T", + "type": "CLASSIC", + "sub_name": "oem_bk7231s_light_ty", + "icon": "lightbulb-outline" + } + ], + "schemas": { + "000000obo9": [ + { + "type": "obj", + "mode": "rw", + "property": { + "type": "bool" + }, + "id": 1 + }, + { + "mode": "rw", + "property": { + "range": [ + "white", + "colour", + "scene", + "scene_1", + "scene_2", + "scene_3", + "scene_4" + ], + "type": "enum" + }, + "id": 2, + "type": "obj" + }, + { + "type": "obj", + "mode": "rw", + "property": { + "min": 25, + "max": 255, + "scale": 0, + "step": 1, + "type": "value" + }, + "id": 3 + }, + { + "type": "obj", + "mode": "rw", + "property": { + "min": 0, + "max": 255, + "scale": 0, + "step": 1, + "type": "value" + }, + "id": 4 + }, + { + "type": "obj", + "mode": "rw", + "property": { + "type": "string", + "maxlen": 255 + }, + "id": 5 + }, + { + "mode": "rw", + "property": { + "type": "string", + "maxlen": 255 + }, + "id": 6, + "type": "obj" + }, + { + "mode": "rw", + "property": { + "type": "string", + "maxlen": 255 + }, + "id": 7, + "type": "obj" + }, + { + "mode": "rw", + "property": { + "type": "string", + "maxlen": 255 + }, + "id": 8, + "type": "obj" + }, + { + "mode": "rw", + "property": { + "type": "string", + "maxlen": 255 + }, + "id": 9, + "type": "obj" + }, + { + "mode": "rw", + "property": { + "type": "string", + "maxlen": 255 + }, + "id": 10, + "type": "obj" + } + ] + }, + "device_configuration": { + "Jsonver": "1.1.6", + "b_lv": 1, + "b_pin": 24, + "brightmax": 100, + "brightmin": 5, + "c_lv": 1, + "c_pin": 7, + "cagt": 20, + "category": "0505", + "cmod": "rgbcw", + "colormax": 100, + "colormin": 10, + "crc": 29, + "cwmaxp": 100, + "cwtype": 0, + "defbright": 100, + "defcolor": "c", + "deftemp": 0, + "dmod": 0, + "g_lv": 1, + "g_pin": 26, + "gmkb": 60, + "gmkg": 60, + "gmkr": 80, + "gmwb": 75, + "gmwg": 70, + "gmwr": 100, + "module": "WB2L", + "onoffmode": 1, + "pmemory": 1, + "prodagain": 0, + "pwmhz": 2000, + "r_lv": 1, + "r_pin": 6, + "rgbt": 10, + "rstbr": 50, + "rstcor": "c", + "rstnum": 3, + "rsttemp": 0, + "title20": 1, + "w_lv": 1, + "w_pin": 8, + "wfcfg": "spcl_auto", + "wfct": 3, + "wt": 20 + }, + "slug": "feit-om60-rgbw-ca-ag-a19-bulb-v2.9.16", + "image_url": "https://tuya-cloudcutter.github.io/images/thumbs/feit-om60-rgbw-ca-ag-a19-bulb-v2.9.16.jpg" +}