예제 #1
0
async def test_device_diagnostics_error(hass, integration):
    """Test the device diagnostics raises exception when an invalid device is used."""
    dev_reg = async_get_dev_reg(hass)
    device = dev_reg.async_get_or_create(config_entry_id=integration.entry_id,
                                         identifiers={("test", "test")})
    with pytest.raises(ValueError):
        await async_get_device_diagnostics(hass, integration, device)
예제 #2
0
def async_get_node_status_sensor_entity_id(
    hass: HomeAssistant,
    device_id: str,
    ent_reg: EntityRegistry | None = None,
    dev_reg: DeviceRegistry | None = None,
) -> str:
    """Get the node status sensor entity ID for a given Z-Wave JS device."""
    if not ent_reg:
        ent_reg = async_get_ent_reg(hass)
    if not dev_reg:
        dev_reg = async_get_dev_reg(hass)
    device = dev_reg.async_get(device_id)
    if not device:
        raise HomeAssistantError("Invalid Device ID provided")

    entry_id = next(entry_id for entry_id in device.config_entries)
    client = hass.data[DOMAIN][entry_id][DATA_CLIENT]
    node = async_get_node_from_device_id(hass, device_id, dev_reg)
    entity_id = ent_reg.async_get_entity_id(
        SENSOR_DOMAIN,
        DOMAIN,
        f"{client.driver.controller.home_id}.{node.node_id}.node_status",
    )
    if not entity_id:
        raise HomeAssistantError(
            "Node status sensor entity not found. Device may not be a zwave_js device"
        )

    return entity_id
예제 #3
0
async def test_get_trigger_capabilities_central_scene_value_notification(
    hass, client, wallmote_central_scene, integration
):
    """Test we get the expected capabilities from a value_notification.central_scene trigger."""
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
    capabilities = await device_trigger.async_get_trigger_capabilities(
        hass,
        {
            "platform": "device",
            "domain": DOMAIN,
            "type": "event.value_notification.central_scene",
            "device_id": device.id,
            "command_class": CommandClass.CENTRAL_SCENE.value,
            "property": "scene",
            "property_key": "001",
            "endpoint": 0,
            "subtype": "Endpoint 0 Scene 001",
        },
    )
    assert capabilities and "extra_fields" in capabilities

    assert voluptuous_serialize.convert(
        capabilities["extra_fields"], custom_serializer=cv.custom_serializer
    ) == [
        {
            "name": "value",
            "optional": True,
            "type": "select",
            "options": [(0, "KeyPressed"), (1, "KeyReleased"), (2, "KeyHeldDown")],
        },
    ]
예제 #4
0
async def test_get_trigger_capabilities_scene_activation_value_notification(
    hass, client, hank_binary_switch, integration
):
    """Test we get the expected capabilities from a value_notification.scene_activation trigger."""
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
    capabilities = await device_trigger.async_get_trigger_capabilities(
        hass,
        {
            "platform": "device",
            "domain": DOMAIN,
            "type": "event.value_notification.scene_activation",
            "device_id": device.id,
            "command_class": CommandClass.SCENE_ACTIVATION.value,
            "property": "sceneId",
            "property_key": None,
            "endpoint": 0,
            "subtype": "Endpoint 0",
        },
    )
    assert capabilities and "extra_fields" in capabilities

    assert voluptuous_serialize.convert(
        capabilities["extra_fields"], custom_serializer=cv.custom_serializer
    ) == [
        {
            "name": "value",
            "optional": True,
            "type": "integer",
            "valueMin": 1,
            "valueMax": 255,
        }
    ]
예제 #5
0
async def test_get_trigger_capabilities_entry_control_notification(
    hass, client, lock_schlage_be469, integration
):
    """Test we get the expected capabilities from a notification.entry_control trigger."""
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
    capabilities = await device_trigger.async_get_trigger_capabilities(
        hass,
        {
            "platform": "device",
            "domain": DOMAIN,
            "device_id": device.id,
            "type": "event.notification.entry_control",
            "command_class": CommandClass.ENTRY_CONTROL.value,
        },
    )
    assert capabilities and "extra_fields" in capabilities

    assert_lists_same(
        voluptuous_serialize.convert(
            capabilities["extra_fields"], custom_serializer=cv.custom_serializer
        ),
        [
            {"name": "event_type", "optional": True, "type": "string"},
            {"name": "data_type", "optional": True, "type": "string"},
        ],
    )
예제 #6
0
async def test_device_diagnostics(
    hass,
    client,
    multisensor_6,
    integration,
    hass_client,
    version_state,
):
    """Test the device level diagnostics data dump."""
    dev_reg = async_get_dev_reg(hass)
    device = dev_reg.async_get_device(
        {get_device_id(client.driver, multisensor_6)})
    assert device

    # Update a value and ensure it is reflected in the node state
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": multisensor_6.node_id,
            "args": {
                "commandClassName": "Multilevel Sensor",
                "commandClass": 49,
                "endpoint": 0,
                "property": PROPERTY_ULTRAVIOLET,
                "newValue": 1,
                "prevValue": 0,
                "propertyName": PROPERTY_ULTRAVIOLET,
            },
        },
    )
    multisensor_6.receive_event(event)

    diagnostics_data = await get_diagnostics_for_device(
        hass, hass_client, integration, device)
    assert diagnostics_data["versionInfo"] == {
        "driverVersion": version_state["driverVersion"],
        "serverVersion": version_state["serverVersion"],
        "minSchemaVersion": 0,
        "maxSchemaVersion": 0,
    }
    # Assert that we only have the entities that were discovered for this device
    # Entities that are created outside of discovery (e.g. node status sensor and
    # ping button) should not be in dump.
    assert len(diagnostics_data["entities"]) == len(
        list(
            async_discover_node_values(multisensor_6, device,
                                       {device.id: set()})))
    assert diagnostics_data["state"] == {
        **multisensor_6.data,
        "statistics": {
            "commandsDroppedRX": 0,
            "commandsDroppedTX": 0,
            "commandsRX": 0,
            "commandsTX": 0,
            "timeoutResponse": 0,
        },
    }
