diff --git a/homeassistant/components/homewizard/diagnostics.py b/homeassistant/components/homewizard/diagnostics.py index 814c3b78355..a8f89b67ce9 100644 --- a/homeassistant/components/homewizard/diagnostics.py +++ b/homeassistant/components/homewizard/diagnostics.py @@ -12,7 +12,14 @@ from homeassistant.core import HomeAssistant from .const import DOMAIN from .coordinator import HWEnergyDeviceUpdateCoordinator -TO_REDACT = {CONF_IP_ADDRESS, "serial", "wifi_ssid"} +TO_REDACT = { + CONF_IP_ADDRESS, + "serial", + "wifi_ssid", + "unique_meter_id", + "unique_id", + "gas_unique_id", +} async def async_get_config_entry_diagnostics( diff --git a/homeassistant/components/homewizard/sensor.py b/homeassistant/components/homewizard/sensor.py index 0e7a494dcd8..fa00e112ea4 100644 --- a/homeassistant/components/homewizard/sensor.py +++ b/homeassistant/components/homewizard/sensor.py @@ -10,7 +10,15 @@ from homeassistant.components.sensor import ( SensorStateClass, ) from homeassistant.config_entries import ConfigEntry -from homeassistant.const import PERCENTAGE, UnitOfEnergy, UnitOfPower, UnitOfVolume +from homeassistant.const import ( + PERCENTAGE, + UnitOfElectricCurrent, + UnitOfElectricPotential, + UnitOfEnergy, + UnitOfFrequency, + UnitOfPower, + UnitOfVolume, +) from homeassistant.core import HomeAssistant from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -41,6 +49,11 @@ SENSORS: Final[tuple[SensorEntityDescription, ...]] = ( icon="mdi:wifi", entity_category=EntityCategory.DIAGNOSTIC, ), + SensorEntityDescription( + key="active_tariff", + name="Active tariff", + icon="mdi:calendar-clock", + ), SensorEntityDescription( key="wifi_strength", name="Wi-Fi strength", @@ -50,6 +63,13 @@ SENSORS: Final[tuple[SensorEntityDescription, ...]] = ( entity_category=EntityCategory.DIAGNOSTIC, entity_registry_enabled_default=False, ), + SensorEntityDescription( + key="total_power_import_kwh", + name="Total power import", + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + ), SensorEntityDescription( key="total_power_import_t1_kwh", name="Total power import T1", @@ -64,6 +84,27 @@ SENSORS: Final[tuple[SensorEntityDescription, ...]] = ( device_class=SensorDeviceClass.ENERGY, state_class=SensorStateClass.TOTAL_INCREASING, ), + SensorEntityDescription( + key="total_power_import_t3_kwh", + name="Total power import T3", + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + SensorEntityDescription( + key="total_power_import_t4_kwh", + name="Total power import T4", + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + SensorEntityDescription( + key="total_power_export_kwh", + name="Total power export", + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + ), SensorEntityDescription( key="total_power_export_t1_kwh", name="Total power export T1", @@ -78,6 +119,20 @@ SENSORS: Final[tuple[SensorEntityDescription, ...]] = ( device_class=SensorDeviceClass.ENERGY, state_class=SensorStateClass.TOTAL_INCREASING, ), + SensorEntityDescription( + key="total_power_export_t3_kwh", + name="Total power export T3", + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + SensorEntityDescription( + key="total_power_export_t4_kwh", + name="Total power export T4", + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + ), SensorEntityDescription( key="active_power_w", name="Active power", @@ -106,6 +161,122 @@ SENSORS: Final[tuple[SensorEntityDescription, ...]] = ( device_class=SensorDeviceClass.POWER, state_class=SensorStateClass.MEASUREMENT, ), + SensorEntityDescription( + key="active_voltage_l1_v", + name="Active voltage L1", + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + SensorEntityDescription( + key="active_voltage_l2_v", + name="Active voltage L2", + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + SensorEntityDescription( + key="active_voltage_l3_v", + name="Active voltage L3", + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + SensorEntityDescription( + key="active_current_l1_a", + name="Active current L1", + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + SensorEntityDescription( + key="active_current_l2_a", + name="Active current L2", + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + SensorEntityDescription( + key="active_current_l3_a", + name="Active current L3", + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + SensorEntityDescription( + key="active_frequency_hz", + name="Active frequency", + native_unit_of_measurement=UnitOfFrequency.HERTZ, + device_class=SensorDeviceClass.FREQUENCY, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + SensorEntityDescription( + key="voltage_sag_l1_count", + name="Voltage sags detected L1", + icon="mdi:alert", + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="voltage_sag_l2_count", + name="Voltage sags detected L2", + icon="mdi:alert", + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="voltage_sag_l3_count", + name="Voltage sags detected L3", + icon="mdi:alert", + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="voltage_swell_l1_count", + name="Voltage swells detected L1", + icon="mdi:alert", + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="voltage_swell_l2_count", + name="Voltage swells detected L2", + icon="mdi:alert", + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="voltage_swell_l3_count", + name="Voltage swells detected L3", + icon="mdi:alert", + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="any_power_fail_count", + name="Power failures detected", + icon="mdi:transmission-tower-off", + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="long_power_fail_count", + name="Long power failures detected", + icon="mdi:transmission-tower-off", + entity_category=EntityCategory.DIAGNOSTIC, + ), + SensorEntityDescription( + key="active_power_average_w", + name="Active average demand", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + ), + SensorEntityDescription( + key="montly_power_peak_w", + name="Peak demand current month", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + ), SensorEntityDescription( key="total_gas_m3", name="Total gas", @@ -171,8 +342,11 @@ class HWEnergySensor(HomeWizardEntity, SensorEntity): if ( self.data_type in [ + "total_power_export_kwh", "total_power_export_t1_kwh", "total_power_export_t2_kwh", + "total_power_export_t3_kwh", + "total_power_export_t4_kwh", ] and self.native_value == 0 ): diff --git a/tests/components/homewizard/fixtures/data.json b/tests/components/homewizard/fixtures/data.json index 35cfd2197a1..f73d3ac1a19 100644 --- a/tests/components/homewizard/fixtures/data.json +++ b/tests/components/homewizard/fixtures/data.json @@ -1,18 +1,41 @@ { - "smr_version": 50, - "meter_model": "ISKRA 2M550T-101", "wifi_ssid": "My Wi-Fi", "wifi_strength": 100, - "total_power_import_t1_kwh": 1234.111, - "total_power_import_t2_kwh": 5678.222, + "smr_version": 50, + "meter_model": "ISKRA 2M550T-101", + "unique_id": "00112233445566778899AABBCCDDEEFF", + "active_tariff": 2, + "total_power_import_kwh": 13779.338, + "total_power_import_t1_kwh": 10830.511, + "total_power_import_t2_kwh": 2948.827, + "total_power_export_kwh": 13086.777, "total_power_export_t1_kwh": 4321.333, "total_power_export_t2_kwh": 8765.444, "active_power_w": -123, "active_power_l1_w": -123, "active_power_l2_w": 456, "active_power_l3_w": 123.456, + "active_voltage_l1_v": 230.111, + "active_voltage_l2_v": 230.222, + "active_voltage_l3_v": 230.333, + "active_current_l1_a": -4, + "active_current_l2_a": 2, + "active_current_l3_a": 0, + "active_frequency_hz": 50, + "voltage_sag_l1_count": 1, + "voltage_sag_l2_count": 2, + "voltage_sag_l3_count": 3, + "voltage_swell_l1_count": 4, + "voltage_swell_l2_count": 5, + "voltage_swell_l3_count": 6, + "any_power_fail_count": 4, + "long_power_fail_count": 5, "total_gas_m3": 1122.333, "gas_timestamp": 210314112233, + "gas_unique_id": "01FFEEDDCCBBAA99887766554433221100", + "active_power_average_w": 123.0, + "montly_power_peak_w": 1111.0, + "montly_power_peak_timestamp": 230101080010, "active_liter_lpm": 12.345, "total_liter_m3": 1234.567 } diff --git a/tests/components/homewizard/test_diagnostics.py b/tests/components/homewizard/test_diagnostics.py index 67c8d23fdaa..00253e8fe55 100644 --- a/tests/components/homewizard/test_diagnostics.py +++ b/tests/components/homewizard/test_diagnostics.py @@ -14,6 +14,7 @@ async def test_diagnostics( init_integration: MockConfigEntry, ): """Test diagnostics.""" + print(await get_diagnostics_for_config_entry(hass, hass_client, init_integration)) assert await get_diagnostics_for_config_entry( hass, hass_client, init_integration ) == { @@ -27,18 +28,18 @@ async def test_diagnostics( "firmware_version": "2.11", }, "data": { + "wifi_ssid": "**REDACTED**", + "wifi_strength": 100, "smr_version": 50, "meter_model": "ISKRA 2M550T-101", - "unique_meter_id": None, - "active_tariff": None, - "wifi_ssid": REDACTED, - "wifi_strength": 100, - "total_power_import_kwh": None, - "total_power_import_t1_kwh": 1234.111, - "total_power_import_t2_kwh": 5678.222, + "unique_meter_id": "**REDACTED**", + "active_tariff": 2, + "total_power_import_kwh": 13779.338, + "total_power_import_t1_kwh": 10830.511, + "total_power_import_t2_kwh": 2948.827, "total_power_import_t3_kwh": None, "total_power_import_t4_kwh": None, - "total_power_export_kwh": None, + "total_power_export_kwh": 13086.777, "total_power_export_t1_kwh": 4321.333, "total_power_export_t2_kwh": 8765.444, "total_power_export_t3_kwh": None, @@ -47,27 +48,27 @@ async def test_diagnostics( "active_power_l1_w": -123, "active_power_l2_w": 456, "active_power_l3_w": 123.456, - "active_voltage_l1_v": None, - "active_voltage_l2_v": None, - "active_voltage_l3_v": None, - "active_current_l1_a": None, - "active_current_l2_a": None, - "active_current_l3_a": None, - "active_frequency_hz": None, - "voltage_sag_l1_count": None, - "voltage_sag_l2_count": None, - "voltage_sag_l3_count": None, - "voltage_swell_l1_count": None, - "voltage_swell_l2_count": None, - "voltage_swell_l3_count": None, - "any_power_fail_count": None, - "long_power_fail_count": None, - "active_power_average_w": None, - "montly_power_peak_timestamp": None, - "montly_power_peak_w": None, + "active_voltage_l1_v": 230.111, + "active_voltage_l2_v": 230.222, + "active_voltage_l3_v": 230.333, + "active_current_l1_a": -4, + "active_current_l2_a": 2, + "active_current_l3_a": 0, + "active_frequency_hz": 50, + "voltage_sag_l1_count": 1, + "voltage_sag_l2_count": 2, + "voltage_sag_l3_count": 3, + "voltage_swell_l1_count": 4, + "voltage_swell_l2_count": 5, + "voltage_swell_l3_count": 6, + "any_power_fail_count": 4, + "long_power_fail_count": 5, + "active_power_average_w": 123.0, + "montly_power_peak_w": 1111.0, + "montly_power_peak_timestamp": "2023-01-01T08:00:10", "total_gas_m3": 1122.333, "gas_timestamp": "2021-03-14T11:22:33", - "gas_unique_id": None, + "gas_unique_id": "**REDACTED**", "active_liter_lpm": 12.345, "total_liter_m3": 1234.567, "external_devices": None, diff --git a/tests/components/homewizard/test_sensor.py b/tests/components/homewizard/test_sensor.py index 2e85dfff459..c90c11ac693 100644 --- a/tests/components/homewizard/test_sensor.py +++ b/tests/components/homewizard/test_sensor.py @@ -16,7 +16,10 @@ from homeassistant.const import ( ATTR_FRIENDLY_NAME, ATTR_ICON, ATTR_UNIT_OF_MEASUREMENT, + UnitOfElectricCurrent, + UnitOfElectricPotential, UnitOfEnergy, + UnitOfFrequency, UnitOfPower, UnitOfVolume, ) @@ -531,6 +534,822 @@ async def test_sensor_entity_total_gas(hass, mock_config_entry_data, mock_config assert ATTR_ICON not in state.attributes +async def test_sensor_entity_active_voltage_l1( + hass, mock_config_entry_data, mock_config_entry +): + """Test entity loads active voltage l1.""" + + api = get_mock_device() + api.data = AsyncMock(return_value=Data.from_dict({"active_voltage_l1_v": 230.123})) + + with patch( + "homeassistant.components.homewizard.coordinator.HomeWizardEnergy", + return_value=api, + ): + entry = mock_config_entry + entry.data = mock_config_entry_data + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + entity_registry = er.async_get(hass) + + disabled_entry = entity_registry.async_get( + "sensor.product_name_aabbccddeeff_active_voltage_l1" + ) + assert disabled_entry + assert disabled_entry.disabled + assert disabled_entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION + + # Enable + entry = entity_registry.async_update_entity( + disabled_entry.entity_id, **{"disabled_by": None} + ) + await hass.async_block_till_done() + assert not entry.disabled + assert entry.unique_id == "aabbccddeeff_active_voltage_l1_v" + + # Let HA reload the integration so state is set + async_fire_time_changed( + hass, + dt_util.utcnow() + timedelta(seconds=30), + ) + await hass.async_block_till_done() + + state = hass.states.get("sensor.product_name_aabbccddeeff_active_voltage_l1") + assert state + assert state.state == "230.123" + assert ( + state.attributes.get(ATTR_FRIENDLY_NAME) + == "Product Name (aabbccddeeff) Active voltage L1" + ) + assert state.attributes.get(ATTR_STATE_CLASS) == SensorStateClass.MEASUREMENT + assert ( + state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) + == UnitOfElectricPotential.VOLT + ) + assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.VOLTAGE + assert ATTR_ICON not in state.attributes + + +async def test_sensor_entity_active_voltage_l2( + hass, mock_config_entry_data, mock_config_entry +): + """Test entity loads active voltage l2.""" + + api = get_mock_device() + api.data = AsyncMock(return_value=Data.from_dict({"active_voltage_l2_v": 230.123})) + + with patch( + "homeassistant.components.homewizard.coordinator.HomeWizardEnergy", + return_value=api, + ): + entry = mock_config_entry + entry.data = mock_config_entry_data + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + entity_registry = er.async_get(hass) + + disabled_entry = entity_registry.async_get( + "sensor.product_name_aabbccddeeff_active_voltage_l2" + ) + assert disabled_entry + assert disabled_entry.disabled + assert disabled_entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION + + # Enable + entry = entity_registry.async_update_entity( + disabled_entry.entity_id, **{"disabled_by": None} + ) + await hass.async_block_till_done() + assert not entry.disabled + assert entry.unique_id == "aabbccddeeff_active_voltage_l2_v" + + # Let HA reload the integration so state is set + async_fire_time_changed( + hass, + dt_util.utcnow() + timedelta(seconds=30), + ) + await hass.async_block_till_done() + + state = hass.states.get("sensor.product_name_aabbccddeeff_active_voltage_l2") + assert state + assert state.state == "230.123" + assert ( + state.attributes.get(ATTR_FRIENDLY_NAME) + == "Product Name (aabbccddeeff) Active voltage L2" + ) + assert state.attributes.get(ATTR_STATE_CLASS) == SensorStateClass.MEASUREMENT + assert ( + state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) + == UnitOfElectricPotential.VOLT + ) + assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.VOLTAGE + assert ATTR_ICON not in state.attributes + + +async def test_sensor_entity_active_voltage_l3( + hass, mock_config_entry_data, mock_config_entry +): + """Test entity loads active voltage l3.""" + + api = get_mock_device() + api.data = AsyncMock(return_value=Data.from_dict({"active_voltage_l3_v": 230.123})) + + with patch( + "homeassistant.components.homewizard.coordinator.HomeWizardEnergy", + return_value=api, + ): + entry = mock_config_entry + entry.data = mock_config_entry_data + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + entity_registry = er.async_get(hass) + + disabled_entry = entity_registry.async_get( + "sensor.product_name_aabbccddeeff_active_voltage_l3" + ) + assert disabled_entry + assert disabled_entry.disabled + assert disabled_entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION + + # Enable + entry = entity_registry.async_update_entity( + disabled_entry.entity_id, **{"disabled_by": None} + ) + await hass.async_block_till_done() + assert not entry.disabled + assert entry.unique_id == "aabbccddeeff_active_voltage_l3_v" + + # Let HA reload the integration so state is set + async_fire_time_changed( + hass, + dt_util.utcnow() + timedelta(seconds=30), + ) + await hass.async_block_till_done() + + state = hass.states.get("sensor.product_name_aabbccddeeff_active_voltage_l3") + assert state + assert state.state == "230.123" + assert ( + state.attributes.get(ATTR_FRIENDLY_NAME) + == "Product Name (aabbccddeeff) Active voltage L3" + ) + assert state.attributes.get(ATTR_STATE_CLASS) == SensorStateClass.MEASUREMENT + assert ( + state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) + == UnitOfElectricPotential.VOLT + ) + assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.VOLTAGE + assert ATTR_ICON not in state.attributes + + +async def test_sensor_entity_active_current_l1( + hass, mock_config_entry_data, mock_config_entry +): + """Test entity loads active current l1.""" + + api = get_mock_device() + api.data = AsyncMock(return_value=Data.from_dict({"active_current_l1_a": 12.34})) + + with patch( + "homeassistant.components.homewizard.coordinator.HomeWizardEnergy", + return_value=api, + ): + entry = mock_config_entry + entry.data = mock_config_entry_data + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + entity_registry = er.async_get(hass) + + disabled_entry = entity_registry.async_get( + "sensor.product_name_aabbccddeeff_active_current_l1" + ) + assert disabled_entry + assert disabled_entry.disabled + assert disabled_entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION + + # Enable + entry = entity_registry.async_update_entity( + disabled_entry.entity_id, **{"disabled_by": None} + ) + await hass.async_block_till_done() + assert not entry.disabled + assert entry.unique_id == "aabbccddeeff_active_current_l1_a" + + # Let HA reload the integration so state is set + async_fire_time_changed( + hass, + dt_util.utcnow() + timedelta(seconds=30), + ) + await hass.async_block_till_done() + + state = hass.states.get("sensor.product_name_aabbccddeeff_active_current_l1") + assert state + assert state.state == "12.34" + assert ( + state.attributes.get(ATTR_FRIENDLY_NAME) + == "Product Name (aabbccddeeff) Active current L1" + ) + assert state.attributes.get(ATTR_STATE_CLASS) == SensorStateClass.MEASUREMENT + assert ( + state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) + == UnitOfElectricCurrent.AMPERE + ) + assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.CURRENT + assert ATTR_ICON not in state.attributes + + +async def test_sensor_entity_active_current_l2( + hass, mock_config_entry_data, mock_config_entry +): + """Test entity loads active current l2.""" + + api = get_mock_device() + api.data = AsyncMock(return_value=Data.from_dict({"active_current_l2_a": 12.34})) + + with patch( + "homeassistant.components.homewizard.coordinator.HomeWizardEnergy", + return_value=api, + ): + entry = mock_config_entry + entry.data = mock_config_entry_data + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + entity_registry = er.async_get(hass) + + disabled_entry = entity_registry.async_get( + "sensor.product_name_aabbccddeeff_active_current_l2" + ) + assert disabled_entry + assert disabled_entry.disabled + assert disabled_entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION + + # Enable + entry = entity_registry.async_update_entity( + disabled_entry.entity_id, **{"disabled_by": None} + ) + await hass.async_block_till_done() + assert not entry.disabled + assert entry.unique_id == "aabbccddeeff_active_current_l2_a" + + # Let HA reload the integration so state is set + async_fire_time_changed( + hass, + dt_util.utcnow() + timedelta(seconds=30), + ) + await hass.async_block_till_done() + + state = hass.states.get("sensor.product_name_aabbccddeeff_active_current_l2") + assert state + assert state.state == "12.34" + assert ( + state.attributes.get(ATTR_FRIENDLY_NAME) + == "Product Name (aabbccddeeff) Active current L2" + ) + assert state.attributes.get(ATTR_STATE_CLASS) == SensorStateClass.MEASUREMENT + assert ( + state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) + == UnitOfElectricCurrent.AMPERE + ) + assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.CURRENT + assert ATTR_ICON not in state.attributes + + +async def test_sensor_entity_active_current_l3( + hass, mock_config_entry_data, mock_config_entry +): + """Test entity loads active current l3.""" + + api = get_mock_device() + api.data = AsyncMock(return_value=Data.from_dict({"active_current_l3_a": 12.34})) + + with patch( + "homeassistant.components.homewizard.coordinator.HomeWizardEnergy", + return_value=api, + ): + entry = mock_config_entry + entry.data = mock_config_entry_data + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + entity_registry = er.async_get(hass) + + disabled_entry = entity_registry.async_get( + "sensor.product_name_aabbccddeeff_active_current_l3" + ) + assert disabled_entry + assert disabled_entry.disabled + assert disabled_entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION + + # Enable + entry = entity_registry.async_update_entity( + disabled_entry.entity_id, **{"disabled_by": None} + ) + await hass.async_block_till_done() + assert not entry.disabled + assert entry.unique_id == "aabbccddeeff_active_current_l3_a" + + # Let HA reload the integration so state is set + async_fire_time_changed( + hass, + dt_util.utcnow() + timedelta(seconds=30), + ) + await hass.async_block_till_done() + + state = hass.states.get("sensor.product_name_aabbccddeeff_active_current_l3") + assert state + assert state.state == "12.34" + assert ( + state.attributes.get(ATTR_FRIENDLY_NAME) + == "Product Name (aabbccddeeff) Active current L3" + ) + assert state.attributes.get(ATTR_STATE_CLASS) == SensorStateClass.MEASUREMENT + assert ( + state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) + == UnitOfElectricCurrent.AMPERE + ) + assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.CURRENT + assert ATTR_ICON not in state.attributes + + +async def test_sensor_entity_active_frequency( + hass, mock_config_entry_data, mock_config_entry +): + """Test entity loads active frequency.""" + + api = get_mock_device() + api.data = AsyncMock(return_value=Data.from_dict({"active_frequency_hz": 50.12})) + + with patch( + "homeassistant.components.homewizard.coordinator.HomeWizardEnergy", + return_value=api, + ): + entry = mock_config_entry + entry.data = mock_config_entry_data + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + entity_registry = er.async_get(hass) + + disabled_entry = entity_registry.async_get( + "sensor.product_name_aabbccddeeff_active_frequency" + ) + assert disabled_entry + assert disabled_entry.disabled + assert disabled_entry.disabled_by is er.RegistryEntryDisabler.INTEGRATION + + # Enable + entry = entity_registry.async_update_entity( + disabled_entry.entity_id, **{"disabled_by": None} + ) + await hass.async_block_till_done() + assert not entry.disabled + assert entry.unique_id == "aabbccddeeff_active_frequency_hz" + + # Let HA reload the integration so state is set + async_fire_time_changed( + hass, + dt_util.utcnow() + timedelta(seconds=30), + ) + await hass.async_block_till_done() + + state = hass.states.get("sensor.product_name_aabbccddeeff_active_frequency") + assert state + assert state.state == "50.12" + assert ( + state.attributes.get(ATTR_FRIENDLY_NAME) + == "Product Name (aabbccddeeff) Active frequency" + ) + assert state.attributes.get(ATTR_STATE_CLASS) == SensorStateClass.MEASUREMENT + assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfFrequency.HERTZ + assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.FREQUENCY + assert ATTR_ICON not in state.attributes + + +async def test_sensor_entity_voltage_sag_count_l1( + hass, mock_config_entry_data, mock_config_entry +): + """Test entity loads voltage_sag_count_l1.""" + + api = get_mock_device() + api.data = AsyncMock(return_value=Data.from_dict({"voltage_sag_l1_count": 123})) + + with patch( + "homeassistant.components.homewizard.coordinator.HomeWizardEnergy", + return_value=api, + ): + entry = mock_config_entry + entry.data = mock_config_entry_data + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + entity_registry = er.async_get(hass) + + state = hass.states.get("sensor.product_name_aabbccddeeff_voltage_sags_detected_l1") + entry = entity_registry.async_get( + "sensor.product_name_aabbccddeeff_voltage_sags_detected_l1" + ) + assert entry + assert state + assert entry.unique_id == "aabbccddeeff_voltage_sag_l1_count" + assert not entry.disabled + assert state.state == "123" + assert ( + state.attributes.get(ATTR_FRIENDLY_NAME) + == "Product Name (aabbccddeeff) Voltage sags detected L1" + ) + assert ATTR_STATE_CLASS not in state.attributes + assert ATTR_UNIT_OF_MEASUREMENT not in state.attributes + assert ATTR_DEVICE_CLASS not in state.attributes + + +async def test_sensor_entity_voltage_sag_count_l2( + hass, mock_config_entry_data, mock_config_entry +): + """Test entity loads voltage_sag_count_l2.""" + + api = get_mock_device() + api.data = AsyncMock(return_value=Data.from_dict({"voltage_sag_l2_count": 123})) + + with patch( + "homeassistant.components.homewizard.coordinator.HomeWizardEnergy", + return_value=api, + ): + entry = mock_config_entry + entry.data = mock_config_entry_data + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + entity_registry = er.async_get(hass) + + state = hass.states.get("sensor.product_name_aabbccddeeff_voltage_sags_detected_l2") + entry = entity_registry.async_get( + "sensor.product_name_aabbccddeeff_voltage_sags_detected_l2" + ) + assert entry + assert state + assert entry.unique_id == "aabbccddeeff_voltage_sag_l2_count" + assert not entry.disabled + assert state.state == "123" + assert ( + state.attributes.get(ATTR_FRIENDLY_NAME) + == "Product Name (aabbccddeeff) Voltage sags detected L2" + ) + assert ATTR_STATE_CLASS not in state.attributes + assert ATTR_UNIT_OF_MEASUREMENT not in state.attributes + assert ATTR_DEVICE_CLASS not in state.attributes + + +async def test_sensor_entity_voltage_sag_count_l3( + hass, mock_config_entry_data, mock_config_entry +): + """Test entity loads voltage_sag_count_l3.""" + + api = get_mock_device() + api.data = AsyncMock(return_value=Data.from_dict({"voltage_sag_l3_count": 123})) + + with patch( + "homeassistant.components.homewizard.coordinator.HomeWizardEnergy", + return_value=api, + ): + entry = mock_config_entry + entry.data = mock_config_entry_data + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + entity_registry = er.async_get(hass) + + state = hass.states.get("sensor.product_name_aabbccddeeff_voltage_sags_detected_l3") + entry = entity_registry.async_get( + "sensor.product_name_aabbccddeeff_voltage_sags_detected_l3" + ) + assert entry + assert state + assert entry.unique_id == "aabbccddeeff_voltage_sag_l3_count" + assert not entry.disabled + assert state.state == "123" + assert ( + state.attributes.get(ATTR_FRIENDLY_NAME) + == "Product Name (aabbccddeeff) Voltage sags detected L3" + ) + assert ATTR_STATE_CLASS not in state.attributes + assert ATTR_UNIT_OF_MEASUREMENT not in state.attributes + assert ATTR_DEVICE_CLASS not in state.attributes + + +async def test_sensor_entity_voltage_swell_count_l1( + hass, mock_config_entry_data, mock_config_entry +): + """Test entity loads voltage_swell_count_l1.""" + + api = get_mock_device() + api.data = AsyncMock(return_value=Data.from_dict({"voltage_swell_l1_count": 123})) + + with patch( + "homeassistant.components.homewizard.coordinator.HomeWizardEnergy", + return_value=api, + ): + entry = mock_config_entry + entry.data = mock_config_entry_data + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + entity_registry = er.async_get(hass) + + state = hass.states.get( + "sensor.product_name_aabbccddeeff_voltage_swells_detected_l1" + ) + entry = entity_registry.async_get( + "sensor.product_name_aabbccddeeff_voltage_swells_detected_l1" + ) + assert entry + assert state + assert entry.unique_id == "aabbccddeeff_voltage_swell_l1_count" + assert not entry.disabled + assert state.state == "123" + assert ( + state.attributes.get(ATTR_FRIENDLY_NAME) + == "Product Name (aabbccddeeff) Voltage swells detected L1" + ) + assert ATTR_STATE_CLASS not in state.attributes + assert ATTR_UNIT_OF_MEASUREMENT not in state.attributes + assert ATTR_DEVICE_CLASS not in state.attributes + + +async def test_sensor_entity_voltage_swell_count_l2( + hass, mock_config_entry_data, mock_config_entry +): + """Test entity loads voltage_swell_count_l2.""" + + api = get_mock_device() + api.data = AsyncMock(return_value=Data.from_dict({"voltage_swell_l2_count": 123})) + + with patch( + "homeassistant.components.homewizard.coordinator.HomeWizardEnergy", + return_value=api, + ): + entry = mock_config_entry + entry.data = mock_config_entry_data + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + entity_registry = er.async_get(hass) + + state = hass.states.get( + "sensor.product_name_aabbccddeeff_voltage_swells_detected_l2" + ) + entry = entity_registry.async_get( + "sensor.product_name_aabbccddeeff_voltage_swells_detected_l2" + ) + assert entry + assert state + assert entry.unique_id == "aabbccddeeff_voltage_swell_l2_count" + assert not entry.disabled + assert state.state == "123" + assert ( + state.attributes.get(ATTR_FRIENDLY_NAME) + == "Product Name (aabbccddeeff) Voltage swells detected L2" + ) + assert ATTR_STATE_CLASS not in state.attributes + assert ATTR_UNIT_OF_MEASUREMENT not in state.attributes + assert ATTR_DEVICE_CLASS not in state.attributes + + +async def test_sensor_entity_voltage_swell_count_l3( + hass, mock_config_entry_data, mock_config_entry +): + """Test entity loads voltage_swell_count_l3.""" + + api = get_mock_device() + api.data = AsyncMock(return_value=Data.from_dict({"voltage_swell_l3_count": 123})) + + with patch( + "homeassistant.components.homewizard.coordinator.HomeWizardEnergy", + return_value=api, + ): + entry = mock_config_entry + entry.data = mock_config_entry_data + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + entity_registry = er.async_get(hass) + + state = hass.states.get( + "sensor.product_name_aabbccddeeff_voltage_swells_detected_l3" + ) + entry = entity_registry.async_get( + "sensor.product_name_aabbccddeeff_voltage_swells_detected_l3" + ) + assert entry + assert state + assert entry.unique_id == "aabbccddeeff_voltage_swell_l3_count" + assert not entry.disabled + assert state.state == "123" + assert ( + state.attributes.get(ATTR_FRIENDLY_NAME) + == "Product Name (aabbccddeeff) Voltage swells detected L3" + ) + assert ATTR_STATE_CLASS not in state.attributes + assert ATTR_UNIT_OF_MEASUREMENT not in state.attributes + assert ATTR_DEVICE_CLASS not in state.attributes + + +async def test_sensor_entity_any_power_fail_count( + hass, mock_config_entry_data, mock_config_entry +): + """Test entity loads any power fail count.""" + + api = get_mock_device() + api.data = AsyncMock(return_value=Data.from_dict({"any_power_fail_count": 123})) + + with patch( + "homeassistant.components.homewizard.coordinator.HomeWizardEnergy", + return_value=api, + ): + entry = mock_config_entry + entry.data = mock_config_entry_data + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + entity_registry = er.async_get(hass) + + state = hass.states.get("sensor.product_name_aabbccddeeff_power_failures_detected") + entry = entity_registry.async_get( + "sensor.product_name_aabbccddeeff_power_failures_detected" + ) + assert entry + assert state + assert entry.unique_id == "aabbccddeeff_any_power_fail_count" + assert not entry.disabled + assert state.state == "123" + assert ( + state.attributes.get(ATTR_FRIENDLY_NAME) + == "Product Name (aabbccddeeff) Power failures detected" + ) + assert ATTR_STATE_CLASS not in state.attributes + assert ATTR_UNIT_OF_MEASUREMENT not in state.attributes + assert ATTR_DEVICE_CLASS not in state.attributes + + +async def test_sensor_entity_long_power_fail_count( + hass, mock_config_entry_data, mock_config_entry +): + """Test entity loads long power fail count.""" + + api = get_mock_device() + api.data = AsyncMock(return_value=Data.from_dict({"long_power_fail_count": 123})) + + with patch( + "homeassistant.components.homewizard.coordinator.HomeWizardEnergy", + return_value=api, + ): + entry = mock_config_entry + entry.data = mock_config_entry_data + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + entity_registry = er.async_get(hass) + + state = hass.states.get( + "sensor.product_name_aabbccddeeff_long_power_failures_detected" + ) + entry = entity_registry.async_get( + "sensor.product_name_aabbccddeeff_long_power_failures_detected" + ) + assert entry + assert state + assert entry.unique_id == "aabbccddeeff_long_power_fail_count" + assert not entry.disabled + assert state.state == "123" + assert ( + state.attributes.get(ATTR_FRIENDLY_NAME) + == "Product Name (aabbccddeeff) Long power failures detected" + ) + assert ATTR_STATE_CLASS not in state.attributes + assert ATTR_UNIT_OF_MEASUREMENT not in state.attributes + assert ATTR_DEVICE_CLASS not in state.attributes + + +async def test_sensor_entity_active_power_average( + hass, mock_config_entry_data, mock_config_entry +): + """Test entity loads active power average.""" + + api = get_mock_device() + api.data = AsyncMock( + return_value=Data.from_dict({"active_power_average_w": 123.456}) + ) + + with patch( + "homeassistant.components.homewizard.coordinator.HomeWizardEnergy", + return_value=api, + ): + entry = mock_config_entry + entry.data = mock_config_entry_data + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + entity_registry = er.async_get(hass) + + state = hass.states.get("sensor.product_name_aabbccddeeff_active_average_demand") + entry = entity_registry.async_get( + "sensor.product_name_aabbccddeeff_active_average_demand" + ) + assert entry + assert state + assert entry.unique_id == "aabbccddeeff_active_power_average_w" + assert not entry.disabled + assert state.state == "123.456" + assert ( + state.attributes.get(ATTR_FRIENDLY_NAME) + == "Product Name (aabbccddeeff) Active average demand" + ) + + assert state.attributes.get(ATTR_STATE_CLASS) is None + assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfPower.WATT + assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.POWER + assert ATTR_ICON not in state.attributes + + +async def test_sensor_entity_montly_power_peak( + hass, mock_config_entry_data, mock_config_entry +): + """Test entity loads monthly power peak.""" + + api = get_mock_device() + api.data = AsyncMock(return_value=Data.from_dict({"montly_power_peak_w": 1234.456})) + + with patch( + "homeassistant.components.homewizard.coordinator.HomeWizardEnergy", + return_value=api, + ): + entry = mock_config_entry + entry.data = mock_config_entry_data + entry.add_to_hass(hass) + + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + entity_registry = er.async_get(hass) + + state = hass.states.get( + "sensor.product_name_aabbccddeeff_peak_demand_current_month" + ) + entry = entity_registry.async_get( + "sensor.product_name_aabbccddeeff_peak_demand_current_month" + ) + assert entry + assert state + assert entry.unique_id == "aabbccddeeff_montly_power_peak_w" + assert not entry.disabled + assert state.state == "1234.456" + assert ( + state.attributes.get(ATTR_FRIENDLY_NAME) + == "Product Name (aabbccddeeff) Peak demand current month" + ) + + assert state.attributes.get(ATTR_STATE_CLASS) is None + assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == UnitOfPower.WATT + assert state.attributes.get(ATTR_DEVICE_CLASS) == SensorDeviceClass.POWER + assert ATTR_ICON not in state.attributes + + async def test_sensor_entity_active_liters( hass, mock_config_entry_data, mock_config_entry ): @@ -660,7 +1479,13 @@ async def test_sensor_entity_export_disabled_when_unused( api = get_mock_device() api.data = AsyncMock( return_value=Data.from_dict( - {"total_power_export_t1_kwh": 0, "total_power_export_t2_kwh": 0} + { + "total_power_export_kwh": 0, + "total_power_export_t1_kwh": 0, + "total_power_export_t2_kwh": 0, + "total_power_export_t3_kwh": 0, + "total_power_export_t4_kwh": 0, + } ) ) @@ -677,6 +1502,12 @@ async def test_sensor_entity_export_disabled_when_unused( entity_registry = er.async_get(hass) + entry = entity_registry.async_get( + "sensor.product_name_aabbccddeeff_total_power_export" + ) + assert entry + assert entry.disabled + entry = entity_registry.async_get( "sensor.product_name_aabbccddeeff_total_power_export_t1" )