mirror of
https://github.com/home-assistant/core.git
synced 2025-10-16 07:09:27 +00:00
Compare commits
4 Commits
fix-data-e
...
water_hier
Author | SHA1 | Date | |
---|---|---|---|
![]() |
03b58a4c21 | ||
![]() |
53d1bbb530 | ||
![]() |
a3ef55274e | ||
![]() |
2034915457 |
@@ -116,6 +116,10 @@ class WaterSourceType(TypedDict):
|
||||
# an EnergyCostSensor will be automatically created
|
||||
stat_cost: str | None
|
||||
|
||||
# An optional statistic_id identifying a device
|
||||
# that includes this device's consumption in its total
|
||||
included_in_stat: str | None
|
||||
|
||||
# Used to generate costs if stat_cost is set to None
|
||||
entity_energy_price: str | None # entity_id of an entity providing price ($/m³)
|
||||
number_energy_price: float | None # Price for energy ($/m³)
|
||||
|
@@ -24,6 +24,7 @@
|
||||
},
|
||||
"config_subentries": {
|
||||
"partition": {
|
||||
"entry_type": "Partition",
|
||||
"initiate_flow": {
|
||||
"user": "Add partition"
|
||||
},
|
||||
@@ -57,6 +58,7 @@
|
||||
}
|
||||
},
|
||||
"zone": {
|
||||
"entry_type": "Zone",
|
||||
"initiate_flow": {
|
||||
"user": "Add zone"
|
||||
},
|
||||
@@ -91,6 +93,7 @@
|
||||
}
|
||||
},
|
||||
"output": {
|
||||
"entry_type": "Output",
|
||||
"initiate_flow": {
|
||||
"user": "Add output"
|
||||
},
|
||||
@@ -125,6 +128,7 @@
|
||||
}
|
||||
},
|
||||
"switchable_output": {
|
||||
"entry_type": "Switchable output",
|
||||
"initiate_flow": {
|
||||
"user": "Add switchable output"
|
||||
},
|
||||
|
@@ -179,6 +179,13 @@ CAPABILITY_TO_SENSORS: dict[
|
||||
is_on_key="open",
|
||||
)
|
||||
},
|
||||
Capability.GAS_DETECTOR: {
|
||||
Attribute.GAS: SmartThingsBinarySensorEntityDescription(
|
||||
key=Attribute.GAS,
|
||||
device_class=BinarySensorDeviceClass.GAS,
|
||||
is_on_key="detected",
|
||||
)
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
@@ -530,7 +530,6 @@ CAPABILITY_TO_SENSORS: dict[
|
||||
)
|
||||
],
|
||||
},
|
||||
# Haven't seen at devices yet
|
||||
Capability.ILLUMINANCE_MEASUREMENT: {
|
||||
Attribute.ILLUMINANCE: [
|
||||
SmartThingsSensorEntityDescription(
|
||||
@@ -1010,7 +1009,6 @@ CAPABILITY_TO_SENSORS: dict[
|
||||
)
|
||||
]
|
||||
},
|
||||
# Haven't seen at devices yet
|
||||
Capability.ULTRAVIOLET_INDEX: {
|
||||
Attribute.ULTRAVIOLET_INDEX: [
|
||||
SmartThingsSensorEntityDescription(
|
||||
|
@@ -799,15 +799,14 @@ class FlowHandler(Generic[_FlowContextT, _FlowResultT, _HandlerT]):
|
||||
without using async_show_progress_done.
|
||||
If no next step is set, abort the flow.
|
||||
"""
|
||||
if (next_step_result := self._progress_step_data["next_step_result"]) is None:
|
||||
if self._progress_step_data["next_step_result"] is None:
|
||||
return self.async_abort(
|
||||
reason=self._progress_step_data["abort_reason"],
|
||||
description_placeholders=self._progress_step_data[
|
||||
"abort_description_placeholders"
|
||||
],
|
||||
)
|
||||
self._progress_step_data["next_step_result"] = None
|
||||
return next_step_result
|
||||
return self._progress_step_data["next_step_result"]
|
||||
|
||||
@callback
|
||||
def async_external_step(
|
||||
@@ -1045,7 +1044,7 @@ def progress_step[
|
||||
|
||||
# Task is done or this is a subsequent call
|
||||
try:
|
||||
progress_task_result = await progress_task
|
||||
self._progress_step_data["next_step_result"] = await progress_task
|
||||
except AbortFlow as err:
|
||||
self._progress_step_data["abort_reason"] = err.reason
|
||||
self._progress_step_data["abort_description_placeholders"] = (
|
||||
@@ -1058,9 +1057,6 @@ def progress_step[
|
||||
# Clean up task reference
|
||||
self._progress_step_data["tasks"].pop(step_id, None)
|
||||
|
||||
if progress_task_result["type"] != FlowResultType.SHOW_PROGRESS_DONE:
|
||||
self._progress_step_data["next_step_result"] = progress_task_result
|
||||
|
||||
return self.async_show_progress_done(
|
||||
next_step_id="_progress_step_progress_done"
|
||||
)
|
||||
|
@@ -97,6 +97,7 @@ def mock_smartthings() -> Generator[AsyncMock]:
|
||||
@pytest.fixture(
|
||||
params=[
|
||||
"aq_sensor_3_ikea",
|
||||
"aeotec_ms6",
|
||||
"da_ac_airsensor_01001",
|
||||
"da_ac_rac_000001",
|
||||
"da_ac_rac_000003",
|
||||
@@ -156,6 +157,7 @@ def mock_smartthings() -> Generator[AsyncMock]:
|
||||
"heatit_ztrm3_thermostat",
|
||||
"heatit_zpushwall",
|
||||
"generic_ef00_v1",
|
||||
"gas_detector",
|
||||
"bosch_radiator_thermostat_ii",
|
||||
"im_speaker_ai_0001",
|
||||
"im_smarttag2_ble_uwb",
|
||||
|
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"components": {
|
||||
"main": {
|
||||
"ultravioletIndex": {
|
||||
"ultravioletIndex": {
|
||||
"value": 0,
|
||||
"timestamp": "2025-09-30T15:13:46.521Z"
|
||||
}
|
||||
},
|
||||
"relativeHumidityMeasurement": {
|
||||
"humidity": {
|
||||
"value": 60.0,
|
||||
"unit": "%",
|
||||
"timestamp": "2025-09-30T15:13:45.441Z"
|
||||
}
|
||||
},
|
||||
"temperatureMeasurement": {
|
||||
"temperatureRange": {
|
||||
"value": null
|
||||
},
|
||||
"temperature": {
|
||||
"value": 22.2,
|
||||
"unit": "C",
|
||||
"timestamp": "2025-09-30T16:13:50.478Z"
|
||||
}
|
||||
},
|
||||
"refresh": {},
|
||||
"motionSensor": {
|
||||
"motion": {
|
||||
"value": "inactive",
|
||||
"timestamp": "2025-09-30T15:33:27.594Z"
|
||||
}
|
||||
},
|
||||
"illuminanceMeasurement": {
|
||||
"illuminance": {
|
||||
"value": 30,
|
||||
"unit": "lux",
|
||||
"timestamp": "2025-09-30T15:13:52.607Z"
|
||||
}
|
||||
},
|
||||
"battery": {
|
||||
"quantity": {
|
||||
"value": null
|
||||
},
|
||||
"battery": {
|
||||
"value": 100,
|
||||
"unit": "%",
|
||||
"timestamp": "2025-09-30T15:13:46.166Z"
|
||||
},
|
||||
"type": {
|
||||
"value": null
|
||||
}
|
||||
},
|
||||
"tamperAlert": {
|
||||
"tamper": {
|
||||
"value": "clear",
|
||||
"timestamp": "2025-09-30T14:06:07.064Z"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"components": {
|
||||
"main": {
|
||||
"momentary": {},
|
||||
"gasDetector": {
|
||||
"gas": {
|
||||
"value": "clear",
|
||||
"timestamp": "2025-10-02T03:18:27.139Z"
|
||||
}
|
||||
},
|
||||
"signalStrength": {
|
||||
"rssi": {
|
||||
"value": -71,
|
||||
"unit": "dBm",
|
||||
"timestamp": "2025-10-07T04:17:08.419Z"
|
||||
},
|
||||
"lqi": {
|
||||
"value": 148,
|
||||
"timestamp": "2025-10-07T04:32:08.512Z"
|
||||
}
|
||||
},
|
||||
"refresh": {}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"deviceId": "00f9233e-fdaa-4020-99d4-e0073e53996a",
|
||||
"name": "aeotec-ms6",
|
||||
"label": "Parent's Bedroom Sensor",
|
||||
"manufacturerName": "SmartThingsCommunity",
|
||||
"presentationId": "6d160aa8-7f54-3611-b7de-0b335d162529",
|
||||
"deviceManufacturerCode": "0086-0102-0064",
|
||||
"locationId": "3478ae40-8bd4-40b8-b7e6-f25e3cf86409",
|
||||
"ownerId": "fe7f9079-8e23-8307-fb7e-4d58929391cf",
|
||||
"roomId": "f1bb7871-3a3d-48da-b23f-0e1297e8acb0",
|
||||
"components": [
|
||||
{
|
||||
"id": "main",
|
||||
"label": "main",
|
||||
"capabilities": [
|
||||
{
|
||||
"id": "motionSensor",
|
||||
"version": 1
|
||||
},
|
||||
{
|
||||
"id": "temperatureMeasurement",
|
||||
"version": 1
|
||||
},
|
||||
{
|
||||
"id": "relativeHumidityMeasurement",
|
||||
"version": 1
|
||||
},
|
||||
{
|
||||
"id": "illuminanceMeasurement",
|
||||
"version": 1
|
||||
},
|
||||
{
|
||||
"id": "ultravioletIndex",
|
||||
"version": 1
|
||||
},
|
||||
{
|
||||
"id": "tamperAlert",
|
||||
"version": 1
|
||||
},
|
||||
{
|
||||
"id": "battery",
|
||||
"version": 1
|
||||
},
|
||||
{
|
||||
"id": "refresh",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"categories": [
|
||||
{
|
||||
"name": "MotionSensor",
|
||||
"categoryType": "manufacturer"
|
||||
}
|
||||
],
|
||||
"optional": false
|
||||
}
|
||||
],
|
||||
"createTime": "2025-04-17T05:47:05.803Z",
|
||||
"parentDeviceId": "9fdfde11-206e-47af-9e47-9c314d8d965f",
|
||||
"profile": {
|
||||
"id": "9893d370-2af6-32a0-86c5-f1a6d2b9fea7"
|
||||
},
|
||||
"zwave": {
|
||||
"networkId": "BE",
|
||||
"driverId": "42930682-019d-4dbe-8098-760d7afb3c7f",
|
||||
"executingLocally": true,
|
||||
"hubId": "9fdfde11-206e-47af-9e47-9c314d8d965f",
|
||||
"networkSecurityLevel": "ZWAVE_LEGACY_NON_SECURE",
|
||||
"provisioningState": "PROVISIONED",
|
||||
"manufacturerId": 134,
|
||||
"productType": 258,
|
||||
"productId": 100,
|
||||
"fingerprintType": "ZWAVE_MANUFACTURER",
|
||||
"fingerprintId": "Aeotec/MS6/US"
|
||||
},
|
||||
"type": "ZWAVE",
|
||||
"restrictionTier": 0,
|
||||
"allowed": null,
|
||||
"executionContext": "LOCAL",
|
||||
"relationships": []
|
||||
}
|
||||
],
|
||||
"_links": {}
|
||||
}
|
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"deviceId": "d830b46f-f094-4560-b8c3-7690032fdb4c",
|
||||
"name": "generic-ef00-v1",
|
||||
"label": "Gas Detector",
|
||||
"manufacturerName": "SmartThingsCommunity",
|
||||
"presentationId": "d4b88195-fd5b-39d3-ac6f-7070655f08ab",
|
||||
"deviceManufacturerCode": "_TZE284_chbyv06x",
|
||||
"locationId": "7139bb09-31e3-4fad-bf03-b9ad02e57b41",
|
||||
"ownerId": "00126705-d35b-27ee-d18b-17620d9929e7",
|
||||
"roomId": "5adccb3a-8ae7-41c0-bc58-7ba80ff78a18",
|
||||
"components": [
|
||||
{
|
||||
"id": "main",
|
||||
"label": "Detector",
|
||||
"capabilities": [
|
||||
{
|
||||
"id": "gasDetector",
|
||||
"version": 1
|
||||
},
|
||||
{
|
||||
"id": "momentary",
|
||||
"version": 1
|
||||
},
|
||||
{
|
||||
"id": "signalStrength",
|
||||
"version": 1
|
||||
},
|
||||
{
|
||||
"id": "refresh",
|
||||
"version": 1
|
||||
}
|
||||
],
|
||||
"categories": [
|
||||
{
|
||||
"name": "Siren",
|
||||
"categoryType": "manufacturer"
|
||||
}
|
||||
],
|
||||
"optional": false
|
||||
}
|
||||
],
|
||||
"createTime": "2025-05-25T04:55:42.440Z",
|
||||
"profile": {
|
||||
"id": "1d34dd9d-6840-3df6-a6d0-5d9f4a4af2e1"
|
||||
},
|
||||
"zigbee": {
|
||||
"eui": "A4C138C524A5BC8D",
|
||||
"networkId": "1575",
|
||||
"driverId": "bc7fd1bc-eb00-4b7f-8977-172acf823508",
|
||||
"executingLocally": true,
|
||||
"hubId": "0afe704f-eabb-4e4d-8333-6c73903e4f84",
|
||||
"provisioningState": "DRIVER_SWITCH",
|
||||
"fingerprintType": "ZIGBEE_GENERIC",
|
||||
"fingerprintId": "GenericEF00"
|
||||
},
|
||||
"type": "ZIGBEE",
|
||||
"restrictionTier": 0,
|
||||
"allowed": null,
|
||||
"executionContext": "LOCAL",
|
||||
"relationships": []
|
||||
}
|
||||
],
|
||||
"_links": {}
|
||||
}
|
@@ -1,4 +1,102 @@
|
||||
# serializer version: 1
|
||||
# name: test_all_entities[aeotec_ms6][binary_sensor.parent_s_bedroom_sensor_motion-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'binary_sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'binary_sensor.parent_s_bedroom_sensor_motion',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <BinarySensorDeviceClass.MOTION: 'motion'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Motion',
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '00f9233e-fdaa-4020-99d4-e0073e53996a_main_motionSensor_motion_motion',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[aeotec_ms6][binary_sensor.parent_s_bedroom_sensor_motion-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'motion',
|
||||
'friendly_name': "Parent's Bedroom Sensor Motion",
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.parent_s_bedroom_sensor_motion',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[aeotec_ms6][binary_sensor.parent_s_bedroom_sensor_tamper-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'binary_sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'binary_sensor.parent_s_bedroom_sensor_tamper',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <BinarySensorDeviceClass.TAMPER: 'tamper'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Tamper',
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '00f9233e-fdaa-4020-99d4-e0073e53996a_main_tamperAlert_tamper_tamper',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[aeotec_ms6][binary_sensor.parent_s_bedroom_sensor_tamper-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'tamper',
|
||||
'friendly_name': "Parent's Bedroom Sensor Tamper",
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.parent_s_bedroom_sensor_tamper',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[c2c_arlo_pro_3_switch][binary_sensor.2nd_floor_hallway_motion-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
@@ -2572,6 +2670,55 @@
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[gas_detector][binary_sensor.gas_detector_gas-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'binary_sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'binary_sensor.gas_detector_gas',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <BinarySensorDeviceClass.GAS: 'gas'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Gas',
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': 'd830b46f-f094-4560-b8c3-7690032fdb4c_main_gasDetector_gas_gas',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[gas_detector][binary_sensor.gas_detector_gas-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'gas',
|
||||
'friendly_name': 'Gas Detector Gas',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'binary_sensor.gas_detector_gas',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': 'off',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[iphone][binary_sensor.iphone_presence-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
|
@@ -64,6 +64,37 @@
|
||||
'via_device_id': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_devices[aeotec_ms6]
|
||||
DeviceRegistryEntrySnapshot({
|
||||
'area_id': None,
|
||||
'config_entries': <ANY>,
|
||||
'config_entries_subentries': <ANY>,
|
||||
'configuration_url': 'https://account.smartthings.com',
|
||||
'connections': set({
|
||||
}),
|
||||
'disabled_by': None,
|
||||
'entry_type': None,
|
||||
'hw_version': None,
|
||||
'id': <ANY>,
|
||||
'identifiers': set({
|
||||
tuple(
|
||||
'smartthings',
|
||||
'00f9233e-fdaa-4020-99d4-e0073e53996a',
|
||||
),
|
||||
}),
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': None,
|
||||
'model': None,
|
||||
'model_id': None,
|
||||
'name': "Parent's Bedroom Sensor",
|
||||
'name_by_user': None,
|
||||
'primary_config_entry': <ANY>,
|
||||
'serial_number': None,
|
||||
'sw_version': None,
|
||||
'via_device_id': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_devices[aq_sensor_3_ikea]
|
||||
DeviceRegistryEntrySnapshot({
|
||||
'area_id': None,
|
||||
@@ -1304,6 +1335,37 @@
|
||||
'via_device_id': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_devices[gas_detector]
|
||||
DeviceRegistryEntrySnapshot({
|
||||
'area_id': None,
|
||||
'config_entries': <ANY>,
|
||||
'config_entries_subentries': <ANY>,
|
||||
'configuration_url': 'https://account.smartthings.com',
|
||||
'connections': set({
|
||||
}),
|
||||
'disabled_by': None,
|
||||
'entry_type': None,
|
||||
'hw_version': None,
|
||||
'id': <ANY>,
|
||||
'identifiers': set({
|
||||
tuple(
|
||||
'smartthings',
|
||||
'd830b46f-f094-4560-b8c3-7690032fdb4c',
|
||||
),
|
||||
}),
|
||||
'labels': set({
|
||||
}),
|
||||
'manufacturer': None,
|
||||
'model': None,
|
||||
'model_id': None,
|
||||
'name': 'Gas Detector',
|
||||
'name_by_user': None,
|
||||
'primary_config_entry': <ANY>,
|
||||
'serial_number': None,
|
||||
'sw_version': None,
|
||||
'via_device_id': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_devices[gas_meter]
|
||||
DeviceRegistryEntrySnapshot({
|
||||
'area_id': None,
|
||||
|
@@ -163,6 +163,269 @@
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[aeotec_ms6][sensor.parent_s_bedroom_sensor_battery-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': None,
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'sensor.parent_s_bedroom_sensor_battery',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.BATTERY: 'battery'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Battery',
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '00f9233e-fdaa-4020-99d4-e0073e53996a_main_battery_battery_battery',
|
||||
'unit_of_measurement': '%',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[aeotec_ms6][sensor.parent_s_bedroom_sensor_battery-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'battery',
|
||||
'friendly_name': "Parent's Bedroom Sensor Battery",
|
||||
'unit_of_measurement': '%',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.parent_s_bedroom_sensor_battery',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '100',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[aeotec_ms6][sensor.parent_s_bedroom_sensor_humidity-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.parent_s_bedroom_sensor_humidity',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.HUMIDITY: 'humidity'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Humidity',
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '00f9233e-fdaa-4020-99d4-e0073e53996a_main_relativeHumidityMeasurement_humidity_humidity',
|
||||
'unit_of_measurement': '%',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[aeotec_ms6][sensor.parent_s_bedroom_sensor_humidity-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'humidity',
|
||||
'friendly_name': "Parent's Bedroom Sensor Humidity",
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': '%',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.parent_s_bedroom_sensor_humidity',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '60.0',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[aeotec_ms6][sensor.parent_s_bedroom_sensor_illuminance-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.parent_s_bedroom_sensor_illuminance',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.ILLUMINANCE: 'illuminance'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Illuminance',
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '00f9233e-fdaa-4020-99d4-e0073e53996a_main_illuminanceMeasurement_illuminance_illuminance',
|
||||
'unit_of_measurement': 'lx',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[aeotec_ms6][sensor.parent_s_bedroom_sensor_illuminance-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'illuminance',
|
||||
'friendly_name': "Parent's Bedroom Sensor Illuminance",
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'lx',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.parent_s_bedroom_sensor_illuminance',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '30',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[aeotec_ms6][sensor.parent_s_bedroom_sensor_temperature-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.parent_s_bedroom_sensor_temperature',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
'sensor': dict({
|
||||
'suggested_display_precision': 1,
|
||||
}),
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.TEMPERATURE: 'temperature'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Temperature',
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': '00f9233e-fdaa-4020-99d4-e0073e53996a_main_temperatureMeasurement_temperature_temperature',
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[aeotec_ms6][sensor.parent_s_bedroom_sensor_temperature-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'temperature',
|
||||
'friendly_name': "Parent's Bedroom Sensor Temperature",
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': <UnitOfTemperature.CELSIUS: '°C'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.parent_s_bedroom_sensor_temperature',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '22.2',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[aeotec_ms6][sensor.parent_s_bedroom_sensor_uv_index-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': None,
|
||||
'entity_id': 'sensor.parent_s_bedroom_sensor_uv_index',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'UV index',
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'uv_index',
|
||||
'unique_id': '00f9233e-fdaa-4020-99d4-e0073e53996a_main_ultravioletIndex_ultravioletIndex_ultravioletIndex',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[aeotec_ms6][sensor.parent_s_bedroom_sensor_uv_index-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': "Parent's Bedroom Sensor UV index",
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.parent_s_bedroom_sensor_uv_index',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '0',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[aq_sensor_3_ikea][sensor.aq_sensor_3_ikea_humidity-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
@@ -12651,6 +12914,110 @@
|
||||
'state': 'unknown',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[gas_detector][sensor.gas_detector_link_quality-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'sensor.gas_detector_link_quality',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Link quality',
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'link_quality',
|
||||
'unique_id': 'd830b46f-f094-4560-b8c3-7690032fdb4c_main_signalStrength_lqi_lqi',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[gas_detector][sensor.gas_detector_link_quality-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Gas Detector Link quality',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.gas_detector_link_quality',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '148',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[gas_detector][sensor.gas_detector_signal_strength-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'sensor',
|
||||
'entity_category': <EntityCategory.DIAGNOSTIC: 'diagnostic'>,
|
||||
'entity_id': 'sensor.gas_detector_signal_strength',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <SensorDeviceClass.SIGNAL_STRENGTH: 'signal_strength'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Signal strength',
|
||||
'platform': 'smartthings',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': None,
|
||||
'unique_id': 'd830b46f-f094-4560-b8c3-7690032fdb4c_main_signalStrength_rssi_rssi',
|
||||
'unit_of_measurement': 'dBm',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[gas_detector][sensor.gas_detector_signal_strength-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'signal_strength',
|
||||
'friendly_name': 'Gas Detector Signal strength',
|
||||
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
|
||||
'unit_of_measurement': 'dBm',
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'sensor.gas_detector_signal_strength',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '-71',
|
||||
})
|
||||
# ---
|
||||
# name: test_all_entities[gas_meter][sensor.gas_meter_gas-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
|
@@ -1,11 +1,9 @@
|
||||
"""Test the flow classes."""
|
||||
|
||||
import asyncio
|
||||
from collections.abc import Callable
|
||||
import dataclasses
|
||||
import logging
|
||||
from typing import Any
|
||||
from unittest.mock import AsyncMock, Mock, patch
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import pytest
|
||||
import voluptuous as vol
|
||||
@@ -932,297 +930,6 @@ async def test_show_progress_fires_only_when_changed(
|
||||
) # change (description placeholder)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("task_side_effect", "flow_result"),
|
||||
[
|
||||
(None, data_entry_flow.FlowResultType.CREATE_ENTRY),
|
||||
(data_entry_flow.AbortFlow("fail"), data_entry_flow.FlowResultType.ABORT),
|
||||
],
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("description", "expected_description"),
|
||||
[
|
||||
(None, None),
|
||||
({"title": "World"}, {"title": "World"}),
|
||||
(lambda x: {"title": "World"}, {"title": "World"}),
|
||||
],
|
||||
)
|
||||
async def test_progress_step(
|
||||
hass: HomeAssistant,
|
||||
manager: MockFlowManager,
|
||||
description: Callable[[data_entry_flow.FlowHandler], dict[str, Any]]
|
||||
| dict[str, Any]
|
||||
| None,
|
||||
expected_description: dict[str, Any] | None,
|
||||
task_side_effect: Exception | None,
|
||||
flow_result: data_entry_flow.FlowResultType,
|
||||
) -> None:
|
||||
"""Test progress_step decorator."""
|
||||
manager.hass = hass
|
||||
events = []
|
||||
task_init_evt = asyncio.Event()
|
||||
event_received_evt = asyncio.Event()
|
||||
task_result = Mock()
|
||||
task_result.side_effect = task_side_effect
|
||||
|
||||
@callback
|
||||
def capture_events(event: Event) -> None:
|
||||
events.append(event)
|
||||
event_received_evt.set()
|
||||
|
||||
@manager.mock_reg_handler("test")
|
||||
class TestFlow(data_entry_flow.FlowHandler):
|
||||
VERSION = 5
|
||||
|
||||
@data_entry_flow.progress_step(description_placeholders=description)
|
||||
async def async_step_init(self, user_input=None):
|
||||
await task_init_evt.wait()
|
||||
task_result()
|
||||
|
||||
return await self.async_step_finish()
|
||||
|
||||
async def async_step_finish(self, user_input=None):
|
||||
return self.async_create_entry(data={})
|
||||
|
||||
hass.bus.async_listen(
|
||||
data_entry_flow.EVENT_DATA_ENTRY_FLOW_PROGRESSED,
|
||||
capture_events,
|
||||
)
|
||||
|
||||
result = await manager.async_init("test")
|
||||
assert result["type"] == data_entry_flow.FlowResultType.SHOW_PROGRESS
|
||||
assert result["progress_action"] == "init"
|
||||
description_placeholders = result["description_placeholders"]
|
||||
assert description_placeholders == expected_description
|
||||
assert len(manager.async_progress()) == 1
|
||||
assert len(manager.async_progress_by_handler("test")) == 1
|
||||
assert manager.async_get(result["flow_id"])["handler"] == "test"
|
||||
|
||||
# Set task one done and wait for event
|
||||
task_init_evt.set()
|
||||
await event_received_evt.wait()
|
||||
event_received_evt.clear()
|
||||
assert len(events) == 1
|
||||
assert events[0].data == {
|
||||
"handler": "test",
|
||||
"flow_id": result["flow_id"],
|
||||
"refresh": True,
|
||||
}
|
||||
|
||||
# Frontend refreshes the flow
|
||||
result = await manager.async_configure(result["flow_id"])
|
||||
assert result["type"] == flow_result
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
(
|
||||
"task_init_side_effect", # side effect for initial step task
|
||||
"task_next_side_effect", # side effect for next step task
|
||||
"flow_result_before_init", # result before init task is done
|
||||
"flow_result_after_init", # result after init task is done
|
||||
"flow_result_after_next", # result after next task is done
|
||||
"flow_init_events", # number of events fired after init task is done
|
||||
"flow_next_events", # number of events fired after next task is done
|
||||
"manager_call_after_init", # lambda to continue the flow after init task
|
||||
"manager_call_after_next", # lambda to continue the flow after next task
|
||||
"before_init_task_side_effect", # function called before init event
|
||||
"before_next_task_side_effect", # function called before next event
|
||||
),
|
||||
[
|
||||
( # both steps show progress and complete successfully
|
||||
None,
|
||||
None,
|
||||
data_entry_flow.FlowResultType.SHOW_PROGRESS,
|
||||
data_entry_flow.FlowResultType.SHOW_PROGRESS,
|
||||
data_entry_flow.FlowResultType.CREATE_ENTRY,
|
||||
1,
|
||||
2,
|
||||
lambda manager, result: manager.async_configure(result["flow_id"]),
|
||||
lambda manager, result: manager.async_configure(result["flow_id"]),
|
||||
lambda received_event, init_task_event, next_task_event: None,
|
||||
lambda received_event, init_task_event, next_task_event: None,
|
||||
),
|
||||
( # first step aborts
|
||||
data_entry_flow.AbortFlow("fail"),
|
||||
None,
|
||||
data_entry_flow.FlowResultType.SHOW_PROGRESS,
|
||||
data_entry_flow.FlowResultType.ABORT,
|
||||
data_entry_flow.FlowResultType.ABORT,
|
||||
1,
|
||||
1,
|
||||
lambda manager, result: manager.async_configure(result["flow_id"]),
|
||||
lambda manager, result: AsyncMock(return_value=result)(),
|
||||
lambda received_event, init_task_event, next_task_event: None,
|
||||
lambda received_event, init_task_event, next_task_event: None,
|
||||
),
|
||||
( # first step shows progress, second step aborts
|
||||
None,
|
||||
data_entry_flow.AbortFlow("fail"),
|
||||
data_entry_flow.FlowResultType.SHOW_PROGRESS,
|
||||
data_entry_flow.FlowResultType.SHOW_PROGRESS,
|
||||
data_entry_flow.FlowResultType.ABORT,
|
||||
1,
|
||||
2,
|
||||
lambda manager, result: manager.async_configure(result["flow_id"]),
|
||||
lambda manager, result: manager.async_configure(result["flow_id"]),
|
||||
lambda received_event, init_task_event, next_task_event: None,
|
||||
lambda received_event, init_task_event, next_task_event: None,
|
||||
),
|
||||
( # first step shows progress and second step task is already done
|
||||
None,
|
||||
None,
|
||||
data_entry_flow.FlowResultType.SHOW_PROGRESS,
|
||||
data_entry_flow.FlowResultType.CREATE_ENTRY,
|
||||
data_entry_flow.FlowResultType.CREATE_ENTRY,
|
||||
1,
|
||||
1,
|
||||
lambda manager, result: manager.async_configure(result["flow_id"]),
|
||||
lambda manager, result: AsyncMock(return_value=result)(),
|
||||
lambda received_event,
|
||||
init_task_event,
|
||||
next_task_event: next_task_event.set(),
|
||||
lambda received_event, init_task_event, next_task_event: None,
|
||||
),
|
||||
( # both step tasks are already done and flow completes immediately
|
||||
None,
|
||||
None,
|
||||
data_entry_flow.FlowResultType.SHOW_PROGRESS_DONE,
|
||||
data_entry_flow.FlowResultType.CREATE_ENTRY,
|
||||
data_entry_flow.FlowResultType.CREATE_ENTRY,
|
||||
0,
|
||||
0,
|
||||
lambda manager, result: manager.async_configure(result["flow_id"]),
|
||||
lambda manager, result: AsyncMock(return_value=result)(),
|
||||
lambda received_event,
|
||||
init_task_event,
|
||||
next_task_event: received_event.set()
|
||||
or init_task_event.set()
|
||||
or next_task_event.set(),
|
||||
lambda received_event,
|
||||
init_task_event,
|
||||
next_task_event: received_event.set(),
|
||||
),
|
||||
( # first step task is already done, second step shows progress and completes
|
||||
None,
|
||||
None,
|
||||
data_entry_flow.FlowResultType.SHOW_PROGRESS_DONE,
|
||||
data_entry_flow.FlowResultType.SHOW_PROGRESS,
|
||||
data_entry_flow.FlowResultType.CREATE_ENTRY,
|
||||
0,
|
||||
0,
|
||||
lambda manager, result: manager.async_configure(result["flow_id"]),
|
||||
lambda manager, result: manager.async_configure(result["flow_id"]),
|
||||
lambda received_event,
|
||||
init_task_event,
|
||||
next_task_event: received_event.set() or init_task_event.set(),
|
||||
lambda received_event,
|
||||
init_task_event,
|
||||
next_task_event: received_event.set(),
|
||||
),
|
||||
],
|
||||
)
|
||||
async def test_chaining_progress_steps(
|
||||
hass: HomeAssistant,
|
||||
manager: MockFlowManager,
|
||||
task_init_side_effect: Exception | None,
|
||||
task_next_side_effect: Exception | None,
|
||||
flow_result_before_init: data_entry_flow.FlowResultType,
|
||||
flow_result_after_init: data_entry_flow.FlowResultType,
|
||||
flow_result_after_next: data_entry_flow.FlowResultType,
|
||||
flow_init_events: int,
|
||||
flow_next_events: int,
|
||||
manager_call_after_init: Callable[
|
||||
[MockFlowManager, data_entry_flow.FlowResult], Any
|
||||
],
|
||||
manager_call_after_next: Callable[
|
||||
[MockFlowManager, data_entry_flow.FlowResult], Any
|
||||
],
|
||||
before_init_task_side_effect: Callable[
|
||||
[asyncio.Event, asyncio.Event, asyncio.Event], None
|
||||
],
|
||||
before_next_task_side_effect: Callable[
|
||||
[asyncio.Event, asyncio.Event, asyncio.Event], None
|
||||
],
|
||||
) -> None:
|
||||
"""Test chaining two steps with progress_step decorators."""
|
||||
manager.hass = hass
|
||||
events = []
|
||||
event_received_evt = asyncio.Event()
|
||||
task_init_evt = asyncio.Event()
|
||||
task_next_evt = asyncio.Event()
|
||||
task_init_result = Mock()
|
||||
task_init_result.side_effect = task_init_side_effect
|
||||
task_next_result = Mock()
|
||||
task_next_result.side_effect = task_next_side_effect
|
||||
|
||||
@callback
|
||||
def capture_events(event: Event) -> None:
|
||||
events.append(event)
|
||||
event_received_evt.set()
|
||||
|
||||
@manager.mock_reg_handler("test")
|
||||
class TestFlow(data_entry_flow.FlowHandler):
|
||||
VERSION = 5
|
||||
|
||||
def async_remove(self) -> None:
|
||||
# Disable event received event to allow test to finish if flow is aborted.
|
||||
event_received_evt.set()
|
||||
|
||||
@data_entry_flow.progress_step()
|
||||
async def async_step_init(self, user_input=None):
|
||||
await task_init_evt.wait()
|
||||
task_init_result()
|
||||
|
||||
return await self.async_step_next()
|
||||
|
||||
@data_entry_flow.progress_step()
|
||||
async def async_step_next(self, user_input=None):
|
||||
await task_next_evt.wait()
|
||||
task_next_result()
|
||||
|
||||
return await self.async_step_finish()
|
||||
|
||||
async def async_step_finish(self, user_input=None):
|
||||
return self.async_create_entry(data={})
|
||||
|
||||
hass.bus.async_listen(
|
||||
data_entry_flow.EVENT_DATA_ENTRY_FLOW_PROGRESSED,
|
||||
capture_events,
|
||||
)
|
||||
|
||||
# Run side effect before first event is awaited
|
||||
before_init_task_side_effect(event_received_evt, task_init_evt, task_next_evt)
|
||||
|
||||
result = await manager.async_init("test")
|
||||
assert result["type"] == flow_result_before_init
|
||||
assert len(manager.async_progress()) == 1
|
||||
assert len(manager.async_progress_by_handler("test")) == 1
|
||||
assert manager.async_get(result["flow_id"])["handler"] == "test"
|
||||
|
||||
# Set task init done and wait for event
|
||||
task_init_evt.set()
|
||||
await event_received_evt.wait()
|
||||
event_received_evt.clear()
|
||||
assert len(events) == flow_init_events
|
||||
|
||||
# Run side effect before second event is awaited
|
||||
before_next_task_side_effect(event_received_evt, task_init_evt, task_next_evt)
|
||||
|
||||
# Continue the flow if needed.
|
||||
result = await manager_call_after_init(manager, result)
|
||||
assert result["type"] == flow_result_after_init
|
||||
|
||||
# Set task next done and wait for event
|
||||
task_next_evt.set()
|
||||
await event_received_evt.wait()
|
||||
event_received_evt.clear()
|
||||
assert len(events) == flow_next_events
|
||||
|
||||
# Continue the flow if needed.
|
||||
result = await manager_call_after_next(manager, result)
|
||||
assert result["type"] == flow_result_after_next
|
||||
|
||||
|
||||
async def test_abort_flow_exception_step(manager: MockFlowManager) -> None:
|
||||
"""Test that the AbortFlow exception works in a step."""
|
||||
|
||||
|
Reference in New Issue
Block a user