From c1b781e80db811ddef55578abd3d9d7e61e55640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Thu, 7 Sep 2023 17:15:01 +0200 Subject: [PATCH] Fetch software version and schema ID from Cloudcutter profile --- ltctplugin/upk2esphome/common.py | 14 ++++++++++++++ upk2esphome/config.py | 30 +++++++++++++++++++++++++----- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/ltctplugin/upk2esphome/common.py b/ltctplugin/upk2esphome/common.py index 1acfb18..5d35168 100644 --- a/ltctplugin/upk2esphome/common.py +++ b/ltctplugin/upk2esphome/common.py @@ -32,4 +32,18 @@ def cloudcutter_get_device(slug: str) -> dict: f"Status code: {r.status_code}" ) device = r.json() + for i, profile in enumerate(device["profiles"]): + device["profiles"][i] = cloudcutter_get_profile(profile["slug"]) return device + + +def cloudcutter_get_profile(slug: str) -> dict: + url = f"https://tuya-cloudcutter.github.io/api/profiles/{slug}.json" + with requests.get(url) as r: + if r.status_code != 200: + raise RuntimeError( + f"Couldn't download Cloudcutter profile '{slug}'.\n" + f"Status code: {r.status_code}" + ) + profile = r.json() + return profile diff --git a/upk2esphome/config.py b/upk2esphome/config.py index 5fa8fe3..a63e7d1 100644 --- a/upk2esphome/config.py +++ b/upk2esphome/config.py @@ -33,7 +33,7 @@ def build(data: dict, extras: dict) -> "ConfigData": def is_tuya_mcu(self) -> bool: match self.type: case ConfigData.Type.CLOUDCUTTER: - slug = self.profile_slug + slug = self.profile_slug or "" return slug.startswith("bk7231") and "common" in slug case ConfigData.Type.STORAGE: return "baud_cfg" in self.data or "uart_adapt_params" in self.data @@ -63,12 +63,21 @@ def category(self) -> str | None: return self.extras.get("category", {}) @property - def profile_slug(self) -> str: + def profile(self) -> dict | None: + profiles = self.data.get("profiles", []) + profile = profiles and profiles[0] or {} + if isinstance(profile, dict): + return profile + return None + + @property + def profile_slug(self) -> str | None: profiles = self.data.get("profiles", []) profile = profiles and profiles[0] or {} if isinstance(profile, str): return profile.lower() - return profile.get("slug", "").lower() + slug = profile.get("slug", None) + return slug and slug.lower() @property def chip_name( @@ -83,6 +92,13 @@ def chip_name( return "BK7231N" case _: return "?" + profile = self.profile + if profile and "firmware" in profile: + chip = profile["firmware"].get("chip", None) + if chip == "BK7231T": + return "BK7231T" + if chip == "BK7231N": + return "BK7231N" slug = self.profile_slug if slug: if "bk7231t" in slug: @@ -100,7 +116,11 @@ def chip_name( @property def schema_id(self) -> str | None: - return self.data.get("gw_di", {}).get("s_id", None) + match self.type: + case ConfigData.Type.CLOUDCUTTER: + return list(self.data.get("schemas", {}) or [None])[0] + case ConfigData.Type.STORAGE: + return self.data.get("gw_di", {}).get("s_id", None) @property def data_device(self) -> dict | None: @@ -111,7 +131,7 @@ def data_device(self) -> dict | None: firmwareKey=key if key.startswith("key") else None, productKey=key if not key.startswith("key") else None, factoryPin=None, - softwareVer=None, + softwareVer=self.profile.get("firmware", {}).get("version", None), ) case ConfigData.Type.STORAGE: gw_di = self.data.get("gw_di", {})