예제 #7
0
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry,
                            async_add_entities: AddEntitiesCallback) -> None:
    """Set up the Tibber sensor."""

    tibber_connection = hass.data[TIBBER_DOMAIN]

    entity_registry = async_get_entity_reg(hass)
    device_registry = async_get_dev_reg(hass)

    coordinator: TibberDataCoordinator | None = None
    entities: list[TibberSensor] = []
    for home in tibber_connection.get_homes(only_active=False):
        try:
            await home.update_info()
        except asyncio.TimeoutError as err:
            _LOGGER.error("Timeout connecting to Tibber home: %s ", err)
            raise PlatformNotReady() from err
        except aiohttp.ClientError as err:
            _LOGGER.error("Error connecting to Tibber home: %s ", err)
            raise PlatformNotReady() from err

        if home.has_active_subscription:
            entities.append(TibberSensorElPrice(home))
            if coordinator is None:
                coordinator = TibberDataCoordinator(hass, tibber_connection)
            for entity_description in SENSORS:
                entities.append(
                    TibberDataSensor(home, coordinator, entity_description))

        if home.has_real_time_consumption:
            await home.rt_subscribe(
                TibberRtDataCoordinator(async_add_entities, home,
                                        hass).async_set_updated_data)

        # migrate
        old_id = home.info["viewer"]["home"]["meteringPointData"][
            "consumptionEan"]
        if old_id is None:
            continue

        # migrate to new device ids
        old_entity_id = entity_registry.async_get_entity_id(
            "sensor", TIBBER_DOMAIN, old_id)
        if old_entity_id is not None:
            entity_registry.async_update_entity(old_entity_id,
                                                new_unique_id=home.home_id)

        # migrate to new device ids
        device_entry = device_registry.async_get_device({(TIBBER_DOMAIN,
                                                          old_id)})
        if device_entry and entry.entry_id in device_entry.config_entries:
            device_registry.async_update_device(device_entry.id,
                                                new_identifiers={
                                                    (TIBBER_DOMAIN,
                                                     home.home_id)
                                                })

    async_add_entities(entities, True)
예제 #8
0
async def test_failure_scenarios(hass, client, hank_binary_switch,
                                 integration):
    """Test failure scenarios."""
    with pytest.raises(HomeAssistantError):
        await async_attach_trigger(hass, {
            "type": "failed.test",
            "device_id": "invalid_device_id"
        }, None, {})

    with pytest.raises(HomeAssistantError):
        await async_attach_trigger(
            hass,
            {
                "type": "event.failed_type",
                "device_id": "invalid_device_id"
            },
            None,
            {},
        )

    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]

    with pytest.raises(HomeAssistantError):
        await async_attach_trigger(hass, {
            "type": "failed.test",
            "device_id": device.id
        }, None, {})

    with pytest.raises(HomeAssistantError):
        await async_attach_trigger(
            hass,
            {
                "type": "event.failed_type",
                "device_id": device.id
            },
            None,
            {},
        )

    with patch(
            "homeassistant.components.zwave_js.device_trigger.async_get_node_from_device_id",
            return_value=None,
    ), patch(
            "homeassistant.components.zwave_js.helpers.get_zwave_value_from_config",
            return_value=None,
    ):
        assert (await
                async_get_trigger_capabilities(hass, {
                    "type": "failed.test",
                    "device_id": "invalid_device_id"
                }) == {})

    with pytest.raises(HomeAssistantError):
        async_get_node_status_sensor_entity_id(hass, "invalid_device_id")
예제 #9
0
def async_get_node_from_device_id(
    hass: HomeAssistant, device_id: str, dev_reg: DeviceRegistry | None = None
) -> ZwaveNode:
    """
    Get node from a device ID.

    Raises ValueError if device is invalid or node can't be found.
    """
    if not dev_reg:
        dev_reg = async_get_dev_reg(hass)
    device_entry = dev_reg.async_get(device_id)

    if not device_entry:
        raise ValueError(f"Device ID {device_id} is not valid")

    # Use device config entry ID's to validate that this is a valid zwave_js device
    # and to get the client
    config_entry_ids = device_entry.config_entries
    config_entry_id = next(
        (
            config_entry_id
            for config_entry_id in config_entry_ids
            if cast(
                ConfigEntry,
                hass.config_entries.async_get_entry(config_entry_id),
            ).domain
            == DOMAIN
        ),
        None,
    )
    if config_entry_id is None or config_entry_id not in hass.data[DOMAIN]:
        raise ValueError(
            f"Device {device_id} is not from an existing zwave_js config entry"
        )

    client = hass.data[DOMAIN][config_entry_id][DATA_CLIENT]

    # Get node ID from device identifier, perform some validation, and then get the
    # node
    identifier = next(
        (
            get_home_and_node_id_from_device_id(identifier)
            for identifier in device_entry.identifiers
            if identifier[0] == DOMAIN
        ),
        None,
    )

    node_id = int(identifier[1]) if identifier is not None else None

    if node_id is None or node_id not in client.driver.controller.nodes:
        raise ValueError(f"Node for device {device_id} can't be found")

    return client.driver.controller.nodes[node_id]
예제 #10
0
async def test_get_trigger_capabilities_node_status(
    hass, client, lock_schlage_be469, integration
):
    """Test we get the expected capabilities from a node_status trigger."""
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
    ent_reg = async_get_ent_reg(hass)
    entity_id = async_get_node_status_sensor_entity_id(
        hass, device.id, ent_reg, dev_reg
    )
    ent_reg.async_update_entity(entity_id, **{"disabled_by": None})
    await hass.config_entries.async_reload(integration.entry_id)
    await hass.async_block_till_done()

    capabilities = await device_trigger.async_get_trigger_capabilities(
        hass,
        {
            "platform": "device",
            "domain": DOMAIN,
            "device_id": device.id,
            "entity_id": entity_id,
            "type": "state.node_status",
        },
    )
    assert capabilities and "extra_fields" in capabilities

    assert voluptuous_serialize.convert(
        capabilities["extra_fields"], custom_serializer=cv.custom_serializer
    ) == [
        {
            "name": "from",
            "optional": True,
            "options": [
                ("asleep", "asleep"),
                ("awake", "awake"),
                ("dead", "dead"),
                ("alive", "alive"),
            ],
            "type": "select",
        },
        {
            "name": "to",
            "optional": True,
            "options": [
                ("asleep", "asleep"),
                ("awake", "awake"),
                ("dead", "dead"),
                ("alive", "alive"),
            ],
            "type": "select",
        },
        {"name": "for", "optional": True, "type": "positive_time_period_dict"},
    ]
