예제 #1
0
def async_extract_referenced_entity_ids(
        hass: HomeAssistant,
        service_call: ServiceCall,
        expand_group: bool = True) -> SelectedEntities:
    """Extract referenced entity IDs from a service call."""
    selector = ServiceTargetSelector(service_call)
    selected = SelectedEntities()

    if not selector.has_any_selector:
        return selected

    entity_ids = selector.entity_ids
    if expand_group:
        entity_ids = hass.components.group.expand_entity_ids(entity_ids)

    selected.referenced.update(entity_ids)

    if not selector.device_ids and not selector.area_ids:
        return selected

    ent_reg = entity_registry.async_get(hass)
    dev_reg = device_registry.async_get(hass)
    area_reg = area_registry.async_get(hass)

    for device_id in selector.device_ids:
        if device_id not in dev_reg.devices:
            selected.missing_devices.add(device_id)

    for area_id in selector.area_ids:
        if area_id not in area_reg.areas:
            selected.missing_areas.add(area_id)

    # Find devices for this area
    selected.referenced_devices.update(selector.device_ids)
    for device_entry in dev_reg.devices.values():
        if device_entry.area_id in selector.area_ids:
            selected.referenced_devices.add(device_entry.id)

    if not selector.area_ids and not selected.referenced_devices:
        return selected

    for ent_entry in ent_reg.entities.values():
        # Do not add config or diagnostic entities referenced by areas or devices
        if ent_entry.entity_category in (
                ENTITY_CATEGORY_CONFIG,
                ENTITY_CATEGORY_DIAGNOSTIC,
        ):
            continue

        if (
                # when area matches the target area
                ent_entry.area_id in selector.area_ids
                # when device matches a referenced devices with no explicitly set area
                or (not ent_entry.area_id
                    and ent_entry.device_id in selected.referenced_devices)
                # when device matches target device
                or ent_entry.device_id in selector.device_ids):
            selected.indirectly_referenced.add(ent_entry.entity_id)

    return selected
예제 #2
0
def websocket_list_areas(hass, connection, msg):
    """Handle list areas command."""
    registry = async_get(hass)
    connection.send_result(
        msg["id"],
        [_entry_dict(entry) for entry in registry.async_list_areas()],
    )
예제 #3
0
async def test_ws_api(hass, hass_ws_client):
    """Test WS API."""
    assert await async_setup_component(hass, "search", {})

    area_reg = ar.async_get(hass)
    device_reg = dr.async_get(hass)

    kitchen_area = area_reg.async_create("Kitchen")

    hue_config_entry = MockConfigEntry(domain="hue")
    hue_config_entry.add_to_hass(hass)

    hue_device = device_reg.async_get_or_create(
        config_entry_id=hue_config_entry.entry_id,
        name="Light Strip",
        identifiers=({"hue", "hue-1"}),
    )

    device_reg.async_update_device(hue_device.id, area_id=kitchen_area.id)

    client = await hass_ws_client(hass)

    await client.send_json({
        "id": 1,
        "type": "search/related",
        "item_type": "device",
        "item_id": hue_device.id,
    })
    response = await client.receive_json()
    assert response["success"]
    assert response["result"] == {
        "config_entry": [hue_config_entry.entry_id],
        "area": [kitchen_area.id],
    }
예제 #4
0
def resolve_area_entities(
        hass: HomeAssistantType,
        area_id_or_name: str) -> dict[str, entity_registry.RegistryEntry]:
    """Get a listing of al entities in a given area"""
    area_reg = area_registry.async_get(hass)
    area = area_reg.async_get_area(area_id_or_name)
    if area is None:
        area = area_reg.async_get_area_by_name(str(area_id_or_name))

    if area is None:
        raise SensorConfigurationError(
            f"No area with id or name '{area_id_or_name}' found in your HA instance"
        )

    area_id = area.id
    entity_reg = entity_registry.async_get(hass)

    entities = entity_registry.async_entries_for_area(entity_reg, area_id)

    device_reg = device_registry.async_get(hass)
    # We also need to add entities tied to a device in the area that don't themselves
    # have an area specified since they inherit the area from the device.
    entities.extend([
        entity for device in device_registry.async_entries_for_area(
            device_reg, area_id)
        for entity in entity_registry.async_entries_for_device(
            entity_reg, device.id) if entity.area_id is None
    ])
    return {
        entity.entity_id: entity
        for entity in entities if entity.domain == LIGHT_DOMAIN
    }
