Home Assistant Unofficial Reference 2024.12.1
sensor.py
Go to the documentation of this file.
1 """Support for Open Hardware Monitor Sensor Platform."""
2 
3 from __future__ import annotations
4 
5 from datetime import timedelta
6 import logging
7 
8 import requests
9 import voluptuous as vol
10 
12  PLATFORM_SCHEMA as SENSOR_PLATFORM_SCHEMA,
13  SensorEntity,
14  SensorStateClass,
15 )
16 from homeassistant.const import CONF_HOST, CONF_PORT
17 from homeassistant.core import HomeAssistant
18 from homeassistant.exceptions import PlatformNotReady
20 from homeassistant.helpers.entity_platform import AddEntitiesCallback
21 from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
22 from homeassistant.util import Throttle
23 from homeassistant.util.dt import utcnow
24 
25 _LOGGER = logging.getLogger(__name__)
26 
27 STATE_MIN_VALUE = "minimal_value"
28 STATE_MAX_VALUE = "maximum_value"
29 STATE_VALUE = "value"
30 STATE_OBJECT = "object"
31 CONF_INTERVAL = "interval"
32 
33 MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=15)
34 SCAN_INTERVAL = timedelta(seconds=30)
35 RETRY_INTERVAL = timedelta(seconds=30)
36 
37 OHM_VALUE = "Value"
38 OHM_MIN = "Min"
39 OHM_MAX = "Max"
40 OHM_CHILDREN = "Children"
41 OHM_NAME = "Text"
42 
43 PLATFORM_SCHEMA = SENSOR_PLATFORM_SCHEMA.extend(
44  {vol.Required(CONF_HOST): cv.string, vol.Optional(CONF_PORT, default=8085): cv.port}
45 )
46 
47 
49  hass: HomeAssistant,
50  config: ConfigType,
51  add_entities: AddEntitiesCallback,
52  discovery_info: DiscoveryInfoType | None = None,
53 ) -> None:
54  """Set up the Open Hardware Monitor platform."""
55  data = OpenHardwareMonitorData(config, hass)
56  if data.data is None:
57  raise PlatformNotReady
58  add_entities(data.devices, True)
59 
60 
62  """Device used to display information from OpenHardwareMonitor."""
63 
64  _attr_state_class = SensorStateClass.MEASUREMENT
65 
66  def __init__(self, data, name, path, unit_of_measurement):
67  """Initialize an OpenHardwareMonitor sensor."""
68  self._name_name = name
69  self._data_data = data
70  self.pathpath = path
71  self.attributesattributes = {}
72  self._unit_of_measurement_unit_of_measurement = unit_of_measurement
73 
74  self.valuevalue = None
75 
76  @property
77  def name(self):
78  """Return the name of the device."""
79  return self._name_name
80 
81  @property
83  """Return the unit of measurement."""
84  return self._unit_of_measurement_unit_of_measurement
85 
86  @property
87  def native_value(self):
88  """Return the state of the device."""
89  if self.valuevalue == "-":
90  return None
91  return self.valuevalue
92 
93  @property
95  """Return the state attributes of the entity."""
96  return self.attributesattributes
97 
98  @classmethod
99  def parse_number(cls, string):
100  """In some locales a decimal numbers uses ',' instead of '.'."""
101  return string.replace(",", ".")
102 
103  def update(self) -> None:
104  """Update the device from a new JSON object."""
105  self._data_data.update()
106 
107  array = self._data_data.data[OHM_CHILDREN]
108  _attributes = {}
109 
110  for path_index, path_number in enumerate(self.pathpath):
111  values = array[path_number]
112 
113  if path_index == len(self.pathpath) - 1:
114  self.valuevalue = self.parse_numberparse_number(values[OHM_VALUE].split(" ")[0])
115  _attributes.update(
116  {
117  "name": values[OHM_NAME],
118  STATE_MIN_VALUE: self.parse_numberparse_number(
119  values[OHM_MIN].split(" ")[0]
120  ),
121  STATE_MAX_VALUE: self.parse_numberparse_number(
122  values[OHM_MAX].split(" ")[0]
123  ),
124  }
125  )
126 
127  self.attributesattributes = _attributes
128  return
129  array = array[path_number][OHM_CHILDREN]
130  _attributes.update({f"level_{path_index}": values[OHM_NAME]})
131 
132 
134  """Class used to pull data from OHM and create sensors."""
135 
136  def __init__(self, config, hass):
137  """Initialize the Open Hardware Monitor data-handler."""
138  self.datadata = None
139  self._config_config = config
140  self._hass_hass = hass
141  self.devicesdevices = []
142  self.initializeinitialize(utcnow())
143 
144  @Throttle(MIN_TIME_BETWEEN_UPDATES)
145  def update(self):
146  """Hit by the timer with the configured interval."""
147  if self.datadata is None:
148  self.initializeinitialize(utcnow())
149  else:
150  self.refreshrefresh()
151 
152  def refresh(self):
153  """Download and parse JSON from OHM."""
154  data_url = (
155  f"http://{self._config.get(CONF_HOST)}:"
156  f"{self._config.get(CONF_PORT)}/data.json"
157  )
158 
159  try:
160  response = requests.get(data_url, timeout=30)
161  self.datadata = response.json()
162  except requests.exceptions.ConnectionError:
163  _LOGGER.debug("ConnectionError: Is OpenHardwareMonitor running?")
164 
165  def initialize(self, now):
166  """Parse of the sensors and adding of devices."""
167  self.refreshrefresh()
168 
169  if self.datadata is None:
170  return
171 
172  self.devicesdevices = self.parse_childrenparse_children(self.datadata, [], [], [])
173 
174  def parse_children(self, json, devices, path, names):
175  """Recursively loop through child objects, finding the values."""
176  result = devices.copy()
177 
178  if json[OHM_CHILDREN]:
179  for child_index in range(len(json[OHM_CHILDREN])):
180  child_path = path.copy()
181  child_path.append(child_index)
182 
183  child_names = names.copy()
184  if path:
185  child_names.append(json[OHM_NAME])
186 
187  obj = json[OHM_CHILDREN][child_index]
188 
189  added_devices = self.parse_childrenparse_children(
190  obj, devices, child_path, child_names
191  )
192 
193  result = result + added_devices
194  return result
195 
196  if json[OHM_VALUE].find(" ") == -1:
197  return result
198 
199  unit_of_measurement = json[OHM_VALUE].split(" ")[1]
200  child_names = names.copy()
201  child_names.append(json[OHM_NAME])
202  fullname = " ".join(child_names)
203 
204  dev = OpenHardwareMonitorDevice(self, fullname, path, unit_of_measurement)
205 
206  result.append(dev)
207  return result
def __init__(self, data, name, path, unit_of_measurement)
Definition: sensor.py:66
def add_entities(account, async_add_entities, tracked)
Definition: sensor.py:40
None setup_platform(HomeAssistant hass, ConfigType config, AddEntitiesCallback add_entities, DiscoveryInfoType|None discovery_info=None)
Definition: sensor.py:53