예제 #11
0
async def test_get_value_updated_value_triggers(hass, client,
                                                lock_schlage_be469,
                                                integration):
    """Test we get the zwave_js.value_updated.value trigger from a zwave_js device."""
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
    expected_trigger = {
        "platform": "device",
        "domain": DOMAIN,
        "type": "zwave_js.value_updated.value",
        "device_id": device.id,
    }
    triggers = await async_get_device_automations(hass, "trigger", device.id)
    assert expected_trigger in triggers
예제 #12
0
async def test_get_notification_notification_triggers(hass, client,
                                                      lock_schlage_be469,
                                                      integration):
    """Test we get the expected triggers from a zwave_js device with the Notification CC."""
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
    expected_trigger = {
        "platform": "device",
        "domain": DOMAIN,
        "type": "event.notification.notification",
        "device_id": device.id,
        "command_class": CommandClass.NOTIFICATION,
    }
    triggers = await async_get_device_automations(hass, "trigger", device.id)
    assert expected_trigger in triggers
예제 #13
0
async def test_get_trigger_capabilities_value_updated_value(
    hass, client, lock_schlage_be469, integration
):
    """Test we get the expected capabilities from a zwave_js.value_updated.value trigger."""
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
    capabilities = await device_trigger.async_get_trigger_capabilities(
        hass,
        {
            "platform": "device",
            "domain": DOMAIN,
            "device_id": device.id,
            "type": "zwave_js.value_updated.value",
            "command_class": CommandClass.DOOR_LOCK.value,
            "property": "latchStatus",
            "property_key": None,
            "endpoint": None,
        },
    )
    assert capabilities and "extra_fields" in capabilities

    assert voluptuous_serialize.convert(
        capabilities["extra_fields"], custom_serializer=cv.custom_serializer
    ) == [
        {
            "name": "command_class",
            "required": True,
            "type": "select",
            "options": [
                (133, "Association"),
                (128, "Battery"),
                (98, "Door Lock"),
                (122, "Firmware Update Meta Data"),
                (114, "Manufacturer Specific"),
                (113, "Notification"),
                (152, "Security"),
                (99, "User Code"),
                (134, "Version"),
            ],
        },
        {"name": "property", "required": True, "type": "string"},
        {"name": "property_key", "optional": True, "type": "string"},
        {"name": "endpoint", "optional": True, "type": "string"},
        {"name": "from", "optional": True, "type": "string"},
        {"name": "to", "optional": True, "type": "string"},
    ]
예제 #14
0
async def test_get_central_scene_value_notification_triggers(
        hass, client, wallmote_central_scene, integration):
    """Test we get the expected triggers from a zwave_js device with the Central Scene CC."""
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
    expected_trigger = {
        "platform": "device",
        "domain": DOMAIN,
        "type": "event.value_notification.central_scene",
        "device_id": device.id,
        "command_class": CommandClass.CENTRAL_SCENE,
        "property": "scene",
        "property_key": "001",
        "endpoint": 0,
        "subtype": "Endpoint 0 Scene 001",
    }
    triggers = await async_get_device_automations(hass, "trigger", device.id)
    assert expected_trigger in triggers
예제 #15
0
async def test_get_scene_activation_value_notification_triggers(
        hass, client, hank_binary_switch, integration):
    """Test we get the expected triggers from a zwave_js device with the SceneActivation CC."""
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
    expected_trigger = {
        "platform": "device",
        "domain": DOMAIN,
        "type": "event.value_notification.scene_activation",
        "device_id": device.id,
        "command_class": CommandClass.SCENE_ACTIVATION.value,
        "property": "sceneId",
        "property_key": None,
        "endpoint": 0,
        "subtype": "Endpoint 0",
    }
    triggers = await async_get_device_automations(hass, "trigger", device.id)
    assert expected_trigger in triggers
예제 #16
0
async def test_get_value_updated_config_parameter_triggers(
        hass, client, lock_schlage_be469, integration):
    """Test we get the zwave_js.value_updated.config_parameter trigger from a zwave_js device."""
    node = lock_schlage_be469
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
    expected_trigger = {
        "platform": "device",
        "domain": DOMAIN,
        "type": "zwave_js.value_updated.config_parameter",
        "device_id": device.id,
        "property": 3,
        "property_key": None,
        "endpoint": 0,
        "command_class": CommandClass.CONFIGURATION.value,
        "subtype": f"{node.node_id}-112-0-3 (Beeper)",
    }
    triggers = await async_get_device_automations(hass, "trigger", device.id)
    assert expected_trigger in triggers
예제 #17
0
async def test_get_basic_value_notification_triggers(hass, client,
                                                     ge_in_wall_dimmer_switch,
                                                     integration):
    """Test we get the expected triggers from a zwave_js device with the Basic CC."""
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
    expected_trigger = {
        "platform": "device",
        "domain": DOMAIN,
        "type": "event.value_notification.basic",
        "device_id": device.id,
        "command_class": CommandClass.BASIC,
        "property": "event",
        "property_key": None,
        "endpoint": 0,
        "subtype": "Endpoint 0",
    }
    triggers = await async_get_device_automations(hass, "trigger", device.id)
    assert expected_trigger in triggers
예제 #18
0
async def test_get_node_status_triggers(hass, client, lock_schlage_be469,
                                        integration):
    """Test we get the expected triggers from a device with node status sensor enabled."""
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
    ent_reg = async_get_ent_reg(hass)
    entity_id = async_get_node_status_sensor_entity_id(hass, device.id,
                                                       ent_reg, dev_reg)
    ent_reg.async_update_entity(entity_id, **{"disabled_by": None})
    await hass.config_entries.async_reload(integration.entry_id)
    await hass.async_block_till_done()

    expected_trigger = {
        "platform": "device",
        "domain": DOMAIN,
        "type": "state.node_status",
        "device_id": device.id,
        "entity_id": entity_id,
    }
    triggers = await async_get_device_automations(hass, "trigger", device.id)
    assert expected_trigger in triggers