예제 #5
0
async def test_onboarding_user(hass, hass_storage, hass_client_no_auth):
    """Test creating a new user."""
    assert await async_setup_component(hass, "person", {})
    assert await async_setup_component(hass, "onboarding", {})
    await hass.async_block_till_done()

    cur_users = len(await hass.auth.async_get_users())
    client = await hass_client_no_auth()

    resp = await client.post(
        "/api/onboarding/users",
        json={
            "client_id": CLIENT_ID,
            "name": "Test Name",
            "username": "******",
            "password": "******",
            "language": "en",
        },
    )

    assert resp.status == 200
    assert const.STEP_USER in hass_storage[const.DOMAIN]["data"]["done"]

    data = await resp.json()
    assert "auth_code" in data

    users = await hass.auth.async_get_users()
    assert len(await hass.auth.async_get_users()) == cur_users + 1
    user = next((user for user in users if user.name == "Test Name"), None)
    assert user is not None
    assert len(user.credentials) == 1
    assert user.credentials[0].data["username"] == "test-user"
    assert len(hass.data["person"][1].async_items()) == 1

    # Validate refresh token 1
    resp = await client.post(
        "/auth/token",
        data={
            "client_id": CLIENT_ID,
            "grant_type": "authorization_code",
            "code": data["auth_code"],
        },
    )

    assert resp.status == 200
    tokens = await resp.json()

    assert (await hass.auth.async_validate_access_token(tokens["access_token"])
            is not None)

    # Validate created areas
    area_registry = ar.async_get(hass)
    assert len(area_registry.areas) == 3
    assert sorted(area.name for area in area_registry.async_list_areas()) == [
        "Bedroom",
        "Kitchen",
        "Living Room",
    ]
예제 #6
0
def _get_registry_entries(
    hass: HomeAssistant, entity_id: str
) -> tuple[device_registry.DeviceEntry, area_registry.AreaEntry]:
    """Get registry entries."""
    ent_reg = entity_registry.async_get(hass)
    dev_reg = device_registry.async_get(hass)
    area_reg = area_registry.async_get(hass)

    if (entity_entry := ent_reg.async_get(entity_id)) and entity_entry.device_id:
        device_entry = dev_reg.devices.get(entity_entry.device_id)
예제 #7
0
def websocket_delete_area(hass, connection, msg):
    """Delete area command."""
    registry = async_get(hass)

    try:
        registry.async_delete(msg["area_id"])
    except KeyError:
        connection.send_error(msg["id"], "invalid_info",
                              "Area ID doesn't exist")
    else:
        connection.send_message(
            websocket_api.result_message(msg["id"], "success"))
예제 #8
0
def websocket_update_area(hass, connection, msg):
    """Handle update area websocket command."""
    registry = async_get(hass)

    data = dict(msg)
    data.pop("type")
    data.pop("id")

    try:
        entry = registry.async_update(**data)
    except ValueError as err:
        connection.send_error(msg["id"], "invalid_info", str(err))
    else:
        connection.send_result(msg["id"], _entry_dict(entry))
예제 #9
0
    async def post(self, request, data):
        """Handle user creation, area creation."""
        hass = request.app["hass"]

        async with self._lock:
            if self._async_is_done():
                return self.json_message("User step already done",
                                         HTTPStatus.FORBIDDEN)

            provider = _async_get_hass_provider(hass)
            await provider.async_initialize()

            user = await hass.auth.async_create_user(
                data["name"], group_ids=[GROUP_ID_ADMIN])
            await hass.async_add_executor_job(provider.data.add_auth,
                                              data["username"],
                                              data["password"])
            credentials = await provider.async_get_or_create_credentials(
                {"username": data["username"]})
            await provider.data.async_save()
            await hass.auth.async_link_user(user, credentials)
            if "person" in hass.config.components:
                await person.async_create_person(hass,
                                                 data["name"],
                                                 user_id=user.id)

            # Create default areas using the users supplied language.
            translations = await async_get_translations(
                hass, data["language"], "area", {DOMAIN})

            area_registry = ar.async_get(hass)

            for area in DEFAULT_AREAS:
                name = translations[f"component.onboarding.area.{area}"]
                # Guard because area might have been created by an automatically
                # set up integration.
                if not area_registry.async_get_area_by_name(name):
                    area_registry.async_create(name)

            await self._async_mark_done(hass)

            # Return authorization code for fetching tokens and connect
            # during onboarding.
            # pylint: disable=import-outside-toplevel
            from homeassistant.components.auth import create_auth_code

            auth_code = create_auth_code(hass, data["client_id"], credentials)
            return self.json({"auth_code": auth_code})
