From a06df2a68023f8e7374933aee3e3fc62a0a0e900 Mon Sep 17 00:00:00 2001 From: Mike Degatano Date: Tue, 12 Aug 2025 02:39:37 -0400 Subject: [PATCH 1/8] Make disk_lifetime issue into a repair (#150140) --- homeassistant/components/hassio/issues.py | 1 + homeassistant/components/hassio/strings.json | 4 ++ tests/components/hassio/test_issues.py | 47 ++++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/homeassistant/components/hassio/issues.py b/homeassistant/components/hassio/issues.py index 35f7f48481e2c0..68d01e93bebfad 100644 --- a/homeassistant/components/hassio/issues.py +++ b/homeassistant/components/hassio/issues.py @@ -103,6 +103,7 @@ ISSUE_KEY_SYSTEM_DOCKER_CONFIG, ISSUE_KEY_ADDON_DETACHED_ADDON_MISSING, ISSUE_KEY_ADDON_DETACHED_ADDON_REMOVED, + "issue_system_disk_lifetime", } _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/hassio/strings.json b/homeassistant/components/hassio/strings.json index 5df197bddcb216..393fe480057385 100644 --- a/homeassistant/components/hassio/strings.json +++ b/homeassistant/components/hassio/strings.json @@ -115,6 +115,10 @@ } } }, + "issue_system_disk_lifetime": { + "title": "Disk lifetime exceeding 90%", + "description": "The data disk has exceeded 90% of its expected lifespan. The disk may soon malfunction which can lead to data loss. You should replace it soon and migrate your data." + }, "unhealthy": { "title": "Unhealthy system - {reason}", "description": "System is currently unhealthy due to {reason}. For troubleshooting information, select Learn more." diff --git a/tests/components/hassio/test_issues.py b/tests/components/hassio/test_issues.py index b0d3920be09407..a4ad0a4a004b71 100644 --- a/tests/components/hassio/test_issues.py +++ b/tests/components/hassio/test_issues.py @@ -850,3 +850,50 @@ async def test_supervisor_issues_detached_addon_missing( "addon_url": "/hassio/addon/test", }, ) + + +@pytest.mark.usefixtures("all_setup_requests") +async def test_supervisor_issues_disk_lifetime( + hass: HomeAssistant, + supervisor_client: AsyncMock, + hass_ws_client: WebSocketGenerator, +) -> None: + """Test supervisor issue for disk lifetime nearly exceeded.""" + mock_resolution_info(supervisor_client) + + result = await async_setup_component(hass, "hassio", {}) + assert result + + client = await hass_ws_client(hass) + + await client.send_json( + { + "id": 1, + "type": "supervisor/event", + "data": { + "event": "issue_changed", + "data": { + "uuid": (issue_uuid := uuid4().hex), + "type": "disk_lifetime", + "context": "system", + "reference": None, + }, + }, + } + ) + msg = await client.receive_json() + assert msg["success"] + await hass.async_block_till_done() + + await client.send_json({"id": 2, "type": "repairs/list_issues"}) + msg = await client.receive_json() + assert msg["success"] + assert len(msg["result"]["issues"]) == 1 + assert_issue_repair_in_list( + msg["result"]["issues"], + uuid=issue_uuid, + context="system", + type_="disk_lifetime", + fixable=False, + placeholders=None, + ) From c46412ee5be26e09d259a1c41293ef17009d66b2 Mon Sep 17 00:00:00 2001 From: Cyrill Raccaud Date: Tue, 12 Aug 2025 09:51:39 +0200 Subject: [PATCH 2/8] Bump cookidoo-api to 0.14.0 (#150450) --- homeassistant/components/cookidoo/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/cookidoo/manifest.json b/homeassistant/components/cookidoo/manifest.json index 5264e47a70993a..b4cf653f810f89 100644 --- a/homeassistant/components/cookidoo/manifest.json +++ b/homeassistant/components/cookidoo/manifest.json @@ -8,5 +8,5 @@ "iot_class": "cloud_polling", "loggers": ["cookidoo_api"], "quality_scale": "silver", - "requirements": ["cookidoo-api==0.12.2"] + "requirements": ["cookidoo-api==0.14.0"] } diff --git a/requirements_all.txt b/requirements_all.txt index 5c3747f865897f..e5d8b95b89a1ef 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -740,7 +740,7 @@ connect-box==0.3.1 construct==2.10.68 # homeassistant.components.cookidoo -cookidoo-api==0.12.2 +cookidoo-api==0.14.0 # homeassistant.components.backup # homeassistant.components.utility_meter diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 7fbf37d1df6db2..a7cac53c700dff 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -643,7 +643,7 @@ colorthief==0.2.1 construct==2.10.68 # homeassistant.components.cookidoo -cookidoo-api==0.12.2 +cookidoo-api==0.14.0 # homeassistant.components.backup # homeassistant.components.utility_meter From e0a8c9b45845c47158a5c915f1a92efbbb329fcc Mon Sep 17 00:00:00 2001 From: Norbert Rittel Date: Tue, 12 Aug 2025 10:30:38 +0200 Subject: [PATCH 3/8] Fix missing sentence-casing in `somfy_mylink` (#150463) --- homeassistant/components/somfy_mylink/strings.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/somfy_mylink/strings.json b/homeassistant/components/somfy_mylink/strings.json index 90489c0ba347f7..ec501fac3027ac 100644 --- a/homeassistant/components/somfy_mylink/strings.json +++ b/homeassistant/components/somfy_mylink/strings.json @@ -29,13 +29,13 @@ }, "step": { "init": { - "title": "Configure MyLink Options", + "title": "Configure MyLink options", "data": { "target_id": "Configure options for a cover." } }, "target_config": { - "title": "Configure MyLink Cover", + "title": "Configure MyLink cover", "description": "Configure options for `{target_name}`", "data": { "reverse": "Cover is reversed" From f6af524ddff80448279330dcbc7d588b1ca98c23 Mon Sep 17 00:00:00 2001 From: Matrix Date: Tue, 12 Aug 2025 16:42:40 +0800 Subject: [PATCH 4/8] Fix YoLink valve state when device running in class A mode (#150456) --- homeassistant/components/yolink/strings.json | 3 +++ homeassistant/components/yolink/valve.py | 14 ++++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/yolink/strings.json b/homeassistant/components/yolink/strings.json index 0eb9de974693ea..4215031d90497c 100644 --- a/homeassistant/components/yolink/strings.json +++ b/homeassistant/components/yolink/strings.json @@ -47,6 +47,9 @@ "exceptions": { "invalid_config_entry": { "message": "Config entry not found or not loaded!" + }, + "valve_inoperable_currently": { + "message": "The Valve cannot be operated currently." } }, "entity": { diff --git a/homeassistant/components/yolink/valve.py b/homeassistant/components/yolink/valve.py index 06dee8af5404f1..e63488194d08a0 100644 --- a/homeassistant/components/yolink/valve.py +++ b/homeassistant/components/yolink/valve.py @@ -21,6 +21,7 @@ ) from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback +from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from .const import DEV_MODEL_WATER_METER_YS5007, DOMAIN @@ -130,6 +131,13 @@ def update_entity_state(self, state: dict[str, str | list[str]]) -> None: async def _async_invoke_device(self, state: str) -> None: """Call setState api to change valve state.""" + if ( + self.coordinator.device.is_support_mode_switching() + and self.coordinator.dev_net_type == ATTR_DEVICE_MODEL_A + ): + raise HomeAssistantError( + translation_domain=DOMAIN, translation_key="valve_inoperable_currently" + ) if ( self.coordinator.device.device_type == ATTR_DEVICE_MULTI_WATER_METER_CONTROLLER @@ -155,10 +163,4 @@ async def async_close_valve(self) -> None: @property def available(self) -> bool: """Return true is device is available.""" - if ( - self.coordinator.device.is_support_mode_switching() - and self.coordinator.dev_net_type is not None - ): - # When the device operates in Class A mode, it cannot be controlled. - return self.coordinator.dev_net_type != ATTR_DEVICE_MODEL_A return super().available From 8f5c8caf07212ddeaaa6a0736a9936dcc7b58023 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Tue, 12 Aug 2025 10:45:39 +0200 Subject: [PATCH 5/8] Add mute switch to Tuya smoke detectors (#150469) --- homeassistant/components/tuya/switch.py | 9 ++ tests/components/tuya/__init__.py | 1 + .../tuya/fixtures/ywbj_rccxox8p.json | 68 ++++++++ .../tuya/snapshots/test_binary_sensor.ambr | 49 ++++++ .../tuya/snapshots/test_sensor.ambr | 152 ++++++++++++++++++ .../tuya/snapshots/test_switch.ambr | 144 +++++++++++++++++ 6 files changed, 423 insertions(+) create mode 100644 tests/components/tuya/fixtures/ywbj_rccxox8p.json diff --git a/homeassistant/components/tuya/switch.py b/homeassistant/components/tuya/switch.py index 81062a092ca6c2..e20923133f93b6 100644 --- a/homeassistant/components/tuya/switch.py +++ b/homeassistant/components/tuya/switch.py @@ -881,6 +881,15 @@ entity_category=EntityCategory.CONFIG, ), ), + # Smoke Detector + # https://developer.tuya.com/en/docs/iot/categoryywbj?id=Kaiuz3f6sf952 + "ywbj": ( + SwitchEntityDescription( + key=DPCode.MUFFLING, + translation_key="mute", + entity_category=EntityCategory.CONFIG, + ), + ), # Smart Electricity Meter # https://developer.tuya.com/en/docs/iot/smart-meter?id=Kaiuz4gv6ack7 "zndb": ( diff --git a/tests/components/tuya/__init__.py b/tests/components/tuya/__init__.py index 700ad9116ed74f..44fe55fbb0b15b 100644 --- a/tests/components/tuya/__init__.py +++ b/tests/components/tuya/__init__.py @@ -187,6 +187,7 @@ "ywbj_cjlutkuuvxnie17o", # https://github.com/home-assistant/core/issues/146164 "ywbj_gf9dejhmzffgdyfj", # https://github.com/home-assistant/core/issues/149704 "ywbj_kscbebaf3s1eogvt", # https://github.com/home-assistant/core/issues/141278 + "ywbj_rccxox8p", # https://github.com/orgs/home-assistant/discussions/625 "ywcgq_h8lvyoahr6s6aybf", # https://github.com/home-assistant/core/issues/145932 "ywcgq_wtzwyhkev3b4ubns", # https://github.com/home-assistant/core/issues/103818 "zjq_nkkl7uzv", # https://github.com/orgs/home-assistant/discussions/482 diff --git a/tests/components/tuya/fixtures/ywbj_rccxox8p.json b/tests/components/tuya/fixtures/ywbj_rccxox8p.json new file mode 100644 index 00000000000000..45a5e8697f200b --- /dev/null +++ b/tests/components/tuya/fixtures/ywbj_rccxox8p.json @@ -0,0 +1,68 @@ +{ + "endpoint": "https://apigw.tuyaeu.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "Smoke Alarm", + "category": "ywbj", + "product_id": "rccxox8p", + "product_name": "Smoke Alarm", + "online": true, + "sub": true, + "time_zone": "+02:00", + "active_time": "2024-08-05T13:47:04+00:00", + "create_time": "2024-08-05T13:47:04+00:00", + "update_time": "2024-08-05T13:47:04+00:00", + "function": { + "muffling": { + "type": "Boolean", + "value": {} + } + }, + "status_range": { + "smoke_sensor_status": { + "type": "Enum", + "value": { + "range": ["alarm", "normal"] + } + }, + "smoke_sensor_value": { + "type": "Integer", + "value": { + "min": 0, + "max": 1000, + "scale": 1, + "step": 1 + } + }, + "battery_state": { + "type": "Enum", + "value": { + "range": ["low", "middle", "high"] + } + }, + "battery_percentage": { + "type": "Integer", + "value": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + } + }, + "muffling": { + "type": "Boolean", + "value": {} + } + }, + "status": { + "smoke_sensor_status": "normal", + "smoke_sensor_value": 0, + "battery_state": "low", + "battery_percentage": 100, + "muffling": false + }, + "set_up": true, + "support_local": true +} diff --git a/tests/components/tuya/snapshots/test_binary_sensor.ambr b/tests/components/tuya/snapshots/test_binary_sensor.ambr index cdc009a5d78b02..c2f246fb9e9d95 100644 --- a/tests/components/tuya/snapshots/test_binary_sensor.ambr +++ b/tests/components/tuya/snapshots/test_binary_sensor.ambr @@ -1174,6 +1174,55 @@ 'state': 'off', }) # --- +# name: test_platform_setup_and_discovery[binary_sensor.smoke_alarm_smoke-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.smoke_alarm_smoke', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Smoke', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': 'tuya.p8xoxccrjbwysmoke_sensor_status', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[binary_sensor.smoke_alarm_smoke-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'smoke', + 'friendly_name': 'Smoke Alarm Smoke', + }), + 'context': , + 'entity_id': 'binary_sensor.smoke_alarm_smoke', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- # name: test_platform_setup_and_discovery[binary_sensor.smoke_detector_upstairs_smoke-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/tuya/snapshots/test_sensor.ambr b/tests/components/tuya/snapshots/test_sensor.ambr index 00c170ca93c174..375e52f6bbde91 100644 --- a/tests/components/tuya/snapshots/test_sensor.ambr +++ b/tests/components/tuya/snapshots/test_sensor.ambr @@ -10098,6 +10098,158 @@ 'state': '97.0', }) # --- +# name: test_platform_setup_and_discovery[sensor.smoke_alarm_battery-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.smoke_alarm_battery', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery', + 'unique_id': 'tuya.p8xoxccrjbwybattery_percentage', + 'unit_of_measurement': '%', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.smoke_alarm_battery-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'Smoke Alarm Battery', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.smoke_alarm_battery', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '100.0', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.smoke_alarm_battery_state-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.smoke_alarm_battery_state', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Battery state', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_state', + 'unique_id': 'tuya.p8xoxccrjbwybattery_state', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[sensor.smoke_alarm_battery_state-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Smoke Alarm Battery state', + }), + 'context': , + 'entity_id': 'sensor.smoke_alarm_battery_state', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'low', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.smoke_alarm_smoke_amount-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.smoke_alarm_smoke_amount', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Smoke amount', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'smoke_amount', + 'unique_id': 'tuya.p8xoxccrjbwysmoke_sensor_value', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[sensor.smoke_alarm_smoke_amount-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Smoke Alarm Smoke amount', + 'state_class': , + }), + 'context': , + 'entity_id': 'sensor.smoke_alarm_smoke_amount', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0.0', + }) +# --- # name: test_platform_setup_and_discovery[sensor.smoke_detector_upstairs_battery-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/tuya/snapshots/test_switch.ambr b/tests/components/tuya/snapshots/test_switch.ambr index 0ab53480c22274..bff8c3e392ac09 100644 --- a/tests/components/tuya/snapshots/test_switch.ambr +++ b/tests/components/tuya/snapshots/test_switch.ambr @@ -6389,6 +6389,102 @@ 'state': 'on', }) # --- +# name: test_platform_setup_and_discovery[switch.smoke_alarm_mute-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'switch', + 'entity_category': , + 'entity_id': 'switch.smoke_alarm_mute', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Mute', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'mute', + 'unique_id': 'tuya.p8xoxccrjbwymuffling', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[switch.smoke_alarm_mute-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Smoke Alarm Mute', + }), + 'context': , + 'entity_id': 'switch.smoke_alarm_mute', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_platform_setup_and_discovery[switch.smoke_detector_upstairs_mute-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'switch', + 'entity_category': , + 'entity_id': 'switch.smoke_detector_upstairs_mute', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Mute', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'mute', + 'unique_id': 'tuya.jfydgffzmhjed9fgjbwymuffling', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[switch.smoke_detector_upstairs_mute-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': ' Smoke detector upstairs Mute', + }), + 'context': , + 'entity_id': 'switch.smoke_detector_upstairs_mute', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- # name: test_platform_setup_and_discovery[switch.socket3_switch_1-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -7898,6 +7994,54 @@ 'state': 'off', }) # --- +# name: test_platform_setup_and_discovery[switch.wifi_smoke_alarm_mute-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'switch', + 'entity_category': , + 'entity_id': 'switch.wifi_smoke_alarm_mute', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Mute', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'mute', + 'unique_id': 'tuya.tvgoe1s3fabebcskjbwymuffling', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[switch.wifi_smoke_alarm_mute-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'WIFI Smoke alarm Mute', + }), + 'context': , + 'entity_id': 'switch.wifi_smoke_alarm_mute', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- # name: test_platform_setup_and_discovery[switch.xoca_dac212xc_v2_s1_switch-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ From db81610983aa2b1cb11efba4fbaeaaf252458b05 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 12 Aug 2025 03:46:53 -0500 Subject: [PATCH 6/8] Bump aioesphomeapi to 38.2.1 (#150455) --- homeassistant/components/esphome/manager.py | 10 ++++---- .../components/esphome/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/esphome/conftest.py | 24 ++++++++++++++++--- tests/components/esphome/test_manager.py | 24 ++++++++++++------- 6 files changed, 45 insertions(+), 19 deletions(-) diff --git a/homeassistant/components/esphome/manager.py b/homeassistant/components/esphome/manager.py index 4d5de77b1e05d3..742ed266bf39d2 100644 --- a/homeassistant/components/esphome/manager.py +++ b/homeassistant/components/esphome/manager.py @@ -564,11 +564,11 @@ async def _on_connect(self) -> None: ) entry_data.loaded_platforms.add(Platform.ASSIST_SATELLITE) - cli.subscribe_states(entry_data.async_update_state) - cli.subscribe_service_calls(self.async_on_service_call) - cli.subscribe_home_assistant_states( - self.async_on_state_subscription, - self.async_on_state_request, + cli.subscribe_home_assistant_states_and_services( + on_state=entry_data.async_update_state, + on_service_call=self.async_on_service_call, + on_state_sub=self.async_on_state_subscription, + on_state_request=self.async_on_state_request, ) entry_data.async_save_to_store() diff --git a/homeassistant/components/esphome/manifest.json b/homeassistant/components/esphome/manifest.json index 6bf164aa9bc6ca..fafeecc1304ff8 100644 --- a/homeassistant/components/esphome/manifest.json +++ b/homeassistant/components/esphome/manifest.json @@ -17,7 +17,7 @@ "mqtt": ["esphome/discover/#"], "quality_scale": "platinum", "requirements": [ - "aioesphomeapi==37.2.2", + "aioesphomeapi==38.2.1", "esphome-dashboard-api==1.3.0", "bleak-esphome==3.1.0" ], diff --git a/requirements_all.txt b/requirements_all.txt index e5d8b95b89a1ef..4cd27301bec4e1 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -247,7 +247,7 @@ aioelectricitymaps==0.4.0 aioemonitor==1.0.5 # homeassistant.components.esphome -aioesphomeapi==37.2.2 +aioesphomeapi==38.2.1 # homeassistant.components.flo aioflo==2021.11.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index a7cac53c700dff..537ca44d85ee7c 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -235,7 +235,7 @@ aioelectricitymaps==0.4.0 aioemonitor==1.0.5 # homeassistant.components.esphome -aioesphomeapi==37.2.2 +aioesphomeapi==38.2.1 # homeassistant.components.flo aioflo==2021.11.0 diff --git a/tests/components/esphome/conftest.py b/tests/components/esphome/conftest.py index 9de97bac3ebf2f..35885722d8a96d 100644 --- a/tests/components/esphome/conftest.py +++ b/tests/components/esphome/conftest.py @@ -517,9 +517,27 @@ def unsub(): mock_client.list_entities_services = AsyncMock( return_value=mock_list_entities_services ) - mock_client.subscribe_states = _subscribe_states - mock_client.subscribe_service_calls = _subscribe_service_calls - mock_client.subscribe_home_assistant_states = _subscribe_home_assistant_states + + def _subscribe_home_assistant_states_and_services( + *, + on_state: Callable[[EntityState], None], + on_service_call: Callable[[HomeassistantServiceCall], None], + on_state_sub: Callable[[str, str | None], None], + on_state_request: Callable[[str, str | None], None], + ) -> None: + """Subscribe to states and service calls.""" + mock_device.set_state_callback(on_state) + mock_device.set_service_call_callback(on_service_call) + mock_device.set_home_assistant_state_subscription_callback( + on_state_sub, on_state_request + ) + # Set the initial states + for state in states: + on_state(state) + + mock_client.subscribe_home_assistant_states_and_services = ( + _subscribe_home_assistant_states_and_services + ) mock_client.subscribe_logs = _subscribe_logs try_connect_done = Event() diff --git a/tests/components/esphome/test_manager.py b/tests/components/esphome/test_manager.py index fec957a95605cd..c29dbad1d3721e 100644 --- a/tests/components/esphome/test_manager.py +++ b/tests/components/esphome/test_manager.py @@ -416,10 +416,12 @@ async def test_unique_id_updated_to_mac( entry.add_to_hass(hass) subscribe_done = hass.loop.create_future() - def async_subscribe_states(*args, **kwargs) -> None: + def async_subscribe_home_assistant_states_and_services(*args, **kwargs) -> None: subscribe_done.set_result(None) - mock_client.subscribe_states = async_subscribe_states + mock_client.subscribe_home_assistant_states_and_services = ( + async_subscribe_home_assistant_states_and_services + ) mock_client.device_info = AsyncMock( return_value=DeviceInfo( mac_address="1122334455aa", @@ -447,10 +449,12 @@ async def test_add_missing_bluetooth_mac_address( entry.add_to_hass(hass) subscribe_done = hass.loop.create_future() - def async_subscribe_states(*args, **kwargs) -> None: + def async_subscribe_home_assistant_states_and_services(*args, **kwargs) -> None: subscribe_done.set_result(None) - mock_client.subscribe_states = async_subscribe_states + mock_client.subscribe_home_assistant_states_and_services = ( + async_subscribe_home_assistant_states_and_services + ) mock_client.device_info = AsyncMock( return_value=DeviceInfo( mac_address="1122334455aa", @@ -587,10 +591,12 @@ async def test_name_updated_only_if_mac_matches( entry.add_to_hass(hass) subscribe_done = hass.loop.create_future() - def async_subscribe_states(*args, **kwargs) -> None: + def async_subscribe_home_assistant_states_and_services(*args, **kwargs) -> None: subscribe_done.set_result(None) - mock_client.subscribe_states = async_subscribe_states + mock_client.subscribe_home_assistant_states_and_services = ( + async_subscribe_home_assistant_states_and_services + ) mock_client.device_info = AsyncMock( return_value=DeviceInfo(mac_address="1122334455aa", name="new") ) @@ -622,10 +628,12 @@ async def test_name_updated_only_if_mac_was_unset( entry.add_to_hass(hass) subscribe_done = hass.loop.create_future() - def async_subscribe_states(*args, **kwargs) -> None: + def async_subscribe_home_assistant_states_and_services(*args, **kwargs) -> None: subscribe_done.set_result(None) - mock_client.subscribe_states = async_subscribe_states + mock_client.subscribe_home_assistant_states_and_services = ( + async_subscribe_home_assistant_states_and_services + ) mock_client.device_info = AsyncMock( return_value=DeviceInfo(mac_address="1122334455aa", name="new") ) From 5b232226e99c8a136f32b6bf5ceca2eba16f8b35 Mon Sep 17 00:00:00 2001 From: yufeng Date: Tue, 12 Aug 2025 16:53:08 +0800 Subject: [PATCH 7/8] Add timers and switches to Tuya irrigation systems (#149236) --- homeassistant/components/tuya/const.py | 9 + homeassistant/components/tuya/number.py | 60 +++ homeassistant/components/tuya/strings.json | 8 + homeassistant/components/tuya/valve.py | 140 ++++++ tests/components/tuya/__init__.py | 1 + .../tuya/fixtures/sfkzq_ed7frwissyqrejic.json | 282 +++++++++++ .../tuya/snapshots/test_number.ambr | 472 ++++++++++++++++++ .../tuya/snapshots/test_sensor.ambr | 101 ++++ .../components/tuya/snapshots/test_valve.ambr | 401 +++++++++++++++ tests/components/tuya/test_valve.py | 96 ++++ 10 files changed, 1570 insertions(+) create mode 100644 homeassistant/components/tuya/valve.py create mode 100644 tests/components/tuya/fixtures/sfkzq_ed7frwissyqrejic.json create mode 100644 tests/components/tuya/snapshots/test_valve.ambr create mode 100644 tests/components/tuya/test_valve.py diff --git a/homeassistant/components/tuya/const.py b/homeassistant/components/tuya/const.py index 62a6c904a1f7eb..752911f98f6a73 100644 --- a/homeassistant/components/tuya/const.py +++ b/homeassistant/components/tuya/const.py @@ -66,6 +66,7 @@ Platform.SIREN, Platform.SWITCH, Platform.VACUUM, + Platform.VALVE, ] @@ -166,6 +167,14 @@ class DPCode(StrEnum): CONTROL_BACK = "control_back" CONTROL_BACK_MODE = "control_back_mode" COUNTDOWN = "countdown" # Countdown + COUNTDOWN_1 = "countdown_1" + COUNTDOWN_2 = "countdown_2" + COUNTDOWN_3 = "countdown_3" + COUNTDOWN_4 = "countdown_4" + COUNTDOWN_5 = "countdown_5" + COUNTDOWN_6 = "countdown_6" + COUNTDOWN_7 = "countdown_7" + COUNTDOWN_8 = "countdown_8" COUNTDOWN_LEFT = "countdown_left" COUNTDOWN_SET = "countdown_set" # Countdown setting CRY_DETECTION_SWITCH = "cry_detection_switch" diff --git a/homeassistant/components/tuya/number.py b/homeassistant/components/tuya/number.py index 88216ae3d069c7..7fadaa0489bd88 100644 --- a/homeassistant/components/tuya/number.py +++ b/homeassistant/components/tuya/number.py @@ -224,6 +224,66 @@ entity_category=EntityCategory.CONFIG, ), ), + # Smart Water Timer + "sfkzq": ( + # Controls the irrigation duration for the water valve + NumberEntityDescription( + key=DPCode.COUNTDOWN_1, + translation_key="indexed_irrigation_duration", + translation_placeholders={"index": "1"}, + device_class=NumberDeviceClass.DURATION, + entity_category=EntityCategory.CONFIG, + ), + NumberEntityDescription( + key=DPCode.COUNTDOWN_2, + translation_key="indexed_irrigation_duration", + translation_placeholders={"index": "2"}, + device_class=NumberDeviceClass.DURATION, + entity_category=EntityCategory.CONFIG, + ), + NumberEntityDescription( + key=DPCode.COUNTDOWN_3, + translation_key="indexed_irrigation_duration", + translation_placeholders={"index": "3"}, + device_class=NumberDeviceClass.DURATION, + entity_category=EntityCategory.CONFIG, + ), + NumberEntityDescription( + key=DPCode.COUNTDOWN_4, + translation_key="indexed_irrigation_duration", + translation_placeholders={"index": "4"}, + device_class=NumberDeviceClass.DURATION, + entity_category=EntityCategory.CONFIG, + ), + NumberEntityDescription( + key=DPCode.COUNTDOWN_5, + translation_key="indexed_irrigation_duration", + translation_placeholders={"index": "5"}, + device_class=NumberDeviceClass.DURATION, + entity_category=EntityCategory.CONFIG, + ), + NumberEntityDescription( + key=DPCode.COUNTDOWN_6, + translation_key="indexed_irrigation_duration", + translation_placeholders={"index": "6"}, + device_class=NumberDeviceClass.DURATION, + entity_category=EntityCategory.CONFIG, + ), + NumberEntityDescription( + key=DPCode.COUNTDOWN_7, + translation_key="indexed_irrigation_duration", + translation_placeholders={"index": "7"}, + device_class=NumberDeviceClass.DURATION, + entity_category=EntityCategory.CONFIG, + ), + NumberEntityDescription( + key=DPCode.COUNTDOWN_8, + translation_key="indexed_irrigation_duration", + translation_placeholders={"index": "8"}, + device_class=NumberDeviceClass.DURATION, + entity_category=EntityCategory.CONFIG, + ), + ), # Siren Alarm # https://developer.tuya.com/en/docs/iot/categorysgbj?id=Kaiuz37tlpbnu "sgbj": ( diff --git a/homeassistant/components/tuya/strings.json b/homeassistant/components/tuya/strings.json index c8268484c3a5ac..fab93b52fc1c3f 100644 --- a/homeassistant/components/tuya/strings.json +++ b/homeassistant/components/tuya/strings.json @@ -148,6 +148,9 @@ "heat_preservation_time": { "name": "Heat preservation time" }, + "indexed_irrigation_duration": { + "name": "Irrigation duration {index}" + }, "feed": { "name": "Feed" }, @@ -899,6 +902,11 @@ "frost_protection": { "name": "Frost protection" } + }, + "valve": { + "indexed_valve": { + "name": "Valve {index}" + } } }, "exceptions": { diff --git a/homeassistant/components/tuya/valve.py b/homeassistant/components/tuya/valve.py new file mode 100644 index 00000000000000..06218c7030fb5c --- /dev/null +++ b/homeassistant/components/tuya/valve.py @@ -0,0 +1,140 @@ +"""Support for Tuya valves.""" + +from __future__ import annotations + +from tuya_sharing import CustomerDevice, Manager + +from homeassistant.components.valve import ( + ValveDeviceClass, + ValveEntity, + ValveEntityDescription, + ValveEntityFeature, +) +from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers.dispatcher import async_dispatcher_connect +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback + +from . import TuyaConfigEntry +from .const import TUYA_DISCOVERY_NEW, DPCode +from .entity import TuyaEntity + +# All descriptions can be found here. Mostly the Boolean data types in the +# default instruction set of each category end up being a Valve. +# https://developer.tuya.com/en/docs/iot/standarddescription?id=K9i5ql6waswzq +VALVES: dict[str, tuple[ValveEntityDescription, ...]] = { + # Smart Water Timer + "sfkzq": ( + ValveEntityDescription( + key=DPCode.SWITCH_1, + translation_key="indexed_valve", + translation_placeholders={"index": "1"}, + device_class=ValveDeviceClass.WATER, + ), + ValveEntityDescription( + key=DPCode.SWITCH_2, + translation_key="indexed_valve", + translation_placeholders={"index": "2"}, + device_class=ValveDeviceClass.WATER, + ), + ValveEntityDescription( + key=DPCode.SWITCH_3, + translation_key="indexed_valve", + translation_placeholders={"index": "3"}, + device_class=ValveDeviceClass.WATER, + ), + ValveEntityDescription( + key=DPCode.SWITCH_4, + translation_key="indexed_valve", + translation_placeholders={"index": "4"}, + device_class=ValveDeviceClass.WATER, + ), + ValveEntityDescription( + key=DPCode.SWITCH_5, + translation_key="indexed_valve", + translation_placeholders={"index": "5"}, + device_class=ValveDeviceClass.WATER, + ), + ValveEntityDescription( + key=DPCode.SWITCH_6, + translation_key="indexed_valve", + translation_placeholders={"index": "6"}, + device_class=ValveDeviceClass.WATER, + ), + ValveEntityDescription( + key=DPCode.SWITCH_7, + translation_key="indexed_valve", + translation_placeholders={"index": "7"}, + device_class=ValveDeviceClass.WATER, + ), + ValveEntityDescription( + key=DPCode.SWITCH_8, + translation_key="indexed_valve", + translation_placeholders={"index": "8"}, + device_class=ValveDeviceClass.WATER, + ), + ), +} + + +async def async_setup_entry( + hass: HomeAssistant, + entry: TuyaConfigEntry, + async_add_entities: AddConfigEntryEntitiesCallback, +) -> None: + """Set up tuya valves dynamically through tuya discovery.""" + hass_data = entry.runtime_data + + @callback + def async_discover_device(device_ids: list[str]) -> None: + """Discover and add a discovered tuya valve.""" + entities: list[TuyaValveEntity] = [] + for device_id in device_ids: + device = hass_data.manager.device_map[device_id] + if descriptions := VALVES.get(device.category): + entities.extend( + TuyaValveEntity(device, hass_data.manager, description) + for description in descriptions + if description.key in device.status + ) + + async_add_entities(entities) + + async_discover_device([*hass_data.manager.device_map]) + + entry.async_on_unload( + async_dispatcher_connect(hass, TUYA_DISCOVERY_NEW, async_discover_device) + ) + + +class TuyaValveEntity(TuyaEntity, ValveEntity): + """Tuya Valve Device.""" + + _attr_supported_features = ValveEntityFeature.OPEN | ValveEntityFeature.CLOSE + + def __init__( + self, + device: CustomerDevice, + device_manager: Manager, + description: ValveEntityDescription, + ) -> None: + """Init TuyaValveEntity.""" + super().__init__(device, device_manager) + self.entity_description = description + self._attr_unique_id = f"{super().unique_id}{description.key}" + + @property + def is_closed(self) -> bool: + """Return if the valve is closed.""" + return not self.device.status.get(self.entity_description.key, False) + + async def async_open_valve(self) -> None: + """Open the valve.""" + await self.hass.async_add_executor_job( + self._send_command, [{"code": self.entity_description.key, "value": True}] + ) + + async def async_close_valve(self) -> None: + """Close the valve.""" + await self.hass.async_add_executor_job( + self._send_command, [{"code": self.entity_description.key, "value": False}] + ) diff --git a/tests/components/tuya/__init__.py b/tests/components/tuya/__init__.py index 44fe55fbb0b15b..5daa3d77427e29 100644 --- a/tests/components/tuya/__init__.py +++ b/tests/components/tuya/__init__.py @@ -140,6 +140,7 @@ "sd_i6hyjg3af7doaswm", # https://github.com/orgs/home-assistant/discussions/539 "sd_lr33znaodtyarrrz", # https://github.com/home-assistant/core/issues/141278 "sfkzq_1fcnd8xk", # https://github.com/orgs/home-assistant/discussions/539 + "sfkzq_ed7frwissyqrejic", # https://github.com/home-assistant/core/pull/149236 "sfkzq_o6dagifntoafakst", # https://github.com/home-assistant/core/issues/148116 "sfkzq_rzklytdei8i8vo37", # https://github.com/home-assistant/core/issues/146164 "sgbj_ulv4nnue7gqp0rjk", # https://github.com/home-assistant/core/issues/149704 diff --git a/tests/components/tuya/fixtures/sfkzq_ed7frwissyqrejic.json b/tests/components/tuya/fixtures/sfkzq_ed7frwissyqrejic.json new file mode 100644 index 00000000000000..e301e25930fa2e --- /dev/null +++ b/tests/components/tuya/fixtures/sfkzq_ed7frwissyqrejic.json @@ -0,0 +1,282 @@ +{ + "endpoint": "https://apigw.tuyacn.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "\u63a5HA\u6c34\u9600", + "category": "sfkzq", + "product_id": "ed7frwissyqrejic", + "product_name": "\u63a5HA\u6c34\u9600", + "online": true, + "sub": false, + "time_zone": "+08:00", + "active_time": "2025-07-14T06:32:48+00:00", + "create_time": "2025-07-14T06:32:48+00:00", + "update_time": "2025-07-14T06:32:48+00:00", + "function": { + "switch_1": { + "type": "Boolean", + "value": {} + }, + "switch_2": { + "type": "Boolean", + "value": {} + }, + "switch_3": { + "type": "Boolean", + "value": {} + }, + "switch_4": { + "type": "Boolean", + "value": {} + }, + "switch_5": { + "type": "Boolean", + "value": {} + }, + "switch_6": { + "type": "Boolean", + "value": {} + }, + "switch_7": { + "type": "Boolean", + "value": {} + }, + "switch_8": { + "type": "Boolean", + "value": {} + }, + "countdown_1": { + "type": "Integer", + "value": { + "unit": "min", + "min": 1, + "max": 1439, + "scale": 0, + "step": 1 + } + }, + "countdown_2": { + "type": "Integer", + "value": { + "unit": "min", + "min": 1, + "max": 1439, + "scale": 0, + "step": 1 + } + }, + "countdown_3": { + "type": "Integer", + "value": { + "unit": "min", + "min": 1, + "max": 1439, + "scale": 0, + "step": 1 + } + }, + "countdown_4": { + "type": "Integer", + "value": { + "unit": "min", + "min": 1, + "max": 1439, + "scale": 0, + "step": 1 + } + }, + "countdown_5": { + "type": "Integer", + "value": { + "unit": "min", + "min": 1, + "max": 1439, + "scale": 0, + "step": 1 + } + }, + "countdown_6": { + "type": "Integer", + "value": { + "unit": "min", + "min": 1, + "max": 1439, + "scale": 0, + "step": 1 + } + }, + "countdown_7": { + "type": "Integer", + "value": { + "unit": "min", + "min": 1, + "max": 1439, + "scale": 0, + "step": 1 + } + }, + "countdown_8": { + "type": "Integer", + "value": { + "unit": "min", + "min": 1, + "max": 1439, + "scale": 0, + "step": 1 + } + } + }, + "status_range": { + "switch_1": { + "type": "Boolean", + "value": {} + }, + "switch_2": { + "type": "Boolean", + "value": {} + }, + "switch_3": { + "type": "Boolean", + "value": {} + }, + "switch_4": { + "type": "Boolean", + "value": {} + }, + "switch_5": { + "type": "Boolean", + "value": {} + }, + "switch_6": { + "type": "Boolean", + "value": {} + }, + "switch_7": { + "type": "Boolean", + "value": {} + }, + "switch_8": { + "type": "Boolean", + "value": {} + }, + "countdown_1": { + "type": "Integer", + "value": { + "unit": "min", + "min": 1, + "max": 1439, + "scale": 0, + "step": 1 + } + }, + "countdown_2": { + "type": "Integer", + "value": { + "unit": "min", + "min": 1, + "max": 1439, + "scale": 0, + "step": 1 + } + }, + "countdown_3": { + "type": "Integer", + "value": { + "unit": "min", + "min": 1, + "max": 1439, + "scale": 0, + "step": 1 + } + }, + "countdown_4": { + "type": "Integer", + "value": { + "unit": "min", + "min": 1, + "max": 1439, + "scale": 0, + "step": 1 + } + }, + "countdown_5": { + "type": "Integer", + "value": { + "unit": "min", + "min": 1, + "max": 1439, + "scale": 0, + "step": 1 + } + }, + "countdown_6": { + "type": "Integer", + "value": { + "unit": "min", + "min": 1, + "max": 1439, + "scale": 0, + "step": 1 + } + }, + "countdown_7": { + "type": "Integer", + "value": { + "unit": "min", + "min": 1, + "max": 1439, + "scale": 0, + "step": 1 + } + }, + "countdown_8": { + "type": "Integer", + "value": { + "unit": "min", + "min": 1, + "max": 1439, + "scale": 0, + "step": 1 + } + }, + "battery_percentage": { + "type": "Integer", + "value": { + "unit": "%", + "min": 0, + "max": 100, + "scale": 0, + "step": 1 + } + }, + "battery_state": { + "type": "Enum", + "value": { + "range": ["low", "middle", "high"] + } + } + }, + "status": { + "switch_1": true, + "switch_2": false, + "switch_3": true, + "switch_4": false, + "switch_5": true, + "switch_6": false, + "switch_7": true, + "switch_8": false, + "countdown_1": 1, + "countdown_2": 1, + "countdown_3": 3, + "countdown_4": 2, + "countdown_5": 2, + "countdown_6": 3, + "countdown_7": 1, + "countdown_8": 1, + "battery_percentage": 0, + "battery_state": "low" + }, + "set_up": true, + "support_local": true +} diff --git a/tests/components/tuya/snapshots/test_number.ambr b/tests/components/tuya/snapshots/test_number.ambr index adfc7543a3e6a0..b100743104685a 100644 --- a/tests/components/tuya/snapshots/test_number.ambr +++ b/tests/components/tuya/snapshots/test_number.ambr @@ -643,6 +643,478 @@ 'state': '3.0', }) # --- +# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'max': 1439.0, + 'min': 1.0, + 'mode': , + 'step': 1.0, + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'number', + 'entity_category': , + 'entity_id': 'number.jie_hashui_fa_irrigation_duration_1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Irrigation duration 1', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'indexed_irrigation_duration', + 'unique_id': 'tuya.cijerqyssiwrf7deqzkfscountdown_1', + 'unit_of_measurement': 'min', + }) +# --- +# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'duration', + 'friendly_name': '接HA水阀 Irrigation duration 1', + 'max': 1439.0, + 'min': 1.0, + 'mode': , + 'step': 1.0, + 'unit_of_measurement': 'min', + }), + 'context': , + 'entity_id': 'number.jie_hashui_fa_irrigation_duration_1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '1.0', + }) +# --- +# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_2-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'max': 1439.0, + 'min': 1.0, + 'mode': , + 'step': 1.0, + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'number', + 'entity_category': , + 'entity_id': 'number.jie_hashui_fa_irrigation_duration_2', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Irrigation duration 2', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'indexed_irrigation_duration', + 'unique_id': 'tuya.cijerqyssiwrf7deqzkfscountdown_2', + 'unit_of_measurement': 'min', + }) +# --- +# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_2-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'duration', + 'friendly_name': '接HA水阀 Irrigation duration 2', + 'max': 1439.0, + 'min': 1.0, + 'mode': , + 'step': 1.0, + 'unit_of_measurement': 'min', + }), + 'context': , + 'entity_id': 'number.jie_hashui_fa_irrigation_duration_2', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '1.0', + }) +# --- +# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_3-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'max': 1439.0, + 'min': 1.0, + 'mode': , + 'step': 1.0, + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'number', + 'entity_category': , + 'entity_id': 'number.jie_hashui_fa_irrigation_duration_3', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Irrigation duration 3', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'indexed_irrigation_duration', + 'unique_id': 'tuya.cijerqyssiwrf7deqzkfscountdown_3', + 'unit_of_measurement': 'min', + }) +# --- +# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_3-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'duration', + 'friendly_name': '接HA水阀 Irrigation duration 3', + 'max': 1439.0, + 'min': 1.0, + 'mode': , + 'step': 1.0, + 'unit_of_measurement': 'min', + }), + 'context': , + 'entity_id': 'number.jie_hashui_fa_irrigation_duration_3', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '3.0', + }) +# --- +# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_4-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'max': 1439.0, + 'min': 1.0, + 'mode': , + 'step': 1.0, + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'number', + 'entity_category': , + 'entity_id': 'number.jie_hashui_fa_irrigation_duration_4', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Irrigation duration 4', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'indexed_irrigation_duration', + 'unique_id': 'tuya.cijerqyssiwrf7deqzkfscountdown_4', + 'unit_of_measurement': 'min', + }) +# --- +# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_4-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'duration', + 'friendly_name': '接HA水阀 Irrigation duration 4', + 'max': 1439.0, + 'min': 1.0, + 'mode': , + 'step': 1.0, + 'unit_of_measurement': 'min', + }), + 'context': , + 'entity_id': 'number.jie_hashui_fa_irrigation_duration_4', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2.0', + }) +# --- +# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_5-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'max': 1439.0, + 'min': 1.0, + 'mode': , + 'step': 1.0, + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'number', + 'entity_category': , + 'entity_id': 'number.jie_hashui_fa_irrigation_duration_5', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Irrigation duration 5', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'indexed_irrigation_duration', + 'unique_id': 'tuya.cijerqyssiwrf7deqzkfscountdown_5', + 'unit_of_measurement': 'min', + }) +# --- +# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_5-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'duration', + 'friendly_name': '接HA水阀 Irrigation duration 5', + 'max': 1439.0, + 'min': 1.0, + 'mode': , + 'step': 1.0, + 'unit_of_measurement': 'min', + }), + 'context': , + 'entity_id': 'number.jie_hashui_fa_irrigation_duration_5', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2.0', + }) +# --- +# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_6-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'max': 1439.0, + 'min': 1.0, + 'mode': , + 'step': 1.0, + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'number', + 'entity_category': , + 'entity_id': 'number.jie_hashui_fa_irrigation_duration_6', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Irrigation duration 6', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'indexed_irrigation_duration', + 'unique_id': 'tuya.cijerqyssiwrf7deqzkfscountdown_6', + 'unit_of_measurement': 'min', + }) +# --- +# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_6-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'duration', + 'friendly_name': '接HA水阀 Irrigation duration 6', + 'max': 1439.0, + 'min': 1.0, + 'mode': , + 'step': 1.0, + 'unit_of_measurement': 'min', + }), + 'context': , + 'entity_id': 'number.jie_hashui_fa_irrigation_duration_6', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '3.0', + }) +# --- +# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_7-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'max': 1439.0, + 'min': 1.0, + 'mode': , + 'step': 1.0, + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'number', + 'entity_category': , + 'entity_id': 'number.jie_hashui_fa_irrigation_duration_7', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Irrigation duration 7', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'indexed_irrigation_duration', + 'unique_id': 'tuya.cijerqyssiwrf7deqzkfscountdown_7', + 'unit_of_measurement': 'min', + }) +# --- +# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_7-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'duration', + 'friendly_name': '接HA水阀 Irrigation duration 7', + 'max': 1439.0, + 'min': 1.0, + 'mode': , + 'step': 1.0, + 'unit_of_measurement': 'min', + }), + 'context': , + 'entity_id': 'number.jie_hashui_fa_irrigation_duration_7', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '1.0', + }) +# --- +# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_8-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'max': 1439.0, + 'min': 1.0, + 'mode': , + 'step': 1.0, + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'number', + 'entity_category': , + 'entity_id': 'number.jie_hashui_fa_irrigation_duration_8', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Irrigation duration 8', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'indexed_irrigation_duration', + 'unique_id': 'tuya.cijerqyssiwrf7deqzkfscountdown_8', + 'unit_of_measurement': 'min', + }) +# --- +# name: test_platform_setup_and_discovery[number.jie_hashui_fa_irrigation_duration_8-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'duration', + 'friendly_name': '接HA水阀 Irrigation duration 8', + 'max': 1439.0, + 'min': 1.0, + 'mode': , + 'step': 1.0, + 'unit_of_measurement': 'min', + }), + 'context': , + 'entity_id': 'number.jie_hashui_fa_irrigation_duration_8', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '1.0', + }) +# --- # name: test_platform_setup_and_discovery[number.kabinet_temperature_correction-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/tuya/snapshots/test_sensor.ambr b/tests/components/tuya/snapshots/test_sensor.ambr index 375e52f6bbde91..88731f34f1097c 100644 --- a/tests/components/tuya/snapshots/test_sensor.ambr +++ b/tests/components/tuya/snapshots/test_sensor.ambr @@ -6094,6 +6094,107 @@ 'state': '9.0', }) # --- +# name: test_platform_setup_and_discovery[sensor.jie_hashui_fa_battery-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jie_hashui_fa_battery', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery', + 'unique_id': 'tuya.cijerqyssiwrf7deqzkfsbattery_percentage', + 'unit_of_measurement': '%', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.jie_hashui_fa_battery-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': '接HA水阀 Battery', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.jie_hashui_fa_battery', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0.0', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.jie_hashui_fa_battery_state-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.jie_hashui_fa_battery_state', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Battery state', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_state', + 'unique_id': 'tuya.cijerqyssiwrf7deqzkfsbattery_state', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[sensor.jie_hashui_fa_battery_state-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': '接HA水阀 Battery state', + }), + 'context': , + 'entity_id': 'sensor.jie_hashui_fa_battery_state', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'low', + }) +# --- # name: test_platform_setup_and_discovery[sensor.kalado_air_purifier_air_quality-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/tuya/snapshots/test_valve.ambr b/tests/components/tuya/snapshots/test_valve.ambr new file mode 100644 index 00000000000000..cb5f78a561069c --- /dev/null +++ b/tests/components/tuya/snapshots/test_valve.ambr @@ -0,0 +1,401 @@ +# serializer version: 1 +# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'valve', + 'entity_category': None, + 'entity_id': 'valve.jie_hashui_fa_valve_1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Valve 1', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': , + 'translation_key': 'indexed_valve', + 'unique_id': 'tuya.cijerqyssiwrf7deqzkfsswitch_1', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'water', + 'friendly_name': '接HA水阀 Valve 1', + 'supported_features': , + }), + 'context': , + 'entity_id': 'valve.jie_hashui_fa_valve_1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'open', + }) +# --- +# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_2-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'valve', + 'entity_category': None, + 'entity_id': 'valve.jie_hashui_fa_valve_2', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Valve 2', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': , + 'translation_key': 'indexed_valve', + 'unique_id': 'tuya.cijerqyssiwrf7deqzkfsswitch_2', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_2-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'water', + 'friendly_name': '接HA水阀 Valve 2', + 'supported_features': , + }), + 'context': , + 'entity_id': 'valve.jie_hashui_fa_valve_2', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'closed', + }) +# --- +# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_3-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'valve', + 'entity_category': None, + 'entity_id': 'valve.jie_hashui_fa_valve_3', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Valve 3', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': , + 'translation_key': 'indexed_valve', + 'unique_id': 'tuya.cijerqyssiwrf7deqzkfsswitch_3', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_3-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'water', + 'friendly_name': '接HA水阀 Valve 3', + 'supported_features': , + }), + 'context': , + 'entity_id': 'valve.jie_hashui_fa_valve_3', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'open', + }) +# --- +# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_4-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'valve', + 'entity_category': None, + 'entity_id': 'valve.jie_hashui_fa_valve_4', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Valve 4', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': , + 'translation_key': 'indexed_valve', + 'unique_id': 'tuya.cijerqyssiwrf7deqzkfsswitch_4', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_4-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'water', + 'friendly_name': '接HA水阀 Valve 4', + 'supported_features': , + }), + 'context': , + 'entity_id': 'valve.jie_hashui_fa_valve_4', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'closed', + }) +# --- +# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_5-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'valve', + 'entity_category': None, + 'entity_id': 'valve.jie_hashui_fa_valve_5', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Valve 5', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': , + 'translation_key': 'indexed_valve', + 'unique_id': 'tuya.cijerqyssiwrf7deqzkfsswitch_5', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_5-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'water', + 'friendly_name': '接HA水阀 Valve 5', + 'supported_features': , + }), + 'context': , + 'entity_id': 'valve.jie_hashui_fa_valve_5', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'open', + }) +# --- +# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_6-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'valve', + 'entity_category': None, + 'entity_id': 'valve.jie_hashui_fa_valve_6', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Valve 6', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': , + 'translation_key': 'indexed_valve', + 'unique_id': 'tuya.cijerqyssiwrf7deqzkfsswitch_6', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_6-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'water', + 'friendly_name': '接HA水阀 Valve 6', + 'supported_features': , + }), + 'context': , + 'entity_id': 'valve.jie_hashui_fa_valve_6', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'closed', + }) +# --- +# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_7-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'valve', + 'entity_category': None, + 'entity_id': 'valve.jie_hashui_fa_valve_7', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Valve 7', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': , + 'translation_key': 'indexed_valve', + 'unique_id': 'tuya.cijerqyssiwrf7deqzkfsswitch_7', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_7-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'water', + 'friendly_name': '接HA水阀 Valve 7', + 'supported_features': , + }), + 'context': , + 'entity_id': 'valve.jie_hashui_fa_valve_7', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'open', + }) +# --- +# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_8-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'valve', + 'entity_category': None, + 'entity_id': 'valve.jie_hashui_fa_valve_8', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Valve 8', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': , + 'translation_key': 'indexed_valve', + 'unique_id': 'tuya.cijerqyssiwrf7deqzkfsswitch_8', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[valve.jie_hashui_fa_valve_8-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'water', + 'friendly_name': '接HA水阀 Valve 8', + 'supported_features': , + }), + 'context': , + 'entity_id': 'valve.jie_hashui_fa_valve_8', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'closed', + }) +# --- diff --git a/tests/components/tuya/test_valve.py b/tests/components/tuya/test_valve.py new file mode 100644 index 00000000000000..9c00f0f4c751f7 --- /dev/null +++ b/tests/components/tuya/test_valve.py @@ -0,0 +1,96 @@ +"""Test Tuya valve platform.""" + +from __future__ import annotations + +from unittest.mock import patch + +import pytest +from syrupy.assertion import SnapshotAssertion +from tuya_sharing import CustomerDevice + +from homeassistant.components.tuya import ManagerCompat +from homeassistant.components.valve import ( + DOMAIN as VALVE_DOMAIN, + SERVICE_CLOSE_VALVE, + SERVICE_OPEN_VALVE, +) +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er + +from . import initialize_entry + +from tests.common import MockConfigEntry, snapshot_platform + + +@patch("homeassistant.components.tuya.PLATFORMS", [Platform.VALVE]) +async def test_platform_setup_and_discovery( + hass: HomeAssistant, + mock_manager: ManagerCompat, + mock_config_entry: MockConfigEntry, + mock_devices: list[CustomerDevice], + entity_registry: er.EntityRegistry, + snapshot: SnapshotAssertion, +) -> None: + """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", + ["sfkzq_ed7frwissyqrejic"], +) +async def test_open_valve( + hass: HomeAssistant, + mock_manager: ManagerCompat, + mock_config_entry: MockConfigEntry, + mock_device: CustomerDevice, +) -> None: + """Test opening a valve.""" + entity_id = "valve.jie_hashui_fa_valve_1" + await initialize_entry(hass, mock_manager, mock_config_entry, mock_device) + + state = hass.states.get(entity_id) + assert state is not None, f"{entity_id} does not exist" + await hass.services.async_call( + VALVE_DOMAIN, + SERVICE_OPEN_VALVE, + { + "entity_id": entity_id, + }, + blocking=True, + ) + mock_manager.send_commands.assert_called_once_with( + mock_device.id, [{"code": "switch_1", "value": True}] + ) + + +@pytest.mark.parametrize( + "mock_device_code", + ["sfkzq_ed7frwissyqrejic"], +) +async def test_close_valve( + hass: HomeAssistant, + mock_manager: ManagerCompat, + mock_config_entry: MockConfigEntry, + mock_device: CustomerDevice, +) -> None: + """Test closing a valve.""" + entity_id = "valve.jie_hashui_fa_valve_1" + await initialize_entry(hass, mock_manager, mock_config_entry, mock_device) + + state = hass.states.get(entity_id) + assert state is not None, f"{entity_id} does not exist" + await hass.services.async_call( + VALVE_DOMAIN, + SERVICE_CLOSE_VALVE, + { + "entity_id": entity_id, + }, + blocking=True, + ) + mock_manager.send_commands.assert_called_once_with( + mock_device.id, [{"code": "switch_1", "value": False}] + ) From fb4a4528723e38797f9f905b8c8e2444a6f5fc48 Mon Sep 17 00:00:00 2001 From: yufeng Date: Tue, 12 Aug 2025 17:02:03 +0800 Subject: [PATCH 8/8] Add supply frequency sensors to Tuya energy monitoring devices (#149320) Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> --- homeassistant/components/tuya/const.py | 1 + homeassistant/components/tuya/sensor.py | 14 + homeassistant/components/tuya/strings.json | 3 + tests/components/tuya/__init__.py | 1 + .../tuya/fixtures/dlq_cnpkf4xdmd9v49iq.json | 158 ++++++++ .../tuya/snapshots/test_sensor.ambr | 336 ++++++++++++++++++ .../tuya/snapshots/test_switch.ambr | 96 +++++ 7 files changed, 609 insertions(+) create mode 100644 tests/components/tuya/fixtures/dlq_cnpkf4xdmd9v49iq.json diff --git a/homeassistant/components/tuya/const.py b/homeassistant/components/tuya/const.py index 752911f98f6a73..6c4b1c02b226cd 100644 --- a/homeassistant/components/tuya/const.py +++ b/homeassistant/components/tuya/const.py @@ -328,6 +328,7 @@ class DPCode(StrEnum): STATUS = "status" STERILIZATION = "sterilization" # Sterilization SUCTION = "suction" + SUPPLY_FREQUENCY = "supply_frequency" SWING = "swing" # Swing mode SWITCH = "switch" # Switch SWITCH_1 = "switch_1" # Switch 1 diff --git a/homeassistant/components/tuya/sensor.py b/homeassistant/components/tuya/sensor.py index a22eba6cc3544f..82ddb1ee0ab8c6 100644 --- a/homeassistant/components/tuya/sensor.py +++ b/homeassistant/components/tuya/sensor.py @@ -363,6 +363,13 @@ class TuyaSensorEntityDescription(SensorEntityDescription): device_class=SensorDeviceClass.ENERGY, state_class=SensorStateClass.TOTAL_INCREASING, ), + TuyaSensorEntityDescription( + key=DPCode.SUPPLY_FREQUENCY, + translation_key="supply_frequency", + device_class=SensorDeviceClass.FREQUENCY, + entity_category=EntityCategory.DIAGNOSTIC, + state_class=SensorStateClass.MEASUREMENT, + ), TuyaSensorEntityDescription( key=DPCode.PHASE_A, translation_key="phase_a_current", @@ -1346,6 +1353,13 @@ class TuyaSensorEntityDescription(SensorEntityDescription): complex_type=ElectricityTypeData, subkey="power", ), + TuyaSensorEntityDescription( + key=DPCode.SUPPLY_FREQUENCY, + translation_key="supply_frequency", + device_class=SensorDeviceClass.FREQUENCY, + entity_category=EntityCategory.DIAGNOSTIC, + state_class=SensorStateClass.MEASUREMENT, + ), TuyaSensorEntityDescription( key=DPCode.PHASE_A, translation_key="phase_a_current", diff --git a/homeassistant/components/tuya/strings.json b/homeassistant/components/tuya/strings.json index fab93b52fc1c3f..f185e8d54892f1 100644 --- a/homeassistant/components/tuya/strings.json +++ b/homeassistant/components/tuya/strings.json @@ -743,6 +743,9 @@ }, "liquid_level": { "name": "Liquid level" + }, + "supply_frequency": { + "name": "Supply frequency" } }, "switch": { diff --git a/tests/components/tuya/__init__.py b/tests/components/tuya/__init__.py index 5daa3d77427e29..a9087b92211afb 100644 --- a/tests/components/tuya/__init__.py +++ b/tests/components/tuya/__init__.py @@ -96,6 +96,7 @@ "dj_zav1pa32pyxray78", # https://github.com/home-assistant/core/issues/149704 "dj_zputiamzanuk6yky", # https://github.com/home-assistant/core/issues/149704 "dlq_0tnvg2xaisqdadcf", # https://github.com/home-assistant/core/issues/102769 + "dlq_cnpkf4xdmd9v49iq", # https://github.com/home-assistant/core/pull/149320 "dlq_jdj6ccklup7btq3a", # https://github.com/home-assistant/core/issues/143209 "dlq_kxdr6su0c55p7bbo", # https://github.com/home-assistant/core/issues/143499 "dlq_r9kg2g1uhhyicycb", # https://github.com/home-assistant/core/issues/149650 diff --git a/tests/components/tuya/fixtures/dlq_cnpkf4xdmd9v49iq.json b/tests/components/tuya/fixtures/dlq_cnpkf4xdmd9v49iq.json new file mode 100644 index 00000000000000..aa42fc0f5682b3 --- /dev/null +++ b/tests/components/tuya/fixtures/dlq_cnpkf4xdmd9v49iq.json @@ -0,0 +1,158 @@ +{ + "endpoint": "https://apigw.tuyacn.com", + "mqtt_connected": true, + "disabled_by": null, + "disabled_polling": false, + "name": "\u65ad\u8def\u5668HA", + "category": "dlq", + "product_id": "cnpkf4xdmd9v49iq", + "product_name": "Breaker", + "online": true, + "sub": false, + "time_zone": "+08:00", + "active_time": "2025-07-03T10:19:11+00:00", + "create_time": "2025-07-03T10:19:11+00:00", + "update_time": "2025-07-03T10:19:11+00:00", + "function": { + "switch": { + "type": "Boolean", + "value": {} + }, + "alarm_set_1": { + "type": "Raw", + "value": {} + }, + "alarm_set_2": { + "type": "Raw", + "value": {} + }, + "leakagecurr_test": { + "type": "Boolean", + "value": {} + }, + "online_state": { + "type": "Enum", + "value": { + "range": ["online", "offline"] + } + }, + "child_lock": { + "type": "Boolean", + "value": {} + } + }, + "status_range": { + "forward_energy_total": { + "type": "Integer", + "value": { + "unit": "kW\u00b7h", + "min": 0, + "max": 99999999, + "scale": 3, + "step": 1 + } + }, + "phase_a": { + "type": "Raw", + "value": {} + }, + "fault": { + "type": "Bitmap", + "value": { + "label": [ + "short_circuit_alarm", + "surge_alarm", + "overload_alarm", + "leakagecurr_alarm", + "temp_dif_fault", + "fire_alarm", + "high_power_alarm", + "self_test_alarm", + "ov_cr", + "unbalance_alarm", + "ov_vol", + "undervoltage_alarm", + "miss_phase_alarm", + "outage_alarm", + "magnetism_alarm", + "credit_alarm", + "no_balance_alarm", + "leakage_early_warning", + "overcur_early_warning", + "overvol_early_warning", + "overpow_early_warning", + "undvol_early_warning", + "higtemp_early_warning" + ] + } + }, + "leakage_current": { + "type": "Integer", + "value": { + "unit": "mA", + "min": 0, + "max": 1000, + "scale": 0, + "step": 1 + } + }, + "switch": { + "type": "Boolean", + "value": {} + }, + "alarm_set_1": { + "type": "Raw", + "value": {} + }, + "alarm_set_2": { + "type": "Raw", + "value": {} + }, + "breaker_number": { + "type": "String", + "value": { + "maxlen": 255 + } + }, + "leakagecurr_test": { + "type": "Boolean", + "value": {} + }, + "supply_frequency": { + "type": "Integer", + "value": { + "unit": "Hz", + "min": 0, + "max": 9999, + "scale": 2, + "step": 1 + } + }, + "online_state": { + "type": "Enum", + "value": { + "range": ["online", "offline"] + } + }, + "child_lock": { + "type": "Boolean", + "value": {} + } + }, + "status": { + "forward_energy_total": 120, + "phase_a": "Ag8JJQAASAAACAAAAAAACGME", + "fault": 0, + "leakage_current": 0, + "switch": false, + "alarm_set_1": "", + "alarm_set_2": "", + "breaker_number": "", + "leakagecurr_test": false, + "supply_frequency": 0, + "online_state": "online", + "child_lock": false + }, + "set_up": true, + "support_local": true +} diff --git a/tests/components/tuya/snapshots/test_sensor.ambr b/tests/components/tuya/snapshots/test_sensor.ambr index 88731f34f1097c..53003ac095a1ce 100644 --- a/tests/components/tuya/snapshots/test_sensor.ambr +++ b/tests/components/tuya/snapshots/test_sensor.ambr @@ -2818,6 +2818,230 @@ 'state': '222.4', }) # --- +# name: test_platform_setup_and_discovery[sensor.duan_lu_qi_ha_phase_a_current-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.duan_lu_qi_ha_phase_a_current', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Phase A current', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'phase_a_current', + 'unique_id': 'tuya.qi94v9dmdx4fkpncqldphase_aelectriccurrent', + 'unit_of_measurement': , + }) +# --- +# name: test_platform_setup_and_discovery[sensor.duan_lu_qi_ha_phase_a_current-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': '断路器HA Phase A current', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.duan_lu_qi_ha_phase_a_current', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '599.296', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.duan_lu_qi_ha_phase_a_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.duan_lu_qi_ha_phase_a_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Phase A power', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'phase_a_power', + 'unique_id': 'tuya.qi94v9dmdx4fkpncqldphase_apower', + 'unit_of_measurement': , + }) +# --- +# name: test_platform_setup_and_discovery[sensor.duan_lu_qi_ha_phase_a_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': '断路器HA Phase A power', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.duan_lu_qi_ha_phase_a_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '18.432', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.duan_lu_qi_ha_phase_a_voltage-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.duan_lu_qi_ha_phase_a_voltage', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Phase A voltage', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'phase_a_voltage', + 'unique_id': 'tuya.qi94v9dmdx4fkpncqldphase_avoltage', + 'unit_of_measurement': , + }) +# --- +# name: test_platform_setup_and_discovery[sensor.duan_lu_qi_ha_phase_a_voltage-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'voltage', + 'friendly_name': '断路器HA Phase A voltage', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.duan_lu_qi_ha_phase_a_voltage', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '52.7', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.duan_lu_qi_ha_supply_frequency-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.duan_lu_qi_ha_supply_frequency', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Supply frequency', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'supply_frequency', + 'unique_id': 'tuya.qi94v9dmdx4fkpncqldsupply_frequency', + 'unit_of_measurement': 'Hz', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.duan_lu_qi_ha_supply_frequency-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'frequency', + 'friendly_name': '断路器HA Supply frequency', + 'state_class': , + 'unit_of_measurement': 'Hz', + }), + 'context': , + 'entity_id': 'sensor.duan_lu_qi_ha_supply_frequency', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0.0', + }) +# --- # name: test_platform_setup_and_discovery[sensor.eau_chaude_current-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -7641,6 +7865,62 @@ 'state': '220.4', }) # --- +# name: test_platform_setup_and_discovery[sensor.metering_3pn_wifi_stable_supply_frequency-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.metering_3pn_wifi_stable_supply_frequency', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Supply frequency', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'supply_frequency', + 'unique_id': 'tuya.obb7p55c0us6rdxkqldsupply_frequency', + 'unit_of_measurement': 'Hz', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.metering_3pn_wifi_stable_supply_frequency-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'frequency', + 'friendly_name': 'Metering_3PN_WiFi_stable Supply frequency', + 'state_class': , + 'unit_of_measurement': 'Hz', + }), + 'context': , + 'entity_id': 'sensor.metering_3pn_wifi_stable_supply_frequency', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '50.0', + }) +# --- # name: test_platform_setup_and_discovery[sensor.motion_sensor_lidl_zigbee_battery-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ @@ -12542,6 +12822,62 @@ 'state': '52.7', }) # --- +# name: test_platform_setup_and_discovery[sensor.xoca_dac212xc_v2_s1_supply_frequency-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.xoca_dac212xc_v2_s1_supply_frequency', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Supply frequency', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'supply_frequency', + 'unique_id': 'tuya.9oh1h1uyalfykgg4bdnzsupply_frequency', + 'unit_of_measurement': 'Hz', + }) +# --- +# name: test_platform_setup_and_discovery[sensor.xoca_dac212xc_v2_s1_supply_frequency-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'frequency', + 'friendly_name': 'XOCA-DAC212XC V2-S1 Supply frequency', + 'state_class': , + 'unit_of_measurement': 'Hz', + }), + 'context': , + 'entity_id': 'sensor.xoca_dac212xc_v2_s1_supply_frequency', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0.0', + }) +# --- # name: test_platform_setup_and_discovery[sensor.xoca_dac212xc_v2_s1_total_energy-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/tuya/snapshots/test_switch.ambr b/tests/components/tuya/snapshots/test_switch.ambr index bff8c3e392ac09..d33c91118ef133 100644 --- a/tests/components/tuya/snapshots/test_switch.ambr +++ b/tests/components/tuya/snapshots/test_switch.ambr @@ -2565,6 +2565,102 @@ 'state': 'on', }) # --- +# name: test_platform_setup_and_discovery[switch.duan_lu_qi_ha_child_lock-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'switch', + 'entity_category': , + 'entity_id': 'switch.duan_lu_qi_ha_child_lock', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Child lock', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'child_lock', + 'unique_id': 'tuya.qi94v9dmdx4fkpncqldchild_lock', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[switch.duan_lu_qi_ha_child_lock-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': '断路器HA Child lock', + }), + 'context': , + 'entity_id': 'switch.duan_lu_qi_ha_child_lock', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- +# name: test_platform_setup_and_discovery[switch.duan_lu_qi_ha_switch-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'switch', + 'entity_category': None, + 'entity_id': 'switch.duan_lu_qi_ha_switch', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Switch', + 'platform': 'tuya', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'switch', + 'unique_id': 'tuya.qi94v9dmdx4fkpncqldswitch', + 'unit_of_measurement': None, + }) +# --- +# name: test_platform_setup_and_discovery[switch.duan_lu_qi_ha_switch-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': '断路器HA Switch', + }), + 'context': , + 'entity_id': 'switch.duan_lu_qi_ha_switch', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'off', + }) +# --- # name: test_platform_setup_and_discovery[switch.eau_chaude_child_lock-entry] EntityRegistryEntrySnapshot({ 'aliases': set({