mirror of
				https://github.com/home-assistant/core.git
				synced 2025-11-04 00:19:31 +00:00 
			
		
		
		
	Compare commits
	
		
			5 Commits
		
	
	
		
			2025.10.0b
			...
			compensati
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					ed68a21afd | ||
| 
						 | 
					612cc91423 | ||
| 
						 | 
					170989ef30 | ||
| 
						 | 
					4aebf41c59 | ||
| 
						 | 
					abbaaf4ff5 | 
@@ -7,15 +7,18 @@ import numpy as np
 | 
			
		||||
import voluptuous as vol
 | 
			
		||||
 | 
			
		||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
 | 
			
		||||
from homeassistant.config_entries import ConfigEntry
 | 
			
		||||
from homeassistant.const import (
 | 
			
		||||
    CONF_ATTRIBUTE,
 | 
			
		||||
    CONF_MAXIMUM,
 | 
			
		||||
    CONF_MINIMUM,
 | 
			
		||||
    CONF_NAME,
 | 
			
		||||
    CONF_SOURCE,
 | 
			
		||||
    CONF_UNIQUE_ID,
 | 
			
		||||
    CONF_UNIT_OF_MEASUREMENT,
 | 
			
		||||
)
 | 
			
		||||
from homeassistant.core import HomeAssistant
 | 
			
		||||
from homeassistant.exceptions import ConfigEntryError
 | 
			
		||||
from homeassistant.helpers import config_validation as cv
 | 
			
		||||
from homeassistant.helpers.discovery import async_load_platform
 | 
			
		||||
from homeassistant.helpers.typing import ConfigType
 | 
			
		||||
