Skip to content
Closed
32 changes: 18 additions & 14 deletions homeassistant/components/onewire/onewire_entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

from dataclasses import dataclass
import logging
from typing import Any

from pyownet import protocol

Expand All @@ -17,6 +16,7 @@
class OneWireEntityDescription(EntityDescription):
"""Class describing OneWire entities."""

decimal_places: int | None = None
read_mode: str | None = None


Expand All @@ -40,18 +40,10 @@ def __init__(
self.entity_description = description
self._attr_unique_id = f"/{device_id}/{description.key}"
self._attr_device_info = device_info
self._attr_extra_state_attributes = {"device_file": device_file}
self._attr_name = name
self._device_file = device_file
self._state: StateType = None
self._value_raw: float | None = None

@property
def extra_state_attributes(self) -> dict[str, Any] | None:
"""Return the state attributes of the entity."""
return {
"device_file": self._device_file,
"raw_value": self._value_raw,
}


class OneWireProxyEntity(OneWireBaseEntity):
Expand All @@ -65,6 +57,7 @@ def __init__(
device_file: str,
name: str,
owproxy: protocol._Proxy,
is_raw_clone: bool = False,
) -> None:
"""Initialize the sensor."""
super().__init__(
Expand All @@ -75,6 +68,12 @@ def __init__(
name=name,
)
self._owproxy = owproxy
self._is_raw_clone = is_raw_clone

if is_raw_clone:
self._attr_entity_registry_enabled_default = False
self._attr_name = f"{self._attr_name} (raw value)"
self._attr_unique_id = f"{self._attr_unique_id}_raw_value"

def _read_value_ownet(self) -> str:
"""Read a value from the owserver."""
Expand All @@ -88,14 +87,19 @@ def _write_value_ownet(self, value: bytes) -> None:
def update(self) -> None:
"""Get the latest data from the device."""
try:
self._value_raw = float(self._read_value_ownet())
raw_value = float(self._read_value_ownet())
except protocol.Error as exc:
_LOGGER.error("Owserver failure in read(), got: %s", exc)
self._state = None
else:
if self.entity_description.read_mode == READ_MODE_INT:
self._state = int(self._value_raw)
self._state = int(raw_value)
elif self.entity_description.read_mode == READ_MODE_BOOL:
self._state = int(self._value_raw) == 1
self._state = int(raw_value) == 1
else:
self._state = round(self._value_raw, 1)
if (
self.entity_description.decimal_places is not None
and not self._is_raw_clone
):
raw_value = round(raw_value, self.entity_description.decimal_places)
self._state = raw_value
74 changes: 71 additions & 3 deletions homeassistant/components/onewire/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,13 @@
class OneWireSensorEntityDescription(OneWireEntityDescription, SensorEntityDescription):
"""Class describing OneWire sensor entities."""

create_raw_value_clone: bool = False


SIMPLE_TEMPERATURE_SENSOR_DESCRIPTION = OneWireSensorEntityDescription(
key="temperature",
create_raw_value_clone=True,
decimal_places=1,
device_class=SensorDeviceClass.TEMPERATURE,
name="Temperature",
native_unit_of_measurement=TEMP_CELSIUS,
Expand All @@ -74,6 +78,8 @@ class OneWireSensorEntityDescription(OneWireEntityDescription, SensorEntityDescr
"12": (
OneWireSensorEntityDescription(
key="TAI8570/temperature",
create_raw_value_clone=True,
decimal_places=1,
device_class=SensorDeviceClass.TEMPERATURE,
entity_registry_enabled_default=False,
name="Temperature",
Expand All @@ -83,6 +89,8 @@ class OneWireSensorEntityDescription(OneWireEntityDescription, SensorEntityDescr
),
OneWireSensorEntityDescription(
key="TAI8570/pressure",
create_raw_value_clone=True,
decimal_places=1,
device_class=SensorDeviceClass.PRESSURE,
entity_registry_enabled_default=False,
name="Pressure",
Expand All @@ -96,6 +104,8 @@ class OneWireSensorEntityDescription(OneWireEntityDescription, SensorEntityDescr
SIMPLE_TEMPERATURE_SENSOR_DESCRIPTION,
OneWireSensorEntityDescription(
key="humidity",
decimal_places=1,
create_raw_value_clone=True,
device_class=SensorDeviceClass.HUMIDITY,
entity_registry_enabled_default=False,
name="Humidity",
Expand All @@ -105,6 +115,8 @@ class OneWireSensorEntityDescription(OneWireEntityDescription, SensorEntityDescr
),
OneWireSensorEntityDescription(
key="HIH3600/humidity",
create_raw_value_clone=True,
decimal_places=1,
device_class=SensorDeviceClass.HUMIDITY,
entity_registry_enabled_default=False,
name="Humidity HIH3600",
Expand All @@ -114,6 +126,8 @@ class OneWireSensorEntityDescription(OneWireEntityDescription, SensorEntityDescr
),
OneWireSensorEntityDescription(
key="HIH4000/humidity",
create_raw_value_clone=True,
decimal_places=1,
device_class=SensorDeviceClass.HUMIDITY,
entity_registry_enabled_default=False,
name="Humidity HIH4000",
Expand All @@ -123,6 +137,8 @@ class OneWireSensorEntityDescription(OneWireEntityDescription, SensorEntityDescr
),
OneWireSensorEntityDescription(
key="HIH5030/humidity",
create_raw_value_clone=True,
decimal_places=1,
device_class=SensorDeviceClass.HUMIDITY,
entity_registry_enabled_default=False,
name="Humidity HIH5030",
Expand All @@ -132,6 +148,8 @@ class OneWireSensorEntityDescription(OneWireEntityDescription, SensorEntityDescr
),
OneWireSensorEntityDescription(
key="HTM1735/humidity",
create_raw_value_clone=True,
decimal_places=1,
device_class=SensorDeviceClass.HUMIDITY,
entity_registry_enabled_default=False,
name="Humidity HTM1735",
Expand All @@ -141,6 +159,8 @@ class OneWireSensorEntityDescription(OneWireEntityDescription, SensorEntityDescr
),
OneWireSensorEntityDescription(
key="B1-R1-A/pressure",
create_raw_value_clone=True,
decimal_places=1,
device_class=SensorDeviceClass.PRESSURE,
entity_registry_enabled_default=False,
name="Pressure",
Expand All @@ -150,6 +170,8 @@ class OneWireSensorEntityDescription(OneWireEntityDescription, SensorEntityDescr
),
OneWireSensorEntityDescription(
key="S3-R1-A/illuminance",
create_raw_value_clone=True,
decimal_places=1,
device_class=SensorDeviceClass.ILLUMINANCE,
entity_registry_enabled_default=False,
name="Illuminance",
Expand Down Expand Up @@ -214,6 +236,8 @@ class OneWireSensorEntityDescription(OneWireEntityDescription, SensorEntityDescr
"HobbyBoards_EF": (
OneWireSensorEntityDescription(
key="humidity/humidity_corrected",
create_raw_value_clone=True,
decimal_places=1,
device_class=SensorDeviceClass.HUMIDITY,
name="Humidity",
native_unit_of_measurement=PERCENTAGE,
Expand All @@ -222,6 +246,8 @@ class OneWireSensorEntityDescription(OneWireEntityDescription, SensorEntityDescr
),
OneWireSensorEntityDescription(
key="humidity/humidity_raw",
create_raw_value_clone=True,
decimal_places=1,
device_class=SensorDeviceClass.HUMIDITY,
name="Humidity Raw",
native_unit_of_measurement=PERCENTAGE,
Expand All @@ -230,6 +256,8 @@ class OneWireSensorEntityDescription(OneWireEntityDescription, SensorEntityDescr
),
OneWireSensorEntityDescription(
key="humidity/temperature",
create_raw_value_clone=True,
decimal_places=1,
device_class=SensorDeviceClass.TEMPERATURE,
name="Temperature",
native_unit_of_measurement=TEMP_CELSIUS,
Expand Down Expand Up @@ -279,6 +307,8 @@ class OneWireSensorEntityDescription(OneWireEntityDescription, SensorEntityDescr
"EDS0066": (
OneWireSensorEntityDescription(
key="EDS0066/temperature",
create_raw_value_clone=True,
decimal_places=1,
device_class=SensorDeviceClass.TEMPERATURE,
name="Temperature",
native_unit_of_measurement=TEMP_CELSIUS,
Expand All @@ -287,6 +317,8 @@ class OneWireSensorEntityDescription(OneWireEntityDescription, SensorEntityDescr
),
OneWireSensorEntityDescription(
key="EDS0066/pressure",
create_raw_value_clone=True,
decimal_places=1,
device_class=SensorDeviceClass.PRESSURE,
name="Pressure",
native_unit_of_measurement=PRESSURE_MBAR,
Expand All @@ -297,6 +329,8 @@ class OneWireSensorEntityDescription(OneWireEntityDescription, SensorEntityDescr
"EDS0068": (
OneWireSensorEntityDescription(
key="EDS0068/temperature",
create_raw_value_clone=True,
decimal_places=1,
device_class=SensorDeviceClass.TEMPERATURE,
name="Temperature",
native_unit_of_measurement=TEMP_CELSIUS,
Expand All @@ -305,6 +339,8 @@ class OneWireSensorEntityDescription(OneWireEntityDescription, SensorEntityDescr
),
OneWireSensorEntityDescription(
key="EDS0068/pressure",
create_raw_value_clone=True,
decimal_places=1,
device_class=SensorDeviceClass.PRESSURE,
name="Pressure",
native_unit_of_measurement=PRESSURE_MBAR,
Expand All @@ -313,6 +349,8 @@ class OneWireSensorEntityDescription(OneWireEntityDescription, SensorEntityDescr
),
OneWireSensorEntityDescription(
key="EDS0068/light",
create_raw_value_clone=True,
decimal_places=1,
device_class=SensorDeviceClass.ILLUMINANCE,
name="Illuminance",
native_unit_of_measurement=LIGHT_LUX,
Expand All @@ -321,6 +359,8 @@ class OneWireSensorEntityDescription(OneWireEntityDescription, SensorEntityDescr
),
OneWireSensorEntityDescription(
key="EDS0068/humidity",
create_raw_value_clone=True,
decimal_places=1,
device_class=SensorDeviceClass.HUMIDITY,
name="Humidity",
native_unit_of_measurement=PERCENTAGE,
Expand Down Expand Up @@ -414,8 +454,21 @@ def get_entities(
device_info=device_info,
name=name,
owproxy=onewirehub.owproxy,
is_raw_clone=False,
)
)
if description.create_raw_value_clone:
entities.append(
OneWireProxySensor(
description=description,
device_id=device_id,
device_file=device_file,
device_info=device_info,
name=name,
owproxy=onewirehub.owproxy,
is_raw_clone=True,
)
)

# We have a raw GPIO ow sensor on a Pi
elif conf_type == CONF_TYPE_SYSBUS:
Expand All @@ -429,15 +482,17 @@ def get_entities(
description = SIMPLE_TEMPERATURE_SENSOR_DESCRIPTION
device_file = f"/sys/bus/w1/devices/{device_id}/w1_slave"
name = f"{device_names.get(device_id, device_id)} {description.name}"
entities.append(
entities.extend(
OneWireDirectSensor(
description=description,
device_id=device_id,
device_file=device_file,
device_info=device_info,
name=name,
owsensor=p1sensor,
is_raw_clone=is_raw_clone,
)
for is_raw_clone in (False, True)
)

return entities
Expand Down Expand Up @@ -471,6 +526,7 @@ def __init__(
device_file: str,
name: str,
owsensor: OneWireInterface,
is_raw_clone: bool,
) -> None:
"""Initialize the sensor."""
super().__init__(
Expand All @@ -481,6 +537,11 @@ def __init__(
name=name,
)
self._attr_unique_id = device_file
self._is_raw_clone = is_raw_clone
if is_raw_clone:
self._attr_entity_registry_enabled_default = False
self._attr_name = f"{self._attr_name} (raw value)"
self._attr_unique_id = f"{self._attr_unique_id}_raw_value"
self._owsensor = owsensor

@property
Expand Down Expand Up @@ -511,8 +572,7 @@ async def get_temperature(self) -> float:
async def async_update(self) -> None:
"""Get the latest data from the device."""
try:
self._value_raw = await self.get_temperature()
self._state = round(self._value_raw, 1)
raw_value = await self.get_temperature()
except (
FileNotFoundError,
InvalidCRCException,
Expand All @@ -524,3 +584,11 @@ async def async_update(self) -> None:
ex,
)
self._state = None
else:
if (
self.entity_description.decimal_places is not None
and not self._is_raw_clone
):
raw_value = round(raw_value, self.entity_description.decimal_places)

self._state = raw_value
7 changes: 7 additions & 0 deletions tests/components/onewire/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
ATTR_DEVICE_FILE,
ATTR_ENTITY_CATEGORY,
ATTR_INJECT_READS,
ATTR_STATE_CLONE,
ATTR_UNIQUE_ID,
FIXED_ATTRIBUTES,
MOCK_OWPROXY_DEVICES,
Expand Down Expand Up @@ -181,6 +182,8 @@ def _setup_owproxy_mock_device_reads(
device_sensors = mock_device.get(platform, [])
for expected_sensor in device_sensors:
sub_read_side_effect.append(expected_sensor[ATTR_INJECT_READS])
if ATTR_STATE_CLONE in expected_sensor:
sub_read_side_effect.append(expected_sensor[ATTR_INJECT_READS])


def setup_sysbus_mock_devices(
Expand All @@ -201,8 +204,12 @@ def setup_sysbus_mock_devices(
for expected_sensor in device_sensors:
if isinstance(expected_sensor[ATTR_INJECT_READS], list):
read_side_effect += expected_sensor[ATTR_INJECT_READS]
if ATTR_STATE_CLONE in expected_sensor:
read_side_effect += expected_sensor[ATTR_INJECT_READS]
else:
read_side_effect.append(expected_sensor[ATTR_INJECT_READS])
if ATTR_STATE_CLONE in expected_sensor:
read_side_effect.append(expected_sensor[ATTR_INJECT_READS])

# Ensure enough read side effect
read_side_effect.extend([FileNotFoundError("Missing injected value")] * 20)
Expand Down
Loading