mirror of
https://github.com/home-assistant/core.git
synced 2026-04-21 00:49:54 +02:00
Skip Tuya update if it is not relevent (#160407)
This commit is contained in:
@@ -463,6 +463,11 @@ class TuyaBinarySensorEntity(TuyaEntity, BinarySensorEntity):
|
||||
self._attr_unique_id = f"{super().unique_id}{description.key}"
|
||||
self._dpcode_wrapper = dpcode_wrapper
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool | None:
|
||||
"""Return true if sensor is on."""
|
||||
return self._read_wrapper(self._dpcode_wrapper)
|
||||
|
||||
async def _handle_state_update(
|
||||
self,
|
||||
updated_status_properties: list[str] | None,
|
||||
@@ -472,8 +477,3 @@ class TuyaBinarySensorEntity(TuyaEntity, BinarySensorEntity):
|
||||
if self._dpcode_wrapper.skip_update(self.device, updated_status_properties):
|
||||
return
|
||||
self.async_write_ha_state()
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool | None:
|
||||
"""Return true if sensor is on."""
|
||||
return self._read_wrapper(self._dpcode_wrapper)
|
||||
|
||||
@@ -551,6 +551,16 @@ class TuyaNumberEntity(TuyaEntity, NumberEntity):
|
||||
"""Return the entity value to represent the entity state."""
|
||||
return self._read_wrapper(self._dpcode_wrapper)
|
||||
|
||||
async def _handle_state_update(
|
||||
self,
|
||||
updated_status_properties: list[str] | None,
|
||||
dp_timestamps: dict | None = None,
|
||||
) -> None:
|
||||
"""Handle state update, only if this entity's dpcode was actually updated."""
|
||||
if self._dpcode_wrapper.skip_update(self.device, updated_status_properties):
|
||||
return
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_native_value(self, value: float) -> None:
|
||||
"""Set new value."""
|
||||
await self._async_send_wrapper_updates(self._dpcode_wrapper, value)
|
||||
|
||||
@@ -407,6 +407,16 @@ class TuyaSelectEntity(TuyaEntity, SelectEntity):
|
||||
"""Return the selected entity option to represent the entity state."""
|
||||
return self._read_wrapper(self._dpcode_wrapper)
|
||||
|
||||
async def _handle_state_update(
|
||||
self,
|
||||
updated_status_properties: list[str] | None,
|
||||
dp_timestamps: dict | None = None,
|
||||
) -> None:
|
||||
"""Handle state update, only if this entity's dpcode was actually updated."""
|
||||
if self._dpcode_wrapper.skip_update(self.device, updated_status_properties):
|
||||
return
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_select_option(self, option: str) -> None:
|
||||
"""Change the selected option."""
|
||||
await self._async_send_wrapper_updates(self._dpcode_wrapper, option)
|
||||
|
||||
@@ -1849,3 +1849,13 @@ class TuyaSensorEntity(TuyaEntity, SensorEntity):
|
||||
def native_value(self) -> StateType:
|
||||
"""Return the value reported by the sensor."""
|
||||
return self._read_wrapper(self._dpcode_wrapper)
|
||||
|
||||
async def _handle_state_update(
|
||||
self,
|
||||
updated_status_properties: list[str] | None,
|
||||
dp_timestamps: dict | None = None,
|
||||
) -> None:
|
||||
"""Handle state update, only if this entity's dpcode was actually updated."""
|
||||
if self._dpcode_wrapper.skip_update(self.device, updated_status_properties):
|
||||
return
|
||||
self.async_write_ha_state()
|
||||
|
||||
@@ -107,6 +107,16 @@ class TuyaSirenEntity(TuyaEntity, SirenEntity):
|
||||
"""Return true if siren is on."""
|
||||
return self._read_wrapper(self._dpcode_wrapper)
|
||||
|
||||
async def _handle_state_update(
|
||||
self,
|
||||
updated_status_properties: list[str] | None,
|
||||
dp_timestamps: dict | None = None,
|
||||
) -> None:
|
||||
"""Handle state update, only if this entity's dpcode was actually updated."""
|
||||
if self._dpcode_wrapper.skip_update(self.device, updated_status_properties):
|
||||
return
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the siren on."""
|
||||
await self._async_send_wrapper_updates(self._dpcode_wrapper, True)
|
||||
|
||||
@@ -1040,6 +1040,16 @@ class TuyaSwitchEntity(TuyaEntity, SwitchEntity):
|
||||
"""Return true if switch is on."""
|
||||
return self._read_wrapper(self._dpcode_wrapper)
|
||||
|
||||
async def _handle_state_update(
|
||||
self,
|
||||
updated_status_properties: list[str] | None,
|
||||
dp_timestamps: dict | None = None,
|
||||
) -> None:
|
||||
"""Handle state update, only if this entity's dpcode was actually updated."""
|
||||
if self._dpcode_wrapper.skip_update(self.device, updated_status_properties):
|
||||
return
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_turn_on(self, **kwargs: Any) -> None:
|
||||
"""Turn the switch on."""
|
||||
await self._async_send_wrapper_updates(self._dpcode_wrapper, True)
|
||||
|
||||
@@ -137,6 +137,16 @@ class TuyaValveEntity(TuyaEntity, ValveEntity):
|
||||
return None
|
||||
return not is_open
|
||||
|
||||
async def _handle_state_update(
|
||||
self,
|
||||
updated_status_properties: list[str] | None,
|
||||
dp_timestamps: dict | None = None,
|
||||
) -> None:
|
||||
"""Handle state update, only if this entity's dpcode was actually updated."""
|
||||
if self._dpcode_wrapper.skip_update(self.device, updated_status_properties):
|
||||
return
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_open_valve(self) -> None:
|
||||
"""Open the valve."""
|
||||
await self._async_send_wrapper_updates(self._dpcode_wrapper, True)
|
||||
|
||||
@@ -6,6 +6,7 @@ import pathlib
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
|
||||
from homeassistant.components.tuya import DeviceListener
|
||||
@@ -61,3 +62,40 @@ async def initialize_entry(
|
||||
with patch("homeassistant.components.tuya.Manager", return_value=mock_manager):
|
||||
await hass.config_entries.async_setup(mock_config_entry.entry_id)
|
||||
await hass.async_block_till_done()
|
||||
|
||||
|
||||
async def check_selective_state_update(
|
||||
hass: HomeAssistant,
|
||||
mock_device: CustomerDevice,
|
||||
mock_listener: MockDeviceListener,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
*,
|
||||
entity_id: str,
|
||||
dpcode: str,
|
||||
initial_state: str,
|
||||
updates: dict[str, Any],
|
||||
expected_state: str,
|
||||
last_reported: str,
|
||||
) -> None:
|
||||
"""Test selective state update.
|
||||
|
||||
This test verifies that when an update event comes with properties that do NOT
|
||||
include the dpcode (e.g., a battery event for a door sensor),
|
||||
the entity state is not changed and last_reported is not updated.
|
||||
"""
|
||||
initial_reported = "2024-01-01T00:00:00+00:00"
|
||||
assert hass.states.get(entity_id).state == initial_state
|
||||
assert hass.states.get(entity_id).last_reported.isoformat() == initial_reported
|
||||
|
||||
# Force update the dpcode and trigger device update
|
||||
freezer.tick(30)
|
||||
mock_device.status[dpcode] = None
|
||||
await mock_listener.async_send_device_update(hass, mock_device, {})
|
||||
assert hass.states.get(entity_id).state == initial_state
|
||||
assert hass.states.get(entity_id).last_reported.isoformat() == initial_reported
|
||||
|
||||
# Trigger device update with provided updates
|
||||
freezer.tick(30)
|
||||
await mock_listener.async_send_device_update(hass, mock_device, updates)
|
||||
assert hass.states.get(entity_id).state == expected_state
|
||||
assert hass.states.get(entity_id).last_reported.isoformat() == last_reported
|
||||
|
||||
@@ -14,7 +14,7 @@ from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from . import MockDeviceListener, initialize_entry
|
||||
from . import MockDeviceListener, check_selective_state_update, initialize_entry
|
||||
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
|
||||
@@ -35,6 +35,54 @@ async def test_platform_setup_and_discovery(
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mock_device_code",
|
||||
["mcs_oxslv1c9"],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("updates", "expected_state", "last_reported"),
|
||||
[
|
||||
# Update without dpcode - state should not change, last_reported stays at initial
|
||||
({"battery_percentage": 80}, "off", "2024-01-01T00:00:00+00:00"),
|
||||
# Update with dpcode - state should change, last_reported advances
|
||||
({"doorcontact_state": True}, "on", "2024-01-01T00:01:00+00:00"),
|
||||
# Update with multiple properties including dpcode - state should change
|
||||
(
|
||||
{"battery_percentage": 50, "doorcontact_state": True},
|
||||
"on",
|
||||
"2024-01-01T00:01:00+00:00",
|
||||
),
|
||||
],
|
||||
)
|
||||
@patch("homeassistant.components.tuya.PLATFORMS", [Platform.BINARY_SENSOR])
|
||||
@pytest.mark.freeze_time("2024-01-01")
|
||||
async def test_selective_state_update(
|
||||
hass: HomeAssistant,
|
||||
mock_manager: Manager,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_device: CustomerDevice,
|
||||
mock_listener: MockDeviceListener,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
updates: dict[str, Any],
|
||||
expected_state: str,
|
||||
last_reported: str,
|
||||
) -> None:
|
||||
"""Test skip_update/last_reported."""
|
||||
await initialize_entry(hass, mock_manager, mock_config_entry, mock_device)
|
||||
await check_selective_state_update(
|
||||
hass,
|
||||
mock_device,
|
||||
mock_listener,
|
||||
freezer,
|
||||
entity_id="binary_sensor.window_downstairs_door",
|
||||
dpcode="doorcontact_state",
|
||||
initial_state="off",
|
||||
updates=updates,
|
||||
expected_state=expected_state,
|
||||
last_reported=last_reported,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mock_device_code",
|
||||
["cs_zibqa9dutqyaxym2"],
|
||||
@@ -75,59 +123,3 @@ async def test_bitmap(
|
||||
assert hass.states.get("binary_sensor.dehumidifier_tank_full").state == tankfull
|
||||
assert hass.states.get("binary_sensor.dehumidifier_defrost").state == defrost
|
||||
assert hass.states.get("binary_sensor.dehumidifier_wet").state == wet
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mock_device_code",
|
||||
["mcs_oxslv1c9"],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("updates", "expected_state", "last_reported"),
|
||||
[
|
||||
# Update without dpcode - state should not change, last_reported stays at initial
|
||||
({"battery_percentage": 80}, "off", "2024-01-01T00:00:00+00:00"),
|
||||
# Update with dpcode - state should change, last_reported advances
|
||||
({"doorcontact_state": True}, "on", "2024-01-01T00:01:00+00:00"),
|
||||
# Update with multiple properties including dpcode - state should change
|
||||
(
|
||||
{"battery_percentage": 50, "doorcontact_state": True},
|
||||
"on",
|
||||
"2024-01-01T00:01:00+00:00",
|
||||
),
|
||||
],
|
||||
)
|
||||
@patch("homeassistant.components.tuya.PLATFORMS", [Platform.BINARY_SENSOR])
|
||||
@pytest.mark.freeze_time("2024-01-01")
|
||||
async def test_selective_state_update(
|
||||
hass: HomeAssistant,
|
||||
mock_manager: Manager,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_device: CustomerDevice,
|
||||
mock_listener: MockDeviceListener,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
updates: dict[str, Any],
|
||||
expected_state: str,
|
||||
last_reported: str,
|
||||
) -> None:
|
||||
"""Test binary sensor only updates when its dpcode is in updated properties.
|
||||
|
||||
This test verifies that when an update event comes with properties that do NOT
|
||||
include the binary sensor's dpcode (e.g., a battery event for a door sensor),
|
||||
the binary sensor state is not changed and last_reported is not updated.
|
||||
"""
|
||||
entity_id = "binary_sensor.window_downstairs_door"
|
||||
await initialize_entry(hass, mock_manager, mock_config_entry, mock_device)
|
||||
|
||||
assert hass.states.get(entity_id).state == "off"
|
||||
assert (
|
||||
hass.states.get(entity_id).last_reported.isoformat()
|
||||
== "2024-01-01T00:00:00+00:00"
|
||||
)
|
||||
|
||||
# Force update the dpcode - should be ignored unless event contains the property
|
||||
mock_device.status["doorcontact_state"] = True
|
||||
freezer.tick(60)
|
||||
await mock_listener.async_send_device_update(hass, mock_device, updates)
|
||||
|
||||
assert hass.states.get(entity_id).state == expected_state
|
||||
assert hass.states.get(entity_id).last_reported.isoformat() == last_reported
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
@@ -17,7 +19,7 @@ from homeassistant.const import ATTR_ENTITY_ID, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from . import initialize_entry
|
||||
from . import MockDeviceListener, check_selective_state_update, initialize_entry
|
||||
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
|
||||
@@ -37,6 +39,54 @@ async def test_platform_setup_and_discovery(
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mock_device_code",
|
||||
["mal_gyitctrjj1kefxp2"],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("updates", "expected_state", "last_reported"),
|
||||
[
|
||||
# Update without dpcode - state should not change, last_reported stays at initial
|
||||
({"switch_alarm_sound": True}, "15.0", "2024-01-01T00:00:00+00:00"),
|
||||
# Update with dpcode - state should change, last_reported advances
|
||||
({"delay_set": 17}, "17.0", "2024-01-01T00:01:00+00:00"),
|
||||
# Update with multiple properties including dpcode - state should change
|
||||
(
|
||||
{"switch_alarm_sound": True, "delay_set": 17},
|
||||
"17.0",
|
||||
"2024-01-01T00:01:00+00:00",
|
||||
),
|
||||
],
|
||||
)
|
||||
@patch("homeassistant.components.tuya.PLATFORMS", [Platform.NUMBER])
|
||||
@pytest.mark.freeze_time("2024-01-01")
|
||||
async def test_selective_state_update(
|
||||
hass: HomeAssistant,
|
||||
mock_manager: Manager,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_device: CustomerDevice,
|
||||
mock_listener: MockDeviceListener,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
updates: dict[str, Any],
|
||||
expected_state: str,
|
||||
last_reported: str,
|
||||
) -> None:
|
||||
"""Test skip_update/last_reported."""
|
||||
await initialize_entry(hass, mock_manager, mock_config_entry, mock_device)
|
||||
await check_selective_state_update(
|
||||
hass,
|
||||
mock_device,
|
||||
mock_listener,
|
||||
freezer,
|
||||
entity_id="number.multifunction_alarm_arm_delay",
|
||||
dpcode="delay_set",
|
||||
initial_state="15.0",
|
||||
updates=updates,
|
||||
expected_state=expected_state,
|
||||
last_reported=last_reported,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mock_device_code",
|
||||
["mal_gyitctrjj1kefxp2"],
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
@@ -18,7 +20,7 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.exceptions import ServiceValidationError
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from . import initialize_entry
|
||||
from . import MockDeviceListener, check_selective_state_update, initialize_entry
|
||||
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
|
||||
@@ -38,6 +40,54 @@ async def test_platform_setup_and_discovery(
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mock_device_code",
|
||||
["cl_zah67ekd"],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("updates", "expected_state", "last_reported"),
|
||||
[
|
||||
# Update without dpcode - state should not change, last_reported stays at initial
|
||||
({"control": "stop"}, "forward", "2024-01-01T00:00:00+00:00"),
|
||||
# Update with dpcode - state should change, last_reported advances
|
||||
({"control_back_mode": "back"}, "back", "2024-01-01T00:01:00+00:00"),
|
||||
# Update with multiple properties including dpcode - state should change
|
||||
(
|
||||
{"control": "stop", "control_back_mode": "back"},
|
||||
"back",
|
||||
"2024-01-01T00:01:00+00:00",
|
||||
),
|
||||
],
|
||||
)
|
||||
@patch("homeassistant.components.tuya.PLATFORMS", [Platform.SELECT])
|
||||
@pytest.mark.freeze_time("2024-01-01")
|
||||
async def test_selective_state_update(
|
||||
hass: HomeAssistant,
|
||||
mock_manager: Manager,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_device: CustomerDevice,
|
||||
mock_listener: MockDeviceListener,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
updates: dict[str, Any],
|
||||
expected_state: str,
|
||||
last_reported: str,
|
||||
) -> None:
|
||||
"""Test skip_update/last_reported."""
|
||||
await initialize_entry(hass, mock_manager, mock_config_entry, mock_device)
|
||||
await check_selective_state_update(
|
||||
hass,
|
||||
mock_device,
|
||||
mock_listener,
|
||||
freezer,
|
||||
entity_id="select.kitchen_blinds_motor_mode",
|
||||
dpcode="control_back_mode",
|
||||
initial_state="forward",
|
||||
updates=updates,
|
||||
expected_state=expected_state,
|
||||
last_reported=last_reported,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mock_device_code",
|
||||
["cl_zah67ekd"],
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
@@ -12,7 +14,7 @@ from homeassistant.const import Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from . import initialize_entry
|
||||
from . import MockDeviceListener, check_selective_state_update, initialize_entry
|
||||
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
|
||||
@@ -31,3 +33,51 @@ async def test_platform_setup_and_discovery(
|
||||
await initialize_entry(hass, mock_manager, mock_config_entry, mock_devices)
|
||||
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mock_device_code",
|
||||
["mcs_8yhypbo7"],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("updates", "expected_state", "last_reported"),
|
||||
[
|
||||
# Update without dpcode - state should not change, last_reported stays at initial
|
||||
({"doorcontact_state": True}, "62.0", "2024-01-01T00:00:00+00:00"),
|
||||
# Update with dpcode - state should change, last_reported advances
|
||||
({"battery_percentage": 50}, "50.0", "2024-01-01T00:01:00+00:00"),
|
||||
# Update with multiple properties including dpcode - state should change
|
||||
(
|
||||
{"doorcontact_state": True, "battery_percentage": 50},
|
||||
"50.0",
|
||||
"2024-01-01T00:01:00+00:00",
|
||||
),
|
||||
],
|
||||
)
|
||||
@patch("homeassistant.components.tuya.PLATFORMS", [Platform.SENSOR])
|
||||
@pytest.mark.freeze_time("2024-01-01")
|
||||
async def test_selective_state_update(
|
||||
hass: HomeAssistant,
|
||||
mock_manager: Manager,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_device: CustomerDevice,
|
||||
mock_listener: MockDeviceListener,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
updates: dict[str, Any],
|
||||
expected_state: str,
|
||||
last_reported: str,
|
||||
) -> None:
|
||||
"""Test skip_update/last_reported."""
|
||||
await initialize_entry(hass, mock_manager, mock_config_entry, mock_device)
|
||||
await check_selective_state_update(
|
||||
hass,
|
||||
mock_device,
|
||||
mock_listener,
|
||||
freezer,
|
||||
entity_id="sensor.boite_aux_lettres_arriere_battery",
|
||||
dpcode="battery_percentage",
|
||||
initial_state="62.0",
|
||||
updates=updates,
|
||||
expected_state=expected_state,
|
||||
last_reported=last_reported,
|
||||
)
|
||||
|
||||
@@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
@@ -18,7 +19,7 @@ from homeassistant.const import ATTR_ENTITY_ID, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from . import initialize_entry
|
||||
from . import MockDeviceListener, check_selective_state_update, initialize_entry
|
||||
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
|
||||
@@ -38,6 +39,54 @@ async def test_platform_setup_and_discovery(
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mock_device_code",
|
||||
["sp_sdd5f5f2dl5wydjf"],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("updates", "expected_state", "last_reported"),
|
||||
[
|
||||
# Update without dpcode - state should not change, last_reported stays at initial
|
||||
({"basic_wdr": False}, "off", "2024-01-01T00:00:00+00:00"),
|
||||
# Update with dpcode - state should change, last_reported advances
|
||||
({"siren_switch": True}, "on", "2024-01-01T00:01:00+00:00"),
|
||||
# Update with multiple properties including dpcode - state should change
|
||||
(
|
||||
{"basic_wdr": False, "siren_switch": True},
|
||||
"on",
|
||||
"2024-01-01T00:01:00+00:00",
|
||||
),
|
||||
],
|
||||
)
|
||||
@patch("homeassistant.components.tuya.PLATFORMS", [Platform.SIREN])
|
||||
@pytest.mark.freeze_time("2024-01-01")
|
||||
async def test_selective_state_update(
|
||||
hass: HomeAssistant,
|
||||
mock_manager: Manager,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_device: CustomerDevice,
|
||||
mock_listener: MockDeviceListener,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
updates: dict[str, Any],
|
||||
expected_state: str,
|
||||
last_reported: str,
|
||||
) -> None:
|
||||
"""Test skip_update/last_reported."""
|
||||
await initialize_entry(hass, mock_manager, mock_config_entry, mock_device)
|
||||
await check_selective_state_update(
|
||||
hass,
|
||||
mock_device,
|
||||
mock_listener,
|
||||
freezer,
|
||||
entity_id="siren.c9",
|
||||
dpcode="siren_switch",
|
||||
initial_state="off",
|
||||
updates=updates,
|
||||
expected_state=expected_state,
|
||||
last_reported=last_reported,
|
||||
)
|
||||
|
||||
|
||||
@patch("homeassistant.components.tuya.PLATFORMS", [Platform.SIREN])
|
||||
@pytest.mark.parametrize(
|
||||
"mock_device_code",
|
||||
|
||||
@@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
@@ -19,7 +20,7 @@ from homeassistant.const import ATTR_ENTITY_ID, STATE_UNKNOWN, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er, issue_registry as ir
|
||||
|
||||
from . import initialize_entry
|
||||
from . import MockDeviceListener, check_selective_state_update, initialize_entry
|
||||
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
|
||||
@@ -39,6 +40,54 @@ async def test_platform_setup_and_discovery(
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mock_device_code",
|
||||
["cz_PGEkBctAbtzKOZng"],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("updates", "expected_state", "last_reported"),
|
||||
[
|
||||
# Update without dpcode - state should not change, last_reported stays at initial
|
||||
({"countdown_1": 50}, "off", "2024-01-01T00:00:00+00:00"),
|
||||
# Update with dpcode - state should change, last_reported advances
|
||||
({"switch": True}, "on", "2024-01-01T00:01:00+00:00"),
|
||||
# Update with multiple properties including dpcode - state should change
|
||||
(
|
||||
{"countdown_1": 50, "switch": True},
|
||||
"on",
|
||||
"2024-01-01T00:01:00+00:00",
|
||||
),
|
||||
],
|
||||
)
|
||||
@patch("homeassistant.components.tuya.PLATFORMS", [Platform.SWITCH])
|
||||
@pytest.mark.freeze_time("2024-01-01")
|
||||
async def test_selective_state_update(
|
||||
hass: HomeAssistant,
|
||||
mock_manager: Manager,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_device: CustomerDevice,
|
||||
mock_listener: MockDeviceListener,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
updates: dict[str, Any],
|
||||
expected_state: str,
|
||||
last_reported: str,
|
||||
) -> None:
|
||||
"""Test skip_update/last_reported."""
|
||||
await initialize_entry(hass, mock_manager, mock_config_entry, mock_device)
|
||||
await check_selective_state_update(
|
||||
hass,
|
||||
mock_device,
|
||||
mock_listener,
|
||||
freezer,
|
||||
entity_id="switch.din_socket",
|
||||
dpcode="switch",
|
||||
initial_state="off",
|
||||
updates=updates,
|
||||
expected_state=expected_state,
|
||||
last_reported=last_reported,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("preexisting_entity", "disabled_by", "expected_entity", "expected_issue"),
|
||||
[
|
||||
|
||||
@@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
from typing import Any
|
||||
from unittest.mock import patch
|
||||
|
||||
from freezegun.api import FrozenDateTimeFactory
|
||||
import pytest
|
||||
from syrupy.assertion import SnapshotAssertion
|
||||
from tuya_sharing import CustomerDevice, Manager
|
||||
@@ -18,7 +19,7 @@ from homeassistant.const import ATTR_ENTITY_ID, STATE_UNKNOWN, Platform
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import entity_registry as er
|
||||
|
||||
from . import initialize_entry
|
||||
from . import MockDeviceListener, check_selective_state_update, initialize_entry
|
||||
|
||||
from tests.common import MockConfigEntry, snapshot_platform
|
||||
|
||||
@@ -38,6 +39,54 @@ async def test_platform_setup_and_discovery(
|
||||
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"mock_device_code",
|
||||
["sfkzq_ed7frwissyqrejic"],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("updates", "expected_state", "last_reported"),
|
||||
[
|
||||
# Update without dpcode - state should not change, last_reported stays at initial
|
||||
({"battery_percentage": 50}, "open", "2024-01-01T00:00:00+00:00"),
|
||||
# Update with dpcode - state should change, last_reported advances
|
||||
({"switch_1": False}, "closed", "2024-01-01T00:01:00+00:00"),
|
||||
# Update with multiple properties including dpcode - state should change
|
||||
(
|
||||
{"battery_percentage": 50, "switch_1": False},
|
||||
"closed",
|
||||
"2024-01-01T00:01:00+00:00",
|
||||
),
|
||||
],
|
||||
)
|
||||
@patch("homeassistant.components.tuya.PLATFORMS", [Platform.VALVE])
|
||||
@pytest.mark.freeze_time("2024-01-01")
|
||||
async def test_selective_state_update(
|
||||
hass: HomeAssistant,
|
||||
mock_manager: Manager,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
mock_device: CustomerDevice,
|
||||
mock_listener: MockDeviceListener,
|
||||
freezer: FrozenDateTimeFactory,
|
||||
updates: dict[str, Any],
|
||||
expected_state: str,
|
||||
last_reported: str,
|
||||
) -> None:
|
||||
"""Test skip_update/last_reported."""
|
||||
await initialize_entry(hass, mock_manager, mock_config_entry, mock_device)
|
||||
await check_selective_state_update(
|
||||
hass,
|
||||
mock_device,
|
||||
mock_listener,
|
||||
freezer,
|
||||
entity_id="valve.jie_hashui_fa_valve_1",
|
||||
dpcode="switch_1",
|
||||
initial_state="open",
|
||||
updates=updates,
|
||||
expected_state=expected_state,
|
||||
last_reported=last_reported,
|
||||
)
|
||||
|
||||
|
||||
@patch("homeassistant.components.tuya.PLATFORMS", [Platform.VALVE])
|
||||
@pytest.mark.parametrize(
|
||||
"mock_device_code",
|
||||
|
||||
Reference in New Issue
Block a user