Exemple #1
0
async def test_removed_device(opp, client, multiple_devices, integration):
    """Test that the device registry gets updated when a device gets removed."""
    nodes = multiple_devices

    # Verify how many nodes are available
    assert len(client.driver.controller.nodes) == 2

    # Make sure there are the same number of devices
    dev_reg = dr.async_get(opp)
    device_entries = dr.async_entries_for_config_entry(dev_reg,
                                                       integration.entry_id)
    assert len(device_entries) == 2

    # Check how many entities there are
    ent_reg = er.async_get(opp)
    entity_entries = er.async_entries_for_config_entry(ent_reg,
                                                       integration.entry_id)
    assert len(entity_entries) == 24

    # Remove a node and reload the entry
    old_node = nodes.pop(13)
    await opp.config_entries.async_reload(integration.entry_id)
    await opp.async_block_till_done()

    # Assert that the node and all of it's entities were removed from the device and
    # entity registry
    device_entries = dr.async_entries_for_config_entry(dev_reg,
                                                       integration.entry_id)
    assert len(device_entries) == 1
    entity_entries = er.async_entries_for_config_entry(ent_reg,
                                                       integration.entry_id)
    assert len(entity_entries) == 15
    assert dev_reg.async_get_device({get_device_id(client, old_node)}) is None
Exemple #2
0
async def async_unload_entry(opp, entry):
    """Unload a config entry."""

    # cleanup platforms
    unload_ok = await opp.config_entries.async_unload_platforms(entry, PLATFORMS)
    if not unload_ok:
        return False

    # disable discovery
    await discovery.async_stop(opp)

    # cleanup subscriptions
    for unsub in opp.data[DATA_UNSUB]:
        unsub()
    opp.data.pop(DATA_REMOVE_DISCOVER_COMPONENT.format("device_automation"))()
    for platform in PLATFORMS:
        opp.data.pop(DATA_REMOVE_DISCOVER_COMPONENT.format(platform))()

    # deattach device triggers
    device_registry = await opp.helpers.device_registry.async_get_registry()
    devices = async_entries_for_config_entry(device_registry, entry.entry_id)
    for device in devices:
        await device_automation.async_remove_automations(opp, device.id)

    return True
Exemple #3
0
async def test_deconz_events_bad_unique_id(opp, aioclient_mock,
                                           mock_deconz_websocket):
    """Verify no devices are created if unique id is bad or missing."""
    data = {
        "sensors": {
            "1": {
                "name": "Switch 1 no unique id",
                "type": "ZHASwitch",
                "state": {
                    "buttonevent": 1000
                },
                "config": {},
            },
            "2": {
                "name": "Switch 2 bad unique id",
                "type": "ZHASwitch",
                "state": {
                    "buttonevent": 1000
                },
                "config": {
                    "battery": 100
                },
                "uniqueid": "00:00-00",
            },
        }
    }
    with patch.dict(DECONZ_WEB_REQUEST, data):
        config_entry = await setup_deconz_integration(opp, aioclient_mock)

    device_registry = await opp.helpers.device_registry.async_get_registry()

    assert len(opp.states.async_all()) == 1
    assert (len(
        async_entries_for_config_entry(device_registry,
                                       config_entry.entry_id)) == 2)
Exemple #4
0
    def _resolve_config_entry(self, config_entry_id) -> None:
        """Resolve a config entry.

        Will only be called if config entry is an entry point.
        """
        for device_entry in device_registry.async_entries_for_config_entry(
                self._device_reg, config_entry_id):
            self._add_or_resolve("device", device_entry.id)

        for entity_entry in entity_registry.async_entries_for_config_entry(
                self._entity_reg, config_entry_id):
            self._add_or_resolve("entity", entity_entry.entity_id)
Exemple #5
0
    async def add_public_entities(update=True):
        """Retrieve Netatmo public weather entities."""
        entities = {
            device.name: device.id
            for device in async_entries_for_config_entry(
                device_registry, entry.entry_id)
            if device.model == "Public Weather stations"
        }

        new_entities = []
        for area in [
                NetatmoArea(**i)
                for i in entry.options.get(CONF_WEATHER_AREAS, {}).values()
        ]:
            signal_name = f"{PUBLICDATA_DATA_CLASS_NAME}-{area.uuid}"

            if area.area_name in entities:
                entities.pop(area.area_name)

                if update:
                    async_dispatcher_send(
                        opp,
                        f"netatmo-config-{area.area_name}",
                        area,
                    )
                    continue

            await data_handler.register_data_class(
                PUBLICDATA_DATA_CLASS_NAME,
                signal_name,
                None,
                lat_ne=area.lat_ne,
                lon_ne=area.lon_ne,
                lat_sw=area.lat_sw,
                lon_sw=area.lon_sw,
            )
            data_class = data_handler.data.get(signal_name)

            if data_class and data_class.raw_data:
                nonlocal platform_not_ready
                platform_not_ready = False

            for sensor_type in SUPPORTED_PUBLIC_SENSOR_TYPES:
                new_entities.append(
                    NetatmoPublicSensor(data_handler, area, sensor_type))

        for device_id in entities.values():
            device_registry.async_remove_device(device_id)

        if new_entities:
            async_add_entities(new_entities)
Exemple #6
0
async def test_entry_setup_unload(opp, api_factory, gateway_id):
    """Test config entry setup and unload."""
    entry = MockConfigEntry(
        domain=tradfri.DOMAIN,
        data={
            tradfri.CONF_HOST: "mock-host",
            tradfri.CONF_IDENTITY: "mock-identity",
            tradfri.CONF_KEY: "mock-key",
            tradfri.CONF_IMPORT_GROUPS: True,
            tradfri.CONF_GATEWAY_ID: gateway_id,
        },
    )

    entry.add_to_opp(opp)
    with patch.object(opp.config_entries,
                      "async_forward_entry_setup",
                      return_value=True) as setup:
        await opp.config_entries.async_setup(entry.entry_id)
        await opp.async_block_till_done()
        assert setup.call_count == len(tradfri.PLATFORMS)

    dev_reg = dr.async_get(opp)
    dev_entries = dr.async_entries_for_config_entry(dev_reg, entry.entry_id)

    assert dev_entries
    dev_entry = dev_entries[0]
    assert dev_entry.identifiers == {(tradfri.DOMAIN,
                                      entry.data[tradfri.CONF_GATEWAY_ID])}
    assert dev_entry.manufacturer == tradfri.ATTR_TRADFRI_MANUFACTURER
    assert dev_entry.name == tradfri.ATTR_TRADFRI_GATEWAY
    assert dev_entry.model == tradfri.ATTR_TRADFRI_GATEWAY_MODEL

    with patch.object(opp.config_entries,
                      "async_forward_entry_unload",
                      return_value=True) as unload:
        assert await opp.config_entries.async_unload(entry.entry_id)
        await opp.async_block_till_done()
        assert unload.call_count == len(tradfri.PLATFORMS)
        assert api_factory.shutdown.call_count == 1
