From ea3ef0b233aceb4b6eff8da47e5198850be013b5 Mon Sep 17 00:00:00 2001 From: Ryan Mattson Date: Mon, 4 Nov 2024 16:02:49 -0600 Subject: [PATCH] Provide defaults for all get lambda calls to prevent None errors. (#83) * write tests and fix functionality. * bump * precheck issues --- .../ac_infinity/binary_sensor.py | 47 ++- custom_components/ac_infinity/core.py | 92 ----- custom_components/ac_infinity/manifest.json | 2 +- custom_components/ac_infinity/number.py | 319 +++++++++++------- custom_components/ac_infinity/select.py | 121 ++++--- custom_components/ac_infinity/sensor.py | 47 ++- custom_components/ac_infinity/switch.py | 119 ++++--- custom_components/ac_infinity/time.py | 12 +- tests/test_binary_sensor.py | 36 +- tests/test_number.py | 72 ++-- tests/test_sensor.py | 49 ++- tests/test_switch.py | 21 +- 12 files changed, 527 insertions(+), 410 deletions(-) diff --git a/custom_components/ac_infinity/binary_sensor.py b/custom_components/ac_infinity/binary_sensor.py index 3a9c3be..1b55f34 100644 --- a/custom_components/ac_infinity/binary_sensor.py +++ b/custom_components/ac_infinity/binary_sensor.py @@ -22,13 +22,10 @@ ACInfinityControllerReadOnlyMixin, ACInfinityDataUpdateCoordinator, ACInfinityEntities, + ACInfinityEntity, ACInfinityPort, ACInfinityPortEntity, ACInfinityPortReadOnlyMixin, - get_value_fn_controller_property_default, - get_value_fn_port_property_default, - suitable_fn_controller_property_default, - suitable_fn_port_property_default, ) _LOGGER = logging.getLogger(__name__) @@ -58,14 +55,44 @@ class ACInfinityPortBinarySensorEntityDescription( """Describes ACInfinity Binary Sensor Port Entities.""" +def __suitable_fn_controller_property_default( + entity: ACInfinityEntity, controller: ACInfinityController +): + return entity.ac_infinity.get_controller_property_exists( + controller.device_id, entity.entity_description.key + ) + + +def __suitable_fn_port_property_default(entity: ACInfinityEntity, port: ACInfinityPort): + return entity.ac_infinity.get_port_property_exists( + port.controller.device_id, port.port_index, entity.entity_description.key + ) + + +def __get_value_fn_controller_property_default( + entity: ACInfinityEntity, controller: ACInfinityController +): + return entity.ac_infinity.get_controller_property( + controller.device_id, entity.entity_description.key, False + ) + + +def __get_value_fn_port_property_default( + entity: ACInfinityEntity, port: ACInfinityPort +): + return entity.ac_infinity.get_port_property( + port.controller.device_id, port.port_index, entity.entity_description.key, False + ) + + CONTROLLER_DESCRIPTIONS: list[ACInfinityControllerBinarySensorEntityDescription] = [ ACInfinityControllerBinarySensorEntityDescription( key=ControllerPropertyKey.ONLINE, device_class=BinarySensorDeviceClass.CONNECTIVITY, icon="mdi:power-plug", translation_key="controller_online", - suitable_fn=suitable_fn_controller_property_default, - get_value_fn=get_value_fn_controller_property_default, + suitable_fn=__suitable_fn_controller_property_default, + get_value_fn=__get_value_fn_controller_property_default, ) ] @@ -75,16 +102,16 @@ class ACInfinityPortBinarySensorEntityDescription( device_class=BinarySensorDeviceClass.CONNECTIVITY, icon="mdi:power-plug", translation_key="port_online", - suitable_fn=suitable_fn_port_property_default, - get_value_fn=get_value_fn_port_property_default, + suitable_fn=__suitable_fn_port_property_default, + get_value_fn=__get_value_fn_port_property_default, ), ACInfinityPortBinarySensorEntityDescription( key=PortPropertyKey.STATE, device_class=BinarySensorDeviceClass.POWER, icon="mdi:power", translation_key="port_state", - suitable_fn=suitable_fn_port_property_default, - get_value_fn=get_value_fn_port_property_default, + suitable_fn=__suitable_fn_port_property_default, + get_value_fn=__get_value_fn_port_property_default, ), ] diff --git a/custom_components/ac_infinity/core.py b/custom_components/ac_infinity/core.py index 7e52cc9..49ec24f 100644 --- a/custom_components/ac_infinity/core.py +++ b/custom_components/ac_infinity/core.py @@ -784,98 +784,6 @@ class ACInfinityPortReadWriteMixin(ACInfinityPortReadOnlyMixin): """Input data object, device id, port number, and desired value.""" -def suitable_fn_controller_property_default( - entity: ACInfinityEntity, controller: ACInfinityController -): - return entity.ac_infinity.get_controller_property_exists( - controller.device_id, entity.entity_description.key - ) - - -def get_value_fn_controller_property_default( - entity: ACInfinityEntity, controller: ACInfinityController -): - return entity.ac_infinity.get_controller_property( - controller.device_id, entity.entity_description.key - ) - - -def suitable_fn_port_property_default(entity: ACInfinityEntity, port: ACInfinityPort): - return entity.ac_infinity.get_port_property_exists( - port.controller.device_id, port.port_index, entity.entity_description.key - ) - - -def get_value_fn_port_property_default(entity: ACInfinityEntity, port: ACInfinityPort): - return entity.ac_infinity.get_port_property( - port.controller.device_id, port.port_index, entity.entity_description.key - ) - - -def suitable_fn_controller_setting_default( - entity: ACInfinityEntity, controller: ACInfinityController -): - return entity.ac_infinity.get_controller_setting_exists( - controller.device_id, entity.entity_description.key - ) - - -def get_value_fn_controller_setting_default( - entity: ACInfinityEntity, controller: ACInfinityController -): - return entity.ac_infinity.get_controller_setting( - controller.device_id, entity.entity_description.key - ) - - -def set_value_fn_controller_setting_default( - entity: ACInfinityEntity, controller: ACInfinityController, value: int -): - return entity.ac_infinity.update_controller_setting( - controller.device_id, entity.entity_description.key, value - ) - - -def suitable_fn_port_control_default(entity: ACInfinityEntity, port: ACInfinityPort): - return entity.ac_infinity.get_port_control_exists( - port.controller.device_id, port.port_index, entity.entity_description.key - ) - - -def get_value_fn_port_control_default(entity: ACInfinityEntity, port: ACInfinityPort): - return entity.ac_infinity.get_port_control( - port.controller.device_id, port.port_index, entity.entity_description.key - ) - - -def set_value_fn_port_control_default( - entity: ACInfinityEntity, port: ACInfinityPort, value: int -): - return entity.ac_infinity.update_port_control( - port.controller.device_id, port.port_index, entity.entity_description.key, value - ) - - -def suitable_fn_port_setting_default(entity: ACInfinityEntity, port: ACInfinityPort): - return entity.ac_infinity.get_port_setting_exists( - port.controller.device_id, port.port_index, entity.entity_description.key - ) - - -def get_value_fn_port_setting_default(entity: ACInfinityEntity, port: ACInfinityPort): - return entity.ac_infinity.get_port_setting( - port.controller.device_id, port.port_index, entity.entity_description.key - ) - - -def set_value_fn_port_setting_default( - entity: ACInfinityEntity, port: ACInfinityPort, value: int -): - return entity.ac_infinity.update_port_setting( - port.controller.device_id, port.port_index, entity.entity_description.key, value - ) - - class ACInfinityEntities(list[ACInfinityEntity]): def append_if_suitable(self, entity: ACInfinityEntity): if entity.is_suitable: diff --git a/custom_components/ac_infinity/manifest.json b/custom_components/ac_infinity/manifest.json index 3f20645..fde97b9 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.8.0" + "version": "1.8.1" } diff --git a/custom_components/ac_infinity/number.py b/custom_components/ac_infinity/number.py index 7d7b8a8..7b9e02e 100644 --- a/custom_components/ac_infinity/number.py +++ b/custom_components/ac_infinity/number.py @@ -27,15 +27,6 @@ ACInfinityPort, ACInfinityPortEntity, ACInfinityPortReadWriteMixin, - get_value_fn_controller_setting_default, - get_value_fn_port_control_default, - get_value_fn_port_setting_default, - set_value_fn_controller_setting_default, - set_value_fn_port_control_default, - set_value_fn_port_setting_default, - suitable_fn_controller_setting_default, - suitable_fn_port_control_default, - suitable_fn_port_setting_default, ) _LOGGER = logging.getLogger(__name__) @@ -70,15 +61,157 @@ class ACInfinityPortNumberEntityDescription( """Describes ACInfinity Number Port Entities.""" +def __suitable_fn_controller_setting_default( + entity: ACInfinityEntity, controller: ACInfinityController +): + return entity.ac_infinity.get_controller_setting_exists( + controller.device_id, entity.entity_description.key + ) + + +def __suitable_fn_port_control_default(entity: ACInfinityEntity, port: ACInfinityPort): + return entity.ac_infinity.get_port_control_exists( + port.controller.device_id, port.port_index, entity.entity_description.key + ) + + +def __suitable_fn_port_setting_default(entity: ACInfinityEntity, port: ACInfinityPort): + return entity.ac_infinity.get_port_setting_exists( + port.controller.device_id, port.port_index, entity.entity_description.key + ) + + +def __get_value_fn_controller_setting_default( + entity: ACInfinityEntity, controller: ACInfinityController +): + return entity.ac_infinity.get_controller_setting( + controller.device_id, entity.entity_description.key, 0 + ) + + +def __get_value_fn_port_control_default(entity: ACInfinityEntity, port: ACInfinityPort): + return entity.ac_infinity.get_port_control( + port.controller.device_id, port.port_index, entity.entity_description.key, 0 + ) + + +def __get_value_fn_port_setting_default(entity: ACInfinityEntity, port: ACInfinityPort): + return entity.ac_infinity.get_port_setting( + port.controller.device_id, port.port_index, entity.entity_description.key, 0 + ) + + def __get_value_fn_cal_temp(entity: ACInfinityEntity, controller: ACInfinityController): temp_unit = entity.ac_infinity.get_controller_setting( - controller.device_id, AdvancedSettingsKey.TEMP_UNIT + controller.device_id, AdvancedSettingsKey.TEMP_UNIT, 0 ) return entity.ac_infinity.get_controller_setting( controller.device_id, AdvancedSettingsKey.CALIBRATE_TEMP if temp_unit > 0 else AdvancedSettingsKey.CALIBRATE_TEMP_F, + 0, + ) + + +def __get_value_fn_vpd_leaf_temp_offset( + entity: ACInfinityEntity, controller: ACInfinityController +): + temp_unit = entity.ac_infinity.get_controller_setting( + controller.device_id, AdvancedSettingsKey.TEMP_UNIT, 0 + ) + return entity.ac_infinity.get_controller_setting( + controller.device_id, + AdvancedSettingsKey.VPD_LEAF_TEMP_OFFSET + if temp_unit > 0 + else AdvancedSettingsKey.VPD_LEAF_TEMP_OFFSET_F, + 0, + ) + + +def __get_value_fn_timer_duration(entity: ACInfinityEntity, port: ACInfinityPort): + # value configured as minutes but stored as seconds + return ( + entity.ac_infinity.get_port_control( + port.controller.device_id, port.port_index, entity.entity_description.key, 0 + ) + / 60 + ) + + +def __get_value_fn_vpd_control(entity: ACInfinityEntity, port: ACInfinityPort): + # value configured as percent (10.2%) but stored as tenths of a percent (102) + return ( + entity.ac_infinity.get_port_control( + port.controller.device_id, port.port_index, entity.entity_description.key, 0 + ) + / 10 + ) + + +def __get_value_fn_vpd_setting(entity: ACInfinityEntity, port: ACInfinityPort): + # value configured as percent (10.2%) but stored as tenths of a percent (102) + return ( + entity.ac_infinity.get_port_setting( + port.controller.device_id, port.port_index, entity.entity_description.key, 0 + ) + / 10 + ) + + +def __get_value_fn_dynamic_transition_temp( + entity: ACInfinityEntity, port: ACInfinityPort +): + temp_unit = entity.ac_infinity.get_controller_setting( + port.controller.device_id, AdvancedSettingsKey.TEMP_UNIT, 0 + ) + + return entity.ac_infinity.get_port_setting( + port.controller.device_id, + port.port_index, + AdvancedSettingsKey.DYNAMIC_TRANSITION_TEMP + if temp_unit > 0 + else AdvancedSettingsKey.DYNAMIC_TRANSITION_TEMP_F, + 0, + ) + + +def __get_value_fn_dynamic_buffer_temp(entity: ACInfinityEntity, port: ACInfinityPort): + temp_unit = entity.ac_infinity.get_controller_setting( + port.controller.device_id, AdvancedSettingsKey.TEMP_UNIT, 0 + ) + + return entity.ac_infinity.get_port_setting( + port.controller.device_id, + port.port_index, + AdvancedSettingsKey.DYNAMIC_BUFFER_TEMP + if temp_unit > 0 + else AdvancedSettingsKey.DYNAMIC_BUFFER_TEMP_F, + 0, + ) + + +def __set_value_fn_port_setting_default( + entity: ACInfinityEntity, port: ACInfinityPort, value: int +): + return entity.ac_infinity.update_port_setting( + port.controller.device_id, port.port_index, entity.entity_description.key, value + ) + + +def __set_value_fn_port_control_default( + entity: ACInfinityEntity, port: ACInfinityPort, value: int +): + return entity.ac_infinity.update_port_control( + port.controller.device_id, port.port_index, entity.entity_description.key, value + ) + + +def __set_value_fn_controller_setting_default( + entity: ACInfinityEntity, controller: ACInfinityController, value: int +): + return entity.ac_infinity.update_controller_setting( + controller.device_id, entity.entity_description.key, value ) @@ -110,20 +243,6 @@ def __set_value_fn_cal_temp( ) -def __get_value_fn_vpd_leaf_temp_offset( - entity: ACInfinityEntity, controller: ACInfinityController -): - temp_unit = entity.ac_infinity.get_controller_setting( - controller.device_id, AdvancedSettingsKey.TEMP_UNIT - ) - return entity.ac_infinity.get_controller_setting( - controller.device_id, - AdvancedSettingsKey.VPD_LEAF_TEMP_OFFSET - if temp_unit > 0 - else AdvancedSettingsKey.VPD_LEAF_TEMP_OFFSET_F, - ) - - def __set_value_fn_vpd_leaf_temp_offset( entity: ACInfinityEntity, controller: ACInfinityController, value: int ): @@ -147,16 +266,6 @@ def __set_value_fn_vpd_leaf_temp_offset( ) -def __get_value_fn_timer_duration(entity: ACInfinityEntity, port: ACInfinityPort): - # value configured as minutes but stored as seconds - return ( - entity.ac_infinity.get_port_control( - port.controller.device_id, port.port_index, entity.entity_description.key - ) - / 60 - ) - - def __set_value_fn_timer_duration( entity: ACInfinityEntity, port: ACInfinityPort, value: int ): @@ -169,16 +278,6 @@ def __set_value_fn_timer_duration( ) -def __get_value_fn_vpd_control(entity: ACInfinityEntity, port: ACInfinityPort): - # value configured as percent (10.2%) but stored as tenths of a percent (102) - return ( - entity.ac_infinity.get_port_control( - port.controller.device_id, port.port_index, entity.entity_description.key - ) - / 10 - ) - - def __set_value_fn_vpd_control( entity: ACInfinityEntity, port: ACInfinityPort, value: int ): @@ -191,16 +290,6 @@ def __set_value_fn_vpd_control( ) -def __get_value_fn_vpd_setting(entity: ACInfinityEntity, port: ACInfinityPort): - # value configured as percent (10.2%) but stored as tenths of a percent (102) - return ( - entity.ac_infinity.get_port_setting( - port.controller.device_id, port.port_index, entity.entity_description.key - ) - / 10 - ) - - def __set_value_fn_vpd_setting( entity: ACInfinityEntity, port: ACInfinityPort, value: int ): @@ -261,36 +350,6 @@ def __set_value_fn_target_temp( ) -def __get_value_fn_dynamic_transition_temp( - entity: ACInfinityEntity, port: ACInfinityPort -): - temp_unit = entity.ac_infinity.get_controller_setting( - port.controller.device_id, AdvancedSettingsKey.TEMP_UNIT - ) - - return entity.ac_infinity.get_port_setting( - port.controller.device_id, - port.port_index, - AdvancedSettingsKey.DYNAMIC_TRANSITION_TEMP - if temp_unit > 0 - else AdvancedSettingsKey.DYNAMIC_TRANSITION_TEMP_F, - ) - - -def __get_value_fn_dynamic_buffer_temp(entity: ACInfinityEntity, port: ACInfinityPort): - temp_unit = entity.ac_infinity.get_controller_setting( - port.controller.device_id, AdvancedSettingsKey.TEMP_UNIT - ) - - return entity.ac_infinity.get_port_setting( - port.controller.device_id, - port.port_index, - AdvancedSettingsKey.DYNAMIC_BUFFER_TEMP - if temp_unit > 0 - else AdvancedSettingsKey.DYNAMIC_BUFFER_TEMP_F, - ) - - def __set_value_fn_dynamic_transition_temp( entity: ACInfinityEntity, port: ACInfinityPort, value: int ): @@ -356,7 +415,7 @@ def __set_value_fn_dynamic_buffer_temp( icon="mdi:thermometer-plus", translation_key="temperature_calibration", native_unit_of_measurement=None, - suitable_fn=suitable_fn_controller_setting_default, + suitable_fn=__suitable_fn_controller_setting_default, get_value_fn=__get_value_fn_cal_temp, set_value_fn=__set_value_fn_cal_temp, ), @@ -370,9 +429,9 @@ def __set_value_fn_dynamic_buffer_temp( icon="mdi:cloud-percent-outline", translation_key="humidity_calibration", native_unit_of_measurement=None, - suitable_fn=suitable_fn_controller_setting_default, - get_value_fn=get_value_fn_controller_setting_default, - set_value_fn=set_value_fn_controller_setting_default, + suitable_fn=__suitable_fn_controller_setting_default, + get_value_fn=__get_value_fn_controller_setting_default, + set_value_fn=__set_value_fn_controller_setting_default, ), ACInfinityControllerNumberEntityDescription( key=AdvancedSettingsKey.VPD_LEAF_TEMP_OFFSET, @@ -384,7 +443,7 @@ def __set_value_fn_dynamic_buffer_temp( icon="mdi:leaf", translation_key="vpd_leaf_temperature_offset", native_unit_of_measurement=None, - suitable_fn=suitable_fn_controller_setting_default, + suitable_fn=__suitable_fn_controller_setting_default, get_value_fn=__get_value_fn_vpd_leaf_temp_offset, set_value_fn=__set_value_fn_vpd_leaf_temp_offset, ), @@ -401,9 +460,9 @@ def __set_value_fn_dynamic_buffer_temp( icon="mdi:knob", translation_key="on_power", 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, + 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.OFF_SPEED, @@ -415,9 +474,9 @@ def __set_value_fn_dynamic_buffer_temp( icon="mdi:knob", translation_key="off_power", 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, + 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.TIMER_DURATION_TO_ON, @@ -429,7 +488,7 @@ def __set_value_fn_dynamic_buffer_temp( icon=None, # default translation_key="timer_mode_minutes_to_on", native_unit_of_measurement=None, - suitable_fn=suitable_fn_port_control_default, + suitable_fn=__suitable_fn_port_control_default, get_value_fn=__get_value_fn_timer_duration, set_value_fn=__set_value_fn_timer_duration, ), @@ -443,7 +502,7 @@ def __set_value_fn_dynamic_buffer_temp( icon=None, # default translation_key="timer_mode_minutes_to_off", native_unit_of_measurement=None, - suitable_fn=suitable_fn_port_control_default, + suitable_fn=__suitable_fn_port_control_default, get_value_fn=__get_value_fn_timer_duration, set_value_fn=__set_value_fn_timer_duration, ), @@ -457,7 +516,7 @@ def __set_value_fn_dynamic_buffer_temp( icon=None, # default translation_key="cycle_mode_minutes_on", native_unit_of_measurement=None, - suitable_fn=suitable_fn_port_control_default, + suitable_fn=__suitable_fn_port_control_default, get_value_fn=__get_value_fn_timer_duration, set_value_fn=__set_value_fn_timer_duration, ), @@ -471,7 +530,7 @@ def __set_value_fn_dynamic_buffer_temp( icon=None, # default translation_key="cycle_mode_minutes_off", native_unit_of_measurement=None, - suitable_fn=suitable_fn_port_control_default, + suitable_fn=__suitable_fn_port_control_default, get_value_fn=__get_value_fn_timer_duration, set_value_fn=__set_value_fn_timer_duration, ), @@ -485,7 +544,7 @@ def __set_value_fn_dynamic_buffer_temp( icon="mdi:water-thermometer-outline", translation_key="vpd_mode_low_trigger", native_unit_of_measurement=None, - suitable_fn=suitable_fn_port_control_default, + suitable_fn=__suitable_fn_port_control_default, get_value_fn=__get_value_fn_vpd_control, set_value_fn=__set_value_fn_vpd_control, ), @@ -499,7 +558,7 @@ def __set_value_fn_dynamic_buffer_temp( icon="mdi:water-thermometer-outline", translation_key="vpd_mode_high_trigger", native_unit_of_measurement=None, - suitable_fn=suitable_fn_port_control_default, + suitable_fn=__suitable_fn_port_control_default, get_value_fn=__get_value_fn_vpd_control, set_value_fn=__set_value_fn_vpd_control, ), @@ -513,7 +572,7 @@ def __set_value_fn_dynamic_buffer_temp( icon="mdi:water-thermometer-outline", translation_key="target_vpd", native_unit_of_measurement=None, - suitable_fn=suitable_fn_port_control_default, + suitable_fn=__suitable_fn_port_control_default, get_value_fn=__get_value_fn_vpd_control, set_value_fn=__set_value_fn_vpd_control, ), @@ -527,9 +586,9 @@ def __set_value_fn_dynamic_buffer_temp( icon="mdi:water-percent", translation_key="auto_mode_humidity_low_trigger", 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, + 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_HUMIDITY_HIGH_TRIGGER, @@ -541,9 +600,9 @@ def __set_value_fn_dynamic_buffer_temp( icon="mdi:water-percent", translation_key="auto_mode_humidity_high_trigger", 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, + 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_TARGET_HUMIDITY, @@ -555,9 +614,9 @@ def __set_value_fn_dynamic_buffer_temp( 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, + 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, @@ -569,8 +628,8 @@ def __set_value_fn_dynamic_buffer_temp( native_step=1, icon=None, translation_key="auto_mode_temp_low_trigger", - suitable_fn=suitable_fn_port_control_default, - get_value_fn=get_value_fn_port_control_default, + suitable_fn=__suitable_fn_port_control_default, + get_value_fn=__get_value_fn_port_control_default, set_value_fn=__set_value_fn_temp_auto_low, ), ACInfinityPortNumberEntityDescription( @@ -583,8 +642,8 @@ def __set_value_fn_dynamic_buffer_temp( native_step=1, icon=None, translation_key="auto_mode_temp_high_trigger", - suitable_fn=suitable_fn_port_control_default, - get_value_fn=get_value_fn_port_control_default, + suitable_fn=__suitable_fn_port_control_default, + get_value_fn=__get_value_fn_port_control_default, set_value_fn=__set_value_fn_temp_auto_high, ), ACInfinityPortNumberEntityDescription( @@ -597,8 +656,8 @@ def __set_value_fn_dynamic_buffer_temp( 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, + 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( @@ -611,7 +670,7 @@ def __set_value_fn_dynamic_buffer_temp( icon="mdi:thermometer-plus", translation_key="dynamic_transition_temp", native_unit_of_measurement=None, - suitable_fn=suitable_fn_port_setting_default, + suitable_fn=__suitable_fn_port_setting_default, get_value_fn=__get_value_fn_dynamic_transition_temp, set_value_fn=__set_value_fn_dynamic_transition_temp, ), @@ -625,9 +684,9 @@ def __set_value_fn_dynamic_buffer_temp( icon="mdi:cloud-percent-outline", translation_key="dynamic_transition_humidity", native_unit_of_measurement=None, - suitable_fn=suitable_fn_port_setting_default, - get_value_fn=get_value_fn_port_setting_default, - set_value_fn=set_value_fn_port_setting_default, + suitable_fn=__suitable_fn_port_setting_default, + get_value_fn=__get_value_fn_port_setting_default, + set_value_fn=__set_value_fn_port_setting_default, ), ACInfinityPortNumberEntityDescription( key=AdvancedSettingsKey.DYNAMIC_TRANSITION_VPD, @@ -639,7 +698,7 @@ def __set_value_fn_dynamic_buffer_temp( icon="mdi:leaf", translation_key="dynamic_transition_vpd", native_unit_of_measurement=None, - suitable_fn=suitable_fn_port_setting_default, + suitable_fn=__suitable_fn_port_setting_default, get_value_fn=__get_value_fn_vpd_setting, set_value_fn=__set_value_fn_vpd_setting, ), @@ -653,7 +712,7 @@ def __set_value_fn_dynamic_buffer_temp( icon="mdi:thermometer-plus", translation_key="dynamic_buffer_temp", native_unit_of_measurement=None, - suitable_fn=suitable_fn_port_setting_default, + suitable_fn=__suitable_fn_port_setting_default, get_value_fn=__get_value_fn_dynamic_buffer_temp, set_value_fn=__set_value_fn_dynamic_buffer_temp, ), @@ -667,9 +726,9 @@ def __set_value_fn_dynamic_buffer_temp( icon="mdi:cloud-percent-outline", translation_key="dynamic_buffer_humidity", native_unit_of_measurement=None, - suitable_fn=suitable_fn_port_setting_default, - get_value_fn=get_value_fn_port_setting_default, - set_value_fn=set_value_fn_port_setting_default, + suitable_fn=__suitable_fn_port_setting_default, + get_value_fn=__get_value_fn_port_setting_default, + set_value_fn=__set_value_fn_port_setting_default, ), ACInfinityPortNumberEntityDescription( key=AdvancedSettingsKey.DYNAMIC_BUFFER_VPD, @@ -681,7 +740,7 @@ def __set_value_fn_dynamic_buffer_temp( icon="mdi:leaf", translation_key="dynamic_buffer_vpd", native_unit_of_measurement=None, - suitable_fn=suitable_fn_port_setting_default, + suitable_fn=__suitable_fn_port_setting_default, get_value_fn=__get_value_fn_vpd_setting, set_value_fn=__set_value_fn_vpd_setting, ), @@ -695,9 +754,9 @@ def __set_value_fn_dynamic_buffer_temp( icon=None, # default translation_key="sunrise_timer_minutes", native_unit_of_measurement=None, - suitable_fn=suitable_fn_port_control_default, - get_value_fn=get_value_fn_port_setting_default, - set_value_fn=set_value_fn_port_setting_default, + suitable_fn=__suitable_fn_port_control_default, + get_value_fn=__get_value_fn_port_setting_default, + set_value_fn=__set_value_fn_port_setting_default, ), ] diff --git a/custom_components/ac_infinity/select.py b/custom_components/ac_infinity/select.py index b0f1189..5a5676c 100644 --- a/custom_components/ac_infinity/select.py +++ b/custom_components/ac_infinity/select.py @@ -21,9 +21,6 @@ ACInfinityPort, ACInfinityPortEntity, ACInfinityPortReadWriteMixin, - suitable_fn_controller_setting_default, - suitable_fn_port_control_default, - suitable_fn_port_setting_default, ) _LOGGER = logging.getLogger(__name__) @@ -81,6 +78,26 @@ class ACInfinityPortSelectEntityDescription( ] +def __suitable_fn_controller_setting_default( + entity: ACInfinityEntity, controller: ACInfinityController +): + return entity.ac_infinity.get_controller_setting_exists( + controller.device_id, entity.entity_description.key + ) + + +def __suitable_fn_port_control_default(entity: ACInfinityEntity, port: ACInfinityPort): + return entity.ac_infinity.get_port_control_exists( + port.controller.device_id, port.port_index, entity.entity_description.key + ) + + +def __suitable_fn_port_setting_default(entity: ACInfinityEntity, port: ACInfinityPort): + return entity.ac_infinity.get_port_setting_exists( + port.controller.device_id, port.port_index, entity.entity_description.key + ) + + def __get_value_fn_outside_climate( entity: ACInfinityEntity, controller: ACInfinityController ): @@ -91,16 +108,6 @@ def __get_value_fn_outside_climate( ] -def __set_value_fn_outside_climate( - entity: ACInfinityEntity, controller: ACInfinityController, value: str -): - return entity.ac_infinity.update_controller_setting( - controller.device_id, - entity.entity_description.key, - OUTSIDE_CLIMATE_OPTIONS.index(value), - ) - - def __get_value_fn_setting_mode(entity: ACInfinityEntity, port: ACInfinityPort): return SETTINGS_MODE_OPTIONS[ entity.ac_infinity.get_port_control( @@ -109,17 +116,6 @@ def __get_value_fn_setting_mode(entity: ACInfinityEntity, port: ACInfinityPort): ] -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 @@ -130,18 +126,6 @@ def __get_value_fn_active_mode(entity: ACInfinityEntity, port: ACInfinityPort): ] -def __set_value_fn_active_mode( - entity: ACInfinityEntity, port: ACInfinityPort, value: str -): - return entity.ac_infinity.update_port_control( - port.controller.device_id, - port.port_index, - PortControlKey.AT_TYPE, - # data is 1 based. Adjust from 0 based enum by adding 1 - MODE_OPTIONS.index(value) + 1, - ) - - def __get_value_fn_dynamic_response_type( entity: ACInfinityEntity, port: ACInfinityPort ): @@ -155,26 +139,59 @@ def __get_value_fn_dynamic_response_type( ] -def __set_value_fn_dynamic_response_type( +def __get_value_fn_device_load_type(entity: ACInfinityEntity, port: ACInfinityPort): + value = entity.ac_infinity.get_port_setting( + port.controller.device_id, + port.port_index, + AdvancedSettingsKey.DEVICE_LOAD_TYPE, + 1, + ) + + return DEVICE_LOAD_TYPE_OPTIONS.get(value, "Unknown Device Type") + + +def __set_value_fn_outside_climate( + entity: ACInfinityEntity, controller: ACInfinityController, value: str +): + return entity.ac_infinity.update_controller_setting( + controller.device_id, + entity.entity_description.key, + OUTSIDE_CLIMATE_OPTIONS.index(value), + ) + + +def __set_value_fn_setting_mode( entity: ACInfinityEntity, port: ACInfinityPort, value: str ): - return entity.ac_infinity.update_port_setting( + return entity.ac_infinity.update_port_control( port.controller.device_id, port.port_index, - AdvancedSettingsKey.DYNAMIC_RESPONSE_TYPE, - DYNAMIC_RESPONSE_OPTIONS.index(value), + entity.entity_description.key, + SETTINGS_MODE_OPTIONS.index(value), ) -def __get_value_fn_device_load_type(entity: ACInfinityEntity, port: ACInfinityPort): - value = entity.ac_infinity.get_port_setting( +def __set_value_fn_active_mode( + entity: ACInfinityEntity, port: ACInfinityPort, value: str +): + return entity.ac_infinity.update_port_control( port.controller.device_id, port.port_index, - AdvancedSettingsKey.DEVICE_LOAD_TYPE, - 1, + PortControlKey.AT_TYPE, + # data is 1 based. Adjust from 0 based enum by adding 1 + MODE_OPTIONS.index(value) + 1, ) - return DEVICE_LOAD_TYPE_OPTIONS.get(value, "Unknown Device Type") + +def __set_value_fn_dynamic_response_type( + entity: ACInfinityEntity, port: ACInfinityPort, value: str +): + return entity.ac_infinity.update_port_setting( + port.controller.device_id, + port.port_index, + AdvancedSettingsKey.DYNAMIC_RESPONSE_TYPE, + DYNAMIC_RESPONSE_OPTIONS.index(value), + ) def __set_value_fn_device_load_type( @@ -197,7 +214,7 @@ def __set_value_fn_device_load_type( key=AdvancedSettingsKey.OUTSIDE_TEMP_COMPARE, translation_key="outside_climate_temperature", options=OUTSIDE_CLIMATE_OPTIONS, - suitable_fn=suitable_fn_controller_setting_default, + suitable_fn=__suitable_fn_controller_setting_default, get_value_fn=__get_value_fn_outside_climate, set_value_fn=__set_value_fn_outside_climate, ), @@ -205,7 +222,7 @@ def __set_value_fn_device_load_type( key=AdvancedSettingsKey.OUTSIDE_HUMIDITY_COMPARE, translation_key="outside_climate_humidity", options=OUTSIDE_CLIMATE_OPTIONS, - suitable_fn=suitable_fn_controller_setting_default, + suitable_fn=__suitable_fn_controller_setting_default, get_value_fn=__get_value_fn_outside_climate, set_value_fn=__set_value_fn_outside_climate, ), @@ -216,7 +233,7 @@ def __set_value_fn_device_load_type( key=PortControlKey.AT_TYPE, translation_key="active_mode", options=MODE_OPTIONS, - suitable_fn=suitable_fn_port_control_default, + suitable_fn=__suitable_fn_port_control_default, get_value_fn=__get_value_fn_active_mode, set_value_fn=__set_value_fn_active_mode, ), @@ -224,7 +241,7 @@ def __set_value_fn_device_load_type( key=PortControlKey.AUTO_SETTINGS_MODE, translation_key="auto_settings_mode", options=SETTINGS_MODE_OPTIONS, - suitable_fn=suitable_fn_port_control_default, + suitable_fn=__suitable_fn_port_control_default, get_value_fn=__get_value_fn_setting_mode, set_value_fn=__set_value_fn_setting_mode, ), @@ -232,7 +249,7 @@ def __set_value_fn_device_load_type( key=PortControlKey.VPD_SETTINGS_MODE, translation_key="vpd_settings_mode", options=SETTINGS_MODE_OPTIONS, - suitable_fn=suitable_fn_port_control_default, + suitable_fn=__suitable_fn_port_control_default, get_value_fn=__get_value_fn_setting_mode, set_value_fn=__set_value_fn_setting_mode, ), @@ -240,7 +257,7 @@ def __set_value_fn_device_load_type( key=AdvancedSettingsKey.DEVICE_LOAD_TYPE, translation_key="device_load_type", options=list(DEVICE_LOAD_TYPE_OPTIONS.values()), - suitable_fn=suitable_fn_port_setting_default, + suitable_fn=__suitable_fn_port_setting_default, get_value_fn=__get_value_fn_device_load_type, set_value_fn=__set_value_fn_device_load_type, ), @@ -248,7 +265,7 @@ def __set_value_fn_device_load_type( key=AdvancedSettingsKey.DYNAMIC_RESPONSE_TYPE, translation_key="dynamic_response_type", options=DYNAMIC_RESPONSE_OPTIONS, - suitable_fn=suitable_fn_port_setting_default, + suitable_fn=__suitable_fn_port_setting_default, get_value_fn=__get_value_fn_dynamic_response_type, set_value_fn=__set_value_fn_dynamic_response_type, ), diff --git a/custom_components/ac_infinity/sensor.py b/custom_components/ac_infinity/sensor.py index 302e1da..9ea4aeb 100644 --- a/custom_components/ac_infinity/sensor.py +++ b/custom_components/ac_infinity/sensor.py @@ -31,9 +31,6 @@ ACInfinityPort, ACInfinityPortEntity, ACInfinityPortReadOnlyMixin, - get_value_fn_port_property_default, - suitable_fn_controller_property_default, - suitable_fn_port_property_default, ) from .const import ( @@ -73,19 +70,21 @@ class ACInfinityPortSensorEntityDescription( """Describes ACInfinity Number Sensor Entities.""" -def __get_value_fn_floating_point_as_int( +def __suitable_fn_controller_property_default( entity: ACInfinityEntity, controller: ACInfinityController ): - # value stored as an integer, but represents a 2 digit precision float - return ( - entity.ac_infinity.get_controller_property( - controller.device_id, entity.entity_description.key - ) - / 100 + return entity.ac_infinity.get_controller_property_exists( + controller.device_id, entity.entity_description.key ) -def __get_value_fn_port_property_default_zero( +def __suitable_fn_port_property_default(entity: ACInfinityEntity, port: ACInfinityPort): + return entity.ac_infinity.get_port_property_exists( + port.controller.device_id, port.port_index, entity.entity_description.key + ) + + +def __get_value_fn_port_property_default( entity: ACInfinityEntity, port: ACInfinityPort ): return entity.ac_infinity.get_port_property( @@ -93,6 +92,18 @@ def __get_value_fn_port_property_default_zero( ) +def __get_value_fn_floating_point_as_int( + entity: ACInfinityEntity, controller: ACInfinityController +): + # value stored as an integer, but represents a 2 digit precision float + return ( + entity.ac_infinity.get_controller_property( + controller.device_id, entity.entity_description.key, 0 + ) + / 100 + ) + + def __get_next_mode_change_timestamp( entity: ACInfinityEntity, port: ACInfinityPort ) -> datetime | None: @@ -119,7 +130,7 @@ def __get_next_mode_change_timestamp( icon=None, # default translation_key="temperature", suggested_unit_of_measurement=None, - suitable_fn=suitable_fn_controller_property_default, + suitable_fn=__suitable_fn_controller_property_default, get_value_fn=__get_value_fn_floating_point_as_int, ), ACInfinityControllerSensorEntityDescription( @@ -130,7 +141,7 @@ def __get_next_mode_change_timestamp( icon=None, # default translation_key="humidity", suggested_unit_of_measurement=None, - suitable_fn=suitable_fn_controller_property_default, + suitable_fn=__suitable_fn_controller_property_default, get_value_fn=__get_value_fn_floating_point_as_int, ), ACInfinityControllerSensorEntityDescription( @@ -141,7 +152,7 @@ def __get_next_mode_change_timestamp( native_unit_of_measurement=UnitOfPressure.KPA, icon="mdi:water-thermometer", translation_key="vapor_pressure_deficit", - suitable_fn=suitable_fn_controller_property_default, + suitable_fn=__suitable_fn_controller_property_default, get_value_fn=__get_value_fn_floating_point_as_int, ), ] @@ -155,8 +166,8 @@ def __get_next_mode_change_timestamp( icon=None, # default translation_key="current_power", suggested_unit_of_measurement=None, - suitable_fn=suitable_fn_port_property_default, - get_value_fn=get_value_fn_port_property_default, + suitable_fn=__suitable_fn_port_property_default, + get_value_fn=__get_value_fn_port_property_default, ), ACInfinityPortSensorEntityDescription( key=PortPropertyKey.REMAINING_TIME, @@ -166,8 +177,8 @@ def __get_next_mode_change_timestamp( translation_key="remaining_time", suggested_unit_of_measurement=None, state_class=None, - suitable_fn=suitable_fn_port_property_default, - get_value_fn=__get_value_fn_port_property_default_zero, + suitable_fn=__suitable_fn_port_property_default, + get_value_fn=__get_value_fn_port_property_default, ), ACInfinityPortSensorEntityDescription( key=CustomPortPropertyKey.NEXT_STATE_CHANGE, diff --git a/custom_components/ac_infinity/switch.py b/custom_components/ac_infinity/switch.py index 9405f1d..a62eb38 100644 --- a/custom_components/ac_infinity/switch.py +++ b/custom_components/ac_infinity/switch.py @@ -25,12 +25,6 @@ ACInfinityPort, ACInfinityPortEntity, ACInfinityPortReadWriteMixin, - get_value_fn_port_control_default, - get_value_fn_port_setting_default, - set_value_fn_port_control_default, - set_value_fn_port_setting_default, - suitable_fn_port_control_default, - suitable_fn_port_setting_default, ) _LOGGER = logging.getLogger(__name__) @@ -65,15 +59,58 @@ class ACInfinityPortSwitchEntityDescription( """Describes ACInfinity Switch Entities.""" +def __suitable_fn_port_setting_default(entity: ACInfinityEntity, port: ACInfinityPort): + return entity.ac_infinity.get_port_setting_exists( + port.controller.device_id, port.port_index, entity.entity_description.key + ) + + +def __suitable_fn_port_control_default(entity: ACInfinityEntity, port: ACInfinityPort): + return entity.ac_infinity.get_port_control_exists( + port.controller.device_id, port.port_index, entity.entity_description.key + ) + + +def __get_value_fn_port_control_default(entity: ACInfinityEntity, port: ACInfinityPort): + return entity.ac_infinity.get_port_control( + port.controller.device_id, port.port_index, entity.entity_description.key, 0 + ) + + +def __get_value_fn_port_setting_default(entity: ACInfinityEntity, port: ACInfinityPort): + return entity.ac_infinity.get_port_setting( + port.controller.device_id, port.port_index, entity.entity_description.key, 0 + ) + + def __get_value_fn_schedule_enabled(entity: ACInfinityEntity, port: ACInfinityPort): return ( entity.ac_infinity.get_port_control( - port.controller.device_id, port.port_index, entity.entity_description.key + port.controller.device_id, + port.port_index, + entity.entity_description.key, + SCHEDULE_DISABLED_VALUE, ) < SCHEDULE_EOD_VALUE + 1 ) +def __set_value_fn_port_control_default( + entity: ACInfinityEntity, port: ACInfinityPort, value: int +): + return entity.ac_infinity.update_port_control( + port.controller.device_id, port.port_index, entity.entity_description.key, value + ) + + +def __set_value_fn_port_setting_default( + entity: ACInfinityEntity, port: ACInfinityPort, value: int +): + return entity.ac_infinity.update_port_setting( + port.controller.device_id, port.port_index, entity.entity_description.key, value + ) + + PORT_DESCRIPTIONS: list[ACInfinityPortSwitchEntityDescription] = [ ACInfinityPortSwitchEntityDescription( key=PortControlKey.VPD_HIGH_ENABLED, @@ -82,9 +119,9 @@ def __get_value_fn_schedule_enabled(entity: ACInfinityEntity, port: ACInfinityPo off_value=0, icon=None, # default translation_key="vpd_mode_high_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, + 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.VPD_LOW_ENABLED, @@ -93,9 +130,9 @@ def __get_value_fn_schedule_enabled(entity: ACInfinityEntity, port: ACInfinityPo off_value=0, icon=None, # default translation_key="vpd_mode_low_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, + 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.VPD_TARGET_ENABLED, @@ -104,9 +141,9 @@ def __get_value_fn_schedule_enabled(entity: ACInfinityEntity, port: ACInfinityPo 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, + 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, @@ -115,9 +152,9 @@ def __get_value_fn_schedule_enabled(entity: ACInfinityEntity, port: ACInfinityPo off_value=0, icon=None, # default translation_key="auto_mode_temp_high_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, + 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_LOW_ENABLED, @@ -126,9 +163,9 @@ def __get_value_fn_schedule_enabled(entity: ACInfinityEntity, port: ACInfinityPo off_value=0, icon=None, # default translation_key="auto_mode_temp_low_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, + 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_HUMIDITY_HIGH_ENABLED, @@ -137,9 +174,9 @@ def __get_value_fn_schedule_enabled(entity: ACInfinityEntity, port: ACInfinityPo off_value=0, icon=None, # default translation_key="auto_mode_humidity_high_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, + 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_HUMIDITY_LOW_ENABLED, @@ -148,9 +185,9 @@ def __get_value_fn_schedule_enabled(entity: ACInfinityEntity, port: ACInfinityPo off_value=0, icon=None, # default translation_key="auto_mode_humidity_low_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, + 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_TEMP_ENABLED, @@ -159,9 +196,9 @@ def __get_value_fn_schedule_enabled(entity: ACInfinityEntity, port: ACInfinityPo 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, + 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, @@ -170,9 +207,9 @@ def __get_value_fn_schedule_enabled(entity: ACInfinityEntity, port: ACInfinityPo 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, + 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, @@ -181,9 +218,9 @@ def __get_value_fn_schedule_enabled(entity: ACInfinityEntity, port: ACInfinityPo off_value=SCHEDULE_DISABLED_VALUE, icon=None, # default translation_key="schedule_mode_on_time_enabled", - suitable_fn=suitable_fn_port_control_default, + suitable_fn=__suitable_fn_port_control_default, get_value_fn=__get_value_fn_schedule_enabled, - set_value_fn=set_value_fn_port_control_default, + set_value_fn=__set_value_fn_port_control_default, ), ACInfinityPortSwitchEntityDescription( key=PortControlKey.SCHEDULED_END_TIME, @@ -192,9 +229,9 @@ def __get_value_fn_schedule_enabled(entity: ACInfinityEntity, port: ACInfinityPo off_value=SCHEDULE_DISABLED_VALUE, icon=None, # default translation_key="schedule_mode_off_time_enabled", - suitable_fn=suitable_fn_port_control_default, + suitable_fn=__suitable_fn_port_control_default, get_value_fn=__get_value_fn_schedule_enabled, - set_value_fn=set_value_fn_port_control_default, + set_value_fn=__set_value_fn_port_control_default, ), ACInfinityPortSwitchEntityDescription( key=AdvancedSettingsKey.SUNRISE_TIMER_ENABLED, @@ -203,9 +240,9 @@ def __get_value_fn_schedule_enabled(entity: ACInfinityEntity, port: ACInfinityPo off_value=0, icon=None, # default translation_key="sunrise_timer_enabled", - suitable_fn=suitable_fn_port_setting_default, - get_value_fn=get_value_fn_port_setting_default, - set_value_fn=set_value_fn_port_setting_default, + suitable_fn=__suitable_fn_port_setting_default, + get_value_fn=__get_value_fn_port_setting_default, + set_value_fn=__set_value_fn_port_setting_default, ), ] diff --git a/custom_components/ac_infinity/time.py b/custom_components/ac_infinity/time.py index 3c6ef7b..6f5df26 100644 --- a/custom_components/ac_infinity/time.py +++ b/custom_components/ac_infinity/time.py @@ -20,7 +20,6 @@ ACInfinityPort, ACInfinityPortEntity, ACInfinityPortReadWriteMixin, - suitable_fn_port_control_default, ) _LOGGER = logging.getLogger(__name__) @@ -63,12 +62,19 @@ class ACInfinityPortTimeEntityDescription( """Describes ACInfinity Time Entities.""" +def __suitable_fn_port_control_default(entity: ACInfinityEntity, port: ACInfinityPort): + return entity.ac_infinity.get_port_control_exists( + port.controller.device_id, port.port_index, entity.entity_description.key + ) + + def __get_value_fn_time(entity: ACInfinityEntity, port: ACInfinityPort): return __get_time_from_total_minutes( entity.ac_infinity.get_port_control( port.controller.device_id, port.port_index, entity.entity_description.key, + None, ) ) @@ -87,7 +93,7 @@ def __set_value_fn_time(entity: ACInfinityEntity, port: ACInfinityPort, value: t key=PortControlKey.SCHEDULED_START_TIME, icon=None, # default translation_key="schedule_mode_on_time", - suitable_fn=suitable_fn_port_control_default, + suitable_fn=__suitable_fn_port_control_default, get_value_fn=__get_value_fn_time, set_value_fn=__set_value_fn_time, ), @@ -95,7 +101,7 @@ def __set_value_fn_time(entity: ACInfinityEntity, port: ACInfinityPort, value: t key=PortControlKey.SCHEDULED_END_TIME, icon=None, # default translation_key="schedule_mode_off_time", - suitable_fn=suitable_fn_port_control_default, + suitable_fn=__suitable_fn_port_control_default, get_value_fn=__get_value_fn_time, set_value_fn=__set_value_fn_time, ), diff --git a/tests/test_binary_sensor.py b/tests/test_binary_sensor.py index 5c0ca18..3d6838d 100644 --- a/tests/test_binary_sensor.py +++ b/tests/test_binary_sensor.py @@ -24,7 +24,7 @@ execute_and_get_port_entity, setup_entity_mocks, ) -from tests.data_models import MAC_ADDR +from tests.data_models import DEVICE_ID, MAC_ADDR @pytest.fixture @@ -81,32 +81,47 @@ async def test_async_setup_entry_entity_created_for_each_port( assert sensor.entity_description.device_class == expected_class assert sensor.device_info is not None - async def test_async_update_entity_controller_value_correct(self, setup): + @pytest.mark.parametrize( + "value,expected", + [ + (None, False), + (0, False), + (1, True), + ], + ) + async def test_async_update_entity_controller_value_correct( + self, setup, value, expected + ): """Reported sensor value matches the value in the json payload""" test_objects: ACTestObjects = setup sensor: ACInfinityControllerEntity = await execute_and_get_controller_entity( setup, async_setup_entry, ControllerPropertyKey.ONLINE ) + + test_objects.ac_infinity._controller_properties[str(DEVICE_ID)][ + ControllerPropertyKey.ONLINE + ] = value + sensor._handle_coordinator_update() assert isinstance(sensor, ACInfinityControllerBinarySensorEntity) - assert sensor.is_on + assert sensor.is_on == expected test_objects.write_ha_mock.assert_called() @pytest.mark.parametrize("setting", [PortPropertyKey.STATE, PortPropertyKey.ONLINE]) + @pytest.mark.parametrize("port", [1, 2, 3, 4]) @pytest.mark.parametrize( - "port,expected", + "value,expected", [ + (None, False), + (0, False), (1, True), - (2, True), - (3, True), - (4, False), ], ) async def test_async_update_entity_port_value_correct( - self, setup, port, setting, expected + self, setup, port, setting, value, expected ): """Reported sensor value matches the value in the json payload""" @@ -114,6 +129,11 @@ async def test_async_update_entity_port_value_correct( sensor: ACInfinityPortEntity = await execute_and_get_port_entity( setup, async_setup_entry, port, setting ) + + test_objects.ac_infinity._port_properties[(str(DEVICE_ID), port)][ + setting + ] = value + sensor._handle_coordinator_update() assert isinstance(sensor, ACInfinityPortBinarySensorEntity) diff --git a/tests/test_number.py b/tests/test_number.py index d561783..2ab2700 100644 --- a/tests/test_number.py +++ b/tests/test_number.py @@ -67,16 +67,21 @@ async def test_async_setup_entry_current_speed_created_for_each_port( assert entity.device_info is not None @pytest.mark.parametrize( - "setting,expected", - [(PortControlKey.OFF_SPEED, 0), (PortControlKey.ON_SPEED, 5)], + "setting", + [PortControlKey.OFF_SPEED, PortControlKey.ON_SPEED], ) + @pytest.mark.parametrize("port", [1, 2, 3, 4]) + @pytest.mark.parametrize("value,expected", [(None, 0), (0, 0), (7, 7)]) async def test_async_update_current_speed_value_correct( - self, setup, setting, expected + self, setup, setting, port, value, expected ): """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, 1, setting) + 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) @@ -124,7 +129,7 @@ async def test_async_setup_timer_created_for_each_port(self, setup, key, port): ) @pytest.mark.parametrize( "value,expected", - [(86400, 1440), (1440, 24), (0, 0)], # minutes to seconds + [(86400, 1440), (1440, 24), (0, 0), (None, 0)], # minutes to seconds ) @pytest.mark.parametrize("port", [1, 2, 3, 4]) async def test_async_update_timer_value_correct( @@ -225,7 +230,7 @@ async def test_async_setup_vpd_trigger_setup_for_each_port(self, setup, key, por ) @pytest.mark.parametrize( "value,expected", - [(55, 55), (0, 0)], # minutes to seconds + [(55, 55), (0, 0), (None, 0)], # minutes to seconds ) @pytest.mark.parametrize("port", [1, 2, 3, 4]) async def test_async_update_value_humidity( @@ -255,7 +260,7 @@ async def test_async_update_value_humidity( ) @pytest.mark.parametrize( "value,expected", - [(55, 5.5), (0, 0)], # minutes to seconds + [(55, 5.5), (0, 0), (None, 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): @@ -366,7 +371,7 @@ async def test_async_setup_cycle_timer_created_for_each_port( ) @pytest.mark.parametrize( "value,expected", - [(86400, 1440), (1440, 24), (0, 0)], # minutes to seconds + [(86400, 1440), (1440, 24), (0, 0), (None, 0)], # minutes to seconds ) @pytest.mark.parametrize("port", [1, 2, 3, 4]) async def test_async_update_cycle_timer_value_correct( @@ -421,31 +426,24 @@ async def test_async_set_native_value_cycle_timer( test_objects.refresh_mock.assert_called() @pytest.mark.parametrize( - "setting, f_setting", + "setting", [ - ( - PortControlKey.AUTO_TEMP_HIGH_TRIGGER, - PortControlKey.AUTO_TEMP_HIGH_TRIGGER_F, - ), - ( - PortControlKey.AUTO_TEMP_LOW_TRIGGER, - PortControlKey.AUTO_TEMP_LOW_TRIGGER_F, - ), - (PortControlKey.AUTO_TARGET_TEMP, PortControlKey.AUTO_TARGET_TEMP_F), + PortControlKey.AUTO_TEMP_HIGH_TRIGGER, + PortControlKey.AUTO_TEMP_LOW_TRIGGER, + PortControlKey.AUTO_TARGET_TEMP, ], ) @pytest.mark.parametrize( - "c,f", - [(0, 32), (90, 194), (46, 115)], + "value, expected", + [(0, 0), (90, 90), (None, 0)], ) @pytest.mark.parametrize("port", [1, 2, 3, 4]) async def test_async_update_temp_trigger_correct( self, setup, setting, - f_setting, - c, - f, + value, + expected, port, ): """Reported sensor value matches the value in the json payload""" @@ -455,12 +453,11 @@ async def test_async_update_temp_trigger_correct( setup, async_setup_entry, port, setting ) - test_objects.ac_infinity._port_controls[(str(DEVICE_ID), port)][setting] = c - test_objects.ac_infinity._port_controls[(str(DEVICE_ID), port)][f_setting] = f + test_objects.ac_infinity._port_controls[(str(DEVICE_ID), port)][setting] = value entity._handle_coordinator_update() assert isinstance(entity, ACInfinityPortNumberEntity) - assert entity.native_value == c + assert entity.native_value == expected test_objects.write_ha_mock.assert_called() @pytest.mark.parametrize( @@ -568,8 +565,11 @@ async def test_async_setup_entry_humidity_calibration_created(self, setup): AdvancedSettingsKey.CALIBRATE_HUMIDITY, ], ) - @pytest.mark.parametrize("value", [-10, 0, 5]) - async def test_async_update_calibration(self, setup, setting, value): + @pytest.mark.parametrize("value,expected", [(-10, -10), (0, 0), (5, 5), (None, 0)]) + @pytest.mark.parametrize("port", [1, 2, 3, 4]) + async def test_async_update_calibration( + self, setup, setting, value, expected, port + ): """Reported sensor value matches the value in the json payload""" test_objects: ACTestObjects = setup @@ -577,11 +577,13 @@ async def test_async_update_calibration(self, setup, setting, value): setup, async_setup_entry, setting ) - test_objects.ac_infinity._device_settings[(str(DEVICE_ID), 0)][setting] = value + test_objects.ac_infinity._device_settings[(str(DEVICE_ID), port)][ + setting + ] = value entity._handle_coordinator_update() assert isinstance(entity, ACInfinityControllerNumberEntity) - assert entity.native_value == value + assert entity.native_value == expected test_objects.write_ha_mock.assert_called() @pytest.mark.parametrize( @@ -771,11 +773,17 @@ async def test_async_setup_dynamic_humidity_vpd_setup_for_each_port( "setting,value,expected", [ (AdvancedSettingsKey.DYNAMIC_TRANSITION_TEMP, 8, 8), + (AdvancedSettingsKey.DYNAMIC_TRANSITION_TEMP, None, 0), (AdvancedSettingsKey.DYNAMIC_TRANSITION_HUMIDITY, 8, 8), + (AdvancedSettingsKey.DYNAMIC_TRANSITION_HUMIDITY, None, 0), (AdvancedSettingsKey.DYNAMIC_TRANSITION_VPD, 8, 0.8), + (AdvancedSettingsKey.DYNAMIC_TRANSITION_VPD, None, 0), (AdvancedSettingsKey.DYNAMIC_BUFFER_TEMP, 8, 8), + (AdvancedSettingsKey.DYNAMIC_BUFFER_TEMP, None, 0), (AdvancedSettingsKey.DYNAMIC_BUFFER_HUMIDITY, 8, 8), + (AdvancedSettingsKey.DYNAMIC_BUFFER_HUMIDITY, None, 0), (AdvancedSettingsKey.DYNAMIC_BUFFER_VPD, 8, 0.8), + (AdvancedSettingsKey.DYNAMIC_BUFFER_VPD, None, 0), ], ) @pytest.mark.parametrize("port", [1, 2, 3, 4]) @@ -874,10 +882,10 @@ async def test_async_set_native_value_dynamic_response_temp( AdvancedSettingsKey.DYNAMIC_BUFFER_HUMIDITY, ], ) - @pytest.mark.parametrize("value", [0, 5, 10]) + @pytest.mark.parametrize("value,expected", [(0, 0), (5, 5), (10, 10), (None, 0)]) @pytest.mark.parametrize("port", [1, 2, 3, 4]) async def test_async_set_native_value_dynamic_response_humidity( - self, setup, value, port, setting + self, setup, value, expected, port, setting ): """Reported sensor value matches the value in the json payload""" future: Future = asyncio.Future() diff --git a/tests/test_sensor.py b/tests/test_sensor.py index 2588dd6..7ea50f2 100644 --- a/tests/test_sensor.py +++ b/tests/test_sensor.py @@ -70,16 +70,23 @@ async def test_async_setup_entry_temperature_created(self, setup): ) assert entity.device_info is not None - async def test_async_update_temperature_value_correct(self, setup): + @pytest.mark.parametrize("value,expected", [(0, 0), (3215, 32.15), (None, 0)]) + async def test_async_update_temperature_value_correct(self, setup, value, expected): """Reported sensor value matches the value in the json payload""" + test_objects: ACTestObjects = setup entity = await execute_and_get_controller_entity( setup, async_setup_entry, ControllerPropertyKey.TEMPERATURE ) + + test_objects.ac_infinity._controller_properties[str(DEVICE_ID)][ + ControllerPropertyKey.TEMPERATURE + ] = value + entity._handle_coordinator_update() assert isinstance(entity, ACInfinityControllerSensorEntity) - assert entity.native_value == 24.17 + assert entity.native_value == expected async def test_async_setup_entry_humidity_created(self, setup): """Sensor for device reported humidity is created on setup""" @@ -97,16 +104,22 @@ async def test_async_setup_entry_humidity_created(self, setup): assert entity.device_info is not None - async def test_async_update_humidity_value_correct(self, setup): + @pytest.mark.parametrize("value,expected", [(0, 0), (3215, 32.15), (None, 0)]) + async def test_async_update_humidity_value_correct(self, setup, value, expected): """Reported sensor value matches the value in the json payload""" + test_objects: ACTestObjects = setup entity = await execute_and_get_controller_entity( setup, async_setup_entry, ControllerPropertyKey.HUMIDITY ) + + test_objects.ac_infinity._controller_properties[str(DEVICE_ID)][ + ControllerPropertyKey.HUMIDITY + ] = value entity._handle_coordinator_update() assert isinstance(entity, ACInfinityControllerSensorEntity) - assert entity.native_value == 72 + assert entity.native_value == expected async def test_async_setup_entry_vpd_created(self, setup): """Sensor for device reported humidity is created on setup""" @@ -127,16 +140,22 @@ async def test_async_setup_entry_vpd_created(self, setup): ) assert entity.device_info is not None - async def test_async_update_vpd_value_correct(self, setup): + @pytest.mark.parametrize("value,expected", [(0, 0), (105, 1.05), (None, 0)]) + async def test_async_update_vpd_value_correct(self, setup, value, expected): """Reported sensor value matches the value in the json payload""" + test_objects: ACTestObjects = setup entity = await execute_and_get_controller_entity( setup, async_setup_entry, ControllerPropertyKey.VPD ) + + test_objects.ac_infinity._controller_properties[str(DEVICE_ID)][ + ControllerPropertyKey.VPD + ] = value entity._handle_coordinator_update() assert isinstance(entity, ACInfinityControllerSensorEntity) - assert entity.native_value == 0.83 + assert entity.native_value == expected @pytest.mark.parametrize("port", [1, 2, 3, 4]) async def test_async_setup_entry_current_power_created_for_each_port( @@ -184,23 +203,17 @@ async def test_async_setup_next_state_change_for_each_port(self, setup, port): assert entity.entity_description.device_class == SensorDeviceClass.TIMESTAMP assert entity.device_info is not None - @pytest.mark.parametrize( - "port,expected", - [ - (1, 5), - (2, 7), - (3, 5), - (4, 0), - ], - ) + @pytest.mark.parametrize("value,expected", [(0, 0), (3, 3), (None, 0)]) + @pytest.mark.parametrize("port", [1, 2, 3, 4]) async def test_async_update_current_power_value_correct( - self, setup, port, expected + self, setup, port, value, expected ): """Reported sensor value matches the value in the json payload""" test_objects: ACTestObjects = setup - test_objects.ac_infinity._port_controls[(str(DEVICE_ID), port)][ + test_objects.ac_infinity._port_properties[(str(DEVICE_ID), port)][ PortPropertyKey.SPEAK - ] = expected + ] = value + entity = await execute_and_get_port_entity( setup, async_setup_entry, port, PortPropertyKey.SPEAK ) diff --git a/tests/test_switch.py b/tests/test_switch.py index 1374284..1cc8e7d 100644 --- a/tests/test_switch.py +++ b/tests/test_switch.py @@ -101,6 +101,18 @@ async def test_async_setup_mode_created_for_each_port(self, setup, port, setting (PortControlKey.VPD_TARGET_ENABLED, 0, False), (PortControlKey.SCHEDULED_START_TIME, SCHEDULE_DISABLED_VALUE, False), (PortControlKey.SCHEDULED_END_TIME, SCHEDULE_DISABLED_VALUE, False), + # None + (PortControlKey.AUTO_HUMIDITY_HIGH_ENABLED, None, False), + (PortControlKey.AUTO_HUMIDITY_LOW_ENABLED, None, False), + (PortControlKey.AUTO_TEMP_HIGH_ENABLED, None, False), + (PortControlKey.AUTO_TEMP_LOW_ENABLED, None, False), + (PortControlKey.AUTO_TARGET_TEMP_ENABLED, None, False), + (PortControlKey.AUTO_TARGET_HUMIDITY_ENABLED, None, False), + (PortControlKey.VPD_HIGH_ENABLED, None, False), + (PortControlKey.VPD_LOW_ENABLED, None, False), + (PortControlKey.VPD_TARGET_ENABLED, None, False), + (PortControlKey.SCHEDULED_START_TIME, None, False), + (PortControlKey.SCHEDULED_END_TIME, None, False), ], ) @pytest.mark.parametrize("port", [1, 2, 3, 4]) @@ -132,20 +144,19 @@ async def test_async_update_port_control_value_correct( (AdvancedSettingsKey.SUNRISE_TIMER_ENABLED, 1, True), # disabled (AdvancedSettingsKey.SUNRISE_TIMER_ENABLED, 0, False), + # None + (AdvancedSettingsKey.SUNRISE_TIMER_ENABLED, None, False), ], ) @pytest.mark.parametrize("port", [1, 2, 3, 4]) async def test_async_update_port_setting_value_correct( - self, setup, setting, expected, port, value + 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, + setup, async_setup_entry, port, setting ) test_objects.ac_infinity._device_settings[(str(DEVICE_ID), port)][