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
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"
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"]
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
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
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
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
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"
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()
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"
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)
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"
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)
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)
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, )
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)
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()
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"
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
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"
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
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
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)