Exemple #7
0
async def test_deconz_events(opp, aioclient_mock, mock_deconz_websocket):
    """Test successful creation of deconz events."""
    data = {
        "sensors": {
            "1": {
                "name": "Switch 1",
                "type": "ZHASwitch",
                "state": {
                    "buttonevent": 1000
                },
                "config": {},
                "uniqueid": "00:00:00:00:00:00:00:01-00",
            },
            "2": {
                "name": "Switch 2",
                "type": "ZHASwitch",
                "state": {
                    "buttonevent": 1000
                },
                "config": {
                    "battery": 100
                },
                "uniqueid": "00:00:00:00:00:00:00:02-00",
            },
            "3": {
                "name": "Switch 3",
                "type": "ZHASwitch",
                "state": {
                    "buttonevent": 1000,
                    "gesture": 1
                },
                "config": {
                    "battery": 100
                },
                "uniqueid": "00:00:00:00:00:00:00:03-00",
            },
            "4": {
                "name": "Switch 4",
                "type": "ZHASwitch",
                "state": {
                    "buttonevent": 1000,
                    "gesture": 1
                },
                "config": {
                    "battery": 100
                },
                "uniqueid": "00:00:00:00:00:00:00:04-00",
            },
            "5": {
                "name": "ZHA remote 1",
                "type": "ZHASwitch",
                "state": {
                    "angle": 0,
                    "buttonevent": 1000,
                    "xy": [0.0, 0.0]
                },
                "config": {
                    "group": "4,5,6",
                    "reachable": True,
                    "on": True
                },
                "uniqueid": "00:00:00:00:00:00:00:05-00",
            },
        }
    }
    with patch.dict(DECONZ_WEB_REQUEST, data):
        config_entry = await setup_deconz_integration(opp, aioclient_mock)

    device_registry = await opp.helpers.device_registry.async_get_registry()

    assert len(opp.states.async_all()) == 3
    # 5 switches + 2 additional devices for deconz service and host
    assert (len(
        async_entries_for_config_entry(device_registry,
                                       config_entry.entry_id)) == 7)
    assert opp.states.get("sensor.switch_2_battery_level").state == "100"
    assert opp.states.get("sensor.switch_3_battery_level").state == "100"
    assert opp.states.get("sensor.switch_4_battery_level").state == "100"

    captured_events = async_capture_events(opp, CONF_DECONZ_EVENT)

    event_changed_sensor = {
        "t": "event",
        "e": "changed",
        "r": "sensors",
        "id": "1",
        "state": {
            "buttonevent": 2000
        },
    }
    await mock_deconz_websocket(data=event_changed_sensor)
    await opp.async_block_till_done()

    device = device_registry.async_get_device(
        identifiers={(DECONZ_DOMAIN, "00:00:00:00:00:00:00:01")})

    assert len(captured_events) == 1
    assert captured_events[0].data == {
        "id": "switch_1",
        "unique_id": "00:00:00:00:00:00:00:01",
        "event": 2000,
        "device_id": device.id,
    }

    event_changed_sensor = {
        "t": "event",
        "e": "changed",
        "r": "sensors",
        "id": "3",
        "state": {
            "buttonevent": 2000
        },
    }
    await mock_deconz_websocket(data=event_changed_sensor)
    await opp.async_block_till_done()

    device = device_registry.async_get_device(
        identifiers={(DECONZ_DOMAIN, "00:00:00:00:00:00:00:03")})

    assert len(captured_events) == 2
    assert captured_events[1].data == {
        "id": "switch_3",
        "unique_id": "00:00:00:00:00:00:00:03",
        "event": 2000,
        "gesture": 1,
        "device_id": device.id,
    }

    event_changed_sensor = {
        "t": "event",
        "e": "changed",
        "r": "sensors",
        "id": "4",
        "state": {
            "gesture": 0
        },
    }
    await mock_deconz_websocket(data=event_changed_sensor)
    await opp.async_block_till_done()

    device = device_registry.async_get_device(
        identifiers={(DECONZ_DOMAIN, "00:00:00:00:00:00:00:04")})

    assert len(captured_events) == 3
    assert captured_events[2].data == {
        "id": "switch_4",
        "unique_id": "00:00:00:00:00:00:00:04",
        "event": 1000,
        "gesture": 0,
        "device_id": device.id,
    }

    event_changed_sensor = {
        "t": "event",
        "e": "changed",
        "r": "sensors",
        "id": "5",
        "state": {
            "buttonevent": 6002,
            "angle": 110,
            "xy": [0.5982, 0.3897]
        },
    }
    await mock_deconz_websocket(data=event_changed_sensor)
    await opp.async_block_till_done()

    device = device_registry.async_get_device(
        identifiers={(DECONZ_DOMAIN, "00:00:00:00:00:00:00:05")})

    assert len(captured_events) == 4
    assert captured_events[3].data == {
        "id": "zha_remote_1",
        "unique_id": "00:00:00:00:00:00:00:05",
        "event": 6002,
        "angle": 110,
        "xy": [0.5982, 0.3897],
        "device_id": device.id,
    }

    # Unsupported event

    event_changed_sensor = {
        "t": "event",
        "e": "changed",
        "r": "sensors",
        "id": "1",
        "name": "other name",
    }
    await mock_deconz_websocket(data=event_changed_sensor)
    await opp.async_block_till_done()

    assert len(captured_events) == 4

    await opp.config_entries.async_unload(config_entry.entry_id)

    states = opp.states.async_all()
    assert len(opp.states.async_all()) == 3
    for state in states:
        assert state.state == STATE_UNAVAILABLE

    await opp.config_entries.async_remove(config_entry.entry_id)
    await opp.async_block_till_done()
    assert len(opp.states.async_all()) == 0