예제 #10
0
async def async_extract_referenced_entity_ids(
        hass: HomeAssistantType,
        service_call: ha.ServiceCall,
        expand_group: bool = True) -> SelectedEntities:
    """Extract referenced entity IDs from a service call."""
    selector = ServiceTargetSelector(service_call)
    selected = SelectedEntities()

    if not selector.has_any_selector:
        return selected

    entity_ids = selector.entity_ids
    if expand_group:
        entity_ids = hass.components.group.expand_entity_ids(entity_ids)

    selected.referenced.update(entity_ids)

    if not selector.device_ids and not selector.area_ids:
        return selected

    ent_reg = entity_registry.async_get(hass)
    dev_reg = device_registry.async_get(hass)
    area_reg = area_registry.async_get(hass)

    for device_id in selector.device_ids:
        if device_id not in dev_reg.devices:
            selected.missing_devices.add(device_id)

    for area_id in selector.area_ids:
        if area_id not in area_reg.areas:
            selected.missing_areas.add(area_id)

    # Find devices for this area
    selected.referenced_devices.update(selector.device_ids)
    for device_entry in dev_reg.devices.values():
        if device_entry.area_id in selector.area_ids:
            selected.referenced_devices.add(device_entry.id)

    if not selector.area_ids and not selected.referenced_devices:
        return selected

    for ent_entry in ent_reg.entities.values():
        if ent_entry.area_id in selector.area_ids or (
                not ent_entry.area_id
                and ent_entry.device_id in selected.referenced_devices):
            selected.indirectly_referenced.add(ent_entry.entity_id)

    return selected
async def test_loading_area_from_storage(hass, hass_storage):
    """Test loading stored areas on start."""
    hass_storage[area_registry.STORAGE_KEY] = {
        "version": area_registry.STORAGE_VERSION,
        "data": {
            "areas": [{
                "id": "12345A",
                "name": "mock"
            }]
        },
    }

    await area_registry.async_load(hass)
    registry = area_registry.async_get(hass)

    assert len(registry.areas) == 1
예제 #12
0
    async def sync_areas_with_loxone(data={}):
        create_areas = data.get(ATTR_AREA_CREATE, DEFAULT)
        if create_areas not in [True, False]:
            create_areas = False
        lox_items = []
        er_registry = er.async_get(hass)
        ar_registry = ar.async_get(hass)
        for id, entry in er_registry.entities.items():
            if entry.platform == DOMAIN:
                state = hass.states.get(entry.entity_id)
                if hasattr(state, "attributes") and "room" in state.attributes:
                    area = ar_registry.async_get_area_by_name(
                        state.attributes["room"])
                    if area is None and create_areas:
                        area = ar_registry.async_get_or_create(
                            state.attributes["room"])
                    if area and entry.area_id is None:
                        lox_items.append((entry.entity_id, area.id))

        for _ in lox_items:
            er_registry.async_update_entity(_[0], area_id=_[1])
