"""Test the Z-Wave JS fan platform.""" import math import pytest from zwave_js_server.event import Event from homeassistant.components.fan import ( ATTR_PERCENTAGE, ATTR_PERCENTAGE_STEP, ATTR_SPEED, SPEED_MEDIUM, ) 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, "speed": SPEED_MEDIUM}, 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, "label": "Target value", }, } assert args["value"] == 66 client.async_send_command.reset_mock() # Test setting unknown speed with pytest.raises(ValueError): await hass.services.async_call( "fan", "set_speed", {"entity_id": entity_id, "speed": 99}, 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, "label": "Target value", }, } 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, "label": "Target value", }, } 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_SPEED] == "high" 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_SPEED] == "off" async def test_configurable_speeds_fan(hass, client, hs_fc200, integration): """Test a fan entity with configurable speeds.""" node = hs_fc200 node_id = 39 entity_id = "fan.scene_capable_fan_control_switch" async def get_zwave_speed_from_percentage(percentage): """Set the fan to a particular percentage and get the resulting Zwave speed.""" client.async_send_command.reset_mock() await hass.services.async_call( "fan", "turn_on", {"entity_id": entity_id, "percentage": percentage}, 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_id return args["value"] async def get_percentage_from_zwave_speed(zwave_speed): """Set the underlying device speed and get the resulting percentage.""" event = Event( type="value updated", data={ "source": "node", "event": "value updated", "nodeId": node_id, "args": { "commandClassName": "Multilevel Switch", "commandClass": 38, "endpoint": 0, "property": "currentValue", "newValue": zwave_speed, "prevValue": 0, "propertyName": "currentValue", }, }, ) node.receive_event(event) state = hass.states.get(entity_id) return state.attributes[ATTR_PERCENTAGE] # In 3-speed mode, the speeds are: # low = 1-33, med=34-66, high=67-99 percentages_to_zwave_speeds = [ [[0], [0]], [range(1, 34), range(1, 34)], [range(34, 68), range(34, 67)], [range(68, 101), range(67, 100)], ] for percentages, zwave_speeds in percentages_to_zwave_speeds: for percentage in percentages: actual_zwave_speed = await get_zwave_speed_from_percentage(percentage) assert actual_zwave_speed in zwave_speeds for zwave_speed in zwave_speeds: actual_percentage = await get_percentage_from_zwave_speed(zwave_speed) assert actual_percentage in percentages state = hass.states.get(entity_id) assert math.isclose(state.attributes[ATTR_PERCENTAGE_STEP], 33.3333, rel_tol=1e-3) async def test_fixed_speeds_fan(hass, client, ge_12730, integration): """Test a fan entity with fixed speeds.""" node = ge_12730 node_id = 24 entity_id = "fan.in_wall_smart_fan_control" async def get_zwave_speed_from_percentage(percentage): """Set the fan to a particular percentage and get the resulting Zwave speed.""" client.async_send_command.reset_mock() await hass.services.async_call( "fan", "turn_on", {"entity_id": entity_id, "percentage": percentage}, 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_id return args["value"] async def get_percentage_from_zwave_speed(zwave_speed): """Set the underlying device speed and get the resulting percentage.""" event = Event( type="value updated", data={ "source": "node", "event": "value updated", "nodeId": node_id, "args": { "commandClassName": "Multilevel Switch", "commandClass": 38, "endpoint": 0, "property": "currentValue", "newValue": zwave_speed, "prevValue": 0, "propertyName": "currentValue", }, }, ) node.receive_event(event) state = hass.states.get(entity_id) return state.attributes[ATTR_PERCENTAGE] # This device has the speeds: # low = 1-33, med = 34-67, high = 68-99 percentages_to_zwave_speeds = [ [[0], [0]], [range(1, 34), range(1, 34)], [range(34, 68), range(34, 68)], [range(68, 101), range(68, 100)], ] for percentages, zwave_speeds in percentages_to_zwave_speeds: for percentage in percentages: actual_zwave_speed = await get_zwave_speed_from_percentage(percentage) assert actual_zwave_speed in zwave_speeds for zwave_speed in zwave_speeds: actual_percentage = await get_percentage_from_zwave_speed(zwave_speed) assert actual_percentage in percentages state = hass.states.get(entity_id) assert math.isclose(state.attributes[ATTR_PERCENTAGE_STEP], 33.3333, rel_tol=1e-3)