Exemple #8
0
async def test_deconz_alarm_events(opp, aioclient_mock, mock_deconz_websocket):
    """Test successful creation of deconz alarm events."""
    data = {
        "sensors": {
            "1": {
                "config": {
                    "armed": "disarmed",
                    "enrolled": 0,
                    "on": True,
                    "panel": "disarmed",
                    "pending": [],
                    "reachable": True,
                },
                "ep": 1,
                "etag": "3c4008d74035dfaa1f0bb30d24468b12",
                "lastseen": "2021-04-02T13:07Z",
                "manufacturername": "Universal Electronics Inc",
                "modelid": "URC4450BC0-X-R",
                "name": "Keypad",
                "state": {
                    "action": "armed_away,1111,55",
                    "lastupdated": "2021-04-02T13:08:18.937",
                    "lowbattery": False,
                    "tampered": True,
                },
                "type": "ZHAAncillaryControl",
                "uniqueid": "00:00:00:00:00:00:00:01-01-0501",
            }
        }
    }
    with patch.dict(DECONZ_WEB_REQUEST, data):
        config_entry = await setup_deconz_integration(opp, aioclient_mock)

    device_registry = await opp.helpers.device_registry.async_get_registry()

    assert len(opp.states.async_all()) == 2
    # 1 alarm control device + 2 additional devices for deconz service and host
    assert (len(
        async_entries_for_config_entry(device_registry,
                                       config_entry.entry_id)) == 3)

    captured_events = async_capture_events(opp, CONF_DECONZ_ALARM_EVENT)

    # Armed away event

    event_changed_sensor = {
        "t": "event",
        "e": "changed",
        "r": "sensors",
        "id": "1",
        "state": {
            "action": "armed_away,1234,1"
        },
    }
    await mock_deconz_websocket(data=event_changed_sensor)
    await opp.async_block_till_done()

    device = device_registry.async_get_device(
        identifiers={(DECONZ_DOMAIN, "00:00:00:00:00:00:00:01")})

    assert len(captured_events) == 1
    assert captured_events[0].data == {
        CONF_ID: "keypad",
        CONF_UNIQUE_ID: "00:00:00:00:00:00:00:01",
        CONF_DEVICE_ID: device.id,
        CONF_EVENT: "armed_away",
        CONF_CODE: "1234",
    }

    # Unsupported events

    event_changed_sensor = {
        "t": "event",
        "e": "changed",
        "r": "sensors",
        "id": "1",
        "state": {
            "action": "unsupported,1234,1"
        },
    }
    await mock_deconz_websocket(data=event_changed_sensor)
    await opp.async_block_till_done()

    assert len(captured_events) == 1

    event_changed_sensor = {
        "t": "event",
        "e": "changed",
        "r": "sensors",
        "id": "1",
        "config": {
            "panel": "armed_away"
        },
    }
    await mock_deconz_websocket(data=event_changed_sensor)
    await opp.async_block_till_done()

    assert len(captured_events) == 1

    await opp.config_entries.async_unload(config_entry.entry_id)

    states = opp.states.async_all()
    assert len(opp.states.async_all()) == 2
    for state in states:
        assert state.state == STATE_UNAVAILABLE

    await opp.config_entries.async_remove(config_entry.entry_id)
    await opp.async_block_till_done()
    assert len(opp.states.async_all()) == 0