예제 #13
0
async def test_existing_node_not_replaced_when_not_ready(
        hass, zp3111, zp3111_not_ready_state, zp3111_state, client,
        integration):
    """Test when a node added event with a non-ready node is received.

    The existing node should not be replaced, and no customization should be lost.
    """
    dev_reg = dr.async_get(hass)
    er_reg = er.async_get(hass)
    kitchen_area = ar.async_get(hass).async_create("Kitchen")

    device_id = f"{client.driver.controller.home_id}-{zp3111.node_id}"
    device_id_ext = (f"{device_id}-{zp3111.manufacturer_id}:"
                     f"{zp3111.product_type}:{zp3111.product_id}")

    device = dev_reg.async_get_device(identifiers={(DOMAIN, device_id)})
    assert device
    assert device.name == "4-in-1 Sensor"
    assert not device.name_by_user
    assert device.manufacturer == "Vision Security"
    assert device.model == "ZP3111-5"
    assert device.sw_version == "5.1"
    assert not device.area_id
    assert device == dev_reg.async_get_device(identifiers={(DOMAIN,
                                                            device_id_ext)})

    motion_entity = "binary_sensor.4_in_1_sensor_home_security_motion_detection"
    state = hass.states.get(motion_entity)
    assert state
    assert state.name == "4-in-1 Sensor: Home Security - Motion detection"

    dev_reg.async_update_device(device.id,
                                name_by_user="******",
                                area_id=kitchen_area.id)

    custom_device = dev_reg.async_get_device(identifiers={(DOMAIN, device_id)})
    assert custom_device
    assert custom_device.name == "4-in-1 Sensor"
    assert custom_device.name_by_user == "Custom Device Name"
    assert custom_device.manufacturer == "Vision Security"
    assert custom_device.model == "ZP3111-5"
    assert device.sw_version == "5.1"
    assert custom_device.area_id == kitchen_area.id
    assert custom_device == dev_reg.async_get_device(
        identifiers={(DOMAIN, device_id_ext)})

    custom_entity = "binary_sensor.custom_motion_sensor"
    er_reg.async_update_entity(motion_entity,
                               new_entity_id=custom_entity,
                               name="Custom Entity Name")
    await hass.async_block_till_done()
    state = hass.states.get(custom_entity)
    assert state
    assert state.name == "Custom Entity Name"
    assert not hass.states.get(motion_entity)

    node_state = deepcopy(zp3111_not_ready_state)
    node_state["isSecure"] = False

    event = Event(
        type="node added",
        data={
            "source": "controller",
            "event": "node added",
            "node": node_state,
            "result": {},
        },
    )
    client.driver.receive_event(event)
    await hass.async_block_till_done()

    device = dev_reg.async_get_device(identifiers={(DOMAIN, device_id)})
    assert device
    assert device == dev_reg.async_get_device(identifiers={(DOMAIN,
                                                            device_id_ext)})
    assert device.id == custom_device.id
    assert device.identifiers == custom_device.identifiers
    assert device.name == f"Node {zp3111.node_id}"
    assert device.name_by_user == "Custom Device Name"
    assert not device.manufacturer
    assert not device.model
    assert not device.sw_version
    assert device.area_id == kitchen_area.id

    state = hass.states.get(custom_entity)
    assert state
    assert state.name == "Custom Entity Name"

    event = Event(
        type="ready",
        data={
            "source": "node",
            "event": "ready",
            "nodeId": zp3111_state["nodeId"],
            "nodeState": deepcopy(zp3111_state),
        },
    )
    client.driver.receive_event(event)
    await hass.async_block_till_done()

    device = dev_reg.async_get_device(identifiers={(DOMAIN, device_id)})
    assert device
    assert device == dev_reg.async_get_device(identifiers={(DOMAIN,
                                                            device_id_ext)})
    assert device.id == custom_device.id
    assert device.identifiers == custom_device.identifiers
    assert device.name == "4-in-1 Sensor"
    assert device.name_by_user == "Custom Device Name"
    assert device.manufacturer == "Vision Security"
    assert device.model == "ZP3111-5"
    assert device.area_id == kitchen_area.id
    assert device.sw_version == "5.1"

    state = hass.states.get(custom_entity)
    assert state
    assert state.state != STATE_UNAVAILABLE
    assert state.name == "Custom Entity Name"
