diff --git a/CODEOWNERS b/CODEOWNERS index bad799a69e6..bcf8b3d745a 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -788,6 +788,8 @@ build.json @home-assistant/supervisor /tests/components/improv_ble/ @emontnemery /homeassistant/components/incomfort/ @jbouwh /tests/components/incomfort/ @jbouwh +/homeassistant/components/indevolt/ @xirtnl +/tests/components/indevolt/ @xirtnl /homeassistant/components/inels/ @epdevlab /tests/components/inels/ @epdevlab /homeassistant/components/influxdb/ @mdegat01 diff --git a/homeassistant/components/indevolt/__init__.py b/homeassistant/components/indevolt/__init__.py new file mode 100644 index 00000000000..a3e045bbf43 --- /dev/null +++ b/homeassistant/components/indevolt/__init__.py @@ -0,0 +1,28 @@ +"""Home Assistant integration for indevolt device.""" + +from __future__ import annotations + +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant + +from .coordinator import IndevoltConfigEntry, IndevoltCoordinator + +PLATFORMS: list[Platform] = [Platform.SENSOR] + + +async def async_setup_entry(hass: HomeAssistant, entry: IndevoltConfigEntry) -> bool: + """Set up indevolt integration entry using given configuration.""" + coordinator = IndevoltCoordinator(hass, entry) + + await coordinator.async_config_entry_first_refresh() + + entry.runtime_data = coordinator + + await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) + + return True + + +async def async_unload_entry(hass: HomeAssistant, entry: IndevoltConfigEntry) -> bool: + """Unload a config entry / clean up resources (when integration is removed / reloaded).""" + return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) diff --git a/homeassistant/components/indevolt/config_flow.py b/homeassistant/components/indevolt/config_flow.py new file mode 100644 index 00000000000..9b813b425da --- /dev/null +++ b/homeassistant/components/indevolt/config_flow.py @@ -0,0 +1,83 @@ +"""Config flow for Indevolt integration.""" + +import logging +from typing import Any + +from aiohttp import ClientError +from indevolt_api import IndevoltAPI +import voluptuous as vol + +from homeassistant.config_entries import ConfigFlow, ConfigFlowResult +from homeassistant.const import CONF_HOST, CONF_MODEL +from homeassistant.helpers.aiohttp_client import async_get_clientsession + +from .const import CONF_GENERATION, CONF_SERIAL_NUMBER, DEFAULT_PORT, DOMAIN + +_LOGGER = logging.getLogger(__name__) + + +class IndevoltConfigFlow(ConfigFlow, domain=DOMAIN): + """Configuration flow for Indevolt integration.""" + + VERSION = 1 + + async def async_step_user( + self, user_input: dict[str, Any] | None = None + ) -> ConfigFlowResult: + """Handle the initial user configuration step.""" + errors: dict[str, str] = {} + + # Attempt to setup from user input + if user_input is not None: + errors, device_data = await self._async_validate_input(user_input) + + if not errors and device_data: + await self.async_set_unique_id(device_data[CONF_SERIAL_NUMBER]) + + # Handle initial setup + self._abort_if_unique_id_configured() + return self.async_create_entry( + title=f"INDEVOLT {device_data[CONF_MODEL]}", + data={ + CONF_HOST: user_input[CONF_HOST], + **device_data, + }, + ) + + # Retrieve user input + return self.async_show_form( + step_id="user", + data_schema=vol.Schema({vol.Required(CONF_HOST): str}), + errors=errors, + ) + + async def _async_validate_input( + self, user_input: dict[str, Any] + ) -> tuple[dict[str, str], dict[str, Any] | None]: + """Validate user input and return errors dict and device data.""" + errors = {} + device_data = None + + try: + device_data = await self._async_get_device_data(user_input[CONF_HOST]) + except TimeoutError: + errors["base"] = "timeout" + except ConnectionError, ClientError: + errors["base"] = "cannot_connect" + except Exception: + _LOGGER.exception("Unknown error occurred while verifying device") + errors["base"] = "unknown" + + return errors, device_data + + async def _async_get_device_data(self, host: str) -> dict[str, Any]: + """Get device data (type, serial number, generation) from API.""" + api = IndevoltAPI(host, DEFAULT_PORT, async_get_clientsession(self.hass)) + config_data = await api.get_config() + device_data = config_data["device"] + + return { + CONF_SERIAL_NUMBER: device_data["sn"], + CONF_GENERATION: device_data["generation"], + CONF_MODEL: device_data["type"], + } diff --git a/homeassistant/components/indevolt/const.py b/homeassistant/components/indevolt/const.py new file mode 100644 index 00000000000..31dac70f286 --- /dev/null +++ b/homeassistant/components/indevolt/const.py @@ -0,0 +1,103 @@ +"""Constants for the Indevolt integration.""" + +DOMAIN = "indevolt" + +# Config entry fields +CONF_SERIAL_NUMBER = "serial_number" +CONF_GENERATION = "generation" + +# Default values +DEFAULT_PORT = 8080 + +# API key fields +SENSOR_KEYS = { + 1: [ + "606", + "7101", + "2101", + "2108", + "2107", + "6000", + "6001", + "6002", + "1501", + "1502", + "1664", + "1665", + "1666", + "1667", + "6105", + "21028", + "1505", + ], + 2: [ + "606", + "7101", + "2101", + "2108", + "2107", + "6000", + "6001", + "6002", + "1501", + "1502", + "1664", + "1665", + "1666", + "1667", + "142", + "667", + "2104", + "2105", + "11034", + "6004", + "6005", + "6006", + "6007", + "11016", + "2600", + "2612", + "1632", + "1600", + "1633", + "1601", + "1634", + "1602", + "1635", + "1603", + "9008", + "9032", + "9051", + "9070", + "9165", + "9218", + "9000", + "9016", + "9035", + "9054", + "9149", + "9202", + "9012", + "9030", + "9049", + "9068", + "9163", + "9216", + "9004", + "9020", + "9039", + "9058", + "9153", + "9206", + "9013", + "19173", + "19174", + "19175", + "19176", + "19177", + "680", + "11011", + "11009", + "11010", + ], +} diff --git a/homeassistant/components/indevolt/coordinator.py b/homeassistant/components/indevolt/coordinator.py new file mode 100644 index 00000000000..7cf30bfc6f7 --- /dev/null +++ b/homeassistant/components/indevolt/coordinator.py @@ -0,0 +1,80 @@ +"""Home Assistant integration for Indevolt device.""" + +from __future__ import annotations + +from datetime import timedelta +import logging +from typing import Any + +from indevolt_api import IndevoltAPI, TimeOutException + +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import CONF_HOST, CONF_MODEL +from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ConfigEntryNotReady +from homeassistant.helpers.aiohttp_client import async_get_clientsession +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed + +from .const import ( + CONF_GENERATION, + CONF_SERIAL_NUMBER, + DEFAULT_PORT, + DOMAIN, + SENSOR_KEYS, +) + +_LOGGER = logging.getLogger(__name__) +SCAN_INTERVAL = 30 + +type IndevoltConfigEntry = ConfigEntry[IndevoltCoordinator] + + +class IndevoltCoordinator(DataUpdateCoordinator[dict[str, Any]]): + """Coordinator for fetching and pushing data to indevolt devices.""" + + config_entry: IndevoltConfigEntry + firmware_version: str | None + + def __init__(self, hass: HomeAssistant, entry: IndevoltConfigEntry) -> None: + """Initialize the indevolt coordinator.""" + super().__init__( + hass, + _LOGGER, + name=DOMAIN, + update_interval=timedelta(seconds=SCAN_INTERVAL), + config_entry=entry, + ) + + # Initialize Indevolt API + self.api = IndevoltAPI( + host=entry.data[CONF_HOST], + port=DEFAULT_PORT, + session=async_get_clientsession(hass), + ) + + self.serial_number = entry.data[CONF_SERIAL_NUMBER] + self.device_model = entry.data[CONF_MODEL] + self.generation = entry.data[CONF_GENERATION] + + async def _async_setup(self) -> None: + """Fetch device info once on boot.""" + try: + config_data = await self.api.get_config() + except TimeOutException as err: + raise ConfigEntryNotReady( + f"Device config retrieval timed out: {err}" + ) from err + + # Cache device information + device_data = config_data.get("device", {}) + + self.firmware_version = device_data.get("fw") + + async def _async_update_data(self) -> dict[str, Any]: + """Fetch raw JSON data from the device.""" + sensor_keys = SENSOR_KEYS[self.generation] + + try: + return await self.api.fetch_data(sensor_keys) + except TimeOutException as err: + raise UpdateFailed(f"Device update timed out: {err}") from err diff --git a/homeassistant/components/indevolt/entity.py b/homeassistant/components/indevolt/entity.py new file mode 100644 index 00000000000..da87036a33a --- /dev/null +++ b/homeassistant/components/indevolt/entity.py @@ -0,0 +1,31 @@ +"""Base entity for Indevolt integration.""" + +from homeassistant.helpers.device_registry import DeviceInfo +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from .const import DOMAIN +from .coordinator import IndevoltCoordinator + + +class IndevoltEntity(CoordinatorEntity[IndevoltCoordinator]): + """Base Indevolt entity with up-to-date device info.""" + + _attr_has_entity_name = True + + @property + def serial_number(self) -> str: + """Return the device serial number.""" + return self.coordinator.serial_number + + @property + def device_info(self) -> DeviceInfo: + """Return device information for registry.""" + coordinator = self.coordinator + return DeviceInfo( + identifiers={(DOMAIN, coordinator.serial_number)}, + manufacturer="INDEVOLT", + serial_number=coordinator.serial_number, + model=coordinator.device_model, + sw_version=coordinator.firmware_version, + hw_version=str(coordinator.generation), + ) diff --git a/homeassistant/components/indevolt/manifest.json b/homeassistant/components/indevolt/manifest.json new file mode 100644 index 00000000000..f85e9745b75 --- /dev/null +++ b/homeassistant/components/indevolt/manifest.json @@ -0,0 +1,11 @@ +{ + "domain": "indevolt", + "name": "Indevolt", + "codeowners": ["@xirtnl"], + "config_flow": true, + "documentation": "https://www.home-assistant.io/integrations/indevolt", + "integration_type": "device", + "iot_class": "local_polling", + "quality_scale": "bronze", + "requirements": ["indevolt-api==1.1.2"] +} diff --git a/homeassistant/components/indevolt/quality_scale.yaml b/homeassistant/components/indevolt/quality_scale.yaml new file mode 100644 index 00000000000..c436beb43fe --- /dev/null +++ b/homeassistant/components/indevolt/quality_scale.yaml @@ -0,0 +1,94 @@ +rules: + # Bronze (mandatory for core integrations) + action-setup: + status: exempt + comment: Integration does not register custom actions + appropriate-polling: done + brands: done + common-modules: done + config-flow-test-coverage: done + config-flow: done + dependency-transparency: done + docs-actions: + status: exempt + comment: Integration does not register custom actions + docs-high-level-description: done + docs-installation-instructions: done + docs-removal-instructions: done + entity-event-setup: + status: exempt + comment: Integration does not subscribe to entity events, uses coordinator pattern + entity-unique-id: done + has-entity-name: done + runtime-data: done + test-before-configure: done + test-before-setup: done + unique-config-entry: done + + # Silver + action-exceptions: + status: exempt + comment: Integration does not register custom actions + config-entry-unloading: done + docs-configuration-parameters: + status: exempt + comment: Integration has no user-configurable parameters beyond setup + docs-installation-parameters: done + entity-unavailable: done + integration-owner: done + log-when-unavailable: done + parallel-updates: done + reauthentication-flow: + status: exempt + comment: Integration uses local device with no authentication + test-coverage: done + + # Gold + devices: done + diagnostics: + status: todo + discovery-update-info: + status: exempt + comment: Integration does not support network discovery + discovery: + status: exempt + comment: Integration does not support network discovery + docs-data-update: + status: todo + docs-examples: + status: todo + docs-known-limitations: + status: todo + docs-supported-devices: + status: todo + docs-supported-functions: + status: todo + docs-troubleshooting: + status: todo + docs-use-cases: + status: todo + dynamic-devices: + status: exempt + comment: Integration represents a single device, not a hub with multiple devices + entity-category: done + entity-device-class: done + entity-disabled-by-default: done + entity-translations: done + exception-translations: + status: todo + icon-translations: + status: todo + reconfiguration-flow: + status: todo + repair-issues: + status: exempt + comment: No repair issues needed for current functionality + stale-devices: + status: exempt + comment: Integration represents a single device, not a hub with multiple devices + + # Platinum + async-dependency: done + inject-websession: done + strict-typing: + status: todo diff --git a/homeassistant/components/indevolt/sensor.py b/homeassistant/components/indevolt/sensor.py new file mode 100644 index 00000000000..3ccfeec8571 --- /dev/null +++ b/homeassistant/components/indevolt/sensor.py @@ -0,0 +1,704 @@ +"""Sensor platform for Indevolt integration.""" + +from dataclasses import dataclass, field +from typing import Final + +from homeassistant.components.sensor import ( + SensorDeviceClass, + SensorEntity, + SensorEntityDescription, + SensorStateClass, +) +from homeassistant.const import ( + PERCENTAGE, + EntityCategory, + UnitOfElectricCurrent, + UnitOfElectricPotential, + UnitOfEnergy, + UnitOfFrequency, + UnitOfPower, + UnitOfTemperature, +) +from homeassistant.core import HomeAssistant +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback + +from . import IndevoltConfigEntry +from .coordinator import IndevoltCoordinator +from .entity import IndevoltEntity + +PARALLEL_UPDATES = 0 + + +@dataclass(frozen=True, kw_only=True) +class IndevoltSensorEntityDescription(SensorEntityDescription): + """Custom entity description class for Indevolt sensors.""" + + state_mapping: dict[str | int, str] = field(default_factory=dict) + generation: list[int] = field(default_factory=lambda: [1, 2]) + + +SENSORS: Final = ( + # System Operating Information + IndevoltSensorEntityDescription( + key="606", + translation_key="mode", + state_mapping={"1000": "main", "1001": "sub", "1002": "standalone"}, + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="7101", + translation_key="energy_mode", + state_mapping={ + 0: "outdoor_portable", + 1: "self_consumed_prioritized", + 4: "real_time_control", + 5: "charge_discharge_schedule", + }, + device_class=SensorDeviceClass.ENUM, + ), + IndevoltSensorEntityDescription( + key="142", + generation=[2], + translation_key="rated_capacity", + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + IndevoltSensorEntityDescription( + key="6105", + generation=[1], + translation_key="rated_capacity", + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + IndevoltSensorEntityDescription( + key="2101", + translation_key="ac_input_power", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + IndevoltSensorEntityDescription( + key="2108", + translation_key="ac_output_power", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + IndevoltSensorEntityDescription( + key="667", + generation=[2], + translation_key="bypass_power", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + # Electrical Energy Information + IndevoltSensorEntityDescription( + key="2107", + translation_key="total_ac_input_energy", + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + IndevoltSensorEntityDescription( + key="2104", + generation=[2], + translation_key="total_ac_output_energy", + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + IndevoltSensorEntityDescription( + key="2105", + generation=[2], + translation_key="off_grid_output_energy", + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + IndevoltSensorEntityDescription( + key="11034", + generation=[2], + translation_key="bypass_input_energy", + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + IndevoltSensorEntityDescription( + key="6004", + generation=[2], + translation_key="battery_daily_charging_energy", + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + IndevoltSensorEntityDescription( + key="6005", + generation=[2], + translation_key="battery_daily_discharging_energy", + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + IndevoltSensorEntityDescription( + key="6006", + generation=[2], + translation_key="battery_total_charging_energy", + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + IndevoltSensorEntityDescription( + key="6007", + generation=[2], + translation_key="battery_total_discharging_energy", + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + # Electricity Meter Status + IndevoltSensorEntityDescription( + key="11016", + generation=[2], + translation_key="meter_power", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + IndevoltSensorEntityDescription( + key="21028", + generation=[1], + translation_key="meter_power", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + # Grid information + IndevoltSensorEntityDescription( + key="2600", + generation=[2], + translation_key="grid_voltage", + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="2612", + generation=[2], + translation_key="grid_frequency", + native_unit_of_measurement=UnitOfFrequency.HERTZ, + device_class=SensorDeviceClass.FREQUENCY, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + # Battery Pack Operating Parameters + IndevoltSensorEntityDescription( + key="6000", + translation_key="battery_power", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + IndevoltSensorEntityDescription( + key="6001", + translation_key="battery_charge_discharge_state", + state_mapping={1000: "static", 1001: "charging", 1002: "discharging"}, + device_class=SensorDeviceClass.ENUM, + ), + IndevoltSensorEntityDescription( + key="6002", + translation_key="battery_soc", + native_unit_of_measurement=PERCENTAGE, + device_class=SensorDeviceClass.BATTERY, + state_class=SensorStateClass.MEASUREMENT, + ), + # PV Operating Parameters + IndevoltSensorEntityDescription( + key="1501", + translation_key="dc_output_power", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + IndevoltSensorEntityDescription( + key="1502", + translation_key="daily_production", + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + IndevoltSensorEntityDescription( + key="1505", + generation=[1], + translation_key="cumulative_production", + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + suggested_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL_INCREASING, + ), + IndevoltSensorEntityDescription( + key="1632", + generation=[2], + translation_key="dc_input_current_1", + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="1600", + generation=[2], + translation_key="dc_input_voltage_1", + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="1664", + translation_key="dc_input_power_1", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="1633", + generation=[2], + translation_key="dc_input_current_2", + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="1601", + generation=[2], + translation_key="dc_input_voltage_2", + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="1665", + translation_key="dc_input_power_2", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="1634", + generation=[2], + translation_key="dc_input_current_3", + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="1602", + generation=[2], + translation_key="dc_input_voltage_3", + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="1666", + generation=[2], + translation_key="dc_input_power_3", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="1635", + generation=[2], + translation_key="dc_input_current_4", + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="1603", + generation=[2], + translation_key="dc_input_voltage_4", + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="1667", + generation=[2], + translation_key="dc_input_power_4", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + entity_registry_enabled_default=False, + ), + # Battery Pack Serial Numbers + IndevoltSensorEntityDescription( + key="9008", + generation=[2], + translation_key="main_serial_number", + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="9032", + generation=[2], + translation_key="battery_pack_1_serial_number", + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="9051", + generation=[2], + translation_key="battery_pack_2_serial_number", + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="9070", + generation=[2], + translation_key="battery_pack_3_serial_number", + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="9165", + generation=[2], + translation_key="battery_pack_4_serial_number", + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="9218", + generation=[2], + translation_key="battery_pack_5_serial_number", + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + # Battery Pack SOC + IndevoltSensorEntityDescription( + key="9000", + generation=[2], + translation_key="main_soc", + native_unit_of_measurement=PERCENTAGE, + device_class=SensorDeviceClass.BATTERY, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="9016", + generation=[2], + translation_key="battery_pack_1_soc", + native_unit_of_measurement=PERCENTAGE, + device_class=SensorDeviceClass.BATTERY, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="9035", + generation=[2], + translation_key="battery_pack_2_soc", + native_unit_of_measurement=PERCENTAGE, + device_class=SensorDeviceClass.BATTERY, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="9054", + generation=[2], + translation_key="battery_pack_3_soc", + native_unit_of_measurement=PERCENTAGE, + device_class=SensorDeviceClass.BATTERY, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="9149", + generation=[2], + translation_key="battery_pack_4_soc", + native_unit_of_measurement=PERCENTAGE, + device_class=SensorDeviceClass.BATTERY, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="9202", + generation=[2], + translation_key="battery_pack_5_soc", + native_unit_of_measurement=PERCENTAGE, + device_class=SensorDeviceClass.BATTERY, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + # Battery Pack Temperature + IndevoltSensorEntityDescription( + key="9012", + generation=[2], + translation_key="main_temperature", + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + device_class=SensorDeviceClass.TEMPERATURE, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="9030", + generation=[2], + translation_key="battery_pack_1_temperature", + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + device_class=SensorDeviceClass.TEMPERATURE, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="9049", + generation=[2], + translation_key="battery_pack_2_temperature", + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + device_class=SensorDeviceClass.TEMPERATURE, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="9068", + generation=[2], + translation_key="battery_pack_3_temperature", + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + device_class=SensorDeviceClass.TEMPERATURE, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="9163", + generation=[2], + translation_key="battery_pack_4_temperature", + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + device_class=SensorDeviceClass.TEMPERATURE, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="9216", + generation=[2], + translation_key="battery_pack_5_temperature", + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + device_class=SensorDeviceClass.TEMPERATURE, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + # Battery Pack Voltage + IndevoltSensorEntityDescription( + key="9004", + generation=[2], + translation_key="main_voltage", + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="9020", + generation=[2], + translation_key="battery_pack_1_voltage", + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="9039", + generation=[2], + translation_key="battery_pack_2_voltage", + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="9058", + generation=[2], + translation_key="battery_pack_3_voltage", + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="9153", + generation=[2], + translation_key="battery_pack_4_voltage", + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="9206", + generation=[2], + translation_key="battery_pack_5_voltage", + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + # Battery Pack Current + IndevoltSensorEntityDescription( + key="9013", + generation=[2], + translation_key="main_current", + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="19173", + generation=[2], + translation_key="battery_pack_1_current", + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="19174", + generation=[2], + translation_key="battery_pack_2_current", + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="19175", + generation=[2], + translation_key="battery_pack_3_current", + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="19176", + generation=[2], + translation_key="battery_pack_4_current", + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), + IndevoltSensorEntityDescription( + key="19177", + generation=[2], + translation_key="battery_pack_5_current", + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + ), +) + +# Sensors per battery pack (SN, SOC, Temperature, Voltage, Current) +BATTERY_PACK_SENSOR_KEYS = [ + ("9032", "9016", "9030", "9020", "19173"), # Battery Pack 1 + ("9051", "9035", "9049", "9039", "19174"), # Battery Pack 2 + ("9070", "9054", "9068", "9058", "19175"), # Battery Pack 3 + ("9165", "9149", "9163", "9153", "19176"), # Battery Pack 4 + ("9218", "9202", "9216", "9206", "19177"), # Battery Pack 5 +] + + +async def async_setup_entry( + hass: HomeAssistant, + entry: IndevoltConfigEntry, + async_add_entities: AddConfigEntryEntitiesCallback, +) -> None: + """Set up the sensor platform for Indevolt.""" + coordinator = entry.runtime_data + device_gen = coordinator.generation + + excluded_keys: set[str] = set() + for pack_keys in BATTERY_PACK_SENSOR_KEYS: + sn_key = pack_keys[0] + + if not coordinator.data.get(sn_key): + excluded_keys.update(pack_keys) + + # Sensor initialization + async_add_entities( + IndevoltSensorEntity(coordinator, description) + for description in SENSORS + if device_gen in description.generation and description.key not in excluded_keys + ) + + +class IndevoltSensorEntity(IndevoltEntity, SensorEntity): + """Represents a sensor entity for Indevolt devices.""" + + entity_description: IndevoltSensorEntityDescription + + def __init__( + self, + coordinator: IndevoltCoordinator, + description: IndevoltSensorEntityDescription, + ) -> None: + """Initialize the Indevolt sensor entity.""" + super().__init__(coordinator) + + self.entity_description = description + self._attr_unique_id = f"{self.serial_number}_{description.key}" + + # Sort options (prevent randomization) for ENUM values + if description.device_class == SensorDeviceClass.ENUM: + self._attr_options = sorted(set(description.state_mapping.values())) + + @property + def native_value(self) -> str | int | float | None: + """Return the current value of the sensor in its native unit.""" + raw_value = self.coordinator.data.get(self.entity_description.key) + if raw_value is None: + return None + + # Return descriptions for ENUM values + if self.entity_description.device_class == SensorDeviceClass.ENUM: + return self.entity_description.state_mapping.get(raw_value) + + return raw_value diff --git a/homeassistant/components/indevolt/strings.json b/homeassistant/components/indevolt/strings.json new file mode 100644 index 00000000000..848378a86c4 --- /dev/null +++ b/homeassistant/components/indevolt/strings.json @@ -0,0 +1,246 @@ +{ + "config": { + "abort": { + "already_configured": "[%key:common::config_flow::abort::already_configured_device%]", + "cannot_connect": "Failed to connect (aborted)" + }, + "error": { + "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", + "timeout": "[%key:common::config_flow::error::timeout_connect%]", + "unknown": "[%key:common::config_flow::error::unknown%]" + }, + "step": { + "user": { + "data": { + "host": "[%key:common::config_flow::data::host%]" + }, + "data_description": { + "host": "The host of the Indevolt device" + }, + "description": "Enter the connection details for your Indevolt device.", + "title": "Connect to Indevolt device" + } + } + }, + "entity": { + "sensor": { + "ac_input_power": { + "name": "AC input power" + }, + "ac_output_power": { + "name": "AC output power" + }, + "battery_charge_discharge_state": { + "name": "Battery charge/discharge state", + "state": { + "charging": "Charging", + "discharging": "Discharging", + "static": "Static" + } + }, + "battery_daily_charging_energy": { + "name": "Battery daily charging energy" + }, + "battery_daily_discharging_energy": { + "name": "Battery daily discharging energy" + }, + "battery_pack_1_current": { + "name": "Battery pack 1 current" + }, + "battery_pack_1_serial_number": { + "name": "Battery pack 1 SN" + }, + "battery_pack_1_soc": { + "name": "Battery pack 1 SOC" + }, + "battery_pack_1_temperature": { + "name": "Battery pack 1 temperature" + }, + "battery_pack_1_voltage": { + "name": "Battery pack 1 voltage" + }, + "battery_pack_2_current": { + "name": "Battery pack 2 current" + }, + "battery_pack_2_serial_number": { + "name": "Battery pack 2 SN" + }, + "battery_pack_2_soc": { + "name": "Battery pack 2 SOC" + }, + "battery_pack_2_temperature": { + "name": "Battery pack 2 temperature" + }, + "battery_pack_2_voltage": { + "name": "Battery pack 2 voltage" + }, + "battery_pack_3_current": { + "name": "Battery pack 3 current" + }, + "battery_pack_3_serial_number": { + "name": "Battery pack 3 SN" + }, + "battery_pack_3_soc": { + "name": "Battery pack 3 SOC" + }, + "battery_pack_3_temperature": { + "name": "Battery pack 3 temperature" + }, + "battery_pack_3_voltage": { + "name": "Battery pack 3 voltage" + }, + "battery_pack_4_current": { + "name": "Battery pack 4 current" + }, + "battery_pack_4_serial_number": { + "name": "Battery pack 4 SN" + }, + "battery_pack_4_soc": { + "name": "Battery pack 4 SOC" + }, + "battery_pack_4_temperature": { + "name": "Battery pack 4 temperature" + }, + "battery_pack_4_voltage": { + "name": "Battery pack 4 voltage" + }, + "battery_pack_5_current": { + "name": "Battery pack 5 current" + }, + "battery_pack_5_serial_number": { + "name": "Battery pack 5 SN" + }, + "battery_pack_5_soc": { + "name": "Battery pack 5 SOC" + }, + "battery_pack_5_temperature": { + "name": "Battery pack 5 temperature" + }, + "battery_pack_5_voltage": { + "name": "Battery pack 5 voltage" + }, + "battery_power": { + "name": "Battery power" + }, + "battery_soc": { + "name": "Battery SOC" + }, + "battery_total_charging_energy": { + "name": "Battery total charging energy" + }, + "battery_total_discharging_energy": { + "name": "Battery total discharging energy" + }, + "bypass_input_energy": { + "name": "Bypass input energy" + }, + "bypass_power": { + "name": "Bypass power" + }, + "cumulative_production": { + "name": "Cumulative production" + }, + "daily_production": { + "name": "Daily production" + }, + "dc_input_current_1": { + "name": "DC input current 1" + }, + "dc_input_current_2": { + "name": "DC input current 2" + }, + "dc_input_current_3": { + "name": "DC input current 3" + }, + "dc_input_current_4": { + "name": "DC input current 4" + }, + "dc_input_power_1": { + "name": "DC input power 1" + }, + "dc_input_power_2": { + "name": "DC input power 2" + }, + "dc_input_power_3": { + "name": "DC input power 3" + }, + "dc_input_power_4": { + "name": "DC input power 4" + }, + "dc_input_voltage_1": { + "name": "DC input voltage 1" + }, + "dc_input_voltage_2": { + "name": "DC input voltage 2" + }, + "dc_input_voltage_3": { + "name": "DC input voltage 3" + }, + "dc_input_voltage_4": { + "name": "DC input voltage 4" + }, + "dc_output_power": { + "name": "DC output power" + }, + "energy_mode": { + "name": "Energy mode", + "state": { + "charge_discharge_schedule": "Charge/discharge schedule", + "outdoor_portable": "Outdoor portable", + "real_time_control": "Real-time control", + "self_consumed_prioritized": "Self-consumed prioritized" + } + }, + "grid_frequency": { + "name": "Grid frequency" + }, + "grid_voltage": { + "name": "Grid voltage" + }, + "main_current": { + "name": "Main current" + }, + "main_serial_number": { + "name": "Main serial number" + }, + "main_soc": { + "name": "Main SOC" + }, + "main_temperature": { + "name": "Main temperature" + }, + "main_voltage": { + "name": "Main voltage" + }, + "meter_power": { + "name": "Meter power" + }, + "mode": { + "name": "Device mode", + "state": { + "main": "Cluster (main)", + "standalone": "Standalone", + "sub": "Cluster (sub)" + } + }, + "off_grid_output_energy": { + "name": "Off-grid output energy" + }, + "rated_capacity": { + "name": "Rated capacity" + }, + "serial_number": { + "name": "Serial number" + }, + "total_ac_input_energy": { + "name": "Total AC input energy" + }, + "total_ac_input_energy_gen1": { + "name": "Total AC input energy" + }, + "total_ac_output_energy": { + "name": "Total AC output energy" + } + } + } +} diff --git a/homeassistant/generated/config_flows.py b/homeassistant/generated/config_flows.py index 9bcc030329a..156029ea0f0 100644 --- a/homeassistant/generated/config_flows.py +++ b/homeassistant/generated/config_flows.py @@ -329,6 +329,7 @@ FLOWS = { "immich", "improv_ble", "incomfort", + "indevolt", "inels", "inkbird", "insteon", diff --git a/homeassistant/generated/integrations.json b/homeassistant/generated/integrations.json index e7935ab7427..38063333132 100644 --- a/homeassistant/generated/integrations.json +++ b/homeassistant/generated/integrations.json @@ -3116,6 +3116,12 @@ "config_flow": true, "iot_class": "local_polling" }, + "indevolt": { + "name": "Indevolt", + "integration_type": "device", + "config_flow": true, + "iot_class": "local_polling" + }, "indianamichiganpower": { "name": "Indiana Michigan Power", "integration_type": "virtual", diff --git a/requirements_all.txt b/requirements_all.txt index 33939a98d47..0a75b3319fd 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1306,6 +1306,9 @@ imgw_pib==2.0.1 # homeassistant.components.incomfort incomfort-client==0.6.12 +# homeassistant.components.indevolt +indevolt-api==1.1.2 + # homeassistant.components.influxdb influxdb-client==1.50.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 183cd008f2f..886cb1e7413 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1155,6 +1155,9 @@ imgw_pib==2.0.1 # homeassistant.components.incomfort incomfort-client==0.6.12 +# homeassistant.components.indevolt +indevolt-api==1.1.2 + # homeassistant.components.influxdb influxdb-client==1.50.0 diff --git a/tests/components/indevolt/__init__.py b/tests/components/indevolt/__init__.py new file mode 100644 index 00000000000..87ece922797 --- /dev/null +++ b/tests/components/indevolt/__init__.py @@ -0,0 +1,14 @@ +"""Tests for the Indevolt integration.""" + +from homeassistant.core import HomeAssistant + +from tests.common import MockConfigEntry + + +async def setup_integration( + hass: HomeAssistant, mock_config_entry: MockConfigEntry +) -> None: + """Set up the integration for testing.""" + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() diff --git a/tests/components/indevolt/conftest.py b/tests/components/indevolt/conftest.py new file mode 100644 index 00000000000..a79fdc2d3fb --- /dev/null +++ b/tests/components/indevolt/conftest.py @@ -0,0 +1,108 @@ +"""Setup the Indevolt test environment.""" + +from collections.abc import Generator +from typing import Any +from unittest.mock import AsyncMock, patch + +import pytest + +from homeassistant.components.indevolt.const import ( + CONF_GENERATION, + CONF_SERIAL_NUMBER, + DOMAIN, +) +from homeassistant.const import CONF_HOST, CONF_MODEL + +from tests.common import MockConfigEntry, load_json_object_fixture + +TEST_HOST = "192.168.1.100" +TEST_PORT = 8080 +TEST_DEVICE_SN_GEN1 = "BK1600-12345678" +TEST_DEVICE_SN_GEN2 = "SolidFlex2000-87654321" +TEST_FW_VERSION = "1.2.3" + +# Map device fixture names to generation and fixture files +DEVICE_MAPPING = { + 1: { + "device": "BK1600", + "generation": 1, + "sn": TEST_DEVICE_SN_GEN1, + }, + 2: { + "device": "CMS-SF2000", + "generation": 2, + "sn": TEST_DEVICE_SN_GEN2, + }, +} + + +@pytest.fixture +def generation(request: pytest.FixtureRequest) -> int: + """Return the device generation.""" + return getattr(request, "param", 2) + + +@pytest.fixture +def entry_data(generation: int) -> dict[str, Any]: + """Return the config entry data based on generation.""" + device_info = DEVICE_MAPPING[generation] + return { + CONF_HOST: TEST_HOST, + CONF_SERIAL_NUMBER: device_info["sn"], + CONF_MODEL: device_info["device"], + CONF_GENERATION: device_info["generation"], + } + + +@pytest.fixture +def mock_config_entry(generation: int, entry_data: dict[str, Any]) -> MockConfigEntry: + """Return the default mocked config entry.""" + device_info = DEVICE_MAPPING[generation] + return MockConfigEntry( + domain=DOMAIN, + title=device_info["device"], + version=1, + data=entry_data, + unique_id=device_info["sn"], + ) + + +@pytest.fixture +def mock_indevolt(generation: int) -> Generator[AsyncMock]: + """Mock an IndevoltAPI client.""" + device_info = DEVICE_MAPPING[generation] + fixture_data = load_json_object_fixture(f"gen_{generation}.json", DOMAIN) + + with ( + patch( + "homeassistant.components.indevolt.coordinator.IndevoltAPI", + autospec=True, + ) as mock_client, + patch( + "homeassistant.components.indevolt.config_flow.IndevoltAPI", + new=mock_client, + ), + ): + # Mock coordinator API (get_data) + client = mock_client.return_value + client.fetch_data.return_value = fixture_data + client.get_config.return_value = { + "device": { + "sn": device_info["sn"], + "type": device_info["device"], + "generation": device_info["generation"], + "fw": TEST_FW_VERSION, + } + } + + yield client + + +@pytest.fixture +def mock_setup_entry() -> Generator[AsyncMock]: + """Mock the async_setup_entry function.""" + with patch( + "homeassistant.components.indevolt.async_setup_entry", + return_value=True, + ) as mock_setup: + yield mock_setup diff --git a/tests/components/indevolt/fixtures/gen_1.json b/tests/components/indevolt/fixtures/gen_1.json new file mode 100644 index 00000000000..46269f8396f --- /dev/null +++ b/tests/components/indevolt/fixtures/gen_1.json @@ -0,0 +1,23 @@ +{ + "0": "BK1600-12345678", + "606": "1000", + "7101": 5, + "1664": 0, + "1665": 0, + "2108": 0, + "1502": 0, + "1505": 553673, + "2101": 0, + "2107": 58.1, + "1501": 0, + "6000": 0, + "6001": 1000, + "6002": 92, + "6105": 5, + "6004": 0, + "6005": 0, + "6006": 277.16, + "6007": 256.39, + "7120": 1001, + "21028": 0 +} diff --git a/tests/components/indevolt/fixtures/gen_2.json b/tests/components/indevolt/fixtures/gen_2.json new file mode 100644 index 00000000000..7643daedd24 --- /dev/null +++ b/tests/components/indevolt/fixtures/gen_2.json @@ -0,0 +1,74 @@ +{ + "0": "SolidFlex2000-87654321", + "606": "1001", + "7101": 1, + "142": 1.79, + "6105": 5, + "2618": 250.5, + "11009": 50.2, + "2101": 0, + "2108": 0, + "11010": 52.3, + "667": 0, + "2107": 289.97, + "2104": 1500, + "2105": 2000, + "11034": 100, + "1502": 0, + "6004": 0.07, + "6005": 0, + "6006": 380.58, + "6007": 338.07, + "7120": 1001, + "11016": 0, + "2600": 1200, + "2612": 50.0, + "6001": 1000, + "6000": 0, + "6002": 92, + "1501": 0, + "1532": 150, + "1600": 48.5, + "1632": 10.2, + "1664": 0, + "1633": 10.1, + "1601": 48.3, + "1665": 0, + "1634": 9.8, + "1602": 48.7, + "1666": 0, + "1635": 9.9, + "1603": 48.6, + "1667": 0, + "11011": 85, + "9008": "MASTER-12345678", + "9032": "PACK1-11111111", + "9051": "PACK2-22222222", + "9070": "PACK3-33333333", + "9165": "PACK4-44444444", + "9218": "PACK5-55555555", + "9000": 92, + "9016": 91, + "9035": 93, + "9054": 92, + "9149": 94, + "9202": 90, + "9012": 25.5, + "9030": 24.8, + "9049": 25.2, + "9068": 25.0, + "9163": 25.7, + "9216": 24.9, + "9004": 51.2, + "9020": 51.0, + "9039": 51.3, + "9058": 51.1, + "9153": 51.4, + "9206": 50.9, + "9013": 15.2, + "19173": 14.8, + "19174": 15.0, + "19175": 15.1, + "19176": 15.3, + "19177": 14.9 +} diff --git a/tests/components/indevolt/snapshots/test_sensor.ambr b/tests/components/indevolt/snapshots/test_sensor.ambr new file mode 100644 index 00000000000..48e3194e781 --- /dev/null +++ b/tests/components/indevolt/snapshots/test_sensor.ambr @@ -0,0 +1,4463 @@ +# serializer version: 1 +# name: test_sensor[1][sensor.bk1600_ac_input_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.bk1600_ac_input_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'AC input power', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'AC input power', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'ac_input_power', + 'unique_id': 'BK1600-12345678_2101', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[1][sensor.bk1600_ac_input_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'BK1600 AC input power', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.bk1600_ac_input_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor[1][sensor.bk1600_ac_output_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.bk1600_ac_output_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'AC output power', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'AC output power', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'ac_output_power', + 'unique_id': 'BK1600-12345678_2108', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[1][sensor.bk1600_ac_output_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'BK1600 AC output power', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.bk1600_ac_output_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor[1][sensor.bk1600_battery_charge_discharge_state-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'charging', + 'discharging', + 'static', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.bk1600_battery_charge_discharge_state', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery charge/discharge state', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery charge/discharge state', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_charge_discharge_state', + 'unique_id': 'BK1600-12345678_6001', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor[1][sensor.bk1600_battery_charge_discharge_state-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'BK1600 Battery charge/discharge state', + 'options': list([ + 'charging', + 'discharging', + 'static', + ]), + }), + 'context': , + 'entity_id': 'sensor.bk1600_battery_charge_discharge_state', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'static', + }) +# --- +# name: test_sensor[1][sensor.bk1600_battery_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.bk1600_battery_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery power', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery power', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_power', + 'unique_id': 'BK1600-12345678_6000', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[1][sensor.bk1600_battery_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'BK1600 Battery power', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.bk1600_battery_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor[1][sensor.bk1600_battery_soc-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.bk1600_battery_soc', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery SOC', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery SOC', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_soc', + 'unique_id': 'BK1600-12345678_6002', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensor[1][sensor.bk1600_battery_soc-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'BK1600 Battery SOC', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.bk1600_battery_soc', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '92', + }) +# --- +# name: test_sensor[1][sensor.bk1600_cumulative_production-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.bk1600_cumulative_production', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Cumulative production', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + 'sensor.private': dict({ + 'suggested_unit_of_measurement': , + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Cumulative production', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'cumulative_production', + 'unique_id': 'BK1600-12345678_1505', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[1][sensor.bk1600_cumulative_production-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'BK1600 Cumulative production', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.bk1600_cumulative_production', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '553.673', + }) +# --- +# name: test_sensor[1][sensor.bk1600_daily_production-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.bk1600_daily_production', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Daily production', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Daily production', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'daily_production', + 'unique_id': 'BK1600-12345678_1502', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[1][sensor.bk1600_daily_production-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'BK1600 Daily production', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.bk1600_daily_production', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor[1][sensor.bk1600_dc_input_power_1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.bk1600_dc_input_power_1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'DC input power 1', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'DC input power 1', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'dc_input_power_1', + 'unique_id': 'BK1600-12345678_1664', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[1][sensor.bk1600_dc_input_power_1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'BK1600 DC input power 1', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.bk1600_dc_input_power_1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor[1][sensor.bk1600_dc_input_power_2-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.bk1600_dc_input_power_2', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'DC input power 2', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'DC input power 2', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'dc_input_power_2', + 'unique_id': 'BK1600-12345678_1665', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[1][sensor.bk1600_dc_input_power_2-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'BK1600 DC input power 2', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.bk1600_dc_input_power_2', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor[1][sensor.bk1600_dc_output_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.bk1600_dc_output_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'DC output power', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'DC output power', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'dc_output_power', + 'unique_id': 'BK1600-12345678_1501', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[1][sensor.bk1600_dc_output_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'BK1600 DC output power', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.bk1600_dc_output_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor[1][sensor.bk1600_device_mode-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'main', + 'standalone', + 'sub', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.bk1600_device_mode', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Device mode', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Device mode', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'mode', + 'unique_id': 'BK1600-12345678_606', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor[1][sensor.bk1600_device_mode-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'BK1600 Device mode', + 'options': list([ + 'main', + 'standalone', + 'sub', + ]), + }), + 'context': , + 'entity_id': 'sensor.bk1600_device_mode', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'main', + }) +# --- +# name: test_sensor[1][sensor.bk1600_energy_mode-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'charge_discharge_schedule', + 'outdoor_portable', + 'real_time_control', + 'self_consumed_prioritized', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.bk1600_energy_mode', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Energy mode', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Energy mode', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'energy_mode', + 'unique_id': 'BK1600-12345678_7101', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor[1][sensor.bk1600_energy_mode-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'BK1600 Energy mode', + 'options': list([ + 'charge_discharge_schedule', + 'outdoor_portable', + 'real_time_control', + 'self_consumed_prioritized', + ]), + }), + 'context': , + 'entity_id': 'sensor.bk1600_energy_mode', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'charge_discharge_schedule', + }) +# --- +# name: test_sensor[1][sensor.bk1600_meter_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.bk1600_meter_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Meter power', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Meter power', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'meter_power', + 'unique_id': 'BK1600-12345678_21028', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[1][sensor.bk1600_meter_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'BK1600 Meter power', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.bk1600_meter_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor[1][sensor.bk1600_rated_capacity-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.bk1600_rated_capacity', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Rated capacity', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Rated capacity', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'rated_capacity', + 'unique_id': 'BK1600-12345678_6105', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[1][sensor.bk1600_rated_capacity-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'BK1600 Rated capacity', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.bk1600_rated_capacity', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '5', + }) +# --- +# name: test_sensor[1][sensor.bk1600_total_ac_input_energy-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.bk1600_total_ac_input_energy', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Total AC input energy', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Total AC input energy', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'total_ac_input_energy', + 'unique_id': 'BK1600-12345678_2107', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[1][sensor.bk1600_total_ac_input_energy-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'BK1600 Total AC input energy', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.bk1600_total_ac_input_energy', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '58.1', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_ac_input_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_ac_input_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'AC input power', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'AC input power', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'ac_input_power', + 'unique_id': 'SolidFlex2000-87654321_2101', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_ac_input_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'CMS-SF2000 AC input power', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_ac_input_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_ac_output_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_ac_output_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'AC output power', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'AC output power', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'ac_output_power', + 'unique_id': 'SolidFlex2000-87654321_2108', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_ac_output_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'CMS-SF2000 AC output power', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_ac_output_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_charge_discharge_state-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'charging', + 'discharging', + 'static', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_battery_charge_discharge_state', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery charge/discharge state', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery charge/discharge state', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_charge_discharge_state', + 'unique_id': 'SolidFlex2000-87654321_6001', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_charge_discharge_state-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'CMS-SF2000 Battery charge/discharge state', + 'options': list([ + 'charging', + 'discharging', + 'static', + ]), + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_charge_discharge_state', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'static', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_daily_charging_energy-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_battery_daily_charging_energy', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery daily charging energy', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery daily charging energy', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_daily_charging_energy', + 'unique_id': 'SolidFlex2000-87654321_6004', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_daily_charging_energy-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'CMS-SF2000 Battery daily charging energy', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_daily_charging_energy', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0.07', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_daily_discharging_energy-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_battery_daily_discharging_energy', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery daily discharging energy', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery daily discharging energy', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_daily_discharging_energy', + 'unique_id': 'SolidFlex2000-87654321_6005', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_daily_discharging_energy-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'CMS-SF2000 Battery daily discharging energy', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_daily_discharging_energy', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_1_current-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_1_current', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 1 current', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery pack 1 current', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_1_current', + 'unique_id': 'SolidFlex2000-87654321_19173', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_1_current-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'CMS-SF2000 Battery pack 1 current', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_1_current', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '14.8', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_1_sn-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_1_sn', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 1 SN', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Battery pack 1 SN', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_1_serial_number', + 'unique_id': 'SolidFlex2000-87654321_9032', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_1_sn-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'CMS-SF2000 Battery pack 1 SN', + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_1_sn', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'PACK1-11111111', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_1_soc-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_1_soc', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 1 SOC', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery pack 1 SOC', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_1_soc', + 'unique_id': 'SolidFlex2000-87654321_9016', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_1_soc-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'CMS-SF2000 Battery pack 1 SOC', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_1_soc', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '91', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_1_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_1_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 1 temperature', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery pack 1 temperature', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_1_temperature', + 'unique_id': 'SolidFlex2000-87654321_9030', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_1_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'CMS-SF2000 Battery pack 1 temperature', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_1_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '24.8', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_1_voltage-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_1_voltage', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 1 voltage', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery pack 1 voltage', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_1_voltage', + 'unique_id': 'SolidFlex2000-87654321_9020', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_1_voltage-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'voltage', + 'friendly_name': 'CMS-SF2000 Battery pack 1 voltage', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_1_voltage', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '51.0', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_2_current-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_2_current', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 2 current', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery pack 2 current', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_2_current', + 'unique_id': 'SolidFlex2000-87654321_19174', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_2_current-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'CMS-SF2000 Battery pack 2 current', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_2_current', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '15.0', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_2_sn-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_2_sn', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 2 SN', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Battery pack 2 SN', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_2_serial_number', + 'unique_id': 'SolidFlex2000-87654321_9051', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_2_sn-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'CMS-SF2000 Battery pack 2 SN', + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_2_sn', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'PACK2-22222222', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_2_soc-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_2_soc', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 2 SOC', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery pack 2 SOC', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_2_soc', + 'unique_id': 'SolidFlex2000-87654321_9035', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_2_soc-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'CMS-SF2000 Battery pack 2 SOC', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_2_soc', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '93', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_2_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_2_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 2 temperature', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery pack 2 temperature', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_2_temperature', + 'unique_id': 'SolidFlex2000-87654321_9049', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_2_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'CMS-SF2000 Battery pack 2 temperature', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_2_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '25.2', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_2_voltage-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_2_voltage', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 2 voltage', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery pack 2 voltage', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_2_voltage', + 'unique_id': 'SolidFlex2000-87654321_9039', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_2_voltage-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'voltage', + 'friendly_name': 'CMS-SF2000 Battery pack 2 voltage', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_2_voltage', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '51.3', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_3_current-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_3_current', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 3 current', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery pack 3 current', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_3_current', + 'unique_id': 'SolidFlex2000-87654321_19175', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_3_current-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'CMS-SF2000 Battery pack 3 current', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_3_current', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '15.1', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_3_sn-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_3_sn', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 3 SN', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Battery pack 3 SN', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_3_serial_number', + 'unique_id': 'SolidFlex2000-87654321_9070', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_3_sn-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'CMS-SF2000 Battery pack 3 SN', + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_3_sn', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'PACK3-33333333', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_3_soc-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_3_soc', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 3 SOC', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery pack 3 SOC', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_3_soc', + 'unique_id': 'SolidFlex2000-87654321_9054', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_3_soc-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'CMS-SF2000 Battery pack 3 SOC', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_3_soc', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '92', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_3_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_3_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 3 temperature', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery pack 3 temperature', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_3_temperature', + 'unique_id': 'SolidFlex2000-87654321_9068', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_3_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'CMS-SF2000 Battery pack 3 temperature', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_3_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '25.0', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_3_voltage-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_3_voltage', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 3 voltage', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery pack 3 voltage', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_3_voltage', + 'unique_id': 'SolidFlex2000-87654321_9058', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_3_voltage-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'voltage', + 'friendly_name': 'CMS-SF2000 Battery pack 3 voltage', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_3_voltage', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '51.1', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_4_current-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_4_current', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 4 current', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery pack 4 current', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_4_current', + 'unique_id': 'SolidFlex2000-87654321_19176', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_4_current-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'CMS-SF2000 Battery pack 4 current', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_4_current', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '15.3', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_4_sn-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_4_sn', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 4 SN', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Battery pack 4 SN', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_4_serial_number', + 'unique_id': 'SolidFlex2000-87654321_9165', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_4_sn-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'CMS-SF2000 Battery pack 4 SN', + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_4_sn', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'PACK4-44444444', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_4_soc-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_4_soc', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 4 SOC', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery pack 4 SOC', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_4_soc', + 'unique_id': 'SolidFlex2000-87654321_9149', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_4_soc-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'CMS-SF2000 Battery pack 4 SOC', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_4_soc', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '94', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_4_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_4_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 4 temperature', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery pack 4 temperature', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_4_temperature', + 'unique_id': 'SolidFlex2000-87654321_9163', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_4_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'CMS-SF2000 Battery pack 4 temperature', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_4_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '25.7', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_4_voltage-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_4_voltage', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 4 voltage', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery pack 4 voltage', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_4_voltage', + 'unique_id': 'SolidFlex2000-87654321_9153', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_4_voltage-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'voltage', + 'friendly_name': 'CMS-SF2000 Battery pack 4 voltage', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_4_voltage', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '51.4', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_5_current-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_5_current', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 5 current', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery pack 5 current', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_5_current', + 'unique_id': 'SolidFlex2000-87654321_19177', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_5_current-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'CMS-SF2000 Battery pack 5 current', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_5_current', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '14.9', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_5_sn-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_5_sn', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 5 SN', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Battery pack 5 SN', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_5_serial_number', + 'unique_id': 'SolidFlex2000-87654321_9218', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_5_sn-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'CMS-SF2000 Battery pack 5 SN', + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_5_sn', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'PACK5-55555555', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_5_soc-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_5_soc', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 5 SOC', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery pack 5 SOC', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_5_soc', + 'unique_id': 'SolidFlex2000-87654321_9202', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_5_soc-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'CMS-SF2000 Battery pack 5 SOC', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_5_soc', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '90', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_5_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_5_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 5 temperature', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery pack 5 temperature', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_5_temperature', + 'unique_id': 'SolidFlex2000-87654321_9216', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_5_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'CMS-SF2000 Battery pack 5 temperature', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_5_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '24.9', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_5_voltage-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_5_voltage', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery pack 5 voltage', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery pack 5 voltage', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_pack_5_voltage', + 'unique_id': 'SolidFlex2000-87654321_9206', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_pack_5_voltage-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'voltage', + 'friendly_name': 'CMS-SF2000 Battery pack 5 voltage', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_pack_5_voltage', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '50.9', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_battery_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery power', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery power', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_power', + 'unique_id': 'SolidFlex2000-87654321_6000', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'CMS-SF2000 Battery power', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_soc-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_battery_soc', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery SOC', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery SOC', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_soc', + 'unique_id': 'SolidFlex2000-87654321_6002', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_soc-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'CMS-SF2000 Battery SOC', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_soc', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '92', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_total_charging_energy-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_battery_total_charging_energy', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery total charging energy', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery total charging energy', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_total_charging_energy', + 'unique_id': 'SolidFlex2000-87654321_6006', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_total_charging_energy-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'CMS-SF2000 Battery total charging energy', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_total_charging_energy', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '380.58', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_total_discharging_energy-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_battery_total_discharging_energy', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Battery total discharging energy', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery total discharging energy', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'battery_total_discharging_energy', + 'unique_id': 'SolidFlex2000-87654321_6007', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_battery_total_discharging_energy-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'CMS-SF2000 Battery total discharging energy', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_battery_total_discharging_energy', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '338.07', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_bypass_input_energy-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_bypass_input_energy', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Bypass input energy', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Bypass input energy', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'bypass_input_energy', + 'unique_id': 'SolidFlex2000-87654321_11034', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_bypass_input_energy-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'CMS-SF2000 Bypass input energy', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_bypass_input_energy', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '100', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_bypass_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_bypass_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Bypass power', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Bypass power', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'bypass_power', + 'unique_id': 'SolidFlex2000-87654321_667', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_bypass_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'CMS-SF2000 Bypass power', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_bypass_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_daily_production-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_daily_production', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Daily production', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Daily production', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'daily_production', + 'unique_id': 'SolidFlex2000-87654321_1502', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_daily_production-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'CMS-SF2000 Daily production', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_daily_production', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_current_1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_dc_input_current_1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'DC input current 1', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'DC input current 1', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'dc_input_current_1', + 'unique_id': 'SolidFlex2000-87654321_1632', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_current_1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'CMS-SF2000 DC input current 1', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_dc_input_current_1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '10.2', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_current_2-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_dc_input_current_2', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'DC input current 2', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'DC input current 2', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'dc_input_current_2', + 'unique_id': 'SolidFlex2000-87654321_1633', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_current_2-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'CMS-SF2000 DC input current 2', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_dc_input_current_2', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '10.1', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_current_3-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_dc_input_current_3', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'DC input current 3', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'DC input current 3', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'dc_input_current_3', + 'unique_id': 'SolidFlex2000-87654321_1634', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_current_3-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'CMS-SF2000 DC input current 3', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_dc_input_current_3', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '9.8', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_current_4-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_dc_input_current_4', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'DC input current 4', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'DC input current 4', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'dc_input_current_4', + 'unique_id': 'SolidFlex2000-87654321_1635', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_current_4-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'CMS-SF2000 DC input current 4', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_dc_input_current_4', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '9.9', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_power_1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_dc_input_power_1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'DC input power 1', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'DC input power 1', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'dc_input_power_1', + 'unique_id': 'SolidFlex2000-87654321_1664', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_power_1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'CMS-SF2000 DC input power 1', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_dc_input_power_1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_power_2-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_dc_input_power_2', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'DC input power 2', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'DC input power 2', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'dc_input_power_2', + 'unique_id': 'SolidFlex2000-87654321_1665', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_power_2-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'CMS-SF2000 DC input power 2', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_dc_input_power_2', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_power_3-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_dc_input_power_3', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'DC input power 3', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'DC input power 3', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'dc_input_power_3', + 'unique_id': 'SolidFlex2000-87654321_1666', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_power_3-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'CMS-SF2000 DC input power 3', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_dc_input_power_3', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_power_4-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_dc_input_power_4', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'DC input power 4', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'DC input power 4', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'dc_input_power_4', + 'unique_id': 'SolidFlex2000-87654321_1667', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_power_4-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'CMS-SF2000 DC input power 4', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_dc_input_power_4', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_voltage_1-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_dc_input_voltage_1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'DC input voltage 1', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'DC input voltage 1', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'dc_input_voltage_1', + 'unique_id': 'SolidFlex2000-87654321_1600', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_voltage_1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'voltage', + 'friendly_name': 'CMS-SF2000 DC input voltage 1', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_dc_input_voltage_1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '48.5', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_voltage_2-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_dc_input_voltage_2', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'DC input voltage 2', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'DC input voltage 2', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'dc_input_voltage_2', + 'unique_id': 'SolidFlex2000-87654321_1601', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_voltage_2-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'voltage', + 'friendly_name': 'CMS-SF2000 DC input voltage 2', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_dc_input_voltage_2', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '48.3', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_voltage_3-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_dc_input_voltage_3', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'DC input voltage 3', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'DC input voltage 3', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'dc_input_voltage_3', + 'unique_id': 'SolidFlex2000-87654321_1602', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_voltage_3-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'voltage', + 'friendly_name': 'CMS-SF2000 DC input voltage 3', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_dc_input_voltage_3', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '48.7', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_voltage_4-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_dc_input_voltage_4', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'DC input voltage 4', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'DC input voltage 4', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'dc_input_voltage_4', + 'unique_id': 'SolidFlex2000-87654321_1603', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_input_voltage_4-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'voltage', + 'friendly_name': 'CMS-SF2000 DC input voltage 4', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_dc_input_voltage_4', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '48.6', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_output_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_dc_output_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'DC output power', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'DC output power', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'dc_output_power', + 'unique_id': 'SolidFlex2000-87654321_1501', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_dc_output_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'CMS-SF2000 DC output power', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_dc_output_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_device_mode-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'main', + 'standalone', + 'sub', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_device_mode', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Device mode', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Device mode', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'mode', + 'unique_id': 'SolidFlex2000-87654321_606', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_device_mode-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'CMS-SF2000 Device mode', + 'options': list([ + 'main', + 'standalone', + 'sub', + ]), + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_device_mode', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'sub', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_energy_mode-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'charge_discharge_schedule', + 'outdoor_portable', + 'real_time_control', + 'self_consumed_prioritized', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_energy_mode', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Energy mode', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Energy mode', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'energy_mode', + 'unique_id': 'SolidFlex2000-87654321_7101', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_energy_mode-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'CMS-SF2000 Energy mode', + 'options': list([ + 'charge_discharge_schedule', + 'outdoor_portable', + 'real_time_control', + 'self_consumed_prioritized', + ]), + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_energy_mode', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'self_consumed_prioritized', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_grid_frequency-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_grid_frequency', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Grid frequency', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Grid frequency', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'grid_frequency', + 'unique_id': 'SolidFlex2000-87654321_2612', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_grid_frequency-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'frequency', + 'friendly_name': 'CMS-SF2000 Grid frequency', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_grid_frequency', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '50.0', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_grid_voltage-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_grid_voltage', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Grid voltage', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Grid voltage', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'grid_voltage', + 'unique_id': 'SolidFlex2000-87654321_2600', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_grid_voltage-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'voltage', + 'friendly_name': 'CMS-SF2000 Grid voltage', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_grid_voltage', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '1200', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_main_current-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_main_current', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Main current', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Main current', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'main_current', + 'unique_id': 'SolidFlex2000-87654321_9013', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_main_current-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'CMS-SF2000 Main current', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_main_current', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '15.2', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_main_serial_number-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_main_serial_number', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Main serial number', + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Main serial number', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'main_serial_number', + 'unique_id': 'SolidFlex2000-87654321_9008', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_main_serial_number-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'CMS-SF2000 Main serial number', + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_main_serial_number', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'MASTER-12345678', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_main_soc-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_main_soc', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Main SOC', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Main SOC', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'main_soc', + 'unique_id': 'SolidFlex2000-87654321_9000', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_main_soc-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'CMS-SF2000 Main SOC', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_main_soc', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '92', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_main_temperature-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_main_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Main temperature', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Main temperature', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'main_temperature', + 'unique_id': 'SolidFlex2000-87654321_9012', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_main_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'CMS-SF2000 Main temperature', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_main_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '25.5', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_main_voltage-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.cms_sf2000_main_voltage', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Main voltage', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Main voltage', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'main_voltage', + 'unique_id': 'SolidFlex2000-87654321_9004', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_main_voltage-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'voltage', + 'friendly_name': 'CMS-SF2000 Main voltage', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_main_voltage', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '51.2', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_meter_power-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_meter_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Meter power', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Meter power', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'meter_power', + 'unique_id': 'SolidFlex2000-87654321_11016', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_meter_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'CMS-SF2000 Meter power', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_meter_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_off_grid_output_energy-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_off_grid_output_energy', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Off-grid output energy', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Off-grid output energy', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'off_grid_output_energy', + 'unique_id': 'SolidFlex2000-87654321_2105', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_off_grid_output_energy-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'CMS-SF2000 Off-grid output energy', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_off_grid_output_energy', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2000', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_rated_capacity-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_rated_capacity', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Rated capacity', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Rated capacity', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'rated_capacity', + 'unique_id': 'SolidFlex2000-87654321_142', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_rated_capacity-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'CMS-SF2000 Rated capacity', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_rated_capacity', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '1.79', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_total_ac_input_energy-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_total_ac_input_energy', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Total AC input energy', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Total AC input energy', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'total_ac_input_energy', + 'unique_id': 'SolidFlex2000-87654321_2107', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_total_ac_input_energy-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'CMS-SF2000 Total AC input energy', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_total_ac_input_energy', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '289.97', + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_total_ac_output_energy-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.cms_sf2000_total_ac_output_energy', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Total AC output energy', + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Total AC output energy', + 'platform': 'indevolt', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'total_ac_output_energy', + 'unique_id': 'SolidFlex2000-87654321_2104', + 'unit_of_measurement': , + }) +# --- +# name: test_sensor[2][sensor.cms_sf2000_total_ac_output_energy-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'CMS-SF2000 Total AC output energy', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.cms_sf2000_total_ac_output_energy', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '1500', + }) +# --- diff --git a/tests/components/indevolt/test_config_flow.py b/tests/components/indevolt/test_config_flow.py new file mode 100644 index 00000000000..3a69e2493c6 --- /dev/null +++ b/tests/components/indevolt/test_config_flow.py @@ -0,0 +1,106 @@ +"""Tests the Indevolt config flow.""" + +from unittest.mock import AsyncMock + +from aiohttp import ClientError +import pytest + +from homeassistant.components.indevolt.const import ( + CONF_GENERATION, + CONF_SERIAL_NUMBER, + DOMAIN, +) +from homeassistant.config_entries import SOURCE_USER +from homeassistant.const import CONF_HOST, CONF_MODEL +from homeassistant.core import HomeAssistant +from homeassistant.data_entry_flow import FlowResultType + +from .conftest import TEST_DEVICE_SN_GEN2, TEST_HOST + +from tests.common import MockConfigEntry + + +async def test_user_flow_success( + hass: HomeAssistant, mock_indevolt: AsyncMock, mock_setup_entry: AsyncMock +) -> None: + """Test successful user-initiated config flow.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "user" + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {"host": TEST_HOST} + ) + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["title"] == "INDEVOLT CMS-SF2000" + assert result["data"] == { + CONF_HOST: TEST_HOST, + CONF_SERIAL_NUMBER: TEST_DEVICE_SN_GEN2, + CONF_MODEL: "CMS-SF2000", + CONF_GENERATION: 2, + } + assert result["result"].unique_id == TEST_DEVICE_SN_GEN2 + + +@pytest.mark.parametrize( + ("exception", "expected_error"), + [ + (TimeoutError, "timeout"), + (ConnectionError, "cannot_connect"), + (ClientError, "cannot_connect"), + (Exception("Some unknown error"), "unknown"), + ], +) +async def test_user_flow_error( + hass: HomeAssistant, + mock_indevolt: AsyncMock, + mock_setup_entry: AsyncMock, + exception: Exception, + expected_error: str, +) -> None: + """Test connection errors in user flow.""" + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + + # Configure mock to raise exception + mock_indevolt.get_config.side_effect = exception + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {CONF_HOST: TEST_HOST} + ) + + assert result["type"] is FlowResultType.FORM + assert result["errors"]["base"] == expected_error + + # Test recovery by patching the library to work + mock_indevolt.get_config.side_effect = None + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {CONF_HOST: TEST_HOST} + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["title"] == "INDEVOLT CMS-SF2000" + + +async def test_user_flow_duplicate_entry( + hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_indevolt: AsyncMock +) -> None: + """Test duplicate entry aborts the flow.""" + mock_config_entry.add_to_hass(hass) + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={"source": SOURCE_USER} + ) + + # Test duplicate entry creation + result = await hass.config_entries.flow.async_configure( + result["flow_id"], {CONF_HOST: TEST_HOST} + ) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "already_configured" diff --git a/tests/components/indevolt/test_init.py b/tests/components/indevolt/test_init.py new file mode 100644 index 00000000000..05670fea426 --- /dev/null +++ b/tests/components/indevolt/test_init.py @@ -0,0 +1,47 @@ +"""Tests for the Indevolt integration initialization and services.""" + +from unittest.mock import AsyncMock + +from indevolt_api import TimeOutException +import pytest + +from homeassistant.config_entries import ConfigEntryState +from homeassistant.core import HomeAssistant + +from . import setup_integration + +from tests.common import MockConfigEntry + + +@pytest.mark.parametrize("generation", [2], indirect=True) +async def test_load_unload( + hass: HomeAssistant, mock_indevolt: AsyncMock, mock_config_entry: MockConfigEntry +) -> None: + """Test setting up and removing a config entry.""" + await setup_integration(hass, mock_config_entry) + + # Verify the config entry is successfully loaded + assert mock_config_entry.state is ConfigEntryState.LOADED + + # Unload the integration + await hass.config_entries.async_unload(mock_config_entry.entry_id) + await hass.async_block_till_done() + + # Verify the config entry is properly unloaded + assert mock_config_entry.state is ConfigEntryState.NOT_LOADED + + +@pytest.mark.parametrize("generation", [2], indirect=True) +async def test_load_failure( + hass: HomeAssistant, mock_indevolt: AsyncMock, mock_config_entry: MockConfigEntry +) -> None: + """Test setup failure when coordinator update fails.""" + # Simulate timeout error during coordinator initialization + mock_indevolt.get_config.side_effect = TimeOutException + + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + # Verify the config entry enters retry state due to failure + assert mock_config_entry.state is ConfigEntryState.SETUP_RETRY diff --git a/tests/components/indevolt/test_sensor.py b/tests/components/indevolt/test_sensor.py new file mode 100644 index 00000000000..21aef8cffcd --- /dev/null +++ b/tests/components/indevolt/test_sensor.py @@ -0,0 +1,164 @@ +"""Tests for the Indevolt sensor platform.""" + +from datetime import timedelta +from unittest.mock import AsyncMock, patch + +from freezegun.api import FrozenDateTimeFactory +import pytest +from syrupy.assertion import SnapshotAssertion + +from homeassistant.components.indevolt.coordinator import SCAN_INTERVAL +from homeassistant.const import STATE_UNAVAILABLE, Platform +from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers import entity_registry as er + +from . import setup_integration + +from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform + + +@pytest.mark.usefixtures("entity_registry_enabled_by_default") +@pytest.mark.parametrize("generation", [2, 1], indirect=True) +async def test_sensor( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + mock_indevolt: AsyncMock, + snapshot: SnapshotAssertion, + mock_config_entry: MockConfigEntry, +) -> None: + """Test sensor registration for sensors.""" + with patch("homeassistant.components.indevolt.PLATFORMS", [Platform.SENSOR]): + await setup_integration(hass, mock_config_entry) + + await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id) + + +@pytest.mark.parametrize("generation", [2], indirect=True) +async def test_sensor_availability( + hass: HomeAssistant, + mock_indevolt: AsyncMock, + mock_config_entry: MockConfigEntry, + freezer: FrozenDateTimeFactory, +) -> None: + """Test sensor availability / non-availability.""" + with patch("homeassistant.components.indevolt.PLATFORMS", [Platform.SENSOR]): + await setup_integration(hass, mock_config_entry) + + assert (state := hass.states.get("sensor.cms_sf2000_battery_soc")) + assert state.state == "92" + + mock_indevolt.fetch_data.side_effect = ConnectionError + freezer.tick(delta=timedelta(seconds=SCAN_INTERVAL)) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert (state := hass.states.get("sensor.cms_sf2000_battery_soc")) + assert state.state == STATE_UNAVAILABLE + + +# In individual tests, you can override the mock behavior +async def test_battery_pack_filtering( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_indevolt: AsyncMock, + entity_registry: er.EntityRegistry, +) -> None: + """Test that battery pack sensors are filtered based on SN availability.""" + + # Mock battery pack data - only first two packs have SNs + mock_indevolt.fetch_data.return_value = { + "9032": "BAT001", + "9051": "BAT002", + "9070": None, + "9165": "", + "9218": None, + } + + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + # Get all sensor entities + entity_entries = er.async_entries_for_config_entry( + entity_registry, mock_config_entry.entry_id + ) + + # Verify sensors for packs 1 and 2 exist (with SNs) + pack1_sensors = [ + e + for e in entity_entries + if any(key in e.unique_id for key in ("9032", "9016", "9030", "9020", "19173")) + ] + pack2_sensors = [ + e + for e in entity_entries + if any(key in e.unique_id for key in ("9051", "9035", "9049", "9039", "19174")) + ] + + assert len(pack1_sensors) == 5 + assert len(pack2_sensors) == 5 + + # Verify sensors for packs 3, 4, and 5 don't exist (no SNs) + pack3_sensors = [ + e + for e in entity_entries + if any(key in e.unique_id for key in ("9070", "9054", "9068", "9058", "19175")) + ] + pack4_sensors = [ + e + for e in entity_entries + if any(key in e.unique_id for key in ("9165", "9149", "9163", "9153", "19176")) + ] + pack5_sensors = [ + e + for e in entity_entries + if any(key in e.unique_id for key in ("9218", "9202", "9216", "9206", "19177")) + ] + + assert len(pack3_sensors) == 0 + assert len(pack4_sensors) == 0 + assert len(pack5_sensors) == 0 + + +async def test_battery_pack_filtering_fetch_error( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_indevolt: AsyncMock, + entity_registry: er.EntityRegistry, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test battery pack filtering when fetch fails.""" + + # Mock fetch_data to raise error on battery pack SN fetch + mock_indevolt.fetch_data.side_effect = HomeAssistantError("Timeout") + + mock_config_entry.add_to_hass(hass) + await hass.config_entries.async_setup(mock_config_entry.entry_id) + await hass.async_block_till_done() + + # Get all sensor entities + entity_entries = er.async_entries_for_config_entry( + entity_registry, mock_config_entry.entry_id + ) + + # Verify sensors (no sensors) + battery_pack_keys = [ + "9032", + "9051", + "9070", + "9165", + "9218", + "9016", + "9035", + "9054", + "9149", + "9202", + ] + battery_sensors = [ + e + for e in entity_entries + if any(key in e.unique_id for key in battery_pack_keys) + ] + + assert len(battery_sensors) == 0