"""Tests for Shelly sensor platform."""

from copy import deepcopy
from unittest.mock import Mock, PropertyMock

from aioshelly.const import MODEL_BLU_GATEWAY_G3, MODEL_EM3
from aioshelly.exceptions import NotInitialized
from freezegun.api import FrozenDateTimeFactory
import pytest
from syrupy.assertion import SnapshotAssertion

from homeassistant.components.homeassistant import (
    DOMAIN as HA_DOMAIN,
    SERVICE_UPDATE_ENTITY,
)
from homeassistant.components.sensor import (
    ATTR_OPTIONS,
    ATTR_STATE_CLASS,
    DOMAIN as SENSOR_DOMAIN,
    SensorDeviceClass,
    SensorStateClass,
)
from homeassistant.components.shelly.const import DOMAIN
from homeassistant.const import (
    ATTR_DEVICE_CLASS,
    ATTR_ENTITY_ID,
    ATTR_FRIENDLY_NAME,
    ATTR_UNIT_OF_MEASUREMENT,
    PERCENTAGE,
    STATE_UNAVAILABLE,
    STATE_UNKNOWN,
    Platform,
    UnitOfElectricCurrent,
    UnitOfElectricPotential,
    UnitOfEnergy,
    UnitOfFrequency,
    UnitOfPower,
    UnitOfTemperature,
    UnitOfVolume,
)
from homeassistant.core import HomeAssistant, State
from homeassistant.helpers.device_registry import DeviceRegistry
from homeassistant.helpers.entity_registry import EntityRegistry
from homeassistant.setup import async_setup_component

from . import (
    MOCK_MAC,
    init_integration,
    mock_polling_rpc_update,
    mock_rest_update,
    mutate_rpc_device_status,
    patch_platforms,
    register_device,
    register_entity,
)
from .conftest import MOCK_BLOCKS, MOCK_CONFIG, MOCK_SHELLY_RPC, MOCK_STATUS_RPC

from tests.common import (
    async_fire_time_changed,
    async_load_json_object_fixture,
    mock_restore_cache_with_extra_data,
)

RELAY_BLOCK_ID = 0
SENSOR_BLOCK_ID = 3
DEVICE_BLOCK_ID = 4


@pytest.fixture(autouse=True)
def fixture_platforms():
    """Limit platforms under test."""
    with patch_platforms([Platform.SENSOR]):
        yield


