diff --git a/homeassistant/components/shelly/sensor.py b/homeassistant/components/shelly/sensor.py index 1ef174119e4..ea1a6801a89 100644 --- a/homeassistant/components/shelly/sensor.py +++ b/homeassistant/components/shelly/sensor.py @@ -1066,7 +1066,7 @@ RPC_SENSORS: Final = { "analoginput": RpcSensorDescription( key="input", sub_key="percent", - name="Analog input", + name="analog", native_unit_of_measurement=PERCENTAGE, state_class=SensorStateClass.MEASUREMENT, removal_condition=lambda config, _, key: ( @@ -1076,7 +1076,7 @@ RPC_SENSORS: Final = { "analoginput_xpercent": RpcSensorDescription( key="input", sub_key="xpercent", - name="Analog value", + name="analog value", removal_condition=lambda config, status, key: ( config[key]["type"] != "analog" or config[key]["enable"] is False @@ -1087,7 +1087,7 @@ RPC_SENSORS: Final = { "pulse_counter": RpcSensorDescription( key="input", sub_key="counts", - name="Pulse counter", + name="pulse counter", native_unit_of_measurement="pulse", state_class=SensorStateClass.TOTAL, value=lambda status, _: status["total"], @@ -1098,7 +1098,7 @@ RPC_SENSORS: Final = { "counter_value": RpcSensorDescription( key="input", sub_key="counts", - name="Counter value", + name="counter value", value=lambda status, _: status["xtotal"], removal_condition=lambda config, status, key: ( config[key]["type"] != "count" @@ -1110,7 +1110,7 @@ RPC_SENSORS: Final = { "counter_frequency": RpcSensorDescription( key="input", sub_key="freq", - name="Pulse counter frequency", + name="pulse counter frequency", native_unit_of_measurement=UnitOfFrequency.HERTZ, state_class=SensorStateClass.MEASUREMENT, removal_condition=lambda config, _, key: ( @@ -1120,7 +1120,7 @@ RPC_SENSORS: Final = { "counter_frequency_value": RpcSensorDescription( key="input", sub_key="xfreq", - name="Pulse counter frequency value", + name="pulse counter frequency value", removal_condition=lambda config, status, key: ( config[key]["type"] != "count" or config[key]["enable"] is False diff --git a/homeassistant/components/shelly/utils.py b/homeassistant/components/shelly/utils.py index d0a8a1230c5..d05943df764 100644 --- a/homeassistant/components/shelly/utils.py +++ b/homeassistant/components/shelly/utils.py @@ -319,15 +319,19 @@ def get_rpc_channel_name(device: RpcDevice, key: str) -> str: device_name = device.name entity_name: str | None = None if key in device.config: - entity_name = device.config[key].get("name", device_name) + entity_name = device.config[key].get("name") if entity_name is None: - if key.startswith(("input:", "light:", "switch:")): - return f"{device_name} {key.replace(':', '_')}" + channel = key.split(":")[0] + channel_id = key.split(":")[-1] + if key.startswith(("cover:", "input:", "light:", "switch:", "thermostat:")): + return f"{device_name} {channel.title()} {channel_id}" + if key.startswith(("rgb:", "rgbw:")): + return f"{device_name} {channel.upper()} light {channel_id}" if key.startswith("em1"): - return f"{device_name} EM{key.split(':')[-1]}" + return f"{device_name} EM{channel_id}" if key.startswith(("boolean:", "enum:", "number:", "text:")): - return key.replace(":", " ").title() + return f"{channel.title()} {channel_id}" return device_name return entity_name diff --git a/tests/components/shelly/test_climate.py b/tests/components/shelly/test_climate.py index 1156d7e0ed5..997cf945626 100644 --- a/tests/components/shelly/test_climate.py +++ b/tests/components/shelly/test_climate.py @@ -609,23 +609,25 @@ async def test_rpc_climate_hvac_mode( monkeypatch: pytest.MonkeyPatch, ) -> None: """Test climate hvac mode service.""" + entity_id = "climate.test_name_thermostat_0" + await init_integration(hass, 2, model=MODEL_WALL_DISPLAY) - state = hass.states.get(ENTITY_ID) + state = hass.states.get(entity_id) assert state.state == HVACMode.HEAT assert state.attributes[ATTR_TEMPERATURE] == 23 assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 12.3 assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.HEATING assert state.attributes[ATTR_CURRENT_HUMIDITY] == 44.4 - entry = entity_registry.async_get(ENTITY_ID) + entry = entity_registry.async_get(entity_id) assert entry assert entry.unique_id == "123456789ABC-thermostat:0" monkeypatch.setitem(mock_rpc_device.status["thermostat:0"], "output", False) mock_rpc_device.mock_update() - state = hass.states.get(ENTITY_ID) + state = hass.states.get(entity_id) assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.IDLE assert state.attributes[ATTR_CURRENT_HUMIDITY] == 44.4 @@ -633,7 +635,7 @@ async def test_rpc_climate_hvac_mode( await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_HVAC_MODE, - {ATTR_ENTITY_ID: ENTITY_ID, ATTR_HVAC_MODE: HVACMode.OFF}, + {ATTR_ENTITY_ID: entity_id, ATTR_HVAC_MODE: HVACMode.OFF}, blocking=True, ) mock_rpc_device.mock_update() @@ -641,7 +643,7 @@ async def test_rpc_climate_hvac_mode( mock_rpc_device.call_rpc.assert_called_once_with( "Thermostat.SetConfig", {"config": {"id": 0, "enable": False}} ) - state = hass.states.get(ENTITY_ID) + state = hass.states.get(entity_id) assert state.state == HVACMode.OFF @@ -652,20 +654,21 @@ async def test_rpc_climate_without_humidity( monkeypatch: pytest.MonkeyPatch, ) -> None: """Test climate entity without the humidity value.""" + entity_id = "climate.test_name_thermostat_0" new_status = deepcopy(mock_rpc_device.status) new_status.pop("humidity:0") monkeypatch.setattr(mock_rpc_device, "status", new_status) await init_integration(hass, 2, model=MODEL_WALL_DISPLAY) - state = hass.states.get(ENTITY_ID) + state = hass.states.get(entity_id) assert state.state == HVACMode.HEAT assert state.attributes[ATTR_TEMPERATURE] == 23 assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 12.3 assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.HEATING assert ATTR_CURRENT_HUMIDITY not in state.attributes - entry = entity_registry.async_get(ENTITY_ID) + entry = entity_registry.async_get(entity_id) assert entry assert entry.unique_id == "123456789ABC-thermostat:0" @@ -674,9 +677,11 @@ async def test_rpc_climate_set_temperature( hass: HomeAssistant, mock_rpc_device: Mock, monkeypatch: pytest.MonkeyPatch ) -> None: """Test climate set target temperature.""" + entity_id = "climate.test_name_thermostat_0" + await init_integration(hass, 2, model=MODEL_WALL_DISPLAY) - state = hass.states.get(ENTITY_ID) + state = hass.states.get(entity_id) assert state.attributes[ATTR_TEMPERATURE] == 23 # test set temperature without target temperature @@ -684,7 +689,7 @@ async def test_rpc_climate_set_temperature( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, { - ATTR_ENTITY_ID: ENTITY_ID, + ATTR_ENTITY_ID: entity_id, ATTR_TARGET_TEMP_LOW: 20, ATTR_TARGET_TEMP_HIGH: 30, }, @@ -696,7 +701,7 @@ async def test_rpc_climate_set_temperature( await hass.services.async_call( CLIMATE_DOMAIN, SERVICE_SET_TEMPERATURE, - {ATTR_ENTITY_ID: ENTITY_ID, ATTR_TEMPERATURE: 28}, + {ATTR_ENTITY_ID: entity_id, ATTR_TEMPERATURE: 28}, blocking=True, ) mock_rpc_device.mock_update() @@ -704,7 +709,7 @@ async def test_rpc_climate_set_temperature( mock_rpc_device.call_rpc.assert_called_once_with( "Thermostat.SetConfig", {"config": {"id": 0, "target_C": 28}} ) - state = hass.states.get(ENTITY_ID) + state = hass.states.get(entity_id) assert state.attributes[ATTR_TEMPERATURE] == 28 @@ -712,13 +717,14 @@ async def test_rpc_climate_hvac_mode_cool( hass: HomeAssistant, mock_rpc_device: Mock, monkeypatch: pytest.MonkeyPatch ) -> None: """Test climate with hvac mode cooling.""" + entity_id = "climate.test_name_thermostat_0" new_config = deepcopy(mock_rpc_device.config) new_config["thermostat:0"]["type"] = "cooling" monkeypatch.setattr(mock_rpc_device, "config", new_config) await init_integration(hass, 2, model=MODEL_WALL_DISPLAY) - state = hass.states.get(ENTITY_ID) + state = hass.states.get(entity_id) assert state.state == HVACMode.COOL assert state.attributes[ATTR_HVAC_ACTION] == HVACAction.COOLING @@ -730,7 +736,7 @@ async def test_wall_display_thermostat_mode( monkeypatch: pytest.MonkeyPatch, ) -> None: """Test Wall Display in thermostat mode.""" - climate_entity_id = "climate.test_name" + climate_entity_id = "climate.test_name_thermostat_0" switch_entity_id = "switch.test_switch_0" await init_integration(hass, 2, model=MODEL_WALL_DISPLAY) @@ -757,7 +763,7 @@ async def test_wall_display_thermostat_mode_external_actuator( monkeypatch: pytest.MonkeyPatch, ) -> None: """Test Wall Display in thermostat mode with an external actuator.""" - climate_entity_id = "climate.test_name" + climate_entity_id = "climate.test_name_thermostat_0" switch_entity_id = "switch.test_switch_0" new_status = deepcopy(mock_rpc_device.status) diff --git a/tests/components/shelly/test_sensor.py b/tests/components/shelly/test_sensor.py index ef8a609998a..18c3d874c55 100644 --- a/tests/components/shelly/test_sensor.py +++ b/tests/components/shelly/test_sensor.py @@ -729,14 +729,14 @@ async def test_rpc_analog_input_sensors( await init_integration(hass, 2) - entity_id = f"{SENSOR_DOMAIN}.test_name_analog_input" + entity_id = f"{SENSOR_DOMAIN}.test_name_input_1_analog" assert hass.states.get(entity_id).state == "89" entry = entity_registry.async_get(entity_id) assert entry assert entry.unique_id == "123456789ABC-input:1-analoginput" - entity_id = f"{SENSOR_DOMAIN}.test_name_analog_value" + entity_id = f"{SENSOR_DOMAIN}.test_name_input_1_analog_value" state = hass.states.get(entity_id) assert state assert state.state == "8.9" @@ -757,10 +757,10 @@ async def test_rpc_disabled_analog_input_sensors( await init_integration(hass, 2) - entity_id = f"{SENSOR_DOMAIN}.test_name_analog_input" + entity_id = f"{SENSOR_DOMAIN}.test_name_input_1_analog" assert hass.states.get(entity_id) is None - entity_id = f"{SENSOR_DOMAIN}.test_name_analog_value" + entity_id = f"{SENSOR_DOMAIN}.test_name_input_1_analog_value" assert hass.states.get(entity_id) is None @@ -777,10 +777,10 @@ async def test_rpc_disabled_xpercent( ) await init_integration(hass, 2) - entity_id = f"{SENSOR_DOMAIN}.test_name_analog_input" + entity_id = f"{SENSOR_DOMAIN}.test_name_input_1_analog" assert hass.states.get(entity_id).state == "89" - entity_id = f"{SENSOR_DOMAIN}.test_name_analog_value" + entity_id = f"{SENSOR_DOMAIN}.test_name_input_1_analog_value" assert hass.states.get(entity_id) is None @@ -1293,7 +1293,7 @@ async def test_rpc_rgbw_sensors( await init_integration(hass, 2) - entity_id = "sensor.test_name_power" + entity_id = f"sensor.test_name_{light_type}_light_0_power" state = hass.states.get(entity_id) assert state @@ -1304,7 +1304,7 @@ async def test_rpc_rgbw_sensors( assert entry assert entry.unique_id == f"123456789ABC-{light_type}:0-power_{light_type}" - entity_id = "sensor.test_name_energy" + entity_id = f"sensor.test_name_{light_type}_light_0_energy" state = hass.states.get(entity_id) assert state @@ -1315,7 +1315,7 @@ async def test_rpc_rgbw_sensors( assert entry assert entry.unique_id == f"123456789ABC-{light_type}:0-energy_{light_type}" - entity_id = "sensor.test_name_current" + entity_id = f"sensor.test_name_{light_type}_light_0_current" state = hass.states.get(entity_id) assert state @@ -1328,7 +1328,7 @@ async def test_rpc_rgbw_sensors( assert entry assert entry.unique_id == f"123456789ABC-{light_type}:0-current_{light_type}" - entity_id = "sensor.test_name_voltage" + entity_id = f"sensor.test_name_{light_type}_light_0_voltage" state = hass.states.get(entity_id) assert state @@ -1341,7 +1341,7 @@ async def test_rpc_rgbw_sensors( assert entry assert entry.unique_id == f"123456789ABC-{light_type}:0-voltage_{light_type}" - entity_id = "sensor.test_name_device_temperature" + entity_id = f"sensor.test_name_{light_type}_light_0_device_temperature" state = hass.states.get(entity_id) assert state diff --git a/tests/components/shelly/test_utils.py b/tests/components/shelly/test_utils.py index 5891f250fae..17bcd6e3d40 100644 --- a/tests/components/shelly/test_utils.py +++ b/tests/components/shelly/test_utils.py @@ -236,7 +236,42 @@ async def test_get_block_input_triggers( async def test_get_rpc_channel_name(mock_rpc_device: Mock) -> None: """Test get RPC channel name.""" assert get_rpc_channel_name(mock_rpc_device, "input:0") == "Test name input 0" - assert get_rpc_channel_name(mock_rpc_device, "input:3") == "Test name input_3" + assert get_rpc_channel_name(mock_rpc_device, "input:3") == "Test name Input 3" + + +@pytest.mark.parametrize( + ("component", "expected"), + [ + ("cover", "Cover"), + ("input", "Input"), + ("light", "Light"), + ("rgb", "RGB light"), + ("rgbw", "RGBW light"), + ("switch", "Switch"), + ("thermostat", "Thermostat"), + ], +) +async def test_get_rpc_channel_name_multiple_components( + mock_rpc_device: Mock, + monkeypatch: pytest.MonkeyPatch, + component: str, + expected: str, +) -> None: + """Test get RPC channel name when there is more components of the same type.""" + config = { + f"{component}:0": {"name": None}, + f"{component}:1": {"name": None}, + } + monkeypatch.setattr(mock_rpc_device, "config", config) + + assert ( + get_rpc_channel_name(mock_rpc_device, f"{component}:0") + == f"Test name {expected} 0" + ) + assert ( + get_rpc_channel_name(mock_rpc_device, f"{component}:1") + == f"Test name {expected} 1" + ) async def test_get_rpc_input_triggers(