diff --git a/custom_components/tuya_smart_ir_ac/api.py b/custom_components/tuya_smart_ir_ac/api.py index 110ab2d..54cd929 100644 --- a/custom_components/tuya_smart_ir_ac/api.py +++ b/custom_components/tuya_smart_ir_ac/api.py @@ -2,7 +2,6 @@ from homeassistant.core import HomeAssistant import logging -from pprint import pformat _LOGGER = logging.getLogger(__package__) @@ -11,37 +10,23 @@ class TuyaAPI: def __init__( self, hass: HomeAssistant, + api_url, access_id, access_secret, climate_id, - infrared_id, - api_url + infrared_id ): - self.hass = hass - self.climate_id = climate_id - self.infrared_id = infrared_id + self._hass = hass + self._climate_id = climate_id + self._infrared_id = infrared_id - openapi = TuyaOpenAPI(api_url, access_id, access_secret) - openapi.connect() - self.openapi = openapi + self._openapi = TuyaOpenAPI(api_url, access_id, access_secret) + self._openapi.connect() - self._temperature = None - self._mode = None - self._power = None - self._wind = None - - async def async_init(self): - await self.update() - - async def async_update(self): + async def async_get_status(self): status = await self.get_status() - if status: - self._temperature = status.get("temp") - self._mode = status.get("mode") - self._power = status.get("power") - self._wind = status.get("wind") - _LOGGER.info(pformat("ASYNC_UPDATE " + str(status))) - + return TuyaData(status) if status else None + async def async_turn_on(self): await self.send_command("power", "1") @@ -49,7 +34,6 @@ async def async_turn_off(self): await self.send_command("power", "0") async def async_set_fan_speed(self, fan_speed): - _LOGGER.info(fan_speed) await self.send_command("wind", str(fan_speed)) async def async_set_temperature(self, temperature): @@ -59,48 +43,52 @@ async def async_set_hvac_mode(self, hvac_mode): await self.send_command("mode", str(hvac_mode)) async def async_set_multiple(self, power, mode, temp, wind): - cmd = { "power": power, "mode": mode, "temp": temp, "wind": wind } - await self.send_multiple_command(cmd) + await self.send_multiple_command(power, mode, temp, wind) async def get_status(self): - url = f"/v2.0/infrareds/{self.infrared_id}/remotes/{self.climate_id}/ac/status" - _LOGGER.info(url) + url = f"/v2.0/infrareds/{self._infrared_id}/remotes/{self._climate_id}/ac/status" try: - data = await self.hass.async_add_executor_job(self.openapi.get, url) + data = await self._hass.async_add_executor_job(self._openapi.get, url) + _LOGGER.debug(f"Climate {self._climate_id} get status response: {str(data)}") if data.get("success"): - _LOGGER.info(pformat("GET_STATUS " + str(data.get("result")))) return data.get("result") + raise Exception(f"{data.get("code", None)} {data.get("msg", None)}") except Exception as e: - _LOGGER.error(f"Error fetching status: {e}") - return None + _LOGGER.error(f"Error getting status for climate {self._climate_id}: {e}") + return None async def send_command(self, code, value): - url = f"/v2.0/infrareds/{self.infrared_id}/air-conditioners/{self.climate_id}/command" - _LOGGER.info(url) + url = f"/v2.0/infrareds/{self._infrared_id}/air-conditioners/{self._climate_id}/command" + command = { "code": code, "value": value } try: - _LOGGER.info(pformat("SEND_COMMAND_CODE_THEN_VAL " + code + " " + value)) - data = await self.hass.async_add_executor_job( - self.openapi.post, - url, - { - "code": code, - "value": value, - }, - ) - _LOGGER.info(pformat("SEND_COMMAND_END " + str(data))) + _LOGGER.debug(f"Climate {self._climate_id} send command request: {str(command)}") + data = await self._hass.async_add_executor_job(self._openapi.post, url, command) + _LOGGER.debug(f"Climate {self._climate_id} send command response: {str(data)}") + if not data.get("success"): + raise Exception(f"{data.get("code", None)} {data.get("msg", None)}") return data except Exception as e: - _LOGGER.error(f"Error sending command: {e}") + _LOGGER.error(f"Error sending command to climate {self._climate_id}: {e}") return False - async def send_multiple_command(self, command): - url = f"/v2.0/infrareds/{self.infrared_id}/air-conditioners/{self.climate_id}/scenes/command" - _LOGGER.info(url) + async def send_multiple_command(self, power, mode, temp, wind): + url = f"/v2.0/infrareds/{self._infrared_id}/air-conditioners/{self._climate_id}/scenes/command" + command = { "power": power, "mode": mode, "temp": temp, "wind": wind } try: - _LOGGER.info(pformat("SEND_COMMAND " + str(command))) - data = await self.hass.async_add_executor_job(self.openapi.post, url, command) - _LOGGER.info(pformat("SEND_COMMAND_END " + str(data))) + _LOGGER.debug(f"Climate {self._climate_id} send multiple command request: {str(command)}") + data = await self._hass.async_add_executor_job(self._openapi.post, url, command) + _LOGGER.debug(f"Climate {self._climate_id} send multiple command response: {str(data)}") + if not data.get("success"): + raise Exception(f"{data.get("code", None)} {data.get("msg", None)}") return data except Exception as e: - _LOGGER.error(f"Error sending command: {e}") + _LOGGER.error(f"Error sending multiple command to climate {self._climate_id}: {e}") return False + + +class TuyaData(object): + def __init__(self, status): + self.temperature = status.get("temp") + self.mode = status.get("mode") + self.power = status.get("power") + self.wind = status.get("wind") \ No newline at end of file diff --git a/custom_components/tuya_smart_ir_ac/climate.py b/custom_components/tuya_smart_ir_ac/climate.py index afac86d..ec5eaca 100644 --- a/custom_components/tuya_smart_ir_ac/climate.py +++ b/custom_components/tuya_smart_ir_ac/climate.py @@ -2,14 +2,14 @@ import logging -from pprint import pformat - from homeassistant.core import HomeAssistant from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType +from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.config_validation import PLATFORM_SCHEMA import homeassistant.helpers.config_validation as cv from homeassistant.components.climate.const import ( + FAN_AUTO, HVACMode, ClimateEntityFeature, DEFAULT_MIN_TEMP, @@ -71,16 +71,17 @@ def setup_platform( add_entities([TuyaClimate(hass, config)]) -class TuyaClimate(ClimateEntity): +class TuyaClimate(ClimateEntity, RestoreEntity): def __init__(self, hass, config): self._api = TuyaAPI( hass, - config[CONF_ACCESS_ID], - config[CONF_ACCESS_SECRET], - config[CONF_CLIMATE_ID], - config[CONF_INFRARED_ID], - TUYA_API_URLS.get(config[CONF_TUYA_COUNTRY]) + TUYA_API_URLS.get(config.get(CONF_TUYA_COUNTRY)), + config.get(CONF_ACCESS_ID), + config.get(CONF_ACCESS_SECRET), + config.get(CONF_CLIMATE_ID), + config.get(CONF_INFRARED_ID) ) + self._name = config.get(CONF_NAME) self._unique_id = config.get(CONF_UNIQUE_ID, None) self._temperature_sensor = config.get(CONF_TEMPERATURE_SENSOR, None) @@ -88,6 +89,10 @@ def __init__(self, hass, config): self._min_temp = config.get(CONF_TEMP_MIN, DEFAULT_MIN_TEMP) self._max_temp = config.get(CONF_TEMP_MAX, DEFAULT_MAX_TEMP) self._temp_step = config.get(CONF_TEMP_STEP, DEFAULT_PRECISION) + + self._hvac_mode = HVACMode.OFF + self._fan_mode = FAN_AUTO + self._target_temperature = 0 @property def name(self): @@ -120,24 +125,20 @@ def target_temperature_step(self): @property def current_temperature(self): sensor_state = self.hass.states.get(self._temperature_sensor) if self._temperature_sensor is not None else None - _LOGGER.info("TEMPERATURE SENSOR STATE ", sensor_state) return float(sensor_state.state) if sensor_state and sensor_state.state not in [STATE_UNKNOWN, STATE_UNAVAILABLE] else None @property def current_humidity(self): sensor_state = self.hass.states.get(self._humidity_sensor) if self._humidity_sensor is not None else None - _LOGGER.info("HUMIDITY SENSOR STATE ", sensor_state) return float(sensor_state.state) if sensor_state and sensor_state.state not in [STATE_UNKNOWN, STATE_UNAVAILABLE] else None @property def target_temperature(self): - return float(self._api._temperature) if self._api._temperature else None + return self._target_temperature @property def hvac_mode(self): - if self._api._power == "0": - return HVACMode.OFF - return TUYA_HVAC_MODES.get(str(self._api._mode), None) + return self._hvac_mode @property def hvac_modes(self): @@ -145,39 +146,50 @@ def hvac_modes(self): @property def fan_mode(self): - return TUYA_FAN_MODES.get(str(self._api._wind), None) + return self._fan_mode @property def fan_modes(self): return list(TUYA_FAN_MODES.values()) + async def async_added_to_hass(self): + last_state = await self.async_get_last_state() + if last_state: + self._hvac_mode = last_state.state + self._fan_mode = last_state.attributes.get("fan_mode") + self._target_temperature = last_state.attributes.get("temperature") + async def async_update(self): - await self._api.async_update() - self.async_write_ha_state() + status = await self._api.async_get_status() + if status: + self._hvac_mode = HVACMode.OFF if status.power == "0" else TUYA_HVAC_MODES.get(str(status.mode), None) + self._fan_mode = TUYA_FAN_MODES.get(str(status.wind), None) + self._target_temperature = float(status.temperature) + self.async_write_ha_state() async def async_turn_on(self): - _LOGGER.info("TURN ON") + _LOGGER.info(f"{self.entity_id} turn on") await self._api.async_turn_on() async def async_set_temperature(self, **kwargs): temperature = kwargs.get("temperature") if temperature is not None: - _LOGGER.info("SETTING TEMPERATURE TO " + str(temperature)) + _LOGGER.info(f"{self.entity_id} setting temperature to {temperature}") await self._api.async_set_temperature(float(temperature)) async def async_set_fan_mode(self, fan_mode): - _LOGGER.info("SETTING FAN MODE TO " + fan_mode) + _LOGGER.info(f"{self.entity_id} setting fan mode to {fan_mode}") for mode, mode_name in TUYA_FAN_MODES.items(): if fan_mode == mode_name: await self._api.async_set_fan_speed(mode) break async def async_set_hvac_mode(self, hvac_mode): - _LOGGER.info("SETTING HVAC MODE TO " + hvac_mode) + _LOGGER.info(f"{self.entity_id} setting hvac mode to {hvac_mode}") for mode, mode_name in TUYA_HVAC_MODES.items(): if hvac_mode == mode_name: if mode == "5": await self._api.async_turn_off() else: - await self._api.async_set_multiple(power = "1", mode = mode, temp = self._api._temperature, wind = "0") + await self._api.async_set_multiple("1", mode, self._target_temperature, "0") break