diff --git a/README.md b/README.md index 87d96d7..4c4cb3e 100644 --- a/README.md +++ b/README.md @@ -29,11 +29,15 @@ This is a custom component for [Home Assistant](http://home-assistant.io) that a - [On Mode](#on-mode) - [Off Mode](#off-mode) - [Auto Mode](#auto-mode) + - [Auto Settings Mode](#auto-setting-mode) + - [Target Settings Mode](#target-settings-mode) - [Timer to On Mode](#timer-to-on-mode) - [Timer to Off Mode](#timer-to-off-mode) - [Cycle Mode](#cycle-mode) - [Schedule Mode](#schedule-mode) - [VPD Mode](#vpd-mode) + - [Auto Settings Mode](#auto-setting-mode-1) + - [Target Settings Mode](#target-settings-mode-1) - [Device Settings](#device-settings) - [Dynamic Response](#dynamic-response) - [Transition Mode](#transition-mode) @@ -183,7 +187,12 @@ Device is always set to the on speed . This mode has no unique controls. Device is always set to the off speed . This mode has no unique controls. ### Auto Mode -Device toggled based on temperature and/or humidity triggers +Device toggled based on temperature and/or humidity triggers. This mode is split into two sub modes: Auto and Target. + +- `Auto Settings Mode`: Swap between `Auto` and `Target` setting mode types. `Target` mode is not valid for some device types. + +#### Auto Setting Mode + - `High Temp Enabled`: Enable or disable high temp trigger while in Auto mode - `High Temp Trigger`: If trigger is enabled, device will be turned on if temp exceeds configured value. - `Low Temp Enabled`: Enable or disable low temp trigger while in Auto mode @@ -193,6 +202,16 @@ Device toggled based on temperature and/or humidity triggers - `Low Humidity Enabled`: Enable or disable low humidity trigger while in Auto mode - `Low Humidity Trigger`: If trigger is enabled, device will be turned on if humidity drops below configured value. +#### Target Settings Mode + +- `Target Temp Enabled`: Enabled or disable the target temperature target. * +- `Target Temp`: If enabled, target temperature to maintain. * +- `Target Humidity Enabled`: Enable or disable the target humidity target. ** +- `Target Humidity`: If enabled, the target humidity to maintain. ** + +* Only valid for AC or Heater devices +** Only valid for Humidifier devices + ### Timer to On Mode Device is turned on after a set duration - `Minutes to On`: Device will be turned on after the configured number of minutes @@ -213,7 +232,19 @@ Device is toggled based on a schedule ### VPD Mode Device is toggled based on VPD triggers + +- `VPD Settings Mode`: Swap between `Auto` and `Target` setting mode types. `Target` mode is not valid for some device types. + +#### Auto Setting Mode + - `VPD High Enabled`: Enable or disable high VPD trigger while in VPD mode - `VPD High Trigger`: If trigger is enabled, device will be turned on if VPD exceeds configured value. - `VPD Low Enabled`: Enable or disable low VPD trigger while in VPD mode - `VPD Low Trigger`: If trigger is enabled, device will be turned on if VPD drops below configured value. + +#### Target Settings Mode + +- `Target VPD Enabled`: Enable or disable the target VPD target * +- `Target VPD`: If enabled, the target VPD to maintain * + +* Only valid for AC, Heater, and Humidifier devices diff --git a/custom_components/ac_infinity/const.py b/custom_components/ac_infinity/const.py index d0e250e..d9f9ec0 100644 --- a/custom_components/ac_infinity/const.py +++ b/custom_components/ac_infinity/const.py @@ -118,10 +118,14 @@ class PortControlKey: TIMER_DURATION_TO_OFF = "acitveTimerOff" CYCLE_DURATION_ON = "activeCycleOn" CYCLE_DURATION_OFF = "activeCycleOff" + VPD_SETTINGS_MODE = "vpdSettingMode" VPD_HIGH_ENABLED = "activeHtVpd" VPD_HIGH_TRIGGER = "activeHtVpdNums" VPD_LOW_ENABLED = "activeLtVpd" VPD_LOW_TRIGGER = "activeLtVpdNums" + VPD_TARGET_ENABLED = "targetVpdSwitch" + VPD_TARGET = "targetVpd" + AUTO_SETTINGS_MODE = "settingMode" AUTO_TEMP_HIGH_TRIGGER = "devHt" AUTO_TEMP_HIGH_TRIGGER_F = "devHtf" AUTO_TEMP_HIGH_ENABLED = "activeHt" @@ -132,9 +136,11 @@ class PortControlKey: AUTO_TEMP_LOW_ENABLED = "activeLt" AUTO_HUMIDITY_LOW_TRIGGER = "devLh" AUTO_HUMIDITY_LOW_ENABLED = "activeLh" - TARGET_HUMIDITY_SWITCH = "targetHumiSwitch" - TARGET_TEMPERATURE_SWITCH = "targetTSwitch" - TARGET_VPD_SWITCH = "targetVpdSwitch" + AUTO_TARGET_TEMP_ENABLED = "targetTSwitch" + AUTO_TARGET_TEMP = "targetTemp" + AUTO_TARGET_TEMP_F = "targetTempF" + AUTO_TARGET_HUMIDITY_ENABLED = "targetHumiSwitch" + AUTO_TARGET_HUMIDITY = "targetHumi" EC_OR_TDS = "ecOrTds" VPD_STATUS = "vpdstatus" VPD_NUMS = "vpdnums" diff --git a/custom_components/ac_infinity/manifest.json b/custom_components/ac_infinity/manifest.json index dcf8c59..9ccf02e 100644 --- a/custom_components/ac_infinity/manifest.json +++ b/custom_components/ac_infinity/manifest.json @@ -10,5 +10,5 @@ "iot_class": "cloud_polling", "issue_tracker": "https://github.com/dalinicus/homeassistant-acinfinity", "requirements": [], - "version": "1.6.0" + "version": "1.7.0" } diff --git a/custom_components/ac_infinity/number.py b/custom_components/ac_infinity/number.py index 28d7d01..7d7b8a8 100644 --- a/custom_components/ac_infinity/number.py +++ b/custom_components/ac_infinity/number.py @@ -246,6 +246,21 @@ def __set_value_fn_temp_auto_high( ) +def __set_value_fn_target_temp( + entity: ACInfinityEntity, port: ACInfinityPort, value: int +): + return entity.ac_infinity.update_port_controls( + port.controller.device_id, + port.port_index, + [ + # value is received from HA as C + (PortControlKey.AUTO_TARGET_TEMP, value), + # degrees F must be calculated and set in addition to C + (PortControlKey.AUTO_TARGET_TEMP_F, int(round((value * 1.8) + 32, 0))), + ], + ) + + def __get_value_fn_dynamic_transition_temp( entity: ACInfinityEntity, port: ACInfinityPort ): @@ -488,6 +503,20 @@ def __set_value_fn_dynamic_buffer_temp( get_value_fn=__get_value_fn_vpd_control, set_value_fn=__set_value_fn_vpd_control, ), + ACInfinityPortNumberEntityDescription( + key=PortControlKey.VPD_TARGET, + device_class=NumberDeviceClass.PRESSURE, + mode=NumberMode.BOX, + native_min_value=0, + native_max_value=9.9, + native_step=0.1, + icon="mdi:water-thermometer-outline", + translation_key="target_vpd", + native_unit_of_measurement=None, + suitable_fn=suitable_fn_port_control_default, + get_value_fn=__get_value_fn_vpd_control, + set_value_fn=__set_value_fn_vpd_control, + ), ACInfinityPortNumberEntityDescription( key=PortControlKey.AUTO_HUMIDITY_LOW_TRIGGER, device_class=NumberDeviceClass.HUMIDITY, @@ -516,6 +545,20 @@ def __set_value_fn_dynamic_buffer_temp( get_value_fn=get_value_fn_port_control_default, set_value_fn=set_value_fn_port_control_default, ), + ACInfinityPortNumberEntityDescription( + key=PortControlKey.AUTO_TARGET_HUMIDITY, + device_class=NumberDeviceClass.HUMIDITY, + mode=NumberMode.AUTO, + native_min_value=0, + native_max_value=100, + native_step=1, + icon="mdi:water-percent", + translation_key="target_humidity", + native_unit_of_measurement=None, + suitable_fn=suitable_fn_port_control_default, + get_value_fn=get_value_fn_port_control_default, + set_value_fn=set_value_fn_port_control_default, + ), ACInfinityPortNumberEntityDescription( key=PortControlKey.AUTO_TEMP_LOW_TRIGGER, device_class=NumberDeviceClass.TEMPERATURE, @@ -544,6 +587,20 @@ def __set_value_fn_dynamic_buffer_temp( get_value_fn=get_value_fn_port_control_default, set_value_fn=__set_value_fn_temp_auto_high, ), + ACInfinityPortNumberEntityDescription( + key=PortControlKey.AUTO_TARGET_TEMP, + device_class=NumberDeviceClass.TEMPERATURE, + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + mode=NumberMode.AUTO, + native_min_value=0, + native_max_value=90, + native_step=1, + icon=None, + translation_key="target_temp", + suitable_fn=suitable_fn_port_control_default, + get_value_fn=get_value_fn_port_control_default, + set_value_fn=__set_value_fn_target_temp, + ), ACInfinityPortNumberEntityDescription( key=AdvancedSettingsKey.DYNAMIC_TRANSITION_TEMP, device_class=None, diff --git a/custom_components/ac_infinity/select.py b/custom_components/ac_infinity/select.py index b423cd3..44dd92b 100644 --- a/custom_components/ac_infinity/select.py +++ b/custom_components/ac_infinity/select.py @@ -75,6 +75,11 @@ class ACInfinityPortSelectEntityDescription( 6: "Fan", } +SETTINGS_MODE_OPTIONS = [ + "Auto", + "Target", +] + def __get_value_fn_outside_climate( entity: ACInfinityEntity, controller: ACInfinityController @@ -97,6 +102,25 @@ def __set_value_fn_outside_climate( ) +def __get_value_fn_setting_mode(entity: ACInfinityEntity, port: ACInfinityPort): + return SETTINGS_MODE_OPTIONS[ + entity.ac_infinity.get_port_control( + port.controller.device_id, port.port_index, entity.entity_description.key + ) + ] + + +def __set_value_fn_setting_mode( + entity: ACInfinityEntity, port: ACInfinityPort, value: str +): + return entity.ac_infinity.update_port_control( + port.controller.device_id, + port.port_index, + entity.entity_description.key, + SETTINGS_MODE_OPTIONS.index(value), + ) + + def __get_value_fn_active_mode(entity: ACInfinityEntity, port: ACInfinityPort): return MODE_OPTIONS[ # data is 1 based. Adjust to 0 based enum by subtracting 1 @@ -193,6 +217,22 @@ def __set_value_fn_device_load_type( get_value_fn=__get_value_fn_active_mode, set_value_fn=__set_value_fn_active_mode, ), + ACInfinityPortSelectEntityDescription( + key=PortControlKey.AUTO_SETTINGS_MODE, + translation_key="auto_settings_mode", + options=SETTINGS_MODE_OPTIONS, + suitable_fn=suitable_fn_port_control_default, + get_value_fn=__get_value_fn_setting_mode, + set_value_fn=__set_value_fn_setting_mode, + ), + ACInfinityPortSelectEntityDescription( + key=PortControlKey.VPD_SETTINGS_MODE, + translation_key="vpd_settings_mode", + options=SETTINGS_MODE_OPTIONS, + suitable_fn=suitable_fn_port_control_default, + get_value_fn=__get_value_fn_setting_mode, + set_value_fn=__set_value_fn_setting_mode, + ), ACInfinityPortSelectEntityDescription( key=AdvancedSettingsKey.DEVICE_LOAD_TYPE, translation_key="device_load_type", diff --git a/custom_components/ac_infinity/strings.json b/custom_components/ac_infinity/strings.json index b5fa67b..ca33658 100644 --- a/custom_components/ac_infinity/strings.json +++ b/custom_components/ac_infinity/strings.json @@ -82,18 +82,27 @@ "vpd_mode_high_trigger": { "name": "VPD High Trigger" }, + "target_vpd": { + "name": "Target VPD" + }, "auto_mode_humidity_low_trigger": { "name": "Humidity Low Trigger" }, "auto_mode_humidity_high_trigger": { "name": "Humidity High Trigger" }, + "target_humidity": { + "name": "Target Humidity" + }, "auto_mode_temp_low_trigger": { "name": "Temperature Low Trigger" }, "auto_mode_temp_high_trigger": { "name": "Temperature High Trigger" }, + "target_temp": { + "name": "Target Temperature" + }, "temperature_calibration": { "name": "Temperature Calibration" }, @@ -140,6 +149,12 @@ }, "outside_climate_humidity": { "name": "Outside Humidity" + }, + "auto_settings_mode": { + "name": "Auto Settings Mode" + }, + "vpd_settings_mode": { + "name": "VPD Settings Mode" } }, "sensor": { @@ -166,6 +181,9 @@ "vpd_mode_high_enabled": { "name": "VPD High Trigger Enabled" }, + "target_vpd_enabled": { + "name": "Target VPD Enabled" + }, "auto_mode_humidity_low_enabled": { "name": "Humidity Low Trigger Enabled" }, @@ -178,6 +196,12 @@ "auto_mode_temp_high_enabled": { "name": "Temperature High Trigger Enabled" }, + "target_temp_enabled": { + "name": "Target Temperature Enabled" + }, + "target_humidity_enabled": { + "name": "Target Humidity Enabled" + }, "schedule_mode_on_time_enabled": { "name": "Scheduled On-Time Enabled" }, diff --git a/custom_components/ac_infinity/switch.py b/custom_components/ac_infinity/switch.py index 40c86e3..9405f1d 100644 --- a/custom_components/ac_infinity/switch.py +++ b/custom_components/ac_infinity/switch.py @@ -97,6 +97,17 @@ def __get_value_fn_schedule_enabled(entity: ACInfinityEntity, port: ACInfinityPo get_value_fn=get_value_fn_port_control_default, set_value_fn=set_value_fn_port_control_default, ), + ACInfinityPortSwitchEntityDescription( + key=PortControlKey.VPD_TARGET_ENABLED, + device_class=SwitchDeviceClass.SWITCH, + on_value=1, + off_value=0, + icon=None, # default + translation_key="target_vpd_enabled", + suitable_fn=suitable_fn_port_control_default, + get_value_fn=get_value_fn_port_control_default, + set_value_fn=set_value_fn_port_control_default, + ), ACInfinityPortSwitchEntityDescription( key=PortControlKey.AUTO_TEMP_HIGH_ENABLED, device_class=SwitchDeviceClass.SWITCH, @@ -141,6 +152,28 @@ def __get_value_fn_schedule_enabled(entity: ACInfinityEntity, port: ACInfinityPo get_value_fn=get_value_fn_port_control_default, set_value_fn=set_value_fn_port_control_default, ), + ACInfinityPortSwitchEntityDescription( + key=PortControlKey.AUTO_TARGET_TEMP_ENABLED, + device_class=SwitchDeviceClass.SWITCH, + on_value=1, + off_value=0, + icon=None, # default + translation_key="target_temp_enabled", + suitable_fn=suitable_fn_port_control_default, + get_value_fn=get_value_fn_port_control_default, + set_value_fn=set_value_fn_port_control_default, + ), + ACInfinityPortSwitchEntityDescription( + key=PortControlKey.AUTO_TARGET_HUMIDITY_ENABLED, + device_class=SwitchDeviceClass.SWITCH, + on_value=1, + off_value=0, + icon=None, # default + translation_key="target_humidity_enabled", + suitable_fn=suitable_fn_port_control_default, + get_value_fn=get_value_fn_port_control_default, + set_value_fn=set_value_fn_port_control_default, + ), ACInfinityPortSwitchEntityDescription( key=PortControlKey.SCHEDULED_START_TIME, device_class=SwitchDeviceClass.SWITCH, diff --git a/custom_components/ac_infinity/translations/en.json b/custom_components/ac_infinity/translations/en.json index 8991236..4db2fc0 100644 --- a/custom_components/ac_infinity/translations/en.json +++ b/custom_components/ac_infinity/translations/en.json @@ -83,18 +83,27 @@ "vpd_mode_high_trigger": { "name": "VPD High Trigger" }, + "target_vpd": { + "name": "Target VPD" + }, "auto_mode_humidity_low_trigger": { "name": "Humidity Low Trigger" }, "auto_mode_humidity_high_trigger": { "name": "Humidity High Trigger" }, + "target_humidity": { + "name": "Target Humidity" + }, "auto_mode_temp_low_trigger": { "name": "Temperature Low Trigger" }, "auto_mode_temp_high_trigger": { "name": "Temperature High Trigger" }, + "target_temp": { + "name": "Target Temperature" + }, "temperature_calibration": { "name": "Temperature Calibration" }, @@ -141,6 +150,12 @@ }, "outside_climate_humidity": { "name": "Outside Humidity" + }, + "auto_settings_mode": { + "name": "Auto Settings Mode" + }, + "vpd_settings_mode": { + "name": "VPD Settings Mode" } }, "sensor": { @@ -167,6 +182,9 @@ "vpd_mode_high_enabled": { "name": "VPD High Trigger Enabled" }, + "target_vpd_enabled": { + "name": "Target VPD Enabled" + }, "auto_mode_humidity_low_enabled": { "name": "Humidity Low Trigger Enabled" }, @@ -179,6 +197,12 @@ "auto_mode_temp_high_enabled": { "name": "Temperature High Trigger Enabled" }, + "target_temp_enabled": { + "name": "Target Temperature Enabled" + }, + "target_humidity_enabled": { + "name": "Target Humidity Enabled" + }, "schedule_mode_on_time_enabled": { "name": "Scheduled On-Time Enabled" }, diff --git a/tests/test_client.py b/tests/test_client.py index 4114705..c46696c 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -245,9 +245,10 @@ async def test_set_device_port_setting_zero_even_when_null(self, set_value): assert isinstance(dev_mode_settings["data"], dict) dev_mode_settings["data"][PortControlKey.SURPLUS] = set_value - dev_mode_settings["data"][PortControlKey.TARGET_TEMPERATURE_SWITCH] = set_value - dev_mode_settings["data"][PortControlKey.TARGET_HUMIDITY_SWITCH] = set_value - dev_mode_settings["data"][PortControlKey.TARGET_VPD_SWITCH] = set_value + dev_mode_settings["data"][ + PortControlKey.AUTO_TARGET_HUMIDITY_ENABLED + ] = set_value + dev_mode_settings["data"][PortControlKey.VPD_TARGET_ENABLED] = set_value dev_mode_settings["data"][PortControlKey.EC_OR_TDS] = set_value dev_mode_settings["data"][PortControlKey.MASTER_PORT] = set_value @@ -257,9 +258,8 @@ async def test_set_device_port_setting_zero_even_when_null(self, set_value): expected = set_value if set_value else 0 assert payload[PortControlKey.SURPLUS] == expected - assert payload[PortControlKey.TARGET_HUMIDITY_SWITCH] == expected - assert payload[PortControlKey.TARGET_TEMPERATURE_SWITCH] == expected - assert payload[PortControlKey.TARGET_VPD_SWITCH] == expected + assert payload[PortControlKey.AUTO_TARGET_HUMIDITY_ENABLED] == expected + assert payload[PortControlKey.VPD_TARGET_ENABLED] == expected assert payload[PortControlKey.EC_OR_TDS] == expected assert payload[PortControlKey.MASTER_PORT] == expected diff --git a/tests/test_number.py b/tests/test_number.py index fe7b5b1..d561783 100644 --- a/tests/test_number.py +++ b/tests/test_number.py @@ -43,7 +43,7 @@ async def test_async_setup_all_sensors_created(self, setup): test_objects.entities.add_entities_callback, ) - assert len(test_objects.entities._added_entities) == 79 + assert len(test_objects.entities._added_entities) == 91 @pytest.mark.parametrize( "setting", [PortControlKey.OFF_SPEED, PortControlKey.ON_SPEED] @@ -180,15 +180,16 @@ async def test_async_set_native_value_timer( test_objects.refresh_mock.assert_called() @pytest.mark.parametrize( - "key,label", + "key", [ - (PortControlKey.VPD_HIGH_TRIGGER, "High"), - (PortControlKey.VPD_LOW_TRIGGER, "Low"), + PortControlKey.AUTO_HUMIDITY_LOW_TRIGGER, + PortControlKey.AUTO_HUMIDITY_HIGH_TRIGGER, + PortControlKey.AUTO_TARGET_HUMIDITY, ], ) @pytest.mark.parametrize("port", [1, 2, 3, 4]) - async def test_async_setup_vpd_trigger_setup_for_each_port( - self, setup, key, port, label + async def test_async_setup_humidity_trigger_setup_for_each_port( + self, setup, key, port ): """Setting for vpd trigger setup for each port""" @@ -198,19 +199,37 @@ async def test_async_setup_vpd_trigger_setup_for_each_port( assert entity.device_info is not None @pytest.mark.parametrize( - "setting,enabled_setting", + "key", + [ + PortControlKey.VPD_HIGH_TRIGGER, + PortControlKey.VPD_LOW_TRIGGER, + PortControlKey.VPD_TARGET, + ], + ) + @pytest.mark.parametrize("port", [1, 2, 3, 4]) + async def test_async_setup_vpd_trigger_setup_for_each_port(self, setup, key, port): + """Setting for vpd trigger setup for each port""" + + entity = await execute_and_get_port_entity(setup, async_setup_entry, port, key) + + assert entity.unique_id == f"{DOMAIN}_{MAC_ADDR}_port_{port}_{key}" + assert entity.device_info is not None + + @pytest.mark.parametrize( + "setting", [ - (PortControlKey.VPD_LOW_TRIGGER, PortControlKey.VPD_LOW_ENABLED), - (PortControlKey.VPD_HIGH_TRIGGER, PortControlKey.VPD_HIGH_ENABLED), + PortControlKey.AUTO_HUMIDITY_LOW_TRIGGER, + PortControlKey.AUTO_HUMIDITY_HIGH_TRIGGER, + PortControlKey.AUTO_TARGET_HUMIDITY, ], ) @pytest.mark.parametrize( "value,expected", - [(55, 5.5), (0, 0)], # minutes to seconds + [(55, 55), (0, 0)], # minutes to seconds ) @pytest.mark.parametrize("port", [1, 2, 3, 4]) - async def test_async_update_value_vpd( - self, setup, setting, value, expected, port, enabled_setting + async def test_async_update_value_humidity( + self, setup, setting, value, expected, port ): """Reported sensor value matches the value in the json payload""" @@ -231,6 +250,72 @@ async def test_async_update_value_vpd( [ PortControlKey.VPD_LOW_TRIGGER, PortControlKey.VPD_HIGH_TRIGGER, + PortControlKey.VPD_TARGET, + ], + ) + @pytest.mark.parametrize( + "value,expected", + [(55, 5.5), (0, 0)], # minutes to seconds + ) + @pytest.mark.parametrize("port", [1, 2, 3, 4]) + async def test_async_update_value_vpd(self, setup, setting, value, expected, port): + """Reported sensor value matches the value in the json payload""" + + test_objects: ACTestObjects = setup + entity = await execute_and_get_port_entity( + setup, async_setup_entry, port, setting + ) + + test_objects.ac_infinity._port_controls[(str(DEVICE_ID), port)][setting] = value + entity._handle_coordinator_update() + + assert isinstance(entity, ACInfinityPortNumberEntity) + assert entity.native_value == expected + test_objects.write_ha_mock.assert_called() + + @pytest.mark.parametrize( + "setting", + [ + PortControlKey.AUTO_HUMIDITY_LOW_TRIGGER, + PortControlKey.AUTO_HUMIDITY_HIGH_TRIGGER, + PortControlKey.AUTO_TARGET_HUMIDITY, + ], + ) + @pytest.mark.parametrize( + "expected,value,prev_value", + [(55, 55, 45), (0, 0, 45)], # minutes to seconds + ) + @pytest.mark.parametrize("port", [1, 2, 3, 4]) + async def test_async_set_native_value_humidity( + self, setup, setting, value, expected, port, prev_value + ): + """Reported entity value matches the value in the json payload""" + future: Future = asyncio.Future() + future.set_result(None) + + test_objects: ACTestObjects = setup + + test_objects.ac_infinity._port_controls[(str(DEVICE_ID), port)][ + setting + ] = prev_value + entity = await execute_and_get_port_entity( + setup, async_setup_entry, port, setting + ) + + assert isinstance(entity, ACInfinityPortNumberEntity) + await entity.async_set_native_value(value) + + test_objects.port_control_set_mock.assert_called_with( + str(DEVICE_ID), port, setting, expected + ) + test_objects.refresh_mock.assert_called() + + @pytest.mark.parametrize( + "setting", + [ + PortControlKey.VPD_LOW_TRIGGER, + PortControlKey.VPD_HIGH_TRIGGER, + PortControlKey.VPD_TARGET, ], ) @pytest.mark.parametrize( @@ -346,6 +431,7 @@ async def test_async_set_native_value_cycle_timer( PortControlKey.AUTO_TEMP_LOW_TRIGGER, PortControlKey.AUTO_TEMP_LOW_TRIGGER_F, ), + (PortControlKey.AUTO_TARGET_TEMP, PortControlKey.AUTO_TARGET_TEMP_F), ], ) @pytest.mark.parametrize( @@ -392,6 +478,7 @@ async def test_async_update_temp_trigger_correct( PortControlKey.AUTO_TEMP_LOW_TRIGGER, PortControlKey.AUTO_TEMP_LOW_TRIGGER_F, ), + (PortControlKey.AUTO_TARGET_TEMP, PortControlKey.AUTO_TARGET_TEMP_F), ], ) @pytest.mark.parametrize("port", [1, 2, 3, 4]) diff --git a/tests/test_select.py b/tests/test_select.py index cc5a86c..5d49b7b 100644 --- a/tests/test_select.py +++ b/tests/test_select.py @@ -42,7 +42,7 @@ async def test_async_setup_all_sensors_created(self, setup): test_objects.entities.add_entities_callback, ) - assert len(test_objects.entities._added_entities) == 14 + assert len(test_objects.entities._added_entities) == 22 @pytest.mark.parametrize( "setting", @@ -374,3 +374,70 @@ async def test_async_set_native_value_load_type_unknown_device_type( assert isinstance(entity, ACInfinityPortSelectEntity) with pytest.raises(ValueError): await entity.async_select_option("Pizza") + + @pytest.mark.parametrize( + "setting", [PortControlKey.AUTO_SETTINGS_MODE, PortControlKey.VPD_SETTINGS_MODE] + ) + @pytest.mark.parametrize( + "setting_mode,expected", + [ + (0, "Auto"), + (1, "Target"), + ], + ) + @pytest.mark.parametrize("port", [1, 2, 3, 4]) + async def test_async_update_settings_mode_value_correct( + self, setup, setting_mode, expected, port, setting + ): + """Reported sensor value matches the value in the json payload""" + + test_objects: ACTestObjects = setup + entity = await execute_and_get_port_entity( + setup, + async_setup_entry, + port, + setting, + ) + + test_objects.ac_infinity._port_controls[(str(DEVICE_ID), port)][ + setting + ] = setting_mode + entity._handle_coordinator_update() + + assert isinstance(entity, ACInfinityPortSelectEntity) + assert entity.current_option == expected + test_objects.write_ha_mock.assert_called() + + @pytest.mark.parametrize( + "setting", [PortControlKey.AUTO_SETTINGS_MODE, PortControlKey.VPD_SETTINGS_MODE] + ) + @pytest.mark.parametrize( + "expected,setting_mode_string", + [ + (0, "Auto"), + (1, "Target"), + ], + ) + @pytest.mark.parametrize("port", [1, 2, 3, 4]) + async def test_async_set_native_value_setting_mode( + self, setup, setting_mode_string, expected, port, setting + ): + """Reported sensor value matches the value in the json payload""" + future: Future = asyncio.Future() + future.set_result(None) + + test_objects: ACTestObjects = setup + entity = await execute_and_get_port_entity( + setup, + async_setup_entry, + port, + setting, + ) + + assert isinstance(entity, ACInfinityPortSelectEntity) + await entity.async_select_option(setting_mode_string) + + test_objects.port_control_set_mock.assert_called_with( + str(DEVICE_ID), port, setting, expected + ) + test_objects.refresh_mock.assert_called() diff --git a/tests/test_switch.py b/tests/test_switch.py index cfe9e28..1374284 100644 --- a/tests/test_switch.py +++ b/tests/test_switch.py @@ -41,7 +41,7 @@ async def test_async_setup_all_sensors_created(self, setup): test_objects.entities.add_entities_callback, ) - assert len(test_objects.entities._added_entities) == 36 + assert len(test_objects.entities._added_entities) == 48 @pytest.mark.parametrize( "setting", @@ -50,8 +50,11 @@ async def test_async_setup_all_sensors_created(self, setup): PortControlKey.AUTO_HUMIDITY_LOW_ENABLED, PortControlKey.AUTO_TEMP_HIGH_ENABLED, PortControlKey.AUTO_TEMP_LOW_ENABLED, + PortControlKey.AUTO_TARGET_TEMP_ENABLED, + PortControlKey.AUTO_TARGET_HUMIDITY_ENABLED, PortControlKey.VPD_HIGH_ENABLED, PortControlKey.VPD_LOW_ENABLED, + PortControlKey.VPD_TARGET_ENABLED, PortControlKey.SCHEDULED_START_TIME, PortControlKey.SCHEDULED_END_TIME, AdvancedSettingsKey.SUNRISE_TIMER_ENABLED, @@ -79,8 +82,11 @@ async def test_async_setup_mode_created_for_each_port(self, setup, port, setting (PortControlKey.AUTO_HUMIDITY_LOW_ENABLED, 1, True), (PortControlKey.AUTO_TEMP_HIGH_ENABLED, 1, True), (PortControlKey.AUTO_TEMP_LOW_ENABLED, 1, True), + (PortControlKey.AUTO_TARGET_TEMP_ENABLED, 1, True), + (PortControlKey.AUTO_TARGET_HUMIDITY_ENABLED, 1, True), (PortControlKey.VPD_HIGH_ENABLED, 1, True), (PortControlKey.VPD_LOW_ENABLED, 1, True), + (PortControlKey.VPD_TARGET_ENABLED, 1, True), (PortControlKey.SCHEDULED_START_TIME, SCHEDULE_MIDNIGHT_VALUE, True), (PortControlKey.SCHEDULED_END_TIME, SCHEDULE_MIDNIGHT_VALUE, True), # disabled @@ -88,8 +94,11 @@ async def test_async_setup_mode_created_for_each_port(self, setup, port, setting (PortControlKey.AUTO_HUMIDITY_LOW_ENABLED, 0, False), (PortControlKey.AUTO_TEMP_HIGH_ENABLED, 0, False), (PortControlKey.AUTO_TEMP_LOW_ENABLED, 0, False), + (PortControlKey.AUTO_TARGET_TEMP_ENABLED, 0, False), + (PortControlKey.AUTO_TARGET_HUMIDITY_ENABLED, 0, False), (PortControlKey.VPD_HIGH_ENABLED, 0, False), (PortControlKey.VPD_LOW_ENABLED, 0, False), + (PortControlKey.VPD_TARGET_ENABLED, 0, False), (PortControlKey.SCHEDULED_START_TIME, SCHEDULE_DISABLED_VALUE, False), (PortControlKey.SCHEDULED_END_TIME, SCHEDULE_DISABLED_VALUE, False), ], @@ -157,8 +166,11 @@ async def test_async_update_port_setting_value_correct( (PortControlKey.AUTO_HUMIDITY_LOW_ENABLED, 1), (PortControlKey.AUTO_TEMP_HIGH_ENABLED, 1), (PortControlKey.AUTO_TEMP_LOW_ENABLED, 1), + (PortControlKey.AUTO_TARGET_TEMP_ENABLED, 1), + (PortControlKey.AUTO_TARGET_HUMIDITY_ENABLED, 1), (PortControlKey.VPD_HIGH_ENABLED, 1), (PortControlKey.VPD_LOW_ENABLED, 1), + (PortControlKey.VPD_TARGET_ENABLED, 1), (PortControlKey.SCHEDULED_START_TIME, SCHEDULE_MIDNIGHT_VALUE), (PortControlKey.SCHEDULED_END_TIME, SCHEDULE_EOD_VALUE), ], @@ -225,8 +237,11 @@ async def test_async_turn_on_port_setting( (PortControlKey.AUTO_HUMIDITY_LOW_ENABLED, 0), (PortControlKey.AUTO_TEMP_HIGH_ENABLED, 0), (PortControlKey.AUTO_TEMP_LOW_ENABLED, 0), + (PortControlKey.AUTO_TARGET_TEMP_ENABLED, 0), + (PortControlKey.AUTO_TARGET_HUMIDITY_ENABLED, 0), (PortControlKey.VPD_HIGH_ENABLED, 0), (PortControlKey.VPD_LOW_ENABLED, 0), + (PortControlKey.VPD_TARGET_ENABLED, 0), (PortControlKey.SCHEDULED_START_TIME, SCHEDULE_DISABLED_VALUE), (PortControlKey.SCHEDULED_END_TIME, SCHEDULE_DISABLED_VALUE), ],