Add support for Shelly number virtual component (#121894)

* Support number component in field mode

* Support number in label mode

* Add tests

* Add mode_fn

* Add support for number component in slider mode

* Add comment

* Suggested change

* Revert max_fn

* Change unit 'min' to 'Hz' in test

---------

Co-authored-by: Maciej Bieniek <478555+bieniu@users.noreply.github.com>
This commit is contained in:
Maciej Bieniek 2024-07-15 22:26:12 +02:00 committed by GitHub
parent a9bf12f102
commit 260e98c3f7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 424 additions and 32 deletions

View file

@ -863,7 +863,7 @@ async def test_rpc_disabled_xfreq(
(None, "sensor.test_name_text_203"),
],
)
async def test_rpc_device_virtual_sensor(
async def test_rpc_device_virtual_text_sensor(
hass: HomeAssistant,
entity_registry: EntityRegistry,
mock_rpc_device: Mock,
@ -871,7 +871,7 @@ async def test_rpc_device_virtual_sensor(
name: str | None,
entity_id: str,
) -> None:
"""Test a virtual sensor for RPC device."""
"""Test a virtual text sensor for RPC device."""
config = deepcopy(mock_rpc_device.config)
config["text:203"] = {
"name": name,
@ -898,14 +898,14 @@ async def test_rpc_device_virtual_sensor(
assert hass.states.get(entity_id).state == "dolor sit amet"
async def test_rpc_remove_virtual_sensor_when_mode_field(
async def test_rpc_remove_text_virtual_sensor_when_mode_field(
hass: HomeAssistant,
entity_registry: EntityRegistry,
device_registry: DeviceRegistry,
mock_rpc_device: Mock,
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""Test if the virtual sensor will be removed if the mode has been changed to a field."""
"""Test if the virtual text sensor will be removed if the mode has been changed to a field."""
config = deepcopy(mock_rpc_device.config)
config["text:200"] = {"name": None, "meta": {"ui": {"view": "field"}}}
monkeypatch.setattr(mock_rpc_device, "config", config)
@ -932,13 +932,13 @@ async def test_rpc_remove_virtual_sensor_when_mode_field(
assert not entry
async def test_rpc_remove_virtual_sensor_when_orphaned(
async def test_rpc_remove_text_virtual_sensor_when_orphaned(
hass: HomeAssistant,
entity_registry: EntityRegistry,
device_registry: DeviceRegistry,
mock_rpc_device: Mock,
) -> None:
"""Check whether the virtual sensor will be removed if it has been removed from the device configuration."""
"""Check whether the virtual text sensor will be removed if it has been removed from the device configuration."""
config_entry = await init_integration(hass, 3, skip_setup=True)
device_entry = register_device(device_registry, config_entry)
entity_id = register_entity(
@ -955,3 +955,114 @@ async def test_rpc_remove_virtual_sensor_when_orphaned(
entry = entity_registry.async_get(entity_id)
assert not entry
@pytest.mark.parametrize(
("name", "entity_id", "original_unit", "expected_unit"),
[
("Virtual number sensor", "sensor.test_name_virtual_number_sensor", "W", "W"),
(None, "sensor.test_name_number_203", "", None),
],
)
async def test_rpc_device_virtual_number_sensor(
hass: HomeAssistant,
entity_registry: EntityRegistry,
mock_rpc_device: Mock,
monkeypatch: pytest.MonkeyPatch,
name: str | None,
entity_id: str,
original_unit: str,
expected_unit: str | None,
) -> None:
"""Test a virtual number sensor for RPC device."""
config = deepcopy(mock_rpc_device.config)
config["number:203"] = {
"name": name,
"min": 0,
"max": 100,
"meta": {"ui": {"step": 0.1, "unit": original_unit, "view": "label"}},
}
monkeypatch.setattr(mock_rpc_device, "config", config)
status = deepcopy(mock_rpc_device.status)
status["number:203"] = {"value": 34.5}
monkeypatch.setattr(mock_rpc_device, "status", status)
await init_integration(hass, 3)
state = hass.states.get(entity_id)
assert state
assert state.state == "34.5"
assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == expected_unit
entry = entity_registry.async_get(entity_id)
assert entry
assert entry.unique_id == "123456789ABC-number:203-number"
monkeypatch.setitem(mock_rpc_device.status["number:203"], "value", 56.7)
mock_rpc_device.mock_update()
assert hass.states.get(entity_id).state == "56.7"
async def test_rpc_remove_number_virtual_sensor_when_mode_field(
hass: HomeAssistant,
entity_registry: EntityRegistry,
device_registry: DeviceRegistry,
mock_rpc_device: Mock,
monkeypatch: pytest.MonkeyPatch,
) -> None:
"""Test if the virtual number sensor will be removed if the mode has been changed to a field."""
config = deepcopy(mock_rpc_device.config)
config["number:200"] = {
"name": None,
"min": 0,
"max": 100,
"meta": {"ui": {"step": 1, "unit": "", "view": "field"}},
}
monkeypatch.setattr(mock_rpc_device, "config", config)
status = deepcopy(mock_rpc_device.status)
status["number:200"] = {"value": 67.8}
monkeypatch.setattr(mock_rpc_device, "status", status)
config_entry = await init_integration(hass, 3, skip_setup=True)
device_entry = register_device(device_registry, config_entry)
entity_id = register_entity(
hass,
SENSOR_DOMAIN,
"test_name_number_200",
"number:200-number",
config_entry,
device_id=device_entry.id,
)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
entry = entity_registry.async_get(entity_id)
assert not entry
async def test_rpc_remove_number_virtual_sensor_when_orphaned(
hass: HomeAssistant,
entity_registry: EntityRegistry,
device_registry: DeviceRegistry,
mock_rpc_device: Mock,
) -> None:
"""Check whether the virtual number sensor will be removed if it has been removed from the device configuration."""
config_entry = await init_integration(hass, 3, skip_setup=True)
device_entry = register_device(device_registry, config_entry)
entity_id = register_entity(
hass,
SENSOR_DOMAIN,
"test_name_number_200",
"number:200-number",
config_entry,
device_id=device_entry.id,
)
await hass.config_entries.async_setup(config_entry.entry_id)
await hass.async_block_till_done()
entry = entity_registry.async_get(entity_id)
assert not entry