Add PresenceFeatureManager ok
This commit is contained in:
@@ -175,6 +175,8 @@ class FeaturePresenceManager(BaseFeatureManager):
|
|||||||
def presence_state(self) -> str | None:
|
def presence_state(self) -> str | None:
|
||||||
"""Return the current presence state STATE_ON or STATE_OFF
|
"""Return the current presence state STATE_ON or STATE_OFF
|
||||||
or STATE_UNAVAILABLE if not configured"""
|
or STATE_UNAVAILABLE if not configured"""
|
||||||
|
if not self._is_configured:
|
||||||
|
return STATE_UNAVAILABLE
|
||||||
return self._presence_state
|
return self._presence_state
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -185,5 +187,10 @@ class FeaturePresenceManager(BaseFeatureManager):
|
|||||||
STATE_OFF,
|
STATE_OFF,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def presence_sensor_entity_id(self) -> bool:
|
||||||
|
"""Return true if the presence is configured and presence sensor is OFF"""
|
||||||
|
return self._presence_sensor_entity_id
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"PresenceManager-{self.name}"
|
return f"PresenceManager-{self.name}"
|
||||||
|
|||||||
@@ -419,7 +419,7 @@ async def test_presence_binary_sensors(
|
|||||||
await entity.async_set_preset_mode(PRESET_COMFORT)
|
await entity.async_set_preset_mode(PRESET_COMFORT)
|
||||||
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
await entity.async_set_hvac_mode(HVACMode.HEAT)
|
||||||
await send_temperature_change_event(entity, 15, now)
|
await send_temperature_change_event(entity, 15, now)
|
||||||
assert entity.presence_state is None
|
assert entity.presence_state is STATE_UNKNOWN
|
||||||
|
|
||||||
await presence_binary_sensor.async_my_climate_changed()
|
await presence_binary_sensor.async_my_climate_changed()
|
||||||
assert presence_binary_sensor.state is STATE_OFF
|
assert presence_binary_sensor.state is STATE_OFF
|
||||||
|
|||||||
@@ -295,7 +295,10 @@ async def test_full_over_switch_wo_central_config(
|
|||||||
assert entity._power_sensor_entity_id == "sensor.mock_power_sensor"
|
assert entity._power_sensor_entity_id == "sensor.mock_power_sensor"
|
||||||
assert entity._max_power_sensor_entity_id == "sensor.mock_max_power_sensor"
|
assert entity._max_power_sensor_entity_id == "sensor.mock_max_power_sensor"
|
||||||
|
|
||||||
assert entity._presence_sensor_entity_id == "binary_sensor.mock_presence_sensor"
|
assert (
|
||||||
|
entity._presence_manager.presence_sensor_entity_id
|
||||||
|
== "binary_sensor.mock_presence_sensor"
|
||||||
|
)
|
||||||
|
|
||||||
entity.remove_thermostat()
|
entity.remove_thermostat()
|
||||||
|
|
||||||
@@ -409,7 +412,10 @@ async def test_full_over_switch_with_central_config(
|
|||||||
assert entity._power_sensor_entity_id == "sensor.mock_power_sensor"
|
assert entity._power_sensor_entity_id == "sensor.mock_power_sensor"
|
||||||
assert entity._max_power_sensor_entity_id == "sensor.mock_max_power_sensor"
|
assert entity._max_power_sensor_entity_id == "sensor.mock_max_power_sensor"
|
||||||
|
|
||||||
assert entity._presence_sensor_entity_id == "binary_sensor.mock_presence_sensor"
|
assert (
|
||||||
|
entity._presence_manager.presence_sensor_entity_id
|
||||||
|
== "binary_sensor.mock_presence_sensor"
|
||||||
|
)
|
||||||
|
|
||||||
entity.remove_thermostat()
|
entity.remove_thermostat()
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ async def test_movement_management_time_not_enough(
|
|||||||
# because no motion is detected yet
|
# because no motion is detected yet
|
||||||
assert entity.target_temperature == 18
|
assert entity.target_temperature == 18
|
||||||
assert entity.motion_state is None
|
assert entity.motion_state is None
|
||||||
assert entity.presence_state is None
|
assert entity.presence_state is STATE_UNKNOWN
|
||||||
|
|
||||||
event_timestamp = now - timedelta(minutes=5)
|
event_timestamp = now - timedelta(minutes=5)
|
||||||
await send_temperature_change_event(entity, 18, event_timestamp)
|
await send_temperature_change_event(entity, 18, event_timestamp)
|
||||||
@@ -283,7 +283,7 @@ async def test_movement_management_time_enough_and_presence(
|
|||||||
# because no motion is detected yet
|
# because no motion is detected yet
|
||||||
assert entity.target_temperature == 18
|
assert entity.target_temperature == 18
|
||||||
assert entity.motion_state is None
|
assert entity.motion_state is None
|
||||||
assert entity.presence_state is None
|
assert entity.presence_state is STATE_UNKNOWN
|
||||||
|
|
||||||
event_timestamp = now - timedelta(minutes=4)
|
event_timestamp = now - timedelta(minutes=4)
|
||||||
await send_temperature_change_event(entity, 18, event_timestamp)
|
await send_temperature_change_event(entity, 18, event_timestamp)
|
||||||
@@ -313,8 +313,7 @@ async def test_movement_management_time_enough_and_presence(
|
|||||||
# because motion is detected yet -> switch to Boost mode
|
# because motion is detected yet -> switch to Boost mode
|
||||||
assert entity.target_temperature == 19
|
assert entity.target_temperature == 19
|
||||||
assert entity.motion_state == "on"
|
assert entity.motion_state == "on"
|
||||||
assert entity.presence_state == "on"
|
assert entity.presence_state == STATE_ON
|
||||||
|
|
||||||
assert mock_send_event.call_count == 0
|
assert mock_send_event.call_count == 0
|
||||||
# Change is confirmed. Heater should be started
|
# Change is confirmed. Heater should be started
|
||||||
assert mock_heater_on.call_count == 1
|
assert mock_heater_on.call_count == 1
|
||||||
@@ -342,7 +341,7 @@ async def test_movement_management_time_enough_and_presence(
|
|||||||
# because no motion is detected yet
|
# because no motion is detected yet
|
||||||
assert entity.target_temperature == 18
|
assert entity.target_temperature == 18
|
||||||
assert entity.motion_state == "off"
|
assert entity.motion_state == "off"
|
||||||
assert entity.presence_state == "on"
|
assert entity.presence_state == STATE_ON
|
||||||
|
|
||||||
assert mock_send_event.call_count == 0
|
assert mock_send_event.call_count == 0
|
||||||
assert mock_heater_on.call_count == 0
|
assert mock_heater_on.call_count == 0
|
||||||
@@ -415,7 +414,7 @@ async def test_movement_management_time_enoughand_not_presence(
|
|||||||
# because no motion is detected yet and presence is unknown
|
# because no motion is detected yet and presence is unknown
|
||||||
assert entity.target_temperature == 18
|
assert entity.target_temperature == 18
|
||||||
assert entity.motion_state is None
|
assert entity.motion_state is None
|
||||||
assert entity.presence_state is None
|
assert entity.presence_state is STATE_UNKNOWN
|
||||||
|
|
||||||
event_timestamp = now - timedelta(minutes=4)
|
event_timestamp = now - timedelta(minutes=4)
|
||||||
await send_temperature_change_event(entity, 18, event_timestamp)
|
await send_temperature_change_event(entity, 18, event_timestamp)
|
||||||
@@ -445,7 +444,7 @@ async def test_movement_management_time_enoughand_not_presence(
|
|||||||
# because motion is detected yet -> switch to Boost away mode
|
# because motion is detected yet -> switch to Boost away mode
|
||||||
assert entity.target_temperature == 19.1
|
assert entity.target_temperature == 19.1
|
||||||
assert entity.motion_state == "on"
|
assert entity.motion_state == "on"
|
||||||
assert entity.presence_state == "off"
|
assert entity.presence_state == STATE_OFF
|
||||||
|
|
||||||
assert mock_send_event.call_count == 0
|
assert mock_send_event.call_count == 0
|
||||||
# Change is confirmed. Heater should be started
|
# Change is confirmed. Heater should be started
|
||||||
@@ -474,8 +473,7 @@ async def test_movement_management_time_enoughand_not_presence(
|
|||||||
# because no motion is detected yet
|
# because no motion is detected yet
|
||||||
assert entity.target_temperature == 18.1
|
assert entity.target_temperature == 18.1
|
||||||
assert entity.motion_state == "off"
|
assert entity.motion_state == "off"
|
||||||
assert entity.presence_state == "off"
|
assert entity.presence_state == STATE_OFF
|
||||||
|
|
||||||
assert mock_send_event.call_count == 0
|
assert mock_send_event.call_count == 0
|
||||||
# 18.1 starts heating with a low on_percent
|
# 18.1 starts heating with a low on_percent
|
||||||
assert mock_heater_on.call_count == 1
|
assert mock_heater_on.call_count == 1
|
||||||
@@ -549,7 +547,7 @@ async def test_movement_management_with_stop_during_condition(
|
|||||||
# because no motion is detected yet
|
# because no motion is detected yet
|
||||||
assert entity.target_temperature == 18
|
assert entity.target_temperature == 18
|
||||||
assert entity.motion_state is None
|
assert entity.motion_state is None
|
||||||
assert entity.presence_state is None
|
assert entity.presence_state is STATE_UNKNOWN
|
||||||
|
|
||||||
event_timestamp = now - timedelta(minutes=6)
|
event_timestamp = now - timedelta(minutes=6)
|
||||||
await send_temperature_change_event(entity, 18, event_timestamp)
|
await send_temperature_change_event(entity, 18, event_timestamp)
|
||||||
@@ -583,8 +581,7 @@ async def test_movement_management_with_stop_during_condition(
|
|||||||
# because motion is detected yet -> switch to Boost mode
|
# because motion is detected yet -> switch to Boost mode
|
||||||
assert entity.target_temperature == 18
|
assert entity.target_temperature == 18
|
||||||
assert entity.motion_state is None
|
assert entity.motion_state is None
|
||||||
assert entity.presence_state == "off"
|
assert entity.presence_state == STATE_OFF
|
||||||
|
|
||||||
# Send a stop detection
|
# Send a stop detection
|
||||||
event_timestamp = now - timedelta(minutes=4)
|
event_timestamp = now - timedelta(minutes=4)
|
||||||
try_condition = await send_motion_change_event(
|
try_condition = await send_motion_change_event(
|
||||||
@@ -596,7 +593,7 @@ async def test_movement_management_with_stop_during_condition(
|
|||||||
assert entity.preset_mode is PRESET_ACTIVITY
|
assert entity.preset_mode is PRESET_ACTIVITY
|
||||||
assert entity.target_temperature == 18
|
assert entity.target_temperature == 18
|
||||||
assert entity.motion_state is None
|
assert entity.motion_state is None
|
||||||
assert entity.presence_state == "off"
|
assert entity.presence_state == STATE_OFF
|
||||||
|
|
||||||
# Resend a start detection
|
# Resend a start detection
|
||||||
event_timestamp = now - timedelta(minutes=3)
|
event_timestamp = now - timedelta(minutes=3)
|
||||||
@@ -612,13 +609,13 @@ async def test_movement_management_with_stop_during_condition(
|
|||||||
# still no motion detected
|
# still no motion detected
|
||||||
assert entity.target_temperature == 18
|
assert entity.target_temperature == 18
|
||||||
assert entity.motion_state is None
|
assert entity.motion_state is None
|
||||||
assert entity.presence_state == "off"
|
assert entity.presence_state == STATE_OFF
|
||||||
|
|
||||||
await try_condition1(None)
|
await try_condition1(None)
|
||||||
# We should have switch this time
|
# We should have switch this time
|
||||||
assert entity.target_temperature == 19 # Boost
|
assert entity.target_temperature == 19 # Boost
|
||||||
assert entity.motion_state == "on" # switch to movement on
|
assert entity.motion_state == "on" # switch to movement on
|
||||||
assert entity.presence_state == "off" # Non change
|
assert entity.presence_state == STATE_OFF # Non change
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
@pytest.mark.parametrize("expected_lingering_tasks", [True])
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ async def test_over_climate_valve_mono(hass: HomeAssistant, skip_hass_states_get
|
|||||||
assert vtherm._security_state is False
|
assert vtherm._security_state is False
|
||||||
assert vtherm._window_state is None
|
assert vtherm._window_state is None
|
||||||
assert vtherm._motion_state is None
|
assert vtherm._motion_state is None
|
||||||
assert vtherm._presence_state is None
|
assert vtherm.presence_state is STATE_UNKNOWN
|
||||||
|
|
||||||
assert vtherm.is_device_active is False
|
assert vtherm.is_device_active is False
|
||||||
assert vtherm.valve_open_percent == 0
|
assert vtherm.valve_open_percent == 0
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ async def test_over_switch_full_start(hass: HomeAssistant, skip_hass_states_is_s
|
|||||||
assert entity._security_state is False
|
assert entity._security_state is False
|
||||||
assert entity._window_state is None
|
assert entity._window_state is None
|
||||||
assert entity._motion_state is None
|
assert entity._motion_state is None
|
||||||
assert entity._presence_state is None
|
assert entity.presence_state is STATE_UNKNOWN
|
||||||
assert entity._prop_algorithm is not None
|
assert entity._prop_algorithm is not None
|
||||||
assert entity.have_valve_regulation is False
|
assert entity.have_valve_regulation is False
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ async def test_over_climate_full_start(hass: HomeAssistant, skip_hass_states_is_
|
|||||||
assert entity._security_state is False
|
assert entity._security_state is False
|
||||||
assert entity._window_state is None
|
assert entity._window_state is None
|
||||||
assert entity._motion_state is None
|
assert entity._motion_state is None
|
||||||
assert entity._presence_state is None
|
assert entity.presence_state is STATE_UNAVAILABLE
|
||||||
assert entity.have_valve_regulation is False
|
assert entity.have_valve_regulation is False
|
||||||
|
|
||||||
# should have been called with EventType.PRESET_EVENT and EventType.HVAC_MODE_EVENT
|
# should have been called with EventType.PRESET_EVENT and EventType.HVAC_MODE_EVENT
|
||||||
@@ -183,7 +183,7 @@ async def test_over_4switch_full_start(hass: HomeAssistant, skip_hass_states_is_
|
|||||||
assert entity._security_state is False
|
assert entity._security_state is False
|
||||||
assert entity._window_state is None
|
assert entity._window_state is None
|
||||||
assert entity._motion_state is None
|
assert entity._motion_state is None
|
||||||
assert entity._presence_state is None
|
assert entity.presence_state is STATE_UNKNOWN
|
||||||
assert entity._prop_algorithm is not None
|
assert entity._prop_algorithm is not None
|
||||||
|
|
||||||
assert entity.nb_underlying_entities == 4
|
assert entity.nb_underlying_entities == 4
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ async def test_over_switch_ac_full_start(
|
|||||||
assert entity._security_state is False # pylint: disable=protected-access
|
assert entity._security_state is False # pylint: disable=protected-access
|
||||||
assert entity._window_state is None # pylint: disable=protected-access
|
assert entity._window_state is None # pylint: disable=protected-access
|
||||||
assert entity._motion_state is None # pylint: disable=protected-access
|
assert entity._motion_state is None # pylint: disable=protected-access
|
||||||
assert entity._presence_state is None # pylint: disable=protected-access
|
assert entity.presence_state is STATE_UNKNOWN
|
||||||
assert entity._prop_algorithm is not None # pylint: disable=protected-access
|
assert entity._prop_algorithm is not None # pylint: disable=protected-access
|
||||||
|
|
||||||
# should have been called with EventType.PRESET_EVENT and EventType.HVAC_MODE_EVENT
|
# should have been called with EventType.PRESET_EVENT and EventType.HVAC_MODE_EVENT
|
||||||
@@ -114,7 +114,7 @@ async def test_over_switch_ac_full_start(
|
|||||||
|
|
||||||
event_timestamp = now - timedelta(minutes=4)
|
event_timestamp = now - timedelta(minutes=4)
|
||||||
await send_presence_change_event(entity, True, False, event_timestamp)
|
await send_presence_change_event(entity, True, False, event_timestamp)
|
||||||
assert entity._presence_state == STATE_ON # pylint: disable=protected-access
|
assert entity.presence_state == STATE_ON # pylint: disable=protected-access
|
||||||
|
|
||||||
await entity.async_set_hvac_mode(HVACMode.COOL)
|
await entity.async_set_hvac_mode(HVACMode.COOL)
|
||||||
assert entity.hvac_mode is HVACMode.COOL
|
assert entity.hvac_mode is HVACMode.COOL
|
||||||
@@ -131,7 +131,7 @@ async def test_over_switch_ac_full_start(
|
|||||||
# Unset the presence
|
# Unset the presence
|
||||||
event_timestamp = now - timedelta(minutes=3)
|
event_timestamp = now - timedelta(minutes=3)
|
||||||
await send_presence_change_event(entity, False, True, event_timestamp)
|
await send_presence_change_event(entity, False, True, event_timestamp)
|
||||||
assert entity._presence_state == STATE_OFF # pylint: disable=protected-access
|
assert entity.presence_state == STATE_OFF # pylint: disable=protected-access
|
||||||
assert entity.target_temperature == 27 # eco_ac_away
|
assert entity.target_temperature == 27 # eco_ac_away
|
||||||
|
|
||||||
# Open a window
|
# Open a window
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ async def test_over_valve_full_start(
|
|||||||
assert entity._security_state is False # pylint: disable=protected-access
|
assert entity._security_state is False # pylint: disable=protected-access
|
||||||
assert entity._window_state is None # pylint: disable=protected-access
|
assert entity._window_state is None # pylint: disable=protected-access
|
||||||
assert entity._motion_state is None # pylint: disable=protected-access
|
assert entity._motion_state is None # pylint: disable=protected-access
|
||||||
assert entity._presence_state is None # pylint: disable=protected-access
|
assert entity.presence_state is STATE_UNKNOWN
|
||||||
assert entity._prop_algorithm is not None # pylint: disable=protected-access
|
assert entity._prop_algorithm is not None # pylint: disable=protected-access
|
||||||
assert entity.have_valve_regulation is False
|
assert entity.have_valve_regulation is False
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user