1
0
mirror of https://github.com/home-assistant/core.git synced 2025-05-14 10:59:15 +00:00
silentguy256 379a8f2f86
Add state_class to OHM sensors ()
* Minimum change required to get OHW into statistics

Not sure if there is any reason not to have this, my only idea would be that there would be that there are A LOT of values, but as far as I can see there are already long term data being stored about them anyway

* Update sensor.py

Guess that was an old way of doing it -_-

* Update sensor.py

remove spaces the break ruff -_-

* Update sensor.py

ruff is rough
2024-09-10 16:10:36 +02:00

208 lines
6.2 KiB
Python

"""Support for Open Hardware Monitor Sensor Platform."""
from __future__ import annotations
from datetime import timedelta
import logging
import requests
import voluptuous as vol
from homeassistant.components.sensor import (
PLATFORM_SCHEMA as SENSOR_PLATFORM_SCHEMA,
SensorEntity,
SensorStateClass,
)
from homeassistant.const import CONF_HOST, CONF_PORT
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import PlatformNotReady
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.util import Throttle
from homeassistant.util.dt import utcnow
_LOGGER = logging.getLogger(__name__)
STATE_MIN_VALUE = "minimal_value"
STATE_MAX_VALUE = "maximum_value"
STATE_VALUE = "value"
STATE_OBJECT = "object"
CONF_INTERVAL = "interval"
MIN_TIME_BETWEEN_UPDATES = timedelta(seconds=15)
SCAN_INTERVAL = timedelta(seconds=30)
RETRY_INTERVAL = timedelta(seconds=30)
OHM_VALUE = "Value"
OHM_MIN = "Min"
OHM_MAX = "Max"
OHM_CHILDREN = "Children"
OHM_NAME = "Text"
PLATFORM_SCHEMA = SENSOR_PLATFORM_SCHEMA.extend(
{vol.Required(CONF_HOST): cv.string, vol.Optional(CONF_PORT, default=8085): cv.port}
)
def setup_platform(
hass: HomeAssistant,
config: ConfigType,
add_entities: AddEntitiesCallback,
discovery_info: DiscoveryInfoType | None = None,
) -> None:
"""Set up the Open Hardware Monitor platform."""
data = OpenHardwareMonitorData(config, hass)
if data.data is None:
raise PlatformNotReady
add_entities(data.devices, True)
class OpenHardwareMonitorDevice(SensorEntity):
"""Device used to display information from OpenHardwareMonitor."""
_attr_state_class = SensorStateClass.MEASUREMENT
def __init__(self, data, name, path, unit_of_measurement):
"""Initialize an OpenHardwareMonitor sensor."""
self._name = name
self._data = data
self.path = path
self.attributes = {}
self._unit_of_measurement = unit_of_measurement
self.value = None
@property
def name(self):
"""Return the name of the device."""
return self._name
@property
def native_unit_of_measurement(self):
"""Return the unit of measurement."""
return self._unit_of_measurement
@property
def native_value(self):
"""Return the state of the device."""
if self.value == "-":
return None
return self.value
@property
def extra_state_attributes(self):
"""Return the state attributes of the entity."""
return self.attributes
@classmethod
def parse_number(cls, string):
"""In some locales a decimal numbers uses ',' instead of '.'."""
return string.replace(",", ".")
def update(self) -> None:
"""Update the device from a new JSON object."""
self._data.update()
array = self._data.data[OHM_CHILDREN]
_attributes = {}
for path_index, path_number in enumerate(self.path):
values = array[path_number]
if path_index == len(self.path) - 1:
self.value = self.parse_number(values[OHM_VALUE].split(" ")[0])
_attributes.update(
{
"name": values[OHM_NAME],
STATE_MIN_VALUE: self.parse_number(
values[OHM_MIN].split(" ")[0]
),
STATE_MAX_VALUE: self.parse_number(
values[OHM_MAX].split(" ")[0]
),
}
)
self.attributes = _attributes
return
array = array[path_number][OHM_CHILDREN]
_attributes.update({f"level_{path_index}": values[OHM_NAME]})
class OpenHardwareMonitorData:
"""Class used to pull data from OHM and create sensors."""
def __init__(self, config, hass):
"""Initialize the Open Hardware Monitor data-handler."""
self.data = None
self._config = config
self._hass = hass
self.devices = []
self.initialize(utcnow())
@Throttle(MIN_TIME_BETWEEN_UPDATES)
def update(self):
"""Hit by the timer with the configured interval."""
if self.data is None:
self.initialize(utcnow())
else:
self.refresh()
def refresh(self):
"""Download and parse JSON from OHM."""
data_url = (
f"http://{self._config.get(CONF_HOST)}:"
f"{self._config.get(CONF_PORT)}/data.json"
)
try:
response = requests.get(data_url, timeout=30)
self.data = response.json()
except requests.exceptions.ConnectionError:
_LOGGER.debug("ConnectionError: Is OpenHardwareMonitor running?")
def initialize(self, now):
"""Parse of the sensors and adding of devices."""
self.refresh()
if self.data is None:
return
self.devices = self.parse_children(self.data, [], [], [])
def parse_children(self, json, devices, path, names):
"""Recursively loop through child objects, finding the values."""
result = devices.copy()
if json[OHM_CHILDREN]:
for child_index in range(len(json[OHM_CHILDREN])):
child_path = path.copy()
child_path.append(child_index)
child_names = names.copy()
if path:
child_names.append(json[OHM_NAME])
obj = json[OHM_CHILDREN][child_index]
added_devices = self.parse_children(
obj, devices, child_path, child_names
)
result = result + added_devices
return result
if json[OHM_VALUE].find(" ") == -1:
return result
unit_of_measurement = json[OHM_VALUE].split(" ")[1]
child_names = names.copy()
child_names.append(json[OHM_NAME])
fullname = " ".join(child_names)
dev = OpenHardwareMonitorDevice(self, fullname, path, unit_of_measurement)
result.append(dev)
return result