diff --git a/tests/test_heiman.py b/tests/test_heiman.py deleted file mode 100644 index 323d7650c3..0000000000 --- a/tests/test_heiman.py +++ /dev/null @@ -1,28 +0,0 @@ -"""Tests for Heiman custom quirks.""" - -from zigpy.zcl.clusters.general import DeviceTemperature - -import zhaquirks.heiman.hs1rm_e - -zhaquirks.setup() - -CURRENT_TEMP_ID = DeviceTemperature.AttributeDefs.current_temperature.id -MIN_TEMP_ID = DeviceTemperature.AttributeDefs.min_temp_experienced.id - - -def test_heiman_hs1rm_e_temperature_scaling(zigpy_device_from_v2_quirk): - """Test that the Heiman HS1RM-E scales raw device temperatures by 100.""" - device = zigpy_device_from_v2_quirk("HEIMAN", "RelayModule-EF-3.0") - device_temp_cluster = device.endpoints[1].device_temperature - - # current_temperature is scaled *100 to centidegrees for ZHA's /100 divisor - device_temp_cluster.update_attribute(CURRENT_TEMP_ID, 25) - assert device_temp_cluster.get(CURRENT_TEMP_ID) == 2500 - - # other attributes pass through unchanged - device_temp_cluster.update_attribute(MIN_TEMP_ID, 25) - assert device_temp_cluster.get(MIN_TEMP_ID) == 25 - - # a None current_temperature must not raise (no multiplication) - device_temp_cluster.update_attribute(CURRENT_TEMP_ID, None) - assert device_temp_cluster.get(CURRENT_TEMP_ID) is None diff --git a/tests/test_sinope.py b/tests/test_sinope.py index 6fd85214ae..5a903a271b 100644 --- a/tests/test_sinope.py +++ b/tests/test_sinope.py @@ -6,7 +6,6 @@ from zigpy.device import Device import zigpy.types as t from zigpy.zcl import foundation -from zigpy.zcl.clusters.general import DeviceTemperature from zigpy.zcl.clusters.measurement import FlowMeasurement from tests.common import ClusterListener @@ -24,7 +23,7 @@ SinopeTechnologieslight, SinopeTechnologiesManufacturerCluster, ) -from zhaquirks.sinope.switch import SinopeTechnologiesCalypso, SinopeTechnologiesValveG2 +from zhaquirks.sinope.switch import SinopeTechnologiesValveG2 zhaquirks.setup() @@ -33,29 +32,6 @@ SINOPE_MANUFACTURER_ID = 4508 # 0x119C -@pytest.mark.parametrize("quirk", (SinopeTechnologiesCalypso,)) -async def test_sinope_device_temp(zigpy_device_from_quirk, quirk): - """Test that device temperature is multiplied.""" - device = zigpy_device_from_quirk(quirk) - - dev_temp_cluster = device.endpoints[1].device_temperature - dev_temp_listener = ClusterListener(dev_temp_cluster) - dev_temp_attr_id = DeviceTemperature.AttributeDefs.current_temperature.id - dev_temp_other_attr_id = DeviceTemperature.AttributeDefs.min_temp_experienced.id - - # verify current temperature is multiplied by 100 - dev_temp_cluster.update_attribute(dev_temp_attr_id, 25) - assert len(dev_temp_listener.attribute_updates) == 1 - assert dev_temp_listener.attribute_updates[0][0] == dev_temp_attr_id - assert dev_temp_listener.attribute_updates[0][1] == 2500 # multiplied by 100 - - # verify other attributes are not modified - dev_temp_cluster.update_attribute(dev_temp_other_attr_id, 25) - assert len(dev_temp_listener.attribute_updates) == 2 - assert dev_temp_listener.attribute_updates[1][0] == dev_temp_other_attr_id - assert dev_temp_listener.attribute_updates[1][1] == 25 # not modified - - @pytest.mark.parametrize("quirk", (SinopeTechnologiesValveG2,)) async def test_sinope_flow_measurement(zigpy_device_from_quirk, quirk): """Test that flow measurement measured value is divided.""" diff --git a/tests/test_tuya_rcbo.py b/tests/test_tuya_rcbo.py index 16538ebc1a..0e311881e5 100644 --- a/tests/test_tuya_rcbo.py +++ b/tests/test_tuya_rcbo.py @@ -134,7 +134,7 @@ async def test_command_rcbo(zigpy_device_from_quirk): ( # TuyaDatapointData(dp=105, data=TuyaData(dp_type=, function=0, raw=b'\x1d\x00\x00\x00', *payload=29)) b"\x09\x09\x01\x02\x03i\x02\x00\x04\x00\x00\x00\x1d", "device_temperature", - {0x0000: 2900}, + {0x0000: 29}, ), ( # TuyaDatapointData(dp=106, data=TuyaData(dp_type=, function=0, raw=b'\x00\x00\x00\x00', *payload=0)) b"\x09\x0a\x01\x02\x03j\x02\x00\x04\x00\x00\x00\x00", diff --git a/tests/test_xiaomi.py b/tests/test_xiaomi.py index 318dd393c7..1470ea8eaa 100644 --- a/tests/test_xiaomi.py +++ b/tests/test_xiaomi.py @@ -1765,7 +1765,7 @@ async def test_xiaomi_weather( [ "1C5F11C10A01FF41210121DB0B03281F0421A8430521B60006240B000000000A21CA356410000B210800", [ - 3100, # temperature + 31, # temperature 9031.899869919436, # illuminance 30.4, # battery voltage 154, # battery percent * 2 @@ -2717,7 +2717,7 @@ async def test_lumi_magnet_sensor_aq2_bad_direction(zigpy_device_from_quirk, cap def test_air_monitor_attribute_scaling(zigpy_device_from_v2_quirk): - """Test Aqara air monitor CO2 and temperature attribute scaling.""" + """Test Aqara air monitor CO2 attribute scaling.""" device = zigpy_device_from_v2_quirk("LUMI", "lumi.airm.fhac01") co2 = device.endpoints[1].carbon_dioxide_concentration @@ -2725,7 +2725,3 @@ def test_air_monitor_attribute_scaling(zigpy_device_from_v2_quirk): CarbonDioxideConcentration.AttributeDefs.measured_value.id, 400_000_000 ) assert co2.get("measured_value") == 400.0 - - temp = device.endpoints[1].device_temperature - temp._update_attribute(DeviceTemperature.AttributeDefs.current_temperature.id, 25) - assert temp.get("current_temperature") == 2500 diff --git a/zhaquirks/heiman/hs1rm_e.py b/zhaquirks/heiman/hs1rm_e.py index d8dcf10847..0d37263acf 100644 --- a/zhaquirks/heiman/hs1rm_e.py +++ b/zhaquirks/heiman/hs1rm_e.py @@ -3,7 +3,7 @@ from typing import Final import zigpy.types as t -from zigpy.zcl.clusters.general import DeviceTemperature, OnOffConfiguration +from zigpy.zcl.clusters.general import OnOffConfiguration from zigpy.zcl.foundation import BaseAttributeDefs, ZCLAttributeDef from zhaquirks.builder import EntityType, QuirkBuilder @@ -30,21 +30,10 @@ class AttributeDefs(BaseAttributeDefs): ) -class HeimanDeviceTemperature(CustomCluster, DeviceTemperature): - """Heiman Device Temperature cluster that scales raw values by 100.""" - - def _update_attribute(self, attrid, value): - """Scale current_temperature to centidegrees for ZHA's /100 divisor.""" - if attrid == self.AttributeDefs.current_temperature.id and value is not None: - value = value * 100 - super()._update_attribute(attrid, value) - - ( QuirkBuilder() .applies_to("HEIMAN", "RelayModule-EF-3.0") .friendly_name(manufacturer="HEIMAN", model="HS1RM-E") - .replaces(HeimanDeviceTemperature) .adds(HeimanSpecialCluster, endpoint_id=1) .adds(HeimanSpecialCluster, endpoint_id=2) # switch input type (Heiman manufacturer-specific cluster 0xFC90) diff --git a/zhaquirks/namron/__init__.py b/zhaquirks/namron/__init__.py new file mode 100644 index 0000000000..c28452f5bb --- /dev/null +++ b/zhaquirks/namron/__init__.py @@ -0,0 +1 @@ +"""Module for Namron quirks implementations.""" diff --git a/zhaquirks/develco/power_plug.py b/zhaquirks/namron/switch.py similarity index 66% rename from zhaquirks/develco/power_plug.py rename to zhaquirks/namron/switch.py index 75fedeae10..7f4b64906e 100644 --- a/zhaquirks/develco/power_plug.py +++ b/zhaquirks/namron/switch.py @@ -1,4 +1,4 @@ -"""Develco smart plugs.""" +"""Namron switches and relays.""" from zigpy.zcl.clusters.general import DeviceTemperature @@ -11,25 +11,27 @@ ) ( - QuirkBuilder("frient A/S", "SPLZB-141") - .applies_to("Develco Products A/S", "SPLZB-131") + QuirkBuilder("Namron AS", "4512785") + # The device reports current_temperature in units of 0.1 °C, violating the + # ZCL spec (whole degrees, range -200..200). Replace the default entity with + # one that applies the correct divisor. .prevent_default_entity_creation( - endpoint_id=2, + endpoint_id=1, cluster_id=DeviceTemperature.cluster_id, function=lambda entity: entity.__class__.__name__ == "DeviceTemperature", ) .sensor( - endpoint_id=2, + endpoint_id=1, cluster_id=DeviceTemperature.cluster_id, attribute_name=DeviceTemperature.AttributeDefs.current_temperature.name, + divisor=10, device_class=SensorDeviceClass.TEMPERATURE, state_class=SensorStateClass.MEASUREMENT, unit=UnitOfTemperature.CELSIUS, - divisor=1, # This should be 100 but the device does not follow the spec + entity_type=EntityType.DIAGNOSTIC, + unique_id_suffix="2", # Replace the ZHA-native entity ({ieee}-1-2) translation_key="device_temperature", fallback_name="Device temperature", - entity_type=EntityType.DIAGNOSTIC, - unique_id_suffix="2", # Replace the ZHA entity ) .add_to_registry() ) diff --git a/zhaquirks/sinope/__init__.py b/zhaquirks/sinope/__init__.py index 3bdfa98556..7578a47370 100644 --- a/zhaquirks/sinope/__init__.py +++ b/zhaquirks/sinope/__init__.py @@ -1,9 +1,7 @@ """Module for Sinope quirks implementations.""" import zigpy.types as t -from zigpy.zcl.clusters.general import DeviceTemperature -from zhaquirks.clusters import CustomCluster from zhaquirks.const import ( ARGS, ATTRIBUTE_ID, @@ -133,12 +131,3 @@ class ButtonAction(t.enum8): }, }, } - - -class CustomDeviceTemperatureCluster(CustomCluster, DeviceTemperature): - """Custom device temperature cluster that multiplies temperature by 100.""" - - def _update_attribute(self, attrid, value): - if attrid == self.AttributeDefs.current_temperature.id: - value = value * 100 - super()._update_attribute(attrid, value) diff --git a/zhaquirks/sinope/light.py b/zhaquirks/sinope/light.py index f3604864d5..9da6196c19 100644 --- a/zhaquirks/sinope/light.py +++ b/zhaquirks/sinope/light.py @@ -54,7 +54,6 @@ SINOPE, SINOPE_MANUFACTURER_CLUSTER_ID, ButtonAction, - CustomDeviceTemperatureCluster, ) _LOGGER = logging.getLogger(__name__) @@ -280,7 +279,7 @@ class SinopeTechnologieslight(CustomDevice): DEVICE_TYPE: zha_p.DeviceType.ON_OFF_LIGHT, INPUT_CLUSTERS: [ Basic.cluster_id, - CustomDeviceTemperatureCluster, + DeviceTemperature.cluster_id, Identify.cluster_id, Groups.cluster_id, Scenes.cluster_id, @@ -344,7 +343,7 @@ class SinopeDM2500ZB(CustomDevice): DEVICE_TYPE: zha_p.DeviceType.DIMMABLE_LIGHT, INPUT_CLUSTERS: [ Basic.cluster_id, - CustomDeviceTemperatureCluster, + DeviceTemperature.cluster_id, Identify.cluster_id, Groups.cluster_id, Scenes.cluster_id, @@ -411,7 +410,7 @@ class SinopeDM2550ZB(CustomDevice): DEVICE_TYPE: zha_p.DeviceType.DIMMABLE_LIGHT, INPUT_CLUSTERS: [ Basic.cluster_id, - CustomDeviceTemperatureCluster, + DeviceTemperature.cluster_id, Identify.cluster_id, Groups.cluster_id, Scenes.cluster_id, diff --git a/zhaquirks/sinope/switch.py b/zhaquirks/sinope/switch.py index 62c3b429c0..ae15fc5f1f 100644 --- a/zhaquirks/sinope/switch.py +++ b/zhaquirks/sinope/switch.py @@ -44,11 +44,7 @@ PROFILE_ID, ) from zhaquirks.legacy import CustomDevice -from zhaquirks.sinope import ( - SINOPE, - SINOPE_MANUFACTURER_CLUSTER_ID, - CustomDeviceTemperatureCluster, -) +from zhaquirks.sinope import SINOPE, SINOPE_MANUFACTURER_CLUSTER_ID class KeypadLock(t.enum8): @@ -458,7 +454,7 @@ class SinopeTechnologiesLoadController_V2(CustomDevice): 1: { INPUT_CLUSTERS: [ Basic.cluster_id, - CustomDeviceTemperatureCluster, + DeviceTemperature.cluster_id, Identify.cluster_id, Groups.cluster_id, Scenes.cluster_id, @@ -736,7 +732,7 @@ class SinopeTechnologiesCalypso(CustomDevice): DEVICE_TYPE: zha_p.DeviceType.ON_OFF_OUTPUT, INPUT_CLUSTERS: [ Basic.cluster_id, - CustomDeviceTemperatureCluster, + DeviceTemperature.cluster_id, Identify.cluster_id, Groups.cluster_id, Scenes.cluster_id, diff --git a/zhaquirks/tuya/ts0601_rcbo.py b/zhaquirks/tuya/ts0601_rcbo.py index 48705b8aa2..bcefe878cc 100644 --- a/zhaquirks/tuya/ts0601_rcbo.py +++ b/zhaquirks/tuya/ts0601_rcbo.py @@ -376,7 +376,6 @@ class TuyaRCBOManufCluster(TuyaMCUCluster): TUYA_DP_TEMPERATURE: DPToAttributeMapping( TuyaRCBODeviceTemperature.ep_attribute, "current_temperature", - lambda x: x * 100, ), TUYA_DP_REMAINING_ENERGY: DPToAttributeMapping( TuyaRCBOMetering.ep_attribute, diff --git a/zhaquirks/xiaomi/__init__.py b/zhaquirks/xiaomi/__init__.py index e3f33c0d0c..c661f65c97 100644 --- a/zhaquirks/xiaomi/__init__.py +++ b/zhaquirks/xiaomi/__init__.py @@ -275,7 +275,7 @@ def _handle_attribute_event( if hasattr(self.endpoint, "device_temperature"): self.endpoint.device_temperature.update_attribute( DeviceTemperature.AttributeDefs.current_temperature.id, - attributes[TEMPERATURE] * 100, + attributes[TEMPERATURE], ) if BATTERY_PERCENTAGE_REMAINING_ATTRIBUTE in attributes: diff --git a/zhaquirks/xiaomi/aqara/airm_fhac01.py b/zhaquirks/xiaomi/aqara/airm_fhac01.py index b7b1296b06..ebfc9a21ce 100644 --- a/zhaquirks/xiaomi/aqara/airm_fhac01.py +++ b/zhaquirks/xiaomi/aqara/airm_fhac01.py @@ -1,6 +1,5 @@ """Quirk for LUMI lumi.airm.fhac01 air quality monitor.""" -from zigpy.zcl.clusters.general import DeviceTemperature from zigpy.zcl.clusters.measurement import CarbonDioxideConcentration from zhaquirks.builder import QuirkBuilder @@ -19,20 +18,8 @@ def _update_attribute(self, attrid, value): super()._update_attribute(attrid, value) -class CustomDeviceTemperature(CustomCluster, DeviceTemperature): - """Temperature measurement cluster that fixes the scaling issue.""" - - def _update_attribute(self, attrid, value): - """Fix temperature scaling by multiplying by 100.""" - if attrid == DeviceTemperature.AttributeDefs.current_temperature.id: - # The device reports temperature divided by 100, so multiply by 100 - value = value * 100 - super()._update_attribute(attrid, value) - - ( QuirkBuilder(LUMI, "lumi.airm.fhac01") .replaces(CarbonDioxideConcentrationCluster) - .replaces(CustomDeviceTemperature) .add_to_registry() )