Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Adds a simulated sensor."""
2 
3 from __future__ import annotations
4 
5 from datetime import datetime
6 import math
7 from random import Random
8 
9 import voluptuous as vol
10 
12  PLATFORM_SCHEMA as SENSOR_PLATFORM_SCHEMA,
13  SensorEntity,
14 )
15 from homeassistant.const import CONF_NAME
16 from homeassistant.core import HomeAssistant
17 from homeassistant.helpers import issue_registry as ir
19 from homeassistant.helpers.entity_platform import AddEntitiesCallback
20 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
21 import homeassistant.util.dt as dt_util
22 
23 CONF_AMP = "amplitude"
24 CONF_FWHM = "spread"
25 CONF_MEAN = "mean"
26 CONF_PERIOD = "period"
27 CONF_PHASE = "phase"
28 CONF_SEED = "seed"
29 CONF_UNIT = "unit"
30 CONF_RELATIVE_TO_EPOCH = "relative_to_epoch"
31 
32 DEFAULT_AMP = 1
33 DEFAULT_FWHM = 0
34 DEFAULT_MEAN = 0
35 DEFAULT_NAME = "simulated"
36 DEFAULT_PERIOD = 60
37 DEFAULT_PHASE = 0
38 DEFAULT_SEED = 999
39 DEFAULT_UNIT = "value"
40 DEFAULT_RELATIVE_TO_EPOCH = True
41 
42 DOMAIN = "simulated"
43 
44 PLATFORM_SCHEMA = SENSOR_PLATFORM_SCHEMA.extend(
45  {
46  vol.Optional(CONF_AMP, default=DEFAULT_AMP): vol.Coerce(float),
47  vol.Optional(CONF_FWHM, default=DEFAULT_FWHM): vol.Coerce(float),
48  vol.Optional(CONF_MEAN, default=DEFAULT_MEAN): vol.Coerce(float),
49  vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
50  vol.Optional(CONF_PERIOD, default=DEFAULT_PERIOD): cv.positive_int,
51  vol.Optional(CONF_PHASE, default=DEFAULT_PHASE): vol.Coerce(float),
52  vol.Optional(CONF_SEED, default=DEFAULT_SEED): cv.positive_int,
53  vol.Optional(CONF_UNIT, default=DEFAULT_UNIT): cv.string,
54  vol.Optional(
55  CONF_RELATIVE_TO_EPOCH, default=DEFAULT_RELATIVE_TO_EPOCH
56  ): cv.boolean,
57  }
58 )
59 
60 
62  hass: HomeAssistant,
63  config: ConfigType,
64  async_add_entities: AddEntitiesCallback,
65  discovery_info: DiscoveryInfoType | None = None,
66 ) -> None:
67  """Set up the simulated sensor."""
68  # Simulated has been deprecated and will be removed in 2025.1
69 
70  ir.async_create_issue(
71  hass,
72  DOMAIN,
73  DOMAIN,
74  breaks_in_ha_version="2025.1.0",
75  is_fixable=False,
76  severity=ir.IssueSeverity.WARNING,
77  translation_key="simulated_deprecation",
78  translation_placeholders={"integration": DOMAIN},
79  learn_more_url="https://www.home-assistant.io/integrations/simulated",
80  )
81 
82  name = config.get(CONF_NAME)
83  unit = config.get(CONF_UNIT)
84  amp = config.get(CONF_AMP)
85  mean = config.get(CONF_MEAN)
86  period = config.get(CONF_PERIOD)
87  phase = config.get(CONF_PHASE)
88  fwhm = config.get(CONF_FWHM)
89  seed = config.get(CONF_SEED)
90  relative_to_epoch = config.get(CONF_RELATIVE_TO_EPOCH)
91 
92  sensor = SimulatedSensor(
93  name, unit, amp, mean, period, phase, fwhm, seed, relative_to_epoch
94  )
95  async_add_entities([sensor], True)
96 
97 
99  """Class for simulated sensor."""
100 
101  _attr_icon = "mdi:chart-line"
102 
103  def __init__(
104  self, name, unit, amp, mean, period, phase, fwhm, seed, relative_to_epoch
105  ):
106  """Init the class."""
107  self._name_name = name
108  self._unit_unit = unit
109  self._amp_amp = amp
110  self._mean_mean = mean
111  self._period_period = period
112  self._phase_phase = phase # phase in degrees
113  self._fwhm_fwhm = fwhm
114  self._seed_seed = seed
115  self._random_random = Random(seed) # A local seeded Random
116  self._start_time_start_time = (
117  datetime(1970, 1, 1, tzinfo=dt_util.UTC)
118  if relative_to_epoch
119  else dt_util.utcnow()
120  )
121  self._relative_to_epoch_relative_to_epoch = relative_to_epoch
122  self._state_state = None
123 
124  def time_delta(self):
125  """Return the time delta."""
126  dt0 = self._start_time_start_time
127  dt1 = dt_util.utcnow()
128  return dt1 - dt0
129 
130  def signal_calc(self):
131  """Calculate the signal."""
132  mean = self._mean_mean
133  amp = self._amp_amp
134  time_delta = self.time_deltatime_delta().total_seconds() * 1e6 # to milliseconds
135  period = self._period_period * 1e6 # to milliseconds
136  fwhm = self._fwhm_fwhm / 2
137  phase = math.radians(self._phase_phase)
138  if period == 0:
139  periodic = 0
140  else:
141  periodic = amp * (math.sin((2 * math.pi * time_delta / period) + phase))
142  noise = self._random_random.gauss(mu=0, sigma=fwhm)
143  return round(mean + periodic + noise, 3)
144 
145  async def async_update(self) -> None:
146  """Update the sensor."""
147  self._state_state = self.signal_calcsignal_calc()
148 
149  @property
150  def name(self):
151  """Return the name of the sensor."""
152  return self._name_name
153 
154  @property
155  def native_value(self):
156  """Return the state of the sensor."""
157  return self._state_state
158 
159  @property
161  """Return the unit this state is expressed in."""
162  return self._unit_unit
163 
164  @property
166  """Return other details about the sensor state."""
167  return {
168  "amplitude": self._amp_amp,
169  "mean": self._mean_mean,
170  "period": self._period_period,
171  "phase": self._phase_phase,
172  "spread": self._fwhm_fwhm,
173  "seed": self._seed_seed,
174  "relative_to_epoch": self._relative_to_epoch_relative_to_epoch,
175  }
def __init__(self, name, unit, amp, mean, period, phase, fwhm, seed, relative_to_epoch)
Definition: sensor.py:105
None async_setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback async_add_entities, DiscoveryInfoType|None discovery_info=None)
Definition: sensor.py:66