From b51bb668c6e7ad046aa77d1ed9066d6b4f92c105 Mon Sep 17 00:00:00 2001 From: Imeon-Energy Date: Thu, 10 Apr 2025 08:25:35 +0200 Subject: [PATCH] Add imeon inverter integration (#130958) * Initial commit prototype with empty inverters * Use modern methods and global variable for character strings * Platform that get the value of the meter in an entity * Add check if inverter already configured * Add tests for config_flow * Update "imeon_inverter_api" in manifest.json * Update "imeon_inverter_api" in requirements_all.txt * Remove async_setup, clean comments, use of const PLATFORM * Use of global variable and remove configuration of device name * Use of entry.data instead of user_input variable * Remove services.yaml * No quality scale * Use of common string * Add sensors, use of EntityDescription and '_attr_device_info' * Remove name from config_flow tests * Use sentence case and change integration from hub to device * Check connection before add platform in config_flow * Use of _async_setup and minor changes * Improve sensor description * Add quality_scale.yaml * Update the quality_scale.json * Add tests for host invalid, route invalid, exception and invalid auth * Type more precisely 'DataUpdateCoordinator' * Don't use 'self.data' directly in coordinator and minor corrections * Complete full quality_scale.yaml * Use of fixtures in the tests * Add snapshot tests for sensors * Refactor the try except and use serial as unique id * Change API version * Add test for sensor * Mock the api to generate the snapshot * New type for async_add_entries * Except timeout error for get_serial * Add test for get_serial timeout error * Move store data out of the try * Use sentence case * Use of fixtures * Use separates fixtures * Mock the api * Put sensors fake data in json fixture file * Use of a const interval, remove except timeout, enhance lisibility * Try to use same fixture in test_config_flow * Try use same fixture for all mock of inverter * Modify the fixture in the context manager, correct the tests * Fixture return mock.__aenter__ directly * Adjust code clarity * Bring all tests to either ABORT or CREATE_ENTRY * Make the try except more concise * Synthetize exception tests into one * Add code clarity * Nitpick with the tests * Use unique id sensor * Log an error on unknown error * Remove useless comments, disable always_update and better use of timeout * Adjust units, set the model and software version * Set full name for Battery SOC and use ip instead of url * Use of host instead of IP * Fix the unit of economy factor * Reduce mornitoring data display precision and update snapshots * Remove unused variable HUBs * Fix device info * Set address label 'Host or IP' * Fix the config_flow tests * Re evaluate the quality_scale * Use of 'host' instead of 'address' * Make inverter discoverable by ssdp * Add test ssdp configuration already exist * Add exemption in quality scale * Test abort ssdp if serial is unknown * Handle update error * Raise other exceptions * Handle ClientError and ValueError from the api * Update homeassistant/components/imeon_inverter/quality_scale.yaml --------- Co-authored-by: Franck Nijhof Co-authored-by: Joost Lekkerkerker Co-authored-by: Josef Zweck --- CODEOWNERS | 2 + .../components/imeon_inverter/__init__.py | 31 + .../components/imeon_inverter/config_flow.py | 114 + .../components/imeon_inverter/const.py | 9 + .../components/imeon_inverter/coordinator.py | 97 + .../components/imeon_inverter/icons.json | 159 + .../components/imeon_inverter/manifest.json | 18 + .../imeon_inverter/quality_scale.yaml | 71 + .../components/imeon_inverter/sensor.py | 464 +++ .../components/imeon_inverter/strings.json | 187 ++ homeassistant/generated/config_flows.py | 1 + homeassistant/generated/integrations.json | 6 + homeassistant/generated/ssdp.py | 7 + requirements_all.txt | 3 + requirements_test_all.txt | 3 + tests/components/imeon_inverter/__init__.py | 14 + tests/components/imeon_inverter/conftest.py | 85 + .../imeon_inverter/fixtures/sensor_data.json | 73 + .../imeon_inverter/snapshots/test_sensor.ambr | 2689 +++++++++++++++++ .../imeon_inverter/test_config_flow.py | 205 ++ .../components/imeon_inverter/test_sensor.py | 29 + 21 files changed, 4267 insertions(+) create mode 100644 homeassistant/components/imeon_inverter/__init__.py create mode 100644 homeassistant/components/imeon_inverter/config_flow.py create mode 100644 homeassistant/components/imeon_inverter/const.py create mode 100644 homeassistant/components/imeon_inverter/coordinator.py create mode 100644 homeassistant/components/imeon_inverter/icons.json create mode 100644 homeassistant/components/imeon_inverter/manifest.json create mode 100644 homeassistant/components/imeon_inverter/quality_scale.yaml create mode 100644 homeassistant/components/imeon_inverter/sensor.py create mode 100644 homeassistant/components/imeon_inverter/strings.json create mode 100644 tests/components/imeon_inverter/__init__.py create mode 100644 tests/components/imeon_inverter/conftest.py create mode 100644 tests/components/imeon_inverter/fixtures/sensor_data.json create mode 100644 tests/components/imeon_inverter/snapshots/test_sensor.ambr create mode 100644 tests/components/imeon_inverter/test_config_flow.py create mode 100644 tests/components/imeon_inverter/test_sensor.py diff --git a/CODEOWNERS b/CODEOWNERS index 8afd3bab028..1a1377f4d3f 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -704,6 +704,8 @@ build.json @home-assistant/supervisor /tests/components/image_upload/ @home-assistant/core /homeassistant/components/imap/ @jbouwh /tests/components/imap/ @jbouwh +/homeassistant/components/imeon_inverter/ @Imeon-Energy +/tests/components/imeon_inverter/ @Imeon-Energy /homeassistant/components/imgw_pib/ @bieniu /tests/components/imgw_pib/ @bieniu /homeassistant/components/improv_ble/ @emontnemery diff --git a/homeassistant/components/imeon_inverter/__init__.py b/homeassistant/components/imeon_inverter/__init__.py new file mode 100644 index 00000000000..0676731f375 --- /dev/null +++ b/homeassistant/components/imeon_inverter/__init__.py @@ -0,0 +1,31 @@ +"""Initialize the Imeon component.""" + +from __future__ import annotations + +import logging + +from homeassistant.core import HomeAssistant + +from .const import PLATFORMS +from .coordinator import InverterConfigEntry, InverterCoordinator + +_LOGGER = logging.getLogger(__name__) + + +async def async_setup_entry(hass: HomeAssistant, entry: InverterConfigEntry) -> bool: + """Handle the creation of a new config entry for the integration (asynchronous).""" + + # Create the corresponding HUB + coordinator = InverterCoordinator(hass, entry) + await coordinator.async_config_entry_first_refresh() + entry.runtime_data = coordinator + + # Call for HUB creation then each entity as a List + await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) + + return True + + +async def async_unload_entry(hass: HomeAssistant, entry: InverterConfigEntry) -> bool: + """Handle entry unloading.""" + return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) diff --git a/homeassistant/components/imeon_inverter/config_flow.py b/homeassistant/components/imeon_inverter/config_flow.py new file mode 100644 index 00000000000..fadb2c65446 --- /dev/null +++ b/homeassistant/components/imeon_inverter/config_flow.py @@ -0,0 +1,114 @@ +"""Config flow for Imeon integration.""" + +import logging +from typing import Any +from urllib.parse import urlparse + +from imeon_inverter_api.inverter import Inverter +import voluptuous as vol + +from homeassistant.config_entries import ConfigFlow, ConfigFlowResult +from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME +from homeassistant.helpers.service_info.ssdp import ( + ATTR_UPNP_MODEL_NUMBER, + ATTR_UPNP_SERIAL, + SsdpServiceInfo, +) +from homeassistant.helpers.typing import VolDictType + +from .const import DOMAIN + +_LOGGER = logging.getLogger(__name__) + + +class ImeonInverterConfigFlow(ConfigFlow, domain=DOMAIN): + """Handle the initial setup flow for Imeon Inverters.""" + + _host: str | None = None + + async def async_step_user( + self, user_input: dict[str, Any] | None = None + ) -> ConfigFlowResult: + """Handle the user step for creating a new configuration entry.""" + + errors: dict[str, str] = {} + + if user_input is not None: + # User have to provide the hostname if device is not discovered + host = self._host or user_input[CONF_HOST] + + async with Inverter(host) as client: + try: + # Check connection + if await client.login( + user_input[CONF_USERNAME], user_input[CONF_PASSWORD] + ): + serial = await client.get_serial() + + else: + errors["base"] = "invalid_auth" + + except TimeoutError: + errors["base"] = "cannot_connect" + + except ValueError as e: + if "Host invalid" in str(e): + errors["base"] = "invalid_host" + + elif "Route invalid" in str(e): + errors["base"] = "invalid_route" + + else: + errors["base"] = "unknown" + _LOGGER.exception( + "Unexpected error occurred while connecting to the Imeon" + ) + + if not errors: + # Check if entry already exists + await self.async_set_unique_id(serial, raise_on_progress=False) + self._abort_if_unique_id_configured() + + # Create a new configuration entry if login succeeds + return self.async_create_entry( + title=f"Imeon {serial}", data={CONF_HOST: host, **user_input} + ) + + host_schema: VolDictType = ( + {vol.Required(CONF_HOST): str} if not self._host else {} + ) + + return self.async_show_form( + step_id="user", + data_schema=vol.Schema( + { + **host_schema, + vol.Required(CONF_USERNAME): str, + vol.Required(CONF_PASSWORD): str, + } + ), + errors=errors, + ) + + async def async_step_ssdp( + self, discovery_info: SsdpServiceInfo + ) -> ConfigFlowResult: + """Handle a SSDP discovery.""" + + host = str(urlparse(discovery_info.ssdp_location).hostname) + serial = discovery_info.upnp.get(ATTR_UPNP_SERIAL, "") + + if not serial: + return self.async_abort(reason="cannot_connect") + + await self.async_set_unique_id(serial) + self._abort_if_unique_id_configured(updates={CONF_HOST: host}) + + self._host = host + + self.context["title_placeholders"] = { + "model": discovery_info.upnp.get(ATTR_UPNP_MODEL_NUMBER, ""), + "serial": serial, + } + + return await self.async_step_user() diff --git a/homeassistant/components/imeon_inverter/const.py b/homeassistant/components/imeon_inverter/const.py new file mode 100644 index 00000000000..c71a8c72d11 --- /dev/null +++ b/homeassistant/components/imeon_inverter/const.py @@ -0,0 +1,9 @@ +"""Constant for Imeon component.""" + +from homeassistant.const import Platform + +DOMAIN = "imeon_inverter" +TIMEOUT = 20 +PLATFORMS = [ + Platform.SENSOR, +] diff --git a/homeassistant/components/imeon_inverter/coordinator.py b/homeassistant/components/imeon_inverter/coordinator.py new file mode 100644 index 00000000000..8342240b9ff --- /dev/null +++ b/homeassistant/components/imeon_inverter/coordinator.py @@ -0,0 +1,97 @@ +"""Coordinator for Imeon integration.""" + +from __future__ import annotations + +from asyncio import timeout +from datetime import timedelta +import logging + +from aiohttp import ClientError +from imeon_inverter_api.inverter import Inverter + +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME +from homeassistant.core import HomeAssistant +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed + +from .const import TIMEOUT + +HUBNAME = "imeon_inverter_hub" +INTERVAL = timedelta(seconds=60) +_LOGGER = logging.getLogger(__name__) + +type InverterConfigEntry = ConfigEntry[InverterCoordinator] + + +# HUB CREATION # +class InverterCoordinator(DataUpdateCoordinator[dict[str, str | float | int]]): + """Each inverter is it's own HUB, thus it's own data set. + + This allows this integration to handle as many + inverters as possible in parallel. + """ + + config_entry: InverterConfigEntry + + # Implement methods to fetch and update data + def __init__( + self, + hass: HomeAssistant, + entry: InverterConfigEntry, + ) -> None: + """Initialize data update coordinator.""" + super().__init__( + hass, + _LOGGER, + name=HUBNAME, + update_interval=INTERVAL, + config_entry=entry, + ) + + self._api = Inverter(entry.data[CONF_HOST]) + + @property + def api(self) -> Inverter: + """Return the inverter object.""" + return self._api + + async def _async_setup(self) -> None: + """Set up the coordinator.""" + async with timeout(TIMEOUT): + await self._api.login( + self.config_entry.data[CONF_USERNAME], + self.config_entry.data[CONF_PASSWORD], + ) + + await self._api.init() + + async def _async_update_data(self) -> dict[str, str | float | int]: + """Fetch and store newest data from API. + + This is the place to where entities can get their data. + It also includes the login process. + """ + + data: dict[str, str | float | int] = {} + + async with timeout(TIMEOUT): + await self._api.login( + self.config_entry.data[CONF_USERNAME], + self.config_entry.data[CONF_PASSWORD], + ) + + # Fetch data using distant API + try: + await self._api.update() + except (ValueError, ClientError) as e: + raise UpdateFailed(e) from e + + # Store data + for key, val in self._api.storage.items(): + if key == "timeline": + data[key] = val + else: + for sub_key, sub_val in val.items(): + data[f"{key}_{sub_key}"] = sub_val + + return data diff --git a/homeassistant/components/imeon_inverter/icons.json b/homeassistant/components/imeon_inverter/icons.json new file mode 100644 index 00000000000..1c74cf4c745 --- /dev/null +++ b/homeassistant/components/imeon_inverter/icons.json @@ -0,0 +1,159 @@ +{ + "entity": { + "sensor": { + "battery_autonomy": { + "default": "mdi:battery-clock" + }, + "battery_charge_time": { + "default": "mdi:battery-charging" + }, + "battery_power": { + "default": "mdi:battery" + }, + "battery_soc": { + "default": "mdi:battery-charging-100" + }, + "battery_stored": { + "default": "mdi:battery" + }, + "grid_current_l1": { + "default": "mdi:current-ac" + }, + "grid_current_l2": { + "default": "mdi:current-ac" + }, + "grid_current_l3": { + "default": "mdi:current-ac" + }, + "grid_frequency": { + "default": "mdi:sine-wave" + }, + "grid_voltage_l1": { + "default": "mdi:flash" + }, + "grid_voltage_l2": { + "default": "mdi:flash" + }, + "grid_voltage_l3": { + "default": "mdi:flash" + }, + "input_power_l1": { + "default": "mdi:power-socket" + }, + "input_power_l2": { + "default": "mdi:power-socket" + }, + "input_power_l3": { + "default": "mdi:power-socket" + }, + "input_power_total": { + "default": "mdi:power-plug" + }, + "inverter_charging_current_limit": { + "default": "mdi:current-dc" + }, + "inverter_injection_power_limit": { + "default": "mdi:power-socket" + }, + "meter_power": { + "default": "mdi:power-plug" + }, + "meter_power_protocol": { + "default": "mdi:protocol" + }, + "output_current_l1": { + "default": "mdi:current-ac" + }, + "output_current_l2": { + "default": "mdi:current-ac" + }, + "output_current_l3": { + "default": "mdi:current-ac" + }, + "output_frequency": { + "default": "mdi:sine-wave" + }, + "output_power_l1": { + "default": "mdi:power-socket" + }, + "output_power_l2": { + "default": "mdi:power-socket" + }, + "output_power_l3": { + "default": "mdi:power-socket" + }, + "output_power_total": { + "default": "mdi:power-plug" + }, + "output_voltage_l1": { + "default": "mdi:flash" + }, + "output_voltage_l2": { + "default": "mdi:flash" + }, + "output_voltage_l3": { + "default": "mdi:flash" + }, + "pv_consumed": { + "default": "mdi:solar-power" + }, + "pv_injected": { + "default": "mdi:solar-power" + }, + "pv_power_1": { + "default": "mdi:solar-power" + }, + "pv_power_2": { + "default": "mdi:solar-power" + }, + "pv_power_total": { + "default": "mdi:solar-power" + }, + "temp_air_temperature": { + "default": "mdi:thermometer" + }, + "temp_component_temperature": { + "default": "mdi:thermometer" + }, + "monitoring_building_consumption": { + "default": "mdi:home-lightning-bolt" + }, + "monitoring_economy_factor": { + "default": "mdi:chart-bar" + }, + "monitoring_grid_consumption": { + "default": "mdi:transmission-tower" + }, + "monitoring_grid_injection": { + "default": "mdi:transmission-tower-export" + }, + "monitoring_grid_power_flow": { + "default": "mdi:power-plug" + }, + "monitoring_self_consumption": { + "default": "mdi:percent" + }, + "monitoring_self_sufficiency": { + "default": "mdi:percent" + }, + "monitoring_solar_production": { + "default": "mdi:solar-power" + }, + "monitoring_minute_building_consumption": { + "default": "mdi:home-lightning-bolt" + }, + "monitoring_minute_grid_consumption": { + "default": "mdi:transmission-tower" + }, + "monitoring_minute_grid_injection": { + "default": "mdi:transmission-tower-export" + }, + "monitoring_minute_grid_power_flow": { + "default": "mdi:power-plug" + }, + "monitoring_minute_solar_production": { + "default": "mdi:solar-power" + } + } + } +} diff --git a/homeassistant/components/imeon_inverter/manifest.json b/homeassistant/components/imeon_inverter/manifest.json new file mode 100644 index 00000000000..1398521dc45 --- /dev/null +++ b/homeassistant/components/imeon_inverter/manifest.json @@ -0,0 +1,18 @@ +{ + "domain": "imeon_inverter", + "name": "Imeon Inverter", + "codeowners": ["@Imeon-Energy"], + "config_flow": true, + "documentation": "https://www.home-assistant.io/integrations/imeon_inverter", + "integration_type": "device", + "iot_class": "local_polling", + "quality_scale": "bronze", + "requirements": ["imeon_inverter_api==0.3.12"], + "ssdp": [ + { + "manufacturer": "IMEON", + "deviceType": "urn:schemas-upnp-org:device:Basic:1", + "st": "upnp:rootdevice" + } + ] +} diff --git a/homeassistant/components/imeon_inverter/quality_scale.yaml b/homeassistant/components/imeon_inverter/quality_scale.yaml new file mode 100644 index 00000000000..6e364977697 --- /dev/null +++ b/homeassistant/components/imeon_inverter/quality_scale.yaml @@ -0,0 +1,71 @@ +rules: + # Bronze + config-flow: done + test-before-configure: done + unique-config-entry: done + config-flow-test-coverage: done + runtime-data: done + test-before-setup: done + appropriate-polling: done + entity-unique-id: done + has-entity-name: done + entity-event-setup: + status: exempt + comment: This integration doesn't have sensors that subscribe to events. + dependency-transparency: done + action-setup: + status: exempt + comment: This integration does not have any service for now. + common-modules: done + docs-high-level-description: done + docs-installation-instructions: done + docs-removal-instructions: done + docs-actions: + status: exempt + comment: This integration does not have any service for now. + brands: done + # Silver + action-exceptions: + status: exempt + comment: This integration does not have any service for now. + config-entry-unloading: todo + docs-configuration-parameters: todo + docs-installation-parameters: todo + entity-unavailable: todo + integration-owner: done + log-when-unavailable: todo + parallel-updates: todo + reauthentication-flow: todo + test-coverage: done + # Gold + devices: done + diagnostics: todo + discovery-update-info: done + discovery: done + docs-data-update: todo + docs-examples: todo + docs-known-limitations: todo + docs-supported-devices: todo + docs-supported-functions: todo + docs-troubleshooting: todo + docs-use-cases: todo + dynamic-devices: + status: exempt + comment: Device type integration. + entity-category: done + entity-device-class: done + entity-disabled-by-default: todo + entity-translations: done + exception-translations: todo + icon-translations: done + reconfiguration-flow: todo + repair-issues: + status: exempt + comment: Currently no issues. + stale-devices: + status: exempt + comment: Device type integration. + # Platinum + async-dependency: todo + inject-websession: todo + strict-typing: todo diff --git a/homeassistant/components/imeon_inverter/sensor.py b/homeassistant/components/imeon_inverter/sensor.py new file mode 100644 index 00000000000..b7a01c3cf17 --- /dev/null +++ b/homeassistant/components/imeon_inverter/sensor.py @@ -0,0 +1,464 @@ +"""Imeon inverter sensor support.""" + +import logging + +from homeassistant.components.sensor import ( + SensorDeviceClass, + SensorEntity, + SensorEntityDescription, + SensorStateClass, +) +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import ( + PERCENTAGE, + EntityCategory, + UnitOfElectricCurrent, + UnitOfElectricPotential, + UnitOfEnergy, + UnitOfFrequency, + UnitOfPower, + UnitOfTemperature, + UnitOfTime, +) +from homeassistant.core import HomeAssistant +from homeassistant.helpers.device_registry import DeviceInfo +from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback +from homeassistant.helpers.typing import StateType +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from .const import DOMAIN +from .coordinator import InverterCoordinator + +type InverterConfigEntry = ConfigEntry[InverterCoordinator] + +_LOGGER = logging.getLogger(__name__) + + +ENTITY_DESCRIPTIONS = ( + # Battery + SensorEntityDescription( + key="battery_autonomy", + translation_key="battery_autonomy", + native_unit_of_measurement=UnitOfTime.HOURS, + device_class=SensorDeviceClass.DURATION, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="battery_charge_time", + translation_key="battery_charge_time", + native_unit_of_measurement=UnitOfTime.HOURS, + device_class=SensorDeviceClass.DURATION, + state_class=SensorStateClass.TOTAL, + ), + SensorEntityDescription( + key="battery_power", + translation_key="battery_power", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="battery_soc", + translation_key="battery_soc", + native_unit_of_measurement=PERCENTAGE, + device_class=SensorDeviceClass.BATTERY, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="battery_stored", + translation_key="battery_stored", + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + device_class=SensorDeviceClass.ENERGY_STORAGE, + state_class=SensorStateClass.TOTAL, + ), + # Grid + SensorEntityDescription( + key="grid_current_l1", + translation_key="grid_current_l1", + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="grid_current_l2", + translation_key="grid_current_l2", + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="grid_current_l3", + translation_key="grid_current_l3", + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="grid_frequency", + translation_key="grid_frequency", + native_unit_of_measurement=UnitOfFrequency.HERTZ, + device_class=SensorDeviceClass.FREQUENCY, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="grid_voltage_l1", + translation_key="grid_voltage_l1", + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="grid_voltage_l2", + translation_key="grid_voltage_l2", + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="grid_voltage_l3", + translation_key="grid_voltage_l3", + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + ), + # AC Input + SensorEntityDescription( + key="input_power_l1", + translation_key="input_power_l1", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="input_power_l2", + translation_key="input_power_l2", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="input_power_l3", + translation_key="input_power_l3", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="input_power_total", + translation_key="input_power_total", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + # Inverter settings + SensorEntityDescription( + key="inverter_charging_current_limit", + translation_key="inverter_charging_current_limit", + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="inverter_injection_power_limit", + translation_key="inverter_injection_power_limit", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + # Meter + SensorEntityDescription( + key="meter_power", + translation_key="meter_power", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="meter_power_protocol", + translation_key="meter_power_protocol", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + # AC Output + SensorEntityDescription( + key="output_current_l1", + translation_key="output_current_l1", + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="output_current_l2", + translation_key="output_current_l2", + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="output_current_l3", + translation_key="output_current_l3", + native_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + device_class=SensorDeviceClass.CURRENT, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="output_frequency", + translation_key="output_frequency", + native_unit_of_measurement=UnitOfFrequency.HERTZ, + device_class=SensorDeviceClass.FREQUENCY, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="output_power_l1", + translation_key="output_power_l1", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="output_power_l2", + translation_key="output_power_l2", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="output_power_l3", + translation_key="output_power_l3", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="output_power_total", + translation_key="output_power_total", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="output_voltage_l1", + translation_key="output_voltage_l1", + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="output_voltage_l2", + translation_key="output_voltage_l2", + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="output_voltage_l3", + translation_key="output_voltage_l3", + native_unit_of_measurement=UnitOfElectricPotential.VOLT, + device_class=SensorDeviceClass.VOLTAGE, + state_class=SensorStateClass.MEASUREMENT, + ), + # Solar Panel + SensorEntityDescription( + key="pv_consumed", + translation_key="pv_consumed", + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL, + ), + SensorEntityDescription( + key="pv_injected", + translation_key="pv_injected", + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL, + ), + SensorEntityDescription( + key="pv_power_1", + translation_key="pv_power_1", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="pv_power_2", + translation_key="pv_power_2", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="pv_power_total", + translation_key="pv_power_total", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + ), + # Temperature + SensorEntityDescription( + key="temp_air_temperature", + translation_key="temp_air_temperature", + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + device_class=SensorDeviceClass.TEMPERATURE, + state_class=SensorStateClass.MEASUREMENT, + ), + SensorEntityDescription( + key="temp_component_temperature", + translation_key="temp_component_temperature", + native_unit_of_measurement=UnitOfTemperature.CELSIUS, + device_class=SensorDeviceClass.TEMPERATURE, + state_class=SensorStateClass.MEASUREMENT, + ), + # Monitoring (data over the last 24 hours) + SensorEntityDescription( + key="monitoring_building_consumption", + translation_key="monitoring_building_consumption", + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL, + suggested_display_precision=2, + ), + SensorEntityDescription( + key="monitoring_economy_factor", + translation_key="monitoring_economy_factor", + native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR, + state_class=SensorStateClass.TOTAL, + suggested_display_precision=2, + ), + SensorEntityDescription( + key="monitoring_grid_consumption", + translation_key="monitoring_grid_consumption", + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL, + suggested_display_precision=2, + ), + SensorEntityDescription( + key="monitoring_grid_injection", + translation_key="monitoring_grid_injection", + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL, + suggested_display_precision=2, + ), + SensorEntityDescription( + key="monitoring_grid_power_flow", + translation_key="monitoring_grid_power_flow", + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL, + suggested_display_precision=2, + ), + SensorEntityDescription( + key="monitoring_self_consumption", + translation_key="monitoring_self_consumption", + native_unit_of_measurement=PERCENTAGE, + state_class=SensorStateClass.MEASUREMENT, + suggested_display_precision=2, + ), + SensorEntityDescription( + key="monitoring_self_sufficiency", + translation_key="monitoring_self_sufficiency", + native_unit_of_measurement=PERCENTAGE, + state_class=SensorStateClass.MEASUREMENT, + suggested_display_precision=2, + ), + SensorEntityDescription( + key="monitoring_solar_production", + translation_key="monitoring_solar_production", + native_unit_of_measurement=UnitOfEnergy.WATT_HOUR, + device_class=SensorDeviceClass.ENERGY, + state_class=SensorStateClass.TOTAL, + suggested_display_precision=2, + ), + # Monitoring (instant minute data) + SensorEntityDescription( + key="monitoring_minute_building_consumption", + translation_key="monitoring_minute_building_consumption", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + suggested_display_precision=2, + ), + SensorEntityDescription( + key="monitoring_minute_grid_consumption", + translation_key="monitoring_minute_grid_consumption", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + suggested_display_precision=2, + ), + SensorEntityDescription( + key="monitoring_minute_grid_injection", + translation_key="monitoring_minute_grid_injection", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + suggested_display_precision=2, + ), + SensorEntityDescription( + key="monitoring_minute_grid_power_flow", + translation_key="monitoring_minute_grid_power_flow", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + suggested_display_precision=2, + ), + SensorEntityDescription( + key="monitoring_minute_solar_production", + translation_key="monitoring_minute_solar_production", + native_unit_of_measurement=UnitOfPower.WATT, + device_class=SensorDeviceClass.POWER, + state_class=SensorStateClass.MEASUREMENT, + suggested_display_precision=2, + ), +) + + +async def async_setup_entry( + hass: HomeAssistant, + entry: InverterConfigEntry, + async_add_entities: AddConfigEntryEntitiesCallback, +) -> None: + """Create each sensor for a given config entry.""" + + coordinator = entry.runtime_data + + # Init sensor entities + async_add_entities( + InverterSensor(coordinator, entry, description) + for description in ENTITY_DESCRIPTIONS + ) + + +class InverterSensor(CoordinatorEntity[InverterCoordinator], SensorEntity): + """A sensor that returns numerical values with units.""" + + _attr_has_entity_name = True + _attr_entity_category = EntityCategory.DIAGNOSTIC + + def __init__( + self, + coordinator: InverterCoordinator, + entry: InverterConfigEntry, + description: SensorEntityDescription, + ) -> None: + """Pass coordinator to CoordinatorEntity.""" + super().__init__(coordinator) + self.entity_description = description + self._inverter = coordinator.api.inverter + self.data_key = description.key + assert entry.unique_id + self._attr_unique_id = f"{entry.unique_id}_{self.data_key}" + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, entry.unique_id)}, + name="Imeon inverter", + manufacturer="Imeon Energy", + model=self._inverter.get("inverter"), + sw_version=self._inverter.get("software"), + ) + + @property + def native_value(self) -> StateType | None: + """Value of the sensor.""" + return self.coordinator.data.get(self.data_key) diff --git a/homeassistant/components/imeon_inverter/strings.json b/homeassistant/components/imeon_inverter/strings.json new file mode 100644 index 00000000000..48604e01273 --- /dev/null +++ b/homeassistant/components/imeon_inverter/strings.json @@ -0,0 +1,187 @@ +{ + "config": { + "flow_title": "Imeon {model} ({serial})", + "step": { + "user": { + "title": "Add Imeon inverter", + "data": { + "host": "[%key:common::config_flow::data::host%]", + "username": "[%key:common::config_flow::data::username%]", + "password": "[%key:common::config_flow::data::password%]" + }, + "data_description": { + "host": "The hostname or IP of your inverter", + "username": "The username of your OS One account", + "password": "The password of your OS One account" + } + } + }, + "abort": { + "already_configured": "[%key:common::config_flow::abort::already_configured_device%]" + }, + "error": { + "cannot_connect": "[%key:common::config_flow::error::cannot_connect%]", + "invalid_auth": "[%key:common::config_flow::error::invalid_auth%]", + "invalid_host": "[%key:common::config_flow::error::invalid_host%]", + "invalid_route": "Unable to request the API, make sure 'API Module' is enabled on your device", + "unknown": "[%key:common::config_flow::error::unknown%]" + } + }, + "entity": { + "sensor": { + "battery_autonomy": { + "name": "Battery autonomy" + }, + "battery_charge_time": { + "name": "Battery charge time" + }, + "battery_power": { + "name": "Battery power" + }, + "battery_soc": { + "name": "Battery state of charge" + }, + "battery_stored": { + "name": "Battery stored" + }, + "grid_current_l1": { + "name": "Grid current L1" + }, + "grid_current_l2": { + "name": "Grid current L2" + }, + "grid_current_l3": { + "name": "Grid current L3" + }, + "grid_frequency": { + "name": "Grid frequency" + }, + "grid_voltage_l1": { + "name": "Grid voltage L1" + }, + "grid_voltage_l2": { + "name": "Grid voltage L2" + }, + "grid_voltage_l3": { + "name": "Grid voltage L3" + }, + "input_power_l1": { + "name": "Input power L1" + }, + "input_power_l2": { + "name": "Input power L2" + }, + "input_power_l3": { + "name": "Input power L3" + }, + "input_power_total": { + "name": "Input power total" + }, + "inverter_charging_current_limit": { + "name": "Charging current limit" + }, + "inverter_injection_power_limit": { + "name": "Injection power limit" + }, + "meter_power": { + "name": "Meter power" + }, + "meter_power_protocol": { + "name": "Meter power protocol" + }, + "output_current_l1": { + "name": "Output current L1" + }, + "output_current_l2": { + "name": "Output current L2" + }, + "output_current_l3": { + "name": "Output current L3" + }, + "output_frequency": { + "name": "Output frequency" + }, + "output_power_l1": { + "name": "Output power L1" + }, + "output_power_l2": { + "name": "Output power L2" + }, + "output_power_l3": { + "name": "Output power L3" + }, + "output_power_total": { + "name": "Output power total" + }, + "output_voltage_l1": { + "name": "Output voltage L1" + }, + "output_voltage_l2": { + "name": "Output voltage L2" + }, + "output_voltage_l3": { + "name": "Output voltage L3" + }, + "pv_consumed": { + "name": "PV consumed" + }, + "pv_injected": { + "name": "PV injected" + }, + "pv_power_1": { + "name": "PV power 1" + }, + "pv_power_2": { + "name": "PV power 2" + }, + "pv_power_total": { + "name": "PV power total" + }, + "temp_air_temperature": { + "name": "Air temperature" + }, + "temp_component_temperature": { + "name": "Component temperature" + }, + "monitoring_building_consumption": { + "name": "Monitoring building consumption" + }, + "monitoring_economy_factor": { + "name": "Monitoring economy factor" + }, + "monitoring_grid_consumption": { + "name": "Monitoring grid consumption" + }, + "monitoring_grid_injection": { + "name": "Monitoring grid injection" + }, + "monitoring_grid_power_flow": { + "name": "Monitoring grid power flow" + }, + "monitoring_self_consumption": { + "name": "Monitoring self consumption" + }, + "monitoring_self_sufficiency": { + "name": "Monitoring self sufficiency" + }, + "monitoring_solar_production": { + "name": "Monitoring solar production" + }, + "monitoring_minute_building_consumption": { + "name": "Monitoring building consumption (minute)" + }, + "monitoring_minute_grid_consumption": { + "name": "Monitoring grid consumption (minute)" + }, + "monitoring_minute_grid_injection": { + "name": "Monitoring grid injection (minute)" + }, + "monitoring_minute_grid_power_flow": { + "name": "Monitoring grid power flow (minute)" + }, + "monitoring_minute_solar_production": { + "name": "Monitoring solar production (minute)" + } + } + } +} diff --git a/homeassistant/generated/config_flows.py b/homeassistant/generated/config_flows.py index d192b8fcd13..268d8c35f40 100644 --- a/homeassistant/generated/config_flows.py +++ b/homeassistant/generated/config_flows.py @@ -285,6 +285,7 @@ FLOWS = { "ifttt", "igloohome", "imap", + "imeon_inverter", "imgw_pib", "improv_ble", "incomfort", diff --git a/homeassistant/generated/integrations.json b/homeassistant/generated/integrations.json index d0f0efe8ded..276102d2032 100644 --- a/homeassistant/generated/integrations.json +++ b/homeassistant/generated/integrations.json @@ -2935,6 +2935,12 @@ "config_flow": true, "iot_class": "cloud_push" }, + "imeon_inverter": { + "name": "Imeon Inverter", + "integration_type": "device", + "config_flow": true, + "iot_class": "local_polling" + }, "imgw_pib": { "name": "IMGW-PIB", "integration_type": "hub", diff --git a/homeassistant/generated/ssdp.py b/homeassistant/generated/ssdp.py index 5bbc178ba17..acbb74645a3 100644 --- a/homeassistant/generated/ssdp.py +++ b/homeassistant/generated/ssdp.py @@ -166,6 +166,13 @@ SSDP = { "st": "urn:hyperion-project.org:device:basic:1", }, ], + "imeon_inverter": [ + { + "deviceType": "urn:schemas-upnp-org:device:Basic:1", + "manufacturer": "IMEON", + "st": "upnp:rootdevice", + }, + ], "isy994": [ { "deviceType": "urn:udi-com:device:X_Insteon_Lighting_Device:1", diff --git a/requirements_all.txt b/requirements_all.txt index 8c5f876f1b4..9879eef9fe0 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1219,6 +1219,9 @@ igloohome-api==0.1.0 # homeassistant.components.ihc ihcsdk==2.8.5 +# homeassistant.components.imeon_inverter +imeon_inverter_api==0.3.12 + # homeassistant.components.imgw_pib imgw_pib==1.0.10 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 13b454e58df..992543f4447 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1034,6 +1034,9 @@ ifaddr==0.2.0 # homeassistant.components.igloohome igloohome-api==0.1.0 +# homeassistant.components.imeon_inverter +imeon_inverter_api==0.3.12 + # homeassistant.components.imgw_pib imgw_pib==1.0.10 diff --git a/tests/components/imeon_inverter/__init__.py b/tests/components/imeon_inverter/__init__.py new file mode 100644 index 00000000000..8305be2d901 --- /dev/null +++ b/tests/components/imeon_inverter/__init__.py @@ -0,0 +1,14 @@ +"""Tests for the Imeon Inverter 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 Imeon Inverter 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/imeon_inverter/conftest.py b/tests/components/imeon_inverter/conftest.py new file mode 100644 index 00000000000..38fb0d90322 --- /dev/null +++ b/tests/components/imeon_inverter/conftest.py @@ -0,0 +1,85 @@ +"""Configuration for the Imeon Inverter integration tests.""" + +from collections.abc import Generator +from unittest.mock import AsyncMock, MagicMock + +import pytest + +from homeassistant.components.imeon_inverter.const import DOMAIN +from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_USERNAME +from homeassistant.helpers.service_info.ssdp import ( + ATTR_UPNP_DEVICE_TYPE, + ATTR_UPNP_FRIENDLY_NAME, + ATTR_UPNP_MANUFACTURER, + ATTR_UPNP_MODEL_NAME, + ATTR_UPNP_SERIAL, + ATTR_UPNP_UDN, + SsdpServiceInfo, +) + +from tests.common import MockConfigEntry, load_json_object_fixture, patch + +# Sample test data +TEST_USER_INPUT = { + CONF_HOST: "192.168.200.1", + CONF_USERNAME: "user@local", + CONF_PASSWORD: "password", +} + +TEST_SERIAL = "111111111111111" + +TEST_DISCOVER = SsdpServiceInfo( + ssdp_usn="mock_usn", + ssdp_st="mock_st", + ssdp_location=f"http://{TEST_USER_INPUT[CONF_HOST]}:8088/imeon.xml", + upnp={ + ATTR_UPNP_MANUFACTURER: "IMEON", + ATTR_UPNP_MODEL_NAME: "IMEON", + ATTR_UPNP_FRIENDLY_NAME: f"IMEON-{TEST_SERIAL}", + ATTR_UPNP_SERIAL: TEST_SERIAL, + ATTR_UPNP_UDN: "uuid:01234567-89ab-cdef-0123-456789abcdef", + ATTR_UPNP_DEVICE_TYPE: "urn:schemas-upnp-org:device:Basic:1", + }, +) + + +@pytest.fixture(autouse=True) +def mock_imeon_inverter() -> Generator[MagicMock]: + """Mock data from the device.""" + with ( + patch( + "homeassistant.components.imeon_inverter.coordinator.Inverter", + autospec=True, + ) as inverter_mock, + patch( + "homeassistant.components.imeon_inverter.config_flow.Inverter", + new=inverter_mock, + ), + ): + inverter = inverter_mock.return_value + inverter.__aenter__.return_value = inverter + inverter.login.return_value = True + inverter.get_serial.return_value = TEST_SERIAL + inverter.storage = load_json_object_fixture("sensor_data.json", DOMAIN) + yield inverter + + +@pytest.fixture +def mock_async_setup_entry() -> Generator[AsyncMock]: + """Fixture for mocking async_setup_entry.""" + with patch( + "homeassistant.components.imeon_inverter.async_setup_entry", + return_value=True, + ) as mock: + yield mock + + +@pytest.fixture +def mock_config_entry() -> MockConfigEntry: + """Mock a config entry.""" + return MockConfigEntry( + title="Imeon inverter", + domain=DOMAIN, + data=TEST_USER_INPUT, + unique_id=TEST_SERIAL, + ) diff --git a/tests/components/imeon_inverter/fixtures/sensor_data.json b/tests/components/imeon_inverter/fixtures/sensor_data.json new file mode 100644 index 00000000000..566716fe3fa --- /dev/null +++ b/tests/components/imeon_inverter/fixtures/sensor_data.json @@ -0,0 +1,73 @@ +{ + "battery": { + "autonomy": 4.5, + "charge_time": 120, + "power": 2500.0, + "soc": 78.0, + "stored": 10.2 + }, + "grid": { + "current_l1": 12.5, + "current_l2": 10.8, + "current_l3": 11.2, + "frequency": 50.0, + "voltage_l1": 230.0, + "voltage_l2": 229.5, + "voltage_l3": 230.1 + }, + "input": { + "power_l1": 1000.0, + "power_l2": 950.0, + "power_l3": 980.0, + "power_total": 2930.0 + }, + "inverter": { + "charging_current_limit": 50, + "injection_power_limit": 5000.0 + }, + "meter": { + "power": 2000.0, + "power_protocol": 2018.0 + }, + "output": { + "current_l1": 15.0, + "current_l2": 14.5, + "current_l3": 15.2, + "frequency": 49.9, + "power_l1": 1100.0, + "power_l2": 1080.0, + "power_l3": 1120.0, + "power_total": 3300.0, + "voltage_l1": 231.0, + "voltage_l2": 229.8, + "voltage_l3": 230.2 + }, + "pv": { + "consumed": 1500.0, + "injected": 800.0, + "power_1": 1200.0, + "power_2": 1300.0, + "power_total": 2500.0 + }, + "temp": { + "air_temperature": 25.0, + "component_temperature": 45.5 + }, + "monitoring": { + "building_consumption": 3000.0, + "economy_factor": 0.8, + "grid_consumption": 500.0, + "grid_injection": 700.0, + "grid_power_flow": -200.0, + "self_consumption": 85.0, + "self_sufficiency": 90.0, + "solar_production": 2600.0 + }, + "monitoring_minute": { + "building_consumption": 50.0, + "grid_consumption": 8.3, + "grid_injection": 11.7, + "grid_power_flow": -3.4, + "solar_production": 43.3 + } +} diff --git a/tests/components/imeon_inverter/snapshots/test_sensor.ambr b/tests/components/imeon_inverter/snapshots/test_sensor.ambr new file mode 100644 index 00000000000..2d1fe14668f --- /dev/null +++ b/tests/components/imeon_inverter/snapshots/test_sensor.ambr @@ -0,0 +1,2689 @@ +# serializer version: 1 +# name: test_sensors[sensor.imeon_inverter_air_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.imeon_inverter_air_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Air temperature', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'temp_air_temperature', + 'unique_id': '111111111111111_temp_air_temperature', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_air_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'Imeon inverter Air temperature', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_air_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '25.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_battery_autonomy-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.imeon_inverter_battery_autonomy', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery autonomy', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'battery_autonomy', + 'unique_id': '111111111111111_battery_autonomy', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_battery_autonomy-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'duration', + 'friendly_name': 'Imeon inverter Battery autonomy', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_battery_autonomy', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '4.5', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_battery_charge_time-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.imeon_inverter_battery_charge_time', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery charge time', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'battery_charge_time', + 'unique_id': '111111111111111_battery_charge_time', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_battery_charge_time-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'duration', + 'friendly_name': 'Imeon inverter Battery charge time', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_battery_charge_time', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '120', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_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': , + 'entity_id': 'sensor.imeon_inverter_battery_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery power', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'battery_power', + 'unique_id': '111111111111111_battery_power', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_battery_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Imeon inverter Battery power', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_battery_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2500.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_battery_state_of_charge-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.imeon_inverter_battery_state_of_charge', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery state of charge', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'battery_soc', + 'unique_id': '111111111111111_battery_soc', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_battery_state_of_charge-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery', + 'friendly_name': 'Imeon inverter Battery state of charge', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_battery_state_of_charge', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '78.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_battery_stored-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.imeon_inverter_battery_stored', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Battery stored', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'battery_stored', + 'unique_id': '111111111111111_battery_stored', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_battery_stored-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy_storage', + 'friendly_name': 'Imeon inverter Battery stored', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_battery_stored', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '10.2', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_charging_current_limit-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.imeon_inverter_charging_current_limit', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Charging current limit', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'inverter_charging_current_limit', + 'unique_id': '111111111111111_inverter_charging_current_limit', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_charging_current_limit-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'Imeon inverter Charging current limit', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_charging_current_limit', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '50', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_component_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.imeon_inverter_component_temperature', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Component temperature', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'temp_component_temperature', + 'unique_id': '111111111111111_temp_component_temperature', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_component_temperature-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', + 'friendly_name': 'Imeon inverter Component temperature', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_component_temperature', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '45.5', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_grid_current_l1-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.imeon_inverter_grid_current_l1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Grid current L1', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'grid_current_l1', + 'unique_id': '111111111111111_grid_current_l1', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_grid_current_l1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'Imeon inverter Grid current L1', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_grid_current_l1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '12.5', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_grid_current_l2-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.imeon_inverter_grid_current_l2', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Grid current L2', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'grid_current_l2', + 'unique_id': '111111111111111_grid_current_l2', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_grid_current_l2-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'Imeon inverter Grid current L2', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_grid_current_l2', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '10.8', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_grid_current_l3-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.imeon_inverter_grid_current_l3', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Grid current L3', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'grid_current_l3', + 'unique_id': '111111111111111_grid_current_l3', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_grid_current_l3-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'Imeon inverter Grid current L3', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_grid_current_l3', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '11.2', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_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': , + 'entity_id': 'sensor.imeon_inverter_grid_frequency', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Grid frequency', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'grid_frequency', + 'unique_id': '111111111111111_grid_frequency', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_grid_frequency-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'frequency', + 'friendly_name': 'Imeon inverter Grid frequency', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_grid_frequency', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '50.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_grid_voltage_l1-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.imeon_inverter_grid_voltage_l1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Grid voltage L1', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'grid_voltage_l1', + 'unique_id': '111111111111111_grid_voltage_l1', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_grid_voltage_l1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'voltage', + 'friendly_name': 'Imeon inverter Grid voltage L1', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_grid_voltage_l1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '230.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_grid_voltage_l2-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.imeon_inverter_grid_voltage_l2', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Grid voltage L2', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'grid_voltage_l2', + 'unique_id': '111111111111111_grid_voltage_l2', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_grid_voltage_l2-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'voltage', + 'friendly_name': 'Imeon inverter Grid voltage L2', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_grid_voltage_l2', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '229.5', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_grid_voltage_l3-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.imeon_inverter_grid_voltage_l3', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Grid voltage L3', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'grid_voltage_l3', + 'unique_id': '111111111111111_grid_voltage_l3', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_grid_voltage_l3-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'voltage', + 'friendly_name': 'Imeon inverter Grid voltage L3', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_grid_voltage_l3', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '230.1', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_injection_power_limit-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.imeon_inverter_injection_power_limit', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Injection power limit', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'inverter_injection_power_limit', + 'unique_id': '111111111111111_inverter_injection_power_limit', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_injection_power_limit-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Imeon inverter Injection power limit', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_injection_power_limit', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '5000.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_input_power_l1-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.imeon_inverter_input_power_l1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Input power L1', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'input_power_l1', + 'unique_id': '111111111111111_input_power_l1', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_input_power_l1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Imeon inverter Input power L1', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_input_power_l1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '1000.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_input_power_l2-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.imeon_inverter_input_power_l2', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Input power L2', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'input_power_l2', + 'unique_id': '111111111111111_input_power_l2', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_input_power_l2-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Imeon inverter Input power L2', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_input_power_l2', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '950.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_input_power_l3-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.imeon_inverter_input_power_l3', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Input power L3', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'input_power_l3', + 'unique_id': '111111111111111_input_power_l3', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_input_power_l3-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Imeon inverter Input power L3', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_input_power_l3', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '980.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_input_power_total-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.imeon_inverter_input_power_total', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Input power total', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'input_power_total', + 'unique_id': '111111111111111_input_power_total', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_input_power_total-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Imeon inverter Input power total', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_input_power_total', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2930.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_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': , + 'entity_id': 'sensor.imeon_inverter_meter_power', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Meter power', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'meter_power', + 'unique_id': '111111111111111_meter_power', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_meter_power-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Imeon inverter Meter power', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_meter_power', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2000.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_meter_power_protocol-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.imeon_inverter_meter_power_protocol', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Meter power protocol', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'meter_power_protocol', + 'unique_id': '111111111111111_meter_power_protocol', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_meter_power_protocol-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Imeon inverter Meter power protocol', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_meter_power_protocol', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2018.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_building_consumption-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.imeon_inverter_monitoring_building_consumption', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Monitoring building consumption', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'monitoring_building_consumption', + 'unique_id': '111111111111111_monitoring_building_consumption', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_building_consumption-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'Imeon inverter Monitoring building consumption', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_monitoring_building_consumption', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '3000.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_building_consumption_minute-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.imeon_inverter_monitoring_building_consumption_minute', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Monitoring building consumption (minute)', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'monitoring_minute_building_consumption', + 'unique_id': '111111111111111_monitoring_minute_building_consumption', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_building_consumption_minute-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Imeon inverter Monitoring building consumption (minute)', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_monitoring_building_consumption_minute', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '50.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_economy_factor-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.imeon_inverter_monitoring_economy_factor', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Monitoring economy factor', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'monitoring_economy_factor', + 'unique_id': '111111111111111_monitoring_economy_factor', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_economy_factor-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Imeon inverter Monitoring economy factor', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_monitoring_economy_factor', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '0.8', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_grid_consumption-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.imeon_inverter_monitoring_grid_consumption', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Monitoring grid consumption', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'monitoring_grid_consumption', + 'unique_id': '111111111111111_monitoring_grid_consumption', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_grid_consumption-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'Imeon inverter Monitoring grid consumption', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_monitoring_grid_consumption', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '500.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_grid_consumption_minute-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.imeon_inverter_monitoring_grid_consumption_minute', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Monitoring grid consumption (minute)', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'monitoring_minute_grid_consumption', + 'unique_id': '111111111111111_monitoring_minute_grid_consumption', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_grid_consumption_minute-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Imeon inverter Monitoring grid consumption (minute)', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_monitoring_grid_consumption_minute', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '8.3', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_grid_injection-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.imeon_inverter_monitoring_grid_injection', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Monitoring grid injection', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'monitoring_grid_injection', + 'unique_id': '111111111111111_monitoring_grid_injection', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_grid_injection-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'Imeon inverter Monitoring grid injection', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_monitoring_grid_injection', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '700.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_grid_injection_minute-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.imeon_inverter_monitoring_grid_injection_minute', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Monitoring grid injection (minute)', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'monitoring_minute_grid_injection', + 'unique_id': '111111111111111_monitoring_minute_grid_injection', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_grid_injection_minute-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Imeon inverter Monitoring grid injection (minute)', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_monitoring_grid_injection_minute', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '11.7', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_grid_power_flow-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.imeon_inverter_monitoring_grid_power_flow', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Monitoring grid power flow', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'monitoring_grid_power_flow', + 'unique_id': '111111111111111_monitoring_grid_power_flow', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_grid_power_flow-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'Imeon inverter Monitoring grid power flow', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_monitoring_grid_power_flow', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '-200.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_grid_power_flow_minute-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.imeon_inverter_monitoring_grid_power_flow_minute', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Monitoring grid power flow (minute)', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'monitoring_minute_grid_power_flow', + 'unique_id': '111111111111111_monitoring_minute_grid_power_flow', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_grid_power_flow_minute-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Imeon inverter Monitoring grid power flow (minute)', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_monitoring_grid_power_flow_minute', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '-3.4', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_self_consumption-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.imeon_inverter_monitoring_self_consumption', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Monitoring self consumption', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'monitoring_self_consumption', + 'unique_id': '111111111111111_monitoring_self_consumption', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_self_consumption-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Imeon inverter Monitoring self consumption', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_monitoring_self_consumption', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '85.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_self_sufficiency-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.imeon_inverter_monitoring_self_sufficiency', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Monitoring self sufficiency', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'monitoring_self_sufficiency', + 'unique_id': '111111111111111_monitoring_self_sufficiency', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_self_sufficiency-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Imeon inverter Monitoring self sufficiency', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_monitoring_self_sufficiency', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '90.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_solar_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': , + 'entity_id': 'sensor.imeon_inverter_monitoring_solar_production', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Monitoring solar production', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'monitoring_solar_production', + 'unique_id': '111111111111111_monitoring_solar_production', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_solar_production-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'Imeon inverter Monitoring solar production', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_monitoring_solar_production', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2600.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_solar_production_minute-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.imeon_inverter_monitoring_solar_production_minute', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Monitoring solar production (minute)', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'monitoring_minute_solar_production', + 'unique_id': '111111111111111_monitoring_minute_solar_production', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_monitoring_solar_production_minute-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Imeon inverter Monitoring solar production (minute)', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_monitoring_solar_production_minute', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '43.3', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_current_l1-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.imeon_inverter_output_current_l1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Output current L1', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'output_current_l1', + 'unique_id': '111111111111111_output_current_l1', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_current_l1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'Imeon inverter Output current L1', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_output_current_l1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '15.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_current_l2-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.imeon_inverter_output_current_l2', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Output current L2', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'output_current_l2', + 'unique_id': '111111111111111_output_current_l2', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_current_l2-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'Imeon inverter Output current L2', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_output_current_l2', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '14.5', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_current_l3-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.imeon_inverter_output_current_l3', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Output current L3', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'output_current_l3', + 'unique_id': '111111111111111_output_current_l3', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_current_l3-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'Imeon inverter Output current L3', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_output_current_l3', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '15.2', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_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': , + 'entity_id': 'sensor.imeon_inverter_output_frequency', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Output frequency', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'output_frequency', + 'unique_id': '111111111111111_output_frequency', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_frequency-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'frequency', + 'friendly_name': 'Imeon inverter Output frequency', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_output_frequency', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '49.9', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_power_l1-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.imeon_inverter_output_power_l1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Output power L1', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'output_power_l1', + 'unique_id': '111111111111111_output_power_l1', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_power_l1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Imeon inverter Output power L1', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_output_power_l1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '1100.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_power_l2-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.imeon_inverter_output_power_l2', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Output power L2', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'output_power_l2', + 'unique_id': '111111111111111_output_power_l2', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_power_l2-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Imeon inverter Output power L2', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_output_power_l2', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '1080.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_power_l3-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.imeon_inverter_output_power_l3', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Output power L3', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'output_power_l3', + 'unique_id': '111111111111111_output_power_l3', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_power_l3-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Imeon inverter Output power L3', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_output_power_l3', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '1120.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_power_total-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.imeon_inverter_output_power_total', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Output power total', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'output_power_total', + 'unique_id': '111111111111111_output_power_total', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_power_total-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Imeon inverter Output power total', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_output_power_total', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '3300.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_voltage_l1-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.imeon_inverter_output_voltage_l1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Output voltage L1', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'output_voltage_l1', + 'unique_id': '111111111111111_output_voltage_l1', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_voltage_l1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'voltage', + 'friendly_name': 'Imeon inverter Output voltage L1', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_output_voltage_l1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '231.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_voltage_l2-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.imeon_inverter_output_voltage_l2', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Output voltage L2', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'output_voltage_l2', + 'unique_id': '111111111111111_output_voltage_l2', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_voltage_l2-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'voltage', + 'friendly_name': 'Imeon inverter Output voltage L2', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_output_voltage_l2', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '229.8', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_voltage_l3-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.imeon_inverter_output_voltage_l3', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Output voltage L3', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'output_voltage_l3', + 'unique_id': '111111111111111_output_voltage_l3', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_output_voltage_l3-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'voltage', + 'friendly_name': 'Imeon inverter Output voltage L3', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_output_voltage_l3', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '230.2', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_pv_consumed-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.imeon_inverter_pv_consumed', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'PV consumed', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'pv_consumed', + 'unique_id': '111111111111111_pv_consumed', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_pv_consumed-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'Imeon inverter PV consumed', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_pv_consumed', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '1500.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_pv_injected-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.imeon_inverter_pv_injected', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'PV injected', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'pv_injected', + 'unique_id': '111111111111111_pv_injected', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_pv_injected-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'energy', + 'friendly_name': 'Imeon inverter PV injected', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_pv_injected', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '800.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_pv_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': , + 'entity_id': 'sensor.imeon_inverter_pv_power_1', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'PV power 1', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'pv_power_1', + 'unique_id': '111111111111111_pv_power_1', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_pv_power_1-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Imeon inverter PV power 1', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_pv_power_1', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '1200.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_pv_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': , + 'entity_id': 'sensor.imeon_inverter_pv_power_2', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'PV power 2', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'pv_power_2', + 'unique_id': '111111111111111_pv_power_2', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_pv_power_2-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Imeon inverter PV power 2', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_pv_power_2', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '1300.0', + }) +# --- +# name: test_sensors[sensor.imeon_inverter_pv_power_total-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.imeon_inverter_pv_power_total', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'PV power total', + 'platform': 'imeon_inverter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'pv_power_total', + 'unique_id': '111111111111111_pv_power_total', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[sensor.imeon_inverter_pv_power_total-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'power', + 'friendly_name': 'Imeon inverter PV power total', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.imeon_inverter_pv_power_total', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2500.0', + }) +# --- diff --git a/tests/components/imeon_inverter/test_config_flow.py b/tests/components/imeon_inverter/test_config_flow.py new file mode 100644 index 00000000000..9ebcf3ec80f --- /dev/null +++ b/tests/components/imeon_inverter/test_config_flow.py @@ -0,0 +1,205 @@ +"""Test the Imeon Inverter config flow.""" + +from copy import deepcopy +from unittest.mock import AsyncMock, MagicMock + +import pytest + +from homeassistant.components.imeon_inverter.const import DOMAIN +from homeassistant.config_entries import SOURCE_SSDP, SOURCE_USER +from homeassistant.const import CONF_HOST, CONF_SOURCE +from homeassistant.core import HomeAssistant +from homeassistant.data_entry_flow import FlowResultType +from homeassistant.helpers.service_info.ssdp import ATTR_UPNP_SERIAL + +from .conftest import TEST_DISCOVER, TEST_SERIAL, TEST_USER_INPUT + +from tests.common import MockConfigEntry + +pytestmark = pytest.mark.usefixtures("mock_async_setup_entry") + + +async def test_form_valid( + hass: HomeAssistant, + mock_async_setup_entry: AsyncMock, +) -> None: + """Test we get the form and the config is created with the good entries.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={CONF_SOURCE: SOURCE_USER} + ) + assert result["type"] is FlowResultType.FORM + assert result["errors"] == {} + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], TEST_USER_INPUT + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["title"] == f"Imeon {TEST_SERIAL}" + assert result["data"] == TEST_USER_INPUT + assert result["result"].unique_id == TEST_SERIAL + assert mock_async_setup_entry.call_count == 1 + + +async def test_form_invalid_auth( + hass: HomeAssistant, mock_imeon_inverter: MagicMock +) -> None: + """Test we handle invalid auth.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={CONF_SOURCE: SOURCE_USER} + ) + + mock_imeon_inverter.login.return_value = False + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], TEST_USER_INPUT + ) + + assert result["type"] is FlowResultType.FORM + assert result["errors"] == {"base": "invalid_auth"} + + mock_imeon_inverter.login.return_value = True + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], TEST_USER_INPUT + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + + +@pytest.mark.parametrize( + ("error", "expected"), + [ + (TimeoutError, "cannot_connect"), + (ValueError("Host invalid"), "invalid_host"), + (ValueError("Route invalid"), "invalid_route"), + (ValueError, "unknown"), + ], +) +async def test_form_exception( + hass: HomeAssistant, + mock_imeon_inverter: MagicMock, + error: Exception, + expected: str, +) -> None: + """Test we handle cannot connect error.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={CONF_SOURCE: SOURCE_USER} + ) + + mock_imeon_inverter.login.side_effect = error + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], TEST_USER_INPUT + ) + + assert result["type"] is FlowResultType.FORM + assert result["errors"] == {"base": expected} + + mock_imeon_inverter.login.side_effect = None + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], TEST_USER_INPUT + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + + +async def test_manual_setup_already_exists( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, +) -> None: + """Test that a flow with an existing id aborts.""" + mock_config_entry.add_to_hass(hass) + + result = await hass.config_entries.flow.async_init( + DOMAIN, context={CONF_SOURCE: SOURCE_USER} + ) + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], TEST_USER_INPUT + ) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "already_configured" + + +async def test_get_serial_timeout( + hass: HomeAssistant, mock_imeon_inverter: MagicMock +) -> None: + """Test the timeout error handling of getting the serial number.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, context={CONF_SOURCE: SOURCE_USER} + ) + + mock_imeon_inverter.get_serial.side_effect = TimeoutError + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], TEST_USER_INPUT + ) + + assert result["type"] is FlowResultType.FORM + assert result["errors"] == {"base": "cannot_connect"} + + mock_imeon_inverter.get_serial.side_effect = None + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], TEST_USER_INPUT + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + + +async def test_ssdp(hass: HomeAssistant) -> None: + """Test a ssdp discovery.""" + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={CONF_SOURCE: SOURCE_SSDP}, + data=TEST_DISCOVER, + ) + + assert result["type"] is FlowResultType.FORM + assert result["step_id"] == "user" + + user_input = TEST_USER_INPUT.copy() + user_input.pop(CONF_HOST) + + result = await hass.config_entries.flow.async_configure( + result["flow_id"], user_input + ) + + assert result["type"] is FlowResultType.CREATE_ENTRY + assert result["title"] == f"Imeon {TEST_SERIAL}" + assert result["data"] == TEST_USER_INPUT + + +async def test_ssdp_already_exist( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, +) -> None: + """Test that a ssdp discovery flow with an existing id aborts.""" + mock_config_entry.add_to_hass(hass) + + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={CONF_SOURCE: SOURCE_SSDP}, + data=TEST_DISCOVER, + ) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "already_configured" + + +async def test_ssdp_abort(hass: HomeAssistant) -> None: + """Test that a ssdp discovery aborts if serial is unknown.""" + data = deepcopy(TEST_DISCOVER) + data.upnp.pop(ATTR_UPNP_SERIAL, None) + + result = await hass.config_entries.flow.async_init( + DOMAIN, + context={CONF_SOURCE: SOURCE_SSDP}, + data=data, + ) + + assert result["type"] is FlowResultType.ABORT + assert result["reason"] == "cannot_connect" diff --git a/tests/components/imeon_inverter/test_sensor.py b/tests/components/imeon_inverter/test_sensor.py new file mode 100644 index 00000000000..19e912c1c5c --- /dev/null +++ b/tests/components/imeon_inverter/test_sensor.py @@ -0,0 +1,29 @@ +"""Test the Imeon Inverter sensors.""" + +from unittest.mock import MagicMock, patch + +from syrupy.assertion import SnapshotAssertion + +from homeassistant.const import Platform +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er + +from . import setup_integration + +from tests.common import MockConfigEntry, snapshot_platform + + +async def test_sensors( + hass: HomeAssistant, + mock_imeon_inverter: MagicMock, + entity_registry: er.EntityRegistry, + snapshot: SnapshotAssertion, + mock_config_entry: MockConfigEntry, +) -> None: + """Test the Imeon Inverter sensors.""" + with patch( + "homeassistant.components.imeon_inverter.const.PLATFORMS", [Platform.SENSOR] + ): + await setup_integration(hass, mock_config_entry) + + await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)