예제 #19
0
async def test_get_trigger_capabilities_value_updated_config_parameter_range(
    hass, client, lock_schlage_be469, integration
):
    """Test we get the expected capabilities from a range zwave_js.value_updated.config_parameter trigger."""
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
    capabilities = await device_trigger.async_get_trigger_capabilities(
        hass,
        {
            "platform": "device",
            "domain": DOMAIN,
            "device_id": device.id,
            "type": "zwave_js.value_updated.config_parameter",
            "property": 6,
            "property_key": None,
            "endpoint": 0,
            "command_class": CommandClass.CONFIGURATION.value,
            "subtype": "6 (User Slot Status)",
        },
    )
    assert capabilities and "extra_fields" in capabilities

    assert voluptuous_serialize.convert(
        capabilities["extra_fields"], custom_serializer=cv.custom_serializer
    ) == [
        {
            "name": "from",
            "optional": True,
            "valueMin": 0,
            "valueMax": 255,
            "type": "integer",
        },
        {
            "name": "to",
            "optional": True,
            "valueMin": 0,
            "valueMax": 255,
            "type": "integer",
        },
    ]
예제 #20
0
async def test_get_trigger_capabilities_value_updated_config_parameter_enumerated(
        hass, client, lock_schlage_be469, integration):
    """Test we get the expected capabilities from an enumerated zwave_js.value_updated.config_parameter trigger."""
    node = lock_schlage_be469
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
    capabilities = await device_trigger.async_get_trigger_capabilities(
        hass,
        {
            "platform": "device",
            "domain": DOMAIN,
            "device_id": device.id,
            "type": "zwave_js.value_updated.config_parameter",
            "property": 3,
            "property_key": None,
            "endpoint": 0,
            "command_class": CommandClass.CONFIGURATION.value,
            "subtype": f"{node.node_id}-112-0-3 (Beeper)",
        },
    )
    assert capabilities and "extra_fields" in capabilities

    assert voluptuous_serialize.convert(
        capabilities["extra_fields"],
        custom_serializer=cv.custom_serializer) == [
            {
                "name": "from",
                "optional": True,
                "options": [(0, "Disable Beeper"), (255, "Enable Beeper")],
                "type": "select",
            },
            {
                "name": "to",
                "optional": True,
                "options": [(0, "Disable Beeper"), (255, "Enable Beeper")],
                "type": "select",
            },
        ]
예제 #21
0
async def test_set_value(hass, client, climate_danfoss_lc_13, integration):
    """Test set_value service."""
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]

    await hass.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 bitmask as value and non bool as bool
    await hass.services.async_call(
        DOMAIN,
        SERVICE_SET_VALUE,
        {
            ATTR_ENTITY_ID: CLIMATE_DANFOSS_LC13_ENTITY,
            ATTR_COMMAND_CLASS: 117,
            ATTR_PROPERTY: "local",
            ATTR_VALUE: "0x2",
            ATTR_WAIT_FOR_RESULT: 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"] == 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.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 hass.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 hass.services.async_call(
            DOMAIN,
            SERVICE_SET_VALUE,
            {
                ATTR_COMMAND_CLASS: 117,
                ATTR_PROPERTY: "local",
                ATTR_VALUE: 2,
                ATTR_WAIT_FOR_RESULT: True,
            },
            blocking=True,
        )
예제 #22
0
async def test_set_config_parameter(hass, client, multisensor_6, integration):
    """Test the set_config_parameter service."""
    dev_reg = async_get_dev_reg(hass)
    ent_reg = async_get_ent_reg(hass)
    entity_entry = ent_reg.async_get(AIR_TEMPERATURE_SENSOR)

    # Test setting config parameter by property and property_key
    await hass.services.async_call(
        DOMAIN,
        SERVICE_SET_CONFIG_PARAMETER,
        {
            ATTR_ENTITY_ID: AIR_TEMPERATURE_SENSOR,
            ATTR_CONFIG_PARAMETER: 102,
            ATTR_CONFIG_PARAMETER_BITMASK: 1,
            ATTR_CONFIG_VALUE: 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"] == {
        "commandClassName": "Configuration",
        "commandClass": 112,
        "endpoint": 0,
        "property": 102,
        "propertyName": "Group 2: Send battery reports",
        "propertyKey": 1,
        "metadata": {
            "type": "number",
            "readable": True,
            "writeable": True,
            "valueSize": 4,
            "min": 0,
            "max": 1,
            "default": 1,
            "format": 0,
            "allowManualEntry": True,
            "label": "Group 2: Send battery reports",
            "description": "Include battery information in periodic reports to Group 2",
            "isFromConfig": True,
        },
        "value": 0,
    }
    assert args["value"] == 1

    client.async_send_command_no_wait.reset_mock()

    # Test setting config parameter value in hex
    await hass.services.async_call(
        DOMAIN,
        SERVICE_SET_CONFIG_PARAMETER,
        {
            ATTR_ENTITY_ID: AIR_TEMPERATURE_SENSOR,
            ATTR_CONFIG_PARAMETER: 102,
            ATTR_CONFIG_PARAMETER_BITMASK: 1,
            ATTR_CONFIG_VALUE: "0x1",
        },
        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"] == {
        "commandClassName": "Configuration",
        "commandClass": 112,
        "endpoint": 0,
        "property": 102,
        "propertyName": "Group 2: Send battery reports",
        "propertyKey": 1,
        "metadata": {
            "type": "number",
            "readable": True,
            "writeable": True,
            "valueSize": 4,
            "min": 0,
            "max": 1,
            "default": 1,
            "format": 0,
            "allowManualEntry": True,
            "label": "Group 2: Send battery reports",
            "description": "Include battery information in periodic reports to Group 2",
            "isFromConfig": True,
        },
        "value": 0,
    }
    assert args["value"] == 1

    client.async_send_command_no_wait.reset_mock()

    # Test setting parameter by property name
    await hass.services.async_call(
        DOMAIN,
        SERVICE_SET_CONFIG_PARAMETER,
        {
            ATTR_ENTITY_ID: AIR_TEMPERATURE_SENSOR,
            ATTR_CONFIG_PARAMETER: "Group 2: Send battery reports",
            ATTR_CONFIG_VALUE: 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"] == {
        "commandClassName": "Configuration",
        "commandClass": 112,
        "endpoint": 0,
        "property": 102,
        "propertyName": "Group 2: Send battery reports",
        "propertyKey": 1,
        "metadata": {
            "type": "number",
            "readable": True,
            "writeable": True,
            "valueSize": 4,
            "min": 0,
            "max": 1,
            "default": 1,
            "format": 0,
            "allowManualEntry": True,
            "label": "Group 2: Send battery reports",
            "description": "Include battery information in periodic reports to Group 2",
            "isFromConfig": True,
        },
        "value": 0,
    }
    assert args["value"] == 1

    client.async_send_command_no_wait.reset_mock()

    # Test setting parameter by property name and state label
    await hass.services.async_call(
        DOMAIN,
        SERVICE_SET_CONFIG_PARAMETER,
        {
            ATTR_DEVICE_ID: entity_entry.device_id,
            ATTR_CONFIG_PARAMETER: "Temperature Threshold (Unit)",
            ATTR_CONFIG_VALUE: "Fahrenheit",
        },
        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"] == {
        "commandClassName": "Configuration",
        "commandClass": 112,
        "endpoint": 0,
        "property": 41,
        "propertyName": "Temperature Threshold (Unit)",
        "propertyKey": 15,
        "metadata": {
            "type": "number",
            "readable": True,
            "writeable": True,
            "valueSize": 3,
            "min": 1,
            "max": 2,
            "default": 1,
            "format": 0,
            "allowManualEntry": False,
            "states": {"1": "Celsius", "2": "Fahrenheit"},
            "label": "Temperature Threshold (Unit)",
            "isFromConfig": True,
        },
        "value": 0,
    }
    assert args["value"] == 2

    client.async_send_command_no_wait.reset_mock()

    # Test setting parameter by property and bitmask
    await hass.services.async_call(
        DOMAIN,
        SERVICE_SET_CONFIG_PARAMETER,
        {
            ATTR_ENTITY_ID: AIR_TEMPERATURE_SENSOR,
            ATTR_CONFIG_PARAMETER: 102,
            ATTR_CONFIG_PARAMETER_BITMASK: "0x01",
            ATTR_CONFIG_VALUE: 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"] == {
        "commandClassName": "Configuration",
        "commandClass": 112,
        "endpoint": 0,
        "property": 102,
        "propertyName": "Group 2: Send battery reports",
        "propertyKey": 1,
        "metadata": {
            "type": "number",
            "readable": True,
            "writeable": True,
            "valueSize": 4,
            "min": 0,
            "max": 1,
            "default": 1,
            "format": 0,
            "allowManualEntry": True,
            "label": "Group 2: Send battery reports",
            "description": "Include battery information in periodic reports to Group 2",
            "isFromConfig": True,
        },
        "value": 0,
    }
    assert args["value"] == 1

    # Test that an invalid entity ID raises a MultipleInvalid
    with pytest.raises(vol.MultipleInvalid):
        await hass.services.async_call(
            DOMAIN,
            SERVICE_SET_CONFIG_PARAMETER,
            {
                ATTR_ENTITY_ID: "sensor.fake_entity",
                ATTR_CONFIG_PARAMETER: "Temperature Threshold (Unit)",
                ATTR_CONFIG_VALUE: "Fahrenheit",
            },
            blocking=True,
        )

    # Test that an invalid device ID raises a MultipleInvalid
    with pytest.raises(vol.MultipleInvalid):
        await hass.services.async_call(
            DOMAIN,
            SERVICE_SET_CONFIG_PARAMETER,
            {
                ATTR_DEVICE_ID: "fake_device_id",
                ATTR_CONFIG_PARAMETER: "Temperature Threshold (Unit)",
                ATTR_CONFIG_VALUE: "Fahrenheit",
            },
            blocking=True,
        )

    # Test that we can't include a bitmask value if parameter is a string
    with pytest.raises(vol.Invalid):
        await hass.services.async_call(
            DOMAIN,
            SERVICE_SET_CONFIG_PARAMETER,
            {
                ATTR_DEVICE_ID: entity_entry.device_id,
                ATTR_CONFIG_PARAMETER: "Temperature Threshold (Unit)",
                ATTR_CONFIG_PARAMETER_BITMASK: 1,
                ATTR_CONFIG_VALUE: "Fahrenheit",
            },
            blocking=True,
        )

    non_zwave_js_config_entry = MockConfigEntry(entry_id="fake_entry_id")
    non_zwave_js_config_entry.add_to_hass(hass)
    non_zwave_js_device = dev_reg.async_get_or_create(
        config_entry_id=non_zwave_js_config_entry.entry_id,
        identifiers={("test", "test")},
    )

    # Test that a non Z-Wave JS device raises a MultipleInvalid
    with pytest.raises(vol.MultipleInvalid):
        await hass.services.async_call(
            DOMAIN,
            SERVICE_SET_CONFIG_PARAMETER,
            {
                ATTR_DEVICE_ID: non_zwave_js_device.id,
                ATTR_CONFIG_PARAMETER: "Temperature Threshold (Unit)",
                ATTR_CONFIG_VALUE: "Fahrenheit",
            },
            blocking=True,
        )

    zwave_js_device_with_invalid_node_id = dev_reg.async_get_or_create(
        config_entry_id=integration.entry_id, identifiers={(DOMAIN, "500-500")}
    )

    # Test that a Z-Wave JS device with an invalid node ID raises a MultipleInvalid
    with pytest.raises(vol.MultipleInvalid):
        await hass.services.async_call(
            DOMAIN,
            SERVICE_SET_CONFIG_PARAMETER,
            {
                ATTR_DEVICE_ID: zwave_js_device_with_invalid_node_id.id,
                ATTR_CONFIG_PARAMETER: "Temperature Threshold (Unit)",
                ATTR_CONFIG_VALUE: "Fahrenheit",
            },
            blocking=True,
        )

    non_zwave_js_entity = ent_reg.async_get_or_create(
        "test",
        "sensor",
        "test_sensor",
        suggested_object_id="test_sensor",
        config_entry=non_zwave_js_config_entry,
    )

    # Test that a non Z-Wave JS entity raises a MultipleInvalid
    with pytest.raises(vol.MultipleInvalid):
        await hass.services.async_call(
            DOMAIN,
            SERVICE_SET_CONFIG_PARAMETER,
            {
                ATTR_ENTITY_ID: non_zwave_js_entity.entity_id,
                ATTR_CONFIG_PARAMETER: "Temperature Threshold (Unit)",
                ATTR_CONFIG_VALUE: "Fahrenheit",
            },
            blocking=True,
        )

    # 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 hass.services.async_call(
        DOMAIN,
        SERVICE_SET_CONFIG_PARAMETER,
        {
            ATTR_ENTITY_ID: AIR_TEMPERATURE_SENSOR,
            ATTR_CONFIG_PARAMETER: 102,
            ATTR_CONFIG_PARAMETER_BITMASK: 1,
            ATTR_CONFIG_VALUE: 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"] == {
        "commandClassName": "Configuration",
        "commandClass": 112,
        "endpoint": 0,
        "property": 102,
        "propertyName": "Group 2: Send battery reports",
        "propertyKey": 1,
        "metadata": {
            "type": "number",
            "readable": True,
            "writeable": True,
            "valueSize": 4,
            "min": 0,
            "max": 1,
            "default": 1,
            "format": 0,
            "allowManualEntry": True,
            "label": "Group 2: Send battery reports",
            "description": "Include battery information in periodic reports to Group 2",
            "isFromConfig": True,
        },
        "value": 0,
    }
    assert args["value"] == 1

    client.async_send_command.reset_mock()
예제 #23
0
async def test_bulk_set_config_parameters(hass, client, multisensor_6, integration):
    """Test the bulk_set_partial_config_parameters service."""
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
    # Test setting config parameter by property and property_key
    await hass.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 hass.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()

    # Test using hex values for config parameter values
    await hass.services.async_call(
        DOMAIN,
        SERVICE_BULK_SET_PARTIAL_CONFIG_PARAMETERS,
        {
            ATTR_ENTITY_ID: AIR_TEMPERATURE_SENSOR,
            ATTR_CONFIG_PARAMETER: 102,
            ATTR_CONFIG_VALUE: {
                1: "0x1",
                16: "0x1",
                32: "0x1",
                64: "0x1",
                128: "0x1",
            },
        },
        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 hass.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 hass.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()
예제 #24
0
async def test_if_value_updated_value_fires(
    hass, client, lock_schlage_be469, integration, calls
):
    """Test for zwave_js.value_updated.value trigger firing."""
    node: Node = lock_schlage_be469
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]

    assert await async_setup_component(
        hass,
        automation.DOMAIN,
        {
            automation.DOMAIN: [
                {
                    "trigger": {
                        "platform": "device",
                        "domain": DOMAIN,
                        "device_id": device.id,
                        "type": "zwave_js.value_updated.value",
                        "command_class": CommandClass.DOOR_LOCK.value,
                        "property": "latchStatus",
                        "property_key": None,
                        "endpoint": None,
                        "from": "open",
                    },
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some": (
                                "zwave_js.value_updated.value - "
                                "{{ trigger.platform}} - "
                                "{{ trigger.previous_value }}"
                            )
                        },
                    },
                },
            ]
        },
    )

    # Publish fake value update that shouldn't trigger
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": node.node_id,
            "args": {
                "commandClassName": "Door Lock",
                "commandClass": 98,
                "endpoint": 0,
                "property": "insideHandlesCanOpenDoor",
                "newValue": [True, False, False, False],
                "prevValue": [False, False, False, False],
                "propertyName": "insideHandlesCanOpenDoor",
            },
        },
    )
    node.receive_event(event)
    await hass.async_block_till_done()
    assert len(calls) == 0

    # Publish fake value update that should trigger
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": node.node_id,
            "args": {
                "commandClassName": "Door Lock",
                "commandClass": 98,
                "endpoint": 0,
                "property": "latchStatus",
                "newValue": "closed",
                "prevValue": "open",
                "propertyName": "latchStatus",
            },
        },
    )
    node.receive_event(event)
    await hass.async_block_till_done()
    assert len(calls) == 1
    assert (
        calls[0].data["some"]
        == "zwave_js.value_updated.value - zwave_js.value_updated - open"
    )
예제 #25
0
async def test_if_scene_activation_value_notification_fires(
    hass, client, hank_binary_switch, integration, calls
):
    """Test for event.value_notification.scene_activation trigger firing."""
    node: Node = hank_binary_switch
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]

    assert await async_setup_component(
        hass,
        automation.DOMAIN,
        {
            automation.DOMAIN: [
                # value
                {
                    "trigger": {
                        "platform": "device",
                        "domain": DOMAIN,
                        "device_id": device.id,
                        "type": "event.value_notification.scene_activation",
                        "command_class": CommandClass.SCENE_ACTIVATION.value,
                        "property": "sceneId",
                        "property_key": None,
                        "endpoint": 0,
                        "subtype": "Endpoint 0",
                        "value": 1,
                    },
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some": (
                                "event.value_notification.scene_activation - "
                                "{{ trigger.platform}} - "
                                "{{ trigger.event.event_type}} - "
                                "{{ trigger.event.data.command_class }}"
                            )
                        },
                    },
                },
                # No value
                {
                    "trigger": {
                        "platform": "device",
                        "domain": DOMAIN,
                        "device_id": device.id,
                        "type": "event.value_notification.scene_activation",
                        "command_class": CommandClass.SCENE_ACTIVATION.value,
                        "property": "sceneId",
                        "property_key": None,
                        "endpoint": 0,
                        "subtype": "Endpoint 0",
                    },
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some": (
                                "event.value_notification.scene_activation2 - "
                                "{{ trigger.platform}} - "
                                "{{ trigger.event.event_type}} - "
                                "{{ trigger.event.data.command_class }}"
                            )
                        },
                    },
                },
            ]
        },
    )

    # Publish fake Scene Activation CC value notification
    event = Event(
        type="value notification",
        data={
            "source": "node",
            "event": "value notification",
            "nodeId": node.node_id,
            "args": {
                "commandClassName": "Scene Activation",
                "commandClass": 43,
                "endpoint": 0,
                "property": "sceneId",
                "propertyName": "sceneId",
                "value": 1,
                "metadata": {
                    "type": "number",
                    "readable": True,
                    "writeable": True,
                    "min": 1,
                    "max": 255,
                    "label": "Scene ID",
                },
                "ccVersion": 1,
            },
        },
    )
    node.receive_event(event)
    await hass.async_block_till_done()
    assert len(calls) == 2
    assert calls[0].data[
        "some"
    ] == "event.value_notification.scene_activation - device - zwave_js_value_notification - {}".format(
        CommandClass.SCENE_ACTIVATION
    )
    assert calls[1].data[
        "some"
    ] == "event.value_notification.scene_activation2 - device - zwave_js_value_notification - {}".format(
        CommandClass.SCENE_ACTIVATION
    )
예제 #26
0
async def test_failure_scenarios(hass, client, hank_binary_switch, integration):
    """Test failure scenarios."""
    with pytest.raises(HomeAssistantError):
        await device_trigger.async_attach_trigger(
            hass, {"type": "failed.test", "device_id": "invalid_device_id"}, None, {}
        )

    with pytest.raises(HomeAssistantError):
        await device_trigger.async_attach_trigger(
            hass,
            {"type": "event.failed_type", "device_id": "invalid_device_id"},
            None,
            {},
        )

    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]

    with pytest.raises(HomeAssistantError):
        await device_trigger.async_attach_trigger(
            hass, {"type": "failed.test", "device_id": device.id}, None, {}
        )

    with pytest.raises(HomeAssistantError):
        await device_trigger.async_attach_trigger(
            hass,
            {"type": "event.failed_type", "device_id": device.id},
            None,
            {},
        )

    with pytest.raises(HomeAssistantError):
        await device_trigger.async_attach_trigger(
            hass,
            {"type": "state.failed_type", "device_id": device.id},
            None,
            {},
        )

    with patch(
        "homeassistant.components.zwave_js.device_trigger.async_get_node_from_device_id",
        return_value=None,
    ), patch(
        "homeassistant.components.zwave_js.helpers.get_zwave_value_from_config",
        return_value=None,
    ):
        assert (
            await device_trigger.async_get_trigger_capabilities(
                hass, {"type": "failed.test", "device_id": "invalid_device_id"}
            )
            == {}
        )

    with pytest.raises(HomeAssistantError):
        async_get_node_status_sensor_entity_id(hass, "invalid_device_id")

    INVALID_CONFIG = {
        "platform": "device",
        "domain": DOMAIN,
        "device_id": device.id,
        "type": "zwave_js.value_updated.value",
        "command_class": CommandClass.DOOR_LOCK.value,
        "property": 9999,
        "property_key": 9999,
        "endpoint": 9999,
    }

    # Test that invalid config raises exception
    with pytest.raises(InvalidDeviceAutomationConfig):
        await device_trigger.async_validate_trigger_config(hass, INVALID_CONFIG)

    # Unload entry so we can verify that validation will pass on an invalid config
    # since we return early
    await hass.config_entries.async_unload(integration.entry_id)
    assert (
        await device_trigger.async_validate_trigger_config(hass, INVALID_CONFIG)
        == INVALID_CONFIG
    )

    # Test invalid device ID fails validation
    with pytest.raises(InvalidDeviceAutomationConfig):
        await device_trigger.async_validate_trigger_config(
            hass,
            {
                "platform": "device",
                "domain": DOMAIN,
                "device_id": "invalid_device_id",
                "type": "zwave_js.value_updated.value",
                "command_class": CommandClass.DOOR_LOCK.value,
                "property": 9999,
                "property_key": 9999,
                "endpoint": 9999,
            },
        )
예제 #27
0
async def test_if_central_scene_value_notification_fires(
    hass, client, wallmote_central_scene, integration, calls
):
    """Test for event.value_notification.central_scene trigger firing."""
    node: Node = wallmote_central_scene
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]

    assert await async_setup_component(
        hass,
        automation.DOMAIN,
        {
            automation.DOMAIN: [
                # value
                {
                    "trigger": {
                        "platform": "device",
                        "domain": DOMAIN,
                        "device_id": device.id,
                        "type": "event.value_notification.central_scene",
                        "command_class": CommandClass.CENTRAL_SCENE.value,
                        "property": "scene",
                        "property_key": "001",
                        "endpoint": 0,
                        "subtype": "Endpoint 0 Scene 001",
                        "value": 0,
                    },
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some": (
                                "event.value_notification.central_scene - "
                                "{{ trigger.platform}} - "
                                "{{ trigger.event.event_type}} - "
                                "{{ trigger.event.data.command_class }}"
                            )
                        },
                    },
                },
                # no value
                {
                    "trigger": {
                        "platform": "device",
                        "domain": DOMAIN,
                        "device_id": device.id,
                        "type": "event.value_notification.central_scene",
                        "command_class": CommandClass.CENTRAL_SCENE.value,
                        "property": "scene",
                        "property_key": "001",
                        "endpoint": 0,
                        "subtype": "Endpoint 0 Scene 001",
                    },
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some": (
                                "event.value_notification.central_scene2 - "
                                "{{ trigger.platform}} - "
                                "{{ trigger.event.event_type}} - "
                                "{{ trigger.event.data.command_class }}"
                            )
                        },
                    },
                },
            ]
        },
    )

    # Publish fake Central Scene CC value notification
    event = Event(
        type="value notification",
        data={
            "source": "node",
            "event": "value notification",
            "nodeId": node.node_id,
            "args": {
                "commandClassName": "Central Scene",
                "commandClass": 91,
                "endpoint": 0,
                "property": "scene",
                "propertyName": "scene",
                "propertyKey": "001",
                "propertyKey": "001",
                "value": 0,
                "metadata": {
                    "type": "number",
                    "readable": True,
                    "writeable": False,
                    "min": 0,
                    "max": 255,
                    "label": "Scene 004",
                    "states": {
                        "0": "KeyPressed",
                        "1": "KeyReleased",
                        "2": "KeyHeldDown",
                    },
                },
                "ccVersion": 1,
            },
        },
    )
    node.receive_event(event)
    await hass.async_block_till_done()
    assert len(calls) == 2
    assert calls[0].data[
        "some"
    ] == "event.value_notification.central_scene - device - zwave_js_value_notification - {}".format(
        CommandClass.CENTRAL_SCENE
    )
    assert calls[1].data[
        "some"
    ] == "event.value_notification.central_scene2 - device - zwave_js_value_notification - {}".format(
        CommandClass.CENTRAL_SCENE
    )
예제 #28
0
async def test_if_notification_notification_fires(
    hass, client, lock_schlage_be469, integration, calls
):
    """Test for event.notification.notification trigger firing."""
    node: Node = lock_schlage_be469
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]

    assert await async_setup_component(
        hass,
        automation.DOMAIN,
        {
            automation.DOMAIN: [
                # event, type, label
                {
                    "trigger": {
                        "platform": "device",
                        "domain": DOMAIN,
                        "device_id": device.id,
                        "type": "event.notification.notification",
                        "command_class": CommandClass.NOTIFICATION.value,
                        "type.": 6,
                        "event": 5,
                        "label": "Access Control",
                    },
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some": (
                                "event.notification.notification - "
                                "{{ trigger.platform}} - "
                                "{{ trigger.event.event_type}} - "
                                "{{ trigger.event.data.command_class }}"
                            )
                        },
                    },
                },
                # no type, event, label
                {
                    "trigger": {
                        "platform": "device",
                        "domain": DOMAIN,
                        "device_id": device.id,
                        "type": "event.notification.notification",
                        "command_class": CommandClass.NOTIFICATION.value,
                    },
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some": (
                                "event.notification.notification2 - "
                                "{{ trigger.platform}} - "
                                "{{ trigger.event.event_type}} - "
                                "{{ trigger.event.data.command_class }}"
                            )
                        },
                    },
                },
            ]
        },
    )

    # Publish fake Notification CC notification
    event = Event(
        type="notification",
        data={
            "source": "node",
            "event": "notification",
            "nodeId": node.node_id,
            "ccId": 113,
            "args": {
                "type": 6,
                "event": 5,
                "label": "Access Control",
                "eventLabel": "Keypad lock operation",
                "parameters": {"userId": 1},
            },
        },
    )
    node.receive_event(event)
    await hass.async_block_till_done()
    assert len(calls) == 2
    assert calls[0].data[
        "some"
    ] == "event.notification.notification - device - zwave_js_notification - {}".format(
        CommandClass.NOTIFICATION
    )
    assert calls[1].data[
        "some"
    ] == "event.notification.notification2 - device - zwave_js_notification - {}".format(
        CommandClass.NOTIFICATION
    )
예제 #29
0
async def test_if_entry_control_notification_fires(
    hass, client, lock_schlage_be469, integration, calls
):
    """Test for notification.entry_control trigger firing."""
    node: Node = lock_schlage_be469
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]

    assert await async_setup_component(
        hass,
        automation.DOMAIN,
        {
            automation.DOMAIN: [
                # event_type and data_type
                {
                    "trigger": {
                        "platform": "device",
                        "domain": DOMAIN,
                        "device_id": device.id,
                        "type": "event.notification.entry_control",
                        "command_class": CommandClass.ENTRY_CONTROL.value,
                        "event_type": 5,
                        "data_type": 2,
                    },
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some": (
                                "event.notification.notification - "
                                "{{ trigger.platform}} - "
                                "{{ trigger.event.event_type}} - "
                                "{{ trigger.event.data.command_class }}"
                            )
                        },
                    },
                },
                # no event_type and data_type
                {
                    "trigger": {
                        "platform": "device",
                        "domain": DOMAIN,
                        "device_id": device.id,
                        "type": "event.notification.entry_control",
                        "command_class": CommandClass.ENTRY_CONTROL.value,
                    },
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some": (
                                "event.notification.notification2 - "
                                "{{ trigger.platform}} - "
                                "{{ trigger.event.event_type}} - "
                                "{{ trigger.event.data.command_class }}"
                            )
                        },
                    },
                },
            ]
        },
    )

    # Publish fake Entry Control CC notification
    event = Event(
        type="notification",
        data={
            "source": "node",
            "event": "notification",
            "nodeId": node.node_id,
            "ccId": 111,
            "args": {"eventType": 5, "dataType": 2, "eventData": "555"},
        },
    )
    node.receive_event(event)
    await hass.async_block_till_done()
    assert len(calls) == 2
    assert calls[0].data[
        "some"
    ] == "event.notification.notification - device - zwave_js_notification - {}".format(
        CommandClass.ENTRY_CONTROL
    )
    assert calls[1].data[
        "some"
    ] == "event.notification.notification2 - device - zwave_js_notification - {}".format(
        CommandClass.ENTRY_CONTROL
    )
예제 #30
0
async def test_if_node_status_change_fires(
    hass, client, lock_schlage_be469, integration, calls
):
    """Test for node_status trigger firing."""
    node: Node = lock_schlage_be469
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]
    ent_reg = async_get_ent_reg(hass)
    entity_id = async_get_node_status_sensor_entity_id(
        hass, device.id, ent_reg, dev_reg
    )
    ent_reg.async_update_entity(entity_id, **{"disabled_by": None})
    await hass.config_entries.async_reload(integration.entry_id)
    await hass.async_block_till_done()

    assert await async_setup_component(
        hass,
        automation.DOMAIN,
        {
            automation.DOMAIN: [
                # from
                {
                    "trigger": {
                        "platform": "device",
                        "domain": DOMAIN,
                        "device_id": device.id,
                        "entity_id": entity_id,
                        "type": "state.node_status",
                        "from": "alive",
                    },
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some": (
                                "state.node_status - "
                                "{{ trigger.platform}} - "
                                "{{ trigger.from_state.state }}"
                            )
                        },
                    },
                },
                # no from or to
                {
                    "trigger": {
                        "platform": "device",
                        "domain": DOMAIN,
                        "device_id": device.id,
                        "entity_id": entity_id,
                        "type": "state.node_status",
                    },
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some": (
                                "state.node_status2 - "
                                "{{ trigger.platform}} - "
                                "{{ trigger.from_state.state }}"
                            )
                        },
                    },
                },
            ]
        },
    )

    # Test status change
    event = Event(
        "dead", data={"source": "node", "event": "dead", "nodeId": node.node_id}
    )
    node.receive_event(event)
    await hass.async_block_till_done()
    assert len(calls) == 2
    assert calls[0].data["some"] == "state.node_status - device - alive"
    assert calls[1].data["some"] == "state.node_status2 - device - alive"