async def test_loading_race_condition(hass):
    """Test only one storage load called when concurrent loading occurred ."""
    with asynctest.patch(
            "homeassistant.helpers.device_registry.DeviceRegistry.async_load"
    ) as mock_load:
        results = await asyncio.gather(
            device_registry.async_get_registry(hass),
            device_registry.async_get_registry(hass),
        )

        mock_load.assert_called_once_with()
        assert results[0] == results[1]
async def test_loading_race_condition(hass):
    """Test only one storage load called when concurrent loading occurred ."""
    with asynctest.patch(
        'homeassistant.helpers.device_registry.DeviceRegistry.async_load',
    ) as mock_load:
        results = await asyncio.gather(
            device_registry.async_get_registry(hass),
            device_registry.async_get_registry(hass),
        )

        mock_load.assert_called_once_with()
        assert results[0] == results[1]
예제 #3
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."""
    entity_ids = service_call.data.get(ATTR_ENTITY_ID)
    device_ids = service_call.data.get(ATTR_DEVICE_ID)
    area_ids = service_call.data.get(ATTR_AREA_ID)

    selects_entity_ids = entity_ids not in (None, ENTITY_MATCH_NONE)
    selects_device_ids = device_ids not in (None, ENTITY_MATCH_NONE)
    selects_area_ids = area_ids not in (None, ENTITY_MATCH_NONE)

    selected = SelectedEntities()

    if not selects_entity_ids and not selects_device_ids and not selects_area_ids:
        return selected

    if selects_entity_ids:
        assert entity_ids is not None

        # Entity ID attr can be a list or a string
        if isinstance(entity_ids, str):
            entity_ids = [entity_ids]

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

        selected.referenced.update(entity_ids)

    if not selects_device_ids and not selects_area_ids:
        return selected

    area_reg, dev_reg, ent_reg = cast(
        Tuple[area_registry.AreaRegistry, device_registry.DeviceRegistry,
              entity_registry.EntityRegistry, ],
        await asyncio.gather(
            area_registry.async_get_registry(hass),
            device_registry.async_get_registry(hass),
            entity_registry.async_get_registry(hass),
        ),
    )

    picked_devices = set()

    if selects_device_ids:
        if isinstance(device_ids, str):
            picked_devices = {device_ids}
        else:
            assert isinstance(device_ids, list)
            picked_devices = set(device_ids)

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

    if selects_area_ids:
        assert area_ids is not None

        if isinstance(area_ids, str):
            area_lookup = {area_ids}
        else:
            area_lookup = set(area_ids)

        for area_id in area_lookup:
            if area_id not in area_reg.areas:
                selected.missing_areas.add(area_id)
                continue

        # Find entities tied to an area
        for entity_entry in ent_reg.entities.values():
            if entity_entry.area_id in area_lookup:
                selected.indirectly_referenced.add(entity_entry.entity_id)

        # Find devices for this area
        for device_entry in dev_reg.devices.values():
            if device_entry.area_id in area_lookup:
                picked_devices.add(device_entry.id)

    if not picked_devices:
        return selected

    for entity_entry in ent_reg.entities.values():
        if not entity_entry.area_id and entity_entry.device_id in picked_devices:
            selected.indirectly_referenced.add(entity_entry.entity_id)

    return selected
예제 #4
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
    """Set up Meross IoT local LAN from a config entry."""
    LOGGER.debug("async_setup_entry entry_id = %s", entry.entry_id)
    api = hass.data.get(DOMAIN)
    if api == None:
        try:
            api = MerossApi(hass)
            hass.data[DOMAIN] = api
            await api.async_mqtt_register()
        except:
            return False

    device_id = entry.data.get(CONF_DEVICE_ID)
    if device_id == None:
        # this is the MQTT Hub entry
        api.key = entry.data.get(
            CONF_KEY
        )  # could be 'None' : if so defaults to "" but allows key reply trick
        api.unsub_entry_update_listener = entry.add_update_listener(
            api.entry_update_listener)
    else:
        #device related entry
        LOGGER.debug("async_setup_entry device_id = %s", device_id)
        device = MerossDevice(api, device_id, entry)
        api.devices[device_id] = device

        p_system = entry.data.get(CONF_DISCOVERY_PAYLOAD,
                                  {}).get("all", {}).get("system", {})
        p_hardware = p_system.get("hardware", {})
        p_firmware = p_system.get("firmware", {})
        p_hardware_type = p_hardware.get("type", MANUFACTURER)

        try:
            #use newer api
            device_registry.async_get(hass).async_get_or_create(
                config_entry_id=entry.entry_id,
                connections={(device_registry.CONNECTION_NETWORK_MAC,
                              p_hardware.get("macAddress"))},
                identifiers={(DOMAIN, device_id)},
                manufacturer=MANUFACTURER,
                name=p_hardware_type + " " + device_id,
                model=p_hardware_type + " " + p_hardware.get("version", ""),
                sw_version=p_firmware.get("version"),
            )
        except:
            #fallback: as of 27-03-2021 this is still working
            device_registry.async_get_registry(hass).async_get_or_create(
                config_entry_id=entry.entry_id,
                connections={(device_registry.CONNECTION_NETWORK_MAC,
                              p_hardware.get("macAddress"))},
                identifiers={(DOMAIN, device_id)},
                manufacturer=MANUFACTURER,
                name=p_hardware_type + " " + device_id,
                model=p_hardware_type + " " + p_hardware.get("version", ""),
                sw_version=p_firmware.get("version"),
            )

        if device.has_switches:
            hass.async_create_task(
                hass.config_entries.async_forward_entry_setup(entry, "switch"))
        if device.has_lights:
            hass.async_create_task(
                hass.config_entries.async_forward_entry_setup(entry, "light"))
        if device.has_sensors:
            hass.async_create_task(
                hass.config_entries.async_forward_entry_setup(entry, "sensor"))

        device.unsub_entry_update_listener = entry.add_update_listener(
            device_entry_update_listener)
        device.unsub_updatecoordinator_listener = api.coordinator.async_add_listener(
            device.updatecoordinator_listener)

    return True