예제 #14
0
async def test_search(hass):
    """Test that search works."""
    area_reg = ar.async_get(hass)
    device_reg = dr.async_get(hass)
    entity_reg = er.async_get(hass)

    living_room_area = area_reg.async_create("Living Room")

    # Light strip with 2 lights.
    wled_config_entry = MockConfigEntry(domain="wled")
    wled_config_entry.add_to_hass(hass)

    wled_device = device_reg.async_get_or_create(
        config_entry_id=wled_config_entry.entry_id,
        name="Light Strip",
        identifiers=({"wled", "wled-1"}),
    )

    device_reg.async_update_device(wled_device.id, area_id=living_room_area.id)

    wled_segment_1_entity = entity_reg.async_get_or_create(
        "light",
        "wled",
        "wled-1-seg-1",
        suggested_object_id="wled segment 1",
        config_entry=wled_config_entry,
        device_id=wled_device.id,
    )
    wled_segment_2_entity = entity_reg.async_get_or_create(
        "light",
        "wled",
        "wled-1-seg-2",
        suggested_object_id="wled segment 2",
        config_entry=wled_config_entry,
        device_id=wled_device.id,
    )

    # Non related info.
    kitchen_area = area_reg.async_create("Kitchen")

    hue_config_entry = MockConfigEntry(domain="hue")
    hue_config_entry.add_to_hass(hass)

    hue_device = device_reg.async_get_or_create(
        config_entry_id=hue_config_entry.entry_id,
        name="Light Strip",
        identifiers=({"hue", "hue-1"}),
    )

    device_reg.async_update_device(hue_device.id, area_id=kitchen_area.id)

    hue_segment_1_entity = entity_reg.async_get_or_create(
        "light",
        "hue",
        "hue-1-seg-1",
        suggested_object_id="hue segment 1",
        config_entry=hue_config_entry,
        device_id=hue_device.id,
    )
    hue_segment_2_entity = entity_reg.async_get_or_create(
        "light",
        "hue",
        "hue-1-seg-2",
        suggested_object_id="hue segment 2",
        config_entry=hue_config_entry,
        device_id=hue_device.id,
    )

    await async_setup_component(
        hass,
        "group",
        {
            "group": {
                "wled": {
                    "name":
                    "wled",
                    "entities": [
                        wled_segment_1_entity.entity_id,
                        wled_segment_2_entity.entity_id,
                    ],
                },
                "hue": {
                    "name":
                    "hue",
                    "entities": [
                        hue_segment_1_entity.entity_id,
                        hue_segment_2_entity.entity_id,
                    ],
                },
                "wled_hue": {
                    "name":
                    "wled and hue",
                    "entities": [
                        wled_segment_1_entity.entity_id,
                        wled_segment_2_entity.entity_id,
                        hue_segment_1_entity.entity_id,
                        hue_segment_2_entity.entity_id,
                    ],
                },
            }
        },
    )

    await async_setup_component(
        hass,
        "scene",
        {
            "scene": [
                {
                    "name": "scene_wled_seg_1",
                    "entities": {
                        wled_segment_1_entity.entity_id: "on"
                    },
                },
                {
                    "name": "scene_hue_seg_1",
                    "entities": {
                        hue_segment_1_entity.entity_id: "on"
                    },
                },
                {
                    "name": "scene_wled_hue",
                    "entities": {
                        wled_segment_1_entity.entity_id: "on",
                        wled_segment_2_entity.entity_id: "on",
                        hue_segment_1_entity.entity_id: "on",
                        hue_segment_2_entity.entity_id: "on",
                    },
                },
            ]
        },
    )

    await async_setup_component(
        hass,
        "script",
        {
            "script": {
                "wled": {
                    "sequence": [
                        {
                            "service": "test.script",
                            "data": {
                                "entity_id": wled_segment_1_entity.entity_id
                            },
                        },
                    ]
                },
                "hue": {
                    "sequence": [
                        {
                            "service": "test.script",
                            "data": {
                                "entity_id": hue_segment_1_entity.entity_id
                            },
                        },
                    ]
                },
            }
        },
    )

    assert await async_setup_component(
        hass,
        "automation",
        {
            "automation": [
                {
                    "alias":
                    "wled_entity",
                    "trigger": {
                        "platform": "template",
                        "value_template": "true"
                    },
                    "action": [
                        {
                            "service": "test.script",
                            "data": {
                                "entity_id": wled_segment_1_entity.entity_id
                            },
                        },
                    ],
                },
                {
                    "alias":
                    "wled_device",
                    "trigger": {
                        "platform": "template",
                        "value_template": "true"
                    },
                    "action": [
                        {
                            "domain": "light",
                            "device_id": wled_device.id,
                            "entity_id": wled_segment_1_entity.entity_id,
                            "type": "turn_on",
                        },
                    ],
                },
            ]
        },
    )

    # Explore the graph from every node and make sure we find the same results
    expected = {
        "config_entry": {wled_config_entry.entry_id},
        "area": {living_room_area.id},
        "device": {wled_device.id},
        "entity":
        {wled_segment_1_entity.entity_id, wled_segment_2_entity.entity_id},
        "scene": {"scene.scene_wled_seg_1", "scene.scene_wled_hue"},
        "group": {"group.wled", "group.wled_hue"},
        "script": {"script.wled"},
        "automation": {"automation.wled_entity", "automation.wled_device"},
    }

    for search_type, search_id in (
        ("config_entry", wled_config_entry.entry_id),
        ("area", living_room_area.id),
        ("device", wled_device.id),
        ("entity", wled_segment_1_entity.entity_id),
        ("entity", wled_segment_2_entity.entity_id),
        ("scene", "scene.scene_wled_seg_1"),
        ("group", "group.wled"),
        ("script", "script.wled"),
        ("automation", "automation.wled_entity"),
        ("automation", "automation.wled_device"),
    ):
        searcher = search.Searcher(hass, device_reg, entity_reg)
        results = searcher.async_search(search_type, search_id)
        # Add the item we searched for, it's omitted from results
        results.setdefault(search_type, set()).add(search_id)

        assert (results == expected
                ), f"Results for {search_type}/{search_id} do not match up"

    # For combined things, needs to return everything.
    expected_combined = {
        "config_entry":
        {wled_config_entry.entry_id, hue_config_entry.entry_id},
        "area": {living_room_area.id, kitchen_area.id},
        "device": {wled_device.id, hue_device.id},
        "entity": {
            wled_segment_1_entity.entity_id,
            wled_segment_2_entity.entity_id,
            hue_segment_1_entity.entity_id,
            hue_segment_2_entity.entity_id,
        },
        "scene": {
            "scene.scene_wled_seg_1",
            "scene.scene_hue_seg_1",
            "scene.scene_wled_hue",
        },
        "group": {"group.wled", "group.hue", "group.wled_hue"},
        "script": {"script.wled", "script.hue"},
        "automation": {"automation.wled_entity", "automation.wled_device"},
    }
    for search_type, search_id in (
        ("scene", "scene.scene_wled_hue"),
        ("group", "group.wled_hue"),
    ):
        searcher = search.Searcher(hass, device_reg, entity_reg)
        results = searcher.async_search(search_type, search_id)
        # Add the item we searched for, it's omitted from results
        results.setdefault(search_type, set()).add(search_id)
        assert (results == expected_combined
                ), f"Results for {search_type}/{search_id} do not match up"

    for search_type, search_id in (
        ("entity", "automation.non_existing"),
        ("entity", "scene.non_existing"),
        ("entity", "group.non_existing"),
        ("entity", "script.non_existing"),
        ("entity", "light.non_existing"),
        ("area", "non_existing"),
        ("config_entry", "non_existing"),
        ("device", "non_existing"),
        ("group", "group.non_existing"),
        ("scene", "scene.non_existing"),
        ("script", "script.non_existing"),
        ("automation", "automation.non_existing"),
    ):
        searcher = search.Searcher(hass, device_reg, entity_reg)
        assert searcher.async_search(search_type, search_id) == {}