async def test_block_sensor(
    hass: HomeAssistant,
    mock_block_device: Mock,
    entity_registry: EntityRegistry,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test block sensor."""
    # num_outputs is 2, channel name is used
    entity_id = f"{SENSOR_DOMAIN}.test_name_channel_1_power"
    await init_integration(hass, 1)

    assert (state := hass.states.get(entity_id))
    assert state.state == "53.4"

    monkeypatch.setattr(mock_block_device.blocks[RELAY_BLOCK_ID], "power", 60.1)
    mock_block_device.mock_update()

    assert (state := hass.states.get(entity_id))
    assert state.state == "60.1"

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-relay_0-power"


async def test_block_sensor_em3(
    hass: HomeAssistant, mock_block_device: Mock, monkeypatch: pytest.MonkeyPatch
) -> None:
    """Test block sensor of EM3."""
    monkeypatch.setitem(mock_block_device.shelly, "num_emeters", 3)
    monkeypatch.setitem(mock_block_device.settings["device"], "type", MODEL_EM3)
    monkeypatch.setitem(
        mock_block_device.settings,
        "emeters",
        [
            {"name": "Grid L1", "appliance_type": "General", "max_power": 0},
            {"appliance_type": "General", "max_power": 0},
            {"appliance_type": "General", "max_power": 0},
        ],
    )
    blocks = deepcopy(MOCK_BLOCKS)
    blocks[5] = Mock(
        sensor_ids={"power": 20},
        channel="0",
        power=20,
        description="emeter_0",
        type="emeter",
    )
    blocks.append(
        Mock(
            sensor_ids={"power": 20},
            channel="1",
            power=20,
            description="emeter_1",
            type="emeter",
        )
    )
    blocks.append(
        Mock(
            sensor_ids={"power": 20},
            channel="2",
            power=20,
            description="emeter_2",
            type="emeter",
        )
    )
    monkeypatch.setattr(mock_block_device, "blocks", blocks)
    await init_integration(hass, 1, model=MODEL_EM3)

    assert hass.states.get(f"{SENSOR_DOMAIN}.grid_l1_power")
    assert hass.states.get(f"{SENSOR_DOMAIN}.test_name_phase_b_power")
    assert hass.states.get(f"{SENSOR_DOMAIN}.test_name_phase_c_power")


async def test_energy_sensor(
    hass: HomeAssistant, mock_block_device: Mock, entity_registry: EntityRegistry
) -> None:
    """Test energy sensor."""
    # num_outputs is 2, channel name is used
    entity_id = f"{SENSOR_DOMAIN}.test_name_channel_1_energy"
    await init_integration(hass, 1)

    assert (state := hass.states.get(entity_id))
    # 1234567.89 Wmin / 60 / 1000 = 20.5761315 kWh
    assert state.state == "20.5761315"
    # suggested unit is KWh
    assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfEnergy.KILO_WATT_HOUR

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-relay_0-energy"


async def test_power_factory_unit_migration(
    hass: HomeAssistant, mock_block_device: Mock, entity_registry: EntityRegistry
) -> None:
    """Test migration unit of the power factory sensor."""
    entity_registry.async_get_or_create(
        SENSOR_DOMAIN,
        DOMAIN,
        "123456789ABC-emeter_0-powerFactor",
        suggested_object_id="test_name_power_factor",
        unit_of_measurement="%",
    )

    entity_id = f"{SENSOR_DOMAIN}.test_name_power_factor"
    await init_integration(hass, 1)

    assert (state := hass.states.get(entity_id))
    # Value of 0.98 is converted to 98.0%
    assert state.state == "98.0"
    assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-emeter_0-powerFactor"


async def test_power_factory_without_unit_migration(
    hass: HomeAssistant, mock_block_device: Mock, entity_registry: EntityRegistry
) -> None:
    """Test unit and value of the power factory sensor without unit migration."""
    entity_id = f"{SENSOR_DOMAIN}.test_name_power_factor"
    await init_integration(hass, 1)

    assert (state := hass.states.get(entity_id))
    assert state.state == "0.98"
    assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is None

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-emeter_0-powerFactor"


async def test_block_rest_sensor(
    hass: HomeAssistant,
    freezer: FrozenDateTimeFactory,
    mock_block_device: Mock,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test block REST sensor."""
    entity_id = register_entity(hass, SENSOR_DOMAIN, "test_name_rssi", "rssi")
    await init_integration(hass, 1)

    assert (state := hass.states.get(entity_id))
    assert state.state == "-64"

    monkeypatch.setitem(mock_block_device.status["wifi_sta"], "rssi", -71)
    await mock_rest_update(hass, freezer)

    assert (state := hass.states.get(entity_id))
    assert state.state == "-71"


async def test_block_sleeping_sensor(
    hass: HomeAssistant,
    mock_block_device: Mock,
    entity_registry: EntityRegistry,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test block sleeping sensor."""
    monkeypatch.setattr(
        mock_block_device.blocks[DEVICE_BLOCK_ID], "sensor_ids", {"battery": 98}
    )
    entity_id = f"{SENSOR_DOMAIN}.test_name_temperature"
    await init_integration(hass, 1, sleep_period=1000)

    # Sensor should be created when device is online
    assert hass.states.get(entity_id) is None

    # Make device online
    mock_block_device.mock_online()
    await hass.async_block_till_done(wait_background_tasks=True)

    assert (state := hass.states.get(entity_id))
    assert state.state == "22.1"

    monkeypatch.setattr(mock_block_device.blocks[SENSOR_BLOCK_ID], "temp", 23.4)
    mock_block_device.mock_update()

    assert (state := hass.states.get(entity_id))
    assert state.state == "23.4"

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-sensor_0-temp"


async def test_block_restored_sleeping_sensor(
    hass: HomeAssistant,
    mock_block_device: Mock,
    device_registry: DeviceRegistry,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test block restored sleeping sensor."""
    entry = await init_integration(hass, 1, sleep_period=1000, skip_setup=True)
    device = register_device(device_registry, entry)
    entity_id = register_entity(
        hass,
        SENSOR_DOMAIN,
        "test_name_temperature",
        "sensor_0-temp",
        entry,
        device_id=device.id,
    )
    extra_data = {"native_value": "20.4", "native_unit_of_measurement": "°C"}

    mock_restore_cache_with_extra_data(hass, ((State(entity_id, ""), extra_data),))
    monkeypatch.setattr(mock_block_device, "initialized", False)
    await hass.config_entries.async_setup(entry.entry_id)
    await hass.async_block_till_done()

    assert (state := hass.states.get(entity_id))
    assert state.state == "20.4"
    assert state.attributes[ATTR_STATE_CLASS] == SensorStateClass.MEASUREMENT
    assert state.attributes[ATTR_DEVICE_CLASS] == SensorDeviceClass.TEMPERATURE

    # Make device online
    monkeypatch.setattr(mock_block_device, "initialized", True)
    mock_block_device.mock_online()
    await hass.async_block_till_done(wait_background_tasks=True)

    assert (state := hass.states.get(entity_id))
    assert state.state == "22.1"


async def test_block_restored_sleeping_sensor_no_last_state(
    hass: HomeAssistant,
    mock_block_device: Mock,
    device_registry: DeviceRegistry,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test block restored sleeping sensor missing last state."""
    entry = await init_integration(hass, 1, sleep_period=1000, skip_setup=True)
    device = register_device(device_registry, entry)
    entity_id = register_entity(
        hass,
        SENSOR_DOMAIN,
        "test_name_temperature",
        "sensor_0-temp",
        entry,
        device_id=device.id,
    )
    monkeypatch.setattr(mock_block_device, "initialized", False)
    await hass.config_entries.async_setup(entry.entry_id)
    await hass.async_block_till_done()

    assert (state := hass.states.get(entity_id))
    assert state.state == STATE_UNKNOWN

    # Make device online
    monkeypatch.setattr(mock_block_device, "initialized", True)
    mock_block_device.mock_online()
    await hass.async_block_till_done(wait_background_tasks=True)

    assert (state := hass.states.get(entity_id))
    assert state.state == "22.1"


async def test_block_sensor_error(
    hass: HomeAssistant,
    mock_block_device: Mock,
    entity_registry: EntityRegistry,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test block sensor unavailable on sensor error."""
    entity_id = f"{SENSOR_DOMAIN}.test_name_battery"
    await init_integration(hass, 1)

    assert (state := hass.states.get(entity_id))
    assert state.state == "98"

    monkeypatch.setattr(mock_block_device.blocks[DEVICE_BLOCK_ID], "battery", -1)
    mock_block_device.mock_update()

    assert (state := hass.states.get(entity_id))
    assert state.state == STATE_UNAVAILABLE

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-device_0-battery"


async def test_block_sensor_removal(
    hass: HomeAssistant,
    mock_block_device: Mock,
    entity_registry: EntityRegistry,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test block sensor is removed due to removal_condition."""
    entity_id = register_entity(
        hass, SENSOR_DOMAIN, "test_name_battery", "device_0-battery"
    )

    assert entity_registry.async_get(entity_id) is not None

    monkeypatch.setitem(mock_block_device.settings, "external_power", 1)
    await init_integration(hass, 1)

    assert entity_registry.async_get(entity_id) is None


async def test_block_not_matched_restored_sleeping_sensor(
    hass: HomeAssistant,
    mock_block_device: Mock,
    device_registry: DeviceRegistry,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test block not matched to restored sleeping sensor."""
    entry = await init_integration(hass, 1, sleep_period=1000, skip_setup=True)
    device = register_device(device_registry, entry)
    entity_id = register_entity(
        hass,
        SENSOR_DOMAIN,
        "test_name_temperature",
        "sensor_0-temp",
        entry,
        device_id=device.id,
    )
    extra_data = {"native_value": "20.4", "native_unit_of_measurement": "°C"}

    mock_restore_cache_with_extra_data(hass, ((State(entity_id, ""), extra_data),))
    monkeypatch.setattr(mock_block_device, "initialized", False)
    await hass.config_entries.async_setup(entry.entry_id)
    await hass.async_block_till_done()

    assert (state := hass.states.get(entity_id))
    assert state.state == "20.4"

    # Make device online
    monkeypatch.setattr(
        mock_block_device.blocks[SENSOR_BLOCK_ID], "description", "other_desc"
    )
    monkeypatch.setattr(mock_block_device, "initialized", True)
    mock_block_device.mock_online()
    await hass.async_block_till_done(wait_background_tasks=True)

    assert (state := hass.states.get(entity_id))
    assert state.state == "20.4"


async def test_block_sensor_without_value(
    hass: HomeAssistant, mock_block_device: Mock, monkeypatch: pytest.MonkeyPatch
) -> None:
    """Test block sensor without value is not created."""
    entity_id = f"{SENSOR_DOMAIN}.test_name_battery"
    monkeypatch.setattr(mock_block_device.blocks[DEVICE_BLOCK_ID], "battery", None)
    await init_integration(hass, 1)

    assert hass.states.get(entity_id) is None


@pytest.mark.parametrize(
    ("entity", "initial_state", "block_id", "attribute", "value", "final_value"),
    [
        ("test_name_battery", "98", DEVICE_BLOCK_ID, "battery", None, STATE_UNKNOWN),
        (
            "test_name_operation",
            "normal",
            SENSOR_BLOCK_ID,
            "sensorOp",
            None,
            STATE_UNKNOWN,
        ),
        (
            "test_name_operation",
            "normal",
            SENSOR_BLOCK_ID,
            "sensorOp",
            "normal",
            "normal",
        ),
        (
            "test_name_self_test",
            "pending",
            SENSOR_BLOCK_ID,
            "selfTest",
            "completed",
            "completed",
        ),
        (
            "test_name_gas_detected",
            "mild",
            SENSOR_BLOCK_ID,
            "gas",
            "heavy",
            "heavy",
        ),
    ],
)
async def test_block_sensor_values(
    hass: HomeAssistant,
    mock_block_device: Mock,
    monkeypatch: pytest.MonkeyPatch,
    entity: str,
    initial_state: str,
    block_id: int,
    attribute: str,
    value: str | None,
    final_value: str,
) -> None:
    """Test block sensor unknown value."""
    entity_id = f"{SENSOR_DOMAIN}.{entity}"
    await init_integration(hass, 1)

    assert hass.states.get(entity_id).state == initial_state

    monkeypatch.setattr(mock_block_device.blocks[block_id], attribute, value)
    mock_block_device.mock_update()

    assert (state := hass.states.get(entity_id))
    assert state.state == final_value


@pytest.mark.parametrize(
    ("lamp_life_seconds", "percentage"),
    [
        (0 * 3600, "100.0"),  # 0 hours, 100% remaining
        (16 * 3600, "99.8222222222222"),
        (4500 * 3600, "50.0"),  # 4500 hours, 50% remaining
        (9000 * 3600, "0.0"),  # 9000 hours, 0% remaining
        (10000 * 3600, "0.0"),  # > 9000 hours, 0% remaining
    ],
)
async def test_block_shelly_air_lamp_life(
    hass: HomeAssistant,
    mock_block_device: Mock,
    monkeypatch: pytest.MonkeyPatch,
    lamp_life_seconds: int,
    percentage: float,
) -> None:
    """Test block Shelly Air lamp life percentage sensor."""
    monkeypatch.setitem(mock_block_device.shelly, "num_outputs", 1)
    # num_outputs is 1, device name is used
    entity_id = f"{SENSOR_DOMAIN}.{'test_name_lamp_life'}"
    monkeypatch.setattr(
        mock_block_device.blocks[RELAY_BLOCK_ID], "totalWorkTime", lamp_life_seconds
    )
    await init_integration(hass, 1)

    assert (state := hass.states.get(entity_id))
    assert state.state == percentage


async def test_rpc_sensor(
    hass: HomeAssistant, mock_rpc_device: Mock, monkeypatch: pytest.MonkeyPatch
) -> None:
    """Test RPC sensor."""
    entity_id = f"{SENSOR_DOMAIN}.test_name_test_cover_0_power"
    await init_integration(hass, 2)

    assert (state := hass.states.get(entity_id))
    assert state.state == "85.3"

    mutate_rpc_device_status(monkeypatch, mock_rpc_device, "cover:0", "apower", "88.2")
    mock_rpc_device.mock_update()

    assert (state := hass.states.get(entity_id))
    assert state.state == "88.2"

    mutate_rpc_device_status(monkeypatch, mock_rpc_device, "cover:0", "apower", None)
    mock_rpc_device.mock_update()

    assert (state := hass.states.get(entity_id))
    assert state.state == STATE_UNKNOWN


@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_rpc_rssi_sensor_removal(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test RPC RSSI sensor removal if no WiFi stations enabled."""
    entity_id = f"{SENSOR_DOMAIN}.test_name_signal_strength"
    entry = await init_integration(hass, 2)

    # WiFi1 enabled, do not remove sensor
    assert (state := hass.states.get(entity_id))
    assert state.state == "-63"

    # WiFi1 & WiFi2 disabled - remove sensor
    monkeypatch.setitem(mock_rpc_device.config["wifi"]["sta"], "enable", False)
    await hass.config_entries.async_reload(entry.entry_id)
    await hass.async_block_till_done()
    assert hass.states.get(entity_id) is None

    # WiFi2 enabled, do not remove sensor
    monkeypatch.setitem(mock_rpc_device.config["wifi"]["sta1"], "enable", True)
    await hass.config_entries.async_reload(entry.entry_id)
    await hass.async_block_till_done()

    assert (state := hass.states.get(entity_id))
    assert state.state == "-63"


async def test_rpc_illuminance_sensor(
    hass: HomeAssistant, mock_rpc_device: Mock, entity_registry: EntityRegistry
) -> None:
    """Test RPC illuminacne sensor."""
    entity_id = f"{SENSOR_DOMAIN}.test_name_illuminance"
    await init_integration(hass, 2)

    assert (state := hass.states.get(entity_id))
    assert state.state == "345"

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-illuminance:0-illuminance"


async def test_rpc_sensor_error(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    entity_registry: EntityRegistry,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test RPC sensor unavailable on sensor error."""
    entity_id = f"{SENSOR_DOMAIN}.test_name_voltmeter"
    await init_integration(hass, 2)

    assert (state := hass.states.get(entity_id))
    assert state.state == "4.321"

    mutate_rpc_device_status(
        monkeypatch, mock_rpc_device, "voltmeter:100", "voltage", None
    )
    mock_rpc_device.mock_update()

    assert (state := hass.states.get(entity_id))
    assert state.state == STATE_UNAVAILABLE

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-voltmeter:100-voltmeter"


async def test_rpc_polling_sensor(
    hass: HomeAssistant,
    freezer: FrozenDateTimeFactory,
    mock_rpc_device: Mock,
    entity_registry: EntityRegistry,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test RPC polling sensor."""
    entity_id = register_entity(hass, SENSOR_DOMAIN, "test_name_rssi", "wifi-rssi")
    await init_integration(hass, 2)

    assert (state := hass.states.get(entity_id))
    assert state.state == "-63"

    mutate_rpc_device_status(monkeypatch, mock_rpc_device, "wifi", "rssi", "-70")
    await mock_polling_rpc_update(hass, freezer)

    assert (state := hass.states.get(entity_id))
    assert state.state == "-70"

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-wifi-rssi"


async def test_rpc_sleeping_sensor(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test RPC online sleeping sensor."""
    entity_id = f"{SENSOR_DOMAIN}.test_name_temperature"
    monkeypatch.setattr(mock_rpc_device, "connected", False)
    monkeypatch.setitem(mock_rpc_device.status["sys"], "wakeup_period", 1000)
    await init_integration(hass, 2, sleep_period=1000)

    # Make device online
    mock_rpc_device.mock_online()
    await hass.async_block_till_done(wait_background_tasks=True)

    assert (state := hass.states.get(entity_id))
    assert state.state == "22.9"

    mutate_rpc_device_status(monkeypatch, mock_rpc_device, "temperature:0", "tC", 23.4)
    mock_rpc_device.mock_update()

    assert (state := hass.states.get(entity_id))
    assert state.state == "23.4"


async def test_rpc_sleeping_sensor_with_channel_name(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test RPC online sleeping sensor with channel name."""
    name = "test channel name"
    entity_id = f"{SENSOR_DOMAIN}.test_name_test_channel_name_temperature"
    monkeypatch.setitem(
        mock_rpc_device.config, "temperature:0", {"id": 0, "name": name}
    )
    monkeypatch.setattr(mock_rpc_device, "connected", False)
    monkeypatch.setitem(mock_rpc_device.status["sys"], "wakeup_period", 1000)
    await init_integration(hass, 2, sleep_period=1000)

    # Make device online
    mock_rpc_device.mock_online()
    await hass.async_block_till_done(wait_background_tasks=True)

    assert (state := hass.states.get(entity_id))
    assert state.attributes["friendly_name"] == f"Test name {name} temperature"
    assert state.state == "22.9"

    mutate_rpc_device_status(monkeypatch, mock_rpc_device, "temperature:0", "tC", 23.4)
    mock_rpc_device.mock_update()

    assert (state := hass.states.get(entity_id))
    assert state.state == "23.4"


async def test_rpc_restored_sleeping_sensor(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    device_registry: DeviceRegistry,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test RPC restored sensor."""
    entry = await init_integration(hass, 2, sleep_period=1000, skip_setup=True)
    device = register_device(device_registry, entry)
    entity_id = register_entity(
        hass,
        SENSOR_DOMAIN,
        "test_name_temperature",
        "temperature:0-temperature_tc",
        entry,
        device_id=device.id,
    )
    extra_data = {"native_value": "21.0", "native_unit_of_measurement": "°C"}

    mock_restore_cache_with_extra_data(hass, ((State(entity_id, ""), extra_data),))
    type(mock_rpc_device).shelly = PropertyMock(side_effect=NotInitialized())
    type(mock_rpc_device).config = PropertyMock(side_effect=NotInitialized())
    type(mock_rpc_device).status = PropertyMock(side_effect=NotInitialized())
    monkeypatch.setattr(mock_rpc_device, "initialized", False)

    await hass.config_entries.async_setup(entry.entry_id)
    await hass.async_block_till_done()

    assert (state := hass.states.get(entity_id))
    assert state.state == "21.0"

    # Make device online
    type(mock_rpc_device).shelly = PropertyMock(return_value=MOCK_SHELLY_RPC)
    type(mock_rpc_device).config = PropertyMock(return_value=MOCK_CONFIG)
    type(mock_rpc_device).status = PropertyMock(return_value=MOCK_STATUS_RPC)
    monkeypatch.setattr(mock_rpc_device, "initialized", True)
    mock_rpc_device.mock_online()
    await hass.async_block_till_done(wait_background_tasks=True)

    # Mock update
    mock_rpc_device.mock_update()
    await hass.async_block_till_done()

    assert (state := hass.states.get(entity_id))
    assert state.state == "22.9"


async def test_rpc_restored_sleeping_sensor_no_last_state(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    device_registry: DeviceRegistry,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test RPC restored sensor missing last state."""
    entry = await init_integration(hass, 2, sleep_period=1000, skip_setup=True)
    device = register_device(device_registry, entry)
    entity_id = register_entity(
        hass,
        SENSOR_DOMAIN,
        "test_name_temperature",
        "temperature:0-temperature_tc",
        entry,
        device_id=device.id,
    )

    monkeypatch.setattr(mock_rpc_device, "initialized", False)

    await hass.config_entries.async_setup(entry.entry_id)
    await hass.async_block_till_done()

    assert (state := hass.states.get(entity_id))
    assert state.state == STATE_UNKNOWN

    # Make device online
    monkeypatch.setattr(mock_rpc_device, "initialized", True)
    mock_rpc_device.mock_online()
    await hass.async_block_till_done(wait_background_tasks=True)

    # Mock update
    mock_rpc_device.mock_update()
    await hass.async_block_till_done()

    assert (state := hass.states.get(entity_id))
    assert state.state == "22.9"


@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_rpc_energy_meter_1_sensors(
    hass: HomeAssistant, entity_registry: EntityRegistry, mock_rpc_device: Mock
) -> None:
    """Test RPC sensors for EM1 component."""
    await init_integration(hass, 2)

    assert (state := hass.states.get("sensor.test_name_energy_meter_0_power"))
    assert state.state == "85.3"

    assert (entry := entity_registry.async_get("sensor.test_name_energy_meter_0_power"))
    assert entry.unique_id == "123456789ABC-em1:0-power_em1"

    assert (state := hass.states.get("sensor.test_name_energy_meter_1_power"))
    assert state.state == "123.3"

    assert (entry := entity_registry.async_get("sensor.test_name_energy_meter_1_power"))
    assert entry.unique_id == "123456789ABC-em1:1-power_em1"

    assert (state := hass.states.get("sensor.test_name_energy_meter_0_energy"))
    assert state.state == "123.4564"

    assert (
        entry := entity_registry.async_get("sensor.test_name_energy_meter_0_energy")
    )
    assert entry.unique_id == "123456789ABC-em1data:0-total_act_energy"

    assert (state := hass.states.get("sensor.test_name_energy_meter_1_energy"))
    assert state.state == "987.6543"

    assert (
        entry := entity_registry.async_get("sensor.test_name_energy_meter_1_energy")
    )
    assert entry.unique_id == "123456789ABC-em1data:1-total_act_energy"


async def test_rpc_sleeping_update_entity_service(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    entity_registry: EntityRegistry,
    monkeypatch: pytest.MonkeyPatch,
    caplog: pytest.LogCaptureFixture,
) -> None:
    """Test RPC sleeping device when the update_entity service is used."""
    await async_setup_component(hass, "homeassistant", {})

    entity_id = f"{SENSOR_DOMAIN}.test_name_temperature"
    monkeypatch.setattr(mock_rpc_device, "connected", False)
    monkeypatch.setitem(mock_rpc_device.status["sys"], "wakeup_period", 1000)
    await init_integration(hass, 2, sleep_period=1000)

    # Make device online
    mock_rpc_device.mock_online()
    await hass.async_block_till_done(wait_background_tasks=True)

    assert (state := hass.states.get(entity_id))
    assert state.state == "22.9"

    await hass.services.async_call(
        HA_DOMAIN,
        SERVICE_UPDATE_ENTITY,
        service_data={ATTR_ENTITY_ID: entity_id},
        blocking=True,
    )

    # Entity should be available after update_entity service call
    assert (state := hass.states.get(entity_id))
    assert state.state == "22.9"

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-temperature:0-temperature_tc"

    assert (
        "Entity sensor.test_name_temperature comes from a sleeping device"
        in caplog.text
    )


async def test_block_sleeping_update_entity_service(
    hass: HomeAssistant,
    mock_block_device: Mock,
    entity_registry: EntityRegistry,
    monkeypatch: pytest.MonkeyPatch,
    caplog: pytest.LogCaptureFixture,
) -> None:
    """Test block sleeping device when the update_entity service is used."""
    await async_setup_component(hass, "homeassistant", {})

    entity_id = f"{SENSOR_DOMAIN}.test_name_temperature"
    monkeypatch.setitem(
        mock_block_device.settings,
        "sleep_mode",
        {"period": 60, "unit": "m"},
    )
    await init_integration(hass, 1, sleep_period=3600)

    # Sensor should be created when device is online
    assert hass.states.get(entity_id) is None

    # Make device online
    mock_block_device.mock_online()
    await hass.async_block_till_done(wait_background_tasks=True)

    assert (state := hass.states.get(entity_id))
    assert state.state == "22.1"

    await hass.services.async_call(
        HA_DOMAIN,
        SERVICE_UPDATE_ENTITY,
        service_data={ATTR_ENTITY_ID: entity_id},
        blocking=True,
    )

    # Entity should be available after update_entity service call
    assert (state := hass.states.get(entity_id))
    assert state.state == "22.1"

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-sensor_0-temp"

    assert (
        "Entity sensor.test_name_temperature comes from a sleeping device"
        in caplog.text
    )


@pytest.mark.parametrize(
    ("original_unit", "expected_unit"),
    [
        ("m/s", "m/s"),
        (None, None),
        ("", None),
    ],
)
async def test_rpc_analog_input_sensors(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    entity_registry: EntityRegistry,
    monkeypatch: pytest.MonkeyPatch,
    original_unit: str | None,
    expected_unit: str | None,
) -> None:
    """Test RPC analog input xpercent sensor."""
    config = deepcopy(mock_rpc_device.config)
    config["input:1"]["xpercent"] = {"expr": "x*0.2995", "unit": original_unit}
    monkeypatch.setattr(mock_rpc_device, "config", config)

    await init_integration(hass, 2)

    entity_id = f"{SENSOR_DOMAIN}.test_name_input_1_analog"
    assert (state := hass.states.get(entity_id))
    assert state.state == "89"

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-input:1-analoginput"

    entity_id = f"{SENSOR_DOMAIN}.test_name_input_1_analog_value"
    assert (state := hass.states.get(entity_id))
    assert state.state == "8.9"
    assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == expected_unit

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-input:1-analoginput_xpercent"


async def test_rpc_disabled_analog_input_sensors(
    hass: HomeAssistant, mock_rpc_device: Mock, monkeypatch: pytest.MonkeyPatch
) -> None:
    """Test RPC disabled counter sensor."""
    new_config = deepcopy(mock_rpc_device.config)
    new_config["input:1"]["enable"] = False
    monkeypatch.setattr(mock_rpc_device, "config", new_config)

    await init_integration(hass, 2)

    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_input_1_analog_value"
    assert hass.states.get(entity_id) is None


async def test_rpc_disabled_xpercent(
    hass: HomeAssistant, mock_rpc_device: Mock, monkeypatch: pytest.MonkeyPatch
) -> None:
    """Test RPC empty xpercent value."""
    mutate_rpc_device_status(
        monkeypatch,
        mock_rpc_device,
        "input:1",
        "xpercent",
        None,
    )
    await init_integration(hass, 2)

    entity_id = f"{SENSOR_DOMAIN}.test_name_input_1_analog"
    assert (state := hass.states.get(entity_id))
    assert state.state == "89"

    entity_id = f"{SENSOR_DOMAIN}.test_name_input_1_analog_value"
    assert hass.states.get(entity_id) is None


@pytest.mark.parametrize(
    ("original_unit", "expected_unit"),
    [
        ("l/h", "l/h"),
        (None, None),
        ("", None),
    ],
)
async def test_rpc_pulse_counter_sensors(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    entity_registry: EntityRegistry,
    monkeypatch: pytest.MonkeyPatch,
    original_unit: str | None,
    expected_unit: str | None,
) -> None:
    """Test RPC counter sensor."""
    config = deepcopy(mock_rpc_device.config)
    config["input:2"]["xcounts"] = {"expr": "x/10", "unit": original_unit}
    monkeypatch.setattr(mock_rpc_device, "config", config)

    await init_integration(hass, 2)

    entity_id = f"{SENSOR_DOMAIN}.test_name_gas_pulse_counter"
    assert (state := hass.states.get(entity_id))
    assert state.state == "56174"
    assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "pulse"
    assert state.attributes.get(ATTR_STATE_CLASS) == SensorStateClass.TOTAL

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-input:2-pulse_counter"

    entity_id = f"{SENSOR_DOMAIN}.test_name_gas_pulse_counter_value"
    assert (state := hass.states.get(entity_id))
    assert state.state == "561.74"
    assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == expected_unit

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-input:2-counter_value"


async def test_rpc_disabled_pulse_counter_sensors(
    hass: HomeAssistant, mock_rpc_device: Mock, monkeypatch: pytest.MonkeyPatch
) -> None:
    """Test RPC disabled counter sensor."""
    new_config = deepcopy(mock_rpc_device.config)
    new_config["input:2"]["enable"] = False
    monkeypatch.setattr(mock_rpc_device, "config", new_config)

    await init_integration(hass, 2)

    entity_id = f"{SENSOR_DOMAIN}.gas_pulse_counter"
    assert hass.states.get(entity_id) is None

    entity_id = f"{SENSOR_DOMAIN}.gas_pulse_counter_value"
    assert hass.states.get(entity_id) is None


async def test_rpc_disabled_xtotal_counter(
    hass: HomeAssistant, mock_rpc_device: Mock, monkeypatch: pytest.MonkeyPatch
) -> None:
    """Test RPC disabled xtotal counter."""
    mutate_rpc_device_status(
        monkeypatch,
        mock_rpc_device,
        "input:2",
        "counts",
        {"total": 20635},
    )
    await init_integration(hass, 2)

    entity_id = f"{SENSOR_DOMAIN}.test_name_gas_pulse_counter"
    assert (state := hass.states.get(entity_id))
    assert state.state == "20635"

    entity_id = f"{SENSOR_DOMAIN}.test_name_gas_counter_value"
    assert hass.states.get(entity_id) is None


@pytest.mark.parametrize(
    ("original_unit", "expected_unit"),
    [
        ("W", "W"),
        (None, None),
        ("", None),
    ],
)
async def test_rpc_pulse_counter_frequency_sensors(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    entity_registry: EntityRegistry,
    monkeypatch: pytest.MonkeyPatch,
    original_unit: str | None,
    expected_unit: str | None,
) -> None:
    """Test RPC counter sensor."""
    config = deepcopy(mock_rpc_device.config)
    config["input:2"]["xfreq"] = {"expr": "x**2", "unit": original_unit}
    monkeypatch.setattr(mock_rpc_device, "config", config)

    await init_integration(hass, 2)

    entity_id = f"{SENSOR_DOMAIN}.test_name_gas_pulse_counter_frequency"
    assert (state := hass.states.get(entity_id))
    assert state.state == "208.0"
    assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfFrequency.HERTZ
    assert state.attributes.get(ATTR_STATE_CLASS) == SensorStateClass.MEASUREMENT

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-input:2-counter_frequency"

    entity_id = f"{SENSOR_DOMAIN}.test_name_gas_pulse_counter_frequency_value"
    assert (state := hass.states.get(entity_id))
    assert state.state == "6.11"
    assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == expected_unit

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-input:2-counter_frequency_value"


async def test_rpc_disabled_xfreq(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    entity_registry: EntityRegistry,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test RPC input with the xfreq sensor disabled."""
    status = deepcopy(mock_rpc_device.status)
    status["input:2"] = {
        "id": 2,
        "counts": {"total": 56174, "xtotal": 561.74},
        "freq": 208.00,
    }
    monkeypatch.setattr(mock_rpc_device, "status", status)

    await init_integration(hass, 2)

    entity_id = f"{SENSOR_DOMAIN}.gas_pulse_counter_frequency_value"

    assert hass.states.get(entity_id) is None

    assert entity_registry.async_get(entity_id) is None


@pytest.mark.parametrize(
    ("name", "entity_id"),
    [
        ("Virtual sensor", "sensor.test_name_virtual_sensor"),
        (None, "sensor.test_name_text_203"),
    ],
)
async def test_rpc_device_virtual_text_sensor(
    hass: HomeAssistant,
    entity_registry: EntityRegistry,
    mock_rpc_device: Mock,
    monkeypatch: pytest.MonkeyPatch,
    name: str | None,
    entity_id: str,
) -> None:
    """Test a virtual text sensor for RPC device."""
    config = deepcopy(mock_rpc_device.config)
    config["text:203"] = {
        "name": name,
        "meta": {"ui": {"view": "label"}},
    }
    monkeypatch.setattr(mock_rpc_device, "config", config)

    status = deepcopy(mock_rpc_device.status)
    status["text:203"] = {"value": "lorem ipsum"}
    monkeypatch.setattr(mock_rpc_device, "status", status)

    await init_integration(hass, 3)

    assert (state := hass.states.get(entity_id))
    assert state.state == "lorem ipsum"

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-text:203-text_generic"

    monkeypatch.setitem(mock_rpc_device.status["text:203"], "value", "dolor sit amet")
    mock_rpc_device.mock_update()
    assert (state := hass.states.get(entity_id))
    assert state.state == "dolor sit amet"


@pytest.mark.parametrize(
    ("old_id", "new_id", "role"),
    [
        ("enum", "enum_generic", None),
        ("number", "number_generic", None),
        ("number", "number_current_humidity", "current_humidity"),
        ("number", "number_current_temperature", "current_temperature"),
        ("text", "text_generic", None),
    ],
)
@pytest.mark.usefixtures("disable_async_remove_shelly_rpc_entities")
async def test_migrate_unique_id_virtual_components_roles(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    entity_registry: EntityRegistry,
    caplog: pytest.LogCaptureFixture,
    monkeypatch: pytest.MonkeyPatch,
    old_id: str,
    new_id: str,
    role: str | None,
) -> None:
    """Test migration of unique_id for virtual components to include role."""
    entry = await init_integration(hass, 3, skip_setup=True)
    unique_base = f"{MOCK_MAC}-{old_id}:200"
    old_unique_id = f"{unique_base}-{old_id}"
    new_unique_id = f"{unique_base}-{new_id}"
    config = deepcopy(mock_rpc_device.config)
    if role:
        config[f"{old_id}:200"] = {
            "role": role,
        }
    else:
        config[f"{old_id}:200"] = {}
    monkeypatch.setattr(mock_rpc_device, "config", config)

    entity = entity_registry.async_get_or_create(
        suggested_object_id="test_name_test_sensor",
        disabled_by=None,
        domain=SENSOR_DOMAIN,
        platform=DOMAIN,
        unique_id=old_unique_id,
        config_entry=entry,
    )
    assert entity.unique_id == old_unique_id

    await hass.config_entries.async_setup(entry.entry_id)
    await hass.async_block_till_done()

    entity_entry = entity_registry.async_get("sensor.test_name_test_sensor")
    assert entity_entry
    assert entity_entry.unique_id == new_unique_id

    assert "Migrating unique_id for sensor.test_name_test_sensor" in caplog.text


@pytest.mark.parametrize(
    ("old_unique_id", "new_unique_id", "entity_id"),
    [
        (
            "123456789ABC-temperature:0-temperature_0",
            "123456789ABC-temperature:0-temperature_tc",
            "sensor.test_name_temperature",
        ),
        (
            "123456789ABC-humidity:0-humidity_0",
            "123456789ABC-humidity:0-humidity_rh",
            "sensor.test_name_humidity",
        ),
    ],
)
@pytest.mark.usefixtures("disable_async_remove_shelly_rpc_entities")
async def test_migrate_unique_id_rpc_sensor_description_key_rename(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    entity_registry: EntityRegistry,
    caplog: pytest.LogCaptureFixture,
    old_unique_id: str,
    new_unique_id: str,
    entity_id: str,
) -> None:
    """Test migration of RPC sensor unique_id after description key rename."""
    entry = await init_integration(hass, 2, skip_setup=True)

    entity = entity_registry.async_get_or_create(
        suggested_object_id=entity_id.split(".")[1],
        disabled_by=None,
        domain=SENSOR_DOMAIN,
        platform=DOMAIN,
        unique_id=old_unique_id,
        config_entry=entry,
    )
    assert entity.unique_id == old_unique_id

    await hass.config_entries.async_setup(entry.entry_id)
    await hass.async_block_till_done()

    entity_entry = entity_registry.async_get(entity_id)
    assert entity_entry
    assert entity_entry.unique_id == new_unique_id

    assert f"Migrating unique_id for {entity_id} entity" in caplog.text


@pytest.mark.usefixtures("disable_async_remove_shelly_rpc_entities")
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 virtual text sensor removal when mode changes to field."""
    config = deepcopy(mock_rpc_device.config)
    config["text:200"] = {"name": None, "meta": {"ui": {"view": "field"}}}
    monkeypatch.setattr(mock_rpc_device, "config", config)

    status = deepcopy(mock_rpc_device.status)
    status["text:200"] = {"value": "lorem ipsum"}
    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_text_200",
        "text:200-text_generic",
        config_entry,
        device_id=device_entry.id,
    )

    await hass.config_entries.async_setup(config_entry.entry_id)
    await hass.async_block_till_done()

    assert entity_registry.async_get(entity_id) is None


async def test_rpc_remove_text_virtual_sensor_when_orphaned(
    hass: HomeAssistant,
    entity_registry: EntityRegistry,
    device_registry: DeviceRegistry,
    mock_rpc_device: Mock,
) -> None:
    """Test virtual text sensor removal from 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_text_200",
        "text:200-text_generic",
        config_entry,
        device_id=device_entry.id,
    )

    await hass.config_entries.async_setup(config_entry.entry_id)
    await hass.async_block_till_done()

    assert entity_registry.async_get(entity_id) is None


@pytest.mark.parametrize(
    ("name", "entity_id", "original_unit", "expected_unit"),
    [
        ("Virtual number sensor", "sensor.test_name_virtual_number_sensor", "W", "W"),
        ("Unit map", "sensor.test_name_unit_map", "m3/min", "m³/min"),
        (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)

    assert (state := hass.states.get(entity_id))
    assert state.state == "34.5"
    assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == expected_unit

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-number:203-number_generic"

    monkeypatch.setitem(mock_rpc_device.status["number:203"], "value", 56.7)
    mock_rpc_device.mock_update()
    assert (state := hass.states.get(entity_id))
    assert state.state == "56.7"


@pytest.mark.usefixtures("disable_async_remove_shelly_rpc_entities")
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 virtual number sensor removal when mode changes to 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_generic",
        config_entry,
        device_id=device_entry.id,
    )

    await hass.config_entries.async_setup(config_entry.entry_id)
    await hass.async_block_till_done()

    assert entity_registry.async_get(entity_id) is None


async def test_rpc_remove_number_virtual_sensor_when_orphaned(
    hass: HomeAssistant,
    entity_registry: EntityRegistry,
    device_registry: DeviceRegistry,
    mock_rpc_device: Mock,
) -> None:
    """Test virtual number sensor removal from 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_generic",
        config_entry,
        device_id=device_entry.id,
    )

    await hass.config_entries.async_setup(config_entry.entry_id)
    await hass.async_block_till_done()

    assert entity_registry.async_get(entity_id) is None


@pytest.mark.parametrize(
    ("name", "entity_id", "value", "expected_state"),
    [
        (
            "Virtual enum sensor",
            "sensor.test_name_virtual_enum_sensor",
            "one",
            "Title 1",
        ),
        (None, "sensor.test_name_enum_203", None, STATE_UNKNOWN),
    ],
)
async def test_rpc_device_virtual_enum_sensor(
    hass: HomeAssistant,
    entity_registry: EntityRegistry,
    mock_rpc_device: Mock,
    monkeypatch: pytest.MonkeyPatch,
    name: str | None,
    entity_id: str,
    value: str | None,
    expected_state: str,
) -> None:
    """Test a virtual enum sensor for RPC device."""
    config = deepcopy(mock_rpc_device.config)
    config["enum:203"] = {
        "name": name,
        "options": ["one", "two", "three"],
        "meta": {"ui": {"view": "label", "titles": {"one": "Title 1", "two": None}}},
    }
    monkeypatch.setattr(mock_rpc_device, "config", config)

    status = deepcopy(mock_rpc_device.status)
    status["enum:203"] = {"value": value}
    monkeypatch.setattr(mock_rpc_device, "status", status)

    await init_integration(hass, 3)

    assert (state := hass.states.get(entity_id))
    assert state.state == expected_state
    assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.ENUM
    assert state.attributes.get(ATTR_OPTIONS) == ["Title 1", "two", "three"]

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-enum:203-enum_generic"

    monkeypatch.setitem(mock_rpc_device.status["enum:203"], "value", "two")
    mock_rpc_device.mock_update()
    assert (state := hass.states.get(entity_id))
    assert state.state == "two"


@pytest.mark.usefixtures("disable_async_remove_shelly_rpc_entities")
async def test_rpc_remove_enum_virtual_sensor_when_mode_dropdown(
    hass: HomeAssistant,
    entity_registry: EntityRegistry,
    device_registry: DeviceRegistry,
    mock_rpc_device: Mock,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test virtual enum sensor removal when mode changes to dropdown."""
    config = deepcopy(mock_rpc_device.config)
    config["enum:200"] = {
        "name": None,
        "options": ["option 1", "option 2", "option 3"],
        "meta": {
            "ui": {
                "view": "dropdown",
                "titles": {"option 1": "Title 1", "option 2": None},
            }
        },
    }
    monkeypatch.setattr(mock_rpc_device, "config", config)

    status = deepcopy(mock_rpc_device.status)
    status["enum:200"] = {"value": "option 2"}
    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_enum_200",
        "enum:200-enum_generic",
        config_entry,
        device_id=device_entry.id,
    )

    await hass.config_entries.async_setup(config_entry.entry_id)
    await hass.async_block_till_done()

    assert entity_registry.async_get(entity_id) is None


async def test_rpc_remove_enum_virtual_sensor_when_orphaned(
    hass: HomeAssistant,
    entity_registry: EntityRegistry,
    device_registry: DeviceRegistry,
    mock_rpc_device: Mock,
) -> None:
    """Test virtual enum sensor removal from 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_enum_200",
        "enum:200-enum_generic",
        config_entry,
        device_id=device_entry.id,
    )

    await hass.config_entries.async_setup(config_entry.entry_id)
    await hass.async_block_till_done()

    assert entity_registry.async_get(entity_id) is None


@pytest.mark.usefixtures("entity_registry_enabled_by_default")
@pytest.mark.parametrize("light_type", ["rgb", "rgbw"])
async def test_rpc_rgbw_sensors(
    hass: HomeAssistant,
    entity_registry: EntityRegistry,
    mock_rpc_device: Mock,
    monkeypatch: pytest.MonkeyPatch,
    light_type: str,
) -> None:
    """Test sensors for RGB/RGBW light."""
    config = deepcopy(mock_rpc_device.config)
    config[f"{light_type}:0"] = {"id": 0}
    monkeypatch.setattr(mock_rpc_device, "config", config)

    status = deepcopy(mock_rpc_device.status)
    status[f"{light_type}:0"] = {
        "temperature": {"tC": 54.3, "tF": 129.7},
        "aenergy": {"total": 45.141},
        "apower": 12.2,
        "current": 0.23,
        "voltage": 12.4,
    }
    monkeypatch.setattr(mock_rpc_device, "status", status)

    await init_integration(hass, 2)

    entity_id = f"sensor.test_name_{light_type}_light_0_power"

    assert (state := hass.states.get(entity_id))
    assert state.state == "12.2"
    assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfPower.WATT

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == f"123456789ABC-{light_type}:0-power_{light_type}"

    entity_id = f"sensor.test_name_{light_type}_light_0_energy"

    assert (state := hass.states.get(entity_id))
    assert state.state == "0.045141"
    assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfEnergy.KILO_WATT_HOUR

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == f"123456789ABC-{light_type}:0-energy_{light_type}"

    entity_id = f"sensor.test_name_{light_type}_light_0_current"

    assert (state := hass.states.get(entity_id))
    assert state.state == "0.23"
    assert (
        state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfElectricCurrent.AMPERE
    )

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == f"123456789ABC-{light_type}:0-current_{light_type}"

    entity_id = f"sensor.test_name_{light_type}_light_0_voltage"

    assert (state := hass.states.get(entity_id))
    assert state.state == "12.4"
    assert (
        state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfElectricPotential.VOLT
    )

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == f"123456789ABC-{light_type}:0-voltage_{light_type}"

    entity_id = f"sensor.test_name_{light_type}_light_0_temperature"

    assert (state := hass.states.get(entity_id))
    assert state.state == "54.3"
    assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfTemperature.CELSIUS

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == f"123456789ABC-{light_type}:0-temperature_{light_type}"


async def test_rpc_device_sensor_goes_unavailable_on_disconnect(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    monkeypatch: pytest.MonkeyPatch,
    freezer: FrozenDateTimeFactory,
    caplog: pytest.LogCaptureFixture,
) -> None:
    """Test RPC device with sensor goes unavailable on disconnect."""
    await init_integration(hass, 2)

    assert (state := hass.states.get("sensor.test_name_temperature"))
    assert state.state != STATE_UNAVAILABLE

    monkeypatch.setattr(mock_rpc_device, "connected", False)
    monkeypatch.setattr(mock_rpc_device, "initialized", False)
    mock_rpc_device.mock_disconnected()
    await hass.async_block_till_done()

    assert (state := hass.states.get("sensor.test_name_temperature"))
    assert state.state == STATE_UNAVAILABLE

    freezer.tick(60)
    async_fire_time_changed(hass)
    await hass.async_block_till_done()
    assert "NotInitialized" not in caplog.text

    monkeypatch.setattr(mock_rpc_device, "connected", True)
    monkeypatch.setattr(mock_rpc_device, "initialized", True)
    mock_rpc_device.mock_initialized()
    await hass.async_block_till_done()

    assert (state := hass.states.get("sensor.test_name_temperature"))
    assert state.state != STATE_UNAVAILABLE


async def test_rpc_voltmeter_value(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    entity_registry: EntityRegistry,
) -> None:
    """Test RPC voltmeter value sensor."""
    entity_id = f"{SENSOR_DOMAIN}.test_name_voltmeter_value"

    await init_integration(hass, 2)

    assert (state := hass.states.get(entity_id))
    assert state.state == "12.34"
    assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "ppm"

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-voltmeter:100-voltmeter_value"


async def test_blu_trv_sensor_entity(
    hass: HomeAssistant,
    mock_blu_trv: Mock,
    entity_registry: EntityRegistry,
    snapshot: SnapshotAssertion,
) -> None:
    """Test BLU TRV sensor entity."""
    await init_integration(hass, 3, model=MODEL_BLU_GATEWAY_G3)

    for entity in ("battery", "signal_strength", "valve_position"):
        entity_id = f"{SENSOR_DOMAIN}.trv_name_{entity}"

        state = hass.states.get(entity_id)
        assert state == snapshot(name=f"{entity_id}-state")

        entry = entity_registry.async_get(entity_id)
        assert entry == snapshot(name=f"{entity_id}-entry")


async def test_rpc_device_virtual_number_sensor_with_device_class(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    monkeypatch: pytest.MonkeyPatch,
    entity_registry: EntityRegistry,
) -> None:
    """Test a virtual number sensor with device class for RPC device."""
    entity_id = f"{SENSOR_DOMAIN}.test_name_humidity"
    config = deepcopy(mock_rpc_device.config)
    config["number:203"] = {
        "name": "Current humidity",
        "min": 0,
        "max": 100,
        "meta": {"ui": {"step": 1, "unit": "%", "view": "label"}},
        "role": "current_humidity",
    }
    monkeypatch.setattr(mock_rpc_device, "config", config)

    status = deepcopy(mock_rpc_device.status)
    status.pop("humidity:0")
    status["number:203"] = {"value": 34}
    monkeypatch.setattr(mock_rpc_device, "status", status)

    await init_integration(hass, 3)

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-number:203-number_current_humidity"

    assert (state := hass.states.get(entity_id))
    assert state.state == "34"
    assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == PERCENTAGE
    assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.HUMIDITY


async def test_rpc_object_role_sensor(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test object role based sensor."""
    config = deepcopy(mock_rpc_device.config)
    config["object:200"] = {
        "name": "Water consumption",
        "meta": {"ui": {"unit": "m3"}},
        "role": "water_consumption",
    }

    monkeypatch.setattr(mock_rpc_device, "config", config)

    status = deepcopy(mock_rpc_device.status)
    status["object:200"] = {"value": {"counter": {"total": 5.4}}}
    monkeypatch.setattr(mock_rpc_device, "status", status)

    await init_integration(hass, 3)

    assert (state := hass.states.get("sensor.test_name_water_consumption"))
    assert state.state == "5.4"
    assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfVolume.CUBIC_METERS
    assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.WATER


@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_rpc_switch_energy_sensors(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    entity_registry: EntityRegistry,
    monkeypatch: pytest.MonkeyPatch,
    snapshot: SnapshotAssertion,
) -> None:
    """Test energy sensors for switch component."""
    status = {
        "sys": {},
        "switch:0": {
            "id": 0,
            "output": True,
            "apower": 85.3,
            "aenergy": {"total": 1234567.89},
            "ret_aenergy": {"total": 98765.43},
        },
    }
    monkeypatch.setattr(mock_rpc_device, "status", status)
    await init_integration(hass, 3)

    for entity in ("energy", "energy_returned", "energy_consumed"):
        entity_id = f"{SENSOR_DOMAIN}.test_name_test_switch_0_{entity}"

        state = hass.states.get(entity_id)
        assert state == snapshot(name=f"{entity_id}-state")

        entry = entity_registry.async_get(entity_id)
        assert entry == snapshot(name=f"{entity_id}-entry")


@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_rpc_switch_no_energy_returned_sensor(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test switch component without energy returned sensor."""
    status = {
        "sys": {},
        "switch:0": {
            "id": 0,
            "output": True,
            "apower": 85.3,
            "aenergy": {"total": 1234567.89},
        },
    }
    monkeypatch.setattr(mock_rpc_device, "status", status)
    await init_integration(hass, 3)

    assert hass.states.get("sensor.test_name_test_switch_0_energy_returned") is None
    assert hass.states.get("sensor.test_name_test_switch_0_energy_consumed") is None


async def test_rpc_shelly_ev_sensors(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    monkeypatch: pytest.MonkeyPatch,
    entity_registry: EntityRegistry,
    snapshot: SnapshotAssertion,
) -> None:
    """Test Shelly EV sensors."""
    config = deepcopy(mock_rpc_device.config)
    config["enum:200"] = {
        "name": "Charger state",
        "meta": {
            "ui": {
                "titles": {
                    "charger_charging": "Charging",
                    "charger_end": "End",
                    "charger_fault": "Fault",
                    "charger_free": "Free",
                    "charger_free_fault": "Free fault",
                    "charger_insert": "Insert",
                    "charger_pause": "Pause",
                    "charger_wait": "Wait",
                },
                "view": "label",
            }
        },
        "options": [
            "charger_charging",
            "charger_end",
            "charger_fault",
            "charger_free",
            "charger_free_fault",
            "charger_insert",
            "charger_pause",
            "charger_wait",
        ],
        "role": "work_state",
    }
    config["number:201"] = {
        "name": "Session energy",
        "meta": {"ui": {"unit": "kWh", "view": "label"}},
        "role": "energy_charge",
    }
    config["number:202"] = {
        "name": "Session duration",
        "meta": {"ui": {"unit": "min", "view": "label"}},
        "role": "time_charge",
    }
    config["object:200"] = {"role": "phase_info"}
    monkeypatch.setattr(mock_rpc_device, "config", config)

    status = deepcopy(mock_rpc_device.status)
    status["enum:200"] = {"value": "charger_charging"}
    status["number:201"] = {"value": 5.0}
    status["number:202"] = {"value": 60}
    status["object:200"] = {
        "value": {
            "phase_a": {"voltage": 231.7, "current": 8.7, "power": 2.015},
            "phase_b": {"voltage": 8.9, "current": 1.2, "power": 2.02},
            "phase_c": {"voltage": 5.5, "current": 1.1, "power": 3.03},
        }
    }
    monkeypatch.setattr(mock_rpc_device, "status", status)

    await init_integration(hass, 3)

    for entity in (
        "charger_state",
        "session_energy",
        "session_duration",
        "phase_a_current",
        "phase_b_current",
        "phase_c_current",
        "phase_a_power",
        "phase_b_power",
        "phase_c_power",
        "phase_a_voltage",
        "phase_b_voltage",
        "phase_c_voltage",
    ):
        entity_id = f"{SENSOR_DOMAIN}.test_name_{entity}"

        state = hass.states.get(entity_id)
        assert state == snapshot(name=f"{entity_id}-state")

        entry = entity_registry.async_get(entity_id)
        assert entry == snapshot(name=f"{entity_id}-entry")


async def test_block_friendly_name_sleeping_sensor(
    hass: HomeAssistant,
    mock_block_device: Mock,
    device_registry: DeviceRegistry,
    entity_registry: EntityRegistry,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test friendly name for restored sleeping sensor."""
    entry = await init_integration(hass, 1, sleep_period=1000, skip_setup=True)
    device = register_device(device_registry, entry)

    entity = entity_registry.async_get_or_create(
        SENSOR_DOMAIN,
        DOMAIN,
        f"{MOCK_MAC}-sensor_0-temp",
        suggested_object_id="test_name_temperature",
        original_name="Test name temperature",
        disabled_by=None,
        config_entry=entry,
        device_id=device.id,
    )

    # Old name, the word "temperature" starts with a lower case letter
    assert entity.original_name == "Test name temperature"

    await hass.config_entries.async_setup(entry.entry_id)
    await hass.async_block_till_done()

    assert (state := hass.states.get(entity.entity_id))

    # New name, the word "temperature" starts with a capital letter
    assert state.attributes[ATTR_FRIENDLY_NAME] == "Test name Temperature"

    # Make device online
    monkeypatch.setattr(mock_block_device, "initialized", True)
    mock_block_device.mock_online()
    await hass.async_block_till_done(wait_background_tasks=True)

    assert (state := hass.states.get(entity.entity_id))
    assert state.attributes[ATTR_FRIENDLY_NAME] == "Test name Temperature"


async def test_rpc_presence_component(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    monkeypatch: pytest.MonkeyPatch,
    entity_registry: EntityRegistry,
) -> None:
    """Test RPC sensor entity for presence component."""
    config = deepcopy(mock_rpc_device.config)
    config["presence"] = {"enable": True}
    monkeypatch.setattr(mock_rpc_device, "config", config)

    status = deepcopy(mock_rpc_device.status)
    status["presence"] = {"num_objects": 2}
    monkeypatch.setattr(mock_rpc_device, "status", status)

    mock_config_entry = await init_integration(hass, 4)

    entity_id = f"{SENSOR_DOMAIN}.test_name_detected_objects"

    assert (state := hass.states.get(entity_id))
    assert state.state == "2"

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-presence-presence_num_objects"

    mutate_rpc_device_status(monkeypatch, mock_rpc_device, "presence", "num_objects", 0)
    mock_rpc_device.mock_update()

    assert (state := hass.states.get(entity_id))
    assert state.state == "0"

    config = deepcopy(mock_rpc_device.config)
    config["presence"] = {"enable": False}
    monkeypatch.setattr(mock_rpc_device, "config", config)
    await hass.config_entries.async_reload(mock_config_entry.entry_id)
    mock_rpc_device.mock_update()

    assert (state := hass.states.get(entity_id))
    assert state.state == STATE_UNAVAILABLE


async def test_rpc_presencezone_component(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    monkeypatch: pytest.MonkeyPatch,
    entity_registry: EntityRegistry,
) -> None:
    """Test RPC sensor entity for presencezone component."""
    config = deepcopy(mock_rpc_device.config)
    config["presencezone:201"] = {"name": "Other zone", "enable": True}
    monkeypatch.setattr(mock_rpc_device, "config", config)

    status = deepcopy(mock_rpc_device.status)
    status["presencezone:201"] = {"state": True, "num_objects": 3}
    monkeypatch.setattr(mock_rpc_device, "status", status)

    mock_config_entry = await init_integration(hass, 4)

    entity_id = f"{SENSOR_DOMAIN}.test_name_other_zone_detected_objects"

    assert (state := hass.states.get(entity_id))
    assert state.state == "3"

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-presencezone:201-presencezone_num_objects"

    mutate_rpc_device_status(
        monkeypatch, mock_rpc_device, "presencezone:201", "num_objects", 2
    )
    mock_rpc_device.mock_update()

    assert (state := hass.states.get(entity_id))
    assert state.state == "2"

    config = deepcopy(mock_rpc_device.config)
    config["presencezone:201"] = {"enable": False}
    monkeypatch.setattr(mock_rpc_device, "config", config)
    await hass.config_entries.async_reload(mock_config_entry.entry_id)
    mock_rpc_device.mock_update()

    assert (state := hass.states.get(entity_id))
    assert state.state == STATE_UNAVAILABLE


@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_rpc_pm1_energy_consumed_sensor(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    entity_registry: EntityRegistry,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test energy sensors for switch component."""
    status = {
        "sys": {},
        "pm1:0": {
            "id": 0,
            "voltage": 235.0,
            "current": 0.957,
            "apower": -220.3,
            "freq": 50.0,
            "aenergy": {"total": 3000.000},
            "ret_aenergy": {"total": 1000.000},
        },
    }
    monkeypatch.setattr(mock_rpc_device, "status", status)
    await init_integration(hass, 3)

    assert (state := hass.states.get(f"{SENSOR_DOMAIN}.test_name_energy"))
    assert state.state == "3.0"

    assert (state := hass.states.get(f"{SENSOR_DOMAIN}.test_name_energy_returned"))
    assert state.state == "1.0"

    entity_id = f"{SENSOR_DOMAIN}.test_name_energy_consumed"
    # energy consumed = energy - energy returned
    assert (state := hass.states.get(entity_id))
    assert state.state == "2.0"

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-pm1:0-consumed_energy_pm1"


@pytest.mark.parametrize(("key"), ["aenergy", "ret_aenergy"])
@pytest.mark.usefixtures("entity_registry_enabled_by_default")
async def test_rpc_pm1_energy_consumed_sensor_non_float_value(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    monkeypatch: pytest.MonkeyPatch,
    key: str,
) -> None:
    """Test energy sensors for switch component."""
    entity_id = f"{SENSOR_DOMAIN}.test_name_energy_consumed"
    status = {
        "sys": {},
        "pm1:0": {
            "id": 0,
            "voltage": 235.0,
            "current": 0.957,
            "apower": -220.3,
            "freq": 50.0,
            "aenergy": {"total": 3000.000},
            "ret_aenergy": {"total": 1000.000},
        },
    }
    monkeypatch.setattr(mock_rpc_device, "status", status)
    await init_integration(hass, 3)

    assert (state := hass.states.get(entity_id))
    assert state.state == "2.0"

    mutate_rpc_device_status(
        monkeypatch, mock_rpc_device, "pm1:0", key, {"total": None}
    )
    mock_rpc_device.mock_update()

    assert (state := hass.states.get(entity_id))
    assert state.state == STATE_UNKNOWN


async def test_cury_sensor_entity(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    entity_registry: EntityRegistry,
    snapshot: SnapshotAssertion,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test sensor entities for cury component."""
    status = {
        "cury:0": {
            "id": 0,
            "slots": {
                "left": {
                    "intensity": 70,
                    "on": True,
                    "vial": {"level": 27, "name": "Forest Dream"},
                },
                "right": {
                    "intensity": 70,
                    "on": False,
                    "vial": {"level": 84, "name": "Velvet Rose"},
                },
            },
        }
    }
    monkeypatch.setattr(mock_rpc_device, "status", status)
    await init_integration(hass, 3)

    for entity in (
        "left_slot_level",
        "right_slot_level",
        "left_slot_vial",
        "right_slot_vial",
    ):
        entity_id = f"{SENSOR_DOMAIN}.test_name_{entity}"

        state = hass.states.get(entity_id)
        assert state == snapshot(name=f"{entity_id}-state")

        entry = entity_registry.async_get(entity_id)
        assert entry == snapshot(name=f"{entity_id}-entry")


async def test_shelly_irrigation_weather_sensors(
    hass: HomeAssistant,
    mock_rpc_device: Mock,
    entity_registry: EntityRegistry,
    snapshot: SnapshotAssertion,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test Shelly Irrigation controller FK-06X weather sensors."""
    device_fixture = await async_load_json_object_fixture(
        hass, "fk-06x_gen3_irrigation.json", DOMAIN
    )
    monkeypatch.setattr(mock_rpc_device, "shelly", device_fixture["shelly"])
    monkeypatch.setattr(mock_rpc_device, "status", device_fixture["status"])
    monkeypatch.setattr(mock_rpc_device, "config", device_fixture["config"])

    config_entry = await init_integration(hass, gen=3)

    for entity in ("average_temperature", "rainfall"):
        entity_id = f"{SENSOR_DOMAIN}.test_name_{entity}"

        state = hass.states.get(entity_id)
        assert state == snapshot(name=f"{entity_id}-state")

        entry = entity_registry.async_get(entity_id)
        assert entry == snapshot(name=f"{entity_id}-entry")

    # weather api disabled
    monkeypatch.setitem(mock_rpc_device.config["service:0"], "weather_api", False)
    await hass.config_entries.async_reload(config_entry.entry_id)
    await hass.async_block_till_done()

    for entity in ("average_temperature", "rainfall"):
        entity_id = f"{SENSOR_DOMAIN}.test_name_{entity}"
        assert hass.states.get(entity_id) is None


async def test_rpc_rgbcct_sensors(
    hass: HomeAssistant,
    entity_registry: EntityRegistry,
    mock_rpc_device: Mock,
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    """Test sensors for RGBCCT light."""
    config = deepcopy(mock_rpc_device.config)
    config["rgbcct:0"] = {"id": 0}
    monkeypatch.setattr(mock_rpc_device, "config", config)

    status = deepcopy(mock_rpc_device.status)
    status["rgbcct:0"] = {
        "aenergy": {"total": 45.141},
        "apower": 12.2,
    }
    monkeypatch.setattr(mock_rpc_device, "status", status)

    await init_integration(hass, 2)

    entity_id = "sensor.test_name_power"

    assert (state := hass.states.get(entity_id))
    assert state.state == "12.2"
    assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfPower.WATT

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-rgbcct:0-power_rgbcct"
    assert entry.name is None
    assert entry.translation_key is None  # entity with device class and no channel name

    entity_id = "sensor.test_name_energy"

    assert (state := hass.states.get(entity_id))
    assert state.state == "0.045141"
    assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfEnergy.KILO_WATT_HOUR

    assert (entry := entity_registry.async_get(entity_id))
    assert entry.unique_id == "123456789ABC-rgbcct:0-energy_rgbcct"
    assert entry.name is None
    assert entry.translation_key is None  # entity with device class and no channel name