@@ -32,6 +35,7 @@ from .const import (
 | 
			
		||||
    DEFAULT_DEGREE,
 | 
			
		||||
    DEFAULT_PRECISION,
 | 
			
		||||
    DOMAIN,
 | 
			
		||||
    PLATFORMS,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
_LOGGER = logging.getLogger(__name__)
 | 
			
		||||
@@ -77,11 +81,10 @@ CONFIG_SCHEMA = vol.Schema(
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
 | 
			
		||||
    """Set up the Compensation sensor."""
 | 
			
		||||
    hass.data[DATA_COMPENSATION] = {}
 | 
			
		||||
 | 
			
		||||
    for compensation, conf in config[DOMAIN].items():
 | 
			
		||||
async def create_compensation_data(
 | 
			
		||||
    hass: HomeAssistant, compensation: str, conf: ConfigType, should_raise: bool = False
 | 
			
		||||
) -> None:
 | 
			
		||||
    """Create compensation data."""
 | 
			
		||||
    _LOGGER.debug("Setup %s.%s", DOMAIN, compensation)
 | 
			
		||||
 | 
			
		||||
    degree = conf[CONF_DEGREE]
 | 
			
		||||
@@ -103,6 +106,15 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
 | 
			
		||||
                compensation,
 | 
			
		||||
                error,
 | 
			
		||||
            )
 | 
			
		||||
            if should_raise:
 | 
			
		||||
                raise ConfigEntryError(
 | 
			
		||||
                    translation_domain=DOMAIN,
 | 
			
		||||
                    translation_key="setup_error",
 | 
			
		||||
                    translation_placeholders={
 | 
			
		||||
                        "title": conf[CONF_NAME],
 | 
			
		||||
                        "error": str(error),
 | 
			
		||||
                    },
 | 
			
		||||
                ) from error
 | 
			
		||||
 | 
			
		||||
    if coefficients is not None:
 | 
			
		||||
        data = {
 | 
			
		||||
@@ -122,6 +134,16 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
 | 
			
		||||
 | 
			
		||||
        hass.data[DATA_COMPENSATION][compensation] = data
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
 | 
			
		||||
    """Set up the Compensation sensor."""
 | 
			
		||||
    hass.data[DATA_COMPENSATION] = {}
 | 
			
		||||
 | 
			
		||||
    if DOMAIN not in config:
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    for compensation, conf in config[DOMAIN].items():
 | 
			
		||||
        await create_compensation_data(hass, compensation, conf)
 | 
			
		||||
        hass.async_create_task(
 | 
			
		||||
            async_load_platform(
 | 
			
		||||
                hass,
 | 
			
		||||
@@ -133,3 +155,30 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    return True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
 | 
			
		||||
    """Set up Compensation from a config entry."""
 | 
			
		||||
    config = dict(entry.options)
 | 
			
		||||
    data_points = config[CONF_DATAPOINTS]
 | 
			
		||||
    new_data_points = []
 | 
			
		||||
    for data_point in data_points:
 | 
			
		||||
        values = data_point.split(",", maxsplit=1)
 | 
			
		||||
        new_data_points.append([float(values[0]), float(values[1])])
 | 
			
		||||
    config[CONF_DATAPOINTS] = new_data_points
 | 
			
		||||
 | 
			
		||||
    await create_compensation_data(hass, entry.entry_id, config, True)
 | 
			
		||||
    await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
 | 
			
		||||
    entry.async_on_unload(entry.add_update_listener(update_listener))
 | 
			
		||||
 | 
			
		||||
    return True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
 | 
			
		||||
    """Unload Compensation config entry."""
 | 
			
		||||
    return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None:
 | 
			
		||||
    """Handle options update."""
 | 
			
		||||
    await hass.config_entries.async_reload(entry.entry_id)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										147
									
								
								homeassistant/components/compensation/config_flow.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								homeassistant/components/compensation/config_flow.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,147 @@
 | 
			
		||||
"""Config flow for statistics."""
 | 
			
		||||
 | 
			
		||||
from __future__ import annotations
 | 
			
		||||
 | 
			
		||||
from collections.abc import Mapping
 | 
			
		||||
from typing import Any, cast
 | 
			
		||||
 | 
			
		||||
import voluptuous as vol
 | 
			
		||||
 | 
			
		||||
from homeassistant.const import (
 | 
			
		||||
    CONF_ATTRIBUTE,
 | 
			
		||||
    CONF_ENTITY_ID,
 | 
			
		||||
    CONF_NAME,
 | 
			
		||||
    CONF_UNIT_OF_MEASUREMENT,
 | 
			
		||||
)
 | 
			
		||||
from homeassistant.helpers.schema_config_entry_flow import (
 | 
			
		||||
    SchemaCommonFlowHandler,
 | 
			
		||||
    SchemaConfigFlowHandler,
 | 
			
		||||
    SchemaFlowError,
 | 
			
		||||
    SchemaFlowFormStep,
 | 
			
		||||
)
 | 
			
		||||
from homeassistant.helpers.selector import (
 | 
			
		||||
    AttributeSelector,
 | 
			
		||||
    AttributeSelectorConfig,
 | 
			
		||||
    BooleanSelector,
 | 
			
		||||
    EntitySelector,
 | 
			
		||||
    NumberSelector,
 | 
			
		||||
    NumberSelectorConfig,
 | 
			
		||||
    NumberSelectorMode,
 | 
			
		||||
    SelectSelector,
 | 
			
		||||
    SelectSelectorConfig,
 | 
			
		||||
    SelectSelectorMode,
 | 
			
		||||
    TextSelector,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
from .const import (
 | 
			
		||||
    CONF_DATAPOINTS,
 | 
			
		||||
    CONF_DEGREE,
 | 
			
		||||
    CONF_LOWER_LIMIT,
 | 
			
		||||
    CONF_PRECISION,
 | 
			
		||||
    CONF_UPPER_LIMIT,
 | 
			
		||||
    DEFAULT_DEGREE,
 | 
			
		||||
    DEFAULT_NAME,
 | 
			
		||||
    DEFAULT_PRECISION,
 | 
			
		||||
    DOMAIN,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def get_options_schema(handler: SchemaCommonFlowHandler) -> vol.Schema:
 | 
			
		||||
    """Get options schema."""
 | 
			
		||||
    entity_id = handler.options[CONF_ENTITY_ID]
 | 
			
		||||
 | 
			
		||||
    return vol.Schema(
 | 
			
		||||
        {
 | 
			
		||||
            vol.Required(CONF_DATAPOINTS): SelectSelector(
 | 
			
		||||
                SelectSelectorConfig(
 | 
			
		||||
                    options=[],
 | 
			
		||||
                    multiple=True,
 | 
			
		||||
                    custom_value=True,
 | 
			
		||||
                    mode=SelectSelectorMode.DROPDOWN,
 | 
			
		||||
                )
 | 
			
		||||
            ),
 | 
			
		||||
            vol.Optional(CONF_ATTRIBUTE): AttributeSelector(
 | 
			
		||||
                AttributeSelectorConfig(entity_id=entity_id)
 | 
			
		||||
            ),
 | 
			
		||||
            vol.Optional(CONF_UPPER_LIMIT, default=False): BooleanSelector(),
 | 
			
		||||
            vol.Optional(CONF_LOWER_LIMIT, default=False): BooleanSelector(),
 | 
			
		||||
            vol.Optional(CONF_PRECISION, default=DEFAULT_PRECISION): NumberSelector(
 | 
			
		||||
                NumberSelectorConfig(min=0, step=1, mode=NumberSelectorMode.BOX)
 | 
			
		||||
            ),
 | 
			
		||||
            vol.Optional(CONF_DEGREE, default=DEFAULT_DEGREE): NumberSelector(
 | 
			
		||||
                NumberSelectorConfig(min=0, max=7, step=1, mode=NumberSelectorMode.BOX)
 | 
			
		||||
            ),
 | 
			
		||||
            vol.Optional(CONF_UNIT_OF_MEASUREMENT): TextSelector(),
 | 
			
		||||
        }
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _is_valid_data_points(check_data_points: list[str]) -> bool:
 | 
			
		||||
    """Validate data points."""
 | 
			
		||||
    result = False
 | 
			
		||||
    for data_point in check_data_points:
 | 
			
		||||
        if not data_point.find(",") > 0:
 | 
			
		||||
            return False
 | 
			
		||||
        values = data_point.split(",", maxsplit=1)
 | 
			
		||||
        for value in values:
 | 
			
		||||
            try:
 | 
			
		||||
                float(value)
 | 
			
		||||
            except ValueError:
 | 
			
		||||
                return False
 | 
			
		||||
        result = True
 | 
			
		||||
    return result
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def validate_options(
 | 
			
		||||
    handler: SchemaCommonFlowHandler, user_input: dict[str, Any]
 | 
			
		||||
) -> dict[str, Any]:
 | 
			
		||||
    """Validate options selected."""
 | 
			
		||||
 | 
			
		||||
    user_input[CONF_PRECISION] = int(user_input[CONF_PRECISION])
 | 
			
		||||
    user_input[CONF_DEGREE] = int(user_input[CONF_DEGREE])
 | 
			
		||||
 | 
			
		||||
    if not _is_valid_data_points(user_input[CONF_DATAPOINTS]):
 | 
			
		||||
        raise SchemaFlowError("incorrect_datapoints")
 | 
			
		||||
 | 
			
		||||
    if len(user_input[CONF_DATAPOINTS]) <= user_input[CONF_DEGREE]:
 | 
			
		||||
        raise SchemaFlowError("not_enough_datapoints")
 | 
			
		||||
 | 
			
		||||
    handler.parent_handler._async_abort_entries_match({**handler.options, **user_input})  # noqa: SLF001
 | 
			
		||||
 | 
			
		||||
    return user_input
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
DATA_SCHEMA_SETUP = vol.Schema(
 | 
			
		||||
    {
 | 
			
		||||
        vol.Required(CONF_NAME, default=DEFAULT_NAME): TextSelector(),
 | 
			
		||||
        vol.Required(CONF_ENTITY_ID): EntitySelector(),
 | 
			
		||||
    }
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
CONFIG_FLOW = {
 | 
			
		||||
    "user": SchemaFlowFormStep(
 | 
			
		||||
        schema=DATA_SCHEMA_SETUP,
 | 
			
		||||
        next_step="options",
 | 
			
		||||
    ),
 | 
			
		||||
    "options": SchemaFlowFormStep(
 | 
			
		||||
        schema=get_options_schema,
 | 
			
		||||
        validate_user_input=validate_options,
 | 
			
		||||
    ),
 | 
			
		||||
}
 | 
			
		||||
OPTIONS_FLOW = {
 | 
			
		||||
    "init": SchemaFlowFormStep(
 | 
			
		||||
        get_options_schema,
 | 
			
		||||
        validate_user_input=validate_options,
 | 
			
		||||
    ),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CompensationConfigFlowHandler(SchemaConfigFlowHandler, domain=DOMAIN):
 | 
			
		||||
    """Handle a config flow for Compensation."""
 | 
			
		||||
 | 
			
		||||
    config_flow = CONFIG_FLOW
 | 
			
		||||
    options_flow = OPTIONS_FLOW
 | 
			
		||||
 | 
			
		||||
    def async_config_entry_title(self, options: Mapping[str, Any]) -> str:
 | 
			
		||||
        """Return config entry title."""
 | 
			
		||||
        return cast(str, options[CONF_NAME])
 | 
			
		||||
@@ -1,6 +1,9 @@
 | 
			
		||||
"""Compensation constants."""
 | 
			
		||||
 | 
			
		||||
from homeassistant.const import Platform
 | 
			
		||||
 | 
			
		||||
DOMAIN = "compensation"
 | 
			
		||||
PLATFORMS = [Platform.SENSOR]
 | 
			
		||||
 | 
			
		||||
SENSOR = "compensation"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,9 @@
 | 
			
		||||
  "domain": "compensation",
 | 
			
		||||
  "name": "Compensation",
 | 
			
		||||
  "codeowners": ["@Petro31"],
 | 
			
		||||
  "config_flow": true,
 | 
			
		||||
  "documentation": "https://www.home-assistant.io/integrations/compensation",
 | 
			
		||||
  "integration_type": "helper",
 | 
			
		||||
  "iot_class": "calculated",
 | 
			
		||||
  "quality_scale": "legacy",
 | 
			
		||||
  "requirements": ["numpy==2.3.0"]
 | 
			
		||||
 
 | 
			
		||||
@@ -8,9 +8,11 @@ from typing import Any
 | 
			
		||||
import numpy as np
 | 
			
		||||
 | 
			
		||||
from homeassistant.components.sensor import SensorEntity
 | 
			
		||||
from homeassistant.config_entries import ConfigEntry
 | 
			
		||||
from homeassistant.const import (
 | 
			
		||||
    ATTR_UNIT_OF_MEASUREMENT,
 | 
			
		||||
    CONF_ATTRIBUTE,
 | 
			
		||||
    CONF_ENTITY_ID,
 | 
			
		||||
    CONF_MAXIMUM,
 | 
			
		||||
    CONF_MINIMUM,
 | 
			
		||||
    CONF_SOURCE,
 | 
			
		||||
@@ -80,6 +82,36 @@ async def async_setup_platform(
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def async_setup_entry(
 | 
			
		||||
    hass: HomeAssistant,
 | 
			
		||||
    entry: ConfigEntry,
 | 
			
		||||
    async_add_entities: AddEntitiesCallback,
 | 
			
		||||
) -> None:
 | 
			
		||||
    """Set up the Compensation sensor entry."""
 | 
			
		||||
    compensation = entry.entry_id
 | 
			
		||||
    conf: dict[str, Any] = hass.data[DATA_COMPENSATION][compensation]
 | 
			
		||||
 | 
			
		||||
    source: str = conf[CONF_ENTITY_ID]
 | 
			
		||||
    attribute: str | None = conf.get(CONF_ATTRIBUTE)
 | 
			
		||||
    name = entry.title
 | 
			
		||||
 | 
			
		||||
    async_add_entities(
 | 
			
		||||
        [
 | 
			
		||||
            CompensationSensor(
 | 
			
		||||
                entry.entry_id,
 | 
			
		||||
                name,
 | 
			
		||||
                source,
 | 
			
		||||
                attribute,
 | 
			
		||||
                conf[CONF_PRECISION],
 | 
			
		||||
                conf[CONF_POLYNOMIAL],
 | 
			
		||||
                conf.get(CONF_UNIT_OF_MEASUREMENT),
 | 
			
		||||
                conf[CONF_MINIMUM],
 | 
			
		||||
                conf[CONF_MAXIMUM],
 | 
			
		||||
            )
 | 
			
		||||
        ]
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class CompensationSensor(SensorEntity):
 | 
			
		||||
    """Representation of a Compensation sensor."""
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										82
									
								
								homeassistant/components/compensation/strings.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								homeassistant/components/compensation/strings.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
{
 | 
			
		||||
  "config": {
 | 
			
		||||
    "abort": {
 | 
			
		||||
      "already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
 | 
			
		||||
    },
 | 
			
		||||
    "error": {
 | 
			
		||||
      "incorrect_datapoints": "Datapoints needs to be provided in the right format, ex. '1.0, 0.0'.",
 | 
			
		||||
      "not_enough_datapoints": "The number of datapoints needs to be more than the configured degree."
 | 
			
		||||
    },
 | 
			
		||||
    "step": {
 | 
			
		||||
      "user": {
 | 
			
		||||
        "description": "Add a compensation sensor",
 | 
			
		||||
        "data": {
 | 
			
		||||
          "name": "[%key:common::config_flow::data::name%]",
 | 
			
		||||
          "entity_id": "Entity"
 | 
			
		||||
        },
 | 
			
		||||
        "data_description": {
 | 
			
		||||
          "name": "Name for the created entity.",
 | 
			
		||||
          "entity_id": "Entity to use as source."
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "options": {
 | 
			
		||||
        "description": "Read the documention for further details on how to configure the statistics sensor using these options.",
 | 
			
		||||
        "data": {
 | 
			
		||||
          "data_points": "Data points",
 | 
			
		||||
          "attribute": "Attribute",
 | 
			
		||||
          "upper_limit": "Upper limit",
 | 
			
		||||
          "lower_limit": "Lower limit",
 | 
			
		||||
          "precision": "Precision",
 | 
			
		||||
          "degree": "Degree",
 | 
			
		||||
          "unit_of_measurement": "Unit of measurement"
 | 
			
		||||
        },
 | 
			
		||||
        "data_description": {
 | 
			
		||||
          "data_points": "The collection of data point conversions with the format 'uncompensated_value, compensated_value', ex. '1.0, 0.0'",
 | 
			
		||||
          "attribute": "Attribute from the source to monitor/compensate.",
 | 
			
		||||
          "upper_limit": "Enables an upper limit for the sensor. The upper limit is defined by the data collections (data_points) greatest uncompensated value.",
 | 
			
		||||
          "lower_limit": "Enables a lower limit for the sensor. The lower limit is defined by the data collections (data_points) lowest uncompensated value.",
 | 
			
		||||
          "precision": "Defines the precision of the calculated values, through the argument of round().",
 | 
			
		||||
          "degree": "The degree of a polynomial.",
 | 
			
		||||
          "unit_of_measurement": "Defines the units of measurement of the sensor, if any."
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "options": {
 | 
			
		||||
    "abort": {
 | 
			
		||||
      "already_configured": "[%key:common::config_flow::abort::already_configured_account%]"
 | 
			
		||||
    },
 | 
			
		||||
    "error": {
 | 
			
		||||
      "incorrect_datapoints": "[%key:component::compensation::config::error::incorrect_datapoints%]",
 | 
			
		||||
      "not_enough_datapoints": "[%key:component::compensation::config::error::not_enough_datapoints%]"
 | 
			
		||||
    },
 | 
			
		||||
    "step": {
 | 
			
		||||
      "init": {
 | 
			
		||||
        "description": "[%key:component::compensation::config::step::options::description%]",
 | 
			
		||||
        "data": {
 | 
			
		||||
          "data_points": "[%key:component::compensation::config::step::options::data::data_points%]",
 | 
			
		||||
          "attribute": "[%key:component::compensation::config::step::options::data::attribute%]",
 | 
			
		||||
          "upper_limit": "[%key:component::compensation::config::step::options::data::upper_limit%]",
 | 
			
		||||
          "lower_limit": "[%key:component::compensation::config::step::options::data::lower_limit%]",
 | 
			
		||||
          "precision": "[%key:component::compensation::config::step::options::data::precision%]",
 | 
			
		||||
          "degree": "[%key:component::compensation::config::step::options::data::degree%]",
 | 
			
		||||
          "unit_of_measurement": "[%key:component::compensation::config::step::options::data::unit_of_measurement%]"
 | 
			
		||||
        },
 | 
			
		||||
        "data_description": {
 | 
			
		||||
          "data_points": "[%key:component::compensation::config::step::options::data_description::data_points%]",
 | 
			
		||||
          "attribute": "[%key:component::compensation::config::step::options::data_description::attribute%]",
 | 
			
		||||
          "upper_limit": "[%key:component::compensation::config::step::options::data_description::upper_limit%]",
 | 
			
		||||
          "lower_limit": "[%key:component::compensation::config::step::options::data_description::lower_limit%]",
 | 
			
		||||
          "precision": "[%key:component::compensation::config::step::options::data_description::precision%]",
 | 
			
		||||
          "degree": "[%key:component::compensation::config::step::options::data_description::degree%]",
 | 
			
		||||
          "unit_of_measurement": "[%key:component::compensation::config::step::options::data_description::unit_of_measurement%]"
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  "exceptions": {
 | 
			
		||||
    "setup_error": {
 | 
			
		||||
      "message": "Setup of {title} could not be setup due to {error}"
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										1
									
								
								homeassistant/generated/config_flows.py
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								homeassistant/generated/config_flows.py
									
									
									
										generated
									
									
									
								
							@@ -5,6 +5,7 @@ To update, run python3 -m script.hassfest
 | 
			
		||||
 | 
			
		||||
FLOWS = {
 | 
			
		||||
    "helper": [
 | 
			
		||||
        "compensation",
 | 
			
		||||
        "derivative",
 | 
			
		||||
        "filter",
 | 
			
		||||
        "generic_hygrostat",
 | 
			
		||||
 
 | 
			
		||||
@@ -1072,12 +1072,6 @@
 | 
			
		||||
      "config_flow": false,
 | 
			
		||||
      "iot_class": "local_polling"
 | 
			
		||||
    },
 | 
			
		||||
    "compensation": {
 | 
			
		||||
      "name": "Compensation",
 | 
			
		||||
      "integration_type": "hub",
 | 
			
		||||
      "config_flow": false,
 | 
			
		||||
      "iot_class": "calculated"
 | 
			
		||||
    },
 | 
			
		||||
    "concord232": {
 | 
			
		||||
      "name": "Concord232",
 | 
			
		||||
      "integration_type": "hub",
 | 
			
		||||
@@ -7733,6 +7727,12 @@
 | 
			
		||||
      "config_flow": false,
 | 
			
		||||
      "iot_class": "local_polling"
 | 
			
		||||
    },
 | 
			
		||||
    "compensation": {
 | 
			
		||||
      "name": "Compensation",
 | 
			
		||||
      "integration_type": "helper",
 | 
			
		||||
      "config_flow": true,
 | 
			
		||||
      "iot_class": "calculated"
 | 
			
		||||
    },
 | 
			
		||||
    "counter": {
 | 
			
		||||
      "integration_type": "helper",
 | 
			
		||||
      "config_flow": false
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										81
									
								
								tests/components/compensation/conftest.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								tests/components/compensation/conftest.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,81 @@
 | 
			
		||||
"""Fixtures for the Compensation integration."""
 | 
			
		||||
 | 
			
		||||
from __future__ import annotations
 | 
			
		||||
 | 
			
		||||
from collections.abc import Generator
 | 
			
		||||
from typing import Any
 | 
			
		||||
from unittest.mock import AsyncMock, patch
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
 | 
			
		||||
from homeassistant.components.compensation.const import (
 | 
			
		||||
    CONF_DATAPOINTS,
 | 
			
		||||
    CONF_DEGREE,
 | 
			
		||||
    CONF_LOWER_LIMIT,
 | 
			
		||||
    CONF_PRECISION,
 | 
			
		||||
    CONF_UPPER_LIMIT,
 | 
			
		||||
    DEFAULT_DEGREE,
 | 
			
		||||
    DEFAULT_NAME,
 | 
			
		||||
    DOMAIN,
 | 
			
		||||
)
 | 
			
		||||
from homeassistant.config_entries import SOURCE_USER
 | 
			
		||||
from homeassistant.const import CONF_ENTITY_ID, CONF_NAME, CONF_UNIT_OF_MEASUREMENT
 | 
			
		||||
from homeassistant.core import HomeAssistant
 | 
			
		||||
 | 
			
		||||
from tests.common import MockConfigEntry
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture
 | 
			
		||||
def mock_setup_entry() -> Generator[AsyncMock]:
 | 
			
		||||
    """Automatically patch compensation setup_entry."""
 | 
			
		||||
    with patch(
 | 
			
		||||
        "homeassistant.components.compensation.async_setup_entry",
 | 
			
		||||
        return_value=True,
 | 
			
		||||
    ) as mock_setup_entry:
 | 
			
		||||
        yield mock_setup_entry
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture(name="get_config")
 | 
			
		||||
async def get_config_to_integration_load() -> dict[str, Any]:
 | 
			
		||||
    """Return configuration.
 | 
			
		||||
 | 
			
		||||
    To override the config, tests can be marked with:
 | 
			
		||||
    @pytest.mark.parametrize("get_config", [{...}])
 | 
			
		||||
    """
 | 
			
		||||
    return {
 | 
			
		||||
        CONF_NAME: DEFAULT_NAME,
 | 
			
		||||
        CONF_ENTITY_ID: "sensor.uncompensated",
 | 
			
		||||
        CONF_DATAPOINTS: [
 | 
			
		||||
            "1.0, 2.0",
 | 
			
		||||
            "2.0, 3.0",
 | 
			
		||||
        ],
 | 
			
		||||
        CONF_UPPER_LIMIT: False,
 | 
			
		||||
        CONF_LOWER_LIMIT: False,
 | 
			
		||||
        CONF_PRECISION: 2,
 | 
			
		||||
        CONF_DEGREE: DEFAULT_DEGREE,
 | 
			
		||||
        CONF_UNIT_OF_MEASUREMENT: "mm",
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@pytest.fixture(name="loaded_entry")
 | 
			
		||||
async def load_integration(
 | 
			
		||||
    hass: HomeAssistant, get_config: dict[str, Any]
 | 
			
		||||
) -> MockConfigEntry:
 | 
			
		||||
    """Set up the Compensation integration in Home Assistant."""
 | 
			
		||||
    config_entry = MockConfigEntry(
 | 
			
		||||
        domain=DOMAIN,
 | 
			
		||||
        title="Compensation sensor",
 | 
			
		||||
        source=SOURCE_USER,
 | 
			
		||||
        options=get_config,
 | 
			
		||||
        entry_id="1",
 | 
			
		||||
    )
 | 
			
		||||
    config_entry.add_to_hass(hass)
 | 
			
		||||
 | 
			
		||||
    entity_id = get_config[CONF_ENTITY_ID]
 | 
			
		||||
    hass.states.async_set(entity_id, 4, {})
 | 
			
		||||
    await hass.async_block_till_done()
 | 
			
		||||
 | 
			
		||||
    await hass.config_entries.async_setup(config_entry.entry_id)
 | 
			
		||||
    await hass.async_block_till_done()
 | 
			
		||||
 | 
			
		||||
    return config_entry
 | 
			
		||||
							
								
								
									
										266
									
								
								tests/components/compensation/test_config_flow.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										266
									
								
								tests/components/compensation/test_config_flow.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,266 @@
 | 
			
		||||
"""Test the Compensation config flow."""
 | 
			
		||||
 | 
			
		||||
from __future__ import annotations
 | 
			
		||||
 | 
			
		||||
from unittest.mock import AsyncMock
 | 
			
		||||
 | 
			
		||||
from homeassistant import config_entries
 | 
			
		||||
from homeassistant.components.compensation.const import (
 | 
			
		||||
    CONF_DATAPOINTS,
 | 
			
		||||
    CONF_DEGREE,
 | 
			
		||||
    CONF_LOWER_LIMIT,
 | 
			
		||||
    CONF_PRECISION,
 | 
			
		||||
    CONF_UPPER_LIMIT,
 | 
			
		||||
    DEFAULT_NAME,
 | 
			
		||||
    DOMAIN,
 | 
			
		||||
)
 | 
			
		||||
from homeassistant.const import CONF_ENTITY_ID, CONF_NAME, CONF_UNIT_OF_MEASUREMENT
 | 
			
		||||
from homeassistant.core import HomeAssistant
 | 
			
		||||
from homeassistant.data_entry_flow import FlowResultType
 | 
			
		||||
 | 
			
		||||
from tests.common import MockConfigEntry
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def test_form(hass: HomeAssistant, mock_setup_entry: AsyncMock) -> None:
 | 
			
		||||
    """Test we get the form."""
 | 
			
		||||
 | 
			
		||||
    result = await hass.config_entries.flow.async_init(
 | 
			
		||||
        DOMAIN, context={"source": config_entries.SOURCE_USER}
 | 
			
		||||
    )
 | 
			
		||||
    assert result["step_id"] == "user"
 | 
			
		||||
    assert result["type"] is FlowResultType.FORM
 | 
			
		||||
 | 
			
		||||
    result = await hass.config_entries.flow.async_configure(
 | 
			
		||||
        result["flow_id"],
 | 
			
		||||
        {
 | 
			
		||||
            CONF_NAME: DEFAULT_NAME,
 | 
			
		||||
            CONF_ENTITY_ID: "sensor.test_monitored",
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
    await hass.async_block_till_done()
 | 
			
		||||
    result = await hass.config_entries.flow.async_configure(
 | 
			
		||||
        result["flow_id"],
 | 
			
		||||
        {
 | 
			
		||||
            CONF_DATAPOINTS: [
 | 
			
		||||
                "1.0, 2.0",
 | 
			
		||||
                "2.0, 3.0",
 | 
			
		||||
            ],
 | 
			
		||||
            CONF_UPPER_LIMIT: False,
 | 
			
		||||
            CONF_LOWER_LIMIT: False,
 | 
			
		||||
            CONF_PRECISION: 2,
 | 
			
		||||
            CONF_DEGREE: 1,
 | 
			
		||||
            CONF_UNIT_OF_MEASUREMENT: "mm",
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
    await hass.async_block_till_done()
 | 
			
		||||
 | 
			
		||||
    assert result["type"] is FlowResultType.CREATE_ENTRY
 | 
			
		||||
    assert result["version"] == 1
 | 
			
		||||
    assert result["options"] == {
 | 
			
		||||
        CONF_NAME: DEFAULT_NAME,
 | 
			
		||||
        CONF_ENTITY_ID: "sensor.test_monitored",
 | 
			
		||||
        CONF_DATAPOINTS: [
 | 
			
		||||
            "1.0, 2.0",
 | 
			
		||||
            "2.0, 3.0",
 | 
			
		||||
        ],
 | 
			
		||||
        CONF_UPPER_LIMIT: False,
 | 
			
		||||
        CONF_LOWER_LIMIT: False,
 | 
			
		||||
        CONF_PRECISION: 2,
 | 
			
		||||
        CONF_DEGREE: 1,
 | 
			
		||||
        CONF_UNIT_OF_MEASUREMENT: "mm",
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    assert len(mock_setup_entry.mock_calls) == 1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def test_options_flow(hass: HomeAssistant, loaded_entry: MockConfigEntry) -> None:
 | 
			
		||||
    """Test options flow."""
 | 
			
		||||
 | 
			
		||||
    result = await hass.config_entries.options.async_init(loaded_entry.entry_id)
 | 
			
		||||
 | 
			
		||||
    assert result["type"] is FlowResultType.FORM
 | 
			
		||||
    assert result["step_id"] == "init"
 | 
			
		||||
 | 
			
		||||
    result = await hass.config_entries.options.async_configure(
 | 
			
		||||
        result["flow_id"],
 | 
			
		||||
        user_input={
 | 
			
		||||
            CONF_DATAPOINTS: [
 | 
			
		||||
                "1.0, 2.0",
 | 
			
		||||
                "2.0, 3.0",
 | 
			
		||||
            ],
 | 
			
		||||
            CONF_UPPER_LIMIT: False,
 | 
			
		||||
            CONF_LOWER_LIMIT: False,
 | 
			
		||||
            CONF_PRECISION: 2,
 | 
			
		||||
            CONF_DEGREE: 1,
 | 
			
		||||
            CONF_UNIT_OF_MEASUREMENT: "km",
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
    await hass.async_block_till_done()
 | 
			
		||||
 | 
			
		||||
    assert result["type"] is FlowResultType.CREATE_ENTRY
 | 
			
		||||
    assert result["data"] == {
 | 
			
		||||
        CONF_NAME: DEFAULT_NAME,
 | 
			
		||||
        CONF_ENTITY_ID: "sensor.uncompensated",
 | 
			
		||||
        CONF_DATAPOINTS: [
 | 
			
		||||
            "1.0, 2.0",
 | 
			
		||||
            "2.0, 3.0",
 | 
			
		||||
        ],
 | 
			
		||||
        CONF_UPPER_LIMIT: False,
 | 
			
		||||
        CONF_LOWER_LIMIT: False,
 | 
			
		||||
        CONF_PRECISION: 2,
 | 
			
		||||
        CONF_DEGREE: 1,
 | 
			
		||||
        CONF_UNIT_OF_MEASUREMENT: "km",
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    await hass.async_block_till_done()
 | 
			
		||||
 | 
			
		||||
    # Check the entity was updated, no new entity was created
 | 
			
		||||
    assert len(hass.states.async_all()) == 2
 | 
			
		||||
 | 
			
		||||
    state = hass.states.get("sensor.compensation_sensor")
 | 
			
		||||
    assert state is not None
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def test_validation_options(
 | 
			
		||||
    hass: HomeAssistant, mock_setup_entry: AsyncMock
 | 
			
		||||
) -> None:
 | 
			
		||||
    """Test validation."""
 | 
			
		||||
 | 
			
		||||
    result = await hass.config_entries.flow.async_init(
 | 
			
		||||
        DOMAIN, context={"source": config_entries.SOURCE_USER}
 | 
			
		||||
    )
 | 
			
		||||
    assert result["step_id"] == "user"
 | 
			
		||||
    assert result["type"] is FlowResultType.FORM
 | 
			
		||||
 | 
			
		||||
    result = await hass.config_entries.flow.async_configure(
 | 
			
		||||
        result["flow_id"],
 | 
			
		||||
        {
 | 
			
		||||
            CONF_NAME: DEFAULT_NAME,
 | 
			
		||||
            CONF_ENTITY_ID: "sensor.test_monitored",
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
    await hass.async_block_till_done()
 | 
			
		||||
    result = await hass.config_entries.flow.async_configure(
 | 
			
		||||
        result["flow_id"],
 | 
			
		||||
        {
 | 
			
		||||
            CONF_DATAPOINTS: [
 | 
			
		||||
                "1.0, 2.0",
 | 
			
		||||
                "2.0, 3.0",
 | 
			
		||||
            ],
 | 
			
		||||
            CONF_UPPER_LIMIT: False,
 | 
			
		||||
            CONF_LOWER_LIMIT: False,
 | 
			
		||||
            CONF_PRECISION: 2,
 | 
			
		||||
            CONF_DEGREE: 2,
 | 
			
		||||
            CONF_UNIT_OF_MEASUREMENT: "km",
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
    await hass.async_block_till_done()
 | 
			
		||||
 | 
			
		||||
    assert result["type"] is FlowResultType.FORM
 | 
			
		||||
    assert result["errors"] == {"base": "not_enough_datapoints"}
 | 
			
		||||
 | 
			
		||||
    result = await hass.config_entries.flow.async_configure(
 | 
			
		||||
        result["flow_id"],
 | 
			
		||||
        {
 | 
			
		||||
            CONF_DATAPOINTS: [
 | 
			
		||||
                "1.0, 2.0",
 | 
			
		||||
                "2.0 3.0",
 | 
			
		||||
            ],
 | 
			
		||||
            CONF_UPPER_LIMIT: False,
 | 
			
		||||
            CONF_LOWER_LIMIT: False,
 | 
			
		||||
            CONF_PRECISION: 2,
 | 
			
		||||
            CONF_DEGREE: 1,
 | 
			
		||||
            CONF_UNIT_OF_MEASUREMENT: "km",
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
    await hass.async_block_till_done()
 | 
			
		||||
 | 
			
		||||
    assert result["type"] is FlowResultType.FORM
 | 
			
		||||
    assert result["errors"] == {"base": "incorrect_datapoints"}
 | 
			
		||||
 | 
			
		||||
    result = await hass.config_entries.flow.async_configure(
 | 
			
		||||
        result["flow_id"],
 | 
			
		||||
        {
 | 
			
		||||
            CONF_DATAPOINTS: [
 | 
			
		||||
                "1.0, 2.0",
 | 
			
		||||
                "2,0, 3.0",
 | 
			
		||||
            ],
 | 
			
		||||
            CONF_UPPER_LIMIT: False,
 | 
			
		||||
            CONF_LOWER_LIMIT: False,
 | 
			
		||||
            CONF_PRECISION: 2,
 | 
			
		||||
            CONF_DEGREE: 1,
 | 
			
		||||
            CONF_UNIT_OF_MEASUREMENT: "km",
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
    await hass.async_block_till_done()
 | 
			
		||||
 | 
			
		||||
    assert result["type"] is FlowResultType.FORM
 | 
			
		||||
    assert result["errors"] == {"base": "incorrect_datapoints"}
 | 
			
		||||
 | 
			
		||||
    result = await hass.config_entries.flow.async_configure(
 | 
			
		||||
        result["flow_id"],
 | 
			
		||||
        {
 | 
			
		||||
            CONF_DATAPOINTS: ["1.0, 2.0", "2.0, 3.0", "3.0, 4.0"],
 | 
			
		||||
            CONF_UPPER_LIMIT: False,
 | 
			
		||||
            CONF_LOWER_LIMIT: False,
 | 
			
		||||
            CONF_PRECISION: 2,
 | 
			
		||||
            CONF_DEGREE: 2,
 | 
			
		||||
            CONF_UNIT_OF_MEASUREMENT: "km",
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
    await hass.async_block_till_done()
 | 
			
		||||
 | 
			
		||||
    assert result["type"] is FlowResultType.CREATE_ENTRY
 | 
			
		||||
    assert result["version"] == 1
 | 
			
		||||
    assert result["options"] == {
 | 
			
		||||
        CONF_NAME: DEFAULT_NAME,
 | 
			
		||||
        CONF_ENTITY_ID: "sensor.test_monitored",
 | 
			
		||||
        CONF_DATAPOINTS: ["1.0, 2.0", "2.0, 3.0", "3.0, 4.0"],
 | 
			
		||||
        CONF_UPPER_LIMIT: False,
 | 
			
		||||
        CONF_LOWER_LIMIT: False,
 | 
			
		||||
        CONF_PRECISION: 2,
 | 
			
		||||
        CONF_DEGREE: 2,
 | 
			
		||||
        CONF_UNIT_OF_MEASUREMENT: "km",
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    assert len(mock_setup_entry.mock_calls) == 1
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def test_entry_already_exist(
 | 
			
		||||
    hass: HomeAssistant, loaded_entry: MockConfigEntry
 | 
			
		||||
) -> None:
 | 
			
		||||
    """Test abort when entry already exist."""
 | 
			
		||||
 | 
			
		||||
    result = await hass.config_entries.flow.async_init(
 | 
			
		||||
        DOMAIN, context={"source": config_entries.SOURCE_USER}
 | 
			
		||||
    )
 | 
			
		||||
    assert result["step_id"] == "user"
 | 
			
		||||
    assert result["type"] is FlowResultType.FORM
 | 
			
		||||
 | 
			
		||||
    result = await hass.config_entries.flow.async_configure(
 | 
			
		||||
        result["flow_id"],
 | 
			
		||||
        {
 | 
			
		||||
            CONF_NAME: DEFAULT_NAME,
 | 
			
		||||
            CONF_ENTITY_ID: "sensor.uncompensated",
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
    await hass.async_block_till_done()
 | 
			
		||||
 | 
			
		||||
    result = await hass.config_entries.flow.async_configure(
 | 
			
		||||
        result["flow_id"],
 | 
			
		||||
        {
 | 
			
		||||
            CONF_DATAPOINTS: [
 | 
			
		||||
                "1.0, 2.0",
 | 
			
		||||
                "2.0, 3.0",
 | 
			
		||||
            ],
 | 
			
		||||
            CONF_UPPER_LIMIT: False,
 | 
			
		||||
            CONF_LOWER_LIMIT: False,
 | 
			
		||||
            CONF_PRECISION: 2,
 | 
			
		||||
            CONF_DEGREE: 1,
 | 
			
		||||
            CONF_UNIT_OF_MEASUREMENT: "mm",
 | 
			
		||||
        },
 | 
			
		||||
    )
 | 
			
		||||
    await hass.async_block_till_done()
 | 
			
		||||
 | 
			
		||||
    assert result["type"] is FlowResultType.ABORT
 | 
			
		||||
    assert result["reason"] == "already_configured"
 | 
			
		||||
							
								
								
									
										44
									
								
								tests/components/compensation/test_init.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								tests/components/compensation/test_init.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
"""Test Statistics component setup process."""
 | 
			
		||||
 | 
			
		||||
from __future__ import annotations
 | 
			
		||||
 | 
			
		||||
from typing import Any
 | 
			
		||||
from unittest.mock import patch
 | 
			
		||||
 | 
			
		||||
from homeassistant.components.compensation.const import DOMAIN
 | 
			
		||||
from homeassistant.config_entries import SOURCE_USER, ConfigEntryState
 | 
			
		||||
from homeassistant.core import HomeAssistant
 | 
			
		||||
 | 
			
		||||
from tests.common import MockConfigEntry
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def test_unload_entry(hass: HomeAssistant, loaded_entry: MockConfigEntry) -> None:
 | 
			
		||||
    """Test unload an entry."""
 | 
			
		||||
 | 
			
		||||
    assert loaded_entry.state is ConfigEntryState.LOADED
 | 
			
		||||
    assert await hass.config_entries.async_unload(loaded_entry.entry_id)
 | 
			
		||||
    await hass.async_block_till_done()
 | 
			
		||||
    assert loaded_entry.state is ConfigEntryState.NOT_LOADED
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def test_could_not_setup(hass: HomeAssistant, get_config: dict[str, Any]) -> None:
 | 
			
		||||
    """Test exception."""
 | 
			
		||||
 | 
			
		||||
    config_entry = MockConfigEntry(
 | 
			
		||||
        domain=DOMAIN,
 | 
			
		||||
        title="Compensation sensor",
 | 
			
		||||
        source=SOURCE_USER,
 | 
			
		||||
        options=get_config,
 | 
			
		||||
        entry_id="1",
 | 
			
		||||
    )
 | 
			
		||||
    config_entry.add_to_hass(hass)
 | 
			
		||||
 | 
			
		||||
    with patch(
 | 
			
		||||
        "homeassistant.components.compensation.np.polyfit",
 | 
			
		||||
        side_effect=FloatingPointError,
 | 
			
		||||
    ):
 | 
			
		||||
        await hass.config_entries.async_setup(config_entry.entry_id)
 | 
			
		||||
        await hass.async_block_till_done()
 | 
			
		||||
 | 
			
		||||
    assert config_entry.state is ConfigEntryState.SETUP_ERROR
 | 
			
		||||
    assert config_entry.error_reason_translation_key == "setup_error"
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
"""The tests for the integration sensor platform."""
 | 
			
		||||
 | 
			
		||||
from typing import Any
 | 
			
		||||
 | 
			
		||||
import pytest
 | 
			
		||||
 | 
			
		||||
from homeassistant.components.compensation.const import CONF_PRECISION, DOMAIN
 | 
			
		||||
@@ -7,6 +9,8 @@ from homeassistant.components.compensation.sensor import ATTR_COEFFICIENTS
 | 
			
		||||
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
 | 
			
		||||
from homeassistant.const import (
 | 
			
		||||
    ATTR_UNIT_OF_MEASUREMENT,
 | 
			
		||||
    CONF_ENTITY_ID,
 | 
			
		||||
    CONF_PLATFORM,
 | 
			
		||||
    EVENT_HOMEASSISTANT_START,
 | 
			
		||||
    EVENT_STATE_CHANGED,
 | 
			
		||||
    STATE_UNKNOWN,
 | 
			
		||||
@@ -14,6 +18,24 @@ from homeassistant.const import (
 | 
			
		||||
from homeassistant.core import HomeAssistant
 | 
			
		||||
from homeassistant.setup import async_setup_component
 | 
			
		||||
 | 
			
		||||
from tests.common import MockConfigEntry
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def test_not_loading_from_platform_yaml(hass: HomeAssistant) -> None:
 | 
			
		||||
    """Test compensation sensor not loaded from platform YAML."""
 | 
			
		||||
    config = {
 | 
			
		||||
        "sensor": [
 | 
			
		||||
            {
 | 
			
		||||
                CONF_PLATFORM: DOMAIN,
 | 
			
		||||
            }
 | 
			
		||||
        ]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    assert await async_setup_component(hass, SENSOR_DOMAIN, config)
 | 
			
		||||
    await hass.async_block_till_done()
 | 
			
		||||
 | 
			
		||||
    assert len(hass.states.async_all()) == 0
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def test_linear_state(hass: HomeAssistant) -> None:
 | 
			
		||||
    """Test compensation sensor state."""
 | 
			
		||||
@@ -60,6 +82,34 @@ async def test_linear_state(hass: HomeAssistant) -> None:
 | 
			
		||||
    assert state.state == STATE_UNKNOWN
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def test_linear_state_from_config_entry(
 | 
			
		||||
    hass: HomeAssistant, loaded_entry: MockConfigEntry, get_config: dict[str, Any]
 | 
			
		||||
) -> None:
 | 
			
		||||
    """Test compensation sensor state loaded from config entry."""
 | 
			
		||||
    expected_entity_id = "sensor.compensation_sensor"
 | 
			
		||||
    entity_id = get_config[CONF_ENTITY_ID]
 | 
			
		||||
 | 
			
		||||
    hass.states.async_set(entity_id, 5, {})
 | 
			
		||||
    await hass.async_block_till_done()
 | 
			
		||||
 | 
			
		||||
    state = hass.states.get(expected_entity_id)
 | 
			
		||||
    assert state is not None
 | 
			
		||||
    assert round(float(state.state), get_config[CONF_PRECISION]) == 6.0
 | 
			
		||||
 | 
			
		||||
    assert state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) == "mm"
 | 
			
		||||
 | 
			
		||||
    coefs = [round(v, 1) for v in state.attributes.get(ATTR_COEFFICIENTS)]
 | 
			
		||||
    assert coefs == [1.0, 1.0]
 | 
			
		||||
 | 
			
		||||
    hass.states.async_set(entity_id, "foo", {})
 | 
			
		||||
    await hass.async_block_till_done()
 | 
			
		||||
 | 
			
		||||
    state = hass.states.get(expected_entity_id)
 | 
			
		||||
    assert state is not None
 | 
			
		||||
 | 
			
		||||
    assert state.state == STATE_UNKNOWN
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
async def test_linear_state_from_attribute(hass: HomeAssistant) -> None:
 | 
			
		||||
    """Test compensation sensor state that pulls from attribute."""
 | 
			
		||||
    config = {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user