diff --git a/homeassistant/components/onewire/onewire_entities.py b/homeassistant/components/onewire/onewire_entities.py index e00733ae3875a8..da24b27d5e6c09 100644 --- a/homeassistant/components/onewire/onewire_entities.py +++ b/homeassistant/components/onewire/onewire_entities.py @@ -3,7 +3,6 @@ from dataclasses import dataclass import logging -from typing import Any from pyownet import protocol @@ -17,6 +16,7 @@ class OneWireEntityDescription(EntityDescription): """Class describing OneWire entities.""" + decimal_places: int | None = None read_mode: str | None = None @@ -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): @@ -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__( @@ -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.""" @@ -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 diff --git a/homeassistant/components/onewire/sensor.py b/homeassistant/components/onewire/sensor.py index cbc616872baf04..2662ef10f6c2fe 100644 --- a/homeassistant/components/onewire/sensor.py +++ b/homeassistant/components/onewire/sensor.py @@ -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, @@ -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", @@ -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", @@ -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", @@ -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", @@ -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", @@ -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", @@ -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", @@ -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", @@ -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", @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -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, @@ -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: @@ -429,7 +482,7 @@ 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, @@ -437,7 +490,9 @@ def get_entities( device_info=device_info, name=name, owsensor=p1sensor, + is_raw_clone=is_raw_clone, ) + for is_raw_clone in (False, True) ) return entities @@ -471,6 +526,7 @@ def __init__( device_file: str, name: str, owsensor: OneWireInterface, + is_raw_clone: bool, ) -> None: """Initialize the sensor.""" super().__init__( @@ -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 @@ -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, @@ -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 diff --git a/tests/components/onewire/__init__.py b/tests/components/onewire/__init__.py index 3ae6dbab050569..1ff72a44a92825 100644 --- a/tests/components/onewire/__init__.py +++ b/tests/components/onewire/__init__.py @@ -26,6 +26,7 @@ ATTR_DEVICE_FILE, ATTR_ENTITY_CATEGORY, ATTR_INJECT_READS, + ATTR_STATE_CLONE, ATTR_UNIQUE_ID, FIXED_ATTRIBUTES, MOCK_OWPROXY_DEVICES, @@ -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( @@ -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) diff --git a/tests/components/onewire/const.py b/tests/components/onewire/const.py index 3eb0ef51742d63..442b83b7d2d9e4 100644 --- a/tests/components/onewire/const.py +++ b/tests/components/onewire/const.py @@ -42,6 +42,7 @@ ATTR_DEVICE_INFO = "device_info" ATTR_ENTITY_CATEGORY = "entity_category" ATTR_INJECT_READS = "inject_reads" +ATTR_STATE_CLONE = "raw_value_clone" ATTR_UNIQUE_ID = "unique_id" ATTR_UNKNOWN_DEVICE = "unknown_device" @@ -96,6 +97,7 @@ ATTR_INJECT_READS: b" 25.123", ATTR_STATE: "25.1", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "25.123", ATTR_UNIQUE_ID: "/10.111111111111/temperature", ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, }, @@ -135,6 +137,7 @@ ATTR_INJECT_READS: b" 25.123", ATTR_STATE: "25.1", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "25.123", ATTR_UNIQUE_ID: "/12.111111111111/TAI8570/temperature", ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, }, @@ -145,6 +148,7 @@ ATTR_INJECT_READS: b" 1025.123", ATTR_STATE: "1025.1", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "1025.123", ATTR_UNIQUE_ID: "/12.111111111111/TAI8570/pressure", ATTR_UNIT_OF_MEASUREMENT: PRESSURE_MBAR, }, @@ -276,6 +280,7 @@ ATTR_INJECT_READS: ProtocolError, ATTR_STATE: STATE_UNKNOWN, ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: STATE_UNKNOWN, ATTR_UNIQUE_ID: "/22.111111111111/temperature", ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, }, @@ -298,6 +303,7 @@ ATTR_INJECT_READS: b" 25.123", ATTR_STATE: "25.1", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "25.123", ATTR_UNIQUE_ID: "/26.111111111111/temperature", ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, }, @@ -308,6 +314,7 @@ ATTR_INJECT_READS: b" 72.7563", ATTR_STATE: "72.8", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "72.7563", ATTR_UNIQUE_ID: "/26.111111111111/humidity", ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, }, @@ -318,6 +325,7 @@ ATTR_INJECT_READS: b" 73.7563", ATTR_STATE: "73.8", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "73.7563", ATTR_UNIQUE_ID: "/26.111111111111/HIH3600/humidity", ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, }, @@ -328,6 +336,7 @@ ATTR_INJECT_READS: b" 74.7563", ATTR_STATE: "74.8", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "74.7563", ATTR_UNIQUE_ID: "/26.111111111111/HIH4000/humidity", ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, }, @@ -338,6 +347,7 @@ ATTR_INJECT_READS: b" 75.7563", ATTR_STATE: "75.8", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "75.7563", ATTR_UNIQUE_ID: "/26.111111111111/HIH5030/humidity", ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, }, @@ -348,6 +358,7 @@ ATTR_INJECT_READS: ProtocolError, ATTR_STATE: STATE_UNKNOWN, ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: STATE_UNKNOWN, ATTR_UNIQUE_ID: "/26.111111111111/HTM1735/humidity", ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, }, @@ -358,6 +369,7 @@ ATTR_INJECT_READS: b" 969.265", ATTR_STATE: "969.3", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "969.265", ATTR_UNIQUE_ID: "/26.111111111111/B1-R1-A/pressure", ATTR_UNIT_OF_MEASUREMENT: PRESSURE_MBAR, }, @@ -368,6 +380,7 @@ ATTR_INJECT_READS: b" 65.8839", ATTR_STATE: "65.9", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "65.8839", ATTR_UNIQUE_ID: "/26.111111111111/S3-R1-A/illuminance", ATTR_UNIT_OF_MEASUREMENT: LIGHT_LUX, }, @@ -376,7 +389,7 @@ ATTR_DEVICE_CLASS: SensorDeviceClass.VOLTAGE, ATTR_ENTITY_ID: "sensor.26_111111111111_voltage_vad", ATTR_INJECT_READS: b" 2.97", - ATTR_STATE: "3.0", + ATTR_STATE: "2.97", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, ATTR_UNIQUE_ID: "/26.111111111111/VAD", ATTR_UNIT_OF_MEASUREMENT: ELECTRIC_POTENTIAL_VOLT, @@ -386,7 +399,7 @@ ATTR_DEVICE_CLASS: SensorDeviceClass.VOLTAGE, ATTR_ENTITY_ID: "sensor.26_111111111111_voltage_vdd", ATTR_INJECT_READS: b" 4.74", - ATTR_STATE: "4.7", + ATTR_STATE: "4.74", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, ATTR_UNIQUE_ID: "/26.111111111111/VDD", ATTR_UNIT_OF_MEASUREMENT: ELECTRIC_POTENTIAL_VOLT, @@ -396,7 +409,7 @@ ATTR_DEVICE_CLASS: SensorDeviceClass.VOLTAGE, ATTR_ENTITY_ID: "sensor.26_111111111111_vis", ATTR_INJECT_READS: b" 0.12", - ATTR_STATE: "0.1", + ATTR_STATE: "0.12", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, ATTR_UNIQUE_ID: "/26.111111111111/vis", ATTR_UNIT_OF_MEASUREMENT: ELECTRIC_POTENTIAL_VOLT, @@ -430,6 +443,7 @@ ATTR_INJECT_READS: b" 26.984", ATTR_STATE: "27.0", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "26.984", ATTR_UNIQUE_ID: "/28.111111111111/temperature", ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, }, @@ -678,6 +692,7 @@ ATTR_INJECT_READS: b" 28.243", ATTR_STATE: "28.2", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "28.243", ATTR_UNIQUE_ID: "/3B.111111111111/temperature", ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, }, @@ -700,6 +715,7 @@ ATTR_INJECT_READS: b" 29.123", ATTR_STATE: "29.1", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "29.123", ATTR_UNIQUE_ID: "/42.111111111111/temperature", ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, }, @@ -722,6 +738,7 @@ ATTR_INJECT_READS: b" 67.745", ATTR_STATE: "67.7", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "67.745", ATTR_UNIQUE_ID: "/EF.111111111111/humidity/humidity_corrected", ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, }, @@ -731,6 +748,7 @@ ATTR_INJECT_READS: b" 65.541", ATTR_STATE: "65.5", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "65.541", ATTR_UNIQUE_ID: "/EF.111111111111/humidity/humidity_raw", ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, }, @@ -739,6 +757,7 @@ ATTR_ENTITY_ID: "sensor.ef_111111111111_temperature", ATTR_INJECT_READS: b" 25.123", ATTR_STATE: "25.1", + ATTR_STATE_CLONE: "25.123", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, ATTR_UNIQUE_ID: "/EF.111111111111/humidity/temperature", ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, @@ -764,7 +783,7 @@ ATTR_DEVICE_CLASS: SensorDeviceClass.HUMIDITY, ATTR_ENTITY_ID: "sensor.ef_111111111112_wetness_0", ATTR_INJECT_READS: b" 41.745", - ATTR_STATE: "41.7", + ATTR_STATE: "41.745", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, ATTR_UNIQUE_ID: "/EF.111111111112/moisture/sensor.0", ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, @@ -773,7 +792,7 @@ ATTR_DEVICE_CLASS: SensorDeviceClass.HUMIDITY, ATTR_ENTITY_ID: "sensor.ef_111111111112_wetness_1", ATTR_INJECT_READS: b" 42.541", - ATTR_STATE: "42.5", + ATTR_STATE: "42.541", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, ATTR_UNIQUE_ID: "/EF.111111111112/moisture/sensor.1", ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, @@ -782,7 +801,7 @@ ATTR_DEVICE_CLASS: SensorDeviceClass.PRESSURE, ATTR_ENTITY_ID: "sensor.ef_111111111112_moisture_2", ATTR_INJECT_READS: b" 43.123", - ATTR_STATE: "43.1", + ATTR_STATE: "43.123", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, ATTR_UNIQUE_ID: "/EF.111111111112/moisture/sensor.2", ATTR_UNIT_OF_MEASUREMENT: PRESSURE_CBAR, @@ -791,7 +810,7 @@ ATTR_DEVICE_CLASS: SensorDeviceClass.PRESSURE, ATTR_ENTITY_ID: "sensor.ef_111111111112_moisture_3", ATTR_INJECT_READS: b" 44.123", - ATTR_STATE: "44.1", + ATTR_STATE: "44.123", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, ATTR_UNIQUE_ID: "/EF.111111111112/moisture/sensor.3", ATTR_UNIT_OF_MEASUREMENT: PRESSURE_CBAR, @@ -965,6 +984,7 @@ ATTR_INJECT_READS: b" 13.9375", ATTR_STATE: "13.9", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "13.9375", ATTR_UNIQUE_ID: "/7E.111111111111/EDS0068/temperature", ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, }, @@ -974,6 +994,7 @@ ATTR_INJECT_READS: b" 1012.21", ATTR_STATE: "1012.2", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "1012.21", ATTR_UNIQUE_ID: "/7E.111111111111/EDS0068/pressure", ATTR_UNIT_OF_MEASUREMENT: PRESSURE_MBAR, }, @@ -983,6 +1004,7 @@ ATTR_INJECT_READS: b" 65.8839", ATTR_STATE: "65.9", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "65.8839", ATTR_UNIQUE_ID: "/7E.111111111111/EDS0068/light", ATTR_UNIT_OF_MEASUREMENT: LIGHT_LUX, }, @@ -992,6 +1014,7 @@ ATTR_INJECT_READS: b" 41.375", ATTR_STATE: "41.4", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "41.375", ATTR_UNIQUE_ID: "/7E.111111111111/EDS0068/humidity", ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, }, @@ -1015,6 +1038,7 @@ ATTR_INJECT_READS: b" 13.9375", ATTR_STATE: "13.9", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "13.9375", ATTR_UNIQUE_ID: "/7E.222222222222/EDS0066/temperature", ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, }, @@ -1024,6 +1048,7 @@ ATTR_INJECT_READS: b" 1012.21", ATTR_STATE: "1012.2", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "1012.21", ATTR_UNIQUE_ID: "/7E.222222222222/EDS0066/pressure", ATTR_UNIT_OF_MEASUREMENT: PRESSURE_MBAR, }, @@ -1049,6 +1074,7 @@ ATTR_INJECT_READS: 25.123, ATTR_STATE: "25.1", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "25.123", ATTR_UNIQUE_ID: "/sys/bus/w1/devices/10-111111111111/w1_slave", ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, }, @@ -1106,6 +1132,7 @@ ATTR_INJECT_READS: 29.993, ATTR_STATE: "30.0", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "29.993", ATTR_UNIQUE_ID: "/sys/bus/w1/devices/3B-111111111111/w1_slave", ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, }, @@ -1144,6 +1171,7 @@ ATTR_INJECT_READS: [UnsupportResponseException] * 9 + [27.993], ATTR_STATE: "28.0", ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, + ATTR_STATE_CLONE: "27.993", ATTR_UNIQUE_ID: "/sys/bus/w1/devices/42-111111111112/w1_slave", ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, }, @@ -1160,7 +1188,7 @@ { ATTR_DEVICE_CLASS: SensorDeviceClass.TEMPERATURE, ATTR_ENTITY_ID: "sensor.42_111111111113_temperature", - ATTR_INJECT_READS: [UnsupportResponseException] * 10 + [27.993], + ATTR_INJECT_READS: [UnsupportResponseException] * 10, ATTR_STATE: STATE_UNKNOWN, ATTR_STATE_CLASS: SensorStateClass.MEASUREMENT, ATTR_UNIQUE_ID: "/sys/bus/w1/devices/42-111111111113/w1_slave", diff --git a/tests/components/onewire/test_sensor.py b/tests/components/onewire/test_sensor.py index 6bfc68d85c85ce..42490317fec653 100644 --- a/tests/components/onewire/test_sensor.py +++ b/tests/components/onewire/test_sensor.py @@ -1,11 +1,12 @@ """Tests for 1-Wire sensor platform.""" +from copy import deepcopy import logging from unittest.mock import MagicMock, patch import pytest from homeassistant.config_entries import ConfigEntry -from homeassistant.const import Platform +from homeassistant.const import ATTR_ENTITY_ID, ATTR_STATE, Platform from homeassistant.core import HomeAssistant from homeassistant.helpers.config_validation import ensure_list @@ -17,7 +18,11 @@ setup_sysbus_mock_devices, ) from .const import ( + ATTR_DEFAULT_DISABLED, + ATTR_DEVICE_FILE, ATTR_DEVICE_INFO, + ATTR_STATE_CLONE, + ATTR_UNIQUE_ID, ATTR_UNKNOWN_DEVICE, MOCK_OWPROXY_DEVICES, MOCK_SYSBUS_DEVICES, @@ -33,6 +38,24 @@ def override_platforms(): yield +def _clone_for_raw_value(expected_entity: dict) -> dict: + new_entity = deepcopy(expected_entity) + new_entity.update( + { + ATTR_DEFAULT_DISABLED: True, + ATTR_DEVICE_FILE: expected_entity.get( + ATTR_DEVICE_FILE, expected_entity[ATTR_UNIQUE_ID] + ), + ATTR_ENTITY_ID: f"{expected_entity[ATTR_ENTITY_ID]}_raw_value", + ATTR_STATE: expected_entity.get( + ATTR_STATE_CLONE, expected_entity[ATTR_STATE] + ), + ATTR_UNIQUE_ID: f"{expected_entity[ATTR_UNIQUE_ID]}_raw_value", + } + ) + return new_entity + + async def test_owserver_sensor( hass: HomeAssistant, config_entry: ConfigEntry, @@ -48,13 +71,18 @@ async def test_owserver_sensor( entity_registry = mock_registry(hass) mock_device = MOCK_OWPROXY_DEVICES[device_id] - expected_entities = mock_device.get(Platform.SENSOR, []) + device_entities = mock_device.get(Platform.SENSOR, []) if "branches" in mock_device: for branch_details in mock_device["branches"].values(): for sub_device in branch_details.values(): - expected_entities += sub_device[Platform.SENSOR] + device_entities += sub_device[Platform.SENSOR] expected_devices = ensure_list(mock_device.get(ATTR_DEVICE_INFO)) + expected_entities = list(device_entities) + for expected_entity in device_entities: + if ATTR_STATE_CLONE in expected_entity: + expected_entities.append(_clone_for_raw_value(expected_entity)) + setup_owproxy_mock_devices(owproxy, Platform.SENSOR, [device_id]) with caplog.at_level(logging.WARNING, logger="homeassistant.components.onewire"): await hass.config_entries.async_setup(config_entry.entry_id) @@ -92,9 +120,13 @@ async def test_onewiredirect_setup_valid_device( ) mock_device = MOCK_SYSBUS_DEVICES[device_id] - expected_entities = mock_device.get(Platform.SENSOR, []) + device_entities = mock_device.get(Platform.SENSOR, []) expected_devices = ensure_list(mock_device.get(ATTR_DEVICE_INFO)) + expected_entities = list(device_entities) + for expected_entity in device_entities: + expected_entities.append(_clone_for_raw_value(expected_entity)) + with patch("pi1wire._finder.glob.glob", return_value=glob_result,), patch( "pi1wire.OneWire.get_temperature", side_effect=read_side_effect, @@ -113,4 +145,13 @@ async def test_onewiredirect_setup_valid_device( check_device_registry(device_registry, expected_devices) assert len(entity_registry.entities) == len(expected_entities) + check_and_enable_disabled_entities(entity_registry, expected_entities) + + with patch("pi1wire._finder.glob.glob", return_value=glob_result,), patch( + "pi1wire.OneWire.get_temperature", + side_effect=read_side_effect, + ), patch("homeassistant.components.onewire.sensor.asyncio.sleep"): + await hass.config_entries.async_reload(sysbus_config_entry.entry_id) + await hass.async_block_till_done() + check_entities(hass, entity_registry, expected_entities)