Home Assistant Unofficial Reference 2024.12.1
__init__.py
Go to the documentation of this file.
1 """The Compensation integration."""
2 
3 import logging
4 from operator import itemgetter
5 
6 import numpy as np
7 import voluptuous as vol
8 
9 from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
10 from homeassistant.const import (
11  CONF_ATTRIBUTE,
12  CONF_MAXIMUM,
13  CONF_MINIMUM,
14  CONF_SOURCE,
15  CONF_UNIQUE_ID,
16  CONF_UNIT_OF_MEASUREMENT,
17 )
18 from homeassistant.core import HomeAssistant
19 from homeassistant.helpers import config_validation as cv
20 from homeassistant.helpers.discovery import async_load_platform
21 from homeassistant.helpers.typing import ConfigType
22 
23 from .const import (
24  CONF_COMPENSATION,
25  CONF_DATAPOINTS,
26  CONF_DEGREE,
27  CONF_LOWER_LIMIT,
28  CONF_POLYNOMIAL,
29  CONF_PRECISION,
30  CONF_UPPER_LIMIT,
31  DATA_COMPENSATION,
32  DEFAULT_DEGREE,
33  DEFAULT_PRECISION,
34  DOMAIN,
35 )
36 
37 _LOGGER = logging.getLogger(__name__)
38 
39 
40 def datapoints_greater_than_degree(value: dict) -> dict:
41  """Validate data point list is greater than polynomial degrees."""
42  if len(value[CONF_DATAPOINTS]) <= value[CONF_DEGREE]:
43  raise vol.Invalid(
44  f"{CONF_DATAPOINTS} must have at least"
45  f" {value[CONF_DEGREE]+1} {CONF_DATAPOINTS}"
46  )
47 
48  return value
49 
50 
51 COMPENSATION_SCHEMA = vol.Schema(
52  {
53  vol.Required(CONF_SOURCE): cv.entity_id,
54  vol.Required(CONF_DATAPOINTS): [
55  vol.ExactSequence([vol.Coerce(float), vol.Coerce(float)])
56  ],
57  vol.Optional(CONF_UNIQUE_ID): cv.string,
58  vol.Optional(CONF_ATTRIBUTE): cv.string,
59  vol.Optional(CONF_UPPER_LIMIT, default=False): cv.boolean,
60  vol.Optional(CONF_LOWER_LIMIT, default=False): cv.boolean,
61  vol.Optional(CONF_PRECISION, default=DEFAULT_PRECISION): cv.positive_int,
62  vol.Optional(CONF_DEGREE, default=DEFAULT_DEGREE): vol.All(
63  vol.Coerce(int),
64  vol.Range(min=1, max=7),
65  ),
66  vol.Optional(CONF_UNIT_OF_MEASUREMENT): cv.string,
67  }
68 )
69 
70 CONFIG_SCHEMA = vol.Schema(
71  {
72  DOMAIN: vol.Schema(
73  {cv.slug: vol.All(COMPENSATION_SCHEMA, datapoints_greater_than_degree)}
74  )
75  },
76  extra=vol.ALLOW_EXTRA,
77 )
78 
79 
80 async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
81  """Set up the Compensation sensor."""
82  hass.data[DATA_COMPENSATION] = {}
83 
84  for compensation, conf in config[DOMAIN].items():
85  _LOGGER.debug("Setup %s.%s", DOMAIN, compensation)
86 
87  degree = conf[CONF_DEGREE]
88 
89  initial_coefficients: list[tuple[float, float]] = conf[CONF_DATAPOINTS]
90  sorted_coefficients = sorted(initial_coefficients, key=itemgetter(0))
91 
92  # get x values and y values from the x,y point pairs
93  x_values, y_values = zip(*initial_coefficients, strict=False)
94 
95  # try to get valid coefficients for a polynomial
96  coefficients = None
97  with np.errstate(all="raise"):
98  try:
99  coefficients = np.polyfit(x_values, y_values, degree)
100  except FloatingPointError as error:
101  _LOGGER.error(
102  "Setup of %s encountered an error, %s",
103  compensation,
104  error,
105  )
106 
107  if coefficients is not None:
108  data = {
109  k: v for k, v in conf.items() if k not in [CONF_DEGREE, CONF_DATAPOINTS]
110  }
111  data[CONF_POLYNOMIAL] = np.poly1d(coefficients)
112 
113  if data[CONF_LOWER_LIMIT]:
114  data[CONF_MINIMUM] = sorted_coefficients[0]
115  else:
116  data[CONF_MINIMUM] = None
117 
118  if data[CONF_UPPER_LIMIT]:
119  data[CONF_MAXIMUM] = sorted_coefficients[-1]
120  else:
121  data[CONF_MAXIMUM] = None
122 
123  hass.data[DATA_COMPENSATION][compensation] = data
124 
125  hass.async_create_task(
127  hass,
128  SENSOR_DOMAIN,
129  DOMAIN,
130  {CONF_COMPENSATION: compensation},
131  config,
132  )
133  )
134 
135  return True
dict datapoints_greater_than_degree(dict value)
Definition: __init__.py:40
bool async_setup(HomeAssistant hass, ConfigType config)
Definition: __init__.py:80
None async_load_platform(core.HomeAssistant hass, Platform|str component, str platform, DiscoveryInfoType|None discovered, ConfigType hass_config)
Definition: discovery.py:152