diff --git a/custom_components/const.py b/custom_components/const.py index b7fd889..9dab212 100644 --- a/custom_components/const.py +++ b/custom_components/const.py @@ -15,6 +15,7 @@ from homeassistant.components.climate.const import ( from .koolnova.const import ( GlobalMode, Efficiency, + FlowEngine, ZoneClimMode, ZoneFanMode, ZoneState, @@ -77,6 +78,25 @@ EFF_MODES = [ EFF_POS_5, ] +ENGINE_FLOW_POS_1 = "Manual minimum" +ENGINE_FLOW_POS_2 = "Manual medium" +ENGINE_FLOW_POS_3 = "Manual High" +ENGINE_FLOW_POS_4 = "Auto" + +ENGINE_FLOW_TRANSLATION = { + int(FlowEngine.MANUAL_MIN): ENGINE_FLOW_POS_1, + int(FlowEngine.MANUAL_MED): ENGINE_FLOW_POS_2, + int(FlowEngine.MANUAL_HIGH): ENGINE_FLOW_POS_3, + int(FlowEngine.AUTO): ENGINE_FLOW_POS_4, +} + +ENGINE_FLOW_MODES = [ + ENGINE_FLOW_POS_1, + ENGINE_FLOW_POS_2, + ENGINE_FLOW_POS_3, + ENGINE_FLOW_POS_4, +] + SUPPORT_FLAGS = ( ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.FAN_MODE diff --git a/custom_components/koolnova/device.py b/custom_components/koolnova/device.py index 2a181a9..51bf2ec 100644 --- a/custom_components/koolnova/device.py +++ b/custom_components/koolnova/device.py @@ -453,14 +453,28 @@ class Koolnova: ''' Get name ''' return self._name + async def async_set_engine_state(self, + val:const.FlowEngine, + engine_id: int, + ) -> None: + ''' set engine flow from id ''' + _LOGGER.debug("set engine (id:{}) flow : {}".format(engine_id, val)) + if not isinstance(val, const.FlowEngine): + raise AssertionError('Input variable must be Enum FlowEngine') + ret = await self._client.async_set_engine_state(engine_id, val) + if not ret: + _LOGGER.error("[GLOBAL] Error writing {} to modbus".format(val)) + raise UpdateValueError('Error writing to modbus updated value') + self._engines[engine_id - 1].state = val + @property def global_mode(self) -> const.GlobalMode: ''' Get Global Mode ''' return self._global_mode async def async_set_global_mode(self, - val:const.GlobalMode, - ) -> None: + val:const.GlobalMode, + ) -> None: ''' Set Global Mode ''' _LOGGER.debug("set global mode : {}".format(val)) if not isinstance(val, const.GlobalMode): diff --git a/custom_components/koolnova/operations.py b/custom_components/koolnova/operations.py index 6be3021..d0eabbc 100644 --- a/custom_components/koolnova/operations.py +++ b/custom_components/koolnova/operations.py @@ -306,6 +306,18 @@ class Operations: reg = 0 return ret, const.FlowEngine(reg) + async def async_set_engine_state(self, + engine_id:int = 0, + opt:const.FlowEngine = const.FlowEngine.AUTO, + ) -> bool: + ''' write engine state specified by id ''' + if engine_id < 1 or engine_id > 4: + raise UnitIdError("Engine id must be between 1 and 4") + reg, ret = await self.__async_write_register(reg = const.REG_START_FLOW_STATE_ENGINE + (engine_id - 1), val = int(opt)) + if not ret: + _LOGGER.error('Error writing engine state for id:{}'.format(engine_id)) + return ret + async def async_engine_order_temp(self, engine_id:int = 0, ) -> (bool, float): diff --git a/custom_components/select.py b/custom_components/select.py index 2f5726b..d3f7640 100644 --- a/custom_components/select.py +++ b/custom_components/select.py @@ -20,14 +20,21 @@ from .const import ( GLOBAL_MODE_TRANSLATION, EFF_MODES, EFF_TRANSLATION, + ENGINE_FLOW_MODES, + ENGINE_FLOW_TRANSLATION, ) from .coordinator import KoolnovaCoordinator -from .koolnova.device import Koolnova +from .koolnova.device import ( + Koolnova, + Engine, +) + from .koolnova.const import ( GlobalMode, Efficiency, + FlowEngine, ) _LOGGER = logging.getLogger(__name__) @@ -45,6 +52,9 @@ async def async_setup_entry(hass: HomeAssistant, GlobalModeSelect(coordinator, device), EfficiencySelect(coordinator, device), ] + + for engine in device.engines: + entities.append(EngineStateSelect(coordinator, device, engine)) async_add_entities(entities) class GlobalModeSelect(CoordinatorEntity, SelectEntity): @@ -140,4 +150,59 @@ class EfficiencySelect(CoordinatorEntity, SelectEntity): self.__select_option( EFF_TRANSLATION[int(self.coordinator.data['eff'])] ) + self.async_write_ha_state() + +class EngineStateSelect(CoordinatorEntity, SelectEntity): + """Select component to set flow engine """ + + _attr_entity_category: EntityCategory = EntityCategory.CONFIG + + def __init__(self, + coordinator: KoolnovaCoordinator, # pylint: disable=unused-argument + device: Koolnova, # pylint: disable=unused-argument, + engine: Engine, # pylint: disable=unused-argument + ) -> None: + super().__init__(coordinator) + self._attr_options = ENGINE_FLOW_MODES + self._device = device + self._engine = engine + self._attr_name = f"{device.name} Engine AC{engine.engine_id} State" + self._attr_device_info = device.device_info + self._attr_icon = "mdi:turbine" + self._attr_unique_id = f"{DOMAIN}-Engine-AC{engine.engine_id}-State-select" + self.__select_option( + ENGINE_FLOW_TRANSLATION[int(self._engine.state)] + ) + + def __select_option(self, + option: str, + ) -> None: + """ Change the selected option. """ + self._attr_current_option = option + + async def async_select_option(self, + option: str, + ) -> None: + """ Change the selected option. """ + _LOGGER.debug("[ENGINE FLOW] async_select_option: {}".format(option)) + opt = 0 + for k,v in ENGINE_FLOW_TRANSLATION.items(): + if v == option: + opt = k + break + await self._device.async_set_engine_state(FlowEngine(opt), self._engine.engine_id) + self.__select_option(option) + await self.coordinator.async_request_refresh() + + @callback + def _handle_coordinator_update(self) -> None: + """ Handle updated data from the coordinator + Retrieve latest state of global efficiency """ + for _cur_engine in self.coordinator.data['engines']: + if self._engine.engine_id == _cur_engine.engine_id: + _LOGGER.debug("[UPDATE] [ENGINE AC{}] Order temp: {}".format(_cur_engine.engine_id, _cur_engine.state)) + self.__select_option( + ENGINE_FLOW_TRANSLATION[int(_cur_engine.state)] + ) + break self.async_write_ha_state() \ No newline at end of file diff --git a/custom_components/switch.py b/custom_components/switch.py index 6b55c4d..faa0eae 100644 --- a/custom_components/switch.py +++ b/custom_components/switch.py @@ -90,9 +90,7 @@ class SystemStateSwitch(CoordinatorEntity, SwitchEntity): def _handle_coordinator_update(self) -> None: """ Handle updated data from the coordinator """ self._attr_is_on = bool(int(self.coordinator.data['sys'])) - _LOGGER.debug("[UPDATE] Switch State: {} - is_on ? {} - state ? {}".format(bool(int(self.coordinator.data['sys'])), - self._attr_is_on, - self._attr_state)) + _LOGGER.debug("[UPDATE] Switch State: {}".format(bool(int(self.coordinator.data['sys'])))) if bool(int(self.coordinator.data['sys'])): self._attr_state = STATE_ON else: