Esempio n. 1
0
async def test_motor_barrier_cover(hass, client, gdc_zw062, integration):
    """Test the cover entity."""
    node = gdc_zw062

    state = hass.states.get(GDC_COVER_ENTITY)
    assert state
    assert state.attributes[ATTR_DEVICE_CLASS] == DEVICE_CLASS_GARAGE

    assert state.state == STATE_CLOSED

    # Test open
    await hass.services.async_call(DOMAIN,
                                   SERVICE_OPEN_COVER,
                                   {"entity_id": GDC_COVER_ENTITY},
                                   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"] == 12
    assert args["value"] == 255
    assert args["valueId"] == {
        "ccVersion": 0,
        "commandClass": 102,
        "commandClassName": "Barrier Operator",
        "endpoint": 0,
        "metadata": {
            "label": "Target Barrier State",
            "max": 255,
            "min": 0,
            "readable": True,
            "states": {
                "0": "Closed",
                "255": "Open"
            },
            "type": "number",
            "writeable": True,
        },
        "property": "targetState",
        "propertyName": "targetState",
    }

    # state doesn't change until currentState value update is received
    state = hass.states.get(GDC_COVER_ENTITY)
    assert state.state == STATE_CLOSED

    client.async_send_command.reset_mock()

    # Test close
    await hass.services.async_call(DOMAIN,
                                   SERVICE_CLOSE_COVER,
                                   {"entity_id": GDC_COVER_ENTITY},
                                   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"] == 12
    assert args["value"] == 0
    assert args["valueId"] == {
        "ccVersion": 0,
        "commandClass": 102,
        "commandClassName": "Barrier Operator",
        "endpoint": 0,
        "metadata": {
            "label": "Target Barrier State",
            "max": 255,
            "min": 0,
            "readable": True,
            "states": {
                "0": "Closed",
                "255": "Open"
            },
            "type": "number",
            "writeable": True,
        },
        "property": "targetState",
        "propertyName": "targetState",
    }

    # state doesn't change until currentState value update is received
    state = hass.states.get(GDC_COVER_ENTITY)
    assert state.state == STATE_CLOSED

    client.async_send_command.reset_mock()

    # Barrier sends an opening state
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 12,
            "args": {
                "commandClassName": "Barrier Operator",
                "commandClass": 102,
                "endpoint": 0,
                "property": "currentState",
                "newValue": 254,
                "prevValue": 0,
                "propertyName": "currentState",
            },
        },
    )
    node.receive_event(event)

    state = hass.states.get(GDC_COVER_ENTITY)
    assert state.state == STATE_OPENING

    # Barrier sends an opened state
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 12,
            "args": {
                "commandClassName": "Barrier Operator",
                "commandClass": 102,
                "endpoint": 0,
                "property": "currentState",
                "newValue": 255,
                "prevValue": 254,
                "propertyName": "currentState",
            },
        },
    )
    node.receive_event(event)

    state = hass.states.get(GDC_COVER_ENTITY)
    assert state.state == STATE_OPEN

    # Barrier sends a closing state
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 12,
            "args": {
                "commandClassName": "Barrier Operator",
                "commandClass": 102,
                "endpoint": 0,
                "property": "currentState",
                "newValue": 252,
                "prevValue": 255,
                "propertyName": "currentState",
            },
        },
    )
    node.receive_event(event)

    state = hass.states.get(GDC_COVER_ENTITY)
    assert state.state == STATE_CLOSING

    # Barrier sends a closed state
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 12,
            "args": {
                "commandClassName": "Barrier Operator",
                "commandClass": 102,
                "endpoint": 0,
                "property": "currentState",
                "newValue": 0,
                "prevValue": 252,
                "propertyName": "currentState",
            },
        },
    )
    node.receive_event(event)

    state = hass.states.get(GDC_COVER_ENTITY)
    assert state.state == STATE_CLOSED

    # Barrier sends a stopped state
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 12,
            "args": {
                "commandClassName": "Barrier Operator",
                "commandClass": 102,
                "endpoint": 0,
                "property": "currentState",
                "newValue": 253,
                "prevValue": 252,
                "propertyName": "currentState",
            },
        },
    )
    node.receive_event(event)

    state = hass.states.get(GDC_COVER_ENTITY)
    assert state.state == STATE_UNKNOWN
Esempio n. 2
0
async def test_window_cover(hass, client, chain_actuator_zws12, integration):
    """Test the cover entity."""
    node = chain_actuator_zws12
    state = hass.states.get(WINDOW_COVER_ENTITY)

    assert state
    assert state.attributes[ATTR_DEVICE_CLASS] == DEVICE_CLASS_WINDOW

    assert state.state == "closed"
    assert state.attributes[ATTR_CURRENT_POSITION] == 0

    # Test setting position
    await hass.services.async_call(
        "cover",
        "set_cover_position",
        {
            "entity_id": WINDOW_COVER_ENTITY,
            "position": 50
        },
        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"] == 6
    assert args["valueId"] == {
        "commandClassName": "Multilevel Switch",
        "commandClass": 38,
        "endpoint": 0,
        "property": "targetValue",
        "propertyName": "targetValue",
        "metadata": {
            "label": "Target value",
            "max": 99,
            "min": 0,
            "type": "number",
            "readable": True,
            "writeable": True,
            "label": "Target value",
        },
    }
    assert args["value"] == 50

    client.async_send_command.reset_mock()

    # Test setting position
    await hass.services.async_call(
        "cover",
        "set_cover_position",
        {
            "entity_id": WINDOW_COVER_ENTITY,
            "position": 0
        },
        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"] == 6
    assert args["valueId"] == {
        "commandClassName": "Multilevel Switch",
        "commandClass": 38,
        "endpoint": 0,
        "property": "targetValue",
        "propertyName": "targetValue",
        "metadata": {
            "label": "Target value",
            "max": 99,
            "min": 0,
            "type": "number",
            "readable": True,
            "writeable": True,
            "label": "Target value",
        },
    }
    assert args["value"] == 0

    client.async_send_command.reset_mock()

    # Test opening
    await hass.services.async_call(
        "cover",
        "open_cover",
        {"entity_id": WINDOW_COVER_ENTITY},
        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"] == 6
    assert args["valueId"] == {
        "commandClassName": "Multilevel Switch",
        "commandClass": 38,
        "endpoint": 0,
        "property": "targetValue",
        "propertyName": "targetValue",
        "metadata": {
            "label": "Target value",
            "max": 99,
            "min": 0,
            "type": "number",
            "readable": True,
            "writeable": True,
            "label": "Target value",
        },
    }
    assert args["value"]

    client.async_send_command.reset_mock()
    # Test stop after opening
    await hass.services.async_call(
        "cover",
        "stop_cover",
        {"entity_id": WINDOW_COVER_ENTITY},
        blocking=True,
    )

    assert len(client.async_send_command.call_args_list) == 2
    open_args = client.async_send_command.call_args_list[0][0][0]
    assert open_args["command"] == "node.set_value"
    assert open_args["nodeId"] == 6
    assert open_args["valueId"] == {
        "commandClassName": "Multilevel Switch",
        "commandClass": 38,
        "endpoint": 0,
        "property": "Open",
        "propertyName": "Open",
        "metadata": {
            "type": "boolean",
            "readable": True,
            "writeable": True,
            "label": "Perform a level change (Open)",
            "ccSpecific": {
                "switchType": 3
            },
        },
    }
    assert not open_args["value"]

    close_args = client.async_send_command.call_args_list[1][0][0]
    assert close_args["command"] == "node.set_value"
    assert close_args["nodeId"] == 6
    assert close_args["valueId"] == {
        "commandClassName": "Multilevel Switch",
        "commandClass": 38,
        "endpoint": 0,
        "property": "Close",
        "propertyName": "Close",
        "metadata": {
            "type": "boolean",
            "readable": True,
            "writeable": True,
            "label": "Perform a level change (Close)",
            "ccSpecific": {
                "switchType": 3
            },
        },
    }
    assert not close_args["value"]

    # Test position update from value updated event
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 6,
            "args": {
                "commandClassName": "Multilevel Switch",
                "commandClass": 38,
                "endpoint": 0,
                "property": "currentValue",
                "newValue": 99,
                "prevValue": 0,
                "propertyName": "currentValue",
            },
        },
    )
    node.receive_event(event)
    client.async_send_command.reset_mock()

    state = hass.states.get(WINDOW_COVER_ENTITY)
    assert state.state == "open"

    # Test closing
    await hass.services.async_call(
        "cover",
        "close_cover",
        {"entity_id": WINDOW_COVER_ENTITY},
        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"] == 6
    assert args["valueId"] == {
        "commandClassName": "Multilevel Switch",
        "commandClass": 38,
        "endpoint": 0,
        "property": "targetValue",
        "propertyName": "targetValue",
        "metadata": {
            "label": "Target value",
            "max": 99,
            "min": 0,
            "type": "number",
            "readable": True,
            "writeable": True,
            "label": "Target value",
        },
    }
    assert args["value"] == 0

    client.async_send_command.reset_mock()

    # Test stop after closing
    await hass.services.async_call(
        "cover",
        "stop_cover",
        {"entity_id": WINDOW_COVER_ENTITY},
        blocking=True,
    )

    assert len(client.async_send_command.call_args_list) == 2
    open_args = client.async_send_command.call_args_list[0][0][0]
    assert open_args["command"] == "node.set_value"
    assert open_args["nodeId"] == 6
    assert open_args["valueId"] == {
        "commandClassName": "Multilevel Switch",
        "commandClass": 38,
        "endpoint": 0,
        "property": "Open",
        "propertyName": "Open",
        "metadata": {
            "type": "boolean",
            "readable": True,
            "writeable": True,
            "label": "Perform a level change (Open)",
            "ccSpecific": {
                "switchType": 3
            },
        },
    }
    assert not open_args["value"]

    close_args = client.async_send_command.call_args_list[1][0][0]
    assert close_args["command"] == "node.set_value"
    assert close_args["nodeId"] == 6
    assert close_args["valueId"] == {
        "commandClassName": "Multilevel Switch",
        "commandClass": 38,
        "endpoint": 0,
        "property": "Close",
        "propertyName": "Close",
        "metadata": {
            "type": "boolean",
            "readable": True,
            "writeable": True,
            "label": "Perform a level change (Close)",
            "ccSpecific": {
                "switchType": 3
            },
        },
    }
    assert not close_args["value"]

    client.async_send_command.reset_mock()

    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 6,
            "args": {
                "commandClassName": "Multilevel Switch",
                "commandClass": 38,
                "endpoint": 0,
                "property": "currentValue",
                "newValue": 0,
                "prevValue": 0,
                "propertyName": "currentValue",
            },
        },
    )
    node.receive_event(event)

    state = hass.states.get(WINDOW_COVER_ENTITY)
    assert state.state == "closed"
Esempio n. 3
0
async def test_aeotec_nano_shutter_cover(hass, client, aeotec_nano_shutter,
                                         integration):
    """Test movement of an Aeotec Nano Shutter cover entity. Useful to make sure the stop command logic is handled properly."""
    node = aeotec_nano_shutter
    state = hass.states.get(AEOTEC_SHUTTER_COVER_ENTITY)

    assert state
    assert state.attributes[ATTR_DEVICE_CLASS] == DEVICE_CLASS_WINDOW

    assert state.state == "closed"
    assert state.attributes[ATTR_CURRENT_POSITION] == 0

    # Test opening
    await hass.services.async_call(
        "cover",
        "open_cover",
        {"entity_id": AEOTEC_SHUTTER_COVER_ENTITY},
        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"] == 3
    assert args["valueId"] == {
        "ccVersion": 4,
        "commandClassName": "Multilevel Switch",
        "commandClass": 38,
        "endpoint": 0,
        "property": "targetValue",
        "propertyName": "targetValue",
        "value": 0,
        "metadata": {
            "label": "Target value",
            "max": 99,
            "min": 0,
            "type": "number",
            "valueChangeOptions": ["transitionDuration"],
            "readable": True,
            "writeable": True,
            "label": "Target value",
        },
    }
    assert args["value"]

    client.async_send_command.reset_mock()
    # Test stop after opening
    await hass.services.async_call(
        "cover",
        "stop_cover",
        {"entity_id": AEOTEC_SHUTTER_COVER_ENTITY},
        blocking=True,
    )

    assert len(client.async_send_command.call_args_list) == 2
    open_args = client.async_send_command.call_args_list[0][0][0]
    assert open_args["command"] == "node.set_value"
    assert open_args["nodeId"] == 3
    assert open_args["valueId"] == {
        "ccVersion": 4,
        "commandClassName": "Multilevel Switch",
        "commandClass": 38,
        "endpoint": 0,
        "property": "On",
        "propertyName": "On",
        "value": False,
        "metadata": {
            "type": "boolean",
            "readable": True,
            "writeable": True,
            "label": "Perform a level change (On)",
            "ccSpecific": {
                "switchType": 1
            },
        },
    }
    assert not open_args["value"]

    close_args = client.async_send_command.call_args_list[1][0][0]
    assert close_args["command"] == "node.set_value"
    assert close_args["nodeId"] == 3
    assert close_args["valueId"] == {
        "ccVersion": 4,
        "commandClassName": "Multilevel Switch",
        "commandClass": 38,
        "endpoint": 0,
        "property": "Off",
        "propertyName": "Off",
        "value": False,
        "metadata": {
            "type": "boolean",
            "readable": True,
            "writeable": True,
            "label": "Perform a level change (Off)",
            "ccSpecific": {
                "switchType": 1
            },
        },
    }
    assert not close_args["value"]

    # Test position update from value updated event
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 6,
            "args": {
                "commandClassName": "Multilevel Switch",
                "commandClass": 38,
                "endpoint": 0,
                "property": "currentValue",
                "newValue": 99,
                "prevValue": 0,
                "propertyName": "currentValue",
            },
        },
    )
    node.receive_event(event)

    client.async_send_command.reset_mock()

    state = hass.states.get(AEOTEC_SHUTTER_COVER_ENTITY)
    assert state.state == "open"

    # Test closing
    await hass.services.async_call(
        "cover",
        "close_cover",
        {"entity_id": AEOTEC_SHUTTER_COVER_ENTITY},
        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"] == 3
    assert args["valueId"] == {
        "ccVersion": 4,
        "commandClassName": "Multilevel Switch",
        "commandClass": 38,
        "endpoint": 0,
        "property": "targetValue",
        "propertyName": "targetValue",
        "value": 0,
        "metadata": {
            "label": "Target value",
            "max": 99,
            "min": 0,
            "type": "number",
            "readable": True,
            "writeable": True,
            "valueChangeOptions": ["transitionDuration"],
            "label": "Target value",
        },
    }
    assert args["value"] == 0

    client.async_send_command.reset_mock()

    # Test stop after closing
    await hass.services.async_call(
        "cover",
        "stop_cover",
        {"entity_id": AEOTEC_SHUTTER_COVER_ENTITY},
        blocking=True,
    )

    assert len(client.async_send_command.call_args_list) == 2
    open_args = client.async_send_command.call_args_list[0][0][0]
    assert open_args["command"] == "node.set_value"
    assert open_args["nodeId"] == 3
    assert open_args["valueId"] == {
        "ccVersion": 4,
        "commandClassName": "Multilevel Switch",
        "commandClass": 38,
        "endpoint": 0,
        "property": "On",
        "propertyName": "On",
        "value": False,
        "metadata": {
            "type": "boolean",
            "readable": True,
            "writeable": True,
            "label": "Perform a level change (On)",
            "ccSpecific": {
                "switchType": 1
            },
        },
    }
    assert not open_args["value"]

    close_args = client.async_send_command.call_args_list[1][0][0]
    assert close_args["command"] == "node.set_value"
    assert close_args["nodeId"] == 3
    assert close_args["valueId"] == {
        "ccVersion": 4,
        "commandClassName": "Multilevel Switch",
        "commandClass": 38,
        "endpoint": 0,
        "property": "Off",
        "propertyName": "Off",
        "value": False,
        "metadata": {
            "type": "boolean",
            "readable": True,
            "writeable": True,
            "label": "Perform a level change (Off)",
            "ccSpecific": {
                "switchType": 1
            },
        },
    }
    assert not close_args["value"]
Esempio n. 4
0
async def test_value_updated(hass, vision_security_zl7432, integration,
                             client):
    """Test value updated events."""
    node = vision_security_zl7432
    events = async_capture_events(hass, "zwave_js_value_updated")

    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 7,
            "args": {
                "commandClassName": "Switch Binary",
                "commandClass": 37,
                "endpoint": 1,
                "property": "currentValue",
                "newValue": 1,
                "prevValue": 0,
                "propertyName": "currentValue",
            },
        },
    )

    node.receive_event(event)
    # wait for the event
    await hass.async_block_till_done()
    assert len(events) == 1
    assert events[0].data["home_id"] == client.driver.controller.home_id
    assert events[0].data["node_id"] == 7
    assert events[0].data["entity_id"] == "switch.in_wall_dual_relay_switch"
    assert events[0].data["command_class"] == CommandClass.SWITCH_BINARY
    assert events[0].data["command_class_name"] == "Switch Binary"
    assert events[0].data["endpoint"] == 1
    assert events[0].data["property_name"] == "currentValue"
    assert events[0].data["property"] == "currentValue"
    assert events[0].data["value"] == 1
    assert events[0].data["value_raw"] == 1

    # Try a value updated event on a value we aren't watching to make sure
    # no event fires
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 7,
            "args": {
                "commandClassName": "Basic",
                "commandClass": 32,
                "endpoint": 1,
                "property": "currentValue",
                "newValue": 1,
                "prevValue": 0,
                "propertyName": "currentValue",
            },
        },
    )

    node.receive_event(event)
    # wait for the event
    await hass.async_block_till_done()
    # We should only still have captured one event
    assert len(events) == 1
Esempio n. 5
0
async def test_unit_change(hass, zp3111, client, integration):
    """Test unit change via metadata updated event is handled by numeric sensors."""
    entity_id = "sensor.4_in_1_sensor_air_temperature"
    state = hass.states.get(entity_id)
    assert state
    assert state.state == "21.98"
    assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == TEMP_CELSIUS
    event = Event(
        "metadata updated",
        {
            "source": "node",
            "event": "metadata updated",
            "nodeId": zp3111.node_id,
            "args": {
                "commandClassName": "Multilevel Sensor",
                "commandClass": 49,
                "endpoint": 0,
                "property": "Air temperature",
                "metadata": {
                    "type": "number",
                    "readable": True,
                    "writeable": False,
                    "label": "Air temperature",
                    "ccSpecific": {
                        "sensorType": 1,
                        "scale": 1
                    },
                    "unit": "°F",
                },
                "propertyName": "Air temperature",
                "nodeId": zp3111.node_id,
            },
        },
    )
    zp3111.receive_event(event)
    await hass.async_block_till_done()
    state = hass.states.get(entity_id)
    assert state
    assert state.state == "21.98"
    assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == TEMP_CELSIUS
    event = Event(
        "value updated",
        {
            "source": "node",
            "event": "value updated",
            "nodeId": zp3111.node_id,
            "args": {
                "commandClassName": "Multilevel Sensor",
                "commandClass": 49,
                "endpoint": 0,
                "property": "Air temperature",
                "newValue": 212,
                "prevValue": 21.98,
                "propertyName": "Air temperature",
            },
        },
    )
    zp3111.receive_event(event)
    await hass.async_block_till_done()
    state = hass.states.get(entity_id)
    assert state
    assert state.state == "100.0"
    assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == TEMP_CELSIUS
Esempio n. 6
0
async def test_volume_number(hass, client, aeotec_zw164_siren, integration):
    """Test the volume number entity."""
    node = aeotec_zw164_siren
    state = hass.states.get(VOLUME_NUMBER_ENTITY)

    assert state
    assert state.state == "1.0"
    assert state.attributes["step"] == 0.01
    assert state.attributes["max"] == 1.0
    assert state.attributes["min"] == 0

    # Test turn on setting value
    await hass.services.async_call(
        "number",
        "set_value",
        {
            "entity_id": VOLUME_NUMBER_ENTITY,
            "value": 0.3
        },
        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"] == node.node_id
    assert args["valueId"] == {
        "endpoint": 2,
        "commandClass": 121,
        "commandClassName": "Sound Switch",
        "property": "defaultVolume",
        "propertyName": "defaultVolume",
        "ccVersion": 1,
        "metadata": {
            "type": "number",
            "readable": True,
            "writeable": True,
            "label": "Default volume",
            "min": 0,
            "max": 100,
            "unit": "%",
        },
        "value": 100,
    }
    assert args["value"] == 30

    client.async_send_command.reset_mock()

    # Test value update from value updated event
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 4,
            "args": {
                "commandClassName": "Sound Switch",
                "commandClass": 121,
                "endpoint": 2,
                "property": "defaultVolume",
                "newValue": 30,
                "prevValue": 100,
                "propertyName": "defaultVolume",
            },
        },
    )
    node.receive_event(event)

    state = hass.states.get(VOLUME_NUMBER_ENTITY)
    assert state.state == "0.3"

    # Test null value
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 4,
            "args": {
                "commandClassName": "Sound Switch",
                "commandClass": 121,
                "endpoint": 2,
                "property": "defaultVolume",
                "newValue": None,
                "prevValue": 30,
                "propertyName": "defaultVolume",
            },
        },
    )
    node.receive_event(event)

    state = hass.states.get(VOLUME_NUMBER_ENTITY)
    assert state.state == STATE_UNKNOWN
Esempio n. 7
0
async def test_scenes(hass, hank_binary_switch, integration, client):
    """Test scene events."""
    # just pick a random node to fake the value notification events
    node = hank_binary_switch
    events = async_capture_events(hass, "zwave_js_value_notification")

    # Publish fake Basic Set value notification
    event = Event(
        type="value notification",
        data={
            "source": "node",
            "event": "value notification",
            "nodeId": 32,
            "args": {
                "commandClassName": "Basic",
                "commandClass": 32,
                "endpoint": 0,
                "property": "event",
                "propertyName": "event",
                "value": 255,
                "metadata": {
                    "type": "number",
                    "readable": True,
                    "writeable": False,
                    "min": 0,
                    "max": 255,
                    "label": "Event value",
                },
                "ccVersion": 1,
            },
        },
    )
    node.receive_event(event)
    # wait for the event
    await hass.async_block_till_done()
    assert len(events) == 1
    assert events[0].data["home_id"] == client.driver.controller.home_id
    assert events[0].data["node_id"] == 32
    assert events[0].data["endpoint"] == 0
    assert events[0].data["command_class"] == 32
    assert events[0].data["command_class_name"] == "Basic"
    assert events[0].data["label"] == "Event value"
    assert events[0].data["value"] == 255
    assert events[0].data["value_raw"] == 255

    # Publish fake Scene Activation value notification
    event = Event(
        type="value notification",
        data={
            "source": "node",
            "event": "value notification",
            "nodeId": 32,
            "args": {
                "commandClassName": "Scene Activation",
                "commandClass": 43,
                "endpoint": 0,
                "property": "SceneID",
                "propertyName": "SceneID",
                "value": 16,
                "metadata": {
                    "type": "number",
                    "readable": True,
                    "writeable": False,
                    "min": 0,
                    "max": 255,
                    "label": "Scene ID",
                },
                "ccVersion": 3,
            },
        },
    )
    node.receive_event(event)
    # wait for the event
    await hass.async_block_till_done()
    assert len(events) == 2
    assert events[1].data["command_class"] == 43
    assert events[1].data["command_class_name"] == "Scene Activation"
    assert events[1].data["label"] == "Scene ID"
    assert events[1].data["value"] == 16
    assert events[1].data["value_raw"] == 16

    # Publish fake Central Scene value notification
    event = Event(
        type="value notification",
        data={
            "source": "node",
            "event": "value notification",
            "nodeId": 32,
            "args": {
                "commandClassName": "Central Scene",
                "commandClass": 91,
                "endpoint": 0,
                "property": "scene",
                "propertyKey": "001",
                "propertyName": "scene",
                "propertyKeyName": "001",
                "value": 4,
                "metadata": {
                    "type": "number",
                    "readable": True,
                    "writeable": False,
                    "min": 0,
                    "max": 255,
                    "label": "Scene 001",
                    "states": {
                        "0": "KeyPressed",
                        "1": "KeyReleased",
                        "2": "KeyHeldDown",
                        "3": "KeyPressed2x",
                        "4": "KeyPressed3x",
                        "5": "KeyPressed4x",
                        "6": "KeyPressed5x",
                    },
                },
                "ccVersion": 3,
            },
        },
    )
    node.receive_event(event)
    # wait for the event
    await hass.async_block_till_done()
    assert len(events) == 3
    assert events[2].data["command_class"] == 91
    assert events[2].data["command_class_name"] == "Central Scene"
    assert events[2].data["label"] == "Scene 001"
    assert events[2].data["value"] == "KeyPressed3x"
    assert events[2].data["value_raw"] == 4
Esempio n. 8
0
async def test_config_parameter_state(hass, client, lock_schlage_be469,
                                      integration, calls) -> None:
    """Test for config_parameter conditions."""
    dev_reg = device_registry.async_get(hass)
    device = device_registry.async_entries_for_config_entry(
        dev_reg, integration.entry_id)[0]

    assert await async_setup_component(
        hass,
        automation.DOMAIN,
        {
            automation.DOMAIN: [
                {
                    "trigger": {
                        "platform": "event",
                        "event_type": "test_event1"
                    },
                    "condition": [{
                        "condition": "device",
                        "domain": DOMAIN,
                        "device_id": device.id,
                        "type": "config_parameter",
                        "value_id": f"{lock_schlage_be469.node_id}-112-0-3",
                        "subtype":
                        f"{lock_schlage_be469.node_id}-112-0-3 (Beeper)",
                        "value": 255,
                    }],
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some":
                            "Beeper - {{ trigger.platform }} - {{ trigger.event.event_type }}"
                        },
                    },
                },
                {
                    "trigger": {
                        "platform": "event",
                        "event_type": "test_event2"
                    },
                    "condition": [{
                        "condition": "device",
                        "domain": DOMAIN,
                        "device_id": device.id,
                        "type": "config_parameter",
                        "value_id": f"{lock_schlage_be469.node_id}-112-0-6",
                        "subtype":
                        f"{lock_schlage_be469.node_id}-112-0-6 (User Slot Status)",
                        "value": 1,
                    }],
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some":
                            "User Slot Status - {{ trigger.platform }} - {{ trigger.event.event_type }}"
                        },
                    },
                },
            ]
        },
    )

    hass.bus.async_fire("test_event1")
    hass.bus.async_fire("test_event2")
    await hass.async_block_till_done()
    assert len(calls) == 1
    assert calls[0].data["some"] == "Beeper - event - test_event1"

    # Flip Beeper state to not match condition
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": lock_schlage_be469.node_id,
            "args": {
                "commandClassName": "Configuration",
                "commandClass": 112,
                "endpoint": 0,
                "property": 3,
                "newValue": 0,
                "prevValue": 255,
            },
        },
    )
    lock_schlage_be469.receive_event(event)

    # Flip User Slot Status to match condition
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": lock_schlage_be469.node_id,
            "args": {
                "commandClassName": "Configuration",
                "commandClass": 112,
                "endpoint": 0,
                "property": 6,
                "newValue": 1,
                "prevValue": 117440512,
            },
        },
    )
    lock_schlage_be469.receive_event(event)

    hass.bus.async_fire("test_event1")
    hass.bus.async_fire("test_event2")
    await hass.async_block_till_done()
    assert len(calls) == 2
    assert calls[1].data["some"] == "User Slot Status - event - test_event2"
Esempio n. 9
0
async def test_node_status_state(hass, client, lock_schlage_be469, integration,
                                 calls) -> None:
    """Test for node_status conditions."""
    dev_reg = device_registry.async_get(hass)
    device = device_registry.async_entries_for_config_entry(
        dev_reg, integration.entry_id)[0]

    assert await async_setup_component(
        hass,
        automation.DOMAIN,
        {
            automation.DOMAIN: [
                {
                    "trigger": {
                        "platform": "event",
                        "event_type": "test_event1"
                    },
                    "condition": [{
                        "condition": "device",
                        "domain": DOMAIN,
                        "device_id": device.id,
                        "type": "node_status",
                        "status": "alive",
                    }],
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some":
                            "alive - {{ trigger.platform }} - {{ trigger.event.event_type }}"
                        },
                    },
                },
                {
                    "trigger": {
                        "platform": "event",
                        "event_type": "test_event2"
                    },
                    "condition": [{
                        "condition": "device",
                        "domain": DOMAIN,
                        "device_id": device.id,
                        "type": "node_status",
                        "status": "awake",
                    }],
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some":
                            "awake - {{ trigger.platform }} - {{ trigger.event.event_type }}"
                        },
                    },
                },
                {
                    "trigger": {
                        "platform": "event",
                        "event_type": "test_event3"
                    },
                    "condition": [{
                        "condition": "device",
                        "domain": DOMAIN,
                        "device_id": device.id,
                        "type": "node_status",
                        "status": "asleep",
                    }],
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some":
                            "asleep - {{ trigger.platform }} - {{ trigger.event.event_type }}"
                        },
                    },
                },
                {
                    "trigger": {
                        "platform": "event",
                        "event_type": "test_event4"
                    },
                    "condition": [{
                        "condition": "device",
                        "domain": DOMAIN,
                        "device_id": device.id,
                        "type": "node_status",
                        "status": "dead",
                    }],
                    "action": {
                        "service": "test.automation",
                        "data_template": {
                            "some":
                            "dead - {{ trigger.platform }} - {{ trigger.event.event_type }}"
                        },
                    },
                },
            ]
        },
    )

    hass.bus.async_fire("test_event1")
    hass.bus.async_fire("test_event2")
    hass.bus.async_fire("test_event3")
    hass.bus.async_fire("test_event4")
    await hass.async_block_till_done()
    assert len(calls) == 1
    assert calls[0].data["some"] == "alive - event - test_event1"

    event = Event(
        "wake up",
        data={
            "source": "node",
            "event": "wake up",
            "nodeId": lock_schlage_be469.node_id,
        },
    )
    lock_schlage_be469.receive_event(event)
    await hass.async_block_till_done()

    hass.bus.async_fire("test_event1")
    hass.bus.async_fire("test_event2")
    hass.bus.async_fire("test_event3")
    hass.bus.async_fire("test_event4")
    await hass.async_block_till_done()
    assert len(calls) == 2
    assert calls[1].data["some"] == "awake - event - test_event2"

    event = Event(
        "sleep",
        data={
            "source": "node",
            "event": "sleep",
            "nodeId": lock_schlage_be469.node_id
        },
    )
    lock_schlage_be469.receive_event(event)
    await hass.async_block_till_done()

    hass.bus.async_fire("test_event1")
    hass.bus.async_fire("test_event2")
    hass.bus.async_fire("test_event3")
    hass.bus.async_fire("test_event4")
    await hass.async_block_till_done()
    assert len(calls) == 3
    assert calls[2].data["some"] == "asleep - event - test_event3"

    event = Event(
        "dead",
        data={
            "source": "node",
            "event": "dead",
            "nodeId": lock_schlage_be469.node_id
        },
    )
    lock_schlage_be469.receive_event(event)
    await hass.async_block_till_done()

    hass.bus.async_fire("test_event1")
    hass.bus.async_fire("test_event2")
    hass.bus.async_fire("test_event3")
    hass.bus.async_fire("test_event4")
    await hass.async_block_till_done()
    assert len(calls) == 4
    assert calls[3].data["some"] == "dead - event - test_event4"

    event = Event(
        "unknown",
        data={
            "source": "node",
            "event": "unknown",
            "nodeId": lock_schlage_be469.node_id,
        },
    )
    lock_schlage_be469.receive_event(event)
    await hass.async_block_till_done()
Esempio n. 10
0
async def test_replace_different_node(
    hass,
    multisensor_6,
    multisensor_6_state,
    hank_binary_switch_state,
    client,
    integration,
):
    """Test when a node is replaced with a different node."""
    dev_reg = dr.async_get(hass)
    node_id = multisensor_6.node_id
    hank_binary_switch_state = deepcopy(hank_binary_switch_state)
    hank_binary_switch_state["nodeId"] = node_id

    device_id = f"{client.driver.controller.home_id}-{node_id}"
    multisensor_6_device_id = (
        f"{device_id}-{multisensor_6.manufacturer_id}:"
        f"{multisensor_6.product_type}:{multisensor_6.product_id}")
    hank_device_id = (
        f"{device_id}-{hank_binary_switch_state['manufacturerId']}:"
        f"{hank_binary_switch_state['productType']}:"
        f"{hank_binary_switch_state['productId']}")

    device = dev_reg.async_get_device(identifiers={(DOMAIN, device_id)})
    assert device
    assert device == dev_reg.async_get_device(
        identifiers={(DOMAIN, multisensor_6_device_id)})
    assert device.manufacturer == "AEON Labs"
    assert device.model == "ZW100"
    dev_id = device.id

    assert hass.states.get(AIR_TEMPERATURE_SENSOR)

    # A replace node event has the extra field "replaced" set to True
    # to distinguish it from an exclusion
    event = Event(
        type="node removed",
        data={
            "source": "controller",
            "event": "node removed",
            "replaced": True,
            "node": multisensor_6_state,
        },
    )
    client.driver.receive_event(event)
    await hass.async_block_till_done()

    # Device should still be there after the node was removed
    device = dev_reg.async_get(dev_id)
    assert device

    # When the node is replaced, a non-ready node added event is emitted
    event = Event(
        type="node added",
        data={
            "source": "controller",
            "event": "node added",
            "node": {
                "nodeId":
                multisensor_6.node_id,
                "index":
                0,
                "status":
                4,
                "ready":
                False,
                "isSecure":
                "unknown",
                "interviewAttempts":
                1,
                "endpoints": [{
                    "nodeId": multisensor_6.node_id,
                    "index": 0,
                    "deviceClass": None
                }],
                "values": [],
                "deviceClass":
                None,
                "commandClasses": [],
                "interviewStage":
                "None",
                "statistics": {
                    "commandsTX": 0,
                    "commandsRX": 0,
                    "commandsDroppedRX": 0,
                    "commandsDroppedTX": 0,
                    "timeoutResponse": 0,
                },
            },
        },
    )

    # Device is still not removed
    client.driver.receive_event(event)
    await hass.async_block_till_done()

    device = dev_reg.async_get(dev_id)
    assert device

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

    # Old device and entities were removed, but the ID is re-used
    device = dev_reg.async_get(dev_id)
    assert device
    assert device == dev_reg.async_get_device(identifiers={(DOMAIN,
                                                            device_id)})
    assert device == dev_reg.async_get_device(identifiers={(DOMAIN,
                                                            hank_device_id)})
    assert not dev_reg.async_get_device(
        identifiers={(DOMAIN, multisensor_6_device_id)})
    assert device.manufacturer == "HANK Electronics Ltd."
    assert device.model == "HKZW-SO01"

    assert not hass.states.get(AIR_TEMPERATURE_SENSOR)
    assert hass.states.get("switch.smart_plug_with_two_usb_ports")
async def test_listening_logs(driver, uuid4, mock_command):
    """Test listening to logs helpers."""
    # Test that start listening to logs command is sent
    ack_commands = mock_command(
        {"command": "driver.start_listening_logs"},
        {"success": True},
    )
    await driver.async_start_listening_logs()

    assert len(ack_commands) == 1
    assert ack_commands[0] == {
        "command": "driver.start_listening_logs",
        "messageId": uuid4,
    }

    # Test that stop listening to logs command is sent
    ack_commands = mock_command(
        {"command": "driver.stop_listening_logs"},
        {"success": True},
    )
    await driver.async_stop_listening_logs()

    assert len(ack_commands) == 2
    assert ack_commands[1] == {
        "command": "driver.stop_listening_logs",
        "messageId": uuid4,
    }

    # Test receiving a log message event
    event = Event(
        type="logging",
        data={
            "source":
            "driver",
            "event":
            "logging",
            "formattedMessage": [
                "2021-04-18T18:03:34.051Z CNTRLR   [Node 005] [~] \n",
                "test",
            ],
            "level":
            "debug",
            "primaryTags":
            "[Node 005] [~] [Notification]",
            "secondaryTags":
            "[Endpoint 0]",
            "message":
            "Home Security[Motion sensor status]\n: 8 => 0",
            "direction":
            "  ",
            "label":
            "CNTRLR",
            "timestamp":
            "2021-04-18T18:03:34.051Z",
            "multiline":
            True,
            "secondaryTagPadding":
            -1,
        },
    )
    driver.receive_event(event)
    assert "log_message" in event.data
    assert isinstance(event.data["log_message"], log_message_pkg.LogMessage)
    log_message = event.data["log_message"]
    assert log_message.message == [
        "Home Security[Motion sensor status]", ": 8 => 0"
    ]
    assert log_message.formatted_message == [
        "2021-04-18T18:03:34.051Z CNTRLR   [Node 005] [~] ",
        "test",
    ]
    assert log_message.direction == "  "
    assert log_message.primary_tags == "[Node 005] [~] [Notification]"
    assert log_message.secondary_tags == "[Endpoint 0]"
    assert log_message.level == "debug"
    assert log_message.label == "CNTRLR"
    assert log_message.multiline
    assert log_message.secondary_tag_padding == -1
    assert log_message.timestamp == "2021-04-18T18:03:34.051Z"
Esempio n. 12
0
async def test_replace_same_node(hass, multisensor_6, multisensor_6_state,
                                 client, integration):
    """Test when a node is replaced with itself that the device remains."""
    dev_reg = dr.async_get(hass)
    node_id = multisensor_6.node_id
    multisensor_6_state = deepcopy(multisensor_6_state)

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

    device = dev_reg.async_get_device(identifiers={(DOMAIN, device_id)})
    assert device
    assert device == dev_reg.async_get_device(
        identifiers={(DOMAIN, multisensor_6_device_id)})
    assert device.manufacturer == "AEON Labs"
    assert device.model == "ZW100"
    dev_id = device.id

    assert hass.states.get(AIR_TEMPERATURE_SENSOR)

    # A replace node event has the extra field "replaced" set to True
    # to distinguish it from an exclusion
    event = Event(
        type="node removed",
        data={
            "source": "controller",
            "event": "node removed",
            "replaced": True,
            "node": multisensor_6_state,
        },
    )
    client.driver.receive_event(event)
    await hass.async_block_till_done()

    # Device should still be there after the node was removed
    device = dev_reg.async_get(dev_id)
    assert device

    # When the node is replaced, a non-ready node added event is emitted
    event = Event(
        type="node added",
        data={
            "source": "controller",
            "event": "node added",
            "node": {
                "nodeId": node_id,
                "index": 0,
                "status": 4,
                "ready": False,
                "isSecure": "unknown",
                "interviewAttempts": 1,
                "endpoints": [{
                    "nodeId": node_id,
                    "index": 0,
                    "deviceClass": None
                }],
                "values": [],
                "deviceClass": None,
                "commandClasses": [],
                "interviewStage": "None",
                "statistics": {
                    "commandsTX": 0,
                    "commandsRX": 0,
                    "commandsDroppedRX": 0,
                    "commandsDroppedTX": 0,
                    "timeoutResponse": 0,
                },
            },
        },
    )

    # Device is still not removed
    client.driver.receive_event(event)
    await hass.async_block_till_done()

    device = dev_reg.async_get(dev_id)
    assert device

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

    # Device is the same
    device = dev_reg.async_get(dev_id)
    assert device
    assert device == dev_reg.async_get_device(identifiers={(DOMAIN,
                                                            device_id)})
    assert device == dev_reg.async_get_device(
        identifiers={(DOMAIN, multisensor_6_device_id)})
    assert device.manufacturer == "AEON Labs"
    assert device.model == "ZW100"

    assert hass.states.get(AIR_TEMPERATURE_SENSOR)
Esempio n. 13
0
async def test_existing_node_not_replaced_when_not_ready(
        hass, zp3111, zp3111_not_ready_state, zp3111_state, client,
        integration):
    """Test when a node added event with a non-ready node is received.

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

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

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

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

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

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

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

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

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

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

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

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

    state = hass.states.get(custom_entity)
    assert state
    assert state.state != STATE_UNAVAILABLE
    assert state.name == "Custom Entity Name"
Esempio n. 14
0
async def test_disabled_entity_on_value_removed(hass, zp3111, client,
                                                integration):
    """Test that when entity primary values are removed the entity is removed."""
    er_reg = er.async_get(hass)

    # re-enable this default-disabled entity
    sensor_cover_entity = "sensor.4_in_1_sensor_home_security_cover_status"
    er_reg.async_update_entity(entity_id=sensor_cover_entity, disabled_by=None)
    await hass.async_block_till_done()

    # must reload the integration when enabling an entity
    await hass.config_entries.async_unload(integration.entry_id)
    await hass.async_block_till_done()
    assert integration.state is ConfigEntryState.NOT_LOADED
    integration.add_to_hass(hass)
    await hass.config_entries.async_setup(integration.entry_id)
    await hass.async_block_till_done()
    assert integration.state is ConfigEntryState.LOADED

    state = hass.states.get(sensor_cover_entity)
    assert state
    assert state.state != STATE_UNAVAILABLE

    # check for expected entities
    binary_cover_entity = (
        "binary_sensor.4_in_1_sensor_home_security_tampering_product_cover_removed"
    )
    state = hass.states.get(binary_cover_entity)
    assert state
    assert state.state != STATE_UNAVAILABLE

    battery_level_entity = "sensor.4_in_1_sensor_battery_level"
    state = hass.states.get(battery_level_entity)
    assert state
    assert state.state != STATE_UNAVAILABLE

    unavailable_entities = {
        state.entity_id
        for state in hass.states.async_all()
        if state.state == STATE_UNAVAILABLE
    }

    # This value ID removal does not remove any entity
    event = Event(
        type="value removed",
        data={
            "source": "node",
            "event": "value removed",
            "nodeId": zp3111.node_id,
            "args": {
                "commandClassName": "Wake Up",
                "commandClass": 132,
                "endpoint": 0,
                "property": "wakeUpInterval",
                "prevValue": 3600,
                "propertyName": "wakeUpInterval",
            },
        },
    )
    client.driver.receive_event(event)
    await hass.async_block_till_done()

    assert all(state != STATE_UNAVAILABLE for state in hass.states.async_all())

    # This value ID removal only affects the battery level entity
    event = Event(
        type="value removed",
        data={
            "source": "node",
            "event": "value removed",
            "nodeId": zp3111.node_id,
            "args": {
                "commandClassName": "Battery",
                "commandClass": 128,
                "endpoint": 0,
                "property": "level",
                "prevValue": 100,
                "propertyName": "level",
            },
        },
    )
    client.driver.receive_event(event)
    await hass.async_block_till_done()

    state = hass.states.get(battery_level_entity)
    assert state
    assert state.state == STATE_UNAVAILABLE

    # This value ID removal affects its multiple notification sensors
    event = Event(
        type="value removed",
        data={
            "source": "node",
            "event": "value removed",
            "nodeId": zp3111.node_id,
            "args": {
                "commandClassName": "Notification",
                "commandClass": 113,
                "endpoint": 0,
                "property": "Home Security",
                "propertyKey": "Cover status",
                "prevValue": 0,
                "propertyName": "Home Security",
                "propertyKeyName": "Cover status",
            },
        },
    )
    client.driver.receive_event(event)
    await hass.async_block_till_done()

    state = hass.states.get(binary_cover_entity)
    assert state
    assert state.state == STATE_UNAVAILABLE

    state = hass.states.get(sensor_cover_entity)
    assert state
    assert state.state == STATE_UNAVAILABLE

    # existing entities and the entities with removed values should be unavailable
    new_unavailable_entities = {
        state.entity_id
        for state in hass.states.async_all()
        if state.state == STATE_UNAVAILABLE
    }
    assert (unavailable_entities
            | {battery_level_entity, binary_cover_entity, sensor_cover_entity
               } == new_unavailable_entities)
Esempio n. 15
0
async def test_zwave_js_value_updated(hass, client, lock_schlage_be469,
                                      integration):
    """Test for zwave_js.value_updated automation trigger."""
    trigger_type = f"{DOMAIN}.value_updated"
    node: Node = lock_schlage_be469
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]

    no_value_filter = async_capture_events(hass, "no_value_filter")
    single_from_value_filter = async_capture_events(
        hass, "single_from_value_filter")
    multiple_from_value_filters = async_capture_events(
        hass, "multiple_from_value_filters")
    from_and_to_value_filters = async_capture_events(
        hass, "from_and_to_value_filters")
    different_value = async_capture_events(hass, "different_value")

    def clear_events():
        """Clear all events in the event list."""
        no_value_filter.clear()
        single_from_value_filter.clear()
        multiple_from_value_filters.clear()
        from_and_to_value_filters.clear()
        different_value.clear()

    assert await async_setup_component(
        hass,
        automation.DOMAIN,
        {
            automation.DOMAIN: [
                # no value filter
                {
                    "trigger": {
                        "platform": trigger_type,
                        "entity_id": SCHLAGE_BE469_LOCK_ENTITY,
                        "command_class": CommandClass.DOOR_LOCK.value,
                        "property": "latchStatus",
                    },
                    "action": {
                        "event": "no_value_filter",
                    },
                },
                # single from value filter
                {
                    "trigger": {
                        "platform": trigger_type,
                        "device_id": device.id,
                        "command_class": CommandClass.DOOR_LOCK.value,
                        "property": "latchStatus",
                        "from": "ajar",
                    },
                    "action": {
                        "event": "single_from_value_filter",
                    },
                },
                # multiple from value filters
                {
                    "trigger": {
                        "platform": trigger_type,
                        "entity_id": SCHLAGE_BE469_LOCK_ENTITY,
                        "command_class": CommandClass.DOOR_LOCK.value,
                        "property": "latchStatus",
                        "from": ["closed", "opened"],
                    },
                    "action": {
                        "event": "multiple_from_value_filters",
                    },
                },
                # from and to value filters
                {
                    "trigger": {
                        "platform": trigger_type,
                        "entity_id": SCHLAGE_BE469_LOCK_ENTITY,
                        "command_class": CommandClass.DOOR_LOCK.value,
                        "property": "latchStatus",
                        "from": ["closed", "opened"],
                        "to": ["opened"],
                    },
                    "action": {
                        "event": "from_and_to_value_filters",
                    },
                },
                # different value
                {
                    "trigger": {
                        "platform": trigger_type,
                        "entity_id": SCHLAGE_BE469_LOCK_ENTITY,
                        "command_class": CommandClass.DOOR_LOCK.value,
                        "property": "boltStatus",
                    },
                    "action": {
                        "event": "different_value",
                    },
                },
            ]
        },
    )

    # Test that no value filter is triggered
    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": "boo",
                "prevValue": "hiss",
                "propertyName": "latchStatus",
            },
        },
    )
    node.receive_event(event)
    await hass.async_block_till_done()

    assert len(no_value_filter) == 1
    assert len(single_from_value_filter) == 0
    assert len(multiple_from_value_filters) == 0
    assert len(from_and_to_value_filters) == 0
    assert len(different_value) == 0

    clear_events()

    # Test that a single_from_value_filter is triggered
    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": "boo",
                "prevValue": "ajar",
                "propertyName": "latchStatus",
            },
        },
    )
    node.receive_event(event)
    await hass.async_block_till_done()

    assert len(no_value_filter) == 1
    assert len(single_from_value_filter) == 1
    assert len(multiple_from_value_filters) == 0
    assert len(from_and_to_value_filters) == 0
    assert len(different_value) == 0

    clear_events()

    # Test that multiple_from_value_filters are triggered
    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": "boo",
                "prevValue": "closed",
                "propertyName": "latchStatus",
            },
        },
    )
    node.receive_event(event)
    await hass.async_block_till_done()

    assert len(no_value_filter) == 1
    assert len(single_from_value_filter) == 0
    assert len(multiple_from_value_filters) == 1
    assert len(from_and_to_value_filters) == 0
    assert len(different_value) == 0

    clear_events()

    # Test that from_and_to_value_filters is triggered
    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": "opened",
                "prevValue": "closed",
                "propertyName": "latchStatus",
            },
        },
    )
    node.receive_event(event)
    await hass.async_block_till_done()

    assert len(no_value_filter) == 1
    assert len(single_from_value_filter) == 0
    assert len(multiple_from_value_filters) == 1
    assert len(from_and_to_value_filters) == 1
    assert len(different_value) == 0

    clear_events()

    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": node.node_id,
            "args": {
                "commandClassName": "Door Lock",
                "commandClass": 98,
                "endpoint": 0,
                "property": "boltStatus",
                "newValue": "boo",
                "prevValue": "hiss",
                "propertyName": "boltStatus",
            },
        },
    )
    node.receive_event(event)
    await hass.async_block_till_done()

    assert len(no_value_filter) == 0
    assert len(single_from_value_filter) == 0
    assert len(multiple_from_value_filters) == 0
    assert len(from_and_to_value_filters) == 0
    assert len(different_value) == 1

    clear_events()

    with patch("homeassistant.config.load_yaml", return_value={}):
        await hass.services.async_call(automation.DOMAIN,
                                       SERVICE_RELOAD,
                                       blocking=True)
Esempio n. 16
0
async def test_thermostat_v2(hass, client, climate_radio_thermostat_ct100_plus,
                             integration):
    """Test a thermostat v2 command class entity."""
    node = climate_radio_thermostat_ct100_plus
    state = hass.states.get(CLIMATE_RADIO_THERMOSTAT_ENTITY)

    assert state
    assert state.state == HVAC_MODE_HEAT
    assert state.attributes[ATTR_HVAC_MODES] == [
        HVAC_MODE_OFF,
        HVAC_MODE_HEAT,
        HVAC_MODE_COOL,
        HVAC_MODE_HEAT_COOL,
    ]
    assert state.attributes[ATTR_CURRENT_HUMIDITY] == 30
    assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 22.2
    assert state.attributes[ATTR_TEMPERATURE] == 22.2
    assert state.attributes[ATTR_HVAC_ACTION] == CURRENT_HVAC_IDLE
    assert state.attributes[ATTR_PRESET_MODE] == PRESET_NONE

    # Test setting preset mode
    await hass.services.async_call(
        CLIMATE_DOMAIN,
        SERVICE_SET_PRESET_MODE,
        {
            ATTR_ENTITY_ID: CLIMATE_RADIO_THERMOSTAT_ENTITY,
            ATTR_PRESET_MODE: PRESET_NONE,
        },
        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"] == 13
    assert args["valueId"] == {
        "commandClassName": "Thermostat Mode",
        "commandClass": 64,
        "endpoint": 1,
        "property": "mode",
        "propertyName": "mode",
        "metadata": {
            "type": "number",
            "readable": True,
            "writeable": True,
            "min": 0,
            "max": 31,
            "label": "Thermostat mode",
            "states": {
                "0": "Off",
                "1": "Heat",
                "2": "Cool",
                "3": "Auto"
            },
        },
        "value": 1,
    }
    assert args["value"] == 1

    client.async_send_command.reset_mock()

    # Test setting hvac mode
    await hass.services.async_call(
        CLIMATE_DOMAIN,
        SERVICE_SET_HVAC_MODE,
        {
            ATTR_ENTITY_ID: CLIMATE_RADIO_THERMOSTAT_ENTITY,
            ATTR_HVAC_MODE: HVAC_MODE_COOL,
        },
        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"] == 13
    assert args["valueId"] == {
        "commandClassName": "Thermostat Mode",
        "commandClass": 64,
        "endpoint": 1,
        "property": "mode",
        "propertyName": "mode",
        "metadata": {
            "type": "number",
            "readable": True,
            "writeable": True,
            "min": 0,
            "max": 31,
            "label": "Thermostat mode",
            "states": {
                "0": "Off",
                "1": "Heat",
                "2": "Cool",
                "3": "Auto"
            },
        },
        "value": 1,
    }
    assert args["value"] == 2

    client.async_send_command.reset_mock()

    # Test setting temperature
    await hass.services.async_call(
        CLIMATE_DOMAIN,
        SERVICE_SET_TEMPERATURE,
        {
            ATTR_ENTITY_ID: CLIMATE_RADIO_THERMOSTAT_ENTITY,
            ATTR_HVAC_MODE: HVAC_MODE_COOL,
            ATTR_TEMPERATURE: 25,
        },
        blocking=True,
    )

    assert len(client.async_send_command.call_args_list) == 2
    args = client.async_send_command.call_args_list[0][0][0]
    assert args["command"] == "node.set_value"
    assert args["nodeId"] == 13
    assert args["valueId"] == {
        "commandClassName": "Thermostat Mode",
        "commandClass": 64,
        "endpoint": 1,
        "property": "mode",
        "propertyName": "mode",
        "metadata": {
            "type": "number",
            "readable": True,
            "writeable": True,
            "min": 0,
            "max": 31,
            "label": "Thermostat mode",
            "states": {
                "0": "Off",
                "1": "Heat",
                "2": "Cool",
                "3": "Auto"
            },
        },
        "value": 1,
    }
    assert args["value"] == 2
    args = client.async_send_command.call_args_list[1][0][0]
    assert args["command"] == "node.set_value"
    assert args["nodeId"] == 13
    assert args["valueId"] == {
        "commandClassName": "Thermostat Setpoint",
        "commandClass": 67,
        "endpoint": 1,
        "property": "setpoint",
        "propertyKey": 1,
        "propertyName": "setpoint",
        "propertyKeyName": "Heating",
        "metadata": {
            "type": "number",
            "readable": True,
            "writeable": True,
            "unit": "°F",
            "ccSpecific": {
                "setpointType": 1
            },
        },
        "value": 72,
    }
    assert args["value"] == 77

    client.async_send_command.reset_mock()

    # Test cool mode update from value updated event
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 13,
            "args": {
                "commandClassName": "Thermostat Mode",
                "commandClass": 64,
                "endpoint": 1,
                "property": "mode",
                "propertyName": "mode",
                "newValue": 2,
                "prevValue": 1,
            },
        },
    )
    node.receive_event(event)

    state = hass.states.get(CLIMATE_RADIO_THERMOSTAT_ENTITY)
    assert state.state == HVAC_MODE_COOL
    assert state.attributes[ATTR_TEMPERATURE] == 22.8

    # Test heat_cool mode update from value updated event
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 13,
            "args": {
                "commandClassName": "Thermostat Mode",
                "commandClass": 64,
                "endpoint": 1,
                "property": "mode",
                "propertyName": "mode",
                "newValue": 3,
                "prevValue": 1,
            },
        },
    )
    node.receive_event(event)

    state = hass.states.get(CLIMATE_RADIO_THERMOSTAT_ENTITY)
    assert state.state == HVAC_MODE_HEAT_COOL
    assert state.attributes[ATTR_TARGET_TEMP_HIGH] == 22.8
    assert state.attributes[ATTR_TARGET_TEMP_LOW] == 22.2

    client.async_send_command.reset_mock()

    # Test setting temperature with heat_cool
    await hass.services.async_call(
        CLIMATE_DOMAIN,
        SERVICE_SET_TEMPERATURE,
        {
            ATTR_ENTITY_ID: CLIMATE_RADIO_THERMOSTAT_ENTITY,
            ATTR_TARGET_TEMP_HIGH: 30,
            ATTR_TARGET_TEMP_LOW: 25,
        },
        blocking=True,
    )

    assert len(client.async_send_command.call_args_list) == 2
    args = client.async_send_command.call_args_list[0][0][0]
    assert args["command"] == "node.set_value"
    assert args["nodeId"] == 13
    assert args["valueId"] == {
        "commandClassName": "Thermostat Setpoint",
        "commandClass": 67,
        "endpoint": 1,
        "property": "setpoint",
        "propertyKey": 1,
        "propertyName": "setpoint",
        "propertyKeyName": "Heating",
        "metadata": {
            "type": "number",
            "readable": True,
            "writeable": True,
            "unit": "°F",
            "ccSpecific": {
                "setpointType": 1
            },
        },
        "value": 72,
    }
    assert args["value"] == 77

    args = client.async_send_command.call_args_list[1][0][0]
    assert args["command"] == "node.set_value"
    assert args["nodeId"] == 13
    assert args["valueId"] == {
        "commandClassName": "Thermostat Setpoint",
        "commandClass": 67,
        "endpoint": 1,
        "property": "setpoint",
        "propertyKey": 2,
        "propertyName": "setpoint",
        "propertyKeyName": "Cooling",
        "metadata": {
            "type": "number",
            "readable": True,
            "writeable": True,
            "unit": "°F",
            "ccSpecific": {
                "setpointType": 2
            },
        },
        "value": 73,
    }
    assert args["value"] == 86

    client.async_send_command.reset_mock()

    with pytest.raises(ValueError):
        # Test setting unknown preset mode
        await hass.services.async_call(
            CLIMATE_DOMAIN,
            SERVICE_SET_PRESET_MODE,
            {
                ATTR_ENTITY_ID: CLIMATE_RADIO_THERMOSTAT_ENTITY,
                ATTR_PRESET_MODE: "unknown_preset",
            },
            blocking=True,
        )

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

    # Test setting invalid hvac mode
    with pytest.raises(ValueError):
        await hass.services.async_call(
            CLIMATE_DOMAIN,
            SERVICE_SET_HVAC_MODE,
            {
                ATTR_ENTITY_ID: CLIMATE_RADIO_THERMOSTAT_ENTITY,
                ATTR_HVAC_MODE: HVAC_MODE_DRY,
            },
            blocking=True,
        )

    # Test setting invalid preset mode
    with pytest.raises(ValueError):
        await hass.services.async_call(
            CLIMATE_DOMAIN,
            SERVICE_SET_PRESET_MODE,
            {
                ATTR_ENTITY_ID: CLIMATE_RADIO_THERMOSTAT_ENTITY,
                ATTR_PRESET_MODE: "invalid_mode",
            },
            blocking=True,
        )
Esempio n. 17
0
async def test_zwave_js_event(hass, client, lock_schlage_be469, integration):
    """Test for zwave_js.event automation trigger."""
    trigger_type = f"{DOMAIN}.event"
    node: Node = lock_schlage_be469
    dev_reg = async_get_dev_reg(hass)
    device = async_entries_for_config_entry(dev_reg, integration.entry_id)[0]

    node_no_event_data_filter = async_capture_events(
        hass, "node_no_event_data_filter")
    node_event_data_filter = async_capture_events(hass,
                                                  "node_event_data_filter")
    controller_no_event_data_filter = async_capture_events(
        hass, "controller_no_event_data_filter")
    controller_event_data_filter = async_capture_events(
        hass, "controller_event_data_filter")
    driver_no_event_data_filter = async_capture_events(
        hass, "driver_no_event_data_filter")
    driver_event_data_filter = async_capture_events(
        hass, "driver_event_data_filter")
    node_event_data_no_partial_dict_match_filter = async_capture_events(
        hass, "node_event_data_no_partial_dict_match_filter")
    node_event_data_partial_dict_match_filter = async_capture_events(
        hass, "node_event_data_partial_dict_match_filter")

    def clear_events():
        """Clear all events in the event list."""
        node_no_event_data_filter.clear()
        node_event_data_filter.clear()
        controller_no_event_data_filter.clear()
        controller_event_data_filter.clear()
        driver_no_event_data_filter.clear()
        driver_event_data_filter.clear()
        node_event_data_no_partial_dict_match_filter.clear()
        node_event_data_partial_dict_match_filter.clear()

    assert await async_setup_component(
        hass,
        automation.DOMAIN,
        {
            automation.DOMAIN: [
                # node filter: no event data
                {
                    "trigger": {
                        "platform": trigger_type,
                        "entity_id": SCHLAGE_BE469_LOCK_ENTITY,
                        "event_source": "node",
                        "event": "interview stage completed",
                    },
                    "action": {
                        "event": "node_no_event_data_filter",
                    },
                },
                # node filter: event data
                {
                    "trigger": {
                        "platform": trigger_type,
                        "device_id": device.id,
                        "event_source": "node",
                        "event": "interview stage completed",
                        "event_data": {
                            "stageName": "ProtocolInfo"
                        },
                    },
                    "action": {
                        "event": "node_event_data_filter",
                    },
                },
                # controller filter: no event data
                {
                    "trigger": {
                        "platform": trigger_type,
                        "config_entry_id": integration.entry_id,
                        "event_source": "controller",
                        "event": "inclusion started",
                    },
                    "action": {
                        "event": "controller_no_event_data_filter",
                    },
                },
                # controller filter: event data
                {
                    "trigger": {
                        "platform": trigger_type,
                        "config_entry_id": integration.entry_id,
                        "event_source": "controller",
                        "event": "inclusion started",
                        "event_data": {
                            "secure": True
                        },
                    },
                    "action": {
                        "event": "controller_event_data_filter",
                    },
                },
                # driver filter: no event data
                {
                    "trigger": {
                        "platform": trigger_type,
                        "config_entry_id": integration.entry_id,
                        "event_source": "driver",
                        "event": "logging",
                    },
                    "action": {
                        "event": "driver_no_event_data_filter",
                    },
                },
                # driver filter: event data
                {
                    "trigger": {
                        "platform": trigger_type,
                        "config_entry_id": integration.entry_id,
                        "event_source": "driver",
                        "event": "logging",
                        "event_data": {
                            "message": "test"
                        },
                    },
                    "action": {
                        "event": "driver_event_data_filter",
                    },
                },
                # node filter: event data, no partial dict match
                {
                    "trigger": {
                        "platform": trigger_type,
                        "entity_id": SCHLAGE_BE469_LOCK_ENTITY,
                        "event_source": "node",
                        "event": "value updated",
                        "event_data": {
                            "args": {
                                "commandClassName": "Door Lock"
                            }
                        },
                    },
                    "action": {
                        "event":
                        "node_event_data_no_partial_dict_match_filter",
                    },
                },
                # node filter: event data, partial dict match
                {
                    "trigger": {
                        "platform": trigger_type,
                        "entity_id": SCHLAGE_BE469_LOCK_ENTITY,
                        "event_source": "node",
                        "event": "value updated",
                        "event_data": {
                            "args": {
                                "commandClassName": "Door Lock"
                            }
                        },
                        "partial_dict_match": True,
                    },
                    "action": {
                        "event": "node_event_data_partial_dict_match_filter",
                    },
                },
            ]
        },
    )

    # Test that `node no event data filter` is triggered and `node event data filter` is not
    event = Event(
        type="interview stage completed",
        data={
            "source": "node",
            "event": "interview stage completed",
            "stageName": "NodeInfo",
            "nodeId": node.node_id,
        },
    )
    node.receive_event(event)
    await hass.async_block_till_done()

    assert len(node_no_event_data_filter) == 1
    assert len(node_event_data_filter) == 0
    assert len(controller_no_event_data_filter) == 0
    assert len(controller_event_data_filter) == 0
    assert len(driver_no_event_data_filter) == 0
    assert len(driver_event_data_filter) == 0
    assert len(node_event_data_no_partial_dict_match_filter) == 0
    assert len(node_event_data_partial_dict_match_filter) == 0

    clear_events()

    # Test that `node no event data filter` and `node event data filter` are triggered
    event = Event(
        type="interview stage completed",
        data={
            "source": "node",
            "event": "interview stage completed",
            "stageName": "ProtocolInfo",
            "nodeId": node.node_id,
        },
    )
    node.receive_event(event)
    await hass.async_block_till_done()

    assert len(node_no_event_data_filter) == 1
    assert len(node_event_data_filter) == 1
    assert len(controller_no_event_data_filter) == 0
    assert len(controller_event_data_filter) == 0
    assert len(driver_no_event_data_filter) == 0
    assert len(driver_event_data_filter) == 0
    assert len(node_event_data_no_partial_dict_match_filter) == 0
    assert len(node_event_data_partial_dict_match_filter) == 0

    clear_events()

    # Test that `controller no event data filter` is triggered and `controller event data filter` is not
    event = Event(
        type="inclusion started",
        data={
            "source": "controller",
            "event": "inclusion started",
            "secure": False,
        },
    )
    client.driver.controller.receive_event(event)
    await hass.async_block_till_done()

    assert len(node_no_event_data_filter) == 0
    assert len(node_event_data_filter) == 0
    assert len(controller_no_event_data_filter) == 1
    assert len(controller_event_data_filter) == 0
    assert len(driver_no_event_data_filter) == 0
    assert len(driver_event_data_filter) == 0
    assert len(node_event_data_no_partial_dict_match_filter) == 0
    assert len(node_event_data_partial_dict_match_filter) == 0

    clear_events()

    # Test that both `controller no event data filter` and `controller event data filter` are triggered
    event = Event(
        type="inclusion started",
        data={
            "source": "controller",
            "event": "inclusion started",
            "secure": True,
        },
    )
    client.driver.controller.receive_event(event)
    await hass.async_block_till_done()

    assert len(node_no_event_data_filter) == 0
    assert len(node_event_data_filter) == 0
    assert len(controller_no_event_data_filter) == 1
    assert len(controller_event_data_filter) == 1
    assert len(driver_no_event_data_filter) == 0
    assert len(driver_event_data_filter) == 0
    assert len(node_event_data_no_partial_dict_match_filter) == 0
    assert len(node_event_data_partial_dict_match_filter) == 0

    clear_events()

    # Test that `driver no event data filter` is triggered and `driver event data filter` is not
    event = Event(
        type="logging",
        data={
            "source": "driver",
            "event": "logging",
            "message": "no test",
            "formattedMessage": "test",
            "direction": ">",
            "level": "debug",
            "primaryTags": "tag",
            "secondaryTags": "tag2",
            "secondaryTagPadding": 0,
            "multiline": False,
            "timestamp": "time",
            "label": "label",
        },
    )
    client.driver.receive_event(event)
    await hass.async_block_till_done()

    assert len(node_no_event_data_filter) == 0
    assert len(node_event_data_filter) == 0
    assert len(controller_no_event_data_filter) == 0
    assert len(controller_event_data_filter) == 0
    assert len(driver_no_event_data_filter) == 1
    assert len(driver_event_data_filter) == 0
    assert len(node_event_data_no_partial_dict_match_filter) == 0
    assert len(node_event_data_partial_dict_match_filter) == 0

    clear_events()

    # Test that both `driver no event data filter` and `driver event data filter` are triggered
    event = Event(
        type="logging",
        data={
            "source": "driver",
            "event": "logging",
            "message": "test",
            "formattedMessage": "test",
            "direction": ">",
            "level": "debug",
            "primaryTags": "tag",
            "secondaryTags": "tag2",
            "secondaryTagPadding": 0,
            "multiline": False,
            "timestamp": "time",
            "label": "label",
        },
    )
    client.driver.receive_event(event)
    await hass.async_block_till_done()

    assert len(node_no_event_data_filter) == 0
    assert len(node_event_data_filter) == 0
    assert len(controller_no_event_data_filter) == 0
    assert len(controller_event_data_filter) == 0
    assert len(driver_no_event_data_filter) == 1
    assert len(driver_event_data_filter) == 1
    assert len(node_event_data_no_partial_dict_match_filter) == 0
    assert len(node_event_data_partial_dict_match_filter) == 0

    clear_events()

    # Test that only `node with event data and partial match dict filter` is triggered
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": node.node_id,
            "args": {
                "commandClassName": "Door Lock",
                "commandClass": 49,
                "endpoint": 0,
                "property": "latchStatus",
                "newValue": "closed",
                "prevValue": "open",
                "propertyName": "latchStatus",
            },
        },
    )
    node.receive_event(event)
    await hass.async_block_till_done()

    assert len(node_no_event_data_filter) == 0
    assert len(node_event_data_filter) == 0
    assert len(controller_no_event_data_filter) == 0
    assert len(controller_event_data_filter) == 0
    assert len(driver_no_event_data_filter) == 0
    assert len(driver_event_data_filter) == 0
    assert len(node_event_data_no_partial_dict_match_filter) == 0
    assert len(node_event_data_partial_dict_match_filter) == 1

    clear_events()

    # Test that `node with event data and partial match dict filter` is not triggered
    # when partial dict doesn't match
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": node.node_id,
            "args": {
                "commandClassName": "fake command class name",
                "commandClass": 49,
                "endpoint": 0,
                "property": "latchStatus",
                "newValue": "closed",
                "prevValue": "open",
                "propertyName": "latchStatus",
            },
        },
    )
    node.receive_event(event)
    await hass.async_block_till_done()

    assert len(node_no_event_data_filter) == 0
    assert len(node_event_data_filter) == 0
    assert len(controller_no_event_data_filter) == 0
    assert len(controller_event_data_filter) == 0
    assert len(driver_no_event_data_filter) == 0
    assert len(driver_event_data_filter) == 0
    assert len(node_event_data_no_partial_dict_match_filter) == 0
    assert len(node_event_data_partial_dict_match_filter) == 0

    clear_events()

    with patch("homeassistant.config.load_yaml", return_value={}):
        await hass.services.async_call(automation.DOMAIN,
                                       SERVICE_RELOAD,
                                       blocking=True)
Esempio n. 18
0
async def test_setpoint_thermostat(hass, client, climate_danfoss_lc_13,
                                   integration):
    """Test a setpoint thermostat command class entity."""
    node = climate_danfoss_lc_13
    state = hass.states.get(CLIMATE_DANFOSS_LC13_ENTITY)

    assert state
    assert state.state == HVAC_MODE_HEAT
    assert state.attributes[ATTR_TEMPERATURE] == 25
    assert state.attributes[ATTR_HVAC_MODES] == [HVAC_MODE_HEAT]
    assert state.attributes[ATTR_PRESET_MODE] == PRESET_NONE

    client.async_send_command.reset_mock()

    # Test setting temperature
    await hass.services.async_call(
        CLIMATE_DOMAIN,
        SERVICE_SET_TEMPERATURE,
        {
            ATTR_ENTITY_ID: CLIMATE_DANFOSS_LC13_ENTITY,
            ATTR_TEMPERATURE: 21.5,
        },
        blocking=True,
    )

    assert len(client.async_send_command.call_args_list) == 1
    args = client.async_send_command.call_args_list[0][0][0]
    assert args["command"] == "node.set_value"
    assert args["nodeId"] == 5
    assert args["valueId"] == {
        "endpoint": 0,
        "commandClass": 67,
        "commandClassName": "Thermostat Setpoint",
        "property": "setpoint",
        "propertyName": "setpoint",
        "propertyKeyName": "Heating",
        "ccVersion": 2,
        "metadata": {
            "type": "number",
            "readable": True,
            "writeable": True,
            "unit": "\u00b0C",
            "ccSpecific": {
                "setpointType": 1
            },
        },
        "value": 25,
    }
    assert args["value"] == 21.5

    client.async_send_command.reset_mock()

    # Test setpoint mode update from value updated event
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 5,
            "args": {
                "commandClassName": "Thermostat Setpoint",
                "commandClass": 67,
                "endpoint": 0,
                "property": "setpoint",
                "propertyKey": 1,
                "propertyKeyName": "Heating",
                "propertyName": "setpoint",
                "newValue": 23,
                "prevValue": 21.5,
            },
        },
    )
    node.receive_event(event)

    state = hass.states.get(CLIMATE_DANFOSS_LC13_ENTITY)
    assert state.state == HVAC_MODE_HEAT
    assert state.attributes[ATTR_TEMPERATURE] == 23

    client.async_send_command.reset_mock()
Esempio n. 19
0
async def test_number(hass, client, aeotec_radiator_thermostat, integration):
    """Test the number entity."""
    node = aeotec_radiator_thermostat
    state = hass.states.get(NUMBER_ENTITY)

    assert state
    assert state.state == "75.0"

    # Test turn on setting value
    await hass.services.async_call(
        "number",
        "set_value",
        {
            "entity_id": NUMBER_ENTITY,
            "value": 30
        },
        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"] == 4
    assert args["valueId"] == {
        "commandClassName": "Multilevel Switch",
        "commandClass": 38,
        "ccVersion": 1,
        "endpoint": 0,
        "property": "targetValue",
        "propertyName": "targetValue",
        "metadata": {
            "label": "Target value",
            "max": 99,
            "min": 0,
            "type": "number",
            "readable": True,
            "writeable": True,
            "label": "Target value",
        },
    }
    assert args["value"] == 30.0

    client.async_send_command_no_wait.reset_mock()

    # Test value update from value updated event
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 4,
            "args": {
                "commandClassName": "Multilevel Switch",
                "commandClass": 38,
                "endpoint": 0,
                "property": "currentValue",
                "newValue": 99,
                "prevValue": 0,
                "propertyName": "currentValue",
            },
        },
    )
    node.receive_event(event)

    state = hass.states.get(NUMBER_ENTITY)
    assert state.state == "99.0"
Esempio n. 20
0
async def test_generic_fan(hass, client, fan_generic, integration):
    """Test the fan entity for a generic fan that lacks specific speed configuration."""
    node = fan_generic
    entity_id = "fan.generic_fan_controller"
    state = hass.states.get(entity_id)

    assert state
    assert state.state == "off"

    # Test turn on setting speed
    await hass.services.async_call(
        "fan",
        "turn_on",
        {"entity_id": entity_id, "percentage": 66},
        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"] == 17
    assert args["valueId"] == {
        "commandClassName": "Multilevel Switch",
        "commandClass": 38,
        "endpoint": 0,
        "property": "targetValue",
        "propertyName": "targetValue",
        "metadata": {
            "label": "Target value",
            "max": 99,
            "min": 0,
            "type": "number",
            "readable": True,
            "writeable": True,
        },
    }
    assert args["value"] == 66

    client.async_send_command.reset_mock()

    # Test setting unknown speed
    with pytest.raises(MultipleInvalid):
        await hass.services.async_call(
            "fan",
            "set_percentage",
            {"entity_id": entity_id, "percentage": "bad"},
            blocking=True,
        )

    client.async_send_command.reset_mock()

    # Test turn on no speed
    await hass.services.async_call(
        "fan",
        "turn_on",
        {"entity_id": entity_id},
        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"] == 17
    assert args["valueId"] == {
        "commandClassName": "Multilevel Switch",
        "commandClass": 38,
        "endpoint": 0,
        "property": "targetValue",
        "propertyName": "targetValue",
        "metadata": {
            "label": "Target value",
            "max": 99,
            "min": 0,
            "type": "number",
            "readable": True,
            "writeable": True,
        },
    }
    assert args["value"] == 255

    client.async_send_command.reset_mock()

    # Test turning off
    await hass.services.async_call(
        "fan",
        "turn_off",
        {"entity_id": entity_id},
        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"] == 17
    assert args["valueId"] == {
        "commandClassName": "Multilevel Switch",
        "commandClass": 38,
        "endpoint": 0,
        "property": "targetValue",
        "propertyName": "targetValue",
        "metadata": {
            "label": "Target value",
            "max": 99,
            "min": 0,
            "type": "number",
            "readable": True,
            "writeable": True,
        },
    }
    assert args["value"] == 0

    client.async_send_command.reset_mock()

    # Test speed update from value updated event
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 17,
            "args": {
                "commandClassName": "Multilevel Switch",
                "commandClass": 38,
                "endpoint": 0,
                "property": "currentValue",
                "newValue": 99,
                "prevValue": 0,
                "propertyName": "currentValue",
            },
        },
    )
    node.receive_event(event)

    state = hass.states.get(entity_id)
    assert state.state == "on"
    assert state.attributes[ATTR_PERCENTAGE] == 100

    client.async_send_command.reset_mock()

    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 17,
            "args": {
                "commandClassName": "Multilevel Switch",
                "commandClass": 38,
                "endpoint": 0,
                "property": "currentValue",
                "newValue": 0,
                "prevValue": 0,
                "propertyName": "currentValue",
            },
        },
    )
    node.receive_event(event)

    state = hass.states.get(entity_id)
    assert state.state == "off"
    assert state.attributes[ATTR_PERCENTAGE] == 0
Esempio n. 21
0
async def test_notifications(hass, hank_binary_switch, integration, client):
    """Test notification events."""
    # just pick a random node to fake the value notification events
    node = hank_binary_switch
    events = async_capture_events(hass, "zwave_js_notification")

    # Publish fake Notification CC notification
    event = Event(
        type="notification",
        data={
            "source": "node",
            "event": "notification",
            "nodeId": 32,
            "ccId": 113,
            "args": {
                "type": 6,
                "event": 5,
                "label": "Access Control",
                "eventLabel": "Keypad lock operation",
                "parameters": {
                    "userId": 1
                },
            },
        },
    )
    node.receive_event(event)
    # wait for the event
    await hass.async_block_till_done()
    assert len(events) == 1
    assert events[0].data["home_id"] == client.driver.controller.home_id
    assert events[0].data["node_id"] == 32
    assert events[0].data["type"] == 6
    assert events[0].data["event"] == 5
    assert events[0].data["label"] == "Access Control"
    assert events[0].data["event_label"] == "Keypad lock operation"
    assert events[0].data["parameters"]["userId"] == 1
    assert events[0].data["command_class"] == CommandClass.NOTIFICATION
    assert events[0].data["command_class_name"] == "Notification"

    # Publish fake Entry Control CC notification
    event = Event(
        type="notification",
        data={
            "source": "node",
            "event": "notification",
            "nodeId": 32,
            "ccId": 111,
            "args": {
                "eventType": 5,
                "dataType": 2,
                "eventData": "555"
            },
        },
    )

    node.receive_event(event)
    # wait for the event
    await hass.async_block_till_done()
    assert len(events) == 2
    assert events[1].data["home_id"] == client.driver.controller.home_id
    assert events[1].data["node_id"] == 32
    assert events[1].data["event_type"] == 5
    assert events[1].data["data_type"] == 2
    assert events[1].data["event_data"] == "555"
    assert events[1].data["command_class"] == CommandClass.ENTRY_CONTROL
    assert events[1].data["command_class_name"] == "Entry Control"

    # Publish fake Multilevel Switch CC notification
    event = Event(
        type="notification",
        data={
            "source": "node",
            "event": "notification",
            "nodeId": 32,
            "ccId": 38,
            "args": {
                "eventType": 4,
                "direction": "up"
            },
        },
    )

    node.receive_event(event)
    # wait for the event
    await hass.async_block_till_done()
    assert len(events) == 3
    assert events[2].data["home_id"] == client.driver.controller.home_id
    assert events[2].data["node_id"] == 32
    assert events[2].data["event_type"] == 4
    assert events[2].data["direction"] == "up"
    assert events[2].data["command_class"] == CommandClass.SWITCH_MULTILEVEL
    assert events[2].data["command_class_name"] == "Multilevel Switch"
Esempio n. 22
0
async def test_thermostat_fan(hass, client, climate_adc_t3000, integration):
    """Test the fan entity for a z-wave fan."""
    node = climate_adc_t3000
    entity_id = "fan.adc_t3000"

    registry = entity_registry.async_get(hass)
    state = hass.states.get(entity_id)
    assert state is None

    entry = registry.async_get(entity_id)
    assert entry
    assert entry.disabled
    assert entry.disabled_by is entity_registry.RegistryEntryDisabler.INTEGRATION

    # Test enabling entity
    updated_entry = registry.async_update_entity(entity_id, disabled_by=None)
    assert updated_entry != entry
    assert updated_entry.disabled is False

    await hass.config_entries.async_reload(integration.entry_id)
    await hass.async_block_till_done()

    state = hass.states.get(entity_id)
    assert state
    assert state.state == STATE_ON
    assert state.attributes.get(ATTR_FAN_STATE) == "Idle / off"
    assert state.attributes.get(ATTR_PRESET_MODE) == "Auto low"
    assert state.attributes.get(ATTR_SUPPORTED_FEATURES) == SUPPORT_PRESET_MODE

    # Test setting preset mode
    await hass.services.async_call(
        FAN_DOMAIN,
        SERVICE_SET_PRESET_MODE,
        {ATTR_ENTITY_ID: entity_id, ATTR_PRESET_MODE: "Low"},
        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"] == 68
    assert args["valueId"] == {
        "ccVersion": 3,
        "commandClassName": "Thermostat Fan Mode",
        "commandClass": CommandClass.THERMOSTAT_FAN_MODE.value,
        "endpoint": 0,
        "property": "mode",
        "propertyName": "mode",
        "metadata": {
            "label": "Thermostat fan mode",
            "max": 255,
            "min": 0,
            "type": "number",
            "readable": True,
            "writeable": True,
            "states": {"0": "Auto low", "1": "Low", "6": "Circulation"},
        },
        "value": 0,
    }
    assert args["value"] == 1

    client.async_send_command.reset_mock()

    # Test setting unknown preset mode
    with pytest.raises(ValueError):
        await hass.services.async_call(
            FAN_DOMAIN,
            SERVICE_SET_PRESET_MODE,
            {ATTR_ENTITY_ID: entity_id, ATTR_PRESET_MODE: "Turbo"},
            blocking=True,
        )

    client.async_send_command.reset_mock()

    # Test turning off
    await hass.services.async_call(
        FAN_DOMAIN,
        SERVICE_TURN_OFF,
        {ATTR_ENTITY_ID: entity_id},
        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"] == 68
    assert args["valueId"] == {
        "ccVersion": 3,
        "commandClassName": "Thermostat Fan Mode",
        "commandClass": CommandClass.THERMOSTAT_FAN_MODE.value,
        "endpoint": 0,
        "property": "off",
        "propertyName": "off",
        "metadata": {
            "label": "Thermostat fan turned off",
            "type": "boolean",
            "readable": True,
            "writeable": True,
        },
        "value": False,
    }
    assert args["value"]

    client.async_send_command.reset_mock()

    # Test turning on
    await hass.services.async_call(
        FAN_DOMAIN,
        SERVICE_TURN_ON,
        {ATTR_ENTITY_ID: entity_id},
        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"] == 68
    assert args["valueId"] == {
        "ccVersion": 3,
        "commandClassName": "Thermostat Fan Mode",
        "commandClass": CommandClass.THERMOSTAT_FAN_MODE.value,
        "endpoint": 0,
        "property": "off",
        "propertyName": "off",
        "metadata": {
            "label": "Thermostat fan turned off",
            "type": "boolean",
            "readable": True,
            "writeable": True,
        },
        "value": False,
    }
    assert not args["value"]

    client.async_send_command.reset_mock()

    # Test fan state update from value updated event
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 68,
            "args": {
                "commandClassName": "Thermostat Fan State",
                "commandClass": CommandClass.THERMOSTAT_FAN_STATE.value,
                "endpoint": 0,
                "property": "state",
                "newValue": 4,
                "prevValue": 0,
                "propertyName": "state",
            },
        },
    )
    node.receive_event(event)

    state = hass.states.get(entity_id)
    assert state.attributes.get(ATTR_FAN_STATE) == "Circulation mode"

    client.async_send_command.reset_mock()

    # Test unknown fan state update from value updated event
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 68,
            "args": {
                "commandClassName": "Thermostat Fan State",
                "commandClass": CommandClass.THERMOSTAT_FAN_STATE.value,
                "endpoint": 0,
                "property": "state",
                "newValue": 99,
                "prevValue": 0,
                "propertyName": "state",
            },
        },
    )
    node.receive_event(event)

    state = hass.states.get(entity_id)
    assert not state.attributes.get(ATTR_FAN_STATE)

    client.async_send_command.reset_mock()

    # Test fan mode update from value updated event
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 68,
            "args": {
                "commandClassName": "Thermostat Fan Mode",
                "commandClass": CommandClass.THERMOSTAT_FAN_MODE.value,
                "endpoint": 0,
                "property": "mode",
                "newValue": 1,
                "prevValue": 0,
                "propertyName": "mode",
            },
        },
    )
    node.receive_event(event)

    state = hass.states.get(entity_id)
    assert state.attributes.get(ATTR_PRESET_MODE) == "Low"

    client.async_send_command.reset_mock()

    # Test fan mode update from value updated event for an unknown mode
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 68,
            "args": {
                "commandClassName": "Thermostat Fan Mode",
                "commandClass": CommandClass.THERMOSTAT_FAN_MODE.value,
                "endpoint": 0,
                "property": "mode",
                "newValue": 79,
                "prevValue": 0,
                "propertyName": "mode",
            },
        },
    )
    node.receive_event(event)

    state = hass.states.get(entity_id)
    assert not state.attributes.get(ATTR_PRESET_MODE)

    client.async_send_command.reset_mock()

    # Test fan mode turned off update from value updated event
    event = Event(
        type="value updated",
        data={
            "source": "node",
            "event": "value updated",
            "nodeId": 68,
            "args": {
                "commandClassName": "Thermostat Fan Mode",
                "commandClass": CommandClass.THERMOSTAT_FAN_MODE.value,
                "endpoint": 0,
                "property": "off",
                "newValue": True,
                "prevValue": False,
                "propertyName": "off",
            },
        },
    )
    node.receive_event(event)

    state = hass.states.get(entity_id)
    assert state.state == STATE_OFF
Esempio n. 23
0
def nortek_thermostat_added_event_fixture(client):
    """Mock a Nortek thermostat node added event."""
    event_data = json.loads(
        load_fixture("zwave_js/nortek_thermostat_added_event.json"))
    event = Event("node added", event_data)
    return event
Esempio n. 24
0
async def test_node_status_sensor(hass, client, controller_node,
                                  lock_id_lock_as_id150, integration):
    """Test node status sensor is created and gets updated on node state changes."""
    NODE_STATUS_ENTITY = "sensor.z_wave_module_for_id_lock_150_and_101_node_status"
    node = lock_id_lock_as_id150
    ent_reg = er.async_get(hass)
    entity_entry = ent_reg.async_get(NODE_STATUS_ENTITY)

    assert not entity_entry.disabled
    assert entity_entry.entity_category is EntityCategory.DIAGNOSTIC
    assert hass.states.get(NODE_STATUS_ENTITY).state == "alive"

    # Test transitions work
    event = Event("dead",
                  data={
                      "source": "node",
                      "event": "dead",
                      "nodeId": node.node_id
                  })
    node.receive_event(event)
    assert hass.states.get(NODE_STATUS_ENTITY).state == "dead"
    assert hass.states.get(
        NODE_STATUS_ENTITY).attributes[ATTR_ICON] == "mdi:robot-dead"

    event = Event("wake up",
                  data={
                      "source": "node",
                      "event": "wake up",
                      "nodeId": node.node_id
                  })
    node.receive_event(event)
    assert hass.states.get(NODE_STATUS_ENTITY).state == "awake"
    assert hass.states.get(
        NODE_STATUS_ENTITY).attributes[ATTR_ICON] == "mdi:eye"

    event = Event("sleep",
                  data={
                      "source": "node",
                      "event": "sleep",
                      "nodeId": node.node_id
                  })
    node.receive_event(event)
    assert hass.states.get(NODE_STATUS_ENTITY).state == "asleep"
    assert hass.states.get(
        NODE_STATUS_ENTITY).attributes[ATTR_ICON] == "mdi:sleep"

    event = Event("alive",
                  data={
                      "source": "node",
                      "event": "alive",
                      "nodeId": node.node_id
                  })
    node.receive_event(event)
    assert hass.states.get(NODE_STATUS_ENTITY).state == "alive"
    assert (hass.states.get(NODE_STATUS_ENTITY).attributes[ATTR_ICON] ==
            "mdi:heart-pulse")

    # Disconnect the client and make sure the entity is still available
    await client.disconnect()
    assert hass.states.get(NODE_STATUS_ENTITY).state != STATE_UNAVAILABLE

    # Assert a node status sensor entity is not created for the controller
    node = client.driver.controller.nodes[1]
    assert node.is_controller_node
    assert (ent_reg.async_get_entity_id(
        DOMAIN,
        "sensor",
        f"{get_valueless_base_unique_id(client, node)}.node_status",
    ) is None)