async def test_options_add_and_configure_device(opp):
    """Test we can add a device."""
    await setup.async_setup_component(opp, "persistent_notification", {})

    entry = MockConfigEntry(
        domain=DOMAIN,
        data={
            "host": None,
            "port": None,
            "device": "/dev/tty123",
            "automatic_add": False,
            "devices": {},
        },
        unique_id=DOMAIN,
    )
    entry.add_to_opp(opp)

    result = await opp.config_entries.options.async_init(entry.entry_id)

    assert result["type"] == "form"
    assert result["step_id"] == "prompt_options"

    result = await opp.config_entries.options.async_configure(
        result["flow_id"],
        user_input={
            "automatic_add": True,
            "event_code": "0913000022670e013970",
        },
    )

    assert result["type"] == "form"
    assert result["step_id"] == "set_device_options"

    result = await opp.config_entries.options.async_configure(
        result["flow_id"],
        user_input={
            "fire_event": False,
            "signal_repetitions": 5,
            "data_bits": 4,
            "off_delay": "abcdef",
            "command_on": "xyz",
            "command_off": "xyz",
        },
    )

    assert result["type"] == "form"
    assert result["step_id"] == "set_device_options"
    assert result["errors"]
    assert result["errors"]["off_delay"] == "invalid_input_off_delay"
    assert result["errors"]["command_on"] == "invalid_input_2262_on"
    assert result["errors"]["command_off"] == "invalid_input_2262_off"

    result = await opp.config_entries.options.async_configure(
        result["flow_id"],
        user_input={
            "fire_event": False,
            "signal_repetitions": 5,
            "data_bits": 4,
            "command_on": "0xE",
            "command_off": "0x7",
            "off_delay": "9",
        },
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY

    await opp.async_block_till_done()

    assert entry.data["automatic_add"]

    assert entry.data["devices"]["0913000022670e013970"]
    assert not entry.data["devices"]["0913000022670e013970"]["fire_event"]
    assert entry.data["devices"]["0913000022670e013970"][
        "signal_repetitions"] == 5
    assert entry.data["devices"]["0913000022670e013970"]["off_delay"] == 9

    state = opp.states.get("binary_sensor.pt2262_22670e")
    assert state
    assert state.state == "off"
    assert state.attributes.get("friendly_name") == "PT2262 22670e"

    device_registry = dr.async_get(opp)
    device_entries = dr.async_entries_for_config_entry(device_registry,
                                                       entry.entry_id)

    assert device_entries[0].id

    result = await opp.config_entries.options.async_init(entry.entry_id)

    assert result["type"] == "form"
    assert result["step_id"] == "prompt_options"

    result = await opp.config_entries.options.async_configure(
        result["flow_id"],
        user_input={
            "automatic_add": False,
            "device": device_entries[0].id,
        },
    )

    assert result["type"] == "form"
    assert result["step_id"] == "set_device_options"

    result = await opp.config_entries.options.async_configure(
        result["flow_id"],
        user_input={
            "fire_event": True,
            "signal_repetitions": 5,
            "data_bits": 4,
            "command_on": "0xE",
            "command_off": "0x7",
        },
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY

    await opp.async_block_till_done()

    assert entry.data["devices"]["0913000022670e013970"]
    assert entry.data["devices"]["0913000022670e013970"]["fire_event"]
    assert entry.data["devices"]["0913000022670e013970"][
        "signal_repetitions"] == 5
    assert "delay_off" not in entry.data["devices"]["0913000022670e013970"]
async def test_options_remove_multiple_devices(opp):
    """Test we can add a device."""
    await setup.async_setup_component(opp, "persistent_notification", {})

    entry = MockConfigEntry(
        domain=DOMAIN,
        data={
            "host": None,
            "port": None,
            "device": "/dev/tty123",
            "automatic_add": False,
            "devices": {
                "0b1100cd0213c7f230010f71": {
                    "device_id": ["11", "0", "213c7f2:48"]
                },
                "0b1100100118cdea02010f70": {
                    "device_id": ["11", "0", "118cdea:2"]
                },
                "0b1100101118cdea02010f70": {
                    "device_id": ["11", "0", "1118cdea:2"]
                },
            },
        },
        unique_id=DOMAIN,
    )
    entry.add_to_opp(opp)

    await opp.config_entries.async_setup(entry.entry_id)
    await opp.async_block_till_done()

    state = opp.states.get("binary_sensor.ac_213c7f2_48")
    assert state
    state = opp.states.get("binary_sensor.ac_118cdea_2")
    assert state
    state = opp.states.get("binary_sensor.ac_1118cdea_2")
    assert state

    device_registry = dr.async_get(opp)
    device_entries = dr.async_entries_for_config_entry(device_registry,
                                                       entry.entry_id)

    assert len(device_entries) == 3

    def match_device_id(entry):
        device_id = next(iter(entry.identifiers))[1:]
        if device_id == ("11", "0", "213c7f2:48"):
            return True
        if device_id == ("11", "0", "118cdea:2"):
            return True
        return False

    remove_devices = [
        elem.id for elem in device_entries if match_device_id(elem)
    ]

    result = await opp.config_entries.options.async_init(entry.entry_id)

    assert result["type"] == "form"
    assert result["step_id"] == "prompt_options"

    result = await opp.config_entries.options.async_configure(
        result["flow_id"],
        user_input={
            "automatic_add": False,
            "remove_device": remove_devices,
        },
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY

    await opp.async_block_till_done()

    state = opp.states.get("binary_sensor.ac_213c7f2_48")
    assert not state
    state = opp.states.get("binary_sensor.ac_118cdea_2")
    assert not state
    state = opp.states.get("binary_sensor.ac_1118cdea_2")
    assert state
async def test_options_replace_control_device(opp):
    """Test we can replace a control device."""
    await setup.async_setup_component(opp, "persistent_notification", {})

    entry = MockConfigEntry(
        domain=DOMAIN,
        data={
            "host": None,
            "port": None,
            "device": "/dev/tty123",
            "automatic_add": False,
            "devices": {
                "0b1100100118cdea02010f70": {
                    "device_id": ["11", "0", "118cdea:2"],
                    "signal_repetitions": 1,
                },
                "0b1100101118cdea02010f70": {
                    "device_id": ["11", "0", "1118cdea:2"],
                    "signal_repetitions": 1,
                },
            },
        },
        unique_id=DOMAIN,
    )
    entry.add_to_opp(opp)

    await opp.config_entries.async_setup(entry.entry_id)
    await opp.async_block_till_done()

    state = opp.states.get("binary_sensor.ac_118cdea_2")
    assert state
    state = opp.states.get("sensor.ac_118cdea_2_rssi_numeric")
    assert state
    state = opp.states.get("switch.ac_118cdea_2")
    assert state
    state = opp.states.get("binary_sensor.ac_1118cdea_2")
    assert state
    state = opp.states.get("sensor.ac_1118cdea_2_rssi_numeric")
    assert state
    state = opp.states.get("switch.ac_1118cdea_2")
    assert state

    device_registry = dr.async_get(opp)
    device_entries = dr.async_entries_for_config_entry(device_registry,
                                                       entry.entry_id)

    old_device = next(
        (elem.id for elem in device_entries
         if next(iter(elem.identifiers))[1:] == ("11", "0", "118cdea:2")),
        None,
    )
    new_device = next(
        (elem.id for elem in device_entries
         if next(iter(elem.identifiers))[1:] == ("11", "0", "1118cdea:2")),
        None,
    )

    result = await opp.config_entries.options.async_init(entry.entry_id)

    assert result["type"] == "form"
    assert result["step_id"] == "prompt_options"

    result = await opp.config_entries.options.async_configure(
        result["flow_id"],
        user_input={
            "automatic_add": False,
            "device": old_device,
        },
    )

    assert result["type"] == "form"
    assert result["step_id"] == "set_device_options"

    result = await opp.config_entries.options.async_configure(
        result["flow_id"],
        user_input={
            "replace_device": new_device,
        },
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY

    await opp.async_block_till_done()

    entity_registry = er.async_get(opp)

    entry = entity_registry.async_get("binary_sensor.ac_118cdea_2")
    assert entry
    assert entry.device_id == new_device
    entry = entity_registry.async_get("sensor.ac_118cdea_2_rssi_numeric")
    assert entry
    assert entry.device_id == new_device
    entry = entity_registry.async_get("switch.ac_118cdea_2")
    assert entry
    assert entry.device_id == new_device

    state = opp.states.get("binary_sensor.ac_1118cdea_2")
    assert not state
    state = opp.states.get("sensor.ac_1118cdea_2_rssi_numeric")
    assert not state
    state = opp.states.get("switch.ac_1118cdea_2")
    assert not state
Exemple #12
0
async def test_set_value(opp, client, climate_danfoss_lc_13, integration):
    """Test set_value service."""
    dev_reg = async_get_dev_reg(opp)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]

    await opp.services.async_call(
        DOMAIN,
        SERVICE_SET_VALUE,
        {
            ATTR_ENTITY_ID: CLIMATE_DANFOSS_LC13_ENTITY,
            ATTR_COMMAND_CLASS: 117,
            ATTR_PROPERTY: "local",
            ATTR_VALUE: 2,
        },
        blocking=True,
    )

    assert len(client.async_send_command_no_wait.call_args_list) == 1
    args = client.async_send_command_no_wait.call_args[0][0]
    assert args["command"] == "node.set_value"
    assert args["nodeId"] == 5
    assert args["valueId"] == {
        "commandClassName": "Protection",
        "commandClass": 117,
        "endpoint": 0,
        "property": "local",
        "propertyName": "local",
        "ccVersion": 2,
        "metadata": {
            "type": "number",
            "readable": True,
            "writeable": True,
            "label": "Local protection state",
            "states": {
                "0": "Unprotected",
                "2": "NoOperationPossible"
            },
        },
        "value": 0,
    }
    assert args["value"] == 2

    client.async_send_command_no_wait.reset_mock()

    # Test that when a command fails we raise an exception
    client.async_send_command.return_value = {"success": False}

    with pytest.raises(SetValueFailed):
        await opp.services.async_call(
            DOMAIN,
            SERVICE_SET_VALUE,
            {
                ATTR_DEVICE_ID: device.id,
                ATTR_COMMAND_CLASS: 117,
                ATTR_PROPERTY: "local",
                ATTR_VALUE: 2,
                ATTR_WAIT_FOR_RESULT: True,
            },
            blocking=True,
        )

    assert len(client.async_send_command.call_args_list) == 1

    args = client.async_send_command.call_args[0][0]
    assert args["command"] == "node.set_value"
    assert args["nodeId"] == 5
    assert args["valueId"] == {
        "commandClassName": "Protection",
        "commandClass": 117,
        "endpoint": 0,
        "property": "local",
        "propertyName": "local",
        "ccVersion": 2,
        "metadata": {
            "type": "number",
            "readable": True,
            "writeable": True,
            "label": "Local protection state",
            "states": {
                "0": "Unprotected",
                "2": "NoOperationPossible"
            },
        },
        "value": 0,
    }
    assert args["value"] == 2

    # Test missing device and entities keys
    with pytest.raises(vol.MultipleInvalid):
        await opp.services.async_call(
            DOMAIN,
            SERVICE_SET_VALUE,
            {
                ATTR_COMMAND_CLASS: 117,
                ATTR_PROPERTY: "local",
                ATTR_VALUE: 2,
                ATTR_WAIT_FOR_RESULT: True,
            },
            blocking=True,
        )
async def test_options_configure_rfy_cover_device(opp):
    """Test we can configure the venetion blind mode of an Rfy cover."""
    await setup.async_setup_component(opp, "persistent_notification", {})

    entry = MockConfigEntry(
        domain=DOMAIN,
        data={
            "host": None,
            "port": None,
            "device": "/dev/tty123",
            "automatic_add": False,
            "devices": {},
        },
        unique_id=DOMAIN,
    )
    entry.add_to_opp(opp)

    await opp.config_entries.async_setup(entry.entry_id)
    await opp.async_block_till_done()

    result = await opp.config_entries.options.async_init(entry.entry_id)

    assert result["type"] == "form"
    assert result["step_id"] == "prompt_options"

    result = await opp.config_entries.options.async_configure(
        result["flow_id"],
        user_input={
            "automatic_add": True,
            "event_code": "071a000001020301",
        },
    )

    assert result["type"] == "form"
    assert result["step_id"] == "set_device_options"

    result = await opp.config_entries.options.async_configure(
        result["flow_id"],
        user_input={
            "fire_event": False,
            "venetian_blind_mode": "EU",
        },
    )

    await opp.async_block_till_done()

    assert entry.data["devices"]["071a000001020301"][
        "venetian_blind_mode"] == "EU"

    device_registry = dr.async_get(opp)
    device_entries = dr.async_entries_for_config_entry(device_registry,
                                                       entry.entry_id)

    assert device_entries[0].id

    result = await opp.config_entries.options.async_init(entry.entry_id)

    assert result["type"] == "form"
    assert result["step_id"] == "prompt_options"

    result = await opp.config_entries.options.async_configure(
        result["flow_id"],
        user_input={
            "automatic_add": False,
            "device": device_entries[0].id,
        },
    )

    assert result["type"] == "form"
    assert result["step_id"] == "set_device_options"

    result = await opp.config_entries.options.async_configure(
        result["flow_id"],
        user_input={
            "fire_event": False,
            "venetian_blind_mode": "EU",
        },
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY

    await opp.async_block_till_done()

    assert entry.data["devices"]["071a000001020301"][
        "venetian_blind_mode"] == "EU"
Exemple #14
0
    async def async_instances_to_clients_raw(instances: list[dict[str, Any]]) -> None:
        """Convert instances to Hyperion clients."""
        device_registry = dr.async_get(opp)
        running_instances: set[int] = set()
        stopped_instances: set[int] = set()
        existing_instances = opp.data[DOMAIN][config_entry.entry_id][
            CONF_INSTANCE_CLIENTS
        ]
        server_id = cast(str, config_entry.unique_id)

        # In practice, an instance can be in 3 states as seen by this function:
        #
        #    * Exists, and is running: Should be present in HASS/registry.
        #    * Exists, but is not running: Cannot add it yet, but entity may have be
        #      registered from a previous time it was running.
        #    * No longer exists at all: Should not be present in HASS/registry.

        # Add instances that are missing.
        for instance in instances:
            instance_num = instance.get(hyperion_const.KEY_INSTANCE)
            if instance_num is None:
                continue
            if not instance.get(hyperion_const.KEY_RUNNING, False):
                stopped_instances.add(instance_num)
                continue
            running_instances.add(instance_num)
            if instance_num in existing_instances:
                continue
            hyperion_client = await async_create_connect_hyperion_client(
                host, port, instance=instance_num, token=token
            )
            if not hyperion_client:
                continue
            existing_instances[instance_num] = hyperion_client
            instance_name = instance.get(hyperion_const.KEY_FRIENDLY_NAME, DEFAULT_NAME)
            async_dispatcher_send(
                opp,
                SIGNAL_INSTANCE_ADD.format(config_entry.entry_id),
                instance_num,
                instance_name,
            )

        # Remove entities that are are not running instances on Hyperion.
        for instance_num in set(existing_instances) - running_instances:
            del existing_instances[instance_num]
            async_dispatcher_send(
                opp, SIGNAL_INSTANCE_REMOVE.format(config_entry.entry_id), instance_num
            )

        # Ensure every device associated with this config entry is still in the list of
        # motionEye cameras, otherwise remove the device (and thus entities).
        known_devices = {
            get_hyperion_device_id(server_id, instance_num)
            for instance_num in running_instances | stopped_instances
        }
        for device_entry in dr.async_entries_for_config_entry(
            device_registry, config_entry.entry_id
        ):
            for (kind, key) in device_entry.identifiers:
                if kind == DOMAIN and key in known_devices:
                    break
            else:
                device_registry.async_remove_device(device_entry.id)
Exemple #15
0
    async def async_step_prompt_options(self, user_input=None):
        """Prompt for options."""
        errors = {}

        if user_input is not None:
            self._global_options = {
                CONF_AUTOMATIC_ADD: user_input[CONF_AUTOMATIC_ADD],
            }
            if CONF_DEVICE in user_input:
                entry_id = user_input[CONF_DEVICE]
                device_data = self._get_device_data(entry_id)
                self._selected_device_entry_id = entry_id
                event_code = device_data[CONF_EVENT_CODE]
                self._selected_device_event_code = event_code
                self._selected_device = self._config_entry.data[CONF_DEVICES][
                    event_code]
                self._selected_device_object = get_rfx_object(event_code)
                return await self.async_step_set_device_options()
            if CONF_REMOVE_DEVICE in user_input:
                remove_devices = user_input[CONF_REMOVE_DEVICE]
                devices = {}
                for entry_id in remove_devices:
                    device_data = self._get_device_data(entry_id)

                    event_code = device_data[CONF_EVENT_CODE]
                    device_id = device_data[CONF_DEVICE_ID]
                    self.opp.helpers.dispatcher.async_dispatcher_send(
                        f"{DOMAIN}_{CONF_REMOVE_DEVICE}_{device_id}")
                    self._device_registry.async_remove_device(entry_id)
                    if event_code is not None:
                        devices[event_code] = None

                self.update_config_data(global_options=self._global_options,
                                        devices=devices)

                return self.async_create_entry(title="", data={})
            if CONF_EVENT_CODE in user_input:
                self._selected_device_event_code = user_input[CONF_EVENT_CODE]
                self._selected_device = {}
                selected_device_object = get_rfx_object(
                    self._selected_device_event_code)
                if selected_device_object is None:
                    errors[CONF_EVENT_CODE] = "invalid_event_code"
                elif not self._can_add_device(selected_device_object):
                    errors[CONF_EVENT_CODE] = "already_configured_device"
                else:
                    self._selected_device_object = selected_device_object
                    return await self.async_step_set_device_options()

            if not errors:
                self.update_config_data(global_options=self._global_options)

                return self.async_create_entry(title="", data={})

        device_registry = await async_get_device_registry(self.opp)
        device_entries = async_entries_for_config_entry(
            device_registry, self._config_entry.entry_id)
        self._device_registry = device_registry
        self._device_entries = device_entries

        remove_devices = {
            entry.id: entry.name_by_user if entry.name_by_user else entry.name
            for entry in device_entries
        }

        configure_devices = {
            entry.id: entry.name_by_user if entry.name_by_user else entry.name
            for entry in device_entries
            if self._get_device_event_code(entry.id) is not None
        }

        options = {
            vol.Optional(
                CONF_AUTOMATIC_ADD,
                default=self._config_entry.data[CONF_AUTOMATIC_ADD],
            ):
            bool,
            vol.Optional(CONF_EVENT_CODE):
            str,
            vol.Optional(CONF_DEVICE):
            vol.In(configure_devices),
            vol.Optional(CONF_REMOVE_DEVICE):
            cv.multi_select(remove_devices),
        }

        return self.async_show_form(step_id="prompt_options",
                                    data_schema=vol.Schema(options),
                                    errors=errors)
async def test_options_add_remove_device(opp):
    """Test we can add a device."""
    await setup.async_setup_component(opp, "persistent_notification", {})

    entry = MockConfigEntry(
        domain=DOMAIN,
        data={
            "host": None,
            "port": None,
            "device": "/dev/tty123",
            "automatic_add": False,
            "devices": {},
        },
        unique_id=DOMAIN,
    )
    entry.add_to_opp(opp)

    result = await opp.config_entries.options.async_init(entry.entry_id)

    assert result["type"] == "form"
    assert result["step_id"] == "prompt_options"

    result = await opp.config_entries.options.async_configure(
        result["flow_id"],
        user_input={
            "automatic_add": True,
            "event_code": "0b1100cd0213c7f230010f71",
        },
    )

    assert result["type"] == "form"
    assert result["step_id"] == "set_device_options"

    result = await opp.config_entries.options.async_configure(
        result["flow_id"],
        user_input={
            "fire_event": True,
            "signal_repetitions": 5,
            "off_delay": "4"
        },
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY

    await opp.async_block_till_done()

    assert entry.data["automatic_add"]

    assert entry.data["devices"]["0b1100cd0213c7f230010f71"]
    assert entry.data["devices"]["0b1100cd0213c7f230010f71"]["fire_event"]
    assert entry.data["devices"]["0b1100cd0213c7f230010f71"][
        "signal_repetitions"] == 5
    assert entry.data["devices"]["0b1100cd0213c7f230010f71"]["off_delay"] == 4

    state = opp.states.get("binary_sensor.ac_213c7f2_48")
    assert state
    assert state.state == "off"
    assert state.attributes.get("friendly_name") == "AC 213c7f2:48"

    device_registry = dr.async_get(opp)
    device_entries = dr.async_entries_for_config_entry(device_registry,
                                                       entry.entry_id)

    assert device_entries[0].id

    result = await opp.config_entries.options.async_init(entry.entry_id)

    assert result["type"] == "form"
    assert result["step_id"] == "prompt_options"

    result = await opp.config_entries.options.async_configure(
        result["flow_id"],
        user_input={
            "automatic_add": False,
            "remove_device": [device_entries[0].id],
        },
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY

    await opp.async_block_till_done()

    assert not entry.data["automatic_add"]

    assert "0b1100cd0213c7f230010f71" not in entry.data["devices"]

    state = opp.states.get("binary_sensor.ac_213c7f2_48")
    assert not state
Exemple #17
0
async def async_setup_entry(  # noqa: C901
        opp: OpenPeerPower, entry: ConfigEntry) -> bool:
    """Set up Synology DSM sensors."""

    # Migrate old unique_id
    @callback
    def _async_migrator(
        entity_entry: entity_registry.RegistryEntry,
    ) -> dict[str, str] | None:
        """Migrate away from ID using label."""
        # Reject if new unique_id
        if "SYNO." in entity_entry.unique_id:
            return None

        entries = {
            **STORAGE_DISK_BINARY_SENSORS,
            **STORAGE_DISK_SENSORS,
            **STORAGE_VOL_SENSORS,
            **UTILISATION_SENSORS,
        }
        infos = entity_entry.unique_id.split("_")
        serial = infos.pop(0)
        label = infos.pop(0)
        device_id = "_".join(infos)

        # Removed entity
        if ("Type" in entity_entry.unique_id
                or "Device" in entity_entry.unique_id
                or "Name" in entity_entry.unique_id):
            return None

        entity_type: str | None = None
        for entity_key, entity_attrs in entries.items():
            if (device_id and entity_attrs[ENTITY_NAME] == "Status"
                    and "Status" in entity_entry.unique_id
                    and "(Smart)" not in entity_entry.unique_id):
                if "sd" in device_id and "disk" in entity_key:
                    entity_type = entity_key
                    continue
                if "volume" in device_id and "volume" in entity_key:
                    entity_type = entity_key
                    continue

            if entity_attrs[ENTITY_NAME] == label:
                entity_type = entity_key

        if entity_type is None:
            return None

        new_unique_id = "_".join([serial, entity_type])
        if device_id:
            new_unique_id += f"_{device_id}"

        _LOGGER.info(
            "Migrating unique_id from [%s] to [%s]",
            entity_entry.unique_id,
            new_unique_id,
        )
        return {"new_unique_id": new_unique_id}

    await entity_registry.async_migrate_entries(opp, entry.entry_id,
                                                _async_migrator)

    # migrate device indetifiers
    dev_reg = await get_dev_reg(opp)
    devices: list[
        DeviceEntry] = device_registry.async_entries_for_config_entry(
            dev_reg, entry.entry_id)
    for device in devices:
        old_identifier = list(next(iter(device.identifiers)))
        if len(old_identifier) > 2:
            new_identifier = {(old_identifier.pop(0),
                               "_".join([str(x) for x in old_identifier]))}
            _LOGGER.debug("migrate identifier '%s' to '%s'",
                          device.identifiers, new_identifier)
            dev_reg.async_update_device(device.id,
                                        new_identifiers=new_identifier)

    # Migrate existing entry configuration
    if entry.data.get(CONF_VERIFY_SSL) is None:
        opp.config_entries.async_update_entry(
            entry, data={
                **entry.data, CONF_VERIFY_SSL: DEFAULT_VERIFY_SSL
            })

    # Continue setup
    api = SynoApi(opp, entry)
    try:
        await api.async_setup()
    except (SynologyDSMLoginFailedException,
            SynologyDSMRequestException) as err:
        _LOGGER.debug("Unable to connect to DSM '%s' during setup: %s",
                      entry.unique_id, err)
        raise ConfigEntryNotReady from err

    opp.data.setdefault(DOMAIN, {})
    opp.data[DOMAIN][entry.unique_id] = {
        UNDO_UPDATE_LISTENER:
        entry.add_update_listener(_async_update_listener),
        SYNO_API: api,
        SYSTEM_LOADED: True,
    }

    # Services
    await _async_setup_services(opp)

    # For SSDP compat
    if not entry.data.get(CONF_MAC):
        network = await opp.async_add_executor_job(getattr, api.dsm, "network")
        opp.config_entries.async_update_entry(entry,
                                              data={
                                                  **entry.data, CONF_MAC:
                                                  network.macs
                                              })

    async def async_coordinator_update_data_cameras(
    ) -> dict[str, dict[str, SynoCamera]] | None:
        """Fetch all camera data from api."""
        if not opp.data[DOMAIN][entry.unique_id][SYSTEM_LOADED]:
            raise UpdateFailed("System not fully loaded")

        if SynoSurveillanceStation.CAMERA_API_KEY not in api.dsm.apis:
            return None

        surveillance_station = api.surveillance_station

        try:
            async with async_timeout.timeout(10):
                await opp.async_add_executor_job(surveillance_station.update)
        except SynologyDSMAPIErrorException as err:
            raise UpdateFailed(f"Error communicating with API: {err}") from err

        return {
            "cameras": {
                camera.id: camera
                for camera in surveillance_station.get_all_cameras()
            }
        }

    async def async_coordinator_update_data_central() -> None:
        """Fetch all device and sensor data from api."""
        try:
            await api.async_update()
        except Exception as err:
            raise UpdateFailed(f"Error communicating with API: {err}") from err
        return None

    async def async_coordinator_update_data_switches(
    ) -> dict[str, dict[str, Any]] | None:
        """Fetch all switch data from api."""
        if not opp.data[DOMAIN][entry.unique_id][SYSTEM_LOADED]:
            raise UpdateFailed("System not fully loaded")
        if SynoSurveillanceStation.HOME_MODE_API_KEY not in api.dsm.apis:
            return None

        surveillance_station = api.surveillance_station

        return {
            "switches": {
                "home_mode":
                await opp.async_add_executor_job(
                    surveillance_station.get_home_mode_status)
            }
        }

    opp.data[DOMAIN][
        entry.unique_id][COORDINATOR_CAMERAS] = DataUpdateCoordinator(
            opp,
            _LOGGER,
            name=f"{entry.unique_id}_cameras",
            update_method=async_coordinator_update_data_cameras,
            update_interval=timedelta(seconds=30),
        )

    opp.data[DOMAIN][
        entry.unique_id][COORDINATOR_CENTRAL] = DataUpdateCoordinator(
            opp,
            _LOGGER,
            name=f"{entry.unique_id}_central",
            update_method=async_coordinator_update_data_central,
            update_interval=timedelta(minutes=entry.options.get(
                CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)),
        )

    opp.data[DOMAIN][
        entry.unique_id][COORDINATOR_SWITCHES] = DataUpdateCoordinator(
            opp,
            _LOGGER,
            name=f"{entry.unique_id}_switches",
            update_method=async_coordinator_update_data_switches,
            update_interval=timedelta(seconds=30),
        )

    opp.config_entries.async_setup_platforms(entry, PLATFORMS)

    return True
async def test_options_replace_sensor_device(opp):
    """Test we can replace a sensor device."""
    await setup.async_setup_component(opp, "persistent_notification", {})

    entry = MockConfigEntry(
        domain=DOMAIN,
        data={
            "host": None,
            "port": None,
            "device": "/dev/tty123",
            "automatic_add": False,
            "devices": {
                "0a520101f00400e22d0189": {
                    "device_id": ["52", "1", "f0:04"]
                },
                "0a520105230400c3260279": {
                    "device_id": ["52", "1", "23:04"]
                },
            },
        },
        unique_id=DOMAIN,
    )
    entry.add_to_opp(opp)

    await opp.config_entries.async_setup(entry.entry_id)
    await opp.async_block_till_done()

    state = opp.states.get(
        "sensor.thgn122_123_thgn132_thgr122_228_238_268_f0_04_rssi_numeric")
    assert state
    state = opp.states.get(
        "sensor.thgn122_123_thgn132_thgr122_228_238_268_f0_04_battery_numeric")
    assert state
    state = opp.states.get(
        "sensor.thgn122_123_thgn132_thgr122_228_238_268_f0_04_humidity")
    assert state
    state = opp.states.get(
        "sensor.thgn122_123_thgn132_thgr122_228_238_268_f0_04_humidity_status")
    assert state
    state = opp.states.get(
        "sensor.thgn122_123_thgn132_thgr122_228_238_268_f0_04_temperature")
    assert state
    state = opp.states.get(
        "sensor.thgn122_123_thgn132_thgr122_228_238_268_23_04_rssi_numeric")
    assert state
    state = opp.states.get(
        "sensor.thgn122_123_thgn132_thgr122_228_238_268_23_04_battery_numeric")
    assert state
    state = opp.states.get(
        "sensor.thgn122_123_thgn132_thgr122_228_238_268_23_04_humidity")
    assert state
    state = opp.states.get(
        "sensor.thgn122_123_thgn132_thgr122_228_238_268_23_04_humidity_status")
    assert state
    state = opp.states.get(
        "sensor.thgn122_123_thgn132_thgr122_228_238_268_23_04_temperature")
    assert state

    device_registry = dr.async_get(opp)
    device_entries = dr.async_entries_for_config_entry(device_registry,
                                                       entry.entry_id)

    old_device = next(
        (elem.id for elem in device_entries
         if next(iter(elem.identifiers))[1:] == ("52", "1", "f0:04")),
        None,
    )
    new_device = next(
        (elem.id for elem in device_entries
         if next(iter(elem.identifiers))[1:] == ("52", "1", "23:04")),
        None,
    )

    result = await opp.config_entries.options.async_init(entry.entry_id)

    assert result["type"] == "form"
    assert result["step_id"] == "prompt_options"

    result = await opp.config_entries.options.async_configure(
        result["flow_id"],
        user_input={
            "automatic_add": False,
            "device": old_device,
        },
    )

    assert result["type"] == "form"
    assert result["step_id"] == "set_device_options"

    result = await opp.config_entries.options.async_configure(
        result["flow_id"],
        user_input={
            "replace_device": new_device,
        },
    )

    assert result["type"] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY

    await opp.async_block_till_done()

    entity_registry = er.async_get(opp)

    entry = entity_registry.async_get(
        "sensor.thgn122_123_thgn132_thgr122_228_238_268_f0_04_rssi_numeric")
    assert entry
    assert entry.device_id == new_device
    entry = entity_registry.async_get(
        "sensor.thgn122_123_thgn132_thgr122_228_238_268_f0_04_humidity")
    assert entry
    assert entry.device_id == new_device
    entry = entity_registry.async_get(
        "sensor.thgn122_123_thgn132_thgr122_228_238_268_f0_04_humidity_status")
    assert entry
    assert entry.device_id == new_device
    entry = entity_registry.async_get(
        "sensor.thgn122_123_thgn132_thgr122_228_238_268_f0_04_battery_numeric")
    assert entry
    assert entry.device_id == new_device
    entry = entity_registry.async_get(
        "sensor.thgn122_123_thgn132_thgr122_228_238_268_f0_04_temperature")
    assert entry
    assert entry.device_id == new_device

    state = opp.states.get(
        "sensor.thgn122_123_thgn132_thgr122_228_238_268_23_04_rssi_numeric")
    assert not state
    state = opp.states.get(
        "sensor.thgn122_123_thgn132_thgr122_228_238_268_23_04_battery_numeric")
    assert not state
    state = opp.states.get(
        "sensor.thgn122_123_thgn132_thgr122_228_238_268_23_04_humidity")
    assert not state
    state = opp.states.get(
        "sensor.thgn122_123_thgn132_thgr122_228_238_268_23_04_humidity_status")
    assert not state
    state = opp.states.get(
        "sensor.thgn122_123_thgn132_thgr122_228_238_268_23_04_temperature")
    assert not state
Exemple #19
0
            await driver_ready.wait()
        except asyncio.CancelledError:
            LOGGER.debug("Cancelling start platforms")
            return

        LOGGER.info("Connection to Zwave JS Server initialized")

        # If opt in preference hasn't been specified yet, we do nothing, otherwise
        # we apply the preference
        if opted_in := entry.data.get(CONF_DATA_COLLECTION_OPTED_IN):
            await async_enable_statistics(client)
        elif opted_in is False:
            await client.driver.async_disable_statistics()

        # Check for nodes that no longer exist and remove them
        stored_devices = device_registry.async_entries_for_config_entry(
            dev_reg, entry.entry_id)
        known_devices = [
            dev_reg.async_get_device({get_device_id(client, node)})
            for node in client.driver.controller.nodes.values()
        ]

        # Devices that are in the device registry that are not known by the controller can be removed
        for device in stored_devices:
            if device not in known_devices:
                dev_reg.async_remove_device(device.id)

        # run discovery on all ready nodes
        await asyncio.gather(*[
            async_on_node_added(node)
            for node in client.driver.controller.nodes.values()
        ])
Exemple #20
0
async def test_bulk_set_config_parameters(opp, client, multisensor_6,
                                          integration):
    """Test the bulk_set_partial_config_parameters service."""
    dev_reg = async_get_dev_reg(opp)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
    # Test setting config parameter by property and property_key
    await opp.services.async_call(
        DOMAIN,
        SERVICE_BULK_SET_PARTIAL_CONFIG_PARAMETERS,
        {
            ATTR_DEVICE_ID: device.id,
            ATTR_CONFIG_PARAMETER: 102,
            ATTR_CONFIG_VALUE: 241,
        },
        blocking=True,
    )

    assert len(client.async_send_command_no_wait.call_args_list) == 1
    args = client.async_send_command_no_wait.call_args[0][0]
    assert args["command"] == "node.set_value"
    assert args["nodeId"] == 52
    assert args["valueId"] == {
        "commandClass": 112,
        "property": 102,
    }
    assert args["value"] == 241

    client.async_send_command_no_wait.reset_mock()

    await opp.services.async_call(
        DOMAIN,
        SERVICE_BULK_SET_PARTIAL_CONFIG_PARAMETERS,
        {
            ATTR_ENTITY_ID: AIR_TEMPERATURE_SENSOR,
            ATTR_CONFIG_PARAMETER: 102,
            ATTR_CONFIG_VALUE: {
                1: 1,
                16: 1,
                32: 1,
                64: 1,
                128: 1,
            },
        },
        blocking=True,
    )

    assert len(client.async_send_command_no_wait.call_args_list) == 1
    args = client.async_send_command_no_wait.call_args[0][0]
    assert args["command"] == "node.set_value"
    assert args["nodeId"] == 52
    assert args["valueId"] == {
        "commandClass": 112,
        "property": 102,
    }
    assert args["value"] == 241

    client.async_send_command_no_wait.reset_mock()

    await opp.services.async_call(
        DOMAIN,
        SERVICE_BULK_SET_PARTIAL_CONFIG_PARAMETERS,
        {
            ATTR_ENTITY_ID: AIR_TEMPERATURE_SENSOR,
            ATTR_CONFIG_PARAMETER: 102,
            ATTR_CONFIG_VALUE: {
                "0x1": 1,
                "0x10": 1,
                "0x20": 1,
                "0x40": 1,
                "0x80": 1,
            },
        },
        blocking=True,
    )

    assert len(client.async_send_command_no_wait.call_args_list) == 1
    args = client.async_send_command_no_wait.call_args[0][0]
    assert args["command"] == "node.set_value"
    assert args["nodeId"] == 52
    assert args["valueId"] == {
        "commandClass": 112,
        "property": 102,
    }
    assert args["value"] == 241

    client.async_send_command_no_wait.reset_mock()

    # Test that when a device is awake, we call async_send_command instead of
    # async_send_command_no_wait
    multisensor_6.handle_wake_up(None)
    await opp.services.async_call(
        DOMAIN,
        SERVICE_BULK_SET_PARTIAL_CONFIG_PARAMETERS,
        {
            ATTR_ENTITY_ID: AIR_TEMPERATURE_SENSOR,
            ATTR_CONFIG_PARAMETER: 102,
            ATTR_CONFIG_VALUE: {
                1: 1,
                16: 1,
                32: 1,
                64: 1,
                128: 1,
            },
        },
        blocking=True,
    )

    assert len(client.async_send_command.call_args_list) == 1
    args = client.async_send_command.call_args[0][0]
    assert args["command"] == "node.set_value"
    assert args["nodeId"] == 52
    assert args["valueId"] == {
        "commandClass": 112,
        "property": 102,
    }
    assert args["value"] == 241

    client.async_send_command.reset_mock()