예제 #15
0
async def test_area_lookup(hass):
    """Test area based lookup."""
    area_reg = ar.async_get(hass)
    device_reg = dr.async_get(hass)
    entity_reg = er.async_get(hass)

    living_room_area = area_reg.async_create("Living Room")

    await async_setup_component(
        hass,
        "script",
        {
            "script": {
                "wled": {
                    "sequence": [
                        {
                            "service": "light.turn_on",
                            "target": {
                                "area_id": living_room_area.id
                            },
                        },
                    ]
                },
            }
        },
    )

    assert await async_setup_component(
        hass,
        "automation",
        {
            "automation": [
                {
                    "alias":
                    "area_turn_on",
                    "trigger": {
                        "platform": "template",
                        "value_template": "true"
                    },
                    "action": [
                        {
                            "service": "light.turn_on",
                            "data": {
                                "area_id": living_room_area.id,
                            },
                        },
                    ],
                },
            ]
        },
    )

    searcher = search.Searcher(hass, device_reg, entity_reg)
    assert searcher.async_search("area", living_room_area.id) == {
        "script": {"script.wled"},
        "automation": {"automation.area_turn_on"},
    }

    searcher = search.Searcher(hass, device_reg, entity_reg)
    assert searcher.async_search("automation", "automation.area_turn_on") == {
        "area": {living_room_area.id},
    }