diff --git a/homeassistant/components/zha/core/cluster_handlers/smartenergy.py b/homeassistant/components/zha/core/cluster_handlers/smartenergy.py index 2ceaeaf1013..32e7899d413 100644 --- a/homeassistant/components/zha/core/cluster_handlers/smartenergy.py +++ b/homeassistant/components/zha/core/cluster_handlers/smartenergy.py @@ -92,6 +92,7 @@ class Metering(ClusterHandler): AttrReportConfig( attr="current_tier6_summ_delivered", config=REPORT_CONFIG_DEFAULT ), + AttrReportConfig(attr="current_summ_received", config=REPORT_CONFIG_DEFAULT), AttrReportConfig(attr="status", config=REPORT_CONFIG_ASAP), ) ZCL_INIT_ATTRS = { diff --git a/homeassistant/components/zha/sensor.py b/homeassistant/components/zha/sensor.py index b4531dc3f68..bb62494396a 100644 --- a/homeassistant/components/zha/sensor.py +++ b/homeassistant/components/zha/sensor.py @@ -802,6 +802,19 @@ class Tier6SmartEnergySummation(PolledSmartEnergySummation): _attr_translation_key: str = "tier6_summation_delivered" +@MULTI_MATCH( + cluster_handler_names=CLUSTER_HANDLER_SMARTENERGY_METERING, +) +# pylint: disable-next=hass-invalid-inheritance # needs fixing +class SmartEnergySummationReceived(PolledSmartEnergySummation): + """Smart Energy Metering summation received sensor.""" + + _use_custom_polling = False # Poll indirectly by PolledSmartEnergySummation + _attribute_name = "current_summ_received" + _unique_id_suffix = "summation_received" + _attr_translation_key: str = "summation_received" + + @MULTI_MATCH(cluster_handler_names=CLUSTER_HANDLER_PRESSURE) # pylint: disable-next=hass-invalid-inheritance # needs fixing class Pressure(Sensor): diff --git a/homeassistant/components/zha/strings.json b/homeassistant/components/zha/strings.json index a47e83fcf4b..e2875550398 100644 --- a/homeassistant/components/zha/strings.json +++ b/homeassistant/components/zha/strings.json @@ -837,6 +837,9 @@ "tier6_summation_delivered": { "name": "Tier 6 summation delivered" }, + "summation_received": { + "name": "Summation received" + }, "device_temperature": { "name": "Device temperature" }, diff --git a/tests/components/zha/test_cluster_handlers.py b/tests/components/zha/test_cluster_handlers.py index 46efe306b91..7d5b46406cc 100644 --- a/tests/components/zha/test_cluster_handlers.py +++ b/tests/components/zha/test_cluster_handlers.py @@ -235,6 +235,7 @@ async def poll_control_device(zha_device_restored, zigpy_device_mock): "current_tier4_summ_delivered", "current_tier5_summ_delivered", "current_tier6_summ_delivered", + "current_summ_received", "status", }, ), diff --git a/tests/components/zha/test_sensor.py b/tests/components/zha/test_sensor.py index 7d67e41512a..c5940a7b689 100644 --- a/tests/components/zha/test_sensor.py +++ b/tests/components/zha/test_sensor.py @@ -5,10 +5,7 @@ from unittest.mock import MagicMock, patch import pytest import zigpy.profiles.zha -import zigpy.zcl.clusters.general as general -import zigpy.zcl.clusters.homeautomation as homeautomation -import zigpy.zcl.clusters.measurement as measurement -import zigpy.zcl.clusters.smartenergy as smartenergy +from zigpy.zcl.clusters import general, homeautomation, measurement, smartenergy from homeassistant.components.sensor import SensorDeviceClass from homeassistant.components.zha.core.const import ZHA_CLUSTER_HANDLER_READS_PER_REQ @@ -70,7 +67,7 @@ def sensor_platform_only(): @pytest.fixture -async def elec_measurement_zigpy_dev(hass, zigpy_device_mock): +async def elec_measurement_zigpy_dev(hass: HomeAssistant, zigpy_device_mock): """Electric Measurement zigpy device.""" zigpy_device = zigpy_device_mock( @@ -110,19 +107,19 @@ async def elec_measurement_zha_dev(elec_measurement_zigpy_dev, zha_device_joined return zha_dev -async def async_test_humidity(hass, cluster, entity_id): +async def async_test_humidity(hass: HomeAssistant, cluster, entity_id): """Test humidity sensor.""" await send_attributes_report(hass, cluster, {1: 1, 0: 1000, 2: 100}) assert_state(hass, entity_id, "10.0", PERCENTAGE) -async def async_test_temperature(hass, cluster, entity_id): +async def async_test_temperature(hass: HomeAssistant, cluster, entity_id): """Test temperature sensor.""" await send_attributes_report(hass, cluster, {1: 1, 0: 2900, 2: 100}) assert_state(hass, entity_id, "29.0", UnitOfTemperature.CELSIUS) -async def async_test_pressure(hass, cluster, entity_id): +async def async_test_pressure(hass: HomeAssistant, cluster, entity_id): """Test pressure sensor.""" await send_attributes_report(hass, cluster, {1: 1, 0: 1000, 2: 10000}) assert_state(hass, entity_id, "1000", UnitOfPressure.HPA) @@ -131,7 +128,7 @@ async def async_test_pressure(hass, cluster, entity_id): assert_state(hass, entity_id, "1000", UnitOfPressure.HPA) -async def async_test_illuminance(hass, cluster, entity_id): +async def async_test_illuminance(hass: HomeAssistant, cluster, entity_id): """Test illuminance sensor.""" await send_attributes_report(hass, cluster, {1: 1, 0: 10, 2: 20}) assert_state(hass, entity_id, "1", LIGHT_LUX) @@ -143,7 +140,7 @@ async def async_test_illuminance(hass, cluster, entity_id): assert_state(hass, entity_id, "unknown", LIGHT_LUX) -async def async_test_metering(hass, cluster, entity_id): +async def async_test_metering(hass: HomeAssistant, cluster, entity_id): """Test Smart Energy metering sensor.""" await send_attributes_report(hass, cluster, {1025: 1, 1024: 12345, 1026: 100}) assert_state(hass, entity_id, "12345.0", None) @@ -164,8 +161,10 @@ async def async_test_metering(hass, cluster, entity_id): assert hass.states.get(entity_id).attributes["status"] in ("", "32") -async def async_test_smart_energy_summation(hass, cluster, entity_id): - """Test SmartEnergy Summation delivered sensro.""" +async def async_test_smart_energy_summation_delivered( + hass: HomeAssistant, cluster, entity_id +): + """Test SmartEnergy Summation delivered sensor.""" await send_attributes_report( hass, cluster, {1025: 1, "current_summ_delivered": 12321, 1026: 100} @@ -179,7 +178,24 @@ async def async_test_smart_energy_summation(hass, cluster, entity_id): ) -async def async_test_electrical_measurement(hass, cluster, entity_id): +async def async_test_smart_energy_summation_received( + hass: HomeAssistant, cluster, entity_id +): + """Test SmartEnergy Summation received sensor.""" + + await send_attributes_report( + hass, cluster, {1025: 1, "current_summ_received": 12321, 1026: 100} + ) + assert_state(hass, entity_id, "12.321", UnitOfEnergy.KILO_WATT_HOUR) + assert hass.states.get(entity_id).attributes["status"] == "NO_ALARMS" + assert hass.states.get(entity_id).attributes["device_type"] == "Electric Metering" + assert ( + hass.states.get(entity_id).attributes[ATTR_DEVICE_CLASS] + == SensorDeviceClass.ENERGY + ) + + +async def async_test_electrical_measurement(hass: HomeAssistant, cluster, entity_id): """Test electrical measurement sensor.""" # update divisor cached value await send_attributes_report(hass, cluster, {"ac_power_divisor": 1}) @@ -201,7 +217,7 @@ async def async_test_electrical_measurement(hass, cluster, entity_id): assert hass.states.get(entity_id).attributes["active_power_max"] == "8.8" -async def async_test_em_apparent_power(hass, cluster, entity_id): +async def async_test_em_apparent_power(hass: HomeAssistant, cluster, entity_id): """Test electrical measurement Apparent Power sensor.""" # update divisor cached value await send_attributes_report(hass, cluster, {"ac_power_divisor": 1}) @@ -219,7 +235,7 @@ async def async_test_em_apparent_power(hass, cluster, entity_id): assert_state(hass, entity_id, "9.9", UnitOfApparentPower.VOLT_AMPERE) -async def async_test_em_rms_current(hass, cluster, entity_id): +async def async_test_em_rms_current(hass: HomeAssistant, cluster, entity_id): """Test electrical measurement RMS Current sensor.""" await send_attributes_report(hass, cluster, {0: 1, 0x0508: 1234, 10: 1000}) @@ -237,7 +253,7 @@ async def async_test_em_rms_current(hass, cluster, entity_id): assert hass.states.get(entity_id).attributes["rms_current_max"] == "8.8" -async def async_test_em_rms_voltage(hass, cluster, entity_id): +async def async_test_em_rms_voltage(hass: HomeAssistant, cluster, entity_id): """Test electrical measurement RMS Voltage sensor.""" await send_attributes_report(hass, cluster, {0: 1, 0x0505: 1234, 10: 1000}) @@ -255,7 +271,7 @@ async def async_test_em_rms_voltage(hass, cluster, entity_id): assert hass.states.get(entity_id).attributes["rms_voltage_max"] == "8.9" -async def async_test_powerconfiguration(hass, cluster, entity_id): +async def async_test_powerconfiguration(hass: HomeAssistant, cluster, entity_id): """Test powerconfiguration/battery sensor.""" await send_attributes_report(hass, cluster, {33: 98}) assert_state(hass, entity_id, "49", "%") @@ -266,7 +282,7 @@ async def async_test_powerconfiguration(hass, cluster, entity_id): assert hass.states.get(entity_id).attributes["battery_voltage"] == 2.0 -async def async_test_powerconfiguration2(hass, cluster, entity_id): +async def async_test_powerconfiguration2(hass: HomeAssistant, cluster, entity_id): """Test powerconfiguration/battery sensor.""" await send_attributes_report(hass, cluster, {33: -1}) assert_state(hass, entity_id, STATE_UNKNOWN, "%") @@ -278,7 +294,7 @@ async def async_test_powerconfiguration2(hass, cluster, entity_id): assert_state(hass, entity_id, "49", "%") -async def async_test_device_temperature(hass, cluster, entity_id): +async def async_test_device_temperature(hass: HomeAssistant, cluster, entity_id): """Test temperature sensor.""" await send_attributes_report(hass, cluster, {0: 2900}) assert_state(hass, entity_id, "29.0", UnitOfTemperature.CELSIUS) @@ -330,7 +346,7 @@ async def async_test_device_temperature(hass, cluster, entity_id): smartenergy.Metering.cluster_id, "instantaneous_demand", async_test_metering, - 9, + 10, { "demand_formatting": 0xF9, "divisor": 1, @@ -338,13 +354,13 @@ async def async_test_device_temperature(hass, cluster, entity_id): "multiplier": 1, "status": 0x00, }, - {"current_summ_delivered"}, + {"current_summ_delivered", "current_summ_received"}, ), ( smartenergy.Metering.cluster_id, "summation_delivered", - async_test_smart_energy_summation, - 9, + async_test_smart_energy_summation_delivered, + 10, { "demand_formatting": 0xF9, "divisor": 1000, @@ -354,7 +370,23 @@ async def async_test_device_temperature(hass, cluster, entity_id): "summation_formatting": 0b1_0111_010, "unit_of_measure": 0x00, }, - {"instaneneous_demand"}, + {"instaneneous_demand", "current_summ_received"}, + ), + ( + smartenergy.Metering.cluster_id, + "summation_received", + async_test_smart_energy_summation_received, + 10, + { + "demand_formatting": 0xF9, + "divisor": 1000, + "metering_device_type": 0x00, + "multiplier": 1, + "status": 0x00, + "summation_formatting": 0b1_0111_010, + "unit_of_measure": 0x00, + }, + {"instaneneous_demand", "current_summ_delivered"}, ), ( homeautomation.ElectricalMeasurement.cluster_id, @@ -476,7 +508,7 @@ async def test_sensor( await async_test_rejoin(hass, zigpy_device, [cluster], (report_count,)) -def assert_state(hass, entity_id, state, unit_of_measurement): +def assert_state(hass: HomeAssistant, entity_id, state, unit_of_measurement): """Check that the state is what is expected. This is used to ensure that the logic in each sensor class handled the @@ -488,7 +520,7 @@ def assert_state(hass, entity_id, state, unit_of_measurement): @pytest.fixture -def hass_ms(hass): +def hass_ms(hass: HomeAssistant): """Hass instance with measurement system.""" async def _hass_ms(meas_sys): @@ -710,6 +742,7 @@ async def test_electrical_measurement_init( }, { "summation_delivered", + "summation_received", }, { "instantaneous_demand", @@ -717,19 +750,21 @@ async def test_electrical_measurement_init( ), ( smartenergy.Metering.cluster_id, - {"instantaneous_demand", "current_summ_delivered"}, + {"instantaneous_demand", "current_summ_delivered", "current_summ_received"}, {}, { - "summation_delivered", "instantaneous_demand", + "summation_delivered", + "summation_received", }, ), ( smartenergy.Metering.cluster_id, {}, { - "summation_delivered", "instantaneous_demand", + "summation_delivered", + "summation_received", }, {}, ), diff --git a/tests/components/zha/zha_devices_list.py b/tests/components/zha/zha_devices_list.py index 65ef55c4711..84a7b6443a1 100644 --- a/tests/components/zha/zha_devices_list.py +++ b/tests/components/zha/zha_devices_list.py @@ -233,6 +233,11 @@ DEVICES = [ DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", DEV_SIG_ENT_MAP_ID: "sensor.centralite_3210_l_summation_delivered", }, + ("sensor", "00:11:22:33:44:55:66:77-1-1794-summation_received"): { + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], + DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", + DEV_SIG_ENT_MAP_ID: "sensor.centralite_3210_l_summation_received", + }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", @@ -571,6 +576,13 @@ DEVICES = [ "sensor.climaxtechnology_psmp5_00_00_02_02tc_summation_delivered" ), }, + ("sensor", "00:11:22:33:44:55:66:77-1-1794-summation_received"): { + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], + DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", + DEV_SIG_ENT_MAP_ID: ( + "sensor.climaxtechnology_psmp5_00_00_02_02tc_summation_received" + ), + }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", @@ -1510,6 +1522,11 @@ DEVICES = [ DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", DEV_SIG_ENT_MAP_ID: "sensor.jasco_products_45852_summation_delivered", }, + ("sensor", "00:11:22:33:44:55:66:77-1-1794-summation_received"): { + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], + DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", + DEV_SIG_ENT_MAP_ID: "sensor.jasco_products_45852_summation_received", + }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", @@ -1565,6 +1582,11 @@ DEVICES = [ DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", DEV_SIG_ENT_MAP_ID: "sensor.jasco_products_45856_summation_delivered", }, + ("sensor", "00:11:22:33:44:55:66:77-1-1794-summation_received"): { + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], + DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", + DEV_SIG_ENT_MAP_ID: "sensor.jasco_products_45856_summation_received", + }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", @@ -1620,6 +1642,11 @@ DEVICES = [ DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", DEV_SIG_ENT_MAP_ID: "sensor.jasco_products_45857_summation_delivered", }, + ("sensor", "00:11:22:33:44:55:66:77-1-1794-summation_received"): { + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], + DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", + DEV_SIG_ENT_MAP_ID: "sensor.jasco_products_45857_summation_received", + }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", @@ -2183,6 +2210,11 @@ DEVICES = [ DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_relay_c2acn01_summation_delivered", }, + ("sensor", "00:11:22:33:44:55:66:77-1-1794-summation_received"): { + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], + DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", + DEV_SIG_ENT_MAP_ID: "sensor.lumi_lumi_relay_c2acn01_summation_received", + }, ("sensor", "00:11:22:33:44:55:66:77-1-1794"): { DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], DEV_SIG_ENT_MAP_CLASS: "SmartEnergyMetering", @@ -4199,6 +4231,11 @@ DEVICES = [ DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_esw01_summation_delivered", }, + ("sensor", "00:11:22:33:44:55:66:77-1-1794-summation_received"): { + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], + DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", + DEV_SIG_ENT_MAP_ID: "sensor.sercomm_corp_sz_esw01_summation_received", + }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", @@ -4955,6 +4992,11 @@ DEVICES = [ DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", DEV_SIG_ENT_MAP_ID: "sensor.sengled_e11_g13_summation_delivered", }, + ("sensor", "00:11:22:33:44:55:66:77-1-1794-summation_received"): { + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], + DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", + DEV_SIG_ENT_MAP_ID: "sensor.sengled_e11_g13_summation_received", + }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", @@ -5003,6 +5045,11 @@ DEVICES = [ DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", DEV_SIG_ENT_MAP_ID: "sensor.sengled_e12_n14_summation_delivered", }, + ("sensor", "00:11:22:33:44:55:66:77-1-1794-summation_received"): { + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], + DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", + DEV_SIG_ENT_MAP_ID: "sensor.sengled_e12_n14_summation_received", + }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor", @@ -5051,6 +5098,11 @@ DEVICES = [ DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", DEV_SIG_ENT_MAP_ID: "sensor.sengled_z01_a19nae26_summation_delivered", }, + ("sensor", "00:11:22:33:44:55:66:77-1-1794-summation_received"): { + DEV_SIG_CLUSTER_HANDLERS: ["smartenergy_metering"], + DEV_SIG_ENT_MAP_CLASS: "SmartEnergySummation", + DEV_SIG_ENT_MAP_ID: "sensor.sengled_z01_a19nae26_summation_received", + }, ("sensor", "00:11:22:33:44:55:66:77-1-0-rssi"): { DEV_SIG_CLUSTER_HANDLERS: ["basic"], DEV_SIG_ENT_MAP_CLASS: